From 650efc2e96644c87e9da365fa41b575578c589a8 Mon Sep 17 00:00:00 2001 From: Klaus Post Date: Fri, 8 Mar 2024 18:50:48 +0100 Subject: [PATCH] Fix listing in objects split across pools (#19227) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merging same-object - multiple versions from different pools would not always result in correct ordering. When merging keep inputs separate. ``` λ mc ls --versions local/testbucket ------ before ------ [2024-03-05 20:17:19 CET] 228B STANDARD 1f163718-9bc5-4b01-bff7-5d8cf09caf10 v3 PUT hosts [2024-03-05 20:19:56 CET] 19KiB STANDARD null v2 PUT hosts [2024-03-05 20:17:15 CET] 228B STANDARD 73c9f651-f023-4566-b012-cc537fdb7ce2 v1 PUT hosts ------ after ------ λ mc ls --versions local/testbucket [2024-03-05 20:19:56 CET] 19KiB STANDARD null v3 PUT hosts [2024-03-05 20:17:19 CET] 228B STANDARD 1f163718-9bc5-4b01-bff7-5d8cf09caf10 v2 PUT hosts [2024-03-05 20:17:15 CET] 228B STANDARD 73c9f651-f023-4566-b012-cc537fdb7ce2 v1 PUT hosts ``` --- cmd/metacache-entries.go | 9 ++-- cmd/testdata/xl-meta-merge.zip | Bin 0 -> 30882 bytes cmd/xl-storage-format-v2.go | 1 + cmd/xl-storage-format-v2_test.go | 72 +++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 4 deletions(-) create mode 100644 cmd/testdata/xl-meta-merge.zip diff --git a/cmd/metacache-entries.go b/cmd/metacache-entries.go index a1688f998..22598d20b 100644 --- a/cmd/metacache-entries.go +++ b/cmd/metacache-entries.go @@ -745,10 +745,10 @@ func mergeEntryChannels(ctx context.Context, in []chan metaCacheEntry, out chan< // Merge any unmerged if len(toMerge) > 0 { - versions := make([]xlMetaV2ShallowVersion, 0, len(toMerge)+1) + versions := make([][]xlMetaV2ShallowVersion, 0, len(toMerge)+1) xl, err := best.xlmeta() if err == nil { - versions = append(versions, xl.versions...) + versions = append(versions, xl.versions) } for _, idx := range toMerge { other := top[idx] @@ -776,11 +776,12 @@ func mergeEntryChannels(ctx context.Context, in []chan metaCacheEntry, out chan< return err } } - versions = append(versions, xl2.versions...) + versions = append(versions, xl2.versions) } + if xl != nil && len(versions) > 0 { // Merge all versions. 'strict' doesn't matter since we only need one. - xl.versions = mergeXLV2Versions(readQuorum, true, 0, versions) + xl.versions = mergeXLV2Versions(readQuorum, true, 0, versions...) if meta, err := xl.AppendTo(metaDataPoolGet()); err == nil { if best.reusable { metaDataPoolPut(best.metadata) diff --git a/cmd/testdata/xl-meta-merge.zip b/cmd/testdata/xl-meta-merge.zip new file mode 100644 index 0000000000000000000000000000000000000000..3554ff01d8cbb9870260a1c5fd0a7be3589fffbb GIT binary patch literal 30882 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 AfdBvi literal 0 HcmV?d00001 diff --git a/cmd/xl-storage-format-v2.go b/cmd/xl-storage-format-v2.go index a51441b79..6bfb3ac8a 100644 --- a/cmd/xl-storage-format-v2.go +++ b/cmd/xl-storage-format-v2.go @@ -1879,6 +1879,7 @@ func (x xlMetaV2) ListVersions(volume, path string, allParts bool) ([]FileInfo, // mergeXLV2Versions will merge all versions, typically from different disks // that have at least quorum entries in all metas. +// Each version slice should be sorted. // Quorum must be the minimum number of matching metadata files. // Quorum should be > 1 and <= len(versions). // If strict is set to false, entries that match type diff --git a/cmd/xl-storage-format-v2_test.go b/cmd/xl-storage-format-v2_test.go index 3162d6e55..29bfa5f9d 100644 --- a/cmd/xl-storage-format-v2_test.go +++ b/cmd/xl-storage-format-v2_test.go @@ -21,6 +21,7 @@ import ( "bufio" "bytes" "compress/gzip" + "context" "encoding/base64" "encoding/json" "fmt" @@ -1011,6 +1012,77 @@ func Test_mergeXLV2Versions2(t *testing.T) { } } +func Test_mergeEntryChannels(t *testing.T) { + dataZ, err := os.ReadFile("testdata/xl-meta-merge.zip") + if err != nil { + t.Fatal(err) + } + var vers []metaCacheEntry + zr, err := zip.NewReader(bytes.NewReader(dataZ), int64(len(dataZ))) + if err != nil { + t.Fatal(err) + } + + for _, file := range zr.File { + if file.UncompressedSize64 == 0 { + continue + } + in, err := file.Open() + if err != nil { + t.Fatal(err) + } + defer in.Close() + buf, err := io.ReadAll(in) + if err != nil { + t.Fatal(err) + } + buf = xlMetaV2TrimData(buf) + + vers = append(vers, metaCacheEntry{ + name: "a", + metadata: buf, + }) + } + + // Shuffle... + for i := 0; i < 100; i++ { + rng := rand.New(rand.NewSource(int64(i))) + rng.Shuffle(len(vers), func(i, j int) { + vers[i], vers[j] = vers[j], vers[i] + }) + var entries []chan metaCacheEntry + for _, v := range vers { + v.cached = nil + ch := make(chan metaCacheEntry, 1) + ch <- v + close(ch) + entries = append(entries, ch) + } + out := make(chan metaCacheEntry, 1) + err := mergeEntryChannels(context.Background(), entries, out, 1) + if err != nil { + t.Fatal(err) + } + got, ok := <-out + if !ok { + t.Fatal("Got no result") + } + + xl, err := got.xlmeta() + if err != nil { + t.Fatal(err) + } + if len(xl.versions) != 3 { + t.Fatal("Got wrong number of versions, want 3, got", len(xl.versions)) + } + if !sort.SliceIsSorted(xl.versions, func(i, j int) bool { + return xl.versions[i].header.sortsBefore(xl.versions[j].header) + }) { + t.Errorf("Got unsorted result") + } + } +} + func TestXMinIOHealingSkip(t *testing.T) { xl := xlMetaV2{} failOnErr := func(err error) {