Skip to content
This repository was archived by the owner on Jan 27, 2026. It is now read-only.

Commit be8a6ad

Browse files
committed
docs reorg
1 parent d7961da commit be8a6ad

File tree

3 files changed

+192
-186
lines changed

3 files changed

+192
-186
lines changed

.github/workflows/redbit.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,14 +171,14 @@ jobs:
171171
}
172172
/<!-- END_BENCH -->/ { print; in_bench = 0; next }
173173
!in_bench { print }
174-
' README.md > README.md.tmp && mv README.md.tmp README.md
174+
' chains/README.md > chains/README.md.tmp && mv chains/README.md.tmp chains/README.md
175175
176176
- name: Commit benchmark results to README
177177
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
178178
run: |
179179
git config --global user.name "github-actions[bot]"
180180
git config --global user.email "[email protected]"
181-
git diff --quiet || (git add README.md && git commit -m "Auto-update README with example code" && git push)
181+
git diff --quiet || (git add chains/README.md && git commit -m "Auto-update README with example code" && git push)
182182
183183
deploy:
184184
if: github.event_name == 'push' && github.ref == 'refs/heads/master'

README.md

Lines changed: 23 additions & 183 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,9 @@ make them catch up with others even if they are HOT, see [chain](chain/README.md
6262

6363
❌ Root key must be newtype struct with numeric inner type (that's part of the design decision to achieve fast indexing of even whole bitcoin)
6464

65-
### Why and when redb?
65+
### Blockchains
6666

67-
Redb is copy-on-write (COW) B+Tree based so in comparison to LSM tree with WAL or log-structured heap, in order
68-
to avoid benchmarking our SSD by random-access writes, ie. to rapidly reduce write amplification, we need to :
69-
70-
- systematically combine durable and non-durable writes to leverage Linux VM (page cache) and reduce amount of fsync calls
71-
- sort all data in batches before writing it to reduce tree building overhead
72-
- solved by parallelizing writes to all columns into long-running batching threads
73-
74-
### Why Macros?
75-
76-
1. Rust's type system is not as expressive as e.g. Haskell's or Scala's for performance reasons
77-
2. Rust's macro system is powerful and straightforward to use
78-
79-
So, I find model driven development with code generation a great fit for Rust. It performs very well unless we generate 50k lines of code
80-
which would be the case of deeply nested entities with many indexes and dictionaries.
81-
82-
The core idea is about deriving R/W entity methods and nested entity definition `println!("{:#?}", Block::definition()?);` from struct annotations.
83-
Definition holds all the entity meta information, and it is used to create rich R/W transaction contexts that are used by derived entity R/W methods.
67+
See [chain](./chain) and [chains](./chains).
8468

8569
### Development
8670

@@ -338,174 +322,30 @@ Deleting blocks:");
338322

339323
The same api is accessible through http endpoints at http://127.0.0.1:3033/swagger-ui/.
340324

341-
### ⏱ Redbit benchmarks (results from github servers)
342-
343-
The demo example persists data into 24 tables to allow for rich querying. Each `index` is backed by 2 tables and `dictionary` by 4 tables.
344-
Each PK, FK, simple column, index or dictionary is backed by its own redb DB and a long-running indexing thread. If you have 20 of these, you are still
345-
fine on Raspberry Pi, consider stronger machine for deeply nested entities with many indexes and dictionaries.
325+
### FAQ
346326

347-
Indexing process is always as slow as the column which in comparison to others has either bigger values, more values or combination of both.
327+
**Why and when redb?**
348328

349-
See [chain](./chain) for more details on performance and data size.
329+
Redb is copy-on-write (COW) B+Tree based so in comparison to LSM tree with WAL or log-structured heap, in order
330+
to avoid benchmarking our SSD by random-access writes, ie. to rapidly reduce write amplification, we need to :
350331

351-
The `persist/remove` methods are slower because each bench iteration opens ~ 34 new databases for whole block.
352-
The throughput is ~ **10 000 blocks/s** in batch mode which is ~ **300 000 db rows/s** until B+Tree grows significantly
353-
=> write amplification increases and kernel page cache is fully utilized => kernel throttles writes.
354-
355-
The `block::_store_many` operation in this context writes and commits 3 blocks of 3 transactions of 1 input and 3 utxos of 3 assets, ie.
356-
the operations writes :
357-
- 3 blocks
358-
- 3 * 3 = 9 transactions
359-
- 3 * 3 = 9 inputs
360-
- 3 * 3 * 3 = 27 utxos
361-
- 3 * 3 * 3 * 3 = 81 assets
362-
363-
`block::_first` operation reads whole block with all its transactions, inputs, utxos and assets.
364-
365-
<!-- BEGIN_BENCH -->
366-
```
367-
function ops/s
368-
-------------------------------------------------------------
369-
model_v1::block_bench::_store_many 95
370-
model_v1::block_bench::_persist 98
371-
model_v1::block_bench::_remove 114
372-
model_v1::block_bench::_store 116
373-
model_v1::transaction_bench::_persist 117
374-
model_v1::transaction_bench::_store_many 119
375-
model_v1::transaction_bench::_store 121
376-
model_v1::transaction_bench::_remove 122
377-
model_v1::utxo_bench::_store 213
378-
model_v1::utxo_bench::_store_many 222
379-
model_v1::utxo_bench::_persist 234
380-
model_v1::utxo_bench::_remove 238
381-
model_v1::input_bench::_store_many 363
382-
model_v1::input_bench::_store 365
383-
model_v1::header_bench::_persist 876
384-
model_v1::header_bench::_remove 1531
385-
model_v1::asset_bench::_persist 1868
386-
model_v1::input_bench::_persist 2258
387-
model_v1::maybevalue_bench::_persist 2377
388-
model_v1::asset_bench::_remove 2441
389-
model_v1::input_bench::_remove 2678
390-
model_v1::maybevalue_bench::_remove 3083
391-
model_v1::header_bench::_store_many 3779
392-
model_v1::header_bench::_store 3966
393-
model_v1::block_bench::_take 4402
394-
model_v1::block_bench::_tail 4439
395-
model_v1::block_bench::_stream_range 6226
396-
model_v1::asset_bench::_store_many 6719
397-
model_v1::transaction_bench::_stream_blocks_by_hash 6720
398-
model_v1::asset_bench::_store 7274
399-
model_v1::transaction_bench::_stream_range 8724
400-
model_v1::block_bench::_get 9268
401-
model_v1::block_bench::_get_transactions 9273
402-
model_v1::block_bench::_first 9297
403-
model_v1::maybevalue_bench::_store_many 9297
404-
model_v1::block_bench::_last 9372
405-
model_v1::transaction_bench::_stream_by_hash 9594
406-
model_v1::maybevalue_bench::_store 9977
407-
model_v1::utxo_bench::_stream_transactions_by_address 10637
408-
model_v1::transaction_bench::_stream_ids_by_hash 11705
409-
model_v1::transaction_bench::_tail 14276
410-
model_v1::transaction_bench::_take 14298
411-
model_v1::utxo_bench::_stream_range 19006
412-
model_v1::utxo_bench::_stream_by_address 20504
413-
model_v1::asset_bench::_stream_utxos_by_name 21895
414-
model_v1::utxo_bench::_stream_ids_by_address 23441
415-
model_v1::transaction_bench::_get_by_hash 29884
416-
model_v1::transaction_bench::_get 30088
417-
model_v1::transaction_bench::_first 30334
418-
model_v1::transaction_bench::_last 30670
419-
model_v1::block_bench::_range 34196
420-
model_v1::header_bench::_stream_range_by_duration 34988
421-
model_v1::header_bench::_stream_range_by_timestamp 35487
422-
model_v1::header_bench::_stream_range 36544
423-
model_v1::block_bench::_filter 38636
424-
model_v1::header_bench::_stream_by_duration 39347
425-
model_v1::transaction_bench::_range 39544
426-
model_v1::header_bench::_stream_by_prev_hash 39592
427-
model_v1::header_bench::_stream_by_hash 39697
428-
model_v1::header_bench::_stream_heights_by_hash 39773
429-
model_v1::header_bench::_stream_by_timestamp 39849
430-
model_v1::header_bench::_stream_heights_by_duration 39928
431-
model_v1::header_bench::_stream_heights_by_prev_hash 41852
432-
model_v1::header_bench::_stream_heights_by_timestamp 41958
433-
model_v1::asset_bench::_stream_range 59811
434-
model_v1::transaction_bench::_get_utxos 64167
435-
model_v1::transaction_bench::_filter 65851
436-
model_v1::asset_bench::_stream_by_name 69869
437-
model_v1::asset_bench::_stream_ids_by_name 73783
438-
model_v1::utxo_bench::_tail 90525
439-
model_v1::maybevalue_bench::_stream_range 92743
440-
model_v1::utxo_bench::_take 92834
441-
model_v1::input_bench::_stream_range 94367
442-
model_v1::maybevalue_bench::_stream_by_hash 122303
443-
model_v1::maybevalue_bench::_stream_ids_by_hash 126754
444-
model_v1::utxo_bench::_range 147605
445-
model_v1::utxo_bench::_get_by_address 225505
446-
model_v1::utxo_bench::_first 241857
447-
model_v1::utxo_bench::_get 243322
448-
model_v1::utxo_bench::_last 246105
449-
model_v1::utxo_bench::_filter 260995
450-
model_v1::utxo_bench::_get_assets 277423
451-
model_v1::asset_bench::_tail 308916
452-
model_v1::asset_bench::_range 315533
453-
model_v1::header_bench::_tail 321105
454-
model_v1::header_bench::_range_by_duration 327259
455-
model_v1::transaction_bench::_get_inputs 333016
456-
model_v1::input_bench::_range 338707
457-
model_v1::header_bench::_range 338709
458-
model_v1::header_bench::_take 340333
459-
model_v1::input_bench::_tail 346649
460-
model_v1::header_bench::_range_by_timestamp 349984
461-
model_v1::asset_bench::_take 352473
462-
model_v1::maybevalue_bench::_range 356888
463-
model_v1::maybevalue_bench::_tail 365762
464-
model_v1::input_bench::_take 392355
465-
model_v1::maybevalue_bench::_take 412213
466-
model_v1::asset_bench::_get_by_name 1558142
467-
model_v1::header_bench::_get_by_duration 1708205
468-
model_v1::header_bench::_get_by_timestamp 1872835
469-
model_v1::header_bench::_get_by_prev_hash 1904653
470-
model_v1::header_bench::_get_by_hash 1924298
471-
model_v1::header_bench::_filter 2351503
472-
model_v1::asset_bench::_filter 2394923
473-
model_v1::asset_bench::_get 2600307
474-
model_v1::header_bench::_last 2649498
475-
model_v1::header_bench::_first 2670584
476-
model_v1::asset_bench::_first 2687016
477-
model_v1::block_bench::_get_header 2723534
478-
model_v1::asset_bench::_last 2787223
479-
model_v1::header_bench::_get 2845193
480-
model_v1::maybevalue_bench::_get_by_hash 3114392
481-
model_v1::asset_bench::_get_ids_by_name 3467046
482-
model_v1::utxo_bench::_get_ids_by_address 3538821
483-
model_v1::input_bench::_filter 4171359
484-
model_v1::input_bench::_get 4342351
485-
model_v1::header_bench::_get_heights_by_duration 4359578
486-
model_v1::input_bench::_last 4418913
487-
model_v1::input_bench::_first 4543389
488-
model_v1::transaction_bench::_get_ids_by_hash 4953192
489-
model_v1::maybevalue_bench::_get_ids_by_hash 5098919
490-
model_v1::header_bench::_get_heights_by_prev_hash 5232589
491-
model_v1::header_bench::_get_heights_by_hash 5261496
492-
model_v1::header_bench::_get_heights_by_timestamp 5537405
493-
model_v1::maybevalue_bench::_last 6679581
494-
model_v1::maybevalue_bench::_first 6877106
495-
model_v1::maybevalue_bench::_filter 6908463
496-
model_v1::maybevalue_bench::_get 6992518
497-
model_v1::transaction_bench::_get_maybe 7039775
498-
model_v1::asset_bench::_exists 9485866
499-
model_v1::input_bench::_exists 10997471
500-
model_v1::utxo_bench::_exists 11128422
501-
model_v1::maybevalue_bench::_exists 12685526
502-
model_v1::transaction_bench::_exists 13386881
503-
model_v1::header_bench::_exists 17448962
504-
model_v1::block_bench::_exists 17568517
505-
```
506-
<!-- END_BENCH -->
332+
- systematically combine durable and non-durable writes to leverage Linux VM (page cache) and reduce amount of fsync calls
333+
- sort all data in batches before writing it to reduce tree building overhead
334+
- solved by parallelizing writes to all columns into long-running batching threads
507335

336+
**Why Macros?**
508337

509-
## Chain
338+
1. Rust's type system is not as expressive as e.g. Haskell's or Scala's for performance reasons
339+
2. Rust's macros are powerful, easy to use, maintain and insanely fast to compile, there is very little compile time overhead
340+
3. Code generation speeds up runtime at hot spots, think of it as inlining
341+
- for instance SQL layer has huge overhead of parsing, planning, optimizing and executing queries for inserting each row
342+
- redbit macro derives the exact R/W code for the user commands so the only overhead is either :
343+
- serialization of value to bytes
344+
- handing a reference to redb in case we use `Vec<u8>` or `&[u8]` directly
345+
- we write by many threads (CPU gen get fully utilized) and the dispatching thread would otherwise become a bottleneck
346+
347+
So, I find model driven development with code generation a great fit for Rust and blockchains. It performs very well unless we generate 50k lines of code
348+
which would be the case of deeply nested entities with many indexes and dictionaries.
510349

511-
See [chain](./chain)
350+
The core idea is about deriving R/W entity methods and nested entity definition `println!("{:#?}", Block::definition()?);` from struct annotations.
351+
Definition holds all the entity meta information, and it is used to create rich R/W transaction contexts that are used by derived entity R/W methods.

0 commit comments

Comments
 (0)