mirror of
https://github.com/minio/minio.git
synced 2025-11-07 12:52:58 -05:00
skip inconsistent shards if possible (#13945)
data shards were wrong due to a healing bug reported in #13803 mainly with unaligned object sizes. This PR is an attempt to automatically avoid these shards, with available information about the `xl.meta` and actually disk mtime.
This commit is contained in:
@@ -375,32 +375,39 @@ func (s *xlStorage) Healing() *healingTracker {
|
||||
return &h
|
||||
}
|
||||
|
||||
func (s *xlStorage) readMetadata(ctx context.Context, itemPath string) ([]byte, error) {
|
||||
// readsMetadata and returns disk mTime information for xl.meta
|
||||
func (s *xlStorage) readMetadataWithDMTime(ctx context.Context, itemPath string) ([]byte, time.Time, error) {
|
||||
if contextCanceled(ctx) {
|
||||
return nil, ctx.Err()
|
||||
return nil, time.Time{}, ctx.Err()
|
||||
}
|
||||
|
||||
if err := checkPathLength(itemPath); err != nil {
|
||||
return nil, err
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
|
||||
f, err := OpenFile(itemPath, readMode, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
defer f.Close()
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
if stat.IsDir() {
|
||||
return nil, &os.PathError{
|
||||
return nil, time.Time{}, &os.PathError{
|
||||
Op: "open",
|
||||
Path: itemPath,
|
||||
Err: syscall.EISDIR,
|
||||
}
|
||||
}
|
||||
return readXLMetaNoData(f, stat.Size())
|
||||
buf, err := readXLMetaNoData(f, stat.Size())
|
||||
return buf, stat.ModTime().UTC(), err
|
||||
}
|
||||
|
||||
func (s *xlStorage) readMetadata(ctx context.Context, itemPath string) ([]byte, error) {
|
||||
buf, _, err := s.readMetadataWithDMTime(ctx, itemPath)
|
||||
return buf, err
|
||||
}
|
||||
|
||||
func (s *xlStorage) NSScanner(ctx context.Context, cache dataUsageCache, updates chan<- dataUsageEntry) (dataUsageCache, error) {
|
||||
@@ -1214,11 +1221,18 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
if err != nil {
|
||||
return fi, err
|
||||
}
|
||||
// Validate file path length, before reading.
|
||||
filePath := pathJoin(volumeDir, path)
|
||||
if err = checkPathLength(filePath); err != nil {
|
||||
return fi, err
|
||||
}
|
||||
|
||||
var buf []byte
|
||||
var dmTime time.Time
|
||||
if readData {
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFile))
|
||||
buf, dmTime, err = s.readAllData(ctx, volumeDir, pathJoin(filePath, xlStorageFormatFile))
|
||||
} else {
|
||||
buf, err = s.readMetadata(ctx, pathJoin(volumeDir, path, xlStorageFormatFile))
|
||||
buf, dmTime, err = s.readMetadataWithDMTime(ctx, pathJoin(filePath, xlStorageFormatFile))
|
||||
if err != nil {
|
||||
if osIsNotExist(err) {
|
||||
if aerr := Access(volumeDir); aerr != nil && osIsNotExist(aerr) {
|
||||
@@ -1231,7 +1245,7 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
|
||||
if err != nil {
|
||||
if err == errFileNotFound {
|
||||
buf, err = s.ReadAll(ctx, volume, pathJoin(path, xlStorageFormatFileV1))
|
||||
buf, dmTime, err = s.readAllData(ctx, volumeDir, pathJoin(filePath, xlStorageFormatFileV1))
|
||||
if err != nil {
|
||||
if err == errFileNotFound {
|
||||
if versionID != "" {
|
||||
@@ -1257,6 +1271,7 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
if err != nil {
|
||||
return fi, err
|
||||
}
|
||||
fi.DiskMTime = dmTime
|
||||
|
||||
if len(fi.Data) == 0 {
|
||||
// We did not read inline data, so we have no references.
|
||||
@@ -1299,7 +1314,7 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
len(fi.Parts) == 1 {
|
||||
partPath := fmt.Sprintf("part.%d", fi.Parts[0].Number)
|
||||
dataPath := pathJoin(volumeDir, path, fi.DataDir, partPath)
|
||||
fi.Data, err = s.readAllData(volumeDir, dataPath)
|
||||
fi.Data, _, err = s.readAllData(ctx, volumeDir, dataPath)
|
||||
if err != nil {
|
||||
return FileInfo{}, err
|
||||
}
|
||||
@@ -1309,38 +1324,42 @@ func (s *xlStorage) ReadVersion(ctx context.Context, volume, path, versionID str
|
||||
return fi, nil
|
||||
}
|
||||
|
||||
func (s *xlStorage) readAllData(volumeDir string, filePath string) (buf []byte, err error) {
|
||||
func (s *xlStorage) readAllData(ctx context.Context, volumeDir string, filePath string) (buf []byte, dmTime time.Time, err error) {
|
||||
if contextCanceled(ctx) {
|
||||
return nil, time.Time{}, ctx.Err()
|
||||
}
|
||||
|
||||
f, err := OpenFileDirectIO(filePath, readMode, 0666)
|
||||
if err != nil {
|
||||
if osIsNotExist(err) {
|
||||
// Check if the object doesn't exist because its bucket
|
||||
// is missing in order to return the correct error.
|
||||
if err = Access(volumeDir); err != nil && osIsNotExist(err) {
|
||||
return nil, errVolumeNotFound
|
||||
return nil, dmTime, errVolumeNotFound
|
||||
}
|
||||
return nil, errFileNotFound
|
||||
return nil, dmTime, errFileNotFound
|
||||
} else if osIsPermission(err) {
|
||||
return nil, errFileAccessDenied
|
||||
return nil, dmTime, errFileAccessDenied
|
||||
} else if isSysErrNotDir(err) || isSysErrIsDir(err) {
|
||||
return nil, errFileNotFound
|
||||
return nil, dmTime, errFileNotFound
|
||||
} else if isSysErrHandleInvalid(err) {
|
||||
// This case is special and needs to be handled for windows.
|
||||
return nil, errFileNotFound
|
||||
return nil, dmTime, errFileNotFound
|
||||
} else if isSysErrIO(err) {
|
||||
return nil, errFaultyDisk
|
||||
return nil, dmTime, errFaultyDisk
|
||||
} else if isSysErrTooManyFiles(err) {
|
||||
return nil, errTooManyOpenFiles
|
||||
return nil, dmTime, errTooManyOpenFiles
|
||||
} else if isSysErrInvalidArg(err) {
|
||||
st, _ := Lstat(filePath)
|
||||
if st != nil && st.IsDir() {
|
||||
// Linux returns InvalidArg for directory O_DIRECT
|
||||
// we need to keep this fallback code to return correct
|
||||
// errors upwards.
|
||||
return nil, errFileNotFound
|
||||
return nil, dmTime, errFileNotFound
|
||||
}
|
||||
return nil, errUnsupportedDisk
|
||||
return nil, dmTime, errUnsupportedDisk
|
||||
}
|
||||
return nil, err
|
||||
return nil, dmTime, err
|
||||
}
|
||||
r := &xioutil.ODirectReader{
|
||||
File: f,
|
||||
@@ -1352,10 +1371,10 @@ func (s *xlStorage) readAllData(volumeDir string, filePath string) (buf []byte,
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
buf, err = ioutil.ReadAll(r)
|
||||
return buf, osErrToFileErr(err)
|
||||
return buf, dmTime, osErrToFileErr(err)
|
||||
}
|
||||
if stat.IsDir() {
|
||||
return nil, errFileNotFound
|
||||
return nil, dmTime, errFileNotFound
|
||||
}
|
||||
|
||||
// Read into appropriate buffer.
|
||||
@@ -1369,7 +1388,7 @@ func (s *xlStorage) readAllData(volumeDir string, filePath string) (buf []byte,
|
||||
// Read file...
|
||||
_, err = io.ReadFull(r, buf)
|
||||
|
||||
return buf, osErrToFileErr(err)
|
||||
return buf, stat.ModTime().UTC(), osErrToFileErr(err)
|
||||
}
|
||||
|
||||
// ReadAll reads from r until an error or EOF and returns the data it read.
|
||||
@@ -1390,7 +1409,8 @@ func (s *xlStorage) ReadAll(ctx context.Context, volume string, path string) (bu
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s.readAllData(volumeDir, filePath)
|
||||
buf, _, err = s.readAllData(ctx, volumeDir, filePath)
|
||||
return buf, err
|
||||
}
|
||||
|
||||
// ReadFile reads exactly len(buf) bytes into buf. It returns the
|
||||
|
||||
Reference in New Issue
Block a user