diff --git a/cmd/object-api-putobject_test.go b/cmd/object-api-putobject_test.go index 3a7884e27..3e889bfb9 100644 --- a/cmd/object-api-putobject_test.go +++ b/cmd/object-api-putobject_test.go @@ -179,11 +179,11 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl // Wrapper for calling PutObject tests for both XL multiple disks case // when quorum is not available. func TestObjectAPIPutObjectDiskNotFound(t *testing.T) { - ExecObjectLayerDiskAlteredTest(t, testObjectAPIPutObjectDiskNotFOund) + ExecObjectLayerDiskAlteredTest(t, testObjectAPIPutObjectDiskNotFound) } // Tests validate correctness of PutObject. -func testObjectAPIPutObjectDiskNotFOund(obj ObjectLayer, instanceType string, disks []string, t *testing.T) { +func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, disks []string, t *testing.T) { // Generating cases for which the PutObject fails. bucket := "minio-bucket" object := "minio-object" diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index fa3187695..a6816dbe4 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -648,11 +648,9 @@ func (xl xlObjects) PutObjectPart(bucket, object, uploadID string, partID int, s defer xl.deleteObject(minioMetaTmpBucket, tmpPart) if size > 0 { - for _, disk := range onlineDisks { - if disk != nil { - actualSize := xl.sizeOnDisk(size, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks) - disk.PrepareFile(minioMetaTmpBucket, tmpPartPath, actualSize) - } + if pErr := xl.prepareFile(minioMetaTmpBucket, tmpPartPath, size, onlineDisks, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks); err != nil { + return PartInfo{}, toObjectErr(pErr, bucket, object) + } } diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index 61d582330..0c85d3980 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -36,6 +36,25 @@ import ( // list all errors which can be ignored in object operations. var objectOpIgnoredErrs = append(baseIgnoredErrs, errDiskAccessDenied) +// prepareFile hints the bottom layer to optimize the creation of a new object +func (xl xlObjects) prepareFile(bucket, object string, size int64, onlineDisks []StorageAPI, blockSize int64, dataBlocks int) error { + pErrs := make([]error, len(onlineDisks)) + // Calculate the real size of the part in one disk. + actualSize := xl.sizeOnDisk(size, blockSize, dataBlocks) + // Prepare object creation in a all disks + for index, disk := range onlineDisks { + if disk != nil { + if err := disk.PrepareFile(bucket, object, actualSize); err != nil { + // Save error to reduce it later + pErrs[index] = err + // Ignore later access to disk which generated the error + onlineDisks[index] = nil + } + } + } + return reduceWriteQuorumErrs(pErrs, objectOpIgnoredErrs, xl.writeQuorum) +} + /// Object Operations // CopyObject - copy object source object to destination object. @@ -555,12 +574,9 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. // Hint the filesystem to pre-allocate one continuous large block. // This is only an optimization. if curPartSize > 0 { - // Calculate the real size of the part in the disk. - actualSize := xl.sizeOnDisk(curPartSize, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks) - for _, disk := range onlineDisks { - if disk != nil { - disk.PrepareFile(minioMetaTmpBucket, tempErasureObj, actualSize) - } + pErr := xl.prepareFile(minioMetaTmpBucket, tempErasureObj, curPartSize, onlineDisks, xlMeta.Erasure.BlockSize, xlMeta.Erasure.DataBlocks) + if pErr != nil { + return ObjectInfo{}, toObjectErr(pErr, bucket, object) } }