fix(io): prune empty local directories after their files are deleted#7938
fix(io): prune empty local directories after their files are deleted#7938wombatu-kun wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: QUIET Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughLocal filesystem-backed object stores now remove empty parent directories after direct and streamed deletions, including ChangesLocal index cleanup
Estimated code review effort: 2 (Simple) | ~15 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 1
Note
Quiet mode is enabled, so only the most important comments were posted inline. Other review comments are grouped below.
🟡 Other comments (1)
rust/lance-io/src/object_store.rs-946-954 (1)
946-954: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd regression coverage for streamed deletion.
This branch bypasses
ObjectStore::deleteand performs its own inner deletion plus pruning. The new tests exercise onlystore.deleteat Line [1486], so a regression here could pass unnoticed. Add equivalentremove_streamtests for bothfileandfile-object-store.As per coding guidelines: “Every bugfix and feature must have corresponding tests.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/lance-io/src/object_store.rs` around lines 946 - 954, Add regression coverage for the streamed deletion branch in the relevant test module: add equivalent remove_stream tests for both the file and file-object-store configurations, exercising deletion and empty-parent-directory pruning through the stream path rather than only ObjectStore::delete. Reuse the existing test setup and assertions around the store.delete test near the referenced location.Source: Coding guidelines
🧹 Nitpick comments (1)
rust/lance-io/src/local.rs (1)
60-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDo not silently discard unexpected cleanup errors.
is_err()conflates expectedDirectoryNotEmpty/NotFoundcases with permission and I/O failures. Handle expected stop conditions separately, but log unexpected failures with the directory path and error context before stopping.As per coding guidelines: “Log warnings on best-effort or cleanup failures instead of silently swallowing or propagating errors.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/lance-io/src/local.rs` around lines 60 - 63, Update the parent-directory cleanup loop to match on the error returned by std::fs::remove_dir rather than using is_err(). Stop quietly for expected DirectoryNotEmpty and NotFound conditions, but log a warning containing the directory path and error context for all other failures before breaking.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@rust/lance-io/src/local.rs`:
- Around line 57-65: Update prune_empty_parent_dirs and its callers, including
ObjectStore::delete and remove_stream, to accept and propagate an explicit
store-root boundary alongside the object path. Stop pruning when the next
directory is the store root, never remove that root, and retain the existing
behavior of removing empty directories below it; add or adjust regression
coverage for an empty store root.
---
Other comments:
In `@rust/lance-io/src/object_store.rs`:
- Around line 946-954: Add regression coverage for the streamed deletion branch
in the relevant test module: add equivalent remove_stream tests for both the
file and file-object-store configurations, exercising deletion and
empty-parent-directory pruning through the stream path rather than only
ObjectStore::delete. Reuse the existing test setup and assertions around the
store.delete test near the referenced location.
---
Nitpick comments:
In `@rust/lance-io/src/local.rs`:
- Around line 60-63: Update the parent-directory cleanup loop to match on the
error returned by std::fs::remove_dir rather than using is_err(). Stop quietly
for expected DirectoryNotEmpty and NotFound conditions, but log a warning
containing the directory path and error context for all other failures before
breaking.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: QUIET
Plan: Pro Plus
Run ID: 93205f61-5992-4516-a099-de2b56028105
📒 Files selected for processing (2)
rust/lance-io/src/local.rsrust/lance-io/src/object_store.rs
f3924aa to
beda2f2
Compare
|
Addressed the other two in beda2f2:
|
Closes #7937
Problem
After
cleanup_old_versionsremoves an obsolete index, its files under_indices/<uuid>/are deleted one at a time, but on a local filesystem the now-empty_indices/<uuid>/directory is left behind. Cleanup deletes files only and never removes directories. On object stores (S3/GCS/Azure) directories are virtual prefixes that vanish with their last object, so this only affects local filesystems.Fix
ObjectStore::deleteandObjectStore::remove_streamwalk up from the deleted file and remove the parent directories that became empty, stopping at the first one that is not.The gate is wider than
is_local(): it also coversfile-object-store, which stores real directories that have no remote equivalent.Why not
LocalFileSystem::with_automatic_cleanuparrow has this built in and the first revision of this PR used it, but it is broken on Windows.
LocalFileSystem::new()roots the store atfile:///, anddelete_locationbounds its upward walk by resolving that root throughUrl::to_file_path(), which on Windows requires a drive letter and so returnsErr. Every delete then removed the file and reportedInvalidUrl; sinceRenameCommitHandleris copy + delete, 1055 of 2531lancetests failed onwindows-build.Tests
test_delete_prunes_empty_dirs_local_store/..._file_object_storeinlance-iodelete a file nested three levels deep and assert the emptied directories are gone while a non-empty sibling survives.Two existing cleanup tests are extended to assert the directory itself is gone, not just its files, via a filesystem check the object-store
exists()cannot observe:cleanup_old_replaced_segment_keeps_still_referenced_segments(flat layout; still-referenced dirs preserved) andcleanup_old_uncommitted_index_artifacts(nested layout).All four fail without the fix. The full
lance-io,lance-tableandlanceunit suites pass.