From 50c328ff1914999827cbe00cf71ce7085ea8d686 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 20 May 2016 01:56:46 -0700 Subject: [PATCH] XL: RenameFile should rename and cleanup on writeQuorum. (#1702) Fixes #1683 --- xl-erasure-v1.go | 73 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 53 insertions(+), 20 deletions(-) diff --git a/xl-erasure-v1.go b/xl-erasure-v1.go index f1fae87d1..8ef430db4 100644 --- a/xl-erasure-v1.go +++ b/xl-erasure-v1.go @@ -511,15 +511,8 @@ func (xl XL) StatFile(volume, path string) (FileInfo, error) { }, nil } -// DeleteFile - delete a file -func (xl XL) DeleteFile(volume, path string) error { - if !isValidVolname(volume) { - return errInvalidArgument - } - if !isValidPath(path) { - return errInvalidArgument - } - +// deleteXLFiles - delete all XL backend files. +func (xl XL) deleteXLFiles(volume, path string) error { errCount := 0 // Update meta data file and remove part file for index, disk := range xl.storageDisks { @@ -551,11 +544,23 @@ func (xl XL) DeleteFile(volume, path string) error { return err } } - // Return success. return nil } +// DeleteFile - delete a file +func (xl XL) DeleteFile(volume, path string) error { + if !isValidVolname(volume) { + return errInvalidArgument + } + if !isValidPath(path) { + return errInvalidArgument + } + + // Delete all XL files. + return xl.deleteXLFiles(volume, path) +} + // RenameFile - rename file. func (xl XL) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) error { // Validate inputs. @@ -572,21 +577,49 @@ func (xl XL) RenameFile(srcVolume, srcPath, dstVolume, dstPath string) error { return errInvalidArgument } - errCount := 0 - for _, disk := range xl.storageDisks { + // Initialize sync waitgroup. + var wg = &sync.WaitGroup{} + + // Initialize list of errors. + var errs = make([]error, len(xl.storageDisks)) + + // Rename file on all underlying storage disks. + for index, disk := range xl.storageDisks { // Append "/" as srcPath and dstPath are either leaf-dirs or non-leaf-dris. // If srcPath is an object instead of prefix we just rename the leaf-dir and // not rename the part and metadata files separately. - err := disk.RenameFile(srcVolume, retainSlash(srcPath), dstVolume, retainSlash(dstPath)) - if err != nil { - errCount++ - // We can safely allow RenameFile errors up to len(xl.storageDisks) - xl.writeQuorum - // otherwise return failure. - if errCount <= len(xl.storageDisks)-xl.writeQuorum { - continue + wg.Add(1) + go func(index int, disk StorageAPI) { + defer wg.Done() + err := disk.RenameFile(srcVolume, retainSlash(srcPath), dstVolume, retainSlash(dstPath)) + if err != nil { + errs[index] = err } - return err + errs[index] = nil + }(index, disk) + } + + // Wait for all RenameFile to finish. + wg.Wait() + + // Gather err count. + var errCount = 0 + for _, err := range errs { + if err == nil { + continue } + errCount++ + } + // We can safely allow RenameFile errors up to len(xl.storageDisks) - xl.writeQuorum + // otherwise return failure. Cleanup successful renames. + if errCount > len(xl.storageDisks)-xl.writeQuorum { + // Special condition if readQuorum exists, then return success. + if errCount <= len(xl.storageDisks)-xl.readQuorum { + return nil + } + // Ignore errors here, delete all successfully written files. + xl.deleteXLFiles(dstVolume, dstPath) + return errWriteQuorum } return nil }