Skip to content

Forbid stores from being shared - #719

Merged
cb1kenobi merged 4 commits into
mainfrom
store-test
Jul 27, 2026
Merged

Forbid stores from being shared#719
cb1kenobi merged 4 commits into
mainfrom
store-test

Conversation

@cb1kenobi

@cb1kenobi cb1kenobi commented Jul 23, 2026

Copy link
Copy Markdown
Member

While reviewing https://github.com/HarperFast/harper/pull/1888/changes#diff-4ff51263bd99981165fc179149c3195ea0c0ca3e2f360bafee2a6bb356964377R605, I realized it's technically possible to share stores between RocksDatabase instances. The store owns the native DB handle and sharing could lead to bugs. It's best to forbid stores from being shared.

@cb1kenobi
cb1kenobi requested a review from kriszyp as a code owner July 23, 2026 00:07

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a new test case to verify that a RocksDatabase instance can be successfully initialized using the store of another instance. The review feedback suggests expanding this test to verify two-way functionality by ensuring that write operations on the new database instance are also readable from the original instance.

Comment thread test/store.test.ts Outdated
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

📊 Benchmark Results

get-sync.bench.ts

getSync() > random keys - small key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 24.36K ops/sec 41.05 39.56 596.204 0.117 121,818
🥈 rocksdb 2 11.35K ops/sec 88.11 85.78 31,426.412 1.24 56,748

getSync() > sequential keys - small key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 28.56K ops/sec 35.02 33.88 580.733 0.104 142,782
🥈 rocksdb 2 10.92K ops/sec 91.55 88.37 3,744.398 0.154 54,617

ranges.bench.ts

getRange() > small range (100 records, 50 range)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 25.31K ops/sec 39.51 36.57 1,928.535 0.296 126,562
🥈 rocksdb 2 17.50K ops/sec 57.13 50.80 1,981.641 0.143 87,519

realistic-load.bench.ts

Realistic write load with workers > write variable records with transaction log

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 384.93 ops/sec 2,597.897 150.265 31,097.849 11.04 770
🥈 lmdb 2 26.19 ops/sec 38,177.494 437.027 1,188,762.836 135.9 64.00

transaction-log.bench.ts

Transaction log > read 100 iterators while write log with 100 byte records

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 38.27K ops/sec 26.13 11.53 13,625.992 0.580 191,351
🥈 lmdb 2 446.69 ops/sec 2,238.68 140.823 23,294.779 1.46 2,234

Transaction log > read one entry from random position from log with 1000 100 byte records

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 702.63K ops/sec 1.42 1.22 492.52 0.061 3,513,171
🥈 lmdb 2 485.96K ops/sec 2.06 1.06 8,857.734 0.574 2,429,799

worker-put-sync.bench.ts

putSync() > random keys - small key size (100 records, 10 workers)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 864.55 ops/sec 1,156.672 998.465 2,136.462 0.335 1,730
🥈 lmdb 2 1.15 ops/sec 868,105.519 845,097.562 894,762.524 1.40 10.00

worker-transaction-log.bench.ts

Transaction log with workers > write log with 100 byte records

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 23.07K ops/sec 43.34 30.37 541.551 0.566 46,144
🥈 lmdb 2 825.21 ops/sec 1,211.818 94.49 28,714.753 5.78 1,651

Results from commit 54baa6c

Comment thread test/store.test.ts Outdated
}
});

it('should allow sharing the store between databases', () =>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, do you think we should update this?:
Could we reconcile this supported-behavior test with the Store JSDoc at src/store.ts:141, which currently says that a store should not be shared between RocksDatabase instances? If sharing is intended, please update that contract here and document the shared-close lifetime this test asserts; otherwise future users and maintainers have two contradictory ownership rules.

A Store owns a single NativeDatabase handle and is 1:1 with a
RocksDatabase. Reusing one store across two RocksDatabase instances
aliased the handle (surprising close-cascade and shared encoder state).

Enforce the invariant: each RocksDatabase claims its store on
construction via Store#claim(), which throws if the store is already
owned by another RocksDatabase. The claim is durable across close/reopen
so a temporarily-closed owner does not release it. Sharing a store with
the owning database's Transaction instances is unaffected.

Document in the Store jsdoc, the constructor `store` option, and the
Custom Store README section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cb1kenobi cb1kenobi changed the title Add test to use an existing db's store for new db instance Forbid stores from being shared Jul 27, 2026

@kriszyp kriszyp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@cb1kenobi
cb1kenobi merged commit 4f4a29c into main Jul 27, 2026
26 checks passed
@cb1kenobi
cb1kenobi deleted the store-test branch July 27, 2026 20:56
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.

2 participants