Skip to content

Conversation

cb1kenobi
Copy link
Contributor

@cb1kenobi cb1kenobi commented Sep 18, 2025

WIP

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

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.77K ops/sec 40.36 35.84 428.287 1.10 12,387
🥈 rocksdb 2 4.66K ops/sec 214.783 199.307 2,487.474 1.29 2,328

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 27.00K ops/sec 37.03 33.17 400.487 0.934 13,503
🥈 rocksdb 2 4.98K ops/sec 200.796 188.393 818.45 0.484 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 24.85K ops/sec 40.25 35.83 837.214 0.990 12,424
🥈 rocksdb 2 4.75K ops/sec 210.553 196.335 2,092.497 0.937 2,375

Value encoding > msgpack values - strings (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 15.77K ops/sec 63.39 56.21 490.461 1.29 7,888
🥈 rocksdb 2 4.12K ops/sec 242.898 226.757 1,148.814 0.748 2,059

Value encoding > msgpack values - numbers (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 25.68K ops/sec 38.94 34.70 407.139 0.909 12,840
🥈 rocksdb 2 4.89K ops/sec 204.596 187.005 1,898.466 1.04 2,444

Value encoding > msgpack values - arrays (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 9.36K ops/sec 106.889 94.94 729.452 1.59 4,678
🥈 rocksdb 2 3.55K ops/sec 281.568 266.731 839.188 0.488 1,776

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 5.94K ops/sec 168.363 150.975 1,097.447 1.77 2,970
🥈 rocksdb 2 2.74K ops/sec 364.577 344.634 919.697 0.559 1,372

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 648.30 ops/sec 1,542.507 1,419.675 6,774.251 3.45 325
🥈 rocksdb 2 643.20 ops/sec 1,554.716 1,412.419 3,181.739 1.96 322

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.61K ops/sec 48.52 41.97 3,232.945 1.73 10,305
🥈 rocksdb 2 4.44K ops/sec 225.182 191.918 12,211.128 7.03 2,221

get.bench.ts

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 random 1 3.89K ops/sec 257.028 238.964 1,323.71 0.814 1,946
🥈 sequential 2 3.88K ops/sec 257.775 242.397 1,323.247 0.662 1,940

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.11K ops/sec 321.293 284.377 2,868.868 2.68 1,557

get() > rocksdb - async vs sync

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 sync 1 4.20K ops/sec 237.941 213.427 5,534.596 2.95 2,102
🥈 async 2 3.69K ops/sec 271.022 254.35 1,263.913 0.581 1,845

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.18K ops/sec 457.904 437.027 655.316 0.227 1,092
🥈 lmdb 2 4.15 ops/sec 240,952.491 235,173.981 259,145.43 2.63 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.18K ops/sec 459.512 435.68 604.464 0.189 1,089
🥈 lmdb 2 4.20 ops/sec 238,013.794 232,578.361 257,329.249 2.10 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 962.14 ops/sec 1,039.344 875.339 15,535.202 5.70 482
🥈 lmdb 2 3.89 ops/sec 256,948.396 247,914.776 295,567.501 4.16 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 995.78 ops/sec 1,004.24 899.733 1,620.08 0.523 498
🥈 lmdb 2 3.89 ops/sec 256,945.003 239,034.278 299,201.578 4.73 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.10K ops/sec 907.886 434.766 243,346.739 95.16 551
🥈 lmdb 2 4.14 ops/sec 241,730.36 234,347.431 259,310.396 2.52 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 50.38 ops/sec 19,849.154 18,055.354 21,636.204 2.71 26.00
🥈 lmdb 2 2.68 ops/sec 372,993.495 330,294.993 407,450.01 3.71 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 4.60 ops/sec 217,195.97 185,833.568 313,596.789 14.14 10.00
🥈 lmdb 2 1.65 ops/sec 607,477.41 578,735.986 637,453.385 2.32 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 0.26 ops/sec 3,782,878.062 3,054,516.105 4,054,198.634 5.27 10.00
🥈 rocksdb 2 0.22 ops/sec 4,620,986.926 4,208,642.046 5,145,213.485 3.97 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.89K ops/sec 529.014 490.999 961.328 0.586 946
🥈 lmdb 2 3.74 ops/sec 267,608.802 259,637.854 288,946.325 2.74 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 468.219 444.123 670.175 0.224 1,068
🥈 async 2 1.98K ops/sec 505.555 480.69 958.946 0.365 990

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.66K ops/sec 44.14 39.28 584.479 1.20 11,329
🥈 rocksdb 2 2.79K ops/sec 358.981 304.627 2,506.236 2.98 1,393

getRange() > full scan vs range scan

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb range scan 1 22.00K ops/sec 45.45 39.90 779.249 1.09 11,001
🥈 lmdb full scan 2 11.57K ops/sec 86.43 75.83 776.006 1.49 5,786
🥉 rocksdb range scan 3 6.35K ops/sec 157.395 135.289 760.773 1.21 3,177
rocksdb full scan 4 1.51K ops/sec 663.838 564.795 3,314.215 3.15 754

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 50.02K ops/sec 19.99 16.34 3,230.942 1.89 25,011
🥈 rocksdb 2 10.36K ops/sec 96.57 82.89 1,305.012 1.16 5,178

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 519.32K ops/sec 1.93 1.23 5,998.81 6.35 259,661
🥈 rocksdb 2 2.70K ops/sec 370.111 327.219 1,607.088 1.56 1,352

Reverse iteration > rocksdb - reverse vs forward

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 forward 1 3.04K ops/sec 328.562 298.769 1,547.74 1.68 1,522
🥈 reverse 2 2.83K ops/sec 353.789 317.493 1,653.281 1.53 1,414

Range query patterns > prefix scan performance

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 30.13K ops/sec 33.19 29.03 1,197.799 1.18 15,067
🥈 rocksdb 2 3.22K ops/sec 310.386 279.278 1,524.391 1.83 1,611

Sparse data patterns > sparse - range over gaps

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 58.20K ops/sec 17.18 14.93 1,806.822 1.52 29,100
🥈 rocksdb 2 5.78K ops/sec 172.877 153.946 1,169.182 1.21 2,893

Sparse data patterns > sparse - prefix with gaps

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 126.95K ops/sec 7.88 6.83 2,669.426 2.29 63,476
🥈 rocksdb 2 11.95K ops/sec 83.67 73.08 2,545.412 1.28 5,976

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.73K ops/sec 78.54 66.78 887.225 1.81 6,366
🥈 rocksdb 2 2.48K ops/sec 403.13 384.147 624.072 0.259 1,241

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 12.83K ops/sec 77.93 67.49 755.837 1.37 6,417
🥈 rocksdb 2 2.52K ops/sec 396.109 363.698 574.566 0.155 1,263

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 random 1 2.55K ops/sec 392.618 359.856 609.27 0.194 1,274
🥈 sequential 2 2.49K ops/sec 401.654 373.149 566.917 0.305 1,245

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 9.58K ops/sec 104.353 89.29 1,642.4 2.70 4,792
🥈 rocksdb 2 1.04K ops/sec 957.418 815.838 2,849.876 0.893 523

removeSync() > random access pattern (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 11.63K ops/sec 86.01 74.39 1,510.793 1.43 5,814
🥈 rocksdb 2 2.57K ops/sec 388.801 369.441 670.032 0.229 1,287

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 12.76K ops/sec 78.39 71.52 364.189 0.337 6,379
🥈 rocksdb 2 2.59K ops/sec 386.571 366.116 602.711 0.295 1,294

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 586.80 ops/sec 1,704.159 1,575.958 4,830.396 1.77 294
🥈 lmdb 2 4.23 ops/sec 236,267.394 234,193.14 239,765.431 0.598 10.00

transaction sync > optimistic > batch operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.91K ops/sec 343.819 307.668 1,936.28 0.867 1,455
🥈 lmdb 2 331.57 ops/sec 3,015.922 2,040.979 6,139.391 3.36 166

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 338.68 ops/sec 2,952.619 2,685.385 5,025.863 1.86 170
🥈 lmdb 2 4.20 ops/sec 238,276.842 232,333.021 258,402.948 2.29 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 577.76 ops/sec 1,730.828 1,656.198 3,384.134 1.21 289
🥈 lmdb 2 4.23 ops/sec 236,183.294 229,177.256 254,777.178 2.95 10.00

transaction sync > optimistic > rollback operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 16.33K ops/sec 61.23 58.56 345.43 0.382 8,167
🥈 rocksdb 2 5.57K ops/sec 179.692 169.521 878.825 0.334 2,783

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.92K ops/sec 341.975 301.425 926.226 0.328 1,463
🥈 rocksdb 2 579.52 ops/sec 1,725.574 1,647.44 4,355.136 1.46 290

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 362.82 ops/sec 2,756.212 2,120.7 7,582.706 2.53 182
🥈 lmdb 2 4.29 ops/sec 233,268.824 220,447.168 250,470.419 2.41 10.00

transaction sync > optimistic > empty transaction overhead

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 797.46K ops/sec 1.25 1.11 1,636.822 0.684 398,733
🥈 rocksdb 2 94.67K ops/sec 10.56 9.28 2,351.759 1.59 47,336

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 1.54K ops/sec 650.503 592.061 4,287.678 3.37 769
🥈 rocksdb 2 253.15 ops/sec 3,950.231 3,628.239 12,463.631 4.72 127

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 517.75 ops/sec 1,931.435 1,851.705 6,427.001 1.82 259
🥈 lmdb 2 4.24 ops/sec 235,968.692 229,142.81 254,166.218 2.96 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 304.74 ops/sec 3,281.452 2,776.244 5,951.056 3.12 153
🥈 lmdb 2 3.46 ops/sec 288,811.646 278,074.116 314,083.414 2.63 10.00

transaction > optimistic > batch operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 2.20K ops/sec 455.154 375.911 544.924 0.222 1,099
🥈 lmdb 2 277.87 ops/sec 3,598.769 2,211.594 6,425.877 3.57 139

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 222.47 ops/sec 4,494.986 3,905.238 10,199.652 3.33 112
🥈 lmdb 2 3.52 ops/sec 284,049.837 271,197.956 305,511.617 2.65 10.00

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 945.26 ops/sec 1,057.913 909.297 3,713.561 3.09 473
🥈 lmdb 2 294.09 ops/sec 3,400.3 2,276.498 9,365.5 5.13 148

transaction > optimistic > rollback operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 4.87K ops/sec 205.45 194.904 813.655 0.453 2,434
🥈 lmdb 2 301.05 ops/sec 3,321.658 3,127.421 3,621.423 0.322 151

transaction > optimistic > rocksdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 1.78K ops/sec 561.665 469.005 791.155 0.380 891
🥈 rocksdb 2 323.85 ops/sec 3,087.834 2,822.532 6,855.25 2.83 162

transaction > optimistic > lmdb - large transaction vs many small

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 311.37 ops/sec 3,211.633 2,246.653 3,581.553 1.61 156
🥈 lmdb 2 3.56 ops/sec 280,555.935 267,709.95 324,172.425 4.13 10.00

transaction > optimistic > empty transaction overhead

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 42.33K ops/sec 23.63 17.86 406.476 0.379 21,164
🥈 rocksdb 2 38.86K ops/sec 25.74 17.93 4,341.986 2.74 19,429

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 345.44 ops/sec 2,894.877 2,579.419 19,970.38 7.73 173
🥈 rocksdb 2 170.83 ops/sec 5,853.901 5,125.231 15,687.648 5.51 86.00

transaction > pessimistic > simple put operations (100 records)

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 rocksdb 1 61.60 ops/sec 16,233.925 3,774.792 42,526.744 31.29 31.00
🥈 lmdb 2 3.43 ops/sec 291,495.804 261,491.317 317,612.456 4.10 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 14.56K ops/sec 68.68 60.31 6,839.412 3.17 7,281
🥈 rocksdb 2 3.72K ops/sec 269.042 223.598 1,639.808 1.09 1,859

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

Implementation Rank Operations/sec Mean (ms) Min (ms) Max (ms) RME (%) Samples
🥇 lmdb 1 14.24K ops/sec 70.25 61.65 6,925.491 3.28 7,118
🥈 rocksdb 2 3.53K ops/sec 283.378 237.085 1,330.099 1.02 1,765

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.34K ops/sec 136.185 117.721 6,584.48 2.57 3,672
🥈 rocksdb 2 1.73K ops/sec 576.914 493.062 3,445.914 2.31 867

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 551.609 492.58 4,007.518 1.49 907
🥈 lmdb 2 4.00 ops/sec 250,015.179 236,950.258 271,529.806 3.63 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.46K ops/sec 686.063 621.805 2,659.176 0.923 729
🥈 lmdb 2 2.08 ops/sec 480,865.665 459,070.214 516,792.659 2.44 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 813.00 ops/sec 1,230.014 1,106.54 4,260.964 1.49 407
🥈 lmdb 2 1.10 ops/sec 909,743.207 795,861.229 1,039,774.864 6.87 10.00

Results from commit 5160fa8

// for writes at specific offset, update size if we wrote beyond current end
size_t newEnd = static_cast<size_t>(offset) + static_cast<size_t>(bytesWritten);
size_t currentSize = this->size.load();
while (newEnd > currentSize && !this->size.compare_exchange_weak(currentSize, newEnd)) {
Copy link
Member

Choose a reason for hiding this comment

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

FWIW, I think calls to write to the log file would need to be synchronized; I think we would expect that there there would a lock at higher level (in the eventual commit that calls this) to ensure we acquire a mutex, do all the writes for a transaction, increment the offset, and then release the mutex, so anything inside this function could expect that we are already in synchronized/locked execution for a file.

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