Skip to content

perf(aerospike): fan out BatchPreviousOutputsDecorate per-tx#893

Merged
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:feat/legacy-perf-3
May 19, 2026
Merged

perf(aerospike): fan out BatchPreviousOutputsDecorate per-tx#893
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:feat/legacy-perf-3

Conversation

@oskarszoon

@oskarszoon oskarszoon commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

stores/utxo/aerospike.(*Store).BatchPreviousOutputsDecorate looped per-tx and called the per-tx decorate path serially. On legacy sync this forced one OutpointBatcherDurationMillis flush per transaction (default 10 ms; 5 ms on our mainnet prod nodes) because each per-tx call only queued ~2 inputs - well below OutpointBatcherSize - so the batcher always waited the full timer before firing.

Observed on bsva-ovh-teranode-eu-3 mainnet legacy sync at height ~381.5k:

Block tx count extendTransactions wall
2856 14.34 s
2820 13.84 s
2076 11.18 s
1620 8.31 s
997 5.39 s

Wall time tracked 5 ms x N_tx almost exactly. CPU was ~16% of one core; the 30 s CPU profile + goroutine dump showed exactly one PreviousOutputsDecorate in flight and zero sendOutpointBatch workers running while the loop waited - the aerospike batcher pool sat idle.

Change

BatchPreviousOutputsDecorate now wraps the per-tx PreviousOutputsDecorate calls in an errgroup so they push into the shared outpoint batcher concurrently. The batcher fills by size from concurrent producers instead of idling at its per-tx duration timer.

Existing per-tx behaviour (skip already-decorated inputs, dedup parent fetches across the batch, external-store cache) is unchanged - we just stop serialising the producers.

Expected impact

For a 2856-tx block: extendTransactions ~14 s -> a few aerospike round-trips (~10-50 ms).

Callers that benefit:

  • services/legacy/netsync/handle_block.go:1029 - block ingest phase 2
  • services/blockvalidation/quick_validate.go:1081, 1419 - catchup decorate

Tests added

aerospike_BatchPreviousOutputsDecorate subtest under TestAerospike covers:

  • Multiple child txs decorated in one call - every input across every child is populated with the correct satoshis / locking script.
  • Shared parent across children - same parent vout referenced by two children exercises the batcher's dedup of the underlying aerospike fetch even though goroutines race to request it.
  • Empty / nil tx slice - no-op.
  • Already-decorated input preserved - PreviousTxScript != nil inputs must not be overwritten (the early-skip in PreviousOutputsDecorate is what stops Phase 1's txMap work from being clobbered by Phase 2 in the legacy caller).

The function had no direct test in the aerospike package before this PR.

Test plan

  • go build ./... clean
  • go vet ./stores/utxo/aerospike/... clean
  • go test -race -count=1 ./stores/utxo/aerospike/... - all subtests pass (524 total, +1 new)
  • Deploy to bsva-ovh-teranode-eu-3, confirm extendTransactions DONE in log line drops by at least one order of magnitude on multi-thousand-tx blocks
  • Confirm block sync rate improves on mainnet legacy sync from same starting height

The previous implementation looped per-tx and called PreviousOutputsDecorate
sequentially, which on legacy sync forced one OutpointBatcherDurationMillis
(default 10 ms, 5 ms on prod) flush per transaction. Each per-tx call only
queued ~2 inputs - far below OutpointBatcherSize (100/4096) - so the batcher
always waited the full duration before firing.

Observed on mainnet legacy sync at height ~381.5k:

  2856 tx  extendTx 14.34s
  2820 tx  extendTx 13.84s
  2076 tx  extendTx 11.18s
  1620 tx  extendTx  8.31s
   997 tx  extendTx  5.39s

Wall time tracked 5 ms x N_tx almost exactly, confirming the per-tx timer
floor as the bottleneck. CPU profile + goroutine dump showed exactly one
PreviousOutputsDecorate active and zero sendOutpointBatch workers running
during the wait - the aerospike batcher pool sat idle while the loop drained
one tx at a time.

Flatten every input across every tx into a single Put loop so the batcher
fills by size for the bulk of the work, with at most one timer flush for the
tail. Channel semantics are unchanged: each errChan is buffered cap 1 and
sendErrorAndClose is non-blocking, so returning on first error never blocks
in-flight workers.

Expected: extendTransactions for a 2856-tx block drops from ~14 s to
~10-50 ms.

The SQL store already implements this shape with
BatchPreviousOutputsDecorateConcurrency + chunked parallel; this brings the
aerospike store in line.
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete


Current Review:

The previously reported concurrency issue has been fixed. The code now properly includes util.SafeSetLimit(g, s.settings.UtxoStore.OutpointBatcherSize) on line 1209 of stores/utxo/aerospike/get.go, which bounds the errgroup to prevent goroutine explosion.

Analysis:

  • Concurrency limit: Now properly set to OutpointBatcherSize (default 100, or 1024 for legacy), consistent with Phase 1 in the caller
  • Context propagation: Correctly uses errgroup.WithContext and propagates gCtx to child operations
  • Error handling: Any error from a goroutine will cancel the context and stop other goroutines via g.Wait()
  • Test coverage: New test aerospike_BatchPreviousOutputsDecorate covers concurrent decoration, deduplication, nil/empty input handling, and preservation of already-decorated inputs
  • Documentation: Function comment accurately describes the concurrency strategy and performance rationale

No issues found.


History:

  • ✅ Fixed: Missing concurrency limit on errgroup (previously would spawn unbounded goroutines)

@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-893 (1e98149)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 142
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.176µ 1.201µ ~ 0.100
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 54.91n 54.81n ~ 0.700
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 54.92n 54.96n ~ 0.400
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 54.85n 54.81n ~ 0.800
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 24.75n 24.69n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 41.27n 41.28n ~ 1.000
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 94.15n 94.35n ~ 0.700
MiningCandidate_Stringify_Short-4 170.6n 169.8n ~ 0.400
MiningCandidate_Stringify_Long-4 1.210µ 1.209µ ~ 0.700
MiningSolution_Stringify-4 630.8n 632.3n ~ 0.700
BlockInfo_MarshalJSON-4 1.320µ 1.312µ ~ 0.300
NewFromBytes-4 123.2n 134.2n ~ 0.300
Mine_EasyDifficulty-4 60.13µ 60.30µ ~ 0.200
Mine_WithAddress-4 6.836µ 6.819µ ~ 0.400
BlockAssembler_AddTx-4 0.02659n 0.02509n ~ 0.700
AddNode-4 10.82 11.07 ~ 1.000
AddNodeWithMap-4 11.44 11.45 ~ 0.700
DirectSubtreeAdd/4_per_subtree-4 61.06n 57.11n ~ 0.200
DirectSubtreeAdd/64_per_subtree-4 28.33n 28.59n ~ 0.200
DirectSubtreeAdd/256_per_subtree-4 27.12n 27.23n ~ 0.200
DirectSubtreeAdd/1024_per_subtree-4 26.10n 26.21n ~ 0.200
DirectSubtreeAdd/2048_per_subtree-4 25.71n 25.89n ~ 0.100
SubtreeProcessorAdd/4_per_subtree-4 279.0n 280.6n ~ 0.400
SubtreeProcessorAdd/64_per_subtree-4 278.2n 287.7n ~ 0.100
SubtreeProcessorAdd/256_per_subtree-4 280.1n 282.3n ~ 0.700
SubtreeProcessorAdd/1024_per_subtree-4 269.6n 275.9n ~ 0.100
SubtreeProcessorAdd/2048_per_subtree-4 270.1n 280.3n ~ 0.100
SubtreeProcessorRotate/4_per_subtree-4 279.1n 281.5n ~ 0.400
SubtreeProcessorRotate/64_per_subtree-4 274.5n 275.9n ~ 0.800
SubtreeProcessorRotate/256_per_subtree-4 276.6n 279.8n ~ 0.100
SubtreeProcessorRotate/1024_per_subtree-4 275.9n 284.4n ~ 0.200
SubtreeNodeAddOnly/4_per_subtree-4 54.27n 54.61n ~ 0.200
SubtreeNodeAddOnly/64_per_subtree-4 34.12n 34.39n ~ 0.100
SubtreeNodeAddOnly/256_per_subtree-4 33.28n 33.28n ~ 1.000
SubtreeNodeAddOnly/1024_per_subtree-4 32.54n 32.59n ~ 0.700
SubtreeCreationOnly/4_per_subtree-4 114.2n 114.3n ~ 1.000
SubtreeCreationOnly/64_per_subtree-4 398.5n 397.0n ~ 1.000
SubtreeCreationOnly/256_per_subtree-4 1.339µ 1.334µ ~ 0.200
SubtreeCreationOnly/1024_per_subtree-4 4.449µ 4.346µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 7.994µ 7.998µ ~ 1.000
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 272.7n 275.4n ~ 0.400
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 274.7n 274.5n ~ 1.000
ParallelGetAndSetIfNotExists/1k_nodes-4 2.211m 2.218m ~ 0.700
ParallelGetAndSetIfNotExists/10k_nodes-4 5.503m 5.496m ~ 1.000
ParallelGetAndSetIfNotExists/50k_nodes-4 7.512m 7.697m ~ 0.400
ParallelGetAndSetIfNotExists/100k_nodes-4 10.15m 10.52m ~ 0.100
SequentialGetAndSetIfNotExists/1k_nodes-4 1.934m 1.941m ~ 1.000
SequentialGetAndSetIfNotExists/10k_nodes-4 4.377m 4.492m ~ 0.200
SequentialGetAndSetIfNotExists/50k_nodes-4 13.18m 12.93m ~ 0.700
SequentialGetAndSetIfNotExists/100k_nodes-4 22.12m 23.70m ~ 0.200
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 2.248m 2.292m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 8.226m 8.686m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 13.25m 14.33m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 1.972m 2.016m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 7.788m 7.932m ~ 0.700
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 40.40m 42.36m ~ 0.100
DiskTxMap_SetIfNotExists-4 3.847µ 3.693µ ~ 0.700
DiskTxMap_SetIfNotExists_Parallel-4 3.571µ 3.524µ ~ 0.400
DiskTxMap_ExistenceOnly-4 317.0n 337.0n ~ 0.100
Queue-4 189.4n 187.2n ~ 0.200
AtomicPointer-4 5.295n 4.729n ~ 0.700
ReorgOptimizations/DedupFilterPipeline/Old/10K-4 857.2µ 838.4µ ~ 0.200
ReorgOptimizations/DedupFilterPipeline/New/10K-4 793.7µ 782.5µ ~ 0.100
ReorgOptimizations/AllMarkFalse/Old/10K-4 105.9µ 102.3µ ~ 0.100
ReorgOptimizations/AllMarkFalse/New/10K-4 62.27µ 61.78µ ~ 0.200
ReorgOptimizations/HashSlicePool/Old/10K-4 54.89µ 55.00µ ~ 1.000
ReorgOptimizations/HashSlicePool/New/10K-4 11.67µ 12.12µ ~ 0.700
ReorgOptimizations/NodeFlags/Old/10K-4 4.747µ 4.809µ ~ 0.100
ReorgOptimizations/NodeFlags/New/10K-4 1.621µ 1.643µ ~ 0.100
ReorgOptimizations/DedupFilterPipeline/Old/100K-4 9.731m 9.556m ~ 0.200
ReorgOptimizations/DedupFilterPipeline/New/100K-4 10.131m 9.946m ~ 1.000
ReorgOptimizations/AllMarkFalse/Old/100K-4 1.100m 1.070m ~ 0.100
ReorgOptimizations/AllMarkFalse/New/100K-4 688.5µ 689.0µ ~ 0.700
ReorgOptimizations/HashSlicePool/Old/100K-4 578.0µ 556.0µ ~ 0.200
ReorgOptimizations/HashSlicePool/New/100K-4 342.0µ 339.8µ ~ 0.400
ReorgOptimizations/NodeFlags/Old/100K-4 50.41µ 50.97µ ~ 0.200
ReorgOptimizations/NodeFlags/New/100K-4 17.62µ 17.64µ ~ 1.000
TxMapSetIfNotExists-4 53.04n 51.61n ~ 0.200
TxMapSetIfNotExistsDuplicate-4 38.36n 38.48n ~ 0.700
ChannelSendReceive-4 598.8n 603.5n ~ 0.100
CalcBlockWork-4 516.7n 505.4n ~ 0.400
CalculateWork-4 696.2n 688.0n ~ 0.100
BuildBlockLocatorString_Helpers/Size_10-4 1.574µ 1.797µ ~ 0.700
BuildBlockLocatorString_Helpers/Size_100-4 13.21µ 13.22µ ~ 1.000
BuildBlockLocatorString_Helpers/Size_1000-4 129.5µ 130.1µ ~ 0.100
CatchupWithHeaderCache-4 104.4m 104.2m ~ 0.200
_prepareTxsPerLevel-4 312.6m 310.2m ~ 1.000
_prepareTxsPerLevelOrdered-4 2.839m 2.818m ~ 0.400
_prepareTxsPerLevel_Comparison/Original-4 314.1m 310.1m ~ 0.700
_prepareTxsPerLevel_Comparison/Optimized-4 2.907m 2.754m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.347m 1.309m ~ 0.200
SubtreeSizes/10k_tx_16_per_subtree-4 310.1µ 311.0µ ~ 1.000
SubtreeSizes/10k_tx_64_per_subtree-4 73.36µ 74.03µ ~ 0.400
SubtreeSizes/10k_tx_256_per_subtree-4 18.19µ 18.27µ ~ 0.400
SubtreeSizes/10k_tx_512_per_subtree-4 8.990µ 9.002µ ~ 0.400
SubtreeSizes/10k_tx_1024_per_subtree-4 4.462µ 4.491µ ~ 1.000
SubtreeSizes/10k_tx_2k_per_subtree-4 2.202µ 2.259µ ~ 0.100
BlockSizeScaling/10k_tx_64_per_subtree-4 70.30µ 71.09µ ~ 0.700
BlockSizeScaling/10k_tx_256_per_subtree-4 17.70µ 17.91µ ~ 0.200
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.355µ 4.405µ ~ 0.100
BlockSizeScaling/50k_tx_64_per_subtree-4 375.2µ 373.1µ ~ 1.000
BlockSizeScaling/50k_tx_256_per_subtree-4 88.74µ 89.88µ ~ 0.700
BlockSizeScaling/50k_tx_1024_per_subtree-4 21.81µ 21.79µ ~ 1.000
SubtreeAllocations/small_subtrees_exists_check-4 152.8µ 152.3µ ~ 0.400
SubtreeAllocations/small_subtrees_data_fetch-4 160.3µ 159.5µ ~ 0.400
SubtreeAllocations/small_subtrees_full_validation-4 310.4µ 310.5µ ~ 1.000
SubtreeAllocations/medium_subtrees_exists_check-4 8.982µ 9.071µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 9.471µ 9.373µ ~ 0.700
SubtreeAllocations/medium_subtrees_full_validation-4 17.82µ 18.00µ ~ 0.700
SubtreeAllocations/large_subtrees_exists_check-4 2.111µ 2.122µ ~ 0.700
SubtreeAllocations/large_subtrees_data_fetch-4 2.267µ 2.270µ ~ 1.000
SubtreeAllocations/large_subtrees_full_validation-4 4.434µ 4.455µ ~ 0.700
_BufferPoolAllocation/16KB-4 3.811µ 3.662µ ~ 0.100
_BufferPoolAllocation/32KB-4 9.762µ 7.136µ ~ 0.100
_BufferPoolAllocation/64KB-4 14.78µ 17.69µ ~ 0.100
_BufferPoolAllocation/128KB-4 31.51µ 33.28µ ~ 0.100
_BufferPoolAllocation/512KB-4 135.9µ 120.9µ ~ 0.100
_BufferPoolConcurrent/32KB-4 18.90µ 18.62µ ~ 0.100
_BufferPoolConcurrent/64KB-4 29.71µ 29.72µ ~ 1.000
_BufferPoolConcurrent/512KB-4 160.5µ 160.6µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/16KB-4 670.9µ 671.1µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/32KB-4 661.7µ 663.6µ ~ 0.700
_SubtreeDeserializationWithBufferSizes/64KB-4 656.3µ 661.0µ ~ 0.400
_SubtreeDeserializationWithBufferSizes/128KB-4 655.1µ 660.7µ ~ 1.000
_SubtreeDeserializationWithBufferSizes/512KB-4 674.2µ 661.6µ ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/16KB-4 38.27m 38.21m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/32KB-4 38.47m 38.55m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/64KB-4 38.20m 38.60m ~ 0.100
_SubtreeDataDeserializationWithBufferSizes/128KB-4 38.33m 38.45m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/512KB-4 38.45m 38.13m ~ 0.200
_PooledVsNonPooled/Pooled-4 823.2n 231.4n ~ 0.100
_PooledVsNonPooled/NonPooled-4 7.598µ 6.920µ ~ 0.700
_MemoryFootprint/Current_512KB_32concurrent-4 8.480µ 7.985µ ~ 0.100
_MemoryFootprint/Proposed_32KB_32concurrent-4 11.62µ 11.46µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 10.82µ 10.92µ ~ 0.200
StoreBlock_Sequential/BelowCSVHeight-4 335.9µ 333.3µ ~ 0.400
StoreBlock_Sequential/AboveCSVHeight-4 334.9µ 339.8µ ~ 0.200
GetUtxoHashes-4 256.6n 256.9n ~ 1.000
GetUtxoHashes_ManyOutputs-4 49.55µ 48.73µ ~ 0.100
_NewMetaDataFromBytes-4 238.3n 239.1n ~ 1.000
_Bytes-4 637.2n 641.1n ~ 0.700
_MetaBytes-4 591.1n 590.7n ~ 0.700

Threshold: >10% with p < 0.05 | Generated: 2026-05-19 10:35 UTC

Replace the prior flatten-into-one-Put-loop approach with the simpler fix:
wrap the existing per-tx PreviousOutputsDecorate calls in an errgroup so all
of them push into the shared outpoint batcher concurrently. The batcher fills
by size from concurrent producers instead of idling at its per-tx duration
timer waiting for ~2 inputs to accumulate.

Same wall-time effect as the flatten variant, but the function body shrinks
back to a few lines and we stop having two near-identical loops in the
package (PreviousOutputsDecorate already owns the Put/drain logic).

Follow-up to review feedback on the prior commit; supersedes that approach.
@oskarszoon oskarszoon changed the title perf(aerospike): flatten BatchPreviousOutputsDecorate into one pass perf(aerospike): fan out BatchPreviousOutputsDecorate per-tx May 19, 2026
BatchPreviousOutputsDecorate previously had no direct test in the aerospike
package - the prior implementation was a per-tx serial loop that delegated
straight to PreviousOutputsDecorate, so coverage on that single-tx path was
treated as sufficient. After switching to per-tx fan-out via errgroup, the
function now runs concurrent producers against the shared outpoint batcher,
which is exactly the path that was untested.

Add an aerospike_BatchPreviousOutputsDecorate subtest under TestAerospike
covering:

- Multiple child txs decorated in one call - asserts every input across every
  child is populated with the correct satoshis / locking script.
- Shared parent across children - same parent vout referenced by two children
  exercises the batcher's dedup of the underlying aerospike fetch even though
  goroutines race to request it.
- Empty / nil tx slice - no-op.
- Already-decorated input preserved - PreviousTxScript != nil inputs must not
  be overwritten (the early-skip in PreviousOutputsDecorate is what stops
  Phase 1's txMap work from being clobbered by Phase 2 in the legacy caller).

Runs under -race so any data-race introduced by the goroutine fan-out into
the per-input slot writes would be caught here.
Comment thread stores/utxo/aerospike/get.go
Cap the per-tx errgroup at UtxoStore.OutpointBatcherSize (default 100, 4096
on prod overrides). The unbounded version was fine in practice - producers
spend most of their time parked on errChan receives, and the real ceiling
on aerospike round-trips is BatcherMaxConcurrent - but bounding the
goroutine count:

- Keeps memory predictable on pathologically large blocks (a 20k-tx block
  would otherwise spawn 20k goroutines, ~160 MB of stack at minimum, plus
  per-input channel allocations).
- Mirrors the Phase 1 errgroup bound in the legacy caller
  (services/legacy/netsync/handle_block.go:980), so Phase 2 no longer
  silently 20x's the producer-side parallelism of Phase 1.
- Matches the codebase pattern of bounding every errgroup that fans out
  per-tx or per-record work.

Throughput is unchanged: the bound is well above the BatcherMaxConcurrent
ceiling that actually gates aerospike batch throughput, and the upstream
batcher fills by size as soon as a few hundred producers have pushed.

Addresses review feedback on PR bsv-blockchain#893.
@sonarqubecloud

Copy link
Copy Markdown

@oskarszoon oskarszoon merged commit 1b062a9 into bsv-blockchain:main May 19, 2026
25 checks passed
@oskarszoon oskarszoon self-assigned this May 19, 2026
freemans13 added a commit to freemans13/teranode that referenced this pull request May 22, 2026
Updates from @ordishs and Copilot reviews:

- Extend the comment above the drain-mode toggles in aerospike.go to
  cover the new outpoint case and the post-bsv-blockchain#893 nuance.
- Rewrite the OutpointBatcherDrainMode longdesc so the
  'when to enable / when to disable' guidance reflects the
  post-bsv-blockchain#893 fan-out path rather than the pre-bsv-blockchain#893 sequential producer.
- Add TestAerospikeOutpointBatcherDrainMode happy-path smoke test
  asserting the toggle stays wired (per-tx + concurrent decorate).
freemans13 added a commit to freemans13/teranode that referenced this pull request Jun 2, 2026
…fan-out; align docs

Add BenchmarkBatchPreviousOutputsDecorateDrainMode comparing the outpoint
batcher's drain mode on vs off across the concurrent BatchPreviousOutputsDecorate
path (bsv-blockchain#893 errgroup fan-out), using distinct parents per input so batch width
maps to real BatchOperate record counts.

Findings (count=10 + benchstat, distinct-parent inputs): drain mode is
neutral-to-faster in the mean at every tx count (-8% at 2856 tx to -94% at 16
tx), but bimodal/heavy-tailed at mid tx counts (~64-256). So the concurrent
node path keeps drain mode default off (predictable latency), and the clean win
is the single-producer, separate-process cmd/rewindblockchain caller.

Update the aerospike.go comment and the setting longdesc to match the measured
behaviour and to note the batcher is store-wide (the toggle cannot be applied
to one caller without affecting the other in the same process).
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.

3 participants