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,462 @@
|
|
|
1
|
+
const std = @import("std");
|
|
2
|
+
const stdx = @import("stdx");
|
|
3
|
+
const assert = std.debug.assert;
|
|
4
|
+
|
|
5
|
+
const constants = @import("../constants.zig");
|
|
6
|
+
|
|
7
|
+
const ProcessID = @import("../trace.zig").ProcessID;
|
|
8
|
+
const IO = @import("../io.zig").IO;
|
|
9
|
+
|
|
10
|
+
const EventMetric = @import("event.zig").EventMetric;
|
|
11
|
+
const EventMetricAggregate = @import("event.zig").EventMetricAggregate;
|
|
12
|
+
const EventTiming = @import("event.zig").EventTiming;
|
|
13
|
+
const EventTimingAggregate = @import("event.zig").EventTimingAggregate;
|
|
14
|
+
|
|
15
|
+
const log = std.log.scoped(.statsd);
|
|
16
|
+
|
|
17
|
+
/// A reasonable value to keep the total length of the packet under a single MTU, for a local
|
|
18
|
+
/// network.
|
|
19
|
+
///
|
|
20
|
+
/// https://github.com/statsd/statsd/blob/master/docs/metric_types.md#multi-metric-packets
|
|
21
|
+
const packet_size_max = 1400;
|
|
22
|
+
|
|
23
|
+
/// No single metric may be larger than this value. If it is, it'll be dropped with an error
|
|
24
|
+
/// message. Since this is calculated at comptime, that means there's a bug in the calculation
|
|
25
|
+
/// logic.
|
|
26
|
+
const statsd_line_size_max = line_size_max: {
|
|
27
|
+
// For each type of event, build a payload containing the maximum possible values for that
|
|
28
|
+
// event. This is essentially maxInt for unsigned integer payloads, minInt for signed integer
|
|
29
|
+
// payloads, and the longest enum tag name for enum payloads.
|
|
30
|
+
var events_metric: [std.meta.fieldNames(EventMetric).len]EventMetricAggregate = undefined;
|
|
31
|
+
for (&events_metric, std.meta.fields(EventMetric)) |*event_metric, EventMetricInner| {
|
|
32
|
+
event_metric.* = .{
|
|
33
|
+
.event = @unionInit(
|
|
34
|
+
EventMetric,
|
|
35
|
+
EventMetricInner.name,
|
|
36
|
+
struct_size_max(EventMetricInner.type),
|
|
37
|
+
),
|
|
38
|
+
.value = if (@typeInfo(EventMetricAggregate.ValueType).int.signedness == .signed)
|
|
39
|
+
std.math.minInt(EventMetricAggregate.ValueType)
|
|
40
|
+
else
|
|
41
|
+
std.math.maxInt(EventMetricAggregate.ValueType),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var events_timing: [std.meta.fieldNames(EventTiming).len]EventTimingAggregate = undefined;
|
|
46
|
+
for (&events_timing, std.meta.fields(EventTiming)) |*event_timing, EventTimingInner| {
|
|
47
|
+
event_timing.* = .{
|
|
48
|
+
.event = @unionInit(
|
|
49
|
+
EventTiming,
|
|
50
|
+
EventTimingInner.name,
|
|
51
|
+
struct_size_max(EventTimingInner.type),
|
|
52
|
+
),
|
|
53
|
+
.values = .{
|
|
54
|
+
.duration_min = .{ .ns = std.math.maxInt(u64) },
|
|
55
|
+
.duration_max = .{ .ns = std.math.maxInt(u64) },
|
|
56
|
+
.duration_sum = .{ .ns = std.math.maxInt(u64) },
|
|
57
|
+
.count = std.math.maxInt(u64),
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var buffer: [packet_size_max]u8 = undefined;
|
|
63
|
+
var buffer_stream = std.io.fixedBufferStream(&buffer);
|
|
64
|
+
const buffer_writer = buffer_stream.writer();
|
|
65
|
+
|
|
66
|
+
var line_size_max: u32 = 0;
|
|
67
|
+
for (events_metric) |event| {
|
|
68
|
+
buffer_stream.reset();
|
|
69
|
+
format_metric(
|
|
70
|
+
buffer_writer,
|
|
71
|
+
.{ .metric = .{ .aggregate = event } },
|
|
72
|
+
.{ .cluster = std.math.maxInt(u128), .replica = constants.members_max - 1 },
|
|
73
|
+
) catch unreachable;
|
|
74
|
+
line_size_max = @max(line_size_max, buffer_stream.getPos() catch unreachable);
|
|
75
|
+
}
|
|
76
|
+
for (events_timing) |event| {
|
|
77
|
+
for (std.enums.values(TimingStat)) |stat| {
|
|
78
|
+
buffer_stream.reset();
|
|
79
|
+
format_metric(
|
|
80
|
+
buffer_writer,
|
|
81
|
+
.{ .timing = .{ .aggregate = event, .stat = stat } },
|
|
82
|
+
.{ .cluster = std.math.maxInt(u128), .replica = constants.members_max - 1 },
|
|
83
|
+
) catch unreachable;
|
|
84
|
+
line_size_max = @max(line_size_max, buffer_stream.getPos() catch unreachable);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
break :line_size_max line_size_max;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const packet_messages_max = @divFloor(packet_size_max, statsd_line_size_max);
|
|
91
|
+
|
|
92
|
+
comptime {
|
|
93
|
+
assert(statsd_line_size_max <= packet_size_max);
|
|
94
|
+
assert(packet_messages_max > 0);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// This implementation emits on an open-loop: on the emit interval, it fires off up to
|
|
98
|
+
/// packet_count_max UDP packets, without waiting for completions.
|
|
99
|
+
///
|
|
100
|
+
/// The emit interval needs to be large enough that the kernel will have finished processing them
|
|
101
|
+
/// before emitting again. If not, an error will be logged.
|
|
102
|
+
const packet_count_max = stdx.div_ceil(
|
|
103
|
+
EventMetric.slot_count + (EventTiming.slot_count * std.enums.values(TimingStat).len),
|
|
104
|
+
packet_messages_max,
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
comptime {
|
|
108
|
+
// Sanity-check:
|
|
109
|
+
assert(packet_count_max > 0);
|
|
110
|
+
assert(packet_count_max < 512);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
pub const StatsD = struct {
|
|
114
|
+
process_id: ProcessID,
|
|
115
|
+
implementation: union(enum) {
|
|
116
|
+
udp: struct {
|
|
117
|
+
socket: std.posix.socket_t,
|
|
118
|
+
io: *IO,
|
|
119
|
+
send_callback_error_count: u64 = 0,
|
|
120
|
+
},
|
|
121
|
+
log,
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
send_buffer: *[packet_count_max * packet_size_max]u8,
|
|
125
|
+
send_completions: [packet_count_max]IO.Completion = undefined,
|
|
126
|
+
send_in_flight_count: u32 = 0,
|
|
127
|
+
|
|
128
|
+
log_buffer: ?std.ArrayListUnmanaged(u8) = null,
|
|
129
|
+
|
|
130
|
+
/// Creates a statsd instance, which will send UDP packets via the IO instance provided.
|
|
131
|
+
pub fn init_udp(
|
|
132
|
+
allocator: std.mem.Allocator,
|
|
133
|
+
process_id: ProcessID,
|
|
134
|
+
io: *IO,
|
|
135
|
+
address: std.net.Address,
|
|
136
|
+
) !StatsD {
|
|
137
|
+
const socket = try io.open_socket_udp(address.any.family);
|
|
138
|
+
errdefer io.close_socket(socket);
|
|
139
|
+
|
|
140
|
+
const send_buffer = try allocator.create([packet_count_max * packet_size_max]u8);
|
|
141
|
+
errdefer allocator.destroy(send_buffer);
|
|
142
|
+
|
|
143
|
+
// 'Connect' the UDP socket, so we can just send() to it normally.
|
|
144
|
+
try std.posix.connect(socket, &address.any, address.getOsSockLen());
|
|
145
|
+
|
|
146
|
+
log.info("{}: sending statsd metrics to {}", .{ process_id, address });
|
|
147
|
+
|
|
148
|
+
return .{
|
|
149
|
+
.process_id = process_id,
|
|
150
|
+
.implementation = .{
|
|
151
|
+
.udp = .{
|
|
152
|
+
.socket = socket,
|
|
153
|
+
.io = io,
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
.send_buffer = send_buffer,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Creates a statsd instance, which will log out the packets that would have been sent. Useful
|
|
161
|
+
// so that all of the other code can run and be tested in the simulator.
|
|
162
|
+
pub fn init_log(
|
|
163
|
+
allocator: std.mem.Allocator,
|
|
164
|
+
process_id: ProcessID,
|
|
165
|
+
) !StatsD {
|
|
166
|
+
const send_buffer = try allocator.create([packet_count_max * packet_size_max]u8);
|
|
167
|
+
errdefer allocator.destroy(send_buffer);
|
|
168
|
+
|
|
169
|
+
const log_buffer = try std.ArrayListUnmanaged(u8).initCapacity(
|
|
170
|
+
allocator,
|
|
171
|
+
packet_count_max * packet_size_max,
|
|
172
|
+
);
|
|
173
|
+
errdefer log_buffer.deinit(allocator);
|
|
174
|
+
|
|
175
|
+
return .{
|
|
176
|
+
.process_id = process_id,
|
|
177
|
+
.implementation = .log,
|
|
178
|
+
.send_buffer = send_buffer,
|
|
179
|
+
.log_buffer = log_buffer,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
pub fn deinit(self: *StatsD, allocator: std.mem.Allocator) void {
|
|
184
|
+
if (self.implementation == .udp) {
|
|
185
|
+
self.implementation.udp.io.close_socket(self.implementation.udp.socket);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (self.log_buffer) |*log_buffer| {
|
|
189
|
+
log_buffer.deinit(allocator);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
allocator.destroy(self.send_buffer);
|
|
193
|
+
|
|
194
|
+
self.* = undefined;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
pub fn emit(
|
|
198
|
+
self: *StatsD,
|
|
199
|
+
events_metric: []const ?EventMetricAggregate,
|
|
200
|
+
events_timing: []const ?EventTimingAggregate,
|
|
201
|
+
) error{ Busy, UnknownProcess }!u32 {
|
|
202
|
+
const cluster, const replica = switch (self.process_id) {
|
|
203
|
+
.unknown => {
|
|
204
|
+
log.err("{}: process id unknown; skipping emit", .{self.process_id});
|
|
205
|
+
return error.UnknownProcess;
|
|
206
|
+
},
|
|
207
|
+
.replica => |replica| .{ replica.cluster, replica.replica },
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
// This really should not happen; it means we're emitting so many packets, on a short
|
|
211
|
+
// enough emit timeout, that the kernel hasn't been able to process them all (UDP doesn't
|
|
212
|
+
// block or provide back-pressure like a TCP socket).
|
|
213
|
+
//
|
|
214
|
+
// Keep it as a log, rather than assert, to avoid the common pitfall of metrics killing
|
|
215
|
+
// the whole system.
|
|
216
|
+
//
|
|
217
|
+
// This is also a load-bearing check: see send_callback().
|
|
218
|
+
if (self.send_in_flight_count != 0) {
|
|
219
|
+
log.err("{}: {} / {} packets still in flight; skipping emit", .{
|
|
220
|
+
self.process_id,
|
|
221
|
+
self.send_in_flight_count,
|
|
222
|
+
packet_count_max,
|
|
223
|
+
});
|
|
224
|
+
return error.Busy;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// If there's a log buffer, clear it out before starting to emit.
|
|
228
|
+
if (self.log_buffer) |*log_buffer| {
|
|
229
|
+
log_buffer.clearRetainingCapacity();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (self.implementation == .udp and self.implementation.udp.send_callback_error_count > 0) {
|
|
233
|
+
log.warn(
|
|
234
|
+
"{}: failed to send {} packets",
|
|
235
|
+
.{ self.process_id, self.implementation.udp.send_callback_error_count },
|
|
236
|
+
);
|
|
237
|
+
self.implementation.udp.send_callback_error_count = 0;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
var send_ready: u32 = 0;
|
|
241
|
+
var send_sizes = stdx.BoundedArrayType(u32, packet_count_max){};
|
|
242
|
+
var send_stream = std.io.fixedBufferStream(self.send_buffer);
|
|
243
|
+
const send_writer = send_stream.writer();
|
|
244
|
+
inline for (.{ events_metric, events_timing }) |events| {
|
|
245
|
+
for (events) |event_new_maybe| {
|
|
246
|
+
const event_new = event_new_maybe orelse continue;
|
|
247
|
+
const stats = switch (@TypeOf(event_new)) {
|
|
248
|
+
EventMetricAggregate => [_]Stat{.{ .metric = .{ .aggregate = event_new } }},
|
|
249
|
+
EventTimingAggregate => [_]Stat{
|
|
250
|
+
.{ .timing = .{ .aggregate = event_new, .stat = .min } },
|
|
251
|
+
.{ .timing = .{ .aggregate = event_new, .stat = .max } },
|
|
252
|
+
.{ .timing = .{ .aggregate = event_new, .stat = .avg } },
|
|
253
|
+
.{ .timing = .{ .aggregate = event_new, .stat = .sum } },
|
|
254
|
+
.{ .timing = .{ .aggregate = event_new, .stat = .count } },
|
|
255
|
+
},
|
|
256
|
+
else => unreachable,
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
for (stats) |stat| {
|
|
260
|
+
const send_position_before = send_stream.getPos() catch unreachable;
|
|
261
|
+
format_metric(send_writer, stat, .{
|
|
262
|
+
.cluster = cluster,
|
|
263
|
+
.replica = replica,
|
|
264
|
+
}) catch |err| switch (err) {
|
|
265
|
+
// This shouldn't ever happen, but don't allow metrics to kill the system.
|
|
266
|
+
error.NoSpaceLeft => {
|
|
267
|
+
log.err("{}: insufficient buffer space", .{self.process_id});
|
|
268
|
+
break;
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const send_position_after = send_stream.getPos() catch unreachable;
|
|
273
|
+
const send_size: u32 = @intCast(send_position_after - send_position_before);
|
|
274
|
+
assert(send_size > 0);
|
|
275
|
+
if (send_ready + send_size > packet_size_max) {
|
|
276
|
+
assert(send_ready > 0);
|
|
277
|
+
if (send_sizes.full()) {
|
|
278
|
+
log.err("{}: insufficient packet count", .{self.process_id});
|
|
279
|
+
break;
|
|
280
|
+
} else {
|
|
281
|
+
send_sizes.push(send_ready);
|
|
282
|
+
}
|
|
283
|
+
send_ready = send_size;
|
|
284
|
+
} else {
|
|
285
|
+
send_ready += send_size;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (send_ready > 0) {
|
|
291
|
+
if (send_sizes.full()) {
|
|
292
|
+
log.err("{}: insufficient packet count", .{self.process_id});
|
|
293
|
+
} else {
|
|
294
|
+
send_sizes.push(send_ready);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
var send_offset: u32 = 0;
|
|
299
|
+
for (send_sizes.const_slice()) |send_size| {
|
|
300
|
+
if (self.send_in_flight_count >= self.send_completions.len) {
|
|
301
|
+
// This shouldn't ever happen, but don't allow metrics to kill the system.
|
|
302
|
+
log.err("{}: insufficient packets to emit any metrics", .{self.process_id});
|
|
303
|
+
return 0;
|
|
304
|
+
}
|
|
305
|
+
const completion = &self.send_completions[self.send_in_flight_count];
|
|
306
|
+
self.send_in_flight_count += 1;
|
|
307
|
+
self.emit_buffer(completion, self.send_buffer[send_offset..][0..send_size]);
|
|
308
|
+
send_offset += send_size;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return @intCast(send_sizes.count());
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
fn emit_buffer(self: *StatsD, send_completion: *IO.Completion, send_buffer: []const u8) void {
|
|
315
|
+
switch (self.implementation) {
|
|
316
|
+
.udp => |udp| {
|
|
317
|
+
udp.io.send(
|
|
318
|
+
*StatsD,
|
|
319
|
+
self,
|
|
320
|
+
StatsD.send_callback,
|
|
321
|
+
send_completion,
|
|
322
|
+
udp.socket,
|
|
323
|
+
send_buffer,
|
|
324
|
+
);
|
|
325
|
+
},
|
|
326
|
+
.log => {
|
|
327
|
+
log.debug("{}: statsd packet: {s}", .{ self.process_id, send_buffer });
|
|
328
|
+
self.log_buffer.?.appendSliceAssumeCapacity(send_buffer);
|
|
329
|
+
StatsD.send_callback(self, send_completion, send_buffer.len);
|
|
330
|
+
},
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/// The UDP packets containing the metrics are sent in a fire-and-forget manner.
|
|
335
|
+
fn send_callback(self: *StatsD, completion: *IO.Completion, result: IO.SendError!usize) void {
|
|
336
|
+
_ = result catch {
|
|
337
|
+
// Errors are only supported when using UDP; not if calling this loopback.
|
|
338
|
+
assert(self.implementation == .udp);
|
|
339
|
+
self.implementation.udp.send_callback_error_count += 1;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
// Completions can be returned in any order: this is _only_ safe because their emitting is
|
|
343
|
+
// guarded on `self.send_in_flight_count != 0`.
|
|
344
|
+
self.send_in_flight_count -= 1;
|
|
345
|
+
completion.* = undefined;
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
const TimingStat = enum { min, max, avg, sum, count };
|
|
350
|
+
const Stat = union(enum) {
|
|
351
|
+
metric: struct { aggregate: EventMetricAggregate },
|
|
352
|
+
timing: struct { aggregate: EventTimingAggregate, stat: TimingStat },
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
fn format_metric(
|
|
356
|
+
writer: anytype,
|
|
357
|
+
stat: Stat,
|
|
358
|
+
options: struct { cluster: u128, replica: u8 },
|
|
359
|
+
) error{NoSpaceLeft}!void {
|
|
360
|
+
const stat_name = switch (stat) {
|
|
361
|
+
inline else => |stat_data| @tagName(stat_data.aggregate.event),
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const stat_suffix, const stat_type, const stat_value = switch (stat) {
|
|
365
|
+
.metric => |data| .{ "", "g", data.aggregate.value },
|
|
366
|
+
.timing => |data| switch (data.stat) {
|
|
367
|
+
.count => .{ "_us.count", "c", data.aggregate.values.count },
|
|
368
|
+
.sum => .{ "_us.sum", "c", data.aggregate.values.duration_sum.to_us() },
|
|
369
|
+
.min => .{ "_us.min", "g", data.aggregate.values.duration_min.to_us() },
|
|
370
|
+
.max => .{ "_us.max", "g", data.aggregate.values.duration_max.to_us() },
|
|
371
|
+
.avg => .{ "_us.avg", "g", @divFloor(
|
|
372
|
+
data.aggregate.values.duration_sum.to_us(),
|
|
373
|
+
data.aggregate.values.count,
|
|
374
|
+
) },
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
try writer.print("tb.{[name]s}{[name_suffix]s}:{[value]d}|{[statsd_type]s}" ++
|
|
379
|
+
"|#cluster:{[cluster]x:0>32},replica:{[replica]d}", .{
|
|
380
|
+
.name = stat_name,
|
|
381
|
+
.name_suffix = stat_suffix,
|
|
382
|
+
.statsd_type = stat_type,
|
|
383
|
+
.value = stat_value,
|
|
384
|
+
.cluster = options.cluster,
|
|
385
|
+
.replica = options.replica,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
switch (stat) {
|
|
389
|
+
inline else => |stat_data| {
|
|
390
|
+
switch (stat_data.aggregate.event) {
|
|
391
|
+
inline else => |data| {
|
|
392
|
+
const Tags = @TypeOf(data);
|
|
393
|
+
if (@typeInfo(Tags) == .@"struct") {
|
|
394
|
+
const fields = std.meta.fields(@TypeOf(data));
|
|
395
|
+
inline for (fields) |data_field| {
|
|
396
|
+
comptime assert(!std.mem.eql(u8, data_field.name, "cluster"));
|
|
397
|
+
comptime assert(!std.mem.eql(u8, data_field.name, "replica"));
|
|
398
|
+
comptime assert(@typeInfo(data_field.type) == .int or
|
|
399
|
+
@typeInfo(data_field.type) == .@"enum" or
|
|
400
|
+
@typeInfo(data_field.type) == .@"union");
|
|
401
|
+
|
|
402
|
+
const data_field_value = @field(data, data_field.name);
|
|
403
|
+
try writer.writeByte(',');
|
|
404
|
+
try writer.writeAll(data_field.name);
|
|
405
|
+
try writer.writeByte(':');
|
|
406
|
+
|
|
407
|
+
if (@typeInfo(data_field.type) == .@"enum" or
|
|
408
|
+
@typeInfo(data_field.type) == .@"union")
|
|
409
|
+
{
|
|
410
|
+
try writer.print("{s}", .{@tagName(data_field_value)});
|
|
411
|
+
} else {
|
|
412
|
+
try writer.print("{}", .{data_field_value});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
assert(@TypeOf(data) == void);
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
}
|
|
422
|
+
try writer.writeByte('\n');
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/// Returns an instance of a Struct (or void) with all fields set to what would result in the
|
|
426
|
+
/// longest length when formatted.
|
|
427
|
+
///
|
|
428
|
+
/// Integers get maxInt, and Enums get a value corresponding to `enum_size_max()`.
|
|
429
|
+
fn struct_size_max(StructOrVoid: type) StructOrVoid {
|
|
430
|
+
if (@typeInfo(StructOrVoid) == .void) return {};
|
|
431
|
+
|
|
432
|
+
assert(@typeInfo(StructOrVoid) == .@"struct");
|
|
433
|
+
const Struct = StructOrVoid;
|
|
434
|
+
|
|
435
|
+
var output: Struct = undefined;
|
|
436
|
+
|
|
437
|
+
for (std.meta.fields(Struct)) |field| {
|
|
438
|
+
const type_info = @typeInfo(field.type);
|
|
439
|
+
assert(type_info == .int or type_info == .@"enum");
|
|
440
|
+
assert(type_info != .int or type_info.Int.signedness == .unsigned);
|
|
441
|
+
switch (type_info) {
|
|
442
|
+
.int => @field(output, field.name) = std.math.maxInt(field.type),
|
|
443
|
+
.@"enum" => @field(output, field.name) =
|
|
444
|
+
std.enums.nameCast(field.type, enum_size_max(field.type)),
|
|
445
|
+
else => @compileError("unsupported type"),
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return output;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/// Returns the longest @tagName for a given Enum.
|
|
453
|
+
fn enum_size_max(Enum: type) []const u8 {
|
|
454
|
+
@setEvalBranchQuota(10_000);
|
|
455
|
+
var tag_longest: []const u8 = "";
|
|
456
|
+
for (std.meta.fieldNames(Enum)) |field_name| {
|
|
457
|
+
if (tag_longest.len < field_name.len) {
|
|
458
|
+
tag_longest = field_name;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return tag_longest;
|
|
462
|
+
}
|