tigerbeetle 0.0.34 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/ext/tb_client/extconf.rb +13 -13
- data/ext/tb_client/tigerbeetle/LICENSE +177 -0
- data/ext/tb_client/tigerbeetle/build.zig +2327 -0
- data/ext/tb_client/tigerbeetle/src/aof.zig +1000 -0
- data/ext/tb_client/tigerbeetle/src/build_multiversion.zig +808 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/protocol.zig +1283 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/spec.zig +1704 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp/types.zig +341 -0
- data/ext/tb_client/tigerbeetle/src/cdc/amqp.zig +1450 -0
- data/ext/tb_client/tigerbeetle/src/cdc/runner.zig +1659 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/samples/main.c +406 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/context.zig +1084 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/echo_client.zig +286 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/packet.zig +158 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal.zig +229 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client/signal_fuzz.zig +110 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_exports.zig +281 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header.zig +312 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/tb_client_header_test.zig +138 -0
- data/ext/tb_client/tigerbeetle/src/clients/c/test.zig +466 -0
- data/ext/tb_client/tigerbeetle/src/clients/docs_samples.zig +157 -0
- data/ext/tb_client/tigerbeetle/src/clients/docs_types.zig +90 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/ci.zig +203 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/docs.zig +79 -0
- data/ext/tb_client/tigerbeetle/src/clients/dotnet/dotnet_bindings.zig +542 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/ci.zig +109 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/docs.zig +86 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/go_bindings.zig +370 -0
- data/ext/tb_client/tigerbeetle/src/clients/go/pkg/native/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/ci.zig +167 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/docs.zig +126 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/java_bindings.zig +996 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/client.zig +748 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni.zig +3238 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_tests.zig +1718 -0
- data/ext/tb_client/tigerbeetle/src/clients/java/src/jni_thread_cleaner.zig +190 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/ci.zig +104 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/docs.zig +75 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/node.zig +522 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/node_bindings.zig +267 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/src/c.zig +3 -0
- data/ext/tb_client/tigerbeetle/src/clients/node/src/translate.zig +379 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/ci.zig +131 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/docs.zig +63 -0
- data/ext/tb_client/tigerbeetle/src/clients/python/python_bindings.zig +588 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/assets/tb_client.h +386 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/ci.zig +73 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/docs.zig +106 -0
- data/ext/tb_client/tigerbeetle/src/clients/rust/rust_bindings.zig +305 -0
- data/ext/tb_client/tigerbeetle/src/config.zig +296 -0
- data/ext/tb_client/tigerbeetle/src/constants.zig +790 -0
- data/ext/tb_client/tigerbeetle/src/copyhound.zig +202 -0
- data/ext/tb_client/tigerbeetle/src/counting_allocator.zig +72 -0
- data/ext/tb_client/tigerbeetle/src/direction.zig +11 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/build.zig +158 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/content.zig +156 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/docs.zig +252 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/file_checker.zig +313 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/html.zig +87 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/page_writer.zig +63 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/redirects.zig +47 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/search_index_writer.zig +28 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/service_worker_writer.zig +61 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/single_page_writer.zig +169 -0
- data/ext/tb_client/tigerbeetle/src/docs_website/src/website.zig +46 -0
- data/ext/tb_client/tigerbeetle/src/ewah.zig +445 -0
- data/ext/tb_client/tigerbeetle/src/ewah_benchmark.zig +128 -0
- data/ext/tb_client/tigerbeetle/src/ewah_fuzz.zig +171 -0
- data/ext/tb_client/tigerbeetle/src/fuzz_tests.zig +179 -0
- data/ext/tb_client/tigerbeetle/src/integration_tests.zig +662 -0
- data/ext/tb_client/tigerbeetle/src/io/common.zig +155 -0
- data/ext/tb_client/tigerbeetle/src/io/darwin.zig +1093 -0
- data/ext/tb_client/tigerbeetle/src/io/linux.zig +1880 -0
- data/ext/tb_client/tigerbeetle/src/io/test.zig +1005 -0
- data/ext/tb_client/tigerbeetle/src/io/windows.zig +1598 -0
- data/ext/tb_client/tigerbeetle/src/io.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/iops.zig +134 -0
- data/ext/tb_client/tigerbeetle/src/list.zig +236 -0
- data/ext/tb_client/tigerbeetle/src/lsm/binary_search.zig +848 -0
- data/ext/tb_client/tigerbeetle/src/lsm/binary_search_benchmark.zig +179 -0
- data/ext/tb_client/tigerbeetle/src/lsm/cache_map.zig +424 -0
- data/ext/tb_client/tigerbeetle/src/lsm/cache_map_fuzz.zig +420 -0
- data/ext/tb_client/tigerbeetle/src/lsm/compaction.zig +2117 -0
- data/ext/tb_client/tigerbeetle/src/lsm/composite_key.zig +182 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest.zig +1119 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest_fuzz.zig +1102 -0
- data/ext/tb_client/tigerbeetle/src/lsm/forest_table_iterator.zig +200 -0
- data/ext/tb_client/tigerbeetle/src/lsm/groove.zig +1495 -0
- data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge.zig +739 -0
- data/ext/tb_client/tigerbeetle/src/lsm/k_way_merge_benchmark.zig +166 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest.zig +754 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_level.zig +1294 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_level_fuzz.zig +510 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_log.zig +1263 -0
- data/ext/tb_client/tigerbeetle/src/lsm/manifest_log_fuzz.zig +628 -0
- data/ext/tb_client/tigerbeetle/src/lsm/node_pool.zig +247 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_buffer.zig +116 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_builder.zig +543 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_fuzz.zig +938 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_lookup.zig +293 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_merge.zig +362 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_range.zig +99 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_state.zig +17 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scan_tree.zig +1036 -0
- data/ext/tb_client/tigerbeetle/src/lsm/schema.zig +617 -0
- data/ext/tb_client/tigerbeetle/src/lsm/scratch_memory.zig +84 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array.zig +1500 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_benchmark.zig +149 -0
- data/ext/tb_client/tigerbeetle/src/lsm/segmented_array_fuzz.zig +7 -0
- data/ext/tb_client/tigerbeetle/src/lsm/set_associative_cache.zig +865 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table.zig +607 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table_memory.zig +843 -0
- data/ext/tb_client/tigerbeetle/src/lsm/table_value_iterator.zig +105 -0
- data/ext/tb_client/tigerbeetle/src/lsm/timestamp_range.zig +40 -0
- data/ext/tb_client/tigerbeetle/src/lsm/tree.zig +630 -0
- data/ext/tb_client/tigerbeetle/src/lsm/tree_fuzz.zig +933 -0
- data/ext/tb_client/tigerbeetle/src/lsm/zig_zag_merge.zig +557 -0
- data/ext/tb_client/tigerbeetle/src/message_buffer.zig +469 -0
- data/ext/tb_client/tigerbeetle/src/message_bus.zig +1214 -0
- data/ext/tb_client/tigerbeetle/src/message_bus_fuzz.zig +936 -0
- data/ext/tb_client/tigerbeetle/src/message_pool.zig +343 -0
- data/ext/tb_client/tigerbeetle/src/multiversion.zig +2195 -0
- data/ext/tb_client/tigerbeetle/src/queue.zig +390 -0
- data/ext/tb_client/tigerbeetle/src/repl/completion.zig +201 -0
- data/ext/tb_client/tigerbeetle/src/repl/parser.zig +1356 -0
- data/ext/tb_client/tigerbeetle/src/repl/terminal.zig +496 -0
- data/ext/tb_client/tigerbeetle/src/repl.zig +1034 -0
- data/ext/tb_client/tigerbeetle/src/scripts/amqp.zig +973 -0
- data/ext/tb_client/tigerbeetle/src/scripts/cfo.zig +1866 -0
- data/ext/tb_client/tigerbeetle/src/scripts/changelog.zig +304 -0
- data/ext/tb_client/tigerbeetle/src/scripts/ci.zig +227 -0
- data/ext/tb_client/tigerbeetle/src/scripts/client_readmes.zig +658 -0
- data/ext/tb_client/tigerbeetle/src/scripts/devhub.zig +466 -0
- data/ext/tb_client/tigerbeetle/src/scripts/release.zig +1058 -0
- data/ext/tb_client/tigerbeetle/src/scripts.zig +105 -0
- data/ext/tb_client/tigerbeetle/src/shell.zig +1195 -0
- data/ext/tb_client/tigerbeetle/src/stack.zig +260 -0
- data/ext/tb_client/tigerbeetle/src/state_machine/auditor.zig +911 -0
- data/ext/tb_client/tigerbeetle/src/state_machine/workload.zig +2079 -0
- data/ext/tb_client/tigerbeetle/src/state_machine.zig +4872 -0
- data/ext/tb_client/tigerbeetle/src/state_machine_fuzz.zig +288 -0
- data/ext/tb_client/tigerbeetle/src/state_machine_tests.zig +3128 -0
- data/ext/tb_client/tigerbeetle/src/static_allocator.zig +82 -0
- data/ext/tb_client/tigerbeetle/src/stdx/bit_set.zig +157 -0
- data/ext/tb_client/tigerbeetle/src/stdx/bounded_array.zig +292 -0
- data/ext/tb_client/tigerbeetle/src/stdx/debug.zig +65 -0
- data/ext/tb_client/tigerbeetle/src/stdx/flags.zig +1414 -0
- data/ext/tb_client/tigerbeetle/src/stdx/mlock.zig +92 -0
- data/ext/tb_client/tigerbeetle/src/stdx/prng.zig +677 -0
- data/ext/tb_client/tigerbeetle/src/stdx/radix.zig +336 -0
- data/ext/tb_client/tigerbeetle/src/stdx/ring_buffer.zig +511 -0
- data/ext/tb_client/tigerbeetle/src/stdx/sort_test.zig +112 -0
- data/ext/tb_client/tigerbeetle/src/stdx/stdx.zig +1160 -0
- data/ext/tb_client/tigerbeetle/src/stdx/testing/low_level_hash_vectors.zig +142 -0
- data/ext/tb_client/tigerbeetle/src/stdx/testing/snaptest.zig +361 -0
- data/ext/tb_client/tigerbeetle/src/stdx/time_units.zig +275 -0
- data/ext/tb_client/tigerbeetle/src/stdx/unshare.zig +295 -0
- data/ext/tb_client/tigerbeetle/src/stdx/vendored/aegis.zig +436 -0
- data/ext/tb_client/tigerbeetle/src/stdx/windows.zig +48 -0
- data/ext/tb_client/tigerbeetle/src/stdx/zipfian.zig +402 -0
- data/ext/tb_client/tigerbeetle/src/storage.zig +489 -0
- data/ext/tb_client/tigerbeetle/src/storage_fuzz.zig +180 -0
- data/ext/tb_client/tigerbeetle/src/testing/bench.zig +146 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/grid_checker.zig +53 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/journal_checker.zig +61 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/manifest_checker.zig +76 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/message_bus.zig +110 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/network.zig +412 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/state_checker.zig +331 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster/storage_checker.zig +458 -0
- data/ext/tb_client/tigerbeetle/src/testing/cluster.zig +1198 -0
- data/ext/tb_client/tigerbeetle/src/testing/exhaustigen.zig +128 -0
- data/ext/tb_client/tigerbeetle/src/testing/fixtures.zig +181 -0
- data/ext/tb_client/tigerbeetle/src/testing/fuzz.zig +144 -0
- data/ext/tb_client/tigerbeetle/src/testing/id.zig +97 -0
- data/ext/tb_client/tigerbeetle/src/testing/io.zig +317 -0
- data/ext/tb_client/tigerbeetle/src/testing/marks.zig +126 -0
- data/ext/tb_client/tigerbeetle/src/testing/packet_simulator.zig +533 -0
- data/ext/tb_client/tigerbeetle/src/testing/reply_sequence.zig +154 -0
- data/ext/tb_client/tigerbeetle/src/testing/state_machine.zig +389 -0
- data/ext/tb_client/tigerbeetle/src/testing/storage.zig +1247 -0
- data/ext/tb_client/tigerbeetle/src/testing/table.zig +249 -0
- data/ext/tb_client/tigerbeetle/src/testing/time.zig +98 -0
- data/ext/tb_client/tigerbeetle/src/testing/tmp_tigerbeetle.zig +212 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/constants.zig +26 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/faulty_network.zig +580 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/java_driver/ci.zig +39 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/logged_process.zig +214 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/rust_driver/ci.zig +34 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/supervisor.zig +766 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/workload.zig +543 -0
- data/ext/tb_client/tigerbeetle/src/testing/vortex/zig_driver.zig +181 -0
- data/ext/tb_client/tigerbeetle/src/tidy.zig +1448 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_driver.zig +227 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/benchmark_load.zig +1069 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/cli.zig +1422 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect.zig +1658 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/inspect_integrity.zig +518 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/libtb_client.zig +36 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle/main.zig +646 -0
- data/ext/tb_client/tigerbeetle/src/tigerbeetle.zig +958 -0
- data/ext/tb_client/tigerbeetle/src/time.zig +236 -0
- data/ext/tb_client/tigerbeetle/src/trace/event.zig +745 -0
- data/ext/tb_client/tigerbeetle/src/trace/statsd.zig +462 -0
- data/ext/tb_client/tigerbeetle/src/trace.zig +556 -0
- data/ext/tb_client/tigerbeetle/src/unit_tests.zig +321 -0
- data/ext/tb_client/tigerbeetle/src/vopr.zig +1785 -0
- data/ext/tb_client/tigerbeetle/src/vortex.zig +101 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checkpoint_trailer.zig +473 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checksum.zig +208 -0
- data/ext/tb_client/tigerbeetle/src/vsr/checksum_benchmark.zig +43 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client.zig +768 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client_replies.zig +532 -0
- data/ext/tb_client/tigerbeetle/src/vsr/client_sessions.zig +338 -0
- data/ext/tb_client/tigerbeetle/src/vsr/clock.zig +1019 -0
- data/ext/tb_client/tigerbeetle/src/vsr/fault_detector.zig +279 -0
- data/ext/tb_client/tigerbeetle/src/vsr/free_set.zig +1381 -0
- data/ext/tb_client/tigerbeetle/src/vsr/free_set_fuzz.zig +315 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid.zig +1460 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid_blocks_missing.zig +757 -0
- data/ext/tb_client/tigerbeetle/src/vsr/grid_scrubber.zig +797 -0
- data/ext/tb_client/tigerbeetle/src/vsr/journal.zig +2586 -0
- data/ext/tb_client/tigerbeetle/src/vsr/marzullo.zig +308 -0
- data/ext/tb_client/tigerbeetle/src/vsr/message_header.zig +1777 -0
- data/ext/tb_client/tigerbeetle/src/vsr/multi_batch.zig +715 -0
- data/ext/tb_client/tigerbeetle/src/vsr/multi_batch_fuzz.zig +185 -0
- data/ext/tb_client/tigerbeetle/src/vsr/repair_budget.zig +333 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica.zig +12355 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_format.zig +416 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_reformat.zig +165 -0
- data/ext/tb_client/tigerbeetle/src/vsr/replica_test.zig +2910 -0
- data/ext/tb_client/tigerbeetle/src/vsr/routing.zig +1075 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock.zig +1603 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_fuzz.zig +484 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums.zig +405 -0
- data/ext/tb_client/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +355 -0
- data/ext/tb_client/tigerbeetle/src/vsr/sync.zig +29 -0
- data/ext/tb_client/tigerbeetle/src/vsr.zig +1727 -0
- data/lib/tb_client/shared_lib.rb +12 -5
- data/lib/tigerbeetle/client.rb +1 -1
- data/lib/tigerbeetle/platforms.rb +9 -0
- data/lib/tigerbeetle/version.rb +2 -2
- data/tigerbeetle.gemspec +22 -5
- metadata +242 -3
- data/ext/tb_client/pkg.tar.gz +0 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const mem = std.mem;
|
|
3
|
+
const math = std.math;
|
|
4
|
+
const assert = std.debug.assert;
|
|
5
|
+
|
|
6
|
+
const constants = @import("../constants.zig");
|
|
7
|
+
const vsr = @import("../vsr.zig");
|
|
8
|
+
const binary_search = @import("binary_search.zig");
|
|
9
|
+
|
|
10
|
+
const stdx = @import("stdx");
|
|
11
|
+
const div_ceil = stdx.div_ceil;
|
|
12
|
+
|
|
13
|
+
const TreeTableInfoType = @import("manifest.zig").TreeTableInfoType;
|
|
14
|
+
const schema = @import("schema.zig");
|
|
15
|
+
|
|
16
|
+
pub const TableUsage = enum {
|
|
17
|
+
/// General purpose table.
|
|
18
|
+
general,
|
|
19
|
+
/// If your usage fits this pattern:
|
|
20
|
+
/// * Only put keys which are not present.
|
|
21
|
+
/// * Only remove keys which are present.
|
|
22
|
+
/// * TableKey == TableValue (modulo padding, eg CompositeKey).
|
|
23
|
+
/// Then we can unlock additional optimizations:
|
|
24
|
+
/// * Immediately cancel out a tombstone and the corresponding insert, without waiting for the
|
|
25
|
+
/// tombstone to sink to the bottom of the LSM tree: absence of updates guarantees that
|
|
26
|
+
/// there are no otherwise visible values on lower level.
|
|
27
|
+
/// * Immediately cancel out an insert and a tombstone for a "different" insert: as the values
|
|
28
|
+
/// are equal, it is correct to just resurrect an older value.
|
|
29
|
+
secondary_index,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const address_size = @sizeOf(u64);
|
|
33
|
+
const checksum_size = @sizeOf(u256);
|
|
34
|
+
|
|
35
|
+
const block_size = constants.block_size;
|
|
36
|
+
const block_body_size = block_size - @sizeOf(vsr.Header);
|
|
37
|
+
|
|
38
|
+
const BlockPtr = *align(constants.sector_size) [block_size]u8;
|
|
39
|
+
const BlockPtrConst = *align(constants.sector_size) const [block_size]u8;
|
|
40
|
+
|
|
41
|
+
/// A table is a set of blocks:
|
|
42
|
+
///
|
|
43
|
+
/// * Index block (exactly 1)
|
|
44
|
+
/// * Value blocks (at least one, at most `value_block_count_max`) store the actual keys/values.
|
|
45
|
+
pub fn TableType(
|
|
46
|
+
comptime TableKey: type,
|
|
47
|
+
comptime TableValue: type,
|
|
48
|
+
/// Returns the key for a value. For example, given `object` returns `object.id`.
|
|
49
|
+
/// Since most objects contain an id, this avoids duplicating the key when storing the value.
|
|
50
|
+
comptime table_key_from_value: fn (*const TableValue) callconv(.@"inline") TableKey,
|
|
51
|
+
/// Must compare greater than all other keys.
|
|
52
|
+
comptime table_sentinel_key: TableKey,
|
|
53
|
+
/// Returns whether a value is a tombstone value.
|
|
54
|
+
comptime table_tombstone: fn (*const TableValue) callconv(.@"inline") bool,
|
|
55
|
+
/// Returns a tombstone value representation for a key.
|
|
56
|
+
comptime table_tombstone_from_key: fn (TableKey) callconv(.@"inline") TableValue,
|
|
57
|
+
/// The maximum number of values per table.
|
|
58
|
+
comptime table_value_count_max: usize,
|
|
59
|
+
comptime table_usage: TableUsage,
|
|
60
|
+
) type {
|
|
61
|
+
comptime assert(@typeInfo(TableKey) == .int or @typeInfo(TableKey) == .comptime_int);
|
|
62
|
+
|
|
63
|
+
return struct {
|
|
64
|
+
const Table = @This();
|
|
65
|
+
|
|
66
|
+
// Re-export all the generic arguments.
|
|
67
|
+
pub const Key = TableKey;
|
|
68
|
+
pub const Value = TableValue;
|
|
69
|
+
pub const key_from_value = table_key_from_value;
|
|
70
|
+
pub const sentinel_key = table_sentinel_key;
|
|
71
|
+
pub const tombstone = table_tombstone;
|
|
72
|
+
pub const tombstone_from_key = table_tombstone_from_key;
|
|
73
|
+
pub const value_count_max = table_value_count_max;
|
|
74
|
+
pub const usage = table_usage;
|
|
75
|
+
|
|
76
|
+
// Export hashmap context for Key and Value
|
|
77
|
+
pub const HashMapContextValue = struct {
|
|
78
|
+
pub inline fn eql(_: HashMapContextValue, a: Value, b: Value) bool {
|
|
79
|
+
return key_from_value(&a) == key_from_value(&b);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
pub inline fn hash(_: HashMapContextValue, value: Value) u64 {
|
|
83
|
+
return stdx.hash_inline(key_from_value(&value));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
pub const key_size = @sizeOf(Key);
|
|
88
|
+
pub const value_size = @sizeOf(Value);
|
|
89
|
+
|
|
90
|
+
comptime {
|
|
91
|
+
assert(@alignOf(Key) == 8 or @alignOf(Key) == 16);
|
|
92
|
+
// TODO(ifreund) What are our alignment expectations for Value?
|
|
93
|
+
|
|
94
|
+
// There must be no padding in the Key/Value types to avoid buffer bleeds.
|
|
95
|
+
assert(stdx.no_padding(Key));
|
|
96
|
+
assert(stdx.no_padding(Value));
|
|
97
|
+
|
|
98
|
+
// These impact our calculation of:
|
|
99
|
+
// * the manifest log layout for alignment.
|
|
100
|
+
assert(key_size >= 8);
|
|
101
|
+
assert(key_size <= 32);
|
|
102
|
+
assert(key_size == 8 or key_size == 16 or key_size == 24 or key_size == 32);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
pub const layout = layout: {
|
|
106
|
+
assert(block_size % constants.sector_size == 0);
|
|
107
|
+
assert(math.isPowerOfTwo(block_size));
|
|
108
|
+
|
|
109
|
+
// If the index is smaller than 16 keys then there are key sizes >= 4 such that
|
|
110
|
+
// the total index size is not 64 byte cache line aligned.
|
|
111
|
+
assert(@sizeOf(Key) >= 4);
|
|
112
|
+
assert(@sizeOf(Key) % 4 == 0);
|
|
113
|
+
|
|
114
|
+
assert(block_body_size >= value_size);
|
|
115
|
+
const block_value_count_max = @divFloor(
|
|
116
|
+
block_body_size,
|
|
117
|
+
value_size,
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
// We need enough blocks to hold `value_count_max` values.
|
|
121
|
+
const value_blocks = div_ceil(value_count_max, block_value_count_max);
|
|
122
|
+
assert(value_blocks >= 1);
|
|
123
|
+
assert(value_blocks <= constants.lsm_table_value_blocks_max);
|
|
124
|
+
|
|
125
|
+
break :layout .{
|
|
126
|
+
// The maximum number of values in a value block.
|
|
127
|
+
.block_value_count_max = block_value_count_max,
|
|
128
|
+
.value_block_count_max = value_blocks,
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const index_block_count = 1;
|
|
133
|
+
pub const value_block_count_max = layout.value_block_count_max;
|
|
134
|
+
pub const block_count_max = index_block_count + value_block_count_max;
|
|
135
|
+
|
|
136
|
+
pub const index = schema.TableIndex.init(.{
|
|
137
|
+
.key_size = key_size,
|
|
138
|
+
.value_block_count_max = value_block_count_max,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
pub const data = schema.TableValue.init(.{
|
|
142
|
+
.value_count_max = layout.block_value_count_max,
|
|
143
|
+
.value_size = value_size,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const compile_log_layout = false;
|
|
147
|
+
comptime {
|
|
148
|
+
if (compile_log_layout) {
|
|
149
|
+
@compileError(std.fmt.comptimePrint(
|
|
150
|
+
\\
|
|
151
|
+
\\
|
|
152
|
+
\\lsm parameters:
|
|
153
|
+
\\ value: {}
|
|
154
|
+
\\ value count max: {}
|
|
155
|
+
\\ key size: {}
|
|
156
|
+
\\ value size: {}
|
|
157
|
+
\\ block size: {}
|
|
158
|
+
\\layout:
|
|
159
|
+
\\ index block count: {}
|
|
160
|
+
\\ value block count max: {}
|
|
161
|
+
\\index:
|
|
162
|
+
\\ size: {}
|
|
163
|
+
\\ value_checksums_offset: {}
|
|
164
|
+
\\ value_checksums_size: {}
|
|
165
|
+
\\ keys_min_offset: {}
|
|
166
|
+
\\ keys_max_offset: {}
|
|
167
|
+
\\ keys_size: {}
|
|
168
|
+
\\ value_addresses_offset: {}
|
|
169
|
+
\\ value_addresses_size: {}
|
|
170
|
+
\\data:
|
|
171
|
+
\\ value_count_max: {}
|
|
172
|
+
\\ values_offset: {}
|
|
173
|
+
\\ values_size: {}
|
|
174
|
+
\\ padding_offset: {}
|
|
175
|
+
\\ padding_size: {}
|
|
176
|
+
\\
|
|
177
|
+
,
|
|
178
|
+
.{
|
|
179
|
+
Value,
|
|
180
|
+
value_count_max,
|
|
181
|
+
key_size,
|
|
182
|
+
value_size,
|
|
183
|
+
block_size,
|
|
184
|
+
|
|
185
|
+
index_block_count,
|
|
186
|
+
value_block_count_max,
|
|
187
|
+
|
|
188
|
+
index.size,
|
|
189
|
+
index.value_checksums_offset,
|
|
190
|
+
index.value_checksums_size,
|
|
191
|
+
index.keys_min_offset,
|
|
192
|
+
index.keys_max_offset,
|
|
193
|
+
index.keys_size,
|
|
194
|
+
index.value_addresses_offset,
|
|
195
|
+
index.value_addresses_size,
|
|
196
|
+
|
|
197
|
+
data.value_count_max,
|
|
198
|
+
data.values_offset,
|
|
199
|
+
data.values_size,
|
|
200
|
+
data.padding_offset,
|
|
201
|
+
data.padding_size,
|
|
202
|
+
},
|
|
203
|
+
));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
comptime {
|
|
208
|
+
assert(index_block_count > 0);
|
|
209
|
+
assert(value_block_count_max > 0);
|
|
210
|
+
|
|
211
|
+
assert(index.size == @sizeOf(vsr.Header) +
|
|
212
|
+
value_block_count_max * ((key_size * 2) + address_size + checksum_size));
|
|
213
|
+
assert(index.size == index.value_addresses_offset + index.value_addresses_size);
|
|
214
|
+
assert(index.size <= block_size);
|
|
215
|
+
assert(index.keys_size > 0);
|
|
216
|
+
assert(index.keys_size % key_size == 0);
|
|
217
|
+
assert(@divExact(index.value_addresses_size, @sizeOf(u64)) == value_block_count_max);
|
|
218
|
+
assert(@divExact(index.value_checksums_size, @sizeOf(u256)) == value_block_count_max);
|
|
219
|
+
assert(block_size == index.padding_offset + index.padding_size);
|
|
220
|
+
assert(block_size == index.size + index.padding_size);
|
|
221
|
+
|
|
222
|
+
assert(data.value_count_max > 0);
|
|
223
|
+
assert(@divExact(data.values_size, value_size) == data.value_count_max);
|
|
224
|
+
assert(data.values_offset % constants.cache_line_size == 0);
|
|
225
|
+
// You can have any size value you want, as long as it fits
|
|
226
|
+
// neatly into the CPU cache lines :)
|
|
227
|
+
assert((data.value_count_max * value_size) % constants.cache_line_size == 0);
|
|
228
|
+
|
|
229
|
+
assert(data.padding_size >= 0);
|
|
230
|
+
assert(block_size == @sizeOf(vsr.Header) + data.values_size + data.padding_size);
|
|
231
|
+
assert(block_size == data.padding_offset + data.padding_size);
|
|
232
|
+
|
|
233
|
+
// We expect no block padding at least for TigerBeetle's objects and indexes:
|
|
234
|
+
if ((key_size == 8 and value_size == 128) or
|
|
235
|
+
(key_size == 8 and value_size == 64) or
|
|
236
|
+
(key_size == 16 and value_size == 16) or
|
|
237
|
+
(key_size == 32 and value_size == 32))
|
|
238
|
+
{
|
|
239
|
+
assert(data.padding_size == 0);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
pub const Builder = struct {
|
|
244
|
+
const TreeTableInfo = TreeTableInfoType(Table);
|
|
245
|
+
|
|
246
|
+
key_min: Key = undefined, // Inclusive.
|
|
247
|
+
key_max: Key = undefined, // Inclusive.
|
|
248
|
+
|
|
249
|
+
index_block: BlockPtr = undefined,
|
|
250
|
+
value_block: BlockPtr = undefined,
|
|
251
|
+
|
|
252
|
+
value_block_count: u32 = 0,
|
|
253
|
+
value_count: u32 = 0,
|
|
254
|
+
value_count_total: u32 = 0, // Count across the entire table.
|
|
255
|
+
|
|
256
|
+
state: enum { no_blocks, index_block, index_and_value_block } = .no_blocks,
|
|
257
|
+
|
|
258
|
+
pub fn set_index_block(builder: *Builder, block: BlockPtr) void {
|
|
259
|
+
assert(builder.state == .no_blocks);
|
|
260
|
+
assert(builder.value_block_count == 0);
|
|
261
|
+
assert(builder.value_count == 0);
|
|
262
|
+
assert(builder.value_count_total == 0);
|
|
263
|
+
|
|
264
|
+
builder.index_block = block;
|
|
265
|
+
builder.state = .index_block;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
pub fn set_value_block(builder: *Builder, block: BlockPtr) void {
|
|
269
|
+
assert(builder.state == .index_block);
|
|
270
|
+
assert(builder.value_count == 0);
|
|
271
|
+
|
|
272
|
+
builder.value_block = block;
|
|
273
|
+
builder.state = .index_and_value_block;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
pub fn value_block_values(builder: *Builder) []Value {
|
|
277
|
+
assert(builder.state == .index_and_value_block);
|
|
278
|
+
return Table.value_block_values(builder.value_block);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
pub fn value_block_empty(builder: *const Builder) bool {
|
|
282
|
+
stdx.maybe(builder.state == .no_blocks);
|
|
283
|
+
assert(builder.value_count <= data.value_count_max);
|
|
284
|
+
return builder.value_count == 0;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
pub fn value_block_full(builder: *const Builder) bool {
|
|
288
|
+
assert(builder.state == .index_and_value_block);
|
|
289
|
+
assert(builder.value_count <= data.value_count_max);
|
|
290
|
+
return builder.value_count == data.value_count_max;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const DataFinishOptions = struct {
|
|
294
|
+
cluster: u128,
|
|
295
|
+
release: vsr.Release,
|
|
296
|
+
address: u64,
|
|
297
|
+
snapshot_min: u64,
|
|
298
|
+
tree_id: u16,
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
pub fn value_block_finish(builder: *Builder, options: DataFinishOptions) void {
|
|
302
|
+
assert(builder.state == .index_and_value_block);
|
|
303
|
+
|
|
304
|
+
// For each block we write the sorted values,
|
|
305
|
+
// complete the block header, and add the block's max key to the table index.
|
|
306
|
+
|
|
307
|
+
assert(options.address > 0);
|
|
308
|
+
assert(builder.value_count > 0);
|
|
309
|
+
|
|
310
|
+
const block = builder.value_block;
|
|
311
|
+
const header = mem.bytesAsValue(vsr.Header.Block, block[0..@sizeOf(vsr.Header)]);
|
|
312
|
+
header.* = .{
|
|
313
|
+
.cluster = options.cluster,
|
|
314
|
+
.metadata_bytes = @bitCast(schema.TableValue.Metadata{
|
|
315
|
+
.value_count_max = data.value_count_max,
|
|
316
|
+
.value_count = builder.value_count,
|
|
317
|
+
.value_size = value_size,
|
|
318
|
+
.tree_id = options.tree_id,
|
|
319
|
+
}),
|
|
320
|
+
.address = options.address,
|
|
321
|
+
.snapshot = options.snapshot_min,
|
|
322
|
+
.size = @sizeOf(vsr.Header) + builder.value_count * @sizeOf(Value),
|
|
323
|
+
.command = .block,
|
|
324
|
+
.release = options.release,
|
|
325
|
+
.block_type = .value,
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
header.set_checksum_body(block[@sizeOf(vsr.Header)..header.size]);
|
|
329
|
+
header.set_checksum();
|
|
330
|
+
|
|
331
|
+
const values = Table.value_block_values_used(block);
|
|
332
|
+
{ // Now that we have checksummed the block, sanity-check the result:
|
|
333
|
+
|
|
334
|
+
if (constants.verify) {
|
|
335
|
+
var a = &values[0];
|
|
336
|
+
for (values[1..]) |*b| {
|
|
337
|
+
assert(key_from_value(a) < key_from_value(b));
|
|
338
|
+
a = b;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
assert(builder.value_count == values.len);
|
|
343
|
+
assert(block_size - header.size ==
|
|
344
|
+
(data.value_count_max - values.len) * @sizeOf(Value) + data.padding_size);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const key_min = key_from_value(&values[0]);
|
|
348
|
+
const key_max = if (values.len == 1) key_min else blk: {
|
|
349
|
+
const key = key_from_value(&values[values.len - 1]);
|
|
350
|
+
assert(key_min < key);
|
|
351
|
+
break :blk key;
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
const current = builder.value_block_count;
|
|
355
|
+
{ // Update the index block:
|
|
356
|
+
index_value_keys(builder.index_block, .key_min)[current] = key_min;
|
|
357
|
+
index_value_keys(builder.index_block, .key_max)[current] = key_max;
|
|
358
|
+
index.value_addresses(builder.index_block)[current] = options.address;
|
|
359
|
+
index.value_checksums(builder.index_block)[current] =
|
|
360
|
+
.{ .value = header.checksum };
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (current == 0) builder.key_min = key_min;
|
|
364
|
+
builder.key_max = key_max;
|
|
365
|
+
|
|
366
|
+
if (current == 0 and values.len == 1) {
|
|
367
|
+
assert(builder.key_min == builder.key_max);
|
|
368
|
+
} else {
|
|
369
|
+
assert(builder.key_min < builder.key_max);
|
|
370
|
+
}
|
|
371
|
+
assert(builder.key_max < sentinel_key);
|
|
372
|
+
|
|
373
|
+
if (current > 0) {
|
|
374
|
+
const slice = index_value_keys(builder.index_block, .key_max);
|
|
375
|
+
const key_max_prev = slice[current - 1];
|
|
376
|
+
assert(key_max_prev < key_from_value(&values[0]));
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
builder.value_block_count += 1;
|
|
380
|
+
builder.value_count_total += builder.value_count;
|
|
381
|
+
builder.value_count = 0;
|
|
382
|
+
builder.value_block = undefined;
|
|
383
|
+
builder.state = .index_block;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
pub fn index_block_empty(builder: *const Builder) bool {
|
|
387
|
+
stdx.maybe(builder.state == .no_blocks);
|
|
388
|
+
assert(builder.value_block_count <= value_block_count_max);
|
|
389
|
+
return builder.value_block_count == 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
pub fn index_block_full(builder: *const Builder) bool {
|
|
393
|
+
assert(builder.state != .no_blocks);
|
|
394
|
+
assert(builder.value_block_count <= value_block_count_max);
|
|
395
|
+
return builder.value_block_count == value_block_count_max;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
const IndexFinishOptions = struct {
|
|
399
|
+
cluster: u128,
|
|
400
|
+
release: vsr.Release,
|
|
401
|
+
address: u64,
|
|
402
|
+
snapshot_min: u64,
|
|
403
|
+
tree_id: u16,
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
pub fn index_block_finish(
|
|
407
|
+
builder: *Builder,
|
|
408
|
+
options: IndexFinishOptions,
|
|
409
|
+
) TreeTableInfo {
|
|
410
|
+
assert(builder.state == .index_block);
|
|
411
|
+
assert(options.address > 0);
|
|
412
|
+
assert(builder.value_block_empty());
|
|
413
|
+
assert(builder.value_block_count > 0);
|
|
414
|
+
assert(builder.value_count == 0);
|
|
415
|
+
|
|
416
|
+
const index_block = builder.index_block;
|
|
417
|
+
const header =
|
|
418
|
+
mem.bytesAsValue(vsr.Header.Block, index_block[0..@sizeOf(vsr.Header)]);
|
|
419
|
+
header.* = .{
|
|
420
|
+
.cluster = options.cluster,
|
|
421
|
+
.metadata_bytes = @bitCast(schema.TableIndex.Metadata{
|
|
422
|
+
.value_block_count = builder.value_block_count,
|
|
423
|
+
.value_block_count_max = index.value_block_count_max,
|
|
424
|
+
.tree_id = options.tree_id,
|
|
425
|
+
.key_size = index.key_size,
|
|
426
|
+
}),
|
|
427
|
+
.address = options.address,
|
|
428
|
+
.snapshot = options.snapshot_min,
|
|
429
|
+
.size = index.size,
|
|
430
|
+
.command = .block,
|
|
431
|
+
.release = options.release,
|
|
432
|
+
.block_type = .index,
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
for (index.padding(index_block)) |padding| {
|
|
436
|
+
@memset(index_block[padding.start..padding.end], 0);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
header.set_checksum_body(index_block[@sizeOf(vsr.Header)..header.size]);
|
|
440
|
+
header.set_checksum();
|
|
441
|
+
|
|
442
|
+
const info: TreeTableInfo = .{
|
|
443
|
+
.checksum = header.checksum,
|
|
444
|
+
.address = options.address,
|
|
445
|
+
.snapshot_min = options.snapshot_min,
|
|
446
|
+
.key_min = builder.key_min,
|
|
447
|
+
.key_max = builder.key_max,
|
|
448
|
+
.value_count = builder.value_count_total,
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
assert(info.snapshot_max == math.maxInt(u64));
|
|
452
|
+
|
|
453
|
+
// Reset the builder to its initial state.
|
|
454
|
+
builder.* = .{};
|
|
455
|
+
|
|
456
|
+
return info;
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
pub inline fn index_value_keys(
|
|
461
|
+
index_block: BlockPtr,
|
|
462
|
+
comptime key: enum { key_min, key_max },
|
|
463
|
+
) []Key {
|
|
464
|
+
const offset = comptime switch (key) {
|
|
465
|
+
.key_min => index.keys_min_offset,
|
|
466
|
+
.key_max => index.keys_max_offset,
|
|
467
|
+
};
|
|
468
|
+
return mem.bytesAsSlice(Key, index_block[offset..][0..index.keys_size]);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
pub inline fn index_value_keys_used(
|
|
472
|
+
index_block: BlockPtrConst,
|
|
473
|
+
comptime key: enum { key_min, key_max },
|
|
474
|
+
) []const Key {
|
|
475
|
+
const offset = comptime switch (key) {
|
|
476
|
+
.key_min => index.keys_min_offset,
|
|
477
|
+
.key_max => index.keys_max_offset,
|
|
478
|
+
};
|
|
479
|
+
const slice = mem.bytesAsSlice(Key, index_block[offset..][0..index.keys_size]);
|
|
480
|
+
return slice[0..index.value_blocks_used(index_block)];
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/// Returns the zero-based index of the value block that may contain the key
|
|
484
|
+
/// or null if the key is not contained in the index block's key range.
|
|
485
|
+
/// May be called on an index block only when the key is in range of the table.
|
|
486
|
+
inline fn index_value_block_for_key(index_block: BlockPtrConst, key: Key) ?u32 {
|
|
487
|
+
// Because we search key_max in the index block we can use the `upsert_index`
|
|
488
|
+
// binary search here and avoid the extra comparison.
|
|
489
|
+
// If the search finds an exact match, we want to return that value block.
|
|
490
|
+
// If the search does not find an exact match it returns the index of the next
|
|
491
|
+
// greatest key, which again is the index of the value block that may contain the key.
|
|
492
|
+
const value_block_index = binary_search.binary_search_keys_upsert_index(
|
|
493
|
+
Key,
|
|
494
|
+
Table.index_value_keys_used(index_block, .key_max),
|
|
495
|
+
key,
|
|
496
|
+
.{},
|
|
497
|
+
);
|
|
498
|
+
assert(value_block_index < index.value_blocks_used(index_block));
|
|
499
|
+
|
|
500
|
+
const key_min = Table.index_value_keys_used(index_block, .key_min)[value_block_index];
|
|
501
|
+
return if (key < key_min) null else value_block_index;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
pub const IndexBlocks = struct {
|
|
505
|
+
value_block_address: u64,
|
|
506
|
+
value_block_checksum: u128,
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
/// Returns all data stored in the index block relating to a given key
|
|
510
|
+
/// or null if the key is not contained in the index block's keys range.
|
|
511
|
+
/// May be called on an index block only when the key is in range of the table.
|
|
512
|
+
pub inline fn index_blocks_for_key(index_block: BlockPtrConst, key: Key) ?IndexBlocks {
|
|
513
|
+
return if (Table.index_value_block_for_key(index_block, key)) |i| .{
|
|
514
|
+
.value_block_address = index.value_addresses_used(index_block)[i],
|
|
515
|
+
.value_block_checksum = index.value_checksums_used(index_block)[i].value,
|
|
516
|
+
} else null;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
pub inline fn value_block_values(value_block: BlockPtr) []Value {
|
|
520
|
+
return mem.bytesAsSlice(Value, data.block_values_bytes(value_block));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
pub inline fn value_block_values_used(value_block: BlockPtrConst) []const Value {
|
|
524
|
+
return mem.bytesAsSlice(Value, data.block_values_used_bytes(value_block));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
pub inline fn block_address(block: BlockPtrConst) u64 {
|
|
528
|
+
const header = schema.header_from_block(block);
|
|
529
|
+
assert(header.address > 0);
|
|
530
|
+
return header.address;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
pub fn value_block_search(value_block: BlockPtrConst, key: Key) ?*const Value {
|
|
534
|
+
const values = value_block_values_used(value_block);
|
|
535
|
+
|
|
536
|
+
return binary_search.binary_search_values(
|
|
537
|
+
Key,
|
|
538
|
+
Value,
|
|
539
|
+
key_from_value,
|
|
540
|
+
values,
|
|
541
|
+
key,
|
|
542
|
+
.{},
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
pub fn verify(
|
|
547
|
+
comptime Storage: type,
|
|
548
|
+
storage: *const Storage,
|
|
549
|
+
index_address: u64,
|
|
550
|
+
key_min: ?Key,
|
|
551
|
+
key_max: ?Key,
|
|
552
|
+
) void {
|
|
553
|
+
if (Storage != @import("../testing/storage.zig").Storage)
|
|
554
|
+
// Too complicated to do async verification
|
|
555
|
+
return;
|
|
556
|
+
|
|
557
|
+
const index_block = storage.grid_block(index_address).?;
|
|
558
|
+
const value_block_addresses = index.value_addresses_used(index_block);
|
|
559
|
+
const value_block_checksums = index.value_checksums_used(index_block);
|
|
560
|
+
|
|
561
|
+
for (
|
|
562
|
+
value_block_addresses,
|
|
563
|
+
value_block_checksums,
|
|
564
|
+
0..,
|
|
565
|
+
) |value_block_address, value_block_checksum, value_block_index| {
|
|
566
|
+
const value_block = storage.grid_block(value_block_address).?;
|
|
567
|
+
const value_block_header = schema.header_from_block(value_block);
|
|
568
|
+
assert(value_block_header.address == value_block_address);
|
|
569
|
+
assert(value_block_header.checksum == value_block_checksum.value);
|
|
570
|
+
|
|
571
|
+
const values = value_block_values_used(value_block);
|
|
572
|
+
if (values.len > 0) {
|
|
573
|
+
if (value_block_index == 0) {
|
|
574
|
+
assert(key_min == null or
|
|
575
|
+
key_min.? == key_from_value(&values[0]));
|
|
576
|
+
}
|
|
577
|
+
if (value_block_index == value_block_addresses.len - 1) {
|
|
578
|
+
assert(key_max == null or
|
|
579
|
+
key_from_value(&values[values.len - 1]) == key_max.?);
|
|
580
|
+
}
|
|
581
|
+
var a = &values[0];
|
|
582
|
+
for (values[1..]) |*b| {
|
|
583
|
+
assert(key_from_value(a) < key_from_value(b));
|
|
584
|
+
a = b;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
test "Table" {
|
|
593
|
+
const CompositeKey = @import("composite_key.zig").CompositeKeyType(u128);
|
|
594
|
+
|
|
595
|
+
const Table = TableType(
|
|
596
|
+
CompositeKey.Key,
|
|
597
|
+
CompositeKey,
|
|
598
|
+
CompositeKey.key_from_value,
|
|
599
|
+
CompositeKey.sentinel_key,
|
|
600
|
+
CompositeKey.tombstone,
|
|
601
|
+
CompositeKey.tombstone_from_key,
|
|
602
|
+
1, // Doesn't matter for this test.
|
|
603
|
+
.general,
|
|
604
|
+
);
|
|
605
|
+
|
|
606
|
+
std.testing.refAllDecls(Table.Builder);
|
|
607
|
+
}
|