aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchrislu <chris.lu@gmail.com>2025-11-05 16:03:07 -0800
committerchrislu <chris.lu@gmail.com>2025-11-05 16:03:07 -0800
commit06e9ca70a64118622fd66f242f72ac03d4bcc811 (patch)
treecabab9f64074e98541433257d92e9507a5a19a9c
parentc125060b51c81205ebe5df23e2c24ae7831082d6 (diff)
downloadseaweedfs-06e9ca70a64118622fd66f242f72ac03d4bcc811.tar.xz
seaweedfs-06e9ca70a64118622fd66f242f72ac03d4bcc811.zip
refactoring
-rw-r--r--weed/pb/filer_pb/filer_client.go55
-rw-r--r--weed/s3api/s3api_object_handlers_delete.go60
2 files changed, 57 insertions, 58 deletions
diff --git a/weed/pb/filer_pb/filer_client.go b/weed/pb/filer_pb/filer_client.go
index 80adab292..a4e875033 100644
--- a/weed/pb/filer_pb/filer_client.go
+++ b/weed/pb/filer_pb/filer_client.go
@@ -308,3 +308,58 @@ func DoRemove(ctx context.Context, client SeaweedFilerClient, parentDirectoryPat
return nil
}
+
+// DoDeleteEmptyParentDirectories recursively deletes empty parent directories.
+// It stops at root "/" or at stopAtPath.
+// For safety, dirPath must be under stopAtPath (when stopAtPath is provided).
+// The checked map tracks already-processed directories to avoid redundant work in batch operations.
+func DoDeleteEmptyParentDirectories(ctx context.Context, client SeaweedFilerClient, dirPath util.FullPath, stopAtPath util.FullPath, checked map[string]bool) {
+ if dirPath == "/" || dirPath == stopAtPath {
+ return
+ }
+
+ // Skip if already checked (for batch delete optimization)
+ dirPathStr := string(dirPath)
+ if checked != nil {
+ if checked[dirPathStr] {
+ return
+ }
+ checked[dirPathStr] = true
+ }
+
+ // Safety check: if stopAtPath is provided, dirPath must be under it
+ if stopAtPath != "" && !strings.HasPrefix(dirPathStr+"/", string(stopAtPath)+"/") {
+ glog.V(1).InfofCtx(ctx, "DoDeleteEmptyParentDirectories: %s is not under %s, skipping", dirPath, stopAtPath)
+ return
+ }
+
+ // Check if directory is empty by listing with limit 1
+ isEmpty := true
+ err := SeaweedList(ctx, client, dirPathStr, "", func(entry *Entry, isLast bool) error {
+ isEmpty = false
+ return io.EOF // Use sentinel error to explicitly stop iteration
+ }, "", false, 1)
+
+ if err != nil && err != io.EOF {
+ glog.V(3).InfofCtx(ctx, "DoDeleteEmptyParentDirectories: error checking %s: %v", dirPath, err)
+ return
+ }
+
+ if !isEmpty {
+ // Directory is not empty, stop checking upward
+ glog.V(3).InfofCtx(ctx, "DoDeleteEmptyParentDirectories: directory %s is not empty, stopping cleanup", dirPath)
+ return
+ }
+
+ // Directory is empty, try to delete it
+ glog.V(2).InfofCtx(ctx, "DoDeleteEmptyParentDirectories: deleting empty directory %s", dirPath)
+ parentDir, dirName := dirPath.DirAndName()
+
+ if err := DoRemove(ctx, client, parentDir, dirName, false, false, false, false, nil); err == nil {
+ // Successfully deleted, continue checking upwards
+ DoDeleteEmptyParentDirectories(ctx, client, util.FullPath(parentDir), stopAtPath, checked)
+ } else {
+ // Failed to delete, stop cleanup
+ glog.V(3).InfofCtx(ctx, "DoDeleteEmptyParentDirectories: failed to delete %s: %v", dirPath, err)
+ }
+}
diff --git a/weed/s3api/s3api_object_handlers_delete.go b/weed/s3api/s3api_object_handlers_delete.go
index 04fea80be..f779a6edc 100644
--- a/weed/s3api/s3api_object_handlers_delete.go
+++ b/weed/s3api/s3api_object_handlers_delete.go
@@ -139,7 +139,7 @@ func (s3a *S3ApiServer) DeleteObjectHandler(w http.ResponseWriter, r *http.Reque
if !s3a.option.AllowEmptyFolder && strings.LastIndex(object, "/") > 0 {
bucketPath := fmt.Sprintf("%s/%s", s3a.option.BucketsPath, bucket)
// Recursively delete empty parent directories, stop at bucket path
- deleteEmptyParentDirectories(opCtx, client, util.FullPath(dir), util.FullPath(bucketPath), nil)
+ filer_pb.DoDeleteEmptyParentDirectories(opCtx, client, util.FullPath(dir), util.FullPath(bucketPath), nil)
}
return nil
@@ -400,7 +400,7 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
if !checked[dirPath] {
// Recursively delete empty parent directories, stop at bucket path
// Mark this directory and all its parents as checked during recursion
- deleteEmptyParentDirectories(opCtx, client, util.FullPath(dirPath), util.FullPath(bucketPath), checked)
+ filer_pb.DoDeleteEmptyParentDirectories(opCtx, client, util.FullPath(dirPath), util.FullPath(bucketPath), checked)
}
}
}
@@ -419,59 +419,3 @@ func (s3a *S3ApiServer) DeleteMultipleObjectsHandler(w http.ResponseWriter, r *h
writeSuccessResponseXML(w, r, deleteResp)
}
-
-// deleteEmptyParentDirectories recursively deletes empty parent directories.
-// It stops at root "/" or at stopAtPath.
-// This implements the same logic as filer.DeleteEmptyParentDirectories but uses gRPC client.
-// For safety, dirPath must be under stopAtPath (when stopAtPath is provided).
-// The checked map tracks already-processed directories to avoid redundant work in batch operations.
-func deleteEmptyParentDirectories(ctx context.Context, client filer_pb.SeaweedFilerClient, dirPath util.FullPath, stopAtPath util.FullPath, checked map[string]bool) {
- if dirPath == "/" || dirPath == stopAtPath {
- return
- }
-
- // Skip if already checked (for batch delete optimization)
- dirPathStr := string(dirPath)
- if checked != nil {
- if checked[dirPathStr] {
- return
- }
- checked[dirPathStr] = true
- }
-
- // Safety check: if stopAtPath is provided, dirPath must be under it
- if stopAtPath != "" && !strings.HasPrefix(dirPathStr+"/", string(stopAtPath)+"/") {
- glog.V(1).InfofCtx(ctx, "deleteEmptyParentDirectories: %s is not under %s, skipping", dirPath, stopAtPath)
- return
- }
-
- // Check if directory is empty by listing with limit 1
- isEmpty := true
- err := filer_pb.SeaweedList(ctx, client, dirPathStr, "", func(entry *filer_pb.Entry, isLast bool) error {
- isEmpty = false
- return io.EOF // Use sentinel error to explicitly stop iteration
- }, "", false, 1)
-
- if err != nil && err != io.EOF {
- glog.V(3).InfofCtx(ctx, "deleteEmptyParentDirectories: error checking %s: %v", dirPath, err)
- return
- }
-
- if !isEmpty {
- // Directory is not empty, stop checking upward
- glog.V(3).InfofCtx(ctx, "deleteEmptyParentDirectories: directory %s is not empty, stopping cleanup", dirPath)
- return
- }
-
- // Directory is empty, try to delete it
- glog.V(2).InfofCtx(ctx, "deleteEmptyParentDirectories: deleting empty directory %s", dirPath)
- parentDir, dirName := dirPath.DirAndName()
-
- if err := doDeleteEntry(client, parentDir, dirName, false, false); err == nil {
- // Successfully deleted, continue checking upwards
- deleteEmptyParentDirectories(ctx, client, util.FullPath(parentDir), stopAtPath, checked)
- } else {
- // Failed to delete, stop cleanup
- glog.V(3).InfofCtx(ctx, "deleteEmptyParentDirectories: failed to delete %s: %v", dirPath, err)
- }
-}