Skip to content

fix: eliminate unnecessary cleanup I/O costs for empty tree deletions - #639

Merged
QuantumExplorer merged 4 commits into
developfrom
fix/delete-tree-cleanup-fees
Mar 10, 2026
Merged

fix: eliminate unnecessary cleanup I/O costs for empty tree deletions#639
QuantumExplorer merged 4 commits into
developfrom
fix/delete-tree-cleanup-fees

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Mar 10, 2026

Copy link
Copy Markdown
Member

Summary

  • Rename SubelementsDeletionBehavior::DontCheck to DontCheckWithNoCleanup — now skips both the emptiness preflight check AND the post-apply storage cleanup phase
  • Change DeleteChildren to skip the emptiness check but still perform post-apply storage cleanup
  • This fixes a fee increase in drive-abci tests caused by the new Merk subtree cleanup phase (added in feat: use transactional storage context for all specialized trees #638) running on every DeleteTree op, even when Platform was deleting known-empty index trees via batch_delete_up_tree_while_empty

Before

DontCheck and DeleteChildren had nearly identical behavior — both added deleted subtrees to the cleanup list. The only difference was DeleteChildren ran an emptiness check first (then ignored the result for non-empty trees). Every DeleteTree(NormalTree, DontCheck) op paid find_subtrees + storage.clear() I/O costs even for empty trees.

After

Variant Tree state Emptiness check Deletes tree Storage cleanup
DontCheckWithNoCleanup empty No Yes No
DontCheckWithNoCleanup non-empty No Yes No
DeleteChildren empty No Yes Yes
DeleteChildren non-empty No Yes Yes
Error empty Yes Yes No
Error non-empty Yes No (returns error) No
Skip empty Yes Yes No
Skip non-empty Yes No (silently skips) No

Fee impact

Platform uses DontCheck (now DontCheckWithNoCleanup) for batch_delete_up_tree_while_empty, which prunes known-empty index trees during document transfers/deletions. These ops no longer incur find_subtrees + clear costs, restoring the previous fee levels.

Test plan

  • All 1421 grovedb tests pass
  • Clippy clean
  • Tests that verify storage cleanup after deleting non-empty trees switched to DeleteChildren
  • Tests that delete known-empty trees or don't verify cleanup use DontCheckWithNoCleanup

🤖 Generated with Claude Code

…skip emptiness check

Previously DontCheck and DeleteChildren had nearly identical behavior:
both added the deleted subtree to the post-apply cleanup list, but
DontCheck skipped the emptiness preflight check while DeleteChildren
ran it (then ignored the result). This meant every
DeleteTree(NormalTree, DontCheck) op paid find_subtrees + storage.clear
I/O costs even when the caller knew the tree was empty.

Now:
- DontCheckWithNoCleanup: skips both emptiness check AND post-apply
  storage cleanup. For callers who guarantee the subtree is already
  empty (e.g. batch_delete_up_tree_while_empty).
- DeleteChildren: skips the emptiness check but still performs
  post-apply storage cleanup. For callers deleting trees that may
  have children needing recursive cleanup.

This eliminates the unnecessary I/O costs (find_subtrees + clear) that
were being charged as processing fees when Platform deleted known-empty
index trees during document transfers and deletions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 10, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@QuantumExplorer has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 minutes and 20 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c160cda-5217-418c-b1f4-456ec3e09498

📥 Commits

Reviewing files that changed from the base of the PR and between 9430b8f and abd5f3a.

📒 Files selected for processing (1)
  • docs/book/src/batch-operations.md
📝 Walkthrough

Walkthrough

This PR renames the DontCheck variant to DontCheckWithNoCleanup in the SubelementsDeletionBehavior enum across documentation translations and source code files. Associated comments clarify that the renamed variant skips both emptiness checks and post-apply cleanup, while DeleteChildren skips emptiness checks but performs post-apply storage cleanup.

Changes

Cohort / File(s) Summary
Documentation Translations
docs/book/translations/ar/.../batch-operations.md, docs/book/translations/cs/.../batch-operations.md, docs/book/translations/de/.../batch-operations.md, docs/book/translations/es/.../batch-operations.md, docs/book/translations/fr/.../batch-operations.md, docs/book/translations/id/.../batch-operations.md, docs/book/translations/it/.../batch-operations.md, docs/book/translations/ja/.../batch-operations.md, docs/book/translations/ko/.../batch-operations.md, docs/book/translations/pl/.../batch-operations.md, docs/book/translations/pt/.../batch-operations.md, docs/book/translations/ru/.../batch-operations.md, docs/book/translations/th/.../batch-operations.md, docs/book/translations/tr/.../batch-operations.md, docs/book/translations/vi/.../batch-operations.md, docs/book/translations/zh/.../batch-operations.md, docs/book/src/batch-operations.md
Renamed SubelementsDeletionBehavior variant from DontCheck to DontCheckWithNoCleanup with updated descriptions clarifying emptiness check and cleanup behavior across all language versions.
Batch Implementation
grovedb/src/batch/mod.rs
Updated enum variant references and match arms to use DontCheckWithNoCleanup instead of DontCheck, with corresponding documentation updates reflecting the new semantics.
Delete Operations
grovedb/src/operations/delete/mod.rs
Updated internal delete logic to reference DontCheckWithNoCleanup instead of DontCheck for empty tree paths, with clarified comments about skipped cleanup.
Batch Tests
grovedb/src/tests/batch_coverage_tests.rs, grovedb/src/tests/batch_delete_tree_tests.rs
Updated test cases and expectations to use the renamed DontCheckWithNoCleanup variant, with corresponding message and comment updates.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Hop, hop—a rename so fine!
DontCheck becomes DontCheckWithNoCleanup divine,
Across all tongues, from French to Thai,
Clarity blooms as we clarify
What our deletion policy will do, oh my!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: renaming DontCheck to DontCheckWithNoCleanup to eliminate unnecessary cleanup costs for empty tree deletions, which is the core objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/delete-tree-cleanup-fees

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
grovedb/src/tests/batch_delete_tree_tests.rs (1)

116-121: ⚠️ Potential issue | 🟠 Major

These tests now model DontCheckWithNoCleanup on a known non-empty tree.

That variant’s new contract is “caller guarantees tree is empty.” Using it here locks in unsupported usage instead of the intended non-empty deletion paths. If these tests are meant to cover sanctioned non-empty deletion, switch them to DeleteChildren; otherwise rename the tests/comments to make clear they are exercising the unsafe no-cleanup bypass rather than the supported contract.

Also applies to: 1652-1661

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grovedb/src/tests/batch_delete_tree_tests.rs` around lines 116 - 121, The
tests call QualifiedGroveDbOp::delete_tree_op with
SubelementsDeletionBehavior::DontCheckWithNoCleanup against a known non-empty
tree, which violates that variant's "caller guarantees tree is empty" contract;
either change the behavior to SubelementsDeletionBehavior::DeleteChildren to
exercise the supported non-empty deletion path (update the ops vec at the sites
using delete_tree_op), or if you intentionally want to test the unsafe bypass,
rename the test and comments to explicitly state it exercises the unsafe
DontCheckWithNoCleanup behavior; update all occurrences (e.g., the ops
construction at the shown location and the similar block at lines ~1652-1661)
accordingly.
🧹 Nitpick comments (1)
grovedb/src/batch/mod.rs (1)

5583-5590: Add one regression for the DontCheckWithNoCleanup branch too.

These updates keep the cleanup-required path covered, but the PR’s main behavior split is that DontCheckWithNoCleanup must avoid the cleanup work entirely. A companion regression in the cost tests or delete-tree tests would make the restored fee behavior much harder to regress.

Also applies to: 5670-5676, 5747-5753

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@grovedb/src/batch/mod.rs` around lines 5583 - 5590, The PR adds regressions
for the cleanup-required path but missed adding a test for the
DontCheckWithNoCleanup path; add a companion regression that constructs a
delete-tree op using QualifiedGroveDbOp::delete_tree_op with
SubelementsDeletionBehavior::DontCheckWithNoCleanup (instead of DeleteChildren)
and assert that no cleanup/fee-related side-effects occur (mirror the existing
test structure used around the delete-tree/cost tests), so the
restored-no-cleanup behavior is covered; place this new test alongside the other
delete-tree regressions that use DeleteChildren to ensure both branches
(DeleteChildren and DontCheckWithNoCleanup) are exercised.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/book/translations/pt/src/batch-operations.md`:
- Around line 47-49: The enum variant descriptions for
SubelementsDeletionBehavior are still in English in the localized page; update
the inline comments for DontCheckWithNoCleanup, Error, and DeleteChildren to
Portuguese equivalents, preserving the original meaning (skip emptiness check
and skip post-apply cleanup; return Error::DeletingNonEmptyTree if non-empty;
skip emptiness check but perform post-apply storage cleanup) so the localized
page matches the renamed enum documentation; apply the same translation change
to the other translated batch-operations.md files that were updated by this
rename.

In `@docs/book/translations/zh/src/batch-operations.md`:
- Around line 47-49: The inline comments for the enum variants
DontCheckWithNoCleanup, Error, and DeleteChildren are still English in the
Chinese translation page; update those three comments to Chinese to match the
surrounding localized prose (translate "Skip emptiness check AND post-apply
cleanup; caller guarantees tree is empty", "Return Error::DeletingNonEmptyTree
if non-empty", and "Skip emptiness check, but perform post-apply storage
cleanup" into concise Chinese and replace the existing English comments next to
DontCheckWithNoCleanup, Error, and DeleteChildren).

In `@grovedb/src/batch/mod.rs`:
- Around line 3088-3099: The non-batch path apply_operations_without_batching()
incorrectly treats SubelementsDeletionBehavior::DontCheckWithNoCleanup like
DeleteChildren (setting allow_deleting_non_empty_trees=true) which causes
recursive cleanup; change the mapping so DontCheckWithNoCleanup is treated like
Skip (i.e., do NOT set allow_deleting_non_empty_trees and ensure the delete call
uses error=false/returns Ok(false) for non-empty trees). Concretely, update the
DeleteOptions construction (the allow_deleting_non_empty_trees matches(...)
expression) to only include SubelementsDeletionBehavior::DeleteChildren, and
ensure any downstream logic that sets the “error on non-empty” behavior for
DeleteTree respects DontCheckWithNoCleanup as skip (allow=false + error=false).

In `@grovedb/src/operations/delete/mod.rs`:
- Around line 683-690: The branch currently returns
QualifiedGroveDbOp::delete_tree_op(...,
SubelementsDeletionBehavior::DontCheckWithNoCleanup) based on an emptiness
preflight that counts all nested DeleteTree ops as deletions; update the
emptiness check to mirror the batch-path logic by filtering out any nested
DeleteTree(_, Skip) ops before deciding the fast no-cleanup path so that
DontCheckWithNoCleanup is only returned when the preflight is exact; locate the
code that computes emptiness for the delete_tree_op (references:
QualifiedGroveDbOp::delete_tree_op,
SubelementsDeletionBehavior::DontCheckWithNoCleanup, and DeleteTree(_, Skip))
and exclude Skip children from that calculation prior to returning the
DontCheckWithNoCleanup variant.

---

Outside diff comments:
In `@grovedb/src/tests/batch_delete_tree_tests.rs`:
- Around line 116-121: The tests call QualifiedGroveDbOp::delete_tree_op with
SubelementsDeletionBehavior::DontCheckWithNoCleanup against a known non-empty
tree, which violates that variant's "caller guarantees tree is empty" contract;
either change the behavior to SubelementsDeletionBehavior::DeleteChildren to
exercise the supported non-empty deletion path (update the ops vec at the sites
using delete_tree_op), or if you intentionally want to test the unsafe bypass,
rename the test and comments to explicitly state it exercises the unsafe
DontCheckWithNoCleanup behavior; update all occurrences (e.g., the ops
construction at the shown location and the similar block at lines ~1652-1661)
accordingly.

---

Nitpick comments:
In `@grovedb/src/batch/mod.rs`:
- Around line 5583-5590: The PR adds regressions for the cleanup-required path
but missed adding a test for the DontCheckWithNoCleanup path; add a companion
regression that constructs a delete-tree op using
QualifiedGroveDbOp::delete_tree_op with
SubelementsDeletionBehavior::DontCheckWithNoCleanup (instead of DeleteChildren)
and assert that no cleanup/fee-related side-effects occur (mirror the existing
test structure used around the delete-tree/cost tests), so the
restored-no-cleanup behavior is covered; place this new test alongside the other
delete-tree regressions that use DeleteChildren to ensure both branches
(DeleteChildren and DontCheckWithNoCleanup) are exercised.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1b1e9420-b569-44df-8c99-5886bd442a87

📥 Commits

Reviewing files that changed from the base of the PR and between 0f7faf5 and 9430b8f.

📒 Files selected for processing (21)
  • docs/book/src/batch-operations.md
  • docs/book/translations/ar/src/batch-operations.md
  • docs/book/translations/cs/src/batch-operations.md
  • docs/book/translations/de/src/batch-operations.md
  • docs/book/translations/es/src/batch-operations.md
  • docs/book/translations/fr/src/batch-operations.md
  • docs/book/translations/id/src/batch-operations.md
  • docs/book/translations/it/src/batch-operations.md
  • docs/book/translations/ja/src/batch-operations.md
  • docs/book/translations/ko/src/batch-operations.md
  • docs/book/translations/pl/src/batch-operations.md
  • docs/book/translations/pt/src/batch-operations.md
  • docs/book/translations/ru/src/batch-operations.md
  • docs/book/translations/th/src/batch-operations.md
  • docs/book/translations/tr/src/batch-operations.md
  • docs/book/translations/vi/src/batch-operations.md
  • docs/book/translations/zh/src/batch-operations.md
  • grovedb/src/batch/mod.rs
  • grovedb/src/operations/delete/mod.rs
  • grovedb/src/tests/batch_coverage_tests.rs
  • grovedb/src/tests/batch_delete_tree_tests.rs

Comment thread docs/book/translations/pt/src/batch-operations.md
Comment thread docs/book/translations/zh/src/batch-operations.md
Comment thread grovedb/src/batch/mod.rs
Comment thread grovedb/src/operations/delete/mod.rs
QuantumExplorer and others added 2 commits March 10, 2026 14:53
DeleteChildren now checks emptiness to decide whether cleanup is needed.
Empty trees skip the post-apply find_subtrees + storage.clear phase
since there's nothing to clean up.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Mar 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.25000% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.83%. Comparing base (0f7faf5) to head (abd5f3a).
⚠️ Report is 1 commits behind head on develop.

Files with missing lines Patch % Lines
grovedb/src/batch/mod.rs 80.00% 3 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #639      +/-   ##
===========================================
- Coverage    90.83%   90.83%   -0.01%     
===========================================
  Files          182      182              
  Lines        51898    51895       -3     
===========================================
- Hits         47142    47138       -4     
- Misses        4756     4757       +1     
Components Coverage Δ
grovedb-core 89.05% <81.25%> (-0.01%) ⬇️
merk 91.94% <ø> (ø)
storage 86.36% <ø> (ø)
commitment-tree 96.43% <ø> (ø)
mmr 96.76% <ø> (ø)
bulk-append-tree 89.65% <ø> (ø)
element 97.56% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@QuantumExplorer
QuantumExplorer merged commit b191ff2 into develop Mar 10, 2026
12 checks passed
@QuantumExplorer
QuantumExplorer deleted the fix/delete-tree-cleanup-fees branch March 10, 2026 08:09
QuantumExplorer added a commit to dashpay/platform that referenced this pull request Mar 10, 2026
Updates grovedb to include dashpay/grovedb#639 which renames
DontCheck to DontCheckWithNoCleanup, eliminating unnecessary
find_subtrees + storage.clear() I/O costs for known-empty tree
deletions during document transfers and deletions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant