Browse Source

fix(s3api): allow bucket recreation when orphaned collection exists (#8605)

* fix(s3api): allow bucket recreation when orphaned collection exists (#8601)

When a bucket is deleted, its filer directory is removed but the
underlying collection/volumes may not be fully cleaned up yet. If the
bucket is immediately recreated, PutBucketHandler was returning
ErrBucketAlreadyExists due to the orphaned collection, blocking bucket
recreation and causing subsequent uploads to fail with InternalError.

Allow bucket creation to proceed when a collection exists without a
corresponding bucket directory, since this is a transient orphaned state
from a previous deletion.

* fix(s3api): handle concurrent bucket creation race in mkdir

On mkdir failure, re-check whether the bucket directory now exists
and return BucketAlreadyExists instead of InternalError when another
request created the bucket concurrently.
pull/8607/head
Chris Lu 2 weeks ago
committed by GitHub
parent
commit
d1a631123f
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 15
      weed/s3api/s3api_bucket_handlers.go

15
weed/s3api/s3api_bucket_handlers.go

@ -251,11 +251,11 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
}
}
// If collection exists but bucket directory doesn't, this is an inconsistent state
// If collection exists but bucket directory doesn't, this is an orphaned state
// from a previous bucket deletion where volumes haven't been fully cleaned up yet.
// Allow the bucket to be recreated by proceeding with directory creation.
if collectionExists {
glog.Errorf("PutBucketHandler: collection exists but bucket directory missing for %s", bucket)
s3err.WriteErrorResponse(w, r, s3err.ErrBucketAlreadyExists)
return
glog.Warningf("PutBucketHandler: collection exists but bucket directory missing for %s, recreating bucket directory", bucket)
}
// Check for x-amz-bucket-object-lock-enabled header BEFORE creating bucket
@ -297,6 +297,13 @@ func (s3a *S3ApiServer) PutBucketHandler(w http.ResponseWriter, r *http.Request)
}
}
}); err != nil {
// If mkdir failed because another request created the bucket concurrently,
// return BucketAlreadyExists instead of InternalError.
if exist, checkErr := s3a.exists(s3a.option.BucketsPath, bucket, true); checkErr == nil && exist {
glog.V(3).Infof("PutBucketHandler: bucket %s was created concurrently", bucket)
s3err.WriteErrorResponse(w, r, s3err.ErrBucketAlreadyExists)
return
}
glog.Errorf("PutBucketHandler mkdir: %v", err)
s3err.WriteErrorResponse(w, r, s3err.ErrInternalError)
return

Loading…
Cancel
Save