pg_xclaim 1.0.0-rc1
High-cardinality, transaction-scoped claims for PostgreSQL — a non-blocking lock primitive for the narrow case where pg_try_advisory_xact_lock runs out of room.
Experimental. First public release candidate. The SQL API is frozen and the full test matrix is green on PostgreSQL 16, 17, and 18, but it has no production track record yet. For the overwhelming majority of workloads a standard advisory lock or claim table is the right tool — the README spells out exactly when (and when not) to reach for this.
The problem it solves
pg_try_advisory_xact_lock keeps every held lock in the shared LockManager. A backend holding hundreds of thousands of transaction-scoped locks at once exhausts max_locks_per_transaction and the cluster runs out of shared memory. pg_xclaim stores claims in its own partitioned, fixed-size shared-memory hash table that bypasses the LockManager, and releases the whole set at transaction end in at most num_partitions LWLock cycles via group-by-partition cleanup.
If you are not hitting LWLock:LockManager as a measured top wait event at 100k+ claims per transaction, you do not need this.
What's in it
- Claim API —
xclaim.try(int8)andxclaim.try(int4, int4): non-blocking, transaction-scoped, signatures matchingpg_try_advisory_xact_lock. - Bulk API —
xclaim.try_many(int8[])andxclaim.try_many(int4, int4[]): partition-presorted batch acquisition. Result element i maps to input i; best-effort, not all-or-nothing. - Observability —
xclaim.stats()/xclaim.count()/xclaim.debug_snapshot()(pg_monitor), plus a superuserxclaim.debug(). - Self-healing — a lazy stale-owner reaper reclaims rows orphaned by a crashed or recycled backend on the next conflicting acquire.
- Tunable — GUCs for capacity, partition count, the per-backend watermark, and on-exhaustion behavior (
error/warn); a kill-switch (pg_xclaim.enabled). - Operations — a DBA runbook, an incident decision tree, a hot-path flamegraph analysis, and an alternatives benchmark with full methodology (all bilingual RU/EN).
Know before you adopt
These are deliberate divergences from advisory locks, by design — not bugs:
- Claims are released only at top-level COMMIT/ABORT — they survive
ROLLBACK TO SAVEPOINT. - A
NULLkey raises instead of returningNULL. PREPARE TRANSACTIONis rejected (0A000); advisory locks survive PREPARE.- Calls on a hot standby are rejected.
- Claims are invisible to
pg_locks— observability lives inxclaim.stats(). - It is try-only: no blocking acquire, no wait queue, no deadlock detection.
max_claimsis one cluster-wide pool shared across all databases. On clusters with untrusted roles,REVOKE EXECUTEthexclaim.try*functions fromPUBLIC(see SECURITY.md).
Compatibility
- PostgreSQL 16, 17, 18 (mainline), built and tested via PGXS.
- Linux and macOS. Windows is untested and unsupported.
Install
make PG_CONFIG=/path/to/pg_config
sudo make PG_CONFIG=/path/to/pg_config install
Add pg_xclaim to shared_preload_libraries (last in the list), restart, then CREATE EXTENSION pg_xclaim;. Full steps and a pre-deploy checklist are in the DBA runbook.
What "rc1" means here
The public SQL surface is frozen and the three-tier test suite (pg_regress, capacity, concurrency) is green across PG 16/17/18. It is labeled rc — and a GitHub pre-release — because it has not yet run in production. Feedback, benchmarks on your hardware, and bug reports are very welcome before a final 1.0.0.
Documentation
- README — what it is, the niche, alternatives, and the full SQL surface
docs/runbook.md— deploy, monitor, roll backdocs/incident-decision-tree.md— on-call triagedocs/perf/COMPARISON.md— benchmarks vs advisory locks and claim tablesCHANGELOG.md
Licensed under the PostgreSQL License.