go-ethereum/eth/fetcher
rayoo 162cd83ee0 eth/fetcher: lazy-allocate unknown slices in TxFetcher.Notify
TxFetcher.Notify is the entry point for every NewPooledTransactionHashes
message: for a well-connected node with dozens of peers it fires
thousands of times per second. On a warm mempool nearly every announced
hash is already known, because some earlier peer already pushed it, so
the "unknown" filter reduces the batch to nothing.

The function still paid `2 * make([]T, 0, len(hashes))` upfront on every
call, wasting ~32B * len(hashes) per slice × 2 slices (common.Hash is
32B, txMetadata is 2B but aligned). At 256-hash announcements that is
10 KiB of allocator pressure per call for nothing to show for it.

Mirror the lazy-allocation pattern applied to scheduleFetches in
2ca74d2ef ("eth/fetcher: lazy-allocate hashes slice in
scheduleFetches"): defer the allocation to the first append, and size
to `len(hashes)-i` so the capacity is right-sized when a late-arriving
fresh hash is the only one we keep.

Benchmark (Apple M4 Pro, 256-hash batch, benchstat of 3 samples):

  scenario      ns/op        B/op           allocs/op
  AllKnown      2670 → 1915  10240 → 0      2 → 0        (-28% / -100% / -100%)
  HalfNew       4873 → 4968  10304 → 10304  3 → 3        (noise)
  AllNew        5932 → 5982  10304 → 10304  3 → 3        (noise)

AllKnown is the steady-state case. HalfNew and AllNew guard against
regressing the cold path; both stay within measurement noise.
2026-05-07 12:26:10 +08:00
..
metrics.go eth: check for tx on chain as well (#33607) 2026-02-24 11:21:03 +01:00
tx_fetcher.go eth/fetcher: lazy-allocate unknown slices in TxFetcher.Notify 2026-05-07 12:26:10 +08:00
tx_fetcher_bench_test.go eth/fetcher: lazy-allocate unknown slices in TxFetcher.Notify 2026-05-07 12:26:10 +08:00
tx_fetcher_test.go eth: check for tx on chain as well (#33607) 2026-02-24 11:21:03 +01:00