mirror of
https://github.com/minio/minio.git
synced 2024-12-24 06:05:55 -05:00
Relax minio server start when disk threshold is reached and adds space check in FS (#3865)
* fs: Rename tempObjPath variable in fsCreateFile() * fs/posix: Factor checkDiskFree() function * fs: Add disk free check in fsCreateFile() * posix: Move free disk check to createFile() * xl: Relax free disk check in POSIX initialization * fs: checkDiskFree checks for space to store data
This commit is contained in:
parent
29ff9674a0
commit
79e0b9e69a
@ -228,20 +228,24 @@ func fsOpenFile(readPath string, offset int64) (io.ReadCloser, int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates a file and copies data from incoming reader. Staging buffer is used by io.CopyBuffer.
|
// Creates a file and copies data from incoming reader. Staging buffer is used by io.CopyBuffer.
|
||||||
func fsCreateFile(tempObjPath string, reader io.Reader, buf []byte, fallocSize int64) (int64, error) {
|
func fsCreateFile(filePath string, reader io.Reader, buf []byte, fallocSize int64) (int64, error) {
|
||||||
if tempObjPath == "" || reader == nil || buf == nil {
|
if filePath == "" || reader == nil || buf == nil {
|
||||||
return 0, traceError(errInvalidArgument)
|
return 0, traceError(errInvalidArgument)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := checkPathLength(tempObjPath); err != nil {
|
if err := checkPathLength(filePath); err != nil {
|
||||||
return 0, traceError(err)
|
return 0, traceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mkdirAll(pathutil.Dir(tempObjPath), 0777); err != nil {
|
if err := mkdirAll(pathutil.Dir(filePath), 0777); err != nil {
|
||||||
return 0, traceError(err)
|
return 0, traceError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
writer, err := os.OpenFile(preparePath(tempObjPath), os.O_CREATE|os.O_WRONLY, 0666)
|
if err := checkDiskFree(pathutil.Dir(filePath), fallocSize); err != nil {
|
||||||
|
return 0, traceError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
writer, err := os.OpenFile(preparePath(filePath), os.O_CREATE|os.O_WRONLY, 0666)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// File path cannot be verified since one of the parents is a file.
|
// File path cannot be verified since one of the parents is a file.
|
||||||
if isSysErrNotDir(err) {
|
if isSysErrNotDir(err) {
|
||||||
|
46
cmd/fs-v1.go
46
cmd/fs-v1.go
@ -24,11 +24,9 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
|
||||||
"sort"
|
"sort"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
"github.com/minio/minio/pkg/disk"
|
|
||||||
"github.com/minio/minio/pkg/lock"
|
"github.com/minio/minio/pkg/lock"
|
||||||
"github.com/minio/sha256-simd"
|
"github.com/minio/sha256-simd"
|
||||||
)
|
)
|
||||||
@ -42,9 +40,6 @@ type fsObjects struct {
|
|||||||
// temporary transactions.
|
// temporary transactions.
|
||||||
fsUUID string
|
fsUUID string
|
||||||
|
|
||||||
minFreeSpace int64
|
|
||||||
minFreeInodes int64
|
|
||||||
|
|
||||||
// FS rw pool.
|
// FS rw pool.
|
||||||
rwPool *fsIOPool
|
rwPool *fsIOPool
|
||||||
|
|
||||||
@ -139,10 +134,8 @@ func newFSObjectLayer(fsPath string) (ObjectLayer, error) {
|
|||||||
|
|
||||||
// Initialize fs objects.
|
// Initialize fs objects.
|
||||||
fs := &fsObjects{
|
fs := &fsObjects{
|
||||||
fsPath: fsPath,
|
fsPath: fsPath,
|
||||||
fsUUID: fsUUID,
|
fsUUID: fsUUID,
|
||||||
minFreeSpace: fsMinFreeSpace,
|
|
||||||
minFreeInodes: fsMinFreeInodes,
|
|
||||||
rwPool: &fsIOPool{
|
rwPool: &fsIOPool{
|
||||||
readersMap: make(map[string]*lock.RLockedFile),
|
readersMap: make(map[string]*lock.RLockedFile),
|
||||||
},
|
},
|
||||||
@ -168,41 +161,6 @@ func newFSObjectLayer(fsPath string) (ObjectLayer, error) {
|
|||||||
return fs, nil
|
return fs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
|
|
||||||
func (fs fsObjects) checkDiskFree() (err error) {
|
|
||||||
// We don't validate disk space or inode utilization on windows.
|
|
||||||
// Each windows calls to 'GetVolumeInformationW' takes around 3-5seconds.
|
|
||||||
if runtime.GOOS == globalWindowsOSName {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var di disk.Info
|
|
||||||
di, err = getDiskInfo(preparePath(fs.fsPath))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove 5% from free space for cumulative disk space used for journalling, inodes etc.
|
|
||||||
availableDiskSpace := float64(di.Free) * 0.95
|
|
||||||
if int64(availableDiskSpace) <= fs.minFreeSpace {
|
|
||||||
return errDiskFull
|
|
||||||
}
|
|
||||||
|
|
||||||
// Some filesystems do not implement a way to provide total inodes available, instead inodes
|
|
||||||
// are allocated based on available disk space. For example CephFS, StoreNext CVFS, AzureFile driver.
|
|
||||||
// Allow for the available disk to be separately validate and we will validate inodes only if
|
|
||||||
// total inodes are provided by the underlying filesystem.
|
|
||||||
if di.Files != 0 && di.FSType != "NFS" {
|
|
||||||
availableFiles := int64(di.Ffree)
|
|
||||||
if availableFiles <= fs.minFreeInodes {
|
|
||||||
return errDiskFull
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should be called when process shuts down.
|
// Should be called when process shuts down.
|
||||||
func (fs fsObjects) Shutdown() error {
|
func (fs fsObjects) Shutdown() error {
|
||||||
// Cleanup and delete tmp uuid.
|
// Cleanup and delete tmp uuid.
|
||||||
|
30
cmd/posix.go
30
cmd/posix.go
@ -40,11 +40,9 @@ const (
|
|||||||
|
|
||||||
// posix - implements StorageAPI interface.
|
// posix - implements StorageAPI interface.
|
||||||
type posix struct {
|
type posix struct {
|
||||||
ioErrCount int32 // ref: https://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
ioErrCount int32 // ref: https://golang.org/pkg/sync/atomic/#pkg-note-BUG
|
||||||
diskPath string
|
diskPath string
|
||||||
minFreeSpace int64
|
pool sync.Pool
|
||||||
minFreeInodes int64
|
|
||||||
pool sync.Pool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkPathLength - returns error if given path name length more than 255
|
// checkPathLength - returns error if given path name length more than 255
|
||||||
@ -109,9 +107,7 @@ func newPosix(path string) (StorageAPI, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fs := &posix{
|
fs := &posix{
|
||||||
diskPath: diskPath,
|
diskPath: diskPath,
|
||||||
minFreeSpace: fsMinFreeSpace,
|
|
||||||
minFreeInodes: fsMinFreeInodes,
|
|
||||||
// 1MiB buffer pool for posix internal operations.
|
// 1MiB buffer pool for posix internal operations.
|
||||||
pool: sync.Pool{
|
pool: sync.Pool{
|
||||||
New: func() interface{} {
|
New: func() interface{} {
|
||||||
@ -133,9 +129,6 @@ func newPosix(path string) (StorageAPI, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err = fs.checkDiskFree(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return fs, nil
|
return fs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +154,7 @@ var ignoreDiskFreeOS = []string{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
|
// checkDiskFree verifies if disk path has sufficient minimum free disk space and files.
|
||||||
func (s *posix) checkDiskFree() (err error) {
|
func checkDiskFree(diskPath string, neededSpace int64) (err error) {
|
||||||
// We don't validate disk space or inode utilization on windows.
|
// We don't validate disk space or inode utilization on windows.
|
||||||
// Each windows calls to 'GetVolumeInformationW' takes around 3-5seconds.
|
// Each windows calls to 'GetVolumeInformationW' takes around 3-5seconds.
|
||||||
// And StatFS is not supported by Go for solaris and netbsd.
|
// And StatFS is not supported by Go for solaris and netbsd.
|
||||||
@ -170,14 +163,14 @@ func (s *posix) checkDiskFree() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var di disk.Info
|
var di disk.Info
|
||||||
di, err = getDiskInfo(preparePath(s.diskPath))
|
di, err = getDiskInfo(preparePath(diskPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove 5% from free space for cumulative disk space used for journalling, inodes etc.
|
// Remove 5% from free space for cumulative disk space used for journalling, inodes etc.
|
||||||
availableDiskSpace := float64(di.Free) * 0.95
|
availableDiskSpace := float64(di.Free) * 0.95
|
||||||
if int64(availableDiskSpace) <= s.minFreeSpace {
|
if int64(availableDiskSpace) <= fsMinFreeSpace {
|
||||||
return errDiskFull
|
return errDiskFull
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,11 +180,16 @@ func (s *posix) checkDiskFree() (err error) {
|
|||||||
// total inodes are provided by the underlying filesystem.
|
// total inodes are provided by the underlying filesystem.
|
||||||
if di.Files != 0 && di.FSType != "NFS" {
|
if di.Files != 0 && di.FSType != "NFS" {
|
||||||
availableFiles := int64(di.Ffree)
|
availableFiles := int64(di.Ffree)
|
||||||
if availableFiles <= s.minFreeInodes {
|
if availableFiles <= fsMinFreeInodes {
|
||||||
return errDiskFull
|
return errDiskFull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if we have enough space to store data
|
||||||
|
if neededSpace > int64(availableDiskSpace) {
|
||||||
|
return errDiskFull
|
||||||
|
}
|
||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -676,7 +674,7 @@ func (s *posix) PrepareFile(volume, path string, fileSize int64) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate if disk is indeed free.
|
// Validate if disk is indeed free.
|
||||||
if err = s.checkDiskFree(); err != nil {
|
if err = checkDiskFree(s.diskPath, fileSize); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user