Skip to content

Conversation

@cb1kenobi
Copy link
Contributor

@cb1kenobi cb1kenobi commented Sep 18, 2025

WIP

  • Adding support for the transaction log store (under construction)

@github-actions
Copy link

github-actions bot commented Sep 18, 2025

📊 Benchmark Results

encoding.bench.ts

Key encoding > ordered-binary keys - strings (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 24.83K ops/sec 40.27 35.90 461.481 1.07 12,416
🥈 rocksdb 2 4.77K ops/sec 209.741 191.604 3,092.259 1.60 2,384

Key encoding > ordered-binary keys - numbers (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 27.09K ops/sec 36.92 33.01 611.031 0.965 13,544
🥈 rocksdb 2 4.98K ops/sec 200.793 186.665 1,583.982 0.723 2,491

Key encoding > ordered-binary keys - mixed types (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 25.97K ops/sec 38.50 36.29 375.671 0.379 12,986
🥈 rocksdb 2 4.94K ops/sec 202.483 190.554 892.751 0.466 2,470

Value encoding > msgpack values - strings (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 15.25K ops/sec 65.58 56.75 558.536 1.16 7,625
🥈 rocksdb 2 4.34K ops/sec 230.595 213.474 865.982 0.483 2,169

Value encoding > msgpack values - numbers (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 25.80K ops/sec 38.76 34.56 391.541 0.936 12,901
🥈 rocksdb 2 4.58K ops/sec 218.346 194.307 4,092.126 1.66 2,290

Value encoding > msgpack values - arrays (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 9.30K ops/sec 107.576 96.43 751.447 1.32 4,648
🥈 rocksdb 2 3.53K ops/sec 283.316 264.08 1,375.313 0.833 1,765

Value encoding > msgpack values - small objects (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 5.73K ops/sec 174.422 153.046 1,101.672 1.86 2,867
🥈 rocksdb 2 2.63K ops/sec 380.378 359.514 1,169.412 0.686 1,315

Value encoding > msgpack values - large objects (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 639.73 ops/sec 1,563.17 1,422.703 9,165.994 4.44 320
🥈 rocksdb 2 630.26 ops/sec 1,586.654 1,443.834 3,593.12 2.02 316

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 20.79K ops/sec 48.10 41.37 4,506.618 2.12 10,395
🥈 rocksdb 2 4.50K ops/sec 222.146 191.799 12,358.979 7.09 2,251

get.bench.ts

get() > rocksdb - random vs sequential keys (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 sequential 1 4.02K ops/sec 249.062 233.834 1,453.086 0.662 2,008
🥈 random 2 3.94K ops/sec 253.872 235.545 1,834.155 1.06 1,970

get() > random keys - max 1978 lmdb key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 3.08K ops/sec 325.158 282.185 3,759.961 3.47 1,538

get() > rocksdb - async vs sync

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 sync 1 4.13K ops/sec 242.06 216.641 5,891.692 2.41 2,066
🥈 async 2 3.76K ops/sec 265.905 251.145 940.995 0.500 1,881

put-sync.bench.ts

putSync() > random keys - insert - small key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.24K ops/sec 445.991 422.99 679.483 0.288 1,122
🥈 lmdb 2 4.22 ops/sec 236,937.374 232,256.779 260,007.099 2.50 10.00

putSync() > random keys - update - small key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.30K ops/sec 434.832 406.325 678.748 0.175 1,150
🥈 lmdb 2 4.12 ops/sec 242,508.879 234,337.566 262,259.04 2.91 10.00

putSync() > random keys - insert - max 1978 lmdb key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 976.47 ops/sec 1,024.098 921.066 1,247.467 0.399 489
🥈 lmdb 2 3.86 ops/sec 259,342.565 247,765.731 274,077.883 2.60 10.00

putSync() > random keys - update - max 1978 lmdb key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.02K ops/sec 980.188 892.609 1,197.723 0.472 511
🥈 lmdb 2 3.91 ops/sec 255,957.908 232,350.901 287,485.97 4.27 10.00

putSync() > sequential keys - insert (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.30K ops/sec 435.191 405.887 570.629 0.192 1,149
🥈 lmdb 2 4.12 ops/sec 242,954.683 230,945.602 263,462.523 3.43 10.00

putSync() > put 100KB value (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 51.29 ops/sec 19,495.64 17,910.536 20,918.426 2.26 26.00
🥈 lmdb 2 2.66 ops/sec 375,711.961 367,036.857 393,118.596 1.78 10.00

putSync() > put 1MB value (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 5.26 ops/sec 190,132.521 183,611.844 206,196.093 2.57 10.00
🥈 lmdb 2 1.96 ops/sec 509,032.804 435,346.869 581,999.058 8.44 10.00

putSync() > get 10MB value (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 0.24 ops/sec 4,145,088.326 3,072,256.939 4,943,164.718 10.06 10.00
🥈 rocksdb 2 0.17 ops/sec 5,895,985.016 4,590,017.045 7,119,413.59 11.17 10.00

put.bench.ts

put > small dataset (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.96K ops/sec 511.11 474.799 847.662 0.353 979
🥈 lmdb 2 3.39 ops/sec 295,241.966 285,604.115 314,525.874 1.81 10.00

put > async vs sync overhead

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 sync 1 2.14K ops/sec 467.016 434.268 667.763 0.216 1,071
🥈 async 2 1.97K ops/sec 508.05 458.341 1,126.085 0.369 985

ranges.bench.ts

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 22.77K ops/sec 43.92 37.03 653.159 1.15 11,385
🥈 rocksdb 2 2.68K ops/sec 373.073 308.855 3,279.492 3.83 1,341

getRange() > full scan vs range scan

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb range scan 1 20.64K ops/sec 48.46 39.92 659.054 1.16 10,319
🥈 lmdb full scan 2 11.78K ops/sec 84.88 75.30 855.364 1.47 5,892
🥉 rocksdb range scan 3 2.80K ops/sec 357.763 289.518 1,631.296 2.22 1,398
rocksdb full scan 4 1.54K ops/sec 650.606 531.175 3,366.977 3.53 769

getKeys() > keys only (100 records, 50 range)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 50.51K ops/sec 19.80 16.48 3,049.726 1.78 25,256
🥈 rocksdb 2 4.55K ops/sec 219.647 187.24 1,190.991 1.33 2,277

Reverse iteration > reverse range (100 records, 50 range)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 544.94K ops/sec 1.84 1.21 6,206.078 6.85 272,470
🥈 rocksdb 2 2.75K ops/sec 363.433 318.464 2,172.855 1.93 1,376

Reverse iteration > rocksdb - reverse vs forward

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 forward 1 3.10K ops/sec 322.672 284.414 1,582.367 1.84 1,550
🥈 reverse 2 2.84K ops/sec 352.623 314.074 1,636.699 1.97 1,418

Range query patterns > prefix scan performance

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 30.53K ops/sec 32.75 28.68 1,158.489 1.18 15,267
🥈 rocksdb 2 3.38K ops/sec 295.468 264.009 1,434.192 1.76 1,693

Sparse data patterns > sparse - range over gaps

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 58.87K ops/sec 16.99 14.71 1,673.602 1.49 29,434
🥈 rocksdb 2 6.14K ops/sec 162.984 143.108 1,366.275 1.22 3,068

Sparse data patterns > sparse - prefix with gaps

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 131.19K ops/sec 7.62 6.74 2,832.152 2.81 65,598
🥈 rocksdb 2 12.24K ops/sec 81.68 70.08 2,559.431 1.35 6,122

remove-sync.bench.ts

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 12.07K ops/sec 82.82 70.96 870.671 1.92 6,038
🥈 rocksdb 2 2.58K ops/sec 387.533 370.406 621.999 0.338 1,291

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 12.22K ops/sec 81.82 72.69 791.499 1.39 6,112
🥈 rocksdb 2 2.65K ops/sec 377.529 360.909 554.392 0.220 1,325

removeSync() > rocksdb - random vs sequential keys (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 random 1 2.65K ops/sec 376.906 345.539 631.35 0.176 1,327
🥈 sequential 2 2.65K ops/sec 377.865 352.29 518.864 0.276 1,324

removeSync() > random keys - max 1978 lmdb key size (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 10.09K ops/sec 99.10 90.06 1,685.128 1.31 5,046
🥈 rocksdb 2 1.06K ops/sec 946.141 817.37 1,132.822 0.424 529

removeSync() > random access pattern (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 11.29K ops/sec 88.59 78.02 645.688 1.40 5,644
🥈 rocksdb 2 2.76K ops/sec 362.539 344.457 515.893 0.163 1,380

removeSync() > non-existent keys (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 12.11K ops/sec 82.58 76.84 1,270.515 0.561 6,055
🥈 rocksdb 2 2.61K ops/sec 383.135 358.853 555.944 0.154 1,306

transaction-sync.bench.ts

transaction sync > optimistic > simple put operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 571.38 ops/sec 1,750.147 1,631.009 5,253.317 2.02 286
🥈 lmdb 2 4.28 ops/sec 233,666.736 224,980.21 238,985.923 1.21 10.00

transaction sync > optimistic > batch operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.85K ops/sec 351.385 304.242 2,196.576 0.991 1,423
🥈 lmdb 2 351.94 ops/sec 2,841.376 2,141.136 8,957.617 4.56 176

transaction sync > optimistic > read-write operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 349.18 ops/sec 2,863.877 2,620.107 4,893.803 1.66 175
🥈 lmdb 2 4.13 ops/sec 242,323.876 232,904.507 262,019.129 3.12 10.00

transaction sync > optimistic > concurrent non-conflicting operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 569.44 ops/sec 1,756.11 1,671.404 3,619.652 1.35 285
🥈 lmdb 2 4.31 ops/sec 232,247.397 218,669.623 256,309.221 3.02 10.00

transaction sync > optimistic > rollback operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 15.45K ops/sec 64.74 62.19 523.339 0.379 7,723
🥈 rocksdb 2 5.48K ops/sec 182.325 170.491 924.366 0.352 2,743

transaction sync > optimistic > rocksdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 3.00K ops/sec 333.248 308.881 436.309 0.144 1,501
🥈 rocksdb 2 592.39 ops/sec 1,688.071 1,617.875 4,876.692 1.66 297

transaction sync > optimistic > lmdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 364.99 ops/sec 2,739.835 2,114.323 5,860.849 2.22 183
🥈 lmdb 2 4.25 ops/sec 235,333.792 228,047.176 254,274.912 3.00 10.00

transaction sync > optimistic > empty transaction overhead

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 791.13K ops/sec 1.26 1.12 1,668.114 0.817 395,565
🥈 rocksdb 2 93.31K ops/sec 10.72 9.37 2,686.428 1.48 46,655

transaction sync > optimistic > transaction with only reads (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 1.52K ops/sec 659.875 590.635 4,469.861 3.19 758
🥈 rocksdb 2 263.48 ops/sec 3,795.289 3,483.909 8,968.903 3.67 132

transaction sync > pessimistic > simple put operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 505.37 ops/sec 1,978.751 1,912.338 2,995.111 0.550 253
🥈 lmdb 2 4.21 ops/sec 237,647.983 225,729.202 255,079.433 3.59 10.00

transaction.bench.ts

transaction > optimistic > simple put operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 307.21 ops/sec 3,255.066 2,801.906 6,667.349 3.64 154
🥈 lmdb 2 3.52 ops/sec 284,193.13 269,671.902 296,721.948 2.23 10.00

transaction > optimistic > batch operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.24K ops/sec 447.29 373.152 531.757 0.220 1,118
🥈 lmdb 2 299.96 ops/sec 3,333.782 2,233.637 6,468.499 2.35 151

transaction > optimistic > read-write operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 217.06 ops/sec 4,606.979 3,918.249 8,781.899 3.50 109
🥈 lmdb 2 3.46 ops/sec 289,361.695 277,977.467 310,911.704 2.25 10.00

transaction > optimistic > concurrent non-conflicting operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 930.22 ops/sec 1,075.014 918.796 4,071.808 3.38 466
🥈 lmdb 2 271.47 ops/sec 3,683.657 2,186.531 9,422 5.37 136

transaction > optimistic > rollback operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 4.97K ops/sec 201.347 189.816 774.117 0.491 2,484
🥈 lmdb 2 295.61 ops/sec 3,382.786 3,045.573 6,555.592 2.22 148

transaction > optimistic > rocksdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.26K ops/sec 442.877 360.818 712.133 0.438 1,130
🥈 rocksdb 2 310.43 ops/sec 3,221.324 2,731.372 8,613.663 4.01 156

transaction > optimistic > lmdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 295.30 ops/sec 3,386.349 2,523.581 6,439.394 1.35 148
🥈 lmdb 2 3.58 ops/sec 279,051.531 268,852.04 299,446.06 2.79 10.00

transaction > optimistic > empty transaction overhead

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 42.43K ops/sec 23.57 18.03 412.022 0.399 21,213
🥈 rocksdb 2 38.20K ops/sec 26.18 20.17 4,521.713 3.07 19,100

transaction > optimistic > transaction with only reads (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 338.19 ops/sec 2,956.896 2,637.327 20,719.303 7.85 170
🥈 rocksdb 2 148.46 ops/sec 6,735.888 6,114.022 17,584.571 5.53 75.00

transaction > pessimistic > simple put operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 256.32 ops/sec 3,901.416 3,485.018 12,924.907 4.40 129
🥈 lmdb 2 3.59 ops/sec 278,337.292 271,072.145 293,290.016 2.14 10.00

worker-get-sync.bench.ts

Worker > random keys - small key size (100 records, 1 worker)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 15.17K ops/sec 65.93 57.07 6,815.496 3.14 7,584
🥈 rocksdb 2 3.80K ops/sec 263.116 219.327 1,387.727 0.962 1,901

Worker > random keys - small key size (100 records, 2 workers)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 13.93K ops/sec 71.81 61.35 5,991.084 2.38 6,963
🥈 rocksdb 2 3.53K ops/sec 283.545 232.631 1,582.328 1.16 1,764

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 7.04K ops/sec 142.065 116.259 11,048.658 4.92 3,520
🥈 rocksdb 2 1.72K ops/sec 581.17 490.742 4,888.469 2.30 861

worker-put-sync.bench.ts

putSync() > random keys - small key size (100 records, 1 worker)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.81K ops/sec 553.663 497.907 3,115.314 1.24 904
🥈 lmdb 2 4.02 ops/sec 248,809.508 237,354.712 294,288.101 4.80 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.39K ops/sec 719.251 668.075 2,692.382 0.847 696
🥈 lmdb 2 2.05 ops/sec 488,468.521 473,335.339 517,395.927 2.04 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 796.63 ops/sec 1,255.29 1,104.209 6,778.456 2.63 399
🥈 lmdb 2 1.14 ops/sec 874,125.23 803,684.464 943,417.619 4.09 10.00

Results from commit c87e14a


// // create a reference to pin the buffer in memory (prevents GC)
napi_ref bufferRef = nullptr;
NAPI_STATUS_THROWS(::napi_create_reference(env, argv[0], 1, &bufferRef));
Copy link
Member

@kriszyp kriszyp Oct 27, 2025

Choose a reason for hiding this comment

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

I think we should copy the contents of the buffer into data, keep this as managed memory in C (delete when done) rather than maintaining a JS ref:

  • Remove the complexity of managing, tracking, and deleting the JS reference
  • Allow the JS buffer to be immediately GC'ed. For very large txns, helps protect against JS OOM, better scalability.
  • Or allow for the safe reuse of shared buffer, that can be written over and over. Right now, I think this expects that the buffer won't be modified until the commit takes place, but this shouldn't be assumed, copying the data keeps it safe.
  • Minimizes napi calls/interactions with the buffer (which is generally expensive, I believe).

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.

3 participants