HarperFast / HarperFast/harper-pro
Record locks: decide what it would take to enable replication.recordLocks by default
- Dominant language
- JavaScript
- Stars
- 3
- Forks
- 0
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 80
Description
## Summary
`replication.recordLocks` is an explicit opt-in and defaults to off. This issue records what would have to be true to make cluster record locks safe by default, so the decision is tracked rather than rediscovered.
It is **not** blocked on the lock protocol being incomplete. The successor-freshness work (harper#2542, harper#2613, harper#2625) is done on harper-pro#822. It is blocked on three things that are each a design call.
## Why it cannot simply be flipped today
The home map is **operator-published by design**: `homeMap()` is never derived from `hdb_nodes` or liveness, because a locally-derived ring is the two-arbiter bug `replication/RECORD_LOCK_HOMES_DESIGN.md` §4 exists to prevent. With the switch on and no activated generation, `homeMap()` returns `undefined` and **every** cluster-scoped `lock()` on a replicated database returns 503 — strictly worse than today's honest opt-in, where the 503 at least names the switch.
Note this also means the current default is not "lock() behaves as it always did". On a replicated database with the feature off, a default-scope `lock()` already answers 503 naming `replication.recordLocks` (`replicator.ts` registers a fail-closed transport for every replicated database). Turning the default on without the items below moves that from one honest 503 to a different, less actionable one.
## What has to be true
1. **A bootstrap path for generation 1.** Landing on harper-pro#822 as `record_lock_bootstrap_generation { database, homes? }`: a local, fresh-state-only write of generation 1 that derives `homes` from `hdb_nodes` and refuses unless the node has never had a home map. That covers a *new* cluster. What is still open is the default-on case: who calls it, and when — first replicated database? first `lock()`? — and what happens for a node that joins later, which must not silently re-derive a ring.
2. **Cluster locks usable at `threads.count > 1`** — harper-pro#852. Default-on while a cluster-scoped `lock()` only succeeds on one worker would break `lock()` for most deployments rather than fix it.
3. **Placement that does not tax non-lock users.** Enabling the switch moves a database's whole inbound apply onto the coordinating worker (`subscriptionManager.ts` `placeSubscription`; `recordLockConfig.ts` says this is precisely why it is opt-in). A default would need placement to move only once a database actually has lock activity, or the throughput change lands on every cluster whether or not it ever calls `lock()`.
Also worth clearing first, all from harper-pro#822's `## For the human reviewer`: the startup `refreshCache` / incarnation-bump latch (one transient storage error leaves `homeMap()` undefined until an operator re-stages), and `homeMap()`'s per-acquisition cost.
## Acceptance
A fresh cluster with no record-lock configuration can call `lock()` on a replicated table and get cluster-wide exclusion, at the default worker count, without an operator running the §4.3 runbook — and a node joining that cluster later either participates or fails closed, never derives its own ring.
## Not in scope
The §4.3 stage → drain → activate runbook stays exactly as it is for every generation **after** the first; nothing here proposes deriving a ring for a live cluster.
Contributor guide
Research direction
Read replication/RECORD_LOCK_HOMES_DESIGN.md §4, then inspect replicator.ts, subscriptionManager.ts, and recordLockConfig.ts. Review harper-pro#822 and the referenced worker-count work before resolving the generation-1 bootstrap, multi-worker locking, placement, and startup-latch decisions. Done means a fresh cluster gets safe cluster-wide exclusion by default and later nodes participate or fail closed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- databases, distributed-systems
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100