|
|
@ -594,7 +594,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, |
|
|
|
// Delete temporary object in the event of failure.
|
|
|
|
// Delete temporary object in the event of failure.
|
|
|
|
// If PutObject succeeded there would be no temporary
|
|
|
|
// If PutObject succeeded there would be no temporary
|
|
|
|
// object to delete.
|
|
|
|
// object to delete.
|
|
|
|
defer xl.deleteObject(ctx, minioMetaTmpBucket, tempObj) |
|
|
|
defer xl.deleteObject(ctx, minioMetaTmpBucket, tempObj, writeQuorum, false) |
|
|
|
|
|
|
|
|
|
|
|
// This is a special case with size as '0' and object ends with
|
|
|
|
// This is a special case with size as '0' and object ends with
|
|
|
|
// a slash separator, we treat it like a valid operation and
|
|
|
|
// a slash separator, we treat it like a valid operation and
|
|
|
@ -763,7 +763,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, |
|
|
|
newUniqueID := mustGetUUID() |
|
|
|
newUniqueID := mustGetUUID() |
|
|
|
|
|
|
|
|
|
|
|
// Delete successfully renamed object.
|
|
|
|
// Delete successfully renamed object.
|
|
|
|
defer xl.deleteObject(ctx, minioMetaTmpBucket, newUniqueID) |
|
|
|
defer xl.deleteObject(ctx, minioMetaTmpBucket, newUniqueID, writeQuorum, false) |
|
|
|
|
|
|
|
|
|
|
|
// NOTE: Do not use online disks slice here.
|
|
|
|
// NOTE: Do not use online disks slice here.
|
|
|
|
// The reason is that existing object should be purged
|
|
|
|
// The reason is that existing object should be purged
|
|
|
@ -822,36 +822,32 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, |
|
|
|
// deleteObject - wrapper for delete object, deletes an object from
|
|
|
|
// deleteObject - wrapper for delete object, deletes an object from
|
|
|
|
// all the disks in parallel, including `xl.json` associated with the
|
|
|
|
// all the disks in parallel, including `xl.json` associated with the
|
|
|
|
// object.
|
|
|
|
// object.
|
|
|
|
func (xl xlObjects) deleteObject(ctx context.Context, bucket, object string) error { |
|
|
|
func (xl xlObjects) deleteObject(ctx context.Context, bucket, object string, writeQuorum int, isDir bool) error { |
|
|
|
// Initialize sync waitgroup.
|
|
|
|
var disks []StorageAPI |
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var writeQuorum int |
|
|
|
|
|
|
|
var err error |
|
|
|
var err error |
|
|
|
|
|
|
|
|
|
|
|
isDir := hasSuffix(object, slashSeparator) |
|
|
|
tmpObj := mustGetUUID() |
|
|
|
|
|
|
|
if bucket == minioMetaTmpBucket { |
|
|
|
if !isDir { |
|
|
|
tmpObj = object |
|
|
|
// Read metadata associated with the object from all disks.
|
|
|
|
disks = xl.getDisks() |
|
|
|
metaArr, errs := readAllXLMetadata(ctx, xl.getDisks(), bucket, object) |
|
|
|
} else { |
|
|
|
// get Quorum for this object
|
|
|
|
if isDir { |
|
|
|
_, writeQuorum, err = objectQuorumFromMeta(ctx, xl, metaArr, errs) |
|
|
|
disks, err = renameObjectDir(ctx, xl.getDisks(), bucket, object, minioMetaTmpBucket, tmpObj, writeQuorum) |
|
|
|
if err != nil { |
|
|
|
} else { |
|
|
|
return err |
|
|
|
disks, err = renameObject(ctx, xl.getDisks(), bucket, object, minioMetaTmpBucket, tmpObj, writeQuorum) |
|
|
|
} |
|
|
|
} |
|
|
|
err = reduceWriteQuorumErrs(ctx, errs, objectOpIgnoredErrs, writeQuorum) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
|
|
|
|
// WriteQuorum is defaulted to N/2 + 1 for directories
|
|
|
|
|
|
|
|
writeQuorum = len(xl.getDisks())/2 + 1 |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize sync waitgroup.
|
|
|
|
|
|
|
|
var wg = &sync.WaitGroup{} |
|
|
|
|
|
|
|
|
|
|
|
// Initialize list of errors.
|
|
|
|
// Initialize list of errors.
|
|
|
|
var dErrs = make([]error, len(xl.getDisks())) |
|
|
|
var dErrs = make([]error, len(disks)) |
|
|
|
|
|
|
|
|
|
|
|
for index, disk := range xl.getDisks() { |
|
|
|
for index, disk := range disks { |
|
|
|
if disk == nil { |
|
|
|
if disk == nil { |
|
|
|
dErrs[index] = errDiskNotFound |
|
|
|
dErrs[index] = errDiskNotFound |
|
|
|
continue |
|
|
|
continue |
|
|
@ -863,9 +859,9 @@ func (xl xlObjects) deleteObject(ctx context.Context, bucket, object string) err |
|
|
|
if isDir { |
|
|
|
if isDir { |
|
|
|
// DeleteFile() simply tries to remove a directory
|
|
|
|
// DeleteFile() simply tries to remove a directory
|
|
|
|
// and will succeed only if that directory is empty.
|
|
|
|
// and will succeed only if that directory is empty.
|
|
|
|
e = disk.DeleteFile(bucket, object) |
|
|
|
e = disk.DeleteFile(minioMetaTmpBucket, tmpObj) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
e = cleanupDir(ctx, disk, bucket, object) |
|
|
|
e = cleanupDir(ctx, disk, minioMetaTmpBucket, tmpObj) |
|
|
|
} |
|
|
|
} |
|
|
|
if e != nil && e != errVolumeNotFound { |
|
|
|
if e != nil && e != errVolumeNotFound { |
|
|
|
dErrs[index] = e |
|
|
|
dErrs[index] = e |
|
|
@ -897,18 +893,22 @@ func (xl xlObjects) DeleteObject(ctx context.Context, bucket, object string) (er |
|
|
|
|
|
|
|
|
|
|
|
if hasSuffix(object, slashSeparator) { |
|
|
|
if hasSuffix(object, slashSeparator) { |
|
|
|
// Delete the object on all disks.
|
|
|
|
// Delete the object on all disks.
|
|
|
|
if err = xl.deleteObject(ctx, bucket, object); err != nil { |
|
|
|
if err = xl.deleteObject(ctx, bucket, object, len(xl.getDisks())/2+1, true); err != nil { |
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Validate object exists.
|
|
|
|
// Read metadata associated with the object from all disks.
|
|
|
|
if !xl.isObject(bucket, object) { |
|
|
|
partsMetadata, errs := readAllXLMetadata(ctx, xl.getDisks(), bucket, object) |
|
|
|
return ObjectNotFound{bucket, object} |
|
|
|
|
|
|
|
} // else proceed to delete the object.
|
|
|
|
// get Quorum for this object
|
|
|
|
|
|
|
|
_, writeQuorum, err := objectQuorumFromMeta(ctx, xl, partsMetadata, errs) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Delete the object on all disks.
|
|
|
|
// Delete the object on all disks.
|
|
|
|
if err = xl.deleteObject(ctx, bucket, object); err != nil { |
|
|
|
if err = xl.deleteObject(ctx, bucket, object, writeQuorum, false); err != nil { |
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
return toObjectErr(err, bucket, object) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|