Skip to content

Fix block count leaks and parallelize recount chunk loading (supersedes #263)#264

Merged
tastybento merged 2 commits into
developfrom
fix/block-count-leaks
Jun 12, 2026
Merged

Fix block count leaks and parallelize recount chunk loading (supersedes #263)#264
tastybento merged 2 commits into
developfrom
fix/block-count-leaks

Conversation

@tastybento

Copy link
Copy Markdown
Member

Builds on @daniel-skopek's #263 — superseding it so the fix can land with the bug-2 correction and tests already applied. Daniel's original commit is preserved here with authorship intact; thanks for the catches. 🙏

What this brings over from #263 (unchanged)

  • BlockSpreadEvent now decrements the replaced block before adding the new one (previously it only incremented, permanently inflating counts for spread-overwritten materials). Mirrors the existing BlockFormEvent pattern.
  • RecountCalculator loads all chunks within an environment — and all three environments — in parallel instead of sequentially, fixing the 5-minute CALCULATION_TIMEOUT that produced no result on large islands.
  • RecountCalculator uses the @NonNull getIsland(Island) overload in the constructor and tidyUp(), so a recount no longer risks creating an empty IslandBlockCount that drops permission-based limits and offsets.

What changed vs #263

The BlockGrowEvent handler in #263 added process(e.getNewState().getBlock(), false) after a cancelled (over-limit) grow. That decrement is unbalanced: process(block, true) returns before incrementing when the limit is hit, so the extra call removes a count that was never added. For a material at a non-zero limit, a blocked grow drove the stored count below the true physical count, then let the next grow slip past the limit.

This branch drops that one line (the cancel branch was already balanced) and adds tests:

  • testBlockSpreadDecrementsOldAddsNew — confirms the spread leak fix
  • testBlockSpreadAtLimitCancelsAndRestoresOld — confirms a clean revert when the new material is at limit
  • testBlockGrowAtNonZeroLimitDoesNotDecrement — regression guard: a blocked grow at 5/5 leaves the count at 5

Full discussion and the empirical 5→4 repro are in the #263 review.

All 233 tests pass.

Closes #263

🤖 Generated with Claude Code

daniel-skopek and others added 2 commits June 12, 2026 07:40
- BlockSpreadEvent: decrement old block before adding new (was leaking old counts)
- BlockGrowEvent: revert count increment when event is cancelled due to limit hit
- RecountCalculator: load chunks in parallel instead of sequentially (fixes calc timeout on large islands)
- RecountCalculator: use @nonnull getIsland(Island) to prevent permission limit loss on null ibc
The BlockGrowEvent handler decremented the new block's count after a
cancelled (over-limit) grow. But process(block, true) returns before
incrementing when the limit is hit, so that decrement removed a count
that was never added — driving a real, physically-present block's count
below its true value and letting the next grow slip past the limit.

Drop the spurious decrement (the cancel branch was already balanced) and
add tests covering:
- BlockSpreadEvent decrementing the old block and adding the new (the
  leak this PR fixes)
- BlockSpreadEvent reverting cleanly when the new material is at limit
- BlockGrowEvent at a non-zero limit leaving the count untouched on a
  blocked grow (regression guard for the reverted line)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@tastybento tastybento merged commit 7c95708 into develop Jun 12, 2026
3 checks passed
@tastybento tastybento deleted the fix/block-count-leaks branch June 12, 2026 14:44
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.

2 participants