mirror of
https://github.com/minio/minio.git
synced 2024-12-25 06:35:56 -05:00
refactor objectQuorumFromMeta() to search for parity quorum (#15844)
This commit is contained in:
parent
97112c69be
commit
783dd875f7
@ -179,53 +179,6 @@ func listOnlineDisks(disks []StorageAPI, partsMetadata []FileInfo, errs []error)
|
|||||||
return onlineDisks, modTime
|
return onlineDisks, modTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the latest updated FileInfo files and error in case of failure.
|
|
||||||
func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, defaultParityCount int, errs []error) (FileInfo, error) {
|
|
||||||
// There should be atleast half correct entries, if not return failure
|
|
||||||
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 {
|
|
||||||
return FileInfo{}, reducedErr
|
|
||||||
}
|
|
||||||
|
|
||||||
// List all the file commit ids from parts metadata.
|
|
||||||
modTimes := listObjectModtimes(partsMetadata, errs)
|
|
||||||
|
|
||||||
// Count all latest updated FileInfo values
|
|
||||||
var count int
|
|
||||||
var latestFileInfo FileInfo
|
|
||||||
|
|
||||||
// Reduce list of UUIDs to a single common value - i.e. the last updated Time
|
|
||||||
modTime := commonTime(modTimes)
|
|
||||||
|
|
||||||
if modTime.IsZero() || modTime.Equal(timeSentinel) {
|
|
||||||
return FileInfo{}, errErasureReadQuorum
|
|
||||||
}
|
|
||||||
|
|
||||||
// Interate through all the modTimes and count the FileInfo(s) with latest time.
|
|
||||||
for index, t := range modTimes {
|
|
||||||
if partsMetadata[index].IsValid() && t.Equal(modTime) {
|
|
||||||
latestFileInfo = partsMetadata[index]
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !latestFileInfo.IsValid() {
|
|
||||||
return FileInfo{}, errErasureReadQuorum
|
|
||||||
}
|
|
||||||
|
|
||||||
if count < latestFileInfo.Erasure.DataBlocks {
|
|
||||||
return FileInfo{}, errErasureReadQuorum
|
|
||||||
}
|
|
||||||
|
|
||||||
return latestFileInfo, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// disksWithAllParts - This function needs to be called with
|
// disksWithAllParts - This function needs to be called with
|
||||||
// []StorageAPI returned by listOnlineDisks. Returns,
|
// []StorageAPI returned by listOnlineDisks. Returns,
|
||||||
//
|
//
|
||||||
|
@ -30,6 +30,53 @@ import (
|
|||||||
"github.com/minio/madmin-go"
|
"github.com/minio/madmin-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Returns the latest updated FileInfo files and error in case of failure.
|
||||||
|
func getLatestFileInfo(ctx context.Context, partsMetadata []FileInfo, defaultParityCount int, errs []error) (FileInfo, error) {
|
||||||
|
// There should be atleast half correct entries, if not return failure
|
||||||
|
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 {
|
||||||
|
return FileInfo{}, reducedErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// List all the file commit ids from parts metadata.
|
||||||
|
modTimes := listObjectModtimes(partsMetadata, errs)
|
||||||
|
|
||||||
|
// Count all latest updated FileInfo values
|
||||||
|
var count int
|
||||||
|
var latestFileInfo FileInfo
|
||||||
|
|
||||||
|
// Reduce list of UUIDs to a single common value - i.e. the last updated Time
|
||||||
|
modTime := commonTime(modTimes)
|
||||||
|
|
||||||
|
if modTime.IsZero() || modTime.Equal(timeSentinel) {
|
||||||
|
return FileInfo{}, errErasureReadQuorum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interate through all the modTimes and count the FileInfo(s) with latest time.
|
||||||
|
for index, t := range modTimes {
|
||||||
|
if partsMetadata[index].IsValid() && t.Equal(modTime) {
|
||||||
|
latestFileInfo = partsMetadata[index]
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !latestFileInfo.IsValid() {
|
||||||
|
return FileInfo{}, errErasureReadQuorum
|
||||||
|
}
|
||||||
|
|
||||||
|
if count < latestFileInfo.Erasure.DataBlocks {
|
||||||
|
return FileInfo{}, errErasureReadQuorum
|
||||||
|
}
|
||||||
|
|
||||||
|
return latestFileInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
// validates functionality provided to find most common
|
// validates functionality provided to find most common
|
||||||
// time occurrence from a list of time.
|
// time occurrence from a list of time.
|
||||||
func TestCommonTime(t *testing.T) {
|
func TestCommonTime(t *testing.T) {
|
||||||
|
@ -394,21 +394,73 @@ func writeUniqueFileInfo(ctx context.Context, disks []StorageAPI, bucket, prefix
|
|||||||
return evalDisks(disks, mErrs), err
|
return evalDisks(disks, mErrs), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func commonParity(parities []int) int {
|
||||||
|
occMap := make(map[int]int)
|
||||||
|
for _, p := range parities {
|
||||||
|
occMap[p]++
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxOcc, commonParity int
|
||||||
|
|
||||||
|
for parity, occ := range occMap {
|
||||||
|
if parity == -1 {
|
||||||
|
// Ignore non defined parity
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if occ >= maxOcc {
|
||||||
|
maxOcc = occ
|
||||||
|
commonParity = parity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if maxOcc == 0 {
|
||||||
|
// Did not found anything useful
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return commonParity
|
||||||
|
}
|
||||||
|
|
||||||
|
func listObjectParities(partsMetadata []FileInfo, errs []error) (parities []int) {
|
||||||
|
parities = make([]int, len(partsMetadata))
|
||||||
|
for index, metadata := range partsMetadata {
|
||||||
|
if errs[index] != nil {
|
||||||
|
parities[index] = -1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
parities[index] = metadata.Erasure.ParityBlocks
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Returns per object readQuorum and writeQuorum
|
// Returns per object readQuorum and writeQuorum
|
||||||
// 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) {
|
||||||
// get the latest updated Metadata and a count of all the latest updated FileInfo(s)
|
// There should be atleast half correct entries, if not return failure
|
||||||
latestFileInfo, err := getLatestFileInfo(ctx, partsMetaData, defaultParityCount, errs)
|
expectedRQuorum := len(partsMetaData) / 2
|
||||||
if err != nil {
|
if defaultParityCount == 0 {
|
||||||
return 0, 0, err
|
// if parity count is '0', we expected all entries to be present.
|
||||||
|
expectedRQuorum = len(partsMetaData)
|
||||||
|
}
|
||||||
|
|
||||||
|
reducedErr := reduceReadQuorumErrs(ctx, errs, objectOpIgnoredErrs, expectedRQuorum)
|
||||||
|
if reducedErr != nil {
|
||||||
|
return -1, -1, reducedErr
|
||||||
}
|
}
|
||||||
|
|
||||||
if latestFileInfo.Deleted {
|
|
||||||
// special case when parity is '0'
|
// special case when parity is '0'
|
||||||
if defaultParityCount == 0 {
|
if defaultParityCount == 0 {
|
||||||
return len(partsMetaData), len(partsMetaData), nil
|
return len(partsMetaData), len(partsMetaData), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parities := listObjectParities(partsMetaData, errs)
|
||||||
|
parityBlocks := commonParity(parities)
|
||||||
|
|
||||||
|
if parityBlocks < 0 {
|
||||||
|
return -1, -1, errErasureReadQuorum
|
||||||
|
}
|
||||||
|
|
||||||
|
if parityBlocks == 0 {
|
||||||
// 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.
|
||||||
@ -416,23 +468,7 @@ func objectQuorumFromMeta(ctx context.Context, partsMetaData []FileInfo, errs []
|
|||||||
return readQuorum, readQuorum + 1, nil
|
return readQuorum, readQuorum + 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parityBlocks := globalStorageClass.GetParityForSC(latestFileInfo.Metadata[xhttp.AmzStorageClass])
|
dataBlocks := len(partsMetaData) - parityBlocks
|
||||||
if parityBlocks < 0 {
|
|
||||||
parityBlocks = defaultParityCount
|
|
||||||
}
|
|
||||||
|
|
||||||
// For erasure code upgraded objects choose the parity
|
|
||||||
// blocks saved internally, instead of 'defaultParityCount'
|
|
||||||
if _, ok := latestFileInfo.Metadata[minIOErasureUpgraded]; ok {
|
|
||||||
if latestFileInfo.Erasure.ParityBlocks != 0 {
|
|
||||||
parityBlocks = latestFileInfo.Erasure.ParityBlocks
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dataBlocks := latestFileInfo.Erasure.DataBlocks
|
|
||||||
if dataBlocks == 0 {
|
|
||||||
dataBlocks = len(partsMetaData) - parityBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
writeQuorum := dataBlocks
|
writeQuorum := dataBlocks
|
||||||
if dataBlocks == parityBlocks {
|
if dataBlocks == parityBlocks {
|
||||||
|
Loading…
Reference in New Issue
Block a user