aerospike: optional native operate-path for mod-teranode UDFs#821
aerospike: optional native operate-path for mod-teranode UDFs#821icellan wants to merge 8 commits intobsv-blockchain:mainfrom
Conversation
Adds optional support for invoking mod-teranode functions via the native operate-path (TeranodeModifyOp, wire op type 200) instead of the legacy UDF path. The new path bypasses the Aerospike UDF executor and runs under the same lock as native ops like LIST_APPEND. Required server: the BSV fork of aerospike-server-private (feat/teranode-native-op or merged equivalent) on every node. Decision is wrapped at one place — call sites use s.teranodeBatchRecord(...) instead of aerospike.NewBatchUDF(...), and the helper picks the path based on: 1. Setting aerospike_use_native_teranode_ops (default false) 2. A startup capability probe against the cluster If either is false, calls fall back to UDF transparently. Clusters without the BSV fork keep working unchanged. Foundation: - go.mod: replace aerospike-client-go/v8 with the BSV fork - AerospikeSettings.UseNativeTeranodeOps (default false) - stores/utxo/aerospike/native_op.go: sub_op id constants, msgpack payload encoder, teranodeBatchRecord/executeTeranodeOp wrappers, capability probe (sends a malformed payload, expects PARAMETER_ERROR from the BSV dispatcher) - Store.useNativeTeranodeOps cached at construction Cutovers: - setMined Remaining cutovers (follow-up commits): preserveUntil, freeze, unfreeze, reassign, setConflicting, setLocked, spendMulti, unspend, incrementSpentExtraRecs (×2 sites). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Routes preserveUntil, freeze, unfreeze, reassign, setConflicting, setLocked, incrementSpentExtraRecs (×2), spendMulti, and unspend through the s.teranodeBatchRecord / s.executeTeranodeOp helpers added in the previous commit. Each call site shrinks because the aerospike.NewValue / aerospike.BoolValue wrappers are absorbed by the helper. Behavior is unchanged when aerospike_use_native_teranode_ops is false (the default) or when the cluster's capability probe rejects the new opcode — both result in the helper producing the same NewBatchUDF / client.Execute call as before. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The BSV fork of aerospike-client-go-v8 is now published at github.com/bsv-blockchain/aerospike-client-go/v8 v8.7.1-bsv1 — adds TeranodeModifyOp / TeranodeReadOp wire opcodes 200/201 alongside the upstream API. Mechanical sed across 55 files renaming all imports from github.com/aerospike/aerospike-client-go/v8 to github.com/bsv-blockchain/aerospike-client-go/v8. Build, vet, and the package test suite all green. Drops the local-filesystem replace directive — the require directive now resolves directly via the Go module proxy. The previously-pinned upstream github.com/aerospike/aerospike-client-go/v8 v8.4.2 remains as an indirect dependency of unrelated transitive imports. The fork is functionally a strict superset of upstream: when aerospike_use_native_teranode_ops is false (default) and/or the cluster's capability probe rejects the new opcode, Teranode's calls go through unchanged NewBatchUDF / client.Execute paths, behaving identically to upstream. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
🤖 Claude Code Review Status: Complete Summary Reviewed 61 changed files implementing optional native operate-path for mod-teranode UDF functions. The implementation is well-structured with appropriate safeguards. Findings No critical issues found. The PR demonstrates careful engineering:
Minor Observations
These are informational only and do not block merge. Compatibility Notes Verified
|
Benchmark Comparison ReportBaseline: Current: Summary
All benchmark results (sec/op)
Threshold: >10% with p < 0.05 | Generated: 2026-05-07 11:13 UTC |
Picks up 15d73f5 on the BSV go-client fork which fixes routing classification for TeranodeReadOp. The original v8.7.1-bsv1 had TeranodeReadOp falling into the operate_args.go default branch and being routed via PartitionForWrite because the client uses explicit op-type switches that didn't include _TERANODE_READ. Caught on PR review of bsv-blockchain/aerospike-client-go#1. No source changes here — only the version pin moves and go.sum updates with the new tarball hash. Build, vet, mod-tidy all green.
8ff71c5 to
c77a2b5
Compare
|
|
Superseded by #828 (re-opened from a branch on bsv-blockchain/teranode instead of icellan/teranode fork). All review/discussion to continue there. |


Summary
Adds an opt-in path that invokes mod-teranode UDF functions through the native operate-path (
TeranodeModifyOp, wire op type 200) instead of the legacy UDF executor. The native path:Expected to give meaningful concurrency wins under heavy batch load. The feature is off by default; existing clusters keep working unchanged.
Required server
The BSV fork of `aerospike-server` (branch `feat/teranode-native-op` or merged equivalent), which adds the matching server-side dispatcher (`AS_MSG_OP_TERANODE_MODIFY` = 200, sub-op id table 1..13).
Clusters running stock Aerospike or older versions of the BSV fork are unaffected — the capability probe (described below) detects unsupported servers and falls back to the UDF path.
Decision wrapping
Each call site delegates path selection to a single helper:
```go
batchRecords[i] = s.teranodeBatchRecord(
batchUDFPolicy, usePackage, key, subOpSetMined, "setMined",
minedBlockInfo.BlockID,
minedBlockInfo.BlockHeight,
// ...plain Go values; helper handles wrapping for either path
)
```
The helper returns either an `aerospike.NewBatchWrite(... TeranodeModifyOp(...))` or `aerospike.NewBatchUDF(...)` BatchRecord, depending on:
If either gate is closed, the helper produces the same `NewBatchUDF` call the existing code did. Behavior is byte-identical to the current code path on clusters that don't enable the setting or don't run the BSV server fork.
What's in the diff
Foundation (commit 1)
Cutovers (commit 2)
11 mod-teranode UDF call sites swapped from `aerospike.NewBatchUDF(...)` / `s.client.Execute(...)` to `s.teranodeBatchRecord(...)` / `s.executeTeranodeOp(...)`:
Net effect: `-3` lines across the call-site files (the wrapper absorbs `aerospike.NewValue(...)` / `aerospike.BoolValue(...)` ladders, so each call site shrinks).
Module path switch (commit 3)
The fork is functionally a strict superset of upstream; on clusters that don't enable the new path, the binary behaves identically to one built against upstream v8.7.0.
Sub-op id assignment (frozen wire contract)
Matches the SUBOP_TABLE in `modules/mod-teranode/src/main/mod_teranode_native_op.c` on the server fork. Never renumber after merge.
Test plan
Compatibility / rollout notes
Companion PRs
This PR depends on both being merged before `aerospike_use_native_teranode_ops=true` can do anything useful — but is safe to merge before then because the default-off behavior is byte-identical to current.
🤖 Generated with Claude Code