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,532 @@
|
|
|
1
|
+
//! Store the latest reply to every active client session.
|
|
2
|
+
//!
|
|
3
|
+
//! This allows them to be resent to the corresponding client if the client missed the original
|
|
4
|
+
//! reply message (e.g. dropped packet).
|
|
5
|
+
//!
|
|
6
|
+
//! - Client replies' headers are stored in the `client_sessions` trailer.
|
|
7
|
+
//! - Client replies (header and body) are only stored by ClientReplies in the `client_replies` zone
|
|
8
|
+
//! when `reply.header.size ≠ sizeOf(Header)` – that is, when the body is non-empty.
|
|
9
|
+
//! - Corrupt client replies can be repaired from other replicas.
|
|
10
|
+
//!
|
|
11
|
+
//! Replies are written asynchronously. Subsequent writes for the same client may be coalesced –
|
|
12
|
+
//! we only care about the last reply to each client session.
|
|
13
|
+
//!
|
|
14
|
+
//! ClientReplies guarantees that the latest replies are durable at checkpoint.
|
|
15
|
+
//!
|
|
16
|
+
//! If the same reply is corrupted by all replicas, the cluster is still available.
|
|
17
|
+
//! If the respective client also never received the reply (due to a network fault), the client may
|
|
18
|
+
//! be "locked out" of the cluster – continually retrying a request which has been executed, but
|
|
19
|
+
//! whose reply has been permanently lost. This can be resolved by the operator restarting the
|
|
20
|
+
//! client to create a new session.
|
|
21
|
+
const std = @import("std");
|
|
22
|
+
const assert = std.debug.assert;
|
|
23
|
+
const maybe = stdx.maybe;
|
|
24
|
+
const log = std.log.scoped(.client_replies);
|
|
25
|
+
|
|
26
|
+
const stdx = @import("stdx");
|
|
27
|
+
const constants = @import("../constants.zig");
|
|
28
|
+
const RingBufferType = stdx.RingBufferType;
|
|
29
|
+
const IOPSType = @import("../iops.zig").IOPSType;
|
|
30
|
+
const vsr = @import("../vsr.zig");
|
|
31
|
+
const Message = @import("../message_pool.zig").MessagePool.Message;
|
|
32
|
+
const MessagePool = @import("../message_pool.zig").MessagePool;
|
|
33
|
+
const Slot = @import("client_sessions.zig").ReplySlot;
|
|
34
|
+
const ClientSessions = @import("client_sessions.zig").ClientSessions;
|
|
35
|
+
|
|
36
|
+
fn slot_offset(slot: Slot) usize {
|
|
37
|
+
return slot.index * constants.message_size_max;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// TODO Optimization:
|
|
41
|
+
// Don't always immediately start writing a reply. Instead, hold onto it in the hopes that
|
|
42
|
+
// the same client will queue another request. If they do (within the same checkpoint),
|
|
43
|
+
// then we no longer need to persist the original reply.
|
|
44
|
+
pub fn ClientRepliesType(comptime Storage: type) type {
|
|
45
|
+
return struct {
|
|
46
|
+
const ClientReplies = @This();
|
|
47
|
+
|
|
48
|
+
const Read = struct {
|
|
49
|
+
client_replies: *ClientReplies,
|
|
50
|
+
completion: Storage.Read,
|
|
51
|
+
callback: ?*const fn (
|
|
52
|
+
client_replies: *ClientReplies,
|
|
53
|
+
reply_header: *const vsr.Header.Reply,
|
|
54
|
+
reply: ?*Message.Reply,
|
|
55
|
+
destination_replica: ?u8,
|
|
56
|
+
) void,
|
|
57
|
+
slot: Slot,
|
|
58
|
+
message: *Message.Reply,
|
|
59
|
+
/// The header of the expected reply.
|
|
60
|
+
header: vsr.Header.Reply,
|
|
61
|
+
destination_replica: ?u8,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const Write = struct {
|
|
65
|
+
client_replies: *ClientReplies,
|
|
66
|
+
completion: Storage.Write,
|
|
67
|
+
slot: Slot,
|
|
68
|
+
message: *Message.Reply,
|
|
69
|
+
trigger: WriteTrigger,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const WriteTrigger = enum { commit, repair };
|
|
73
|
+
|
|
74
|
+
const WriteQueue = RingBufferType(*Write, .{
|
|
75
|
+
.array = constants.client_replies_iops_write_max,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
storage: *Storage,
|
|
79
|
+
message_pool: *MessagePool,
|
|
80
|
+
replica: u8,
|
|
81
|
+
|
|
82
|
+
reads: IOPSType(Read, constants.client_replies_iops_read_max) = .{},
|
|
83
|
+
writes: IOPSType(Write, constants.client_replies_iops_write_max) = .{},
|
|
84
|
+
|
|
85
|
+
/// Track which slots have a write currently in progress.
|
|
86
|
+
writing: stdx.BitSetType(constants.clients_max) = .{},
|
|
87
|
+
/// Track which slots hold a corrupt reply, or are otherwise missing the reply
|
|
88
|
+
/// that ClientSessions believes they should hold.
|
|
89
|
+
///
|
|
90
|
+
/// Invariants:
|
|
91
|
+
/// - Set bits must correspond to occupied slots in ClientSessions.
|
|
92
|
+
/// - Set bits must correspond to entries in ClientSessions with
|
|
93
|
+
/// `header.size > @sizeOf(vsr.Header)`.
|
|
94
|
+
faulty: stdx.BitSetType(constants.clients_max) = .{},
|
|
95
|
+
|
|
96
|
+
/// Guard against multiple concurrent writes to the same slot.
|
|
97
|
+
/// Pointers are into `writes`.
|
|
98
|
+
write_queue: WriteQueue = WriteQueue.init(),
|
|
99
|
+
|
|
100
|
+
ready_callback: ?*const fn (*ClientReplies) void = null,
|
|
101
|
+
|
|
102
|
+
checkpoint_next_tick: Storage.NextTick = undefined,
|
|
103
|
+
checkpoint_callback: ?*const fn (*ClientReplies) void = null,
|
|
104
|
+
|
|
105
|
+
pub fn init(options: struct {
|
|
106
|
+
storage: *Storage,
|
|
107
|
+
message_pool: *MessagePool,
|
|
108
|
+
replica_index: u8,
|
|
109
|
+
}) ClientReplies {
|
|
110
|
+
return .{
|
|
111
|
+
.storage = options.storage,
|
|
112
|
+
.message_pool = options.message_pool,
|
|
113
|
+
.replica = options.replica_index,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub fn deinit(client_replies: *ClientReplies) void {
|
|
118
|
+
{
|
|
119
|
+
var it = client_replies.reads.iterate();
|
|
120
|
+
while (it.next()) |read| client_replies.message_pool.unref(read.message);
|
|
121
|
+
}
|
|
122
|
+
{
|
|
123
|
+
var it = client_replies.writes.iterate();
|
|
124
|
+
while (it.next()) |write| client_replies.message_pool.unref(write.message);
|
|
125
|
+
}
|
|
126
|
+
// Don't unref `write_queue`'s Writes — they are a subset of `writes`.
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/// Returns true if the reply at the given slot is durably persisted to disk. The
|
|
130
|
+
/// difference with `faulty` bit set is that `faulty` is cleared at the start of a write
|
|
131
|
+
/// when the reply is still in RAM. In contrast, `reply_durable` checks that the
|
|
132
|
+
/// corresponding reply hit the disk.
|
|
133
|
+
pub fn reply_durable(
|
|
134
|
+
client_replies: *const ClientReplies,
|
|
135
|
+
slot: Slot,
|
|
136
|
+
) bool {
|
|
137
|
+
return !client_replies.faulty.is_set(slot.index) and
|
|
138
|
+
!client_replies.writing.is_set(slot.index);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
pub fn read_reply_sync(
|
|
142
|
+
client_replies: *ClientReplies,
|
|
143
|
+
slot: Slot,
|
|
144
|
+
session: *const ClientSessions.Entry,
|
|
145
|
+
) ?*Message.Reply {
|
|
146
|
+
const client = session.header.client;
|
|
147
|
+
|
|
148
|
+
if (!client_replies.writing.is_set(slot.index)) return null;
|
|
149
|
+
|
|
150
|
+
var writes = client_replies.writes.iterate();
|
|
151
|
+
var write_latest: ?*const Write = null;
|
|
152
|
+
while (writes.next()) |write| {
|
|
153
|
+
if (write.message.header.client == client) {
|
|
154
|
+
if (write_latest == null or
|
|
155
|
+
write_latest.?.message.header.request < write.message.header.request)
|
|
156
|
+
{
|
|
157
|
+
write_latest = write;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// The reply being written to the target slot may not be for the client that we're
|
|
163
|
+
// looking for. For example, it may be an old reply for a different client.
|
|
164
|
+
maybe(write_latest == null);
|
|
165
|
+
|
|
166
|
+
if (write_latest == null or
|
|
167
|
+
write_latest.?.message.header.checksum != session.header.checksum)
|
|
168
|
+
{
|
|
169
|
+
// We are writing a reply, but that's a wrong reply according to `client_sessions`.
|
|
170
|
+
// This happens after state sync, where we update `client_sessions` without
|
|
171
|
+
// waiting for the in-flight write requests to complete.
|
|
172
|
+
assert(client_replies.faulty.is_set(slot.index));
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
assert(!client_replies.faulty.is_set(slot.index));
|
|
177
|
+
return write_latest.?.message;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/// Caller must check read_reply_sync() first.
|
|
181
|
+
/// (They are split up to avoid complicated NextTick bounds.)
|
|
182
|
+
pub fn read_reply(
|
|
183
|
+
client_replies: *ClientReplies,
|
|
184
|
+
slot: Slot,
|
|
185
|
+
session: *const ClientSessions.Entry,
|
|
186
|
+
callback: *const fn (
|
|
187
|
+
*ClientReplies,
|
|
188
|
+
*const vsr.Header.Reply,
|
|
189
|
+
?*Message.Reply,
|
|
190
|
+
?u8,
|
|
191
|
+
) void,
|
|
192
|
+
destination_replica: ?u8,
|
|
193
|
+
) error{Busy}!void {
|
|
194
|
+
assert(client_replies.read_reply_sync(slot, session) == null);
|
|
195
|
+
|
|
196
|
+
const read = client_replies.reads.acquire() orelse {
|
|
197
|
+
log.debug("{}: read_reply: busy (client={} reply={x:0>32})", .{
|
|
198
|
+
client_replies.replica,
|
|
199
|
+
session.header.client,
|
|
200
|
+
session.header.checksum,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return error.Busy;
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
log.debug("{}: read_reply: start (client={} reply={x:0>32})", .{
|
|
207
|
+
client_replies.replica,
|
|
208
|
+
session.header.client,
|
|
209
|
+
session.header.checksum,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
const message = client_replies.message_pool.get_message(.reply);
|
|
213
|
+
defer client_replies.message_pool.unref(message);
|
|
214
|
+
|
|
215
|
+
read.* = .{
|
|
216
|
+
.client_replies = client_replies,
|
|
217
|
+
.completion = undefined,
|
|
218
|
+
.slot = slot,
|
|
219
|
+
.message = message.ref(),
|
|
220
|
+
.callback = callback,
|
|
221
|
+
.header = session.header,
|
|
222
|
+
.destination_replica = destination_replica,
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
client_replies.storage.read_sectors(
|
|
226
|
+
read_reply_callback,
|
|
227
|
+
&read.completion,
|
|
228
|
+
message.buffer[0..vsr.sector_ceil(session.header.size)],
|
|
229
|
+
.client_replies,
|
|
230
|
+
slot_offset(slot),
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
fn read_reply_callback(completion: *Storage.Read) void {
|
|
235
|
+
const read: *ClientReplies.Read = @alignCast(@fieldParentPtr("completion", completion));
|
|
236
|
+
const client_replies = read.client_replies;
|
|
237
|
+
const header = read.header;
|
|
238
|
+
const message = read.message;
|
|
239
|
+
const callback_or_null = read.callback;
|
|
240
|
+
const destination_replica = read.destination_replica;
|
|
241
|
+
|
|
242
|
+
client_replies.reads.release(read);
|
|
243
|
+
defer client_replies.message_pool.unref(message);
|
|
244
|
+
|
|
245
|
+
const callback = callback_or_null orelse {
|
|
246
|
+
log.debug("{}: read_reply: already resolved (client={} reply={x:0>32})", .{
|
|
247
|
+
client_replies.replica,
|
|
248
|
+
header.client,
|
|
249
|
+
header.checksum,
|
|
250
|
+
});
|
|
251
|
+
return;
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
if (!message.header.valid_checksum() or
|
|
255
|
+
!message.header.valid_checksum_body(message.body_used()))
|
|
256
|
+
{
|
|
257
|
+
log.warn("{}: read_reply: corrupt reply (client={} reply={x:0>32})", .{
|
|
258
|
+
client_replies.replica,
|
|
259
|
+
header.client,
|
|
260
|
+
header.checksum,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
callback(client_replies, &header, null, destination_replica);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Possible causes:
|
|
268
|
+
// - The read targets an older reply.
|
|
269
|
+
// - The read targets a newer reply (that we haven't seen/written yet).
|
|
270
|
+
// - The read targets a reply that we wrote, but was misdirected.
|
|
271
|
+
if (message.header.checksum != header.checksum) {
|
|
272
|
+
log.warn("{}: read_reply: unexpected header " ++
|
|
273
|
+
"(client={} reply={x:0>32} found={x:0>32})", .{
|
|
274
|
+
client_replies.replica,
|
|
275
|
+
header.client,
|
|
276
|
+
header.checksum,
|
|
277
|
+
message.header.checksum,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
callback(client_replies, &header, null, destination_replica);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
assert(message.header.command == .reply);
|
|
285
|
+
assert(message.header.cluster == header.cluster);
|
|
286
|
+
|
|
287
|
+
log.debug("{}: read_reply: done (client={} reply={x:0>32})", .{
|
|
288
|
+
client_replies.replica,
|
|
289
|
+
header.client,
|
|
290
|
+
header.checksum,
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
callback(client_replies, &header, message, destination_replica);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
pub fn ready_sync(client_replies: *ClientReplies) bool {
|
|
297
|
+
maybe(client_replies.ready_callback == null);
|
|
298
|
+
assert(client_replies.writing.count() + client_replies.write_queue.count ==
|
|
299
|
+
client_replies.writes.executing());
|
|
300
|
+
|
|
301
|
+
return client_replies.writes.available() > 0;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/// Caller must check ready_sync() first.
|
|
305
|
+
/// Call `callback` when ClientReplies is able to start another write_reply().
|
|
306
|
+
pub fn ready(
|
|
307
|
+
client_replies: *ClientReplies,
|
|
308
|
+
callback: *const fn (client_replies: *ClientReplies) void,
|
|
309
|
+
) void {
|
|
310
|
+
assert(client_replies.ready_callback == null);
|
|
311
|
+
assert(!client_replies.ready_sync());
|
|
312
|
+
assert(client_replies.writes.available() == 0);
|
|
313
|
+
assert(client_replies.writing.count() + client_replies.write_queue.count ==
|
|
314
|
+
client_replies.writes.executing());
|
|
315
|
+
|
|
316
|
+
// ready_callback will be called the next time a write completes.
|
|
317
|
+
client_replies.ready_callback = callback;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
pub fn remove_reply(client_replies: *ClientReplies, slot: Slot) void {
|
|
321
|
+
maybe(client_replies.faulty.is_set(slot.index));
|
|
322
|
+
|
|
323
|
+
client_replies.faulty.unset(slot.index);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/// The caller is responsible for ensuring that the ClientReplies is able to write
|
|
327
|
+
/// by calling `write_reply()` after `ready()` finishes.
|
|
328
|
+
pub fn write_reply(
|
|
329
|
+
client_replies: *ClientReplies,
|
|
330
|
+
slot: Slot,
|
|
331
|
+
message: *Message.Reply,
|
|
332
|
+
trigger: WriteTrigger,
|
|
333
|
+
) void {
|
|
334
|
+
assert(client_replies.ready_sync());
|
|
335
|
+
assert(client_replies.ready_callback == null);
|
|
336
|
+
assert(client_replies.writes.available() > 0);
|
|
337
|
+
maybe(client_replies.writing.is_set(slot.index));
|
|
338
|
+
assert(client_replies.writing.count() + client_replies.write_queue.count ==
|
|
339
|
+
client_replies.writes.executing());
|
|
340
|
+
assert(message.header.command == .reply);
|
|
341
|
+
// There is never any need to write a body-less message, since the header is
|
|
342
|
+
// stored safely in the `client_sessions` trailer.
|
|
343
|
+
assert(message.header.size != @sizeOf(vsr.Header));
|
|
344
|
+
|
|
345
|
+
switch (trigger) {
|
|
346
|
+
.commit => {
|
|
347
|
+
assert(client_replies.checkpoint_callback == null);
|
|
348
|
+
maybe(client_replies.faulty.is_set(slot.index));
|
|
349
|
+
},
|
|
350
|
+
.repair => {
|
|
351
|
+
maybe(client_replies.checkpoint_callback == null);
|
|
352
|
+
assert(client_replies.faulty.is_set(slot.index));
|
|
353
|
+
},
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// Resolve any pending reads for this reply.
|
|
357
|
+
// If we don't do this, an earlier started read can complete with an error, and
|
|
358
|
+
// erroneously clobber the faulty bit.
|
|
359
|
+
// For simplicity, resolve the reads synchronously, instead of going through next tick
|
|
360
|
+
// machinery.
|
|
361
|
+
var reads = client_replies.reads.iterate();
|
|
362
|
+
while (reads.next()) |read| {
|
|
363
|
+
if (read.callback == null) continue; // Already resolved.
|
|
364
|
+
if (read.header.checksum == message.header.checksum) {
|
|
365
|
+
defer read.callback = null;
|
|
366
|
+
|
|
367
|
+
read.callback.?(
|
|
368
|
+
client_replies,
|
|
369
|
+
&read.header,
|
|
370
|
+
message,
|
|
371
|
+
read.destination_replica,
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Clear the fault *before* the write completes, not after.
|
|
377
|
+
// Otherwise, a replica exiting state sync might mark a reply as faulty, then the
|
|
378
|
+
// ClientReplies clears that bit due to an unrelated write that was already queued.
|
|
379
|
+
client_replies.faulty.unset(slot.index);
|
|
380
|
+
|
|
381
|
+
const write = client_replies.writes.acquire().?;
|
|
382
|
+
write.* = .{
|
|
383
|
+
.client_replies = client_replies,
|
|
384
|
+
.completion = undefined,
|
|
385
|
+
.message = message.ref(),
|
|
386
|
+
.slot = slot,
|
|
387
|
+
.trigger = trigger,
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
// If there is already a write to the same slot queued (but not started), replace it.
|
|
391
|
+
var write_queue = client_replies.write_queue.iterator_mutable();
|
|
392
|
+
while (write_queue.next_ptr()) |queued| {
|
|
393
|
+
if (queued.*.slot.index == slot.index) {
|
|
394
|
+
client_replies.message_pool.unref(queued.*.message);
|
|
395
|
+
client_replies.writes.release(queued.*);
|
|
396
|
+
|
|
397
|
+
queued.* = write;
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
} else {
|
|
401
|
+
client_replies.write_queue.push_assume_capacity(write);
|
|
402
|
+
client_replies.write_reply_next();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
assert(client_replies.writing.is_set(write.slot.index));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
fn write_reply_next(client_replies: *ClientReplies) void {
|
|
409
|
+
while (client_replies.write_queue.head()) |write| {
|
|
410
|
+
if (client_replies.writing.is_set(write.slot.index)) return;
|
|
411
|
+
|
|
412
|
+
const message = write.message;
|
|
413
|
+
_ = client_replies.write_queue.pop();
|
|
414
|
+
|
|
415
|
+
// Padding must be zero to ensure deterministic storage.
|
|
416
|
+
const size = message.header.size;
|
|
417
|
+
const size_ceil = vsr.sector_ceil(size);
|
|
418
|
+
assert(stdx.zeroed(message.buffer[size..size_ceil]));
|
|
419
|
+
|
|
420
|
+
client_replies.writing.set(write.slot.index);
|
|
421
|
+
client_replies.storage.write_sectors(
|
|
422
|
+
write_reply_callback,
|
|
423
|
+
&write.completion,
|
|
424
|
+
message.buffer[0..size_ceil],
|
|
425
|
+
.client_replies,
|
|
426
|
+
slot_offset(write.slot),
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
fn write_reply_callback(completion: *Storage.Write) void {
|
|
432
|
+
const write: *ClientReplies.Write = @fieldParentPtr("completion", completion);
|
|
433
|
+
const client_replies = write.client_replies;
|
|
434
|
+
const message = write.message;
|
|
435
|
+
assert(client_replies.writing.is_set(write.slot.index));
|
|
436
|
+
maybe(client_replies.faulty.is_set(write.slot.index));
|
|
437
|
+
|
|
438
|
+
var reads = client_replies.reads.iterate();
|
|
439
|
+
while (reads.next()) |read| {
|
|
440
|
+
if (read.slot.index == write.slot.index) {
|
|
441
|
+
if (read.header.checksum == message.header.checksum) {
|
|
442
|
+
assert(read.callback == null);
|
|
443
|
+
} else {
|
|
444
|
+
// A read and a write can race on the slot if:
|
|
445
|
+
// - the write is from before the latest state sync (outdated write)
|
|
446
|
+
// - the read is from before the write (outdated read)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
log.debug("{}: write_reply: wrote (client={} request={})", .{
|
|
452
|
+
client_replies.replica,
|
|
453
|
+
message.header.client,
|
|
454
|
+
message.header.request,
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// Release the write *before* invoking the callback, so that if the callback checks
|
|
458
|
+
// .writes.available() we don't erroneously appear busy.
|
|
459
|
+
client_replies.writing.unset(write.slot.index);
|
|
460
|
+
client_replies.writes.release(write);
|
|
461
|
+
|
|
462
|
+
client_replies.message_pool.unref(message);
|
|
463
|
+
client_replies.write_reply_next();
|
|
464
|
+
|
|
465
|
+
if (client_replies.ready_callback) |ready_callback| {
|
|
466
|
+
client_replies.ready_callback = null;
|
|
467
|
+
ready_callback(client_replies);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (client_replies.checkpoint_callback != null and
|
|
471
|
+
client_replies.writes_executing_by_trigger(.commit) == 0)
|
|
472
|
+
{
|
|
473
|
+
client_replies.checkpoint_done();
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Wait until all writes with trigger=commit are done, and then invoke the callback.
|
|
478
|
+
// (Writes with trigger=repair may still be in progress.)
|
|
479
|
+
pub fn checkpoint(
|
|
480
|
+
client_replies: *ClientReplies,
|
|
481
|
+
callback: *const fn (*ClientReplies) void,
|
|
482
|
+
) void {
|
|
483
|
+
assert(client_replies.checkpoint_callback == null);
|
|
484
|
+
client_replies.checkpoint_callback = callback;
|
|
485
|
+
|
|
486
|
+
if (client_replies.writes_executing_by_trigger(.commit) == 0) {
|
|
487
|
+
client_replies.storage.on_next_tick(
|
|
488
|
+
.vsr,
|
|
489
|
+
checkpoint_next_tick_callback,
|
|
490
|
+
&client_replies.checkpoint_next_tick,
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
fn checkpoint_next_tick_callback(next_tick: *Storage.NextTick) void {
|
|
496
|
+
const client_replies: *ClientReplies =
|
|
497
|
+
@alignCast(@fieldParentPtr("checkpoint_next_tick", next_tick));
|
|
498
|
+
|
|
499
|
+
if (client_replies.checkpoint_callback != null) {
|
|
500
|
+
client_replies.checkpoint_done();
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
fn checkpoint_done(client_replies: *ClientReplies) void {
|
|
505
|
+
assert(client_replies.writes_executing_by_trigger(.commit) == 0);
|
|
506
|
+
|
|
507
|
+
const repairing = client_replies.writes_executing_by_trigger(.repair);
|
|
508
|
+
assert(client_replies.writes.executing() == repairing);
|
|
509
|
+
assert(client_replies.writing.count() + client_replies.write_queue.count == repairing);
|
|
510
|
+
|
|
511
|
+
const callback = client_replies.checkpoint_callback.?;
|
|
512
|
+
client_replies.checkpoint_callback = null;
|
|
513
|
+
|
|
514
|
+
callback(client_replies);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
fn writes_executing_by_trigger(
|
|
518
|
+
client_replies: *const ClientReplies,
|
|
519
|
+
trigger: WriteTrigger,
|
|
520
|
+
) u32 {
|
|
521
|
+
assert(client_replies.writing.count() + client_replies.write_queue.count ==
|
|
522
|
+
client_replies.writes.executing());
|
|
523
|
+
|
|
524
|
+
var writes = client_replies.writes.iterate_const();
|
|
525
|
+
var writes_by_trigger: u32 = 0;
|
|
526
|
+
while (writes.next()) |write| {
|
|
527
|
+
writes_by_trigger += @intFromBool(write.trigger == trigger);
|
|
528
|
+
}
|
|
529
|
+
return writes_by_trigger;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
}
|