Skip to content

defer checkBounds during batch block operations to fix#5797

Open
Ashutoshx7 wants to merge 1 commit intosugarlabs:masterfrom
Ashutoshx7:perf/defer-checkbounds-layout-recalc
Open

defer checkBounds during batch block operations to fix#5797
Ashutoshx7 wants to merge 1 commit intosugarlabs:masterfrom
Ashutoshx7:perf/defer-checkbounds-layout-recalc

Conversation

@Ashutoshx7
Copy link
Contributor

Fixes #5650

Problem

_moveBlock() calls checkBounds() on every invocation, and adjustDocks() recursively calls _moveBlock() for every connected block. Since checkBounds() iterates the entire blockList each time, this creates O(N x M) complexity per dock adjustment — where N is the number of blocks in the stack and M is total blocks in the project. The same pattern exists in moveStackRelative(), moveAllBlocksExcept(), and updateBlockPositions().

For a 200-block project with a 20-block stack, that's 4,000 iterations per adjustment instead of 200.

Solution

Introduced a deferred batching mechanism: _beginDeferCheckBounds() and _endDeferCheckBounds() suppress intermediate checkBounds() calls and run a single check when the batch completes. The mechanism supports nesting.

  • adjustDocks() automatically defers on the outermost call, so recursive _moveBlock() calls skip the redundant scans.
  • moveStackRelative(), moveAllBlocksExcept(), and updateBlockPositions() wrap their loops the same way.
  • Standalone _moveBlock() and moveBlockRelative() calls outside a deferred window still call checkBounds() immediately, so single-block behavior is unchanged.

One file changed, 70 insertions, 3 deletions. No public API changes.

Testing

  • All 3,108 Jest tests pass (110 suites)
  • Manual browser testing: blocks load, drag, snap, and disconnect correctly

…yout recalculation

Previously, _moveBlock() called checkBounds() on every invocation, and
�djustDocks() recursively called _moveBlock() for every connected block.
Since checkBounds() iterates the entire blockList, this created O(N×M)
complexity (N = blocks in stack, M = total blocks) for every dock adjustment,
stack move, or block reconnection.

This commit introduces a deferred batching mechanism:

- _beginDeferCheckBounds() / _endDeferCheckBounds() suppress intermediate
  checkBounds() calls and run a single check when the batch completes.
  Supports nesting for safety.

- �djustDocks() automatically defers on the outermost call, so all recursive
  _moveBlock() invocations skip redundant checkBounds iterations.

- moveStackRelative(), moveAllBlocksExcept(), and updateBlockPositions()
  also wrap their loops with the deferred mechanism.

- Standalone _moveBlock() / moveBlockRelative() calls (outside a deferred
  window) continue to call checkBounds() immediately, preserving existing
  behavior for single-block moves.

For a project with 200 blocks where adjustDocks touches a 20-block stack,
this reduces checkBounds iterations from ~4,000 (20 × 200) to just 200
(a single scan), a 20x improvement in layout recalculation overhead.

Fixes sugarlabs#5650
@Ashutoshx7 Ashutoshx7 changed the title defer checkBounds during batch block operations to fix O(n²) la… defer checkBounds during batch block operations to fix O(n²) Feb 18, 2026
@github-actions
Copy link
Contributor

✅ All Jest tests passed! This PR is ready to merge.

@Ashutoshx7 Ashutoshx7 changed the title defer checkBounds during batch block operations to fix O(n²) defer checkBounds during batch block operations to fix Feb 20, 2026
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.

Block workspace performance degrades for large projects due to repeated full layout recalculations

1 participant