From 886262e58af77ebc7c836ef587c08544e9a0c271 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 17 Nov 2021 15:49:12 -0800 Subject: [PATCH] heal legacy objects when versioning is enabled after upgrade (#13671) legacy objects in 'xl.json' after upgrade, should have following sequence of events - bucket should have versioning enabled and the object should have been overwritten with another version of an object. this situation was not handled, which would lead to older objects to stay perpetually with "legacy" dataDir, however these objects were readable by all means - there weren't converted to newer format. This PR fixes this situation properly. --- cmd/xl-storage-format-utils.go | 10 +++++++--- cmd/xl-storage-format-v1.go | 2 ++ cmd/xl-storage.go | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/cmd/xl-storage-format-utils.go b/cmd/xl-storage-format-utils.go index 767520144..6eb64f327 100644 --- a/cmd/xl-storage-format-utils.go +++ b/cmd/xl-storage-format-utils.go @@ -18,9 +18,11 @@ package cmd import ( + "fmt" "sort" jsoniter "github.com/json-iterator/go" + "github.com/minio/minio/internal/logger" ) // versionsSorter sorts FileInfo slices by version. @@ -121,15 +123,17 @@ func getFileInfo(xlMetaBuf []byte, volume, path, versionID string, data bool) (F xlMeta := &xlMetaV1Object{} var json = jsoniter.ConfigCompatibleWithStandardLibrary if err := json.Unmarshal(xlMetaBuf, xlMeta); err != nil { + logger.LogIf(GlobalContext, fmt.Errorf("unable to unmarshal json object: %v", err)) return FileInfo{}, errFileCorrupt } fi, err := xlMeta.ToFileInfo(volume, path) - if err == errFileNotFound && versionID != "" { - return fi, errFileVersionNotFound + if err != nil { + return FileInfo{}, err } - fi.IsLatest = true // No versions so current version is latest. + fi.XLV1 = true // indicates older version + fi.IsLatest = true // No versions so current version is latest. return fi, err } diff --git a/cmd/xl-storage-format-v1.go b/cmd/xl-storage-format-v1.go index 7a4119d61..50049d04a 100644 --- a/cmd/xl-storage-format-v1.go +++ b/cmd/xl-storage-format-v1.go @@ -199,7 +199,9 @@ func (m *xlMetaV1Object) ToFileInfo(volume, path string) (FileInfo, error) { Erasure: m.Erasure, VersionID: m.VersionID, DataDir: m.DataDir, + XLV1: true, } + return fi, nil } diff --git a/cmd/xl-storage.go b/cmd/xl-storage.go index a9c2158c2..f8b352749 100644 --- a/cmd/xl-storage.go +++ b/cmd/xl-storage.go @@ -2133,6 +2133,10 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f xlMeta.AddFreeVersion(fi) } + // indicates if RenameData() is called by healing. + // healing doesn't preserve the dataDir as 'legacy' + healing := fi.XLV1 && fi.DataDir != legacyDataDir + if err = xlMeta.AddVersion(fi); err != nil { if legacyPreserved { // Any failed rename calls un-roll previous transaction. @@ -2164,6 +2168,12 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath string, f // renameAll only for objects that have xl.meta not saved inline. if len(fi.Data) == 0 && fi.Size > 0 { s.moveToTrash(dstDataPath, true) + if healing { + // If we are healing we should purge any legacyDataPath content, + // that was previously preserved during PutObject() call + // on a versioned bucket. + s.moveToTrash(legacyDataPath, true) + } if err = renameAll(srcDataPath, dstDataPath); err != nil { if legacyPreserved { // Any failed rename calls un-roll previous transaction.