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,338 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const assert = std.debug.assert;
|
|
3
|
+
const mem = std.mem;
|
|
4
|
+
|
|
5
|
+
const constants = @import("../constants.zig");
|
|
6
|
+
const vsr = @import("../vsr.zig");
|
|
7
|
+
const stdx = @import("stdx");
|
|
8
|
+
|
|
9
|
+
/// There is a slot corresponding to every active client (i.e. a total of clients_max slots).
|
|
10
|
+
pub const ReplySlot = struct { index: usize };
|
|
11
|
+
|
|
12
|
+
/// Track the headers of the latest reply for each active client.
|
|
13
|
+
/// Serialized/deserialized to/from the trailer on-disk.
|
|
14
|
+
/// For the reply bodies, see ClientReplies.
|
|
15
|
+
pub const ClientSessions = struct {
|
|
16
|
+
/// We found two bugs in the VRR paper relating to the client table:
|
|
17
|
+
///
|
|
18
|
+
/// 1. a correctness bug, where successive client crashes may cause request numbers to collide
|
|
19
|
+
/// for different request payloads, resulting in requests receiving the wrong reply, and
|
|
20
|
+
///
|
|
21
|
+
/// 2. a liveness bug, where if the client table is updated for request and prepare messages
|
|
22
|
+
/// with the client's latest request number, then the client may be locked out from the cluster
|
|
23
|
+
/// if the request is ever reordered through a view change.
|
|
24
|
+
///
|
|
25
|
+
/// We therefore take a different approach with the implementation of our client table, to:
|
|
26
|
+
///
|
|
27
|
+
/// 1. register client sessions explicitly through the state machine to ensure that
|
|
28
|
+
/// session numbers always increase, and
|
|
29
|
+
///
|
|
30
|
+
/// 2. make a more careful distinction between uncommitted and committed request numbers,
|
|
31
|
+
/// considering that uncommitted requests may not survive a view change.
|
|
32
|
+
pub const Entry = struct {
|
|
33
|
+
/// The client's session number as committed to the cluster by a register request.
|
|
34
|
+
session: u64,
|
|
35
|
+
|
|
36
|
+
/// The header of the reply corresponding to the client's latest committed request.
|
|
37
|
+
header: vsr.Header.Reply,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/// Values are indexes into `entries`.
|
|
41
|
+
const EntriesByClient = std.AutoHashMapUnmanaged(u128, usize);
|
|
42
|
+
|
|
43
|
+
const EntriesPresent = stdx.BitSetType(constants.clients_max);
|
|
44
|
+
|
|
45
|
+
/// Free entries are zeroed, both in `entries` and on-disk.
|
|
46
|
+
entries: []Entry,
|
|
47
|
+
entries_by_client: EntriesByClient,
|
|
48
|
+
entries_present: EntriesPresent = .{},
|
|
49
|
+
|
|
50
|
+
pub fn init(allocator: mem.Allocator) !ClientSessions {
|
|
51
|
+
var entries_by_client: EntriesByClient = .{};
|
|
52
|
+
errdefer entries_by_client.deinit(allocator);
|
|
53
|
+
|
|
54
|
+
try entries_by_client.ensureTotalCapacity(allocator, @intCast(constants.clients_max));
|
|
55
|
+
assert(entries_by_client.capacity() >= constants.clients_max);
|
|
56
|
+
|
|
57
|
+
const entries = try allocator.alloc(Entry, constants.clients_max);
|
|
58
|
+
errdefer allocator.free(entries);
|
|
59
|
+
@memset(entries, std.mem.zeroes(Entry));
|
|
60
|
+
|
|
61
|
+
return ClientSessions{
|
|
62
|
+
.entries_by_client = entries_by_client,
|
|
63
|
+
.entries = entries,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn deinit(client_sessions: *ClientSessions, allocator: mem.Allocator) void {
|
|
68
|
+
client_sessions.entries_by_client.deinit(allocator);
|
|
69
|
+
allocator.free(client_sessions.entries);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn reset(client_sessions: *ClientSessions) void {
|
|
73
|
+
@memset(client_sessions.entries, std.mem.zeroes(Entry));
|
|
74
|
+
client_sessions.entries_by_client.clearRetainingCapacity();
|
|
75
|
+
client_sessions.entries_present = .{};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Size of the buffer needed to encode the client sessions on disk.
|
|
79
|
+
/// (Not rounded up to a sector boundary).
|
|
80
|
+
pub const encode_size = blk: {
|
|
81
|
+
var size_max: usize = 0;
|
|
82
|
+
|
|
83
|
+
// First goes the vsr headers for the entries.
|
|
84
|
+
// This takes advantage of the buffer alignment to avoid adding padding for the headers.
|
|
85
|
+
assert(@alignOf(vsr.Header) == 16);
|
|
86
|
+
size_max = std.mem.alignForward(usize, size_max, 16);
|
|
87
|
+
size_max += @sizeOf(vsr.Header) * constants.clients_max;
|
|
88
|
+
|
|
89
|
+
// Then follows the session values for the entries.
|
|
90
|
+
assert(@alignOf(u64) == 8);
|
|
91
|
+
size_max = std.mem.alignForward(usize, size_max, 8);
|
|
92
|
+
size_max += @sizeOf(u64) * constants.clients_max;
|
|
93
|
+
|
|
94
|
+
// For encoding/decoding simplicity, the ClientSessions always fits in a single block.
|
|
95
|
+
assert(size_max <= constants.block_size - @sizeOf(vsr.Header));
|
|
96
|
+
|
|
97
|
+
break :blk size_max;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
pub fn encode(
|
|
101
|
+
client_sessions: *const ClientSessions,
|
|
102
|
+
target: []align(@alignOf(vsr.Header)) u8,
|
|
103
|
+
) u64 {
|
|
104
|
+
assert(target.len >= encode_size);
|
|
105
|
+
|
|
106
|
+
var size: u64 = 0;
|
|
107
|
+
|
|
108
|
+
// Write all headers:
|
|
109
|
+
assert(@alignOf(vsr.Header) == 16);
|
|
110
|
+
var new_size = std.mem.alignForward(usize, size, 16);
|
|
111
|
+
@memset(target[size..new_size], 0);
|
|
112
|
+
size = new_size;
|
|
113
|
+
|
|
114
|
+
for (client_sessions.entries) |*entry| {
|
|
115
|
+
stdx.copy_disjoint(.inexact, u8, target[size..], mem.asBytes(&entry.header));
|
|
116
|
+
size += @sizeOf(vsr.Header);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Write all sessions:
|
|
120
|
+
assert(@alignOf(u64) == 8);
|
|
121
|
+
new_size = std.mem.alignForward(usize, size, 8);
|
|
122
|
+
@memset(target[size..new_size], 0);
|
|
123
|
+
size = new_size;
|
|
124
|
+
|
|
125
|
+
for (client_sessions.entries) |*entry| {
|
|
126
|
+
stdx.copy_disjoint(.inexact, u8, target[size..], mem.asBytes(&entry.session));
|
|
127
|
+
size += @sizeOf(u64);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
assert(size == encode_size);
|
|
131
|
+
return size;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
pub fn decode(
|
|
135
|
+
client_sessions: *ClientSessions,
|
|
136
|
+
source: []align(@alignOf(vsr.Header)) const u8,
|
|
137
|
+
) void {
|
|
138
|
+
assert(client_sessions.count() == 0);
|
|
139
|
+
assert(client_sessions.entries_present.empty());
|
|
140
|
+
for (client_sessions.entries) |*entry| {
|
|
141
|
+
assert(entry.session == 0);
|
|
142
|
+
assert(stdx.zeroed(std.mem.asBytes(&entry.header)));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
var size: u64 = 0;
|
|
146
|
+
assert(source.len > 0);
|
|
147
|
+
assert(source.len <= encode_size);
|
|
148
|
+
|
|
149
|
+
assert(@alignOf(vsr.Header) == 16);
|
|
150
|
+
size = std.mem.alignForward(usize, size, 16);
|
|
151
|
+
const headers: []const vsr.Header.Reply = @alignCast(mem.bytesAsSlice(
|
|
152
|
+
vsr.Header.Reply,
|
|
153
|
+
source[size..][0 .. constants.clients_max * @sizeOf(vsr.Header)],
|
|
154
|
+
));
|
|
155
|
+
size += mem.sliceAsBytes(headers).len;
|
|
156
|
+
|
|
157
|
+
assert(@alignOf(u64) == 8);
|
|
158
|
+
size = std.mem.alignForward(usize, size, 8);
|
|
159
|
+
const sessions = mem.bytesAsSlice(
|
|
160
|
+
u64,
|
|
161
|
+
source[size..][0 .. constants.clients_max * @sizeOf(u64)],
|
|
162
|
+
);
|
|
163
|
+
size += mem.sliceAsBytes(sessions).len;
|
|
164
|
+
|
|
165
|
+
assert(size == encode_size);
|
|
166
|
+
|
|
167
|
+
for (headers, 0..) |*header, i| {
|
|
168
|
+
const session = sessions[i];
|
|
169
|
+
if (session == 0) {
|
|
170
|
+
assert(stdx.zeroed(std.mem.asBytes(header)));
|
|
171
|
+
} else {
|
|
172
|
+
assert(header.valid_checksum());
|
|
173
|
+
assert(header.command == .reply);
|
|
174
|
+
assert(header.commit >= session);
|
|
175
|
+
|
|
176
|
+
client_sessions.entries_by_client.putAssumeCapacityNoClobber(header.client, i);
|
|
177
|
+
client_sessions.entries_present.set(i);
|
|
178
|
+
client_sessions.entries[i] = .{
|
|
179
|
+
.session = session,
|
|
180
|
+
.header = header.*,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
assert(
|
|
186
|
+
client_sessions.entries_present.count() == client_sessions.entries_by_client.count(),
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
pub fn count(client_sessions: *const ClientSessions) usize {
|
|
191
|
+
return client_sessions.entries_by_client.count();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
pub fn capacity(client_sessions: *const ClientSessions) usize {
|
|
195
|
+
_ = client_sessions;
|
|
196
|
+
return constants.clients_max;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
pub fn get(client_sessions: *ClientSessions, client: u128) ?*Entry {
|
|
200
|
+
const entry_index = client_sessions.entries_by_client.get(client) orelse return null;
|
|
201
|
+
const entry = &client_sessions.entries[entry_index];
|
|
202
|
+
assert(entry.session != 0);
|
|
203
|
+
assert(entry.header.command == .reply);
|
|
204
|
+
assert(entry.header.client == client);
|
|
205
|
+
return entry;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pub fn get_slot_for_client(client_sessions: *const ClientSessions, client: u128) ?ReplySlot {
|
|
209
|
+
const index = client_sessions.entries_by_client.get(client) orelse return null;
|
|
210
|
+
return ReplySlot{ .index = index };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
pub fn get_slot_for_header(
|
|
214
|
+
client_sessions: *const ClientSessions,
|
|
215
|
+
header: *const vsr.Header.Reply,
|
|
216
|
+
) ?ReplySlot {
|
|
217
|
+
if (client_sessions.entries_by_client.get(header.client)) |entry_index| {
|
|
218
|
+
const entry = &client_sessions.entries[entry_index];
|
|
219
|
+
if (entry.header.checksum == header.checksum) {
|
|
220
|
+
return ReplySlot{ .index = entry_index };
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/// If the entry is from a newly-registered client, the caller is responsible for ensuring
|
|
227
|
+
/// the ClientSessions has available capacity.
|
|
228
|
+
pub fn put(
|
|
229
|
+
client_sessions: *ClientSessions,
|
|
230
|
+
session: u64,
|
|
231
|
+
header: *const vsr.Header.Reply,
|
|
232
|
+
) ReplySlot {
|
|
233
|
+
assert(session != 0);
|
|
234
|
+
assert(header.command == .reply);
|
|
235
|
+
const client = header.client;
|
|
236
|
+
|
|
237
|
+
defer assert(client_sessions.entries_by_client.contains(client));
|
|
238
|
+
|
|
239
|
+
const entry_gop = client_sessions.entries_by_client.getOrPutAssumeCapacity(client);
|
|
240
|
+
if (entry_gop.found_existing) {
|
|
241
|
+
const entry_index = entry_gop.value_ptr.*;
|
|
242
|
+
assert(client_sessions.entries_present.is_set(entry_index));
|
|
243
|
+
|
|
244
|
+
const existing = &client_sessions.entries[entry_index];
|
|
245
|
+
assert(existing.session == session);
|
|
246
|
+
assert(existing.header.cluster == header.cluster);
|
|
247
|
+
assert(existing.header.client == header.client);
|
|
248
|
+
assert(existing.header.commit < header.commit);
|
|
249
|
+
|
|
250
|
+
existing.header = header.*;
|
|
251
|
+
return ReplySlot{ .index = entry_index };
|
|
252
|
+
} else {
|
|
253
|
+
const entry_index = client_sessions.entries_present.first_unset().?;
|
|
254
|
+
client_sessions.entries_present.set(entry_index);
|
|
255
|
+
|
|
256
|
+
const e = &client_sessions.entries[entry_index];
|
|
257
|
+
assert(e.session == 0);
|
|
258
|
+
|
|
259
|
+
entry_gop.value_ptr.* = entry_index;
|
|
260
|
+
e.session = session;
|
|
261
|
+
e.header = header.*;
|
|
262
|
+
return ReplySlot{ .index = entry_index };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/// For correctness, it's critical that all replicas evict deterministically:
|
|
267
|
+
/// We cannot depend on `HashMap.capacity()` since `HashMap.ensureTotalCapacity()` may
|
|
268
|
+
/// change across versions of the Zig std lib. We therefore rely on
|
|
269
|
+
/// `constants.clients_max`, which must be the same across all replicas, and must not
|
|
270
|
+
/// change after initializing a cluster.
|
|
271
|
+
/// We also do not depend on `HashMap.valueIterator()` being deterministic here. However,
|
|
272
|
+
/// we do require that all entries have different commit numbers and are iterated.
|
|
273
|
+
/// This ensures that we will always pick the entry with the oldest commit number.
|
|
274
|
+
/// We also check that a client has only one entry in the hash map (or it's buggy).
|
|
275
|
+
pub fn evictee(client_sessions: *const ClientSessions) u128 {
|
|
276
|
+
assert(client_sessions.entries_present.full());
|
|
277
|
+
assert(client_sessions.count() == constants.clients_max);
|
|
278
|
+
|
|
279
|
+
var evictee_: ?*const vsr.Header.Reply = null;
|
|
280
|
+
var iterated: usize = 0;
|
|
281
|
+
var entries = client_sessions.iterator();
|
|
282
|
+
while (entries.next()) |entry| : (iterated += 1) {
|
|
283
|
+
assert(entry.header.command == .reply);
|
|
284
|
+
assert(entry.header.op == entry.header.commit);
|
|
285
|
+
assert(entry.header.commit >= entry.session);
|
|
286
|
+
|
|
287
|
+
if (evictee_) |evictee_reply| {
|
|
288
|
+
assert(entry.header.client != evictee_reply.client);
|
|
289
|
+
assert(entry.header.commit != evictee_reply.commit);
|
|
290
|
+
|
|
291
|
+
if (entry.header.commit < evictee_reply.commit) {
|
|
292
|
+
evictee_ = &entry.header;
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
evictee_ = &entry.header;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
assert(iterated == constants.clients_max);
|
|
299
|
+
|
|
300
|
+
return evictee_.?.client;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
pub fn remove(client_sessions: *ClientSessions, client: u128) void {
|
|
304
|
+
const entry_index = client_sessions.entries_by_client.fetchRemove(client).?.value;
|
|
305
|
+
|
|
306
|
+
assert(client_sessions.entries_present.is_set(entry_index));
|
|
307
|
+
client_sessions.entries_present.unset(entry_index);
|
|
308
|
+
|
|
309
|
+
assert(client_sessions.entries[entry_index].header.client == client);
|
|
310
|
+
client_sessions.entries[entry_index] = std.mem.zeroes(Entry);
|
|
311
|
+
|
|
312
|
+
assert(!client_sessions.entries_by_client.contains(client));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
pub const Iterator = struct {
|
|
316
|
+
client_sessions: *const ClientSessions,
|
|
317
|
+
index: usize = 0,
|
|
318
|
+
|
|
319
|
+
pub fn next(it: *Iterator) ?*const Entry {
|
|
320
|
+
while (it.index < it.client_sessions.entries.len) {
|
|
321
|
+
defer it.index += 1;
|
|
322
|
+
|
|
323
|
+
const entry = &it.client_sessions.entries[it.index];
|
|
324
|
+
if (entry.session == 0) {
|
|
325
|
+
assert(!it.client_sessions.entries_present.is_set(it.index));
|
|
326
|
+
} else {
|
|
327
|
+
assert(it.client_sessions.entries_present.is_set(it.index));
|
|
328
|
+
return entry;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
pub fn iterator(client_sessions: *const ClientSessions) Iterator {
|
|
336
|
+
return .{ .client_sessions = client_sessions };
|
|
337
|
+
}
|
|
338
|
+
};
|