Skip to content

perf(mempool): O(k) reap with head-offset compaction#1070

Draft
daps94 wants to merge 1 commit intomainfrom
perf/reaplist-head-offset
Draft

perf(mempool): O(k) reap with head-offset compaction#1070
daps94 wants to merge 1 commit intomainfrom
perf/reaplist-head-offset

Conversation

@daps94
Copy link

@daps94 daps94 commented Mar 11, 2026

Summary

  • Replaces O(N) full txIndex rebuild after every Reap() with an O(k) head-offset design that advances a pointer past consumed entries
  • Amortized compaction only triggers when head >= 1024 or head*2 >= len(txs), keeping the common path allocation-free
  • Collapses separate exists() + push() into single-lock pushLocked(), eliminating a TOCTOU race on duplicate detection

Motivation

The ReapList maintained a txIndex map[string]int for deduplication. After every Reap(), the entire index was rebuilt from scratch (slices.DeleteFunc + re-index loop), even though Reap() only consumes entries from the front. This is O(N) in the total list size, wasted work when the list is large.

Benchmark Results (benchstat, 5 runs, Apple M4 Pro)

                                      │   main    │  reaplist   │
                                      │  sec/op   │  sec/op  vs │
EVMMempoolIterator/EVM_0/Cosmos_50       96.7µ      73.1µ   -24%
EVMMempoolIterator/EVM_0/Cosmos_500       224µ       150µ   -33%
EVMMempoolIterator/EVM_0/Cosmos_1000      321µ       258µ   -20%
EVMMempoolIterator/EVM_0/Cosmos_2500     1212µ       694µ   -43%
EVMMempoolIterator/EVM_0/Cosmos_10000    6101µ      4894µ   -20%
EVMMempoolIterator/EVM_1000/Cosmos_1k    4415µ      2504µ   -43%
EVMMempoolIterator/EVM_5000/Cosmos_5k   16965µ     14757µ   -13%

Geomean latency:  -21%

All Cosmos-path results statistically significant (p ≤ 0.032). EVM-only paths show no change (expected — ReapList is Cosmos-side only). Memory and allocs unchanged (zero-allocation design).

Files Changed

File Change
mempool/reap_list.go Add head int field; rewrite Reap() to iterate from head; add maybeCompactLocked(); merge exists()+push() into pushLocked()

Test Plan

  • go test -tags=test -race ./mempool/... — 74 tests pass with race detection
  • 27 focused reap_list tests pass
  • Benchmark shows 21% geomean improvement (no regression in EVM-only paths)

🤖 Generated with Claude Code

Replace the full O(N) index rebuild after every Reap() with a head-offset
design. Reap now advances a head pointer past consumed entries and only
compacts the backing slice when a meaningful prefix has been consumed
(threshold-based). Push operations deduplicate under a single write lock,
eliminating the TOCTOU window between the old exists() and push() calls.

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