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,416 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const assert = std.debug.assert;
|
|
3
|
+
|
|
4
|
+
const constants = @import("../constants.zig");
|
|
5
|
+
const stdx = @import("stdx");
|
|
6
|
+
const vsr = @import("../vsr.zig");
|
|
7
|
+
const Header = vsr.Header;
|
|
8
|
+
const data_file_size_min = @import("./superblock.zig").data_file_size_min;
|
|
9
|
+
|
|
10
|
+
/// Initialize the TigerBeetle replica's data file.
|
|
11
|
+
pub fn format(
|
|
12
|
+
comptime Storage: type,
|
|
13
|
+
gpa: std.mem.Allocator,
|
|
14
|
+
storage: *Storage,
|
|
15
|
+
options: vsr.SuperBlockType(Storage).FormatOptions,
|
|
16
|
+
) !void {
|
|
17
|
+
const ReplicaFormat = ReplicaFormatType(Storage);
|
|
18
|
+
const SuperBlock = vsr.SuperBlockType(Storage);
|
|
19
|
+
|
|
20
|
+
var superblock = try SuperBlock.init(gpa, storage, .{
|
|
21
|
+
.storage_size_limit = data_file_size_min,
|
|
22
|
+
});
|
|
23
|
+
defer superblock.deinit(gpa);
|
|
24
|
+
|
|
25
|
+
var replica_format = try ReplicaFormat.init(gpa);
|
|
26
|
+
defer replica_format.deinit(gpa);
|
|
27
|
+
|
|
28
|
+
try replica_format.queue_format_wal(options.cluster, storage);
|
|
29
|
+
replica_format.format_and_tick(storage, &superblock, options);
|
|
30
|
+
replica_format.verify_writes();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// When formatting, we write:
|
|
34
|
+
/// * constants.journal_slot_count many prepares,
|
|
35
|
+
/// * 1 write that contains all of the headers.
|
|
36
|
+
pub const writes_max = constants.journal_slot_count + 1;
|
|
37
|
+
|
|
38
|
+
fn ReplicaFormatType(comptime Storage: type) type {
|
|
39
|
+
const SuperBlock = vsr.SuperBlockType(Storage);
|
|
40
|
+
return struct {
|
|
41
|
+
const ReplicaFormat = @This();
|
|
42
|
+
|
|
43
|
+
const Write = struct {
|
|
44
|
+
write: Storage.Write = undefined,
|
|
45
|
+
replica_format: *ReplicaFormat,
|
|
46
|
+
|
|
47
|
+
issued_buffer: []const u8,
|
|
48
|
+
issued_offset: u64,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
formatting: bool = false,
|
|
52
|
+
formatting_superblock: bool = false,
|
|
53
|
+
superblock_context: SuperBlock.Context = undefined,
|
|
54
|
+
|
|
55
|
+
writes: [writes_max]Write = undefined,
|
|
56
|
+
writes_pending: u64 = 0,
|
|
57
|
+
|
|
58
|
+
sectors_written: std.DynamicBitSetUnmanaged,
|
|
59
|
+
arena: std.heap.ArenaAllocator,
|
|
60
|
+
|
|
61
|
+
fn init(gpa: std.mem.Allocator) !ReplicaFormat {
|
|
62
|
+
var sectors_written = try std.DynamicBitSetUnmanaged.initEmpty(
|
|
63
|
+
gpa,
|
|
64
|
+
@divExact(data_file_size_min, constants.sector_size),
|
|
65
|
+
);
|
|
66
|
+
errdefer sectors_written.deinit(gpa);
|
|
67
|
+
|
|
68
|
+
var arena = std.heap.ArenaAllocator.init(gpa);
|
|
69
|
+
errdefer arena.deinit();
|
|
70
|
+
|
|
71
|
+
return .{
|
|
72
|
+
.sectors_written = sectors_written,
|
|
73
|
+
.arena = arena,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fn deinit(self: *ReplicaFormat, gpa: std.mem.Allocator) void {
|
|
78
|
+
self.arena.deinit();
|
|
79
|
+
self.sectors_written.deinit(gpa);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fn queue_format_wal(
|
|
83
|
+
self: *ReplicaFormat,
|
|
84
|
+
cluster: u128,
|
|
85
|
+
storage: *Storage,
|
|
86
|
+
) !void {
|
|
87
|
+
assert(!self.formatting and !self.formatting_superblock);
|
|
88
|
+
|
|
89
|
+
const arena = self.arena.allocator();
|
|
90
|
+
|
|
91
|
+
// The logical offset *within the Zone*.
|
|
92
|
+
// Even though the prepare zone follows the redundant header zone, write the prepares
|
|
93
|
+
// first. This allows the test Storage to check the invariant "never write the redundant
|
|
94
|
+
// header before the prepare".
|
|
95
|
+
for (0..constants.journal_slot_count) |slot| {
|
|
96
|
+
// Direct I/O requires the buffer to be sector-aligned. Allocate a buffer for each
|
|
97
|
+
// sector in the arena, so they can be written concurrently.
|
|
98
|
+
const header_buffer = try arena.alignedAlloc(
|
|
99
|
+
u8,
|
|
100
|
+
constants.sector_size,
|
|
101
|
+
constants.sector_size,
|
|
102
|
+
);
|
|
103
|
+
const header: *Header.Prepare = std.mem.bytesAsValue(
|
|
104
|
+
Header.Prepare,
|
|
105
|
+
header_buffer,
|
|
106
|
+
);
|
|
107
|
+
header.* = slot_header(cluster, slot);
|
|
108
|
+
assert(header.valid_checksum());
|
|
109
|
+
|
|
110
|
+
const prepare_offset = slot * constants.message_size_max;
|
|
111
|
+
assert(prepare_offset <= constants.journal_size_prepares);
|
|
112
|
+
assert(prepare_offset % @sizeOf(Header) == 0);
|
|
113
|
+
assert(prepare_offset % constants.sector_size == 0);
|
|
114
|
+
|
|
115
|
+
// Zero padding to produce identical checksums of an empty datafile, not because
|
|
116
|
+
// it's required for correctness.
|
|
117
|
+
const header_padding = header_buffer[@sizeOf(Header.Prepare)..];
|
|
118
|
+
@memset(header_padding, 0);
|
|
119
|
+
assert(stdx.zeroed(header_padding));
|
|
120
|
+
|
|
121
|
+
if (header.op == 0) {
|
|
122
|
+
assert(header.operation == .root);
|
|
123
|
+
} else {
|
|
124
|
+
assert(header.operation == .reserved);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
self.writes[self.writes_pending] = .{
|
|
128
|
+
.replica_format = self,
|
|
129
|
+
.issued_buffer = header_buffer,
|
|
130
|
+
.issued_offset = prepare_offset,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
storage.write_sectors(
|
|
134
|
+
write_sectors_callback,
|
|
135
|
+
&self.writes[self.writes_pending].write,
|
|
136
|
+
header_buffer,
|
|
137
|
+
.wal_prepares,
|
|
138
|
+
prepare_offset,
|
|
139
|
+
);
|
|
140
|
+
self.writes_pending += 1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Direct I/O requires the buffer to be sector-aligned. Unlike the Prepares above that
|
|
144
|
+
// require a buffer per prepare, since they are spread out with zeros inbetween, the
|
|
145
|
+
// headers zone is contiguous so a single buffer will do.
|
|
146
|
+
//
|
|
147
|
+
// There might be padding, so allocate []u8 instead of []Header.Prepare.
|
|
148
|
+
const headers_buffer = try arena.alignedAlloc(
|
|
149
|
+
u8,
|
|
150
|
+
constants.sector_size,
|
|
151
|
+
vsr.sector_ceil(constants.journal_size_headers),
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
for (0..constants.journal_slot_count) |slot| {
|
|
155
|
+
const header_buffer =
|
|
156
|
+
headers_buffer[slot * @sizeOf(Header.Prepare) ..][0..@sizeOf(Header.Prepare)];
|
|
157
|
+
const header: *Header.Prepare = @alignCast(
|
|
158
|
+
std.mem.bytesAsValue(Header.Prepare, header_buffer),
|
|
159
|
+
);
|
|
160
|
+
header.* = slot_header(cluster, slot);
|
|
161
|
+
assert(header.valid_checksum());
|
|
162
|
+
|
|
163
|
+
if (header.op == 0) {
|
|
164
|
+
assert(header.operation == .root);
|
|
165
|
+
} else {
|
|
166
|
+
assert(header.operation == .reserved);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Zero padding to produce identical checksums of an empty datafile, not because it's
|
|
171
|
+
// required for correctness.
|
|
172
|
+
const headers_padding =
|
|
173
|
+
headers_buffer[constants.journal_slot_count * @sizeOf(Header.Prepare) ..];
|
|
174
|
+
@memset(headers_padding, 0);
|
|
175
|
+
assert(stdx.zeroed(headers_padding));
|
|
176
|
+
|
|
177
|
+
self.writes[self.writes_pending] = .{
|
|
178
|
+
.replica_format = self,
|
|
179
|
+
.issued_buffer = headers_buffer,
|
|
180
|
+
.issued_offset = 0,
|
|
181
|
+
};
|
|
182
|
+
storage.write_sectors(
|
|
183
|
+
write_sectors_callback,
|
|
184
|
+
&self.writes[self.writes_pending].write,
|
|
185
|
+
headers_buffer,
|
|
186
|
+
.wal_headers,
|
|
187
|
+
0,
|
|
188
|
+
);
|
|
189
|
+
self.writes_pending += 1;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
fn format_and_tick(
|
|
193
|
+
self: *ReplicaFormat,
|
|
194
|
+
storage: *Storage,
|
|
195
|
+
superblock: *SuperBlock,
|
|
196
|
+
superblock_options: SuperBlock.FormatOptions,
|
|
197
|
+
) void {
|
|
198
|
+
assert(self.writes_pending == writes_max);
|
|
199
|
+
|
|
200
|
+
self.formatting = true;
|
|
201
|
+
while (self.formatting) storage.run();
|
|
202
|
+
|
|
203
|
+
self.formatting_superblock = true;
|
|
204
|
+
superblock.format(
|
|
205
|
+
format_superblock_callback,
|
|
206
|
+
&self.superblock_context,
|
|
207
|
+
superblock_options,
|
|
208
|
+
);
|
|
209
|
+
while (self.formatting_superblock) storage.run();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
fn write_sectors_callback(storage_write: *Storage.Write) void {
|
|
213
|
+
const write: *Write = @fieldParentPtr("write", storage_write);
|
|
214
|
+
const self = write.replica_format;
|
|
215
|
+
|
|
216
|
+
assert(self.formatting);
|
|
217
|
+
assert(!self.formatting_superblock);
|
|
218
|
+
|
|
219
|
+
self.writes_pending -= 1;
|
|
220
|
+
|
|
221
|
+
const sector_offset = @divExact(
|
|
222
|
+
storage_write.zone.offset(write.issued_offset),
|
|
223
|
+
constants.sector_size,
|
|
224
|
+
);
|
|
225
|
+
const sector_count = @divExact(write.issued_buffer.len, constants.sector_size);
|
|
226
|
+
|
|
227
|
+
for (sector_offset..sector_offset + sector_count) |sector| {
|
|
228
|
+
self.sectors_written.set(sector);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (self.writes_pending == 0) {
|
|
232
|
+
self.formatting = false;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
fn format_superblock_callback(superblock_context: *SuperBlock.Context) void {
|
|
237
|
+
const self: *ReplicaFormat =
|
|
238
|
+
@alignCast(@fieldParentPtr("superblock_context", superblock_context));
|
|
239
|
+
assert(!self.formatting);
|
|
240
|
+
assert(self.formatting_superblock);
|
|
241
|
+
self.formatting_superblock = false;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
fn verify_writes(self: *ReplicaFormat) void {
|
|
245
|
+
assert(!self.formatting and !self.formatting_superblock);
|
|
246
|
+
assert(self.writes_pending == 0);
|
|
247
|
+
|
|
248
|
+
assert(self.sectors_written.count() > 0);
|
|
249
|
+
assert(self.sectors_written.capacity() ==
|
|
250
|
+
@divExact(data_file_size_min, constants.sector_size));
|
|
251
|
+
|
|
252
|
+
// Expect that:
|
|
253
|
+
// * every sector in the wal_headers zone has been written,
|
|
254
|
+
// * the first sector in every constants.message_size_max has been written,
|
|
255
|
+
// * nothing else has been written.
|
|
256
|
+
//
|
|
257
|
+
// This might seem to miss the superblock zone, but that's handled entirely by
|
|
258
|
+
// superblock.zig, which reads back the headers to validate it has been written
|
|
259
|
+
// correctly.
|
|
260
|
+
for (0..self.sectors_written.capacity()) |sector| {
|
|
261
|
+
const sector_start = sector * constants.sector_size;
|
|
262
|
+
|
|
263
|
+
const zone = for (std.enums.values(vsr.Zone)) |zone| {
|
|
264
|
+
if (sector_start >= zone.start() and
|
|
265
|
+
sector_start < zone.start() + zone.size().?) break zone;
|
|
266
|
+
} else unreachable;
|
|
267
|
+
|
|
268
|
+
switch (zone) {
|
|
269
|
+
// Every sector in the wal_headers zone has been written:
|
|
270
|
+
.wal_headers => assert(self.sectors_written.isSet(sector)),
|
|
271
|
+
|
|
272
|
+
// The first sector in every constants.message_size_max has been written:
|
|
273
|
+
.wal_prepares => {
|
|
274
|
+
if ((sector_start - zone.start()) % constants.message_size_max == 0) {
|
|
275
|
+
assert(self.sectors_written.isSet(sector));
|
|
276
|
+
} else {
|
|
277
|
+
assert(!self.sectors_written.isSet(sector));
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
|
|
281
|
+
// Nothing else has been written:
|
|
282
|
+
else => assert(!self.sectors_written.isSet(sector)),
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
pub fn slot_header(cluster: u128, slot: u64) Header.Prepare {
|
|
290
|
+
assert(slot < constants.journal_slot_count);
|
|
291
|
+
assert(slot * @sizeOf(Header.Prepare) < constants.journal_size_headers);
|
|
292
|
+
assert(slot * constants.message_size_max < constants.journal_size_prepares);
|
|
293
|
+
assert(@sizeOf(Header.Prepare) < constants.sector_size);
|
|
294
|
+
|
|
295
|
+
return if (slot == 0)
|
|
296
|
+
Header.Prepare.root(cluster)
|
|
297
|
+
else
|
|
298
|
+
Header.Prepare.reserve(cluster, slot);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
test slot_header {
|
|
302
|
+
const allocator = std.testing.allocator;
|
|
303
|
+
|
|
304
|
+
const header_buffer = try allocator.create(Header.Prepare);
|
|
305
|
+
defer allocator.destroy(header_buffer);
|
|
306
|
+
|
|
307
|
+
for (0..constants.journal_slot_count) |slot| {
|
|
308
|
+
const header = slot_header(0, slot);
|
|
309
|
+
|
|
310
|
+
try std.testing.expect(header.valid_checksum());
|
|
311
|
+
try std.testing.expect(header.valid_checksum_body(&[0]u8{}));
|
|
312
|
+
try std.testing.expectEqual(header.invalid(), null);
|
|
313
|
+
try std.testing.expectEqual(header.cluster, 0);
|
|
314
|
+
try std.testing.expectEqual(header.op, slot);
|
|
315
|
+
try std.testing.expectEqual(header.size, @sizeOf(vsr.Header));
|
|
316
|
+
try std.testing.expectEqual(header.command, .prepare);
|
|
317
|
+
if (slot == 0) {
|
|
318
|
+
try std.testing.expectEqual(header.operation, .root);
|
|
319
|
+
} else {
|
|
320
|
+
try std.testing.expectEqual(header.operation, .reserved);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
test "format" {
|
|
326
|
+
const Storage = @import("../testing/storage.zig").Storage;
|
|
327
|
+
const fixtures = @import("../testing/fixtures.zig");
|
|
328
|
+
const allocator = std.testing.allocator;
|
|
329
|
+
const cluster = 0;
|
|
330
|
+
const replica = 1;
|
|
331
|
+
const replica_count = 1;
|
|
332
|
+
|
|
333
|
+
var storage = try fixtures.init_storage(allocator, .{
|
|
334
|
+
.size = data_file_size_min,
|
|
335
|
+
.iops_write_max = writes_max,
|
|
336
|
+
});
|
|
337
|
+
defer storage.deinit(allocator);
|
|
338
|
+
|
|
339
|
+
try format(Storage, allocator, &storage, .{
|
|
340
|
+
.cluster = cluster,
|
|
341
|
+
.release = vsr.Release.minimum,
|
|
342
|
+
.replica = replica,
|
|
343
|
+
.replica_count = replica_count,
|
|
344
|
+
.view = null,
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
// Verify the superblock headers.
|
|
348
|
+
var copy: u8 = 0;
|
|
349
|
+
while (copy < constants.superblock_copies) : (copy += 1) {
|
|
350
|
+
const superblock_header = storage.superblock_header(copy);
|
|
351
|
+
|
|
352
|
+
try std.testing.expectEqual(superblock_header.copy, copy);
|
|
353
|
+
try std.testing.expectEqual(superblock_header.cluster, cluster);
|
|
354
|
+
try std.testing.expectEqual(superblock_header.sequence, 1);
|
|
355
|
+
try std.testing.expectEqual(
|
|
356
|
+
superblock_header.vsr_state.checkpoint.storage_size,
|
|
357
|
+
storage.size,
|
|
358
|
+
);
|
|
359
|
+
try std.testing.expectEqual(superblock_header.vsr_state.checkpoint.header.op, 0);
|
|
360
|
+
try std.testing.expectEqual(superblock_header.vsr_state.commit_max, 0);
|
|
361
|
+
try std.testing.expectEqual(superblock_header.vsr_state.view, 0);
|
|
362
|
+
try std.testing.expectEqual(superblock_header.vsr_state.log_view, 0);
|
|
363
|
+
try std.testing.expectEqual(
|
|
364
|
+
superblock_header.vsr_state.replica_id,
|
|
365
|
+
superblock_header.vsr_state.members[replica],
|
|
366
|
+
);
|
|
367
|
+
try std.testing.expectEqual(superblock_header.vsr_state.replica_count, replica_count);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Verify the WAL headers and prepares zones.
|
|
371
|
+
for (storage.wal_headers(), storage.wal_prepares(), 0..) |header, *message, slot| {
|
|
372
|
+
try std.testing.expect(std.meta.eql(header, message.header));
|
|
373
|
+
|
|
374
|
+
try std.testing.expect(header.valid_checksum());
|
|
375
|
+
try std.testing.expect(header.valid_checksum_body(&[0]u8{}));
|
|
376
|
+
try std.testing.expectEqual(header.invalid(), null);
|
|
377
|
+
try std.testing.expectEqual(header.cluster, cluster);
|
|
378
|
+
try std.testing.expectEqual(header.op, slot);
|
|
379
|
+
try std.testing.expectEqual(header.size, @sizeOf(vsr.Header));
|
|
380
|
+
try std.testing.expectEqual(header.command, .prepare);
|
|
381
|
+
if (slot == 0) {
|
|
382
|
+
try std.testing.expectEqual(header.operation, .root);
|
|
383
|
+
} else {
|
|
384
|
+
try std.testing.expectEqual(header.operation, .reserved);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Verify client replies. The contents are not zeroed.
|
|
389
|
+
try std.testing.expectEqual(storage.client_replies().len, constants.clients_max);
|
|
390
|
+
|
|
391
|
+
// Verify grid alignment. The contents of the padding are not zeroed.
|
|
392
|
+
try std.testing.expect(vsr.Zone.grid.start() % constants.sector_size == 0);
|
|
393
|
+
|
|
394
|
+
// Explicitly zero client_replies and the grid padding. This is not required for formatting, but
|
|
395
|
+
// it allows for easy checksums of the entire testing storage.
|
|
396
|
+
@memset(
|
|
397
|
+
storage.memory[vsr.Zone.client_replies.offset(0)..][0..vsr.Zone.client_replies.size().?],
|
|
398
|
+
0,
|
|
399
|
+
);
|
|
400
|
+
if (vsr.Zone.grid_padding.size().? > 0) {
|
|
401
|
+
@memset(
|
|
402
|
+
storage.memory[vsr.Zone.grid_padding.offset(0)..][0..vsr.Zone.grid_padding.size().?],
|
|
403
|
+
0,
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Lastly, verify the entire storage contents against a known good checksum for the given
|
|
408
|
+
// cluster, replica and replica count.
|
|
409
|
+
//
|
|
410
|
+
// This doesn't match the output from `tigerbeetle format ...` since the testing storage / slot
|
|
411
|
+
// counts are lower.
|
|
412
|
+
try std.testing.expectEqual(
|
|
413
|
+
vsr.checksum(storage.memory),
|
|
414
|
+
339529914272821912685300045374558551362,
|
|
415
|
+
);
|
|
416
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
//! Replica recovery: Format a data file to replace one which was permanently lost.
|
|
2
|
+
//!
|
|
3
|
+
//! 1. The recovery process send `pipeline_prepare_queue_max` requests (1 register + many noops) to
|
|
4
|
+
//! the cluster.
|
|
5
|
+
//! 2. Once those have committed, it creates the new data file. The data file is identical to
|
|
6
|
+
//! `tigerbeetle format`'s output *except* that `vsr_state.view == client.view + 2` (where
|
|
7
|
+
//! `client.view` is the view number of the client at the end of committing the requests).
|
|
8
|
+
//! 3. The recovery process exits. Now running `tigerbeetle start` as normal will work.
|
|
9
|
+
//!
|
|
10
|
+
//! The `pipeline_prepare_queue_max` committed requests ensure that if the newly recovered replica
|
|
11
|
+
//! nacks uncommitted ops via a DVC message, it is nacking ops which were definitely not received by
|
|
12
|
+
//! the previous version of the replica.
|
|
13
|
+
//!
|
|
14
|
+
//! The +2 is because:
|
|
15
|
+
//! - We don't want to join in the same view, since the replica might have participated in it before
|
|
16
|
+
//! being lost, and we can't remember any promises we made.
|
|
17
|
+
//! - Likewise, we don't want to go to view + 1 -- if we were the first to collect a SVC quorum
|
|
18
|
+
//! before being lost, we might have sent a DVC. Since we don't remember, we must skip past
|
|
19
|
+
//! `view + 11 to ensure that we don't send a different DVC. (We have the invariant that if a
|
|
20
|
+
//! replica sends a DVC for a given view, then all DVC's it sends for that view will be
|
|
21
|
+
//! identical.)
|
|
22
|
+
const std = @import("std");
|
|
23
|
+
const assert = std.debug.assert;
|
|
24
|
+
|
|
25
|
+
const constants = @import("../constants.zig");
|
|
26
|
+
const vsr = @import("../vsr.zig");
|
|
27
|
+
const format = @import("./replica_format.zig").format;
|
|
28
|
+
|
|
29
|
+
const log = std.log.scoped(.reformat);
|
|
30
|
+
|
|
31
|
+
pub fn ReplicaReformatType(
|
|
32
|
+
comptime StateMachine: type,
|
|
33
|
+
comptime MessageBus: type,
|
|
34
|
+
comptime Storage: type,
|
|
35
|
+
) type {
|
|
36
|
+
const Client = vsr.ClientType(StateMachine.Operation, MessageBus);
|
|
37
|
+
const SuperBlock = vsr.SuperBlockType(Storage);
|
|
38
|
+
|
|
39
|
+
return struct {
|
|
40
|
+
const ReplicaReformat = @This();
|
|
41
|
+
|
|
42
|
+
const Result = union(enum) {
|
|
43
|
+
failed: anyerror,
|
|
44
|
+
ok,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
allocator: std.mem.Allocator,
|
|
48
|
+
options: SuperBlock.FormatOptions,
|
|
49
|
+
client: *Client,
|
|
50
|
+
storage: *Storage,
|
|
51
|
+
|
|
52
|
+
requests_done: u32 = 0,
|
|
53
|
+
result: ?Result = null,
|
|
54
|
+
|
|
55
|
+
pub fn init(
|
|
56
|
+
allocator: std.mem.Allocator,
|
|
57
|
+
client: *Client,
|
|
58
|
+
storage: *Storage,
|
|
59
|
+
options: SuperBlock.FormatOptions,
|
|
60
|
+
) !ReplicaReformat {
|
|
61
|
+
assert(options.view == null);
|
|
62
|
+
assert(options.replica_count >= 3);
|
|
63
|
+
|
|
64
|
+
return .{
|
|
65
|
+
.allocator = allocator,
|
|
66
|
+
.options = options,
|
|
67
|
+
.client = client,
|
|
68
|
+
.storage = storage,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
pub fn deinit(reformat: *ReplicaReformat, allocator: std.mem.Allocator) void {
|
|
73
|
+
_ = reformat;
|
|
74
|
+
_ = allocator;
|
|
75
|
+
}
|
|
76
|
+
pub fn done(reformat: *const ReplicaReformat) ?Result {
|
|
77
|
+
assert(reformat.requests_done <= constants.pipeline_prepare_queue_max);
|
|
78
|
+
return reformat.result;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
pub fn start(reformat: *ReplicaReformat) void {
|
|
82
|
+
assert(reformat.requests_done == 0);
|
|
83
|
+
const user_data = @intFromPtr(reformat);
|
|
84
|
+
reformat.client.register(client_register_callback, user_data);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn client_register_callback(
|
|
88
|
+
user_data: u128,
|
|
89
|
+
register_result: *const vsr.RegisterResult,
|
|
90
|
+
) void {
|
|
91
|
+
_ = register_result;
|
|
92
|
+
const reformat: *ReplicaReformat = @ptrFromInt(@as(usize, @intCast(user_data)));
|
|
93
|
+
assert(reformat.requests_done == 0);
|
|
94
|
+
|
|
95
|
+
log.debug("{}: register", .{reformat.options.replica});
|
|
96
|
+
|
|
97
|
+
reformat.requests_done += 1;
|
|
98
|
+
reformat.client_request();
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
fn client_request(reformat: *ReplicaReformat) void {
|
|
102
|
+
assert(reformat.requests_done < constants.pipeline_prepare_queue_max);
|
|
103
|
+
|
|
104
|
+
log.debug("{}: request start={}", .{
|
|
105
|
+
reformat.options.replica,
|
|
106
|
+
reformat.requests_done,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const message = reformat.client.get_message().build(.request);
|
|
110
|
+
errdefer reformat.client.release_message(message.base());
|
|
111
|
+
|
|
112
|
+
message.header.* = .{
|
|
113
|
+
.client = reformat.client.id,
|
|
114
|
+
.request = 0, // Set inside `raw_request`.
|
|
115
|
+
.cluster = reformat.client.cluster,
|
|
116
|
+
.command = .request,
|
|
117
|
+
.release = reformat.client.release,
|
|
118
|
+
.operation = .noop,
|
|
119
|
+
.size = @sizeOf(vsr.Header),
|
|
120
|
+
.previous_request_latency = 0,
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const user_data = @intFromPtr(reformat);
|
|
124
|
+
reformat.client.raw_request(client_request_callback, user_data, message);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
fn client_request_callback(
|
|
128
|
+
user_data: u128,
|
|
129
|
+
operation: vsr.Operation,
|
|
130
|
+
timestamp: u64,
|
|
131
|
+
results: []u8,
|
|
132
|
+
) void {
|
|
133
|
+
assert(operation == .noop);
|
|
134
|
+
assert(timestamp > 0);
|
|
135
|
+
|
|
136
|
+
const reformat: *ReplicaReformat = @ptrFromInt(@as(usize, @intCast(user_data)));
|
|
137
|
+
assert(reformat.requests_done > 0);
|
|
138
|
+
assert(reformat.requests_done < constants.pipeline_prepare_queue_max);
|
|
139
|
+
assert(results.len == 0);
|
|
140
|
+
|
|
141
|
+
log.debug("{}: request done={}", .{
|
|
142
|
+
reformat.options.replica,
|
|
143
|
+
reformat.requests_done,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
reformat.requests_done += 1;
|
|
147
|
+
if (reformat.requests_done == constants.pipeline_prepare_queue_max) {
|
|
148
|
+
// +2 since we might have sent a DVC as part of +1 before we crashed.
|
|
149
|
+
reformat.options.view = reformat.client.view + 2;
|
|
150
|
+
format(
|
|
151
|
+
Storage,
|
|
152
|
+
reformat.allocator,
|
|
153
|
+
reformat.storage,
|
|
154
|
+
reformat.options,
|
|
155
|
+
) catch |err| {
|
|
156
|
+
reformat.result = .{ .failed = err };
|
|
157
|
+
return;
|
|
158
|
+
};
|
|
159
|
+
reformat.result = .ok;
|
|
160
|
+
} else {
|
|
161
|
+
reformat.client_request();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|