HarperFast / HarperFast/harper
Intent-based increment API with per-key coalescing for high-contention counters (token quotas)
- Dominant language
- JavaScript
- Stars
- 89
- Forks
- 10
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 200
Description
## Problem
High-contention increment workloads (canonical case: token-quota accounting — many concurrent requests incrementing a numeric property on the same record) degrade badly under optimistic concurrency: every concurrent writer to the hot key fails commit validation and retries. Coordinated retry (rocksdb-js verification table, harper#410 record-caching work) makes the retries orderly, but the workload is still serialized read-modify-write with N−1 wasted commit attempts per N writers.
Collapsing *general* conflicting transactions on retry is not safe: by commit time their writes are computed values derived from stale reads, and merging computed puts is precisely the lost-update anomaly optimistic validation exists to catch.
## Proposal: declare the intent, collapse by construction
Add an intent-based write API at the Table/Resource layer:
```js
Table.increment(id, property, delta, context)
```
Semantics and implementation sketch:
- **Per-key delta queue.** Increments for the same (table, key) coalesce in a per-worker pending map instead of each opening its own transaction.
- **Single flush.** A flush (per event-loop turn, or piggybacked on the commit-batching flush) reads the base value once, applies the queued deltas **in arrival order**, and writes the record once — one transaction, one commit, zero conflicts among the coalesced increments.
- **Per-caller post-values.** Each awaiter receives its own resulting value (base + prefix sum in arrival order), so quota checks like "did this request push usage over the limit?" remain per-caller and deterministic. Optionally support a bound (`increment(..., { max })`) that rejects the specific caller whose prefix sum crosses the limit.
- **Retry routing.** When a *regular* transaction fails commit validation and its write-set is tagged as pure increments, route it into the coalescer on retry instead of blindly re-running — "collapse on retry" restricted to the provably-safe subset.
- **Audit/replication.** The flushed write is a normal record write, so existing replication and audit machinery applies unchanged; if a per-delta audit trail is wanted, emit one audit entry per coalesced increment.
## Relation to other work
- Pairs with the rocksdb-js commit-thread + batched-commit work (dispatch overhead amortization); the coalescer reduces hot-key transactions from N to 1 before batching even starts.
- Deep-tier alternative: RocksDB Merge operator (HarperFast/rocksdb-js#692) — conflict-free at the storage layer and commutatively replicable, but far more invasive. This JS-side coalescer is the recommended first tier.
---
_Filed by KrAIs (Claude Opus 4.8) on behalf of @kriszyp, from the commit-batching feasibility research (2026-07-08)._
Contributor guide
Research direction
Start at the Table/Resource layer and trace the existing transaction, commit-batching, retry, replication, and audit paths referenced in the proposal. Done would mean an agreed increment API with per-key coalescing, ordered per-caller results, and defined retry and bound semantics, validated against the relevant concurrency behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- backend-api-design, databases, performance
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100