From 8e379d1415fe02fdf2b7bf8c628d6fee1d3a425b Mon Sep 17 00:00:00 2001 From: chrislu Date: Sun, 16 Nov 2025 13:28:25 -0800 Subject: [PATCH] skip retry if object is not found --- weed/s3api/s3api_object_handlers.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/weed/s3api/s3api_object_handlers.go b/weed/s3api/s3api_object_handlers.go index 7371ef0a9..8a3715560 100644 --- a/weed/s3api/s3api_object_handlers.go +++ b/weed/s3api/s3api_object_handlers.go @@ -358,10 +358,10 @@ func (s3a *S3ApiServer) GetObjectHandler(w http.ResponseWriter, r *http.Request) bucketDir := s3a.option.BucketsPath + "/" + bucket normalizedObject := removeDuplicateSlashes(object) versionsDir := normalizedObject + s3_constants.VersionsFolder - + // Quick check (no retries) for .versions/ directory versionsEntry, versionsErr := s3a.getEntry(bucketDir, versionsDir) - + if versionsErr == nil && versionsEntry != nil { // .versions/ exists, meaning real versions are stored there // Use getLatestObjectVersion which will properly find the newest version @@ -1273,7 +1273,8 @@ func (s3a *S3ApiServer) HeadObjectHandler(w http.ResponseWriter, r *http.Request // Request for latest version - OPTIMIZATION: // Check if .versions/ directory exists quickly (no retries) to decide path // - If .versions/ exists: real versions available, use getLatestObjectVersion - // - If .versions/ doesn't exist: only null version at regular path, use it directly + // - If .versions/ doesn't exist (ErrNotFound): only null version at regular path, use it directly + // - If transient error: fall back to getLatestObjectVersion which has retry logic bucketDir := s3a.option.BucketsPath + "/" + bucket normalizedObject := removeDuplicateSlashes(object) versionsDir := normalizedObject + s3_constants.VersionsFolder @@ -1290,8 +1291,8 @@ func (s3a *S3ApiServer) HeadObjectHandler(w http.ResponseWriter, r *http.Request s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey) return } - } else { - // .versions/ doesn't exist, check regular path for null version + } else if errors.Is(versionsErr, filer_pb.ErrNotFound) { + // .versions/ doesn't exist (confirmed not found), check regular path for null version regularEntry, regularErr := s3a.getEntry(bucketDir, normalizedObject) if regularErr == nil && regularEntry != nil { // Found object at regular path - this is the null version @@ -1303,6 +1304,15 @@ func (s3a *S3ApiServer) HeadObjectHandler(w http.ResponseWriter, r *http.Request s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey) return } + } else { + // Transient error checking .versions/, fall back to getLatestObjectVersion with retries + glog.V(2).Infof("HeadObject: transient error checking .versions for %s%s: %v, falling back to getLatestObjectVersion", bucket, object, versionsErr) + entry, err = s3a.getLatestObjectVersion(bucket, object) + if err != nil { + glog.Errorf("HeadObject: Failed to get latest version for %s%s: %v", bucket, object, err) + s3err.WriteErrorResponse(w, r, s3err.ErrNoSuchKey) + return + } } // Safety check: entry must be valid after successful retrieval if entry == nil {