tigerbeetle 0.0.36 → 0.0.38
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 +5 -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 +1092 -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 +120 -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 +359 -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 +962 -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 +90 -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 +534 -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 +2928 -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/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,331 @@
|
|
|
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
|
+
const maybe = stdx.maybe;
|
|
9
|
+
|
|
10
|
+
const message_pool = @import("../../message_pool.zig");
|
|
11
|
+
const MessagePool = message_pool.MessagePool;
|
|
12
|
+
const Message = MessagePool.Message;
|
|
13
|
+
|
|
14
|
+
const ReplicaSet = stdx.BitSetType(constants.members_max);
|
|
15
|
+
const Commits = std.ArrayList(struct {
|
|
16
|
+
header: vsr.Header.Prepare,
|
|
17
|
+
// null for operation=root and operation=upgrade
|
|
18
|
+
release: ?vsr.Release,
|
|
19
|
+
replicas: ReplicaSet = .{},
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const ReplicaHead = struct {
|
|
23
|
+
view: u32,
|
|
24
|
+
op: u64,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
pub fn StateCheckerType(comptime Client: type, comptime Replica: type) type {
|
|
28
|
+
return struct {
|
|
29
|
+
const StateChecker = @This();
|
|
30
|
+
|
|
31
|
+
node_count: u8,
|
|
32
|
+
replica_count: u8,
|
|
33
|
+
|
|
34
|
+
commits: Commits,
|
|
35
|
+
commit_mins: [constants.members_max]u64 = @splat(0),
|
|
36
|
+
|
|
37
|
+
replicas: []const Replica,
|
|
38
|
+
clients: []const ?Client,
|
|
39
|
+
/// Tracks the latest reply for every non-evicted client.
|
|
40
|
+
client_replies: std.AutoArrayHashMapUnmanaged(u128, vsr.Header.Reply),
|
|
41
|
+
clients_exhaustive: bool = true,
|
|
42
|
+
clients_register_op_latest: u64 = 0,
|
|
43
|
+
|
|
44
|
+
/// The number of times the canonical state has been advanced.
|
|
45
|
+
requests_committed: u64 = 0,
|
|
46
|
+
|
|
47
|
+
/// Tracks the latest op acked by a replica across restarts.
|
|
48
|
+
replica_head_max: []ReplicaHead,
|
|
49
|
+
|
|
50
|
+
pub fn init(allocator: mem.Allocator, options: struct {
|
|
51
|
+
cluster_id: u128,
|
|
52
|
+
replica_count: u8,
|
|
53
|
+
replicas: []const Replica,
|
|
54
|
+
clients: []const ?Client,
|
|
55
|
+
}) !StateChecker {
|
|
56
|
+
const root_prepare = vsr.Header.Prepare.root(options.cluster_id);
|
|
57
|
+
|
|
58
|
+
var commits = Commits.init(allocator);
|
|
59
|
+
errdefer commits.deinit();
|
|
60
|
+
|
|
61
|
+
var commit_replicas: ReplicaSet = .{};
|
|
62
|
+
for (options.replicas, 0..) |_, i| commit_replicas.set(i);
|
|
63
|
+
try commits.append(.{
|
|
64
|
+
.header = root_prepare,
|
|
65
|
+
.release = null,
|
|
66
|
+
.replicas = commit_replicas,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
var client_replies: std.AutoArrayHashMapUnmanaged(u128, vsr.Header.Reply) = .{};
|
|
70
|
+
try client_replies.ensureTotalCapacity(allocator, constants.clients_max);
|
|
71
|
+
errdefer client_replies.deinit(allocator);
|
|
72
|
+
|
|
73
|
+
const replica_head_max = try allocator.alloc(ReplicaHead, options.replicas.len);
|
|
74
|
+
errdefer allocator.free(replica_head_max);
|
|
75
|
+
for (replica_head_max) |*head| head.* = .{ .view = 0, .op = 0 };
|
|
76
|
+
|
|
77
|
+
return StateChecker{
|
|
78
|
+
.node_count = @intCast(options.replicas.len),
|
|
79
|
+
.replica_count = options.replica_count,
|
|
80
|
+
.commits = commits,
|
|
81
|
+
.replicas = options.replicas,
|
|
82
|
+
.clients = options.clients,
|
|
83
|
+
.client_replies = client_replies,
|
|
84
|
+
.replica_head_max = replica_head_max,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
pub fn deinit(state_checker: *StateChecker) void {
|
|
89
|
+
const allocator = state_checker.commits.allocator;
|
|
90
|
+
|
|
91
|
+
allocator.free(state_checker.replica_head_max);
|
|
92
|
+
state_checker.client_replies.deinit(allocator);
|
|
93
|
+
state_checker.commits.deinit();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
pub fn on_client_eviction(state_checker: *StateChecker, client_id: u128) void {
|
|
97
|
+
const removed = state_checker.client_replies.swapRemove(client_id);
|
|
98
|
+
maybe(removed);
|
|
99
|
+
// Disable checking of `Client.request_inflight`, to guard against the following panic:
|
|
100
|
+
// 1. Client `A` sends an `operation=register` to a fresh cluster. (`A₁`)
|
|
101
|
+
// 2. Cluster prepares + commits `A₁`, and sends the reply to `A`.
|
|
102
|
+
// 4. `A` receives the reply to `A₁`, and issues a second request (`A₂`).
|
|
103
|
+
// 5. `clients_max` other clients register, evicting `A`'s session.
|
|
104
|
+
// 6. An old retry (or replay) of `A₁` arrives at the cluster.
|
|
105
|
+
// 7. `A₁` is committed (for a second time, as a different op).
|
|
106
|
+
// If `StateChecker` were to check `Client.request_inflight`, it would see that `A₁`
|
|
107
|
+
// is not actually in-flight, despite being committed for the "first time" by a
|
|
108
|
+
// replica.
|
|
109
|
+
state_checker.clients_exhaustive = false;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
pub fn on_message(state_checker: *StateChecker, message: *const Message) void {
|
|
113
|
+
switch (message.header.into_any()) {
|
|
114
|
+
.prepare_ok => |header| {
|
|
115
|
+
const head = &state_checker.replica_head_max[header.replica];
|
|
116
|
+
if (header.view > head.view or
|
|
117
|
+
(header.view == head.view and header.op > head.op))
|
|
118
|
+
{
|
|
119
|
+
head.view = header.view;
|
|
120
|
+
head.op = header.op;
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
.reply => |header| {
|
|
124
|
+
if (header.operation == .register and
|
|
125
|
+
header.op > state_checker.clients_register_op_latest)
|
|
126
|
+
{
|
|
127
|
+
state_checker.client_replies
|
|
128
|
+
.putAssumeCapacityNoClobber(header.client, header.*);
|
|
129
|
+
state_checker.clients_register_op_latest = header.op;
|
|
130
|
+
} else {
|
|
131
|
+
if (state_checker.client_replies.getEntry(header.client)) |entry| {
|
|
132
|
+
if (entry.value_ptr.op < header.op) {
|
|
133
|
+
entry.value_ptr.* = header.*;
|
|
134
|
+
} else {
|
|
135
|
+
// An old message is replayed.
|
|
136
|
+
}
|
|
137
|
+
} else {
|
|
138
|
+
// Client was evicted, an old message is replayed.
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
else => {},
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Verify that the cluster has advanced since the replica was lost.
|
|
147
|
+
/// Then forget about the given replica's progress, since its data file has been "lost".
|
|
148
|
+
pub fn reformat(state_checker: *StateChecker, replica_index: u8) void {
|
|
149
|
+
const reformat_state = state_checker.replica_head_max[replica_index];
|
|
150
|
+
var commit_advanced: bool = false;
|
|
151
|
+
for (
|
|
152
|
+
state_checker.commit_mins[0..state_checker.replica_head_max.len],
|
|
153
|
+
0..,
|
|
154
|
+
) |commit_min, i| {
|
|
155
|
+
if (i != replica_index) {
|
|
156
|
+
commit_advanced = commit_advanced or reformat_state.op < commit_min;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
assert(commit_advanced);
|
|
160
|
+
|
|
161
|
+
state_checker.replica_head_max[replica_index] = .{ .view = 0, .op = 0 };
|
|
162
|
+
state_checker.commit_mins[replica_index] = 0;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// Returns whether the replica's state changed since the last check_state().
|
|
166
|
+
pub fn check_state(state_checker: *StateChecker, replica_index: u8) !void {
|
|
167
|
+
const replica = &state_checker.replicas[replica_index];
|
|
168
|
+
if (replica.syncing == .updating_checkpoint) {
|
|
169
|
+
// Allow a syncing replica to fast-forward its commit.
|
|
170
|
+
//
|
|
171
|
+
// But "fast-forwarding" may actually move commit_min slightly backwards:
|
|
172
|
+
// 1. Suppose op X is a checkpoint trigger.
|
|
173
|
+
// 2. We are committing op X-1 but are stuck due to a block that does not exist in
|
|
174
|
+
// the cluster anymore.
|
|
175
|
+
// 3. When we sync, `commit_min` "backtracks", to `X - lsm_compaction_ops`.
|
|
176
|
+
const commit_min_source = state_checker.commit_mins[replica_index];
|
|
177
|
+
const commit_min_target =
|
|
178
|
+
replica.syncing.updating_checkpoint.header.op;
|
|
179
|
+
assert(commit_min_source <= commit_min_target + constants.lsm_compaction_ops);
|
|
180
|
+
state_checker.commit_mins[replica_index] = commit_min_target;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
assert(replica.view >= state_checker.replica_head_max[replica_index].view);
|
|
185
|
+
|
|
186
|
+
const commit_root_op = replica.superblock.working.vsr_state.checkpoint.header.op;
|
|
187
|
+
const commit_root = replica.superblock.working.vsr_state.checkpoint.header.checksum;
|
|
188
|
+
|
|
189
|
+
const commit_a = state_checker.commit_mins[replica_index];
|
|
190
|
+
const commit_b = replica.commit_min;
|
|
191
|
+
|
|
192
|
+
const header_b = replica.journal.header_with_op(replica.commit_min);
|
|
193
|
+
|
|
194
|
+
if (header_b == null and replica.commit_min != replica.op_checkpoint()) {
|
|
195
|
+
// The slot with commit_min may have been overwritten by an op from the next wrap.
|
|
196
|
+
// Further, the op may then also be truncated as part of a view change.
|
|
197
|
+
if (replica.journal.header_for_op(replica.commit_min)) |header| {
|
|
198
|
+
assert(header.op == replica.commit_min + constants.journal_slot_count);
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (header_b != null) assert(header_b.?.op == commit_b);
|
|
204
|
+
|
|
205
|
+
const checksum_a = state_checker.commits.items[commit_a].header.checksum;
|
|
206
|
+
// Even if we have header_b, if its op is commit_root_op, we can't trust it.
|
|
207
|
+
// If we just finished state sync, the header in our log might not have been
|
|
208
|
+
// committed (it might be left over from before sync).
|
|
209
|
+
const checksum_b = if (commit_b == commit_root_op) commit_root else header_b.?.checksum;
|
|
210
|
+
|
|
211
|
+
assert(checksum_b != commit_root or
|
|
212
|
+
replica.commit_min == replica.superblock.working.vsr_state.checkpoint.header.op);
|
|
213
|
+
assert((commit_a == commit_b) == (checksum_a == checksum_b));
|
|
214
|
+
|
|
215
|
+
if (checksum_a == checksum_b) return;
|
|
216
|
+
|
|
217
|
+
assert(commit_b < commit_a or commit_a + 1 == commit_b);
|
|
218
|
+
state_checker.commit_mins[replica_index] = commit_b;
|
|
219
|
+
|
|
220
|
+
// If some other replica has already reached this state, then it will be in the commit
|
|
221
|
+
// history:
|
|
222
|
+
if (replica.commit_min < state_checker.commits.items.len) {
|
|
223
|
+
const commit = &state_checker.commits.items[commit_b];
|
|
224
|
+
if (replica.op_checkpoint() < replica.commit_min) {
|
|
225
|
+
if (commit.release) |release| assert(release.value == replica.release.value);
|
|
226
|
+
} else {
|
|
227
|
+
// When op_checkpoint==commit_min, we recovered from checkpoint, so it is ok if
|
|
228
|
+
// the release doesn't match. (commit_min is not actually being executed.)
|
|
229
|
+
assert(replica.op_checkpoint() == replica.commit_min);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
assert(checksum_b == commit.header.checksum);
|
|
233
|
+
commit.replicas.set(replica_index);
|
|
234
|
+
|
|
235
|
+
assert(replica.commit_min < state_checker.commits.items.len);
|
|
236
|
+
// A replica may transition more than once to the same state, for example, when
|
|
237
|
+
// restarting after a crash and replaying the log. The more important invariant is
|
|
238
|
+
// that the cluster as a whole may not transition to the same state more than once,
|
|
239
|
+
// and once transitioned may not regress.
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (header_b == null) return;
|
|
244
|
+
assert(header_b.?.checksum == checksum_b);
|
|
245
|
+
assert(header_b.?.parent == checksum_a);
|
|
246
|
+
assert(header_b.?.op > 0);
|
|
247
|
+
assert(header_b.?.command == .prepare);
|
|
248
|
+
assert(header_b.?.operation != .reserved);
|
|
249
|
+
|
|
250
|
+
if (header_b.?.client == 0) {
|
|
251
|
+
assert(header_b.?.operation == .upgrade or
|
|
252
|
+
header_b.?.operation == .pulse);
|
|
253
|
+
} else {
|
|
254
|
+
if (state_checker.clients_exhaustive) {
|
|
255
|
+
// The replica has transitioned to state `b` that is not yet in the commit
|
|
256
|
+
// history. Check if this is a valid new state based on the originating client's
|
|
257
|
+
// inflight request.
|
|
258
|
+
const client: *const Client = for (state_checker.clients) |*client| {
|
|
259
|
+
if (client.*.?.id == header_b.?.client) break &client.*.?;
|
|
260
|
+
} else unreachable;
|
|
261
|
+
|
|
262
|
+
if (client.request_inflight == null) {
|
|
263
|
+
return error.ReplicaTransitionedToInvalidState;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const request = client.request_inflight.?.message;
|
|
267
|
+
assert(request.header.client == header_b.?.client);
|
|
268
|
+
assert(request.header.checksum == header_b.?.request_checksum);
|
|
269
|
+
assert(request.header.request == header_b.?.request);
|
|
270
|
+
assert(request.header.command == .request);
|
|
271
|
+
assert(request.header.operation == header_b.?.operation);
|
|
272
|
+
assert(request.header.size == header_b.?.size);
|
|
273
|
+
// `checksum_body` will not match; the leader's StateMachine updated the
|
|
274
|
+
// timestamps in the prepare body's accounts/transfers.
|
|
275
|
+
} else {
|
|
276
|
+
// Either:
|
|
277
|
+
// - The cluster is running with one or more raw MessageBus "clients", so there
|
|
278
|
+
// may be requests not found in `Cluster.clients`.
|
|
279
|
+
// - The test includes one or more client evictions.
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
state_checker.requests_committed += 1;
|
|
284
|
+
assert(state_checker.requests_committed == header_b.?.op);
|
|
285
|
+
|
|
286
|
+
const release = release: {
|
|
287
|
+
if (header_b.?.operation == .root or
|
|
288
|
+
header_b.?.operation == .upgrade)
|
|
289
|
+
{
|
|
290
|
+
break :release null;
|
|
291
|
+
} else {
|
|
292
|
+
break :release replica.release;
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
assert(state_checker.commits.items.len == header_b.?.op);
|
|
297
|
+
state_checker.commits.append(.{
|
|
298
|
+
.header = header_b.?.*,
|
|
299
|
+
.release = release,
|
|
300
|
+
}) catch unreachable;
|
|
301
|
+
state_checker.commits.items[header_b.?.op].replicas.set(replica_index);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
pub fn replica_convergence(state_checker: *StateChecker, replica_index: u8) bool {
|
|
305
|
+
const a = state_checker.commits.items.len - 1;
|
|
306
|
+
const b = state_checker.commit_mins[replica_index];
|
|
307
|
+
return a == b;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
pub fn assert_cluster_convergence(state_checker: *StateChecker) void {
|
|
311
|
+
for (state_checker.commits.items, 0..) |commit, i| {
|
|
312
|
+
assert(commit.replicas.count() > 0);
|
|
313
|
+
assert(commit.header.command == .prepare);
|
|
314
|
+
assert(commit.header.op == i);
|
|
315
|
+
if (i > 0) {
|
|
316
|
+
const previous = state_checker.commits.items[i - 1].header;
|
|
317
|
+
assert(commit.header.parent == previous.checksum);
|
|
318
|
+
assert(commit.header.view >= previous.view);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
pub fn header_with_op(state_checker: *StateChecker, op: u64) vsr.Header.Prepare {
|
|
324
|
+
assert(op < state_checker.commits.items.len);
|
|
325
|
+
const commit = &state_checker.commits.items[op];
|
|
326
|
+
assert(commit.header.op == op);
|
|
327
|
+
assert(commit.replicas.count() > 0);
|
|
328
|
+
return commit.header;
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
}
|