fix: readQuorum calculation when defaultParityCount is 0 (#15363)

when parity is '0' the readQuorum must be equal
to the number of data disks.
This commit is contained in:
Harshavardhana 2022-07-21 07:25:54 -07:00 committed by GitHub
parent 8249cd4406
commit 65166e4ce4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 28 additions and 20 deletions

View File

@ -140,6 +140,8 @@ clean: ## cleanup all generated assets
@echo "Cleaning up all the generated files" @echo "Cleaning up all the generated files"
@find . -name '*.test' | xargs rm -fv @find . -name '*.test' | xargs rm -fv
@find . -name '*~' | xargs rm -fv @find . -name '*~' | xargs rm -fv
@find . -name '.#*#' | xargs rm -fv
@find . -name '#*#' | xargs rm -fv
@rm -rvf minio @rm -rvf minio
@rm -rvf build @rm -rvf build
@rm -rvf release @rm -rvf release

View File

@ -180,9 +180,15 @@ func listOnlineDisks(disks []StorageAPI, partsMetadata []FileInfo, errs []error)
} }
// Returns the latest updated FileInfo files and error in case of failure. // Returns the latest updated FileInfo files and error in case of failure.
func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, errs []error) (FileInfo, error) { func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, defaultParityCount int, errs []error) (FileInfo, error) {
// There should be atleast half correct entries, if not return failure // There should be atleast half correct entries, if not return failure
reducedErr := reduceReadQuorumErrs(ctx, errs, objectOpIgnoredErrs, len(partsMetadata)/2) expectedRQuorum := len(partsMetadata) / 2
if defaultParityCount == 0 {
// if parity count is '0', we expected all entries to be present.
expectedRQuorum = len(partsMetadata)
}
reducedErr := reduceReadQuorumErrs(ctx, errs, objectOpIgnoredErrs, expectedRQuorum)
if reducedErr != nil { if reducedErr != nil {
return FileInfo{}, reducedErr return FileInfo{}, reducedErr
} }

View File

@ -194,7 +194,7 @@ func TestListOnlineDisks(t *testing.T) {
} }
partsMetadata, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) partsMetadata, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
fi, err := getLatestFileInfo(ctx, partsMetadata, errs) fi, err := getLatestFileInfo(ctx, partsMetadata, z.serverPools[0].sets[0].defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo %v", err) t.Fatalf("Failed to getLatestFileInfo %v", err)
} }
@ -370,7 +370,7 @@ func TestListOnlineDisksSmallObjects(t *testing.T) {
} }
partsMetadata, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", true) partsMetadata, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", true)
_, err = getLatestFileInfo(ctx, partsMetadata, errs) _, err = getLatestFileInfo(ctx, partsMetadata, z.serverPools[0].sets[0].defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo %v", err) t.Fatalf("Failed to getLatestFileInfo %v", err)
} }
@ -429,7 +429,7 @@ func TestListOnlineDisksSmallObjects(t *testing.T) {
} }
partsMetadata, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", true) partsMetadata, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", true)
fi, err := getLatestFileInfo(ctx, partsMetadata, errs) fi, err := getLatestFileInfo(ctx, partsMetadata, z.serverPools[0].sets[0].defaultParityCount, errs)
if !errors.Is(err, errErasureReadQuorum) { if !errors.Is(err, errErasureReadQuorum) {
t.Fatalf("Failed to getLatestFileInfo, expected %v, got %v", errErasureReadQuorum, err) t.Fatalf("Failed to getLatestFileInfo, expected %v, got %v", errErasureReadQuorum, err)
} }
@ -495,7 +495,7 @@ func TestDisksWithAllParts(t *testing.T) {
t.Fatalf("Failed to read xl meta data %v", err) t.Fatalf("Failed to read xl meta data %v", err)
} }
fi, err := getLatestFileInfo(ctx, partsMetadata, errs) fi, err := getLatestFileInfo(ctx, partsMetadata, s.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to get quorum consistent fileInfo %v", err) t.Fatalf("Failed to get quorum consistent fileInfo %v", err)
} }

View File

@ -601,7 +601,7 @@ func TestHealCorrectQuorum(t *testing.T) {
erasureDisks := er.getDisks() erasureDisks := er.getDisks()
fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
nfi, err := getLatestFileInfo(ctx, fileInfos, errs) nfi, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if errors.Is(err, errFileNotFound) { if errors.Is(err, errFileNotFound) {
continue continue
} }
@ -628,7 +628,7 @@ func TestHealCorrectQuorum(t *testing.T) {
} }
fileInfos, errs = readAllFileInfo(ctx, erasureDisks, minioMetaBucket, cfgFile, "", false) fileInfos, errs = readAllFileInfo(ctx, erasureDisks, minioMetaBucket, cfgFile, "", false)
nfi, err = getLatestFileInfo(ctx, fileInfos, errs) nfi, err = getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if errors.Is(err, errFileNotFound) { if errors.Is(err, errFileNotFound) {
continue continue
} }
@ -734,7 +734,7 @@ func TestHealObjectCorruptedPools(t *testing.T) {
} }
fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
fi, err := getLatestFileInfo(ctx, fileInfos, errs) fi, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -762,7 +762,7 @@ func TestHealObjectCorruptedPools(t *testing.T) {
} }
fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
nfi, err := getLatestFileInfo(ctx, fileInfos, errs) nfi, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -793,7 +793,7 @@ func TestHealObjectCorruptedPools(t *testing.T) {
} }
fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
nfi, err = getLatestFileInfo(ctx, fileInfos, errs) nfi, err = getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -897,7 +897,7 @@ func TestHealObjectCorruptedXLMeta(t *testing.T) {
// Test 1: Remove the object backend files from the first disk. // Test 1: Remove the object backend files from the first disk.
fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
fi, err := getLatestFileInfo(ctx, fileInfos, errs) fi, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -920,7 +920,7 @@ func TestHealObjectCorruptedXLMeta(t *testing.T) {
} }
fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
nfi1, err := getLatestFileInfo(ctx, fileInfos, errs) nfi1, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -943,7 +943,7 @@ func TestHealObjectCorruptedXLMeta(t *testing.T) {
} }
fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs = readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
nfi2, err := getLatestFileInfo(ctx, fileInfos, errs) nfi2, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }
@ -1041,7 +1041,7 @@ func TestHealObjectCorruptedParts(t *testing.T) {
secondDisk := erasureDisks[1] secondDisk := erasureDisks[1]
fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false) fileInfos, errs := readAllFileInfo(ctx, erasureDisks, bucket, object, "", false)
fi, err := getLatestFileInfo(ctx, fileInfos, errs) fi, err := getLatestFileInfo(ctx, fileInfos, er.defaultParityCount, errs)
if err != nil { if err != nil {
t.Fatalf("Failed to getLatestFileInfo - %v", err) t.Fatalf("Failed to getLatestFileInfo - %v", err)
} }

View File

@ -400,17 +400,17 @@ func writeUniqueFileInfo(ctx context.Context, disks []StorageAPI, bucket, prefix
// readQuorum is the min required disks to read data. // readQuorum is the min required disks to read data.
// writeQuorum is the min required disks to write data. // writeQuorum is the min required disks to write data.
func objectQuorumFromMeta(ctx context.Context, partsMetaData []FileInfo, errs []error, defaultParityCount int) (objectReadQuorum, objectWriteQuorum int, err error) { func objectQuorumFromMeta(ctx context.Context, partsMetaData []FileInfo, errs []error, defaultParityCount int) (objectReadQuorum, objectWriteQuorum int, err error) {
if defaultParityCount == 0 {
return 1, 1, nil
}
// get the latest updated Metadata and a count of all the latest updated FileInfo(s) // get the latest updated Metadata and a count of all the latest updated FileInfo(s)
latestFileInfo, err := getLatestFileInfo(ctx, partsMetaData, errs) latestFileInfo, err := getLatestFileInfo(ctx, partsMetaData, defaultParityCount, errs)
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
if latestFileInfo.Deleted { if latestFileInfo.Deleted {
// special case when parity is '0'
if defaultParityCount == 0 {
return len(partsMetaData), len(partsMetaData), nil
}
// For delete markers do not use 'defaultParityCount' as it is not expected to be the case. // For delete markers do not use 'defaultParityCount' as it is not expected to be the case.
// Use maximum allowed read quorum instead, writeQuorum+1 is returned for compatibility sake // Use maximum allowed read quorum instead, writeQuorum+1 is returned for compatibility sake
// but there are no callers that shall be using this. // but there are no callers that shall be using this.