mirror of https://github.com/minio/minio.git
xl: avoid sending Delete() remote call for fully successful runs
an optimization to avoid extra syscalls in PutObject(), adds up to our PutObject response times.
This commit is contained in:
parent
906d68c356
commit
d7f32ad649
|
@ -276,7 +276,6 @@ func (er erasureObjects) ListMultipartUploads(ctx context.Context, bucket, objec
|
||||||
// disks. `uploads.json` carries metadata regarding on-going multipart
|
// disks. `uploads.json` carries metadata regarding on-going multipart
|
||||||
// operation(s) on the object.
|
// operation(s) on the object.
|
||||||
func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string, object string, opts ObjectOptions) (string, error) {
|
func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string, object string, opts ObjectOptions) (string, error) {
|
||||||
|
|
||||||
onlineDisks := er.getDisks()
|
onlineDisks := er.getDisks()
|
||||||
parityBlocks := globalStorageClass.GetParityForSC(opts.UserDefined[xhttp.AmzStorageClass])
|
parityBlocks := globalStorageClass.GetParityForSC(opts.UserDefined[xhttp.AmzStorageClass])
|
||||||
if parityBlocks <= 0 {
|
if parityBlocks <= 0 {
|
||||||
|
@ -317,7 +316,12 @@ func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string,
|
||||||
// Delete the tmp path later in case we fail to commit (ignore
|
// Delete the tmp path later in case we fail to commit (ignore
|
||||||
// returned errors) - this will be a no-op in case of a commit
|
// returned errors) - this will be a no-op in case of a commit
|
||||||
// success.
|
// success.
|
||||||
defer er.deleteObject(context.Background(), minioMetaTmpBucket, tempUploadIDPath, writeQuorum)
|
var online int
|
||||||
|
defer func() {
|
||||||
|
if online != len(onlineDisks) {
|
||||||
|
er.deleteObject(context.Background(), minioMetaTmpBucket, tempUploadIDPath, writeQuorum)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
var partsMetadata = make([]FileInfo, len(onlineDisks))
|
var partsMetadata = make([]FileInfo, len(onlineDisks))
|
||||||
for i := range onlineDisks {
|
for i := range onlineDisks {
|
||||||
|
@ -339,6 +343,8 @@ func (er erasureObjects) newMultipartUpload(ctx context.Context, bucket string,
|
||||||
return "", toObjectErr(err, minioMetaMultipartBucket, uploadIDPath)
|
return "", toObjectErr(err, minioMetaMultipartBucket, uploadIDPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
online = countOnlineDisks(onlineDisks)
|
||||||
|
|
||||||
// Return success.
|
// Return success.
|
||||||
return uploadID, nil
|
return uploadID, nil
|
||||||
}
|
}
|
||||||
|
@ -441,7 +447,12 @@ func (er erasureObjects) PutObjectPart(ctx context.Context, bucket, object, uplo
|
||||||
tmpPartPath := pathJoin(tmpPart, partSuffix)
|
tmpPartPath := pathJoin(tmpPart, partSuffix)
|
||||||
|
|
||||||
// Delete the temporary object part. If PutObjectPart succeeds there would be nothing to delete.
|
// Delete the temporary object part. If PutObjectPart succeeds there would be nothing to delete.
|
||||||
defer er.deleteObject(context.Background(), minioMetaTmpBucket, tmpPart, writeQuorum)
|
var online int
|
||||||
|
defer func() {
|
||||||
|
if online != len(onlineDisks) {
|
||||||
|
er.deleteObject(context.Background(), minioMetaTmpBucket, tmpPart, writeQuorum)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
erasure, err := NewErasure(ctx, fi.Erasure.DataBlocks, fi.Erasure.ParityBlocks, fi.Erasure.BlockSize)
|
erasure, err := NewErasure(ctx, fi.Erasure.DataBlocks, fi.Erasure.ParityBlocks, fi.Erasure.BlockSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -563,6 +574,8 @@ func (er erasureObjects) PutObjectPart(ctx context.Context, bucket, object, uplo
|
||||||
return pi, toObjectErr(err, minioMetaMultipartBucket, uploadIDPath)
|
return pi, toObjectErr(err, minioMetaMultipartBucket, uploadIDPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
online = countOnlineDisks(onlineDisks)
|
||||||
|
|
||||||
// Return success.
|
// Return success.
|
||||||
return PartInfo{
|
return PartInfo{
|
||||||
PartNumber: partID,
|
PartNumber: partID,
|
||||||
|
|
|
@ -42,6 +42,15 @@ var objectOpIgnoredErrs = append(baseIgnoredErrs, errDiskAccessDenied, errUnform
|
||||||
|
|
||||||
/// Object Operations
|
/// Object Operations
|
||||||
|
|
||||||
|
func countOnlineDisks(onlineDisks []StorageAPI) (online int) {
|
||||||
|
for _, onlineDisk := range onlineDisks {
|
||||||
|
if onlineDisk != nil && onlineDisk.IsOnline() {
|
||||||
|
online++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return online
|
||||||
|
}
|
||||||
|
|
||||||
// CopyObject - copy object source object to destination object.
|
// CopyObject - copy object source object to destination object.
|
||||||
// if source object and destination object are same we only
|
// if source object and destination object are same we only
|
||||||
// update metadata.
|
// update metadata.
|
||||||
|
@ -116,8 +125,13 @@ func (er erasureObjects) CopyObject(ctx context.Context, srcBucket, srcObject, d
|
||||||
|
|
||||||
tempObj := mustGetUUID()
|
tempObj := mustGetUUID()
|
||||||
|
|
||||||
|
var online int
|
||||||
// Cleanup in case of xl.meta writing failure
|
// Cleanup in case of xl.meta writing failure
|
||||||
defer er.deleteObject(context.Background(), minioMetaTmpBucket, tempObj, writeQuorum)
|
defer func() {
|
||||||
|
if online != len(onlineDisks) {
|
||||||
|
er.deleteObject(context.Background(), minioMetaTmpBucket, tempObj, writeQuorum)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Write unique `xl.meta` for each disk.
|
// Write unique `xl.meta` for each disk.
|
||||||
if onlineDisks, err = writeUniqueFileInfo(ctx, onlineDisks, minioMetaTmpBucket, tempObj, metaArr, writeQuorum); err != nil {
|
if onlineDisks, err = writeUniqueFileInfo(ctx, onlineDisks, minioMetaTmpBucket, tempObj, metaArr, writeQuorum); err != nil {
|
||||||
|
@ -129,6 +143,8 @@ func (er erasureObjects) CopyObject(ctx context.Context, srcBucket, srcObject, d
|
||||||
return oi, toObjectErr(err, srcBucket, srcObject)
|
return oi, toObjectErr(err, srcBucket, srcObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
online = countOnlineDisks(onlineDisks)
|
||||||
|
|
||||||
return fi.ToObjectInfo(srcBucket, srcObject), nil
|
return fi.ToObjectInfo(srcBucket, srcObject), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -641,11 +657,6 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||||
writeQuorum++
|
writeQuorum++
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete temporary object in the event of failure.
|
|
||||||
// If PutObject succeeded there would be no temporary
|
|
||||||
// object to delete.
|
|
||||||
defer er.deleteObject(context.Background(), minioMetaTmpBucket, tempObj, writeQuorum)
|
|
||||||
|
|
||||||
// Validate input data size and it can never be less than zero.
|
// Validate input data size and it can never be less than zero.
|
||||||
if data.Size() < -1 {
|
if data.Size() < -1 {
|
||||||
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
logger.LogIf(ctx, errInvalidArgument, logger.Application)
|
||||||
|
@ -713,6 +724,16 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||||
partName := "part.1"
|
partName := "part.1"
|
||||||
tempErasureObj := pathJoin(uniqueID, fi.DataDir, partName)
|
tempErasureObj := pathJoin(uniqueID, fi.DataDir, partName)
|
||||||
|
|
||||||
|
// Delete temporary object in the event of failure.
|
||||||
|
// If PutObject succeeded there would be no temporary
|
||||||
|
// object to delete.
|
||||||
|
var online int
|
||||||
|
defer func() {
|
||||||
|
if online != len(onlineDisks) {
|
||||||
|
er.deleteObject(context.Background(), minioMetaTmpBucket, tempObj, writeQuorum)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
writers := make([]io.Writer, len(onlineDisks))
|
writers := make([]io.Writer, len(onlineDisks))
|
||||||
for i, disk := range onlineDisks {
|
for i, disk := range onlineDisks {
|
||||||
if disk == nil {
|
if disk == nil {
|
||||||
|
@ -806,6 +827,7 @@ func (er erasureObjects) putObject(ctx context.Context, bucket string, object st
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
online = countOnlineDisks(onlineDisks)
|
||||||
|
|
||||||
return fi.ToObjectInfo(bucket, object), nil
|
return fi.ToObjectInfo(bucket, object), nil
|
||||||
}
|
}
|
||||||
|
@ -859,8 +881,8 @@ func (er erasureObjects) deleteObject(ctx context.Context, bucket, object string
|
||||||
var err error
|
var err error
|
||||||
defer ObjectPathUpdated(pathJoin(bucket, object))
|
defer ObjectPathUpdated(pathJoin(bucket, object))
|
||||||
|
|
||||||
tmpObj := mustGetUUID()
|
|
||||||
disks := er.getDisks()
|
disks := er.getDisks()
|
||||||
|
tmpObj := mustGetUUID()
|
||||||
if bucket == minioMetaTmpBucket {
|
if bucket == minioMetaTmpBucket {
|
||||||
tmpObj = object
|
tmpObj = object
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -177,15 +176,15 @@ func (st *HTTPStats) updateStats(api string, r *http.Request, w *logger.Response
|
||||||
!strings.HasSuffix(r.URL.Path, prometheusMetricsV2ClusterPath) ||
|
!strings.HasSuffix(r.URL.Path, prometheusMetricsV2ClusterPath) ||
|
||||||
!strings.HasSuffix(r.URL.Path, prometheusMetricsV2NodePath) {
|
!strings.HasSuffix(r.URL.Path, prometheusMetricsV2NodePath) {
|
||||||
st.totalS3Requests.Inc(api)
|
st.totalS3Requests.Inc(api)
|
||||||
if !successReq && w.StatusCode != 0 {
|
if !successReq {
|
||||||
|
switch w.StatusCode {
|
||||||
|
case 0:
|
||||||
|
case 499:
|
||||||
|
// 499 is a good error, shall be counted at canceled.
|
||||||
|
st.totalS3Canceled.Inc(api)
|
||||||
|
default:
|
||||||
st.totalS3Errors.Inc(api)
|
st.totalS3Errors.Inc(api)
|
||||||
}
|
}
|
||||||
select {
|
|
||||||
case <-r.Context().Done():
|
|
||||||
if err := r.Context().Err(); err == context.Canceled {
|
|
||||||
st.totalS3Canceled.Inc(api)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ const (
|
||||||
versionInfo MetricName = "version_info"
|
versionInfo MetricName = "version_info"
|
||||||
|
|
||||||
sizeDistribution = "size_distribution"
|
sizeDistribution = "size_distribution"
|
||||||
ttfbDistribution = "ttbf_seconds_distribution"
|
ttfbDistribution = "ttfb_seconds_distribution"
|
||||||
|
|
||||||
lastActivityTime = "last_activity_nano_seconds"
|
lastActivityTime = "last_activity_nano_seconds"
|
||||||
startTime = "starttime_seconds"
|
startTime = "starttime_seconds"
|
||||||
|
|
|
@ -832,7 +832,7 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F
|
||||||
if !isXL2V1Format(buf) {
|
if !isXL2V1Format(buf) {
|
||||||
// Delete the meta file, if there are no more versions the
|
// Delete the meta file, if there are no more versions the
|
||||||
// top level parent is automatically removed.
|
// top level parent is automatically removed.
|
||||||
return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true, volume == minioMetaTmpBucket)
|
return s.deleteFile(volumeDir, pathJoin(volumeDir, path), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
var xlMeta xlMetaV2
|
var xlMeta xlMetaV2
|
||||||
|
@ -878,7 +878,7 @@ func (s *xlStorage) DeleteVersion(ctx context.Context, volume, path string, fi F
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.deleteFile(volumeDir, filePath, false, volume == minioMetaTmpBucket)
|
return s.deleteFile(volumeDir, filePath, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteMetadata - writes FileInfo metadata for path at `xl.meta`
|
// WriteMetadata - writes FileInfo metadata for path at `xl.meta`
|
||||||
|
@ -1664,7 +1664,7 @@ func (s *xlStorage) CheckFile(ctx context.Context, volume string, path string) e
|
||||||
// move up the tree, deleting empty parent directories until it finds one
|
// move up the tree, deleting empty parent directories until it finds one
|
||||||
// with files in it. Returns nil for a non-empty directory even when
|
// with files in it. Returns nil for a non-empty directory even when
|
||||||
// recursive is set to false.
|
// recursive is set to false.
|
||||||
func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool, tmpbucket bool) error {
|
func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool) error {
|
||||||
if basePath == "" || deletePath == "" {
|
if basePath == "" || deletePath == "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1677,11 +1677,7 @@ func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool, tmpb
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if recursive {
|
if recursive {
|
||||||
if tmpbucket {
|
|
||||||
err = removeAll(deletePath)
|
|
||||||
} else {
|
|
||||||
err = renameAll(deletePath, pathutil.Join(s.diskPath, minioMetaTmpDeletedBucket, mustGetUUID()))
|
err = renameAll(deletePath, pathutil.Join(s.diskPath, minioMetaTmpDeletedBucket, mustGetUUID()))
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
err = Remove(deletePath)
|
err = Remove(deletePath)
|
||||||
}
|
}
|
||||||
|
@ -1712,7 +1708,7 @@ func (s *xlStorage) deleteFile(basePath, deletePath string, recursive bool, tmpb
|
||||||
|
|
||||||
// Delete parent directory obviously not recursively. Errors for
|
// Delete parent directory obviously not recursively. Errors for
|
||||||
// parent directories shouldn't trickle down.
|
// parent directories shouldn't trickle down.
|
||||||
s.deleteFile(basePath, deletePath, false, tmpbucket)
|
s.deleteFile(basePath, deletePath, false)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -1745,7 +1741,7 @@ func (s *xlStorage) Delete(ctx context.Context, volume string, path string, recu
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete file and delete parent directory as well if it's empty.
|
// Delete file and delete parent directory as well if it's empty.
|
||||||
return s.deleteFile(volumeDir, filePath, recursive, volume == minioMetaTmpBucket)
|
return s.deleteFile(volumeDir, filePath, recursive)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenameData - rename source path to destination path atomically, metadata and data directory.
|
// RenameData - rename source path to destination path atomically, metadata and data directory.
|
||||||
|
@ -1987,7 +1983,7 @@ func (s *xlStorage) RenameData(ctx context.Context, srcVolume, srcPath, dataDir,
|
||||||
|
|
||||||
// Remove parent dir of the source file if empty
|
// Remove parent dir of the source file if empty
|
||||||
parentDir := pathutil.Dir(srcFilePath)
|
parentDir := pathutil.Dir(srcFilePath)
|
||||||
s.deleteFile(srcVolumeDir, parentDir, false, srcVolume == minioMetaTmpBucket)
|
s.deleteFile(srcVolumeDir, parentDir, false)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2066,7 +2062,7 @@ func (s *xlStorage) RenameFile(ctx context.Context, srcVolume, srcPath, dstVolum
|
||||||
|
|
||||||
// Remove parent dir of the source file if empty
|
// Remove parent dir of the source file if empty
|
||||||
parentDir := pathutil.Dir(srcFilePath)
|
parentDir := pathutil.Dir(srcFilePath)
|
||||||
s.deleteFile(srcVolumeDir, parentDir, false, srcVolume == minioMetaTmpBucket)
|
s.deleteFile(srcVolumeDir, parentDir, false)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue