From ee028a4693eb09628e505ef9db6212e7b8c1b25b Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Wed, 18 Aug 2021 18:05:05 -0700 Subject: [PATCH] listObjects optimized to handle max-keys=1 when prefix is object (#13000) Some applications albeit poorly written rather than using headObject rely on listObjects to check for existence of object, this unusual request always has prefix=(to actual object) and max-keys=1 handle this situation specially such that we can avoid readdir() on the top level parent to avoid sorting and skipping, ensuring that such type of listObjects() always behaves similar to a headObject() call. --- cmd/bootstrap-peer-server.go | 4 +++- cmd/erasure-server-pool.go | 16 ++++++++++++++++ cmd/metacache-walk.go | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/cmd/bootstrap-peer-server.go b/cmd/bootstrap-peer-server.go index b528139e2..5d0e1a538 100644 --- a/cmd/bootstrap-peer-server.go +++ b/cmd/bootstrap-peer-server.go @@ -188,7 +188,9 @@ func verifyServerSystemConfig(ctx context.Context, endpointServerPools EndpointS // after 5 retries start logging that servers are not reachable yet if retries >= 5 { logger.Info(fmt.Sprintf("Waiting for atleast %d remote servers to be online for bootstrap check", len(clnts)/2)) - logger.Info(fmt.Sprintf("Following servers are currently offline or unreachable %s", offlineEndpoints)) + if len(offlineEndpoints) > 0 { + logger.Info(fmt.Sprintf("Following servers are currently offline or unreachable %s", offlineEndpoints)) + } retries = 0 // reset to log again after 5 retries. } offlineEndpoints = nil diff --git a/cmd/erasure-server-pool.go b/cmd/erasure-server-pool.go index 98a154e55..1c4cddad1 100644 --- a/cmd/erasure-server-pool.go +++ b/cmd/erasure-server-pool.go @@ -1060,6 +1060,22 @@ func maxKeysPlusOne(maxKeys int, addOne bool) int { func (z *erasureServerPools) ListObjects(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int) (ListObjectsInfo, error) { var loi ListObjectsInfo + + if len(prefix) > 0 && maxKeys == 1 && delimiter == "" && marker == "" { + // Optimization for certain applications like + // - Cohesity + // - Actifio, Splunk etc. + // which send ListObjects requests where the actual object + // itself is the prefix and max-keys=1 in such scenarios + // we can simply verify locally if such an object exists + // to avoid the need for ListObjects(). + objInfo, err := z.GetObjectInfo(ctx, bucket, prefix, ObjectOptions{NoLock: true}) + if err == nil { + loi.Objects = append(loi.Objects, objInfo) + return loi, nil + } + } + opts := listPathOptions{ Bucket: bucket, Prefix: prefix, diff --git a/cmd/metacache-walk.go b/cmd/metacache-walk.go index 2a0288a1e..e11d244fa 100644 --- a/cmd/metacache-walk.go +++ b/cmd/metacache-walk.go @@ -331,7 +331,7 @@ func (s *storageRESTServer) WalkDirHandler(w http.ResponseWriter, r *http.Reques } var reportNotFound bool - if v := vars[storageRESTReportNotFound]; v != "" { + if v := r.Form.Get(storageRESTReportNotFound); v != "" { reportNotFound, err = strconv.ParseBool(v) if err != nil { s.writeErrorResponse(w, err)