mirror of
https://github.com/pgsty/minio.git
synced 2026-10-30 12:30:39 +03:00
fix: preserve version state across late rollback and nested mutations
Signed-off-by: Feng Ruohang <rh@vonng.com>
This commit is contained in:
+37
-60
@@ -19,7 +19,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -28,8 +27,6 @@ import (
|
||||
"github.com/minio/minio/internal/amztime"
|
||||
"github.com/minio/minio/internal/bucket/lifecycle"
|
||||
"github.com/minio/minio/internal/bucket/replication"
|
||||
"github.com/minio/minio/internal/crypto"
|
||||
"github.com/minio/minio/internal/hash/sha256"
|
||||
xhttp "github.com/minio/minio/internal/http"
|
||||
"github.com/pgsty/silo-pkg/v3/sync/errgroup"
|
||||
)
|
||||
@@ -319,68 +316,48 @@ func findFileInfoInQuorum(ctx context.Context, metaArr []FileInfo, modTime time.
|
||||
if quorum < 1 {
|
||||
return FileInfo{}, InsufficientReadQuorum{Err: errErasureReadQuorum, Type: RQInsufficientOnlineDrives}
|
||||
}
|
||||
metaHashes := make([]string, len(metaArr))
|
||||
h := sha256.New()
|
||||
// Group by exact logical state rather than a layout-only hash. There are
|
||||
// at most one erasure set's worth of candidates; healthy objects compare
|
||||
// against a single representative without hashing or a second XL decode.
|
||||
groups := make([]int, len(metaArr))
|
||||
representatives := make([]int, 0, len(metaArr))
|
||||
counts := make([]int, len(metaArr)+1)
|
||||
for i, meta := range metaArr {
|
||||
if !meta.IsValid() {
|
||||
continue
|
||||
}
|
||||
etagOnly := modTime.Equal(timeSentinel) && (etag != "" && etag == meta.Metadata["etag"])
|
||||
mtimeValid := meta.ModTime.Equal(modTime)
|
||||
if mtimeValid || etagOnly {
|
||||
fmt.Fprintf(h, "%v", meta.XLV1)
|
||||
for _, part := range meta.Parts {
|
||||
fmt.Fprintf(h, "part.%d", part.Number)
|
||||
fmt.Fprintf(h, "part.%d", part.Size)
|
||||
}
|
||||
// Previously we checked if we had quorum on DataDir value.
|
||||
// We have removed this check to allow reading objects with different DataDir
|
||||
// values in a few drives (due to a rebalance-stop race bug)
|
||||
// provided their their etags or ModTimes match.
|
||||
|
||||
if !meta.Deleted && meta.Size != 0 {
|
||||
fmt.Fprintf(h, "%v+%v", meta.Erasure.DataBlocks, meta.Erasure.ParityBlocks)
|
||||
fmt.Fprintf(h, "%v", meta.Erasure.Distribution)
|
||||
}
|
||||
|
||||
if meta.IsRemote() {
|
||||
// ILM transition fields
|
||||
fmt.Fprint(h, meta.TransitionStatus)
|
||||
fmt.Fprint(h, meta.TransitionTier)
|
||||
fmt.Fprint(h, meta.TransitionedObjName)
|
||||
fmt.Fprint(h, meta.TransitionVersionID)
|
||||
}
|
||||
|
||||
// If metadata says encrypted, ask for it in quorum.
|
||||
if etyp, ok := crypto.IsEncrypted(meta.Metadata); ok {
|
||||
fmt.Fprint(h, etyp)
|
||||
}
|
||||
|
||||
// If compressed, look for compressed FileInfo only
|
||||
if meta.IsCompressed() {
|
||||
fmt.Fprint(h, meta.Metadata[ReservedMetadataPrefix+"compression"])
|
||||
}
|
||||
|
||||
metaHashes[i] = hex.EncodeToString(h.Sum(nil))
|
||||
h.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
metaHashCountMap := make(map[string]int)
|
||||
for _, hash := range metaHashes {
|
||||
if hash == "" {
|
||||
etagOnly := modTime.Equal(timeSentinel) && etag != "" && etag == meta.Metadata["etag"]
|
||||
if !meta.ModTime.Equal(modTime) && !etagOnly {
|
||||
continue
|
||||
}
|
||||
metaHashCountMap[hash]++
|
||||
}
|
||||
|
||||
maxHash := ""
|
||||
maxCount := 0
|
||||
for hash, count := range metaHashCountMap {
|
||||
if count > maxCount {
|
||||
maxCount = count
|
||||
maxHash = hash
|
||||
group := 0
|
||||
for j, representative := range representatives {
|
||||
if sameFileInfoVersion(metaArr[representative], meta) {
|
||||
group = j + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
if group == 0 {
|
||||
representatives = append(representatives, i)
|
||||
group = len(representatives)
|
||||
}
|
||||
groups[i] = group
|
||||
counts[group]++
|
||||
}
|
||||
maxGroup, maxCount := 0, 0
|
||||
tied := false
|
||||
for group, count := range counts {
|
||||
if group == 0 {
|
||||
continue
|
||||
}
|
||||
if count > maxCount {
|
||||
maxGroup, maxCount, tied = group, count, false
|
||||
} else if count == maxCount {
|
||||
tied = true
|
||||
}
|
||||
}
|
||||
if tied {
|
||||
return FileInfo{}, InsufficientReadQuorum{Err: errErasureReadQuorum, Type: RQInconsistentMeta}
|
||||
}
|
||||
|
||||
if maxCount < quorum {
|
||||
@@ -397,8 +374,8 @@ func findFileInfoInQuorum(ctx context.Context, metaArr []FileInfo, modTime time.
|
||||
otherPropsMap := make(counterMap[objProps])
|
||||
var candidate FileInfo
|
||||
var found bool
|
||||
for i, hash := range metaHashes {
|
||||
if hash == maxHash {
|
||||
for i, group := range groups {
|
||||
if group == maxGroup {
|
||||
if metaArr[i].IsValid() {
|
||||
if !found {
|
||||
candidate = metaArr[i]
|
||||
|
||||
Reference in New Issue
Block a user