tigerbeetle-node 0.11.8 → 0.11.9
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.
- package/dist/.client.node.sha256 +1 -1
- package/package.json +4 -3
- package/scripts/build_lib.sh +29 -0
- package/src/node.zig +1 -1
- package/src/tigerbeetle/scripts/validate_docs.sh +7 -1
- package/src/tigerbeetle/src/benchmark.zig +3 -3
- package/src/tigerbeetle/src/config.zig +29 -16
- package/src/tigerbeetle/src/constants.zig +30 -9
- package/src/tigerbeetle/src/ewah.zig +5 -5
- package/src/tigerbeetle/src/ewah_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/binary_search.zig +1 -1
- package/src/tigerbeetle/src/lsm/bloom_filter.zig +1 -1
- package/src/tigerbeetle/src/lsm/compaction.zig +34 -21
- package/src/tigerbeetle/src/lsm/forest_fuzz.zig +85 -103
- package/src/tigerbeetle/src/lsm/grid.zig +19 -13
- package/src/tigerbeetle/src/lsm/manifest_log.zig +8 -10
- package/src/tigerbeetle/src/lsm/manifest_log_fuzz.zig +12 -8
- package/src/tigerbeetle/src/lsm/merge_iterator.zig +1 -1
- package/src/tigerbeetle/src/lsm/segmented_array.zig +17 -17
- package/src/tigerbeetle/src/lsm/segmented_array_fuzz.zig +1 -1
- package/src/tigerbeetle/src/lsm/set_associative_cache.zig +1 -1
- package/src/tigerbeetle/src/lsm/table.zig +8 -20
- package/src/tigerbeetle/src/lsm/table_immutable.zig +1 -1
- package/src/tigerbeetle/src/lsm/table_iterator.zig +3 -3
- package/src/tigerbeetle/src/lsm/table_mutable.zig +14 -2
- package/src/tigerbeetle/src/lsm/tree.zig +31 -5
- package/src/tigerbeetle/src/lsm/tree_fuzz.zig +86 -114
- package/src/tigerbeetle/src/message_bus.zig +4 -4
- package/src/tigerbeetle/src/message_pool.zig +7 -10
- package/src/tigerbeetle/src/ring_buffer.zig +22 -12
- package/src/tigerbeetle/src/simulator.zig +360 -214
- package/src/tigerbeetle/src/state_machine/auditor.zig +5 -5
- package/src/tigerbeetle/src/state_machine/workload.zig +3 -3
- package/src/tigerbeetle/src/state_machine.zig +190 -178
- package/src/tigerbeetle/src/{util.zig → stdx.zig} +2 -0
- package/src/tigerbeetle/src/storage.zig +13 -6
- package/src/tigerbeetle/src/{test → testing/cluster}/message_bus.zig +3 -3
- package/src/tigerbeetle/src/{test → testing/cluster}/network.zig +46 -22
- package/src/tigerbeetle/src/testing/cluster/state_checker.zig +169 -0
- package/src/tigerbeetle/src/testing/cluster/storage_checker.zig +202 -0
- package/src/tigerbeetle/src/testing/cluster.zig +537 -0
- package/src/tigerbeetle/src/{test → testing}/fuzz.zig +0 -0
- package/src/tigerbeetle/src/testing/hash_log.zig +66 -0
- package/src/tigerbeetle/src/{test → testing}/id.zig +0 -0
- package/src/tigerbeetle/src/testing/packet_simulator.zig +365 -0
- package/src/tigerbeetle/src/{test → testing}/priority_queue.zig +1 -1
- package/src/tigerbeetle/src/testing/reply_sequence.zig +139 -0
- package/src/tigerbeetle/src/{test → testing}/state_machine.zig +3 -1
- package/src/tigerbeetle/src/testing/storage.zig +754 -0
- package/src/tigerbeetle/src/{test → testing}/table.zig +21 -0
- package/src/tigerbeetle/src/{test → testing}/time.zig +0 -0
- package/src/tigerbeetle/src/tigerbeetle.zig +2 -0
- package/src/tigerbeetle/src/tracer.zig +3 -3
- package/src/tigerbeetle/src/unit_tests.zig +4 -4
- package/src/tigerbeetle/src/vopr.zig +2 -2
- package/src/tigerbeetle/src/vsr/client.zig +5 -2
- package/src/tigerbeetle/src/vsr/clock.zig +93 -53
- package/src/tigerbeetle/src/vsr/journal.zig +29 -14
- package/src/tigerbeetle/src/vsr/journal_format_fuzz.zig +2 -2
- package/src/tigerbeetle/src/vsr/replica.zig +1383 -774
- package/src/tigerbeetle/src/vsr/replica_format.zig +2 -2
- package/src/tigerbeetle/src/vsr/superblock.zig +59 -43
- package/src/tigerbeetle/src/vsr/superblock_client_table.zig +7 -7
- package/src/tigerbeetle/src/vsr/superblock_free_set.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_free_set_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr/superblock_fuzz.zig +15 -7
- package/src/tigerbeetle/src/vsr/superblock_manifest.zig +38 -19
- package/src/tigerbeetle/src/vsr/superblock_quorums_fuzz.zig +1 -1
- package/src/tigerbeetle/src/vsr.zig +6 -4
- package/src/tigerbeetle/src/demo.zig +0 -132
- package/src/tigerbeetle/src/demo_01_create_accounts.zig +0 -35
- package/src/tigerbeetle/src/demo_02_lookup_accounts.zig +0 -7
- package/src/tigerbeetle/src/demo_03_create_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_04_create_pending_transfers.zig +0 -61
- package/src/tigerbeetle/src/demo_05_post_pending_transfers.zig +0 -37
- package/src/tigerbeetle/src/demo_06_void_pending_transfers.zig +0 -24
- package/src/tigerbeetle/src/demo_07_lookup_transfers.zig +0 -7
- package/src/tigerbeetle/src/test/cluster.zig +0 -352
- package/src/tigerbeetle/src/test/conductor.zig +0 -366
- package/src/tigerbeetle/src/test/packet_simulator.zig +0 -398
- package/src/tigerbeetle/src/test/state_checker.zig +0 -169
- package/src/tigerbeetle/src/test/storage.zig +0 -864
- package/src/tigerbeetle/src/test/storage_checker.zig +0 -204
|
@@ -1,366 +0,0 @@
|
|
|
1
|
-
//! The Conductor coordinates a set of Clients, scheduling requests (generated by the Workload),
|
|
2
|
-
//! and receiving replies (validated by the Workload).
|
|
3
|
-
//!
|
|
4
|
-
//! Replies from the cluster may arrive out-of-order; the Conductor reassembles them in the
|
|
5
|
-
//! correct order (by ascending op number) before passing them into the Workload.
|
|
6
|
-
const std = @import("std");
|
|
7
|
-
const assert = std.debug.assert;
|
|
8
|
-
const log = std.log.scoped(.test_conductor);
|
|
9
|
-
|
|
10
|
-
const vsr = @import("../vsr.zig");
|
|
11
|
-
const util = @import("../util.zig");
|
|
12
|
-
const constants = @import("../constants.zig");
|
|
13
|
-
const IdPermutation = @import("id.zig").IdPermutation;
|
|
14
|
-
const MessagePool = @import("../message_pool.zig").MessagePool;
|
|
15
|
-
const Message = MessagePool.Message;
|
|
16
|
-
|
|
17
|
-
// TODO(zig) This won't be necessary in Zig 0.10.
|
|
18
|
-
const PriorityQueue = @import("./priority_queue.zig").PriorityQueue;
|
|
19
|
-
|
|
20
|
-
/// Both messages belong to the Conductor's `MessagePool`.
|
|
21
|
-
const PendingReply = struct {
|
|
22
|
-
client_index: usize,
|
|
23
|
-
request: *Message,
|
|
24
|
-
reply: *Message,
|
|
25
|
-
|
|
26
|
-
/// `PendingReply`s are ordered by ascending reply op.
|
|
27
|
-
fn compare(context: void, a: PendingReply, b: PendingReply) std.math.Order {
|
|
28
|
-
_ = context;
|
|
29
|
-
return std.math.order(a.reply.header.op, b.reply.header.op);
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const PendingReplyQueue = PriorityQueue(PendingReply, void, PendingReply.compare);
|
|
34
|
-
|
|
35
|
-
pub fn ConductorType(
|
|
36
|
-
comptime Client: type,
|
|
37
|
-
comptime MessageBus: type,
|
|
38
|
-
comptime StateMachine: type,
|
|
39
|
-
) type {
|
|
40
|
-
return struct {
|
|
41
|
-
const Self = @This();
|
|
42
|
-
|
|
43
|
-
/// Reply messages (from cluster to client) may be reordered during transit.
|
|
44
|
-
/// The Conductor must reassemble them in the original order (ascending op/commit
|
|
45
|
-
/// number) before handing them off to the Workload for verification.
|
|
46
|
-
///
|
|
47
|
-
/// `Conduction.stalled_queue` hold replies (and corresponding requests) that are
|
|
48
|
-
/// waiting to be processed.
|
|
49
|
-
pub const stalled_queue_capacity =
|
|
50
|
-
constants.clients_max * constants.client_request_queue_max * 2;
|
|
51
|
-
|
|
52
|
-
random: std.rand.Random,
|
|
53
|
-
workload: *StateMachine.Workload,
|
|
54
|
-
options: Options,
|
|
55
|
-
client_id_permutation: IdPermutation,
|
|
56
|
-
|
|
57
|
-
clients: []Client,
|
|
58
|
-
client_pools: []MessagePool,
|
|
59
|
-
message_pool: MessagePool,
|
|
60
|
-
|
|
61
|
-
/// The next op to be verified.
|
|
62
|
-
/// Starts at 1, because op=0 is the root.
|
|
63
|
-
stalled_op: u64 = 1,
|
|
64
|
-
|
|
65
|
-
/// The list of messages waiting to be verified (the reply for a lower op has not yet arrived).
|
|
66
|
-
/// Includes `register` messages.
|
|
67
|
-
stalled_queue: PendingReplyQueue,
|
|
68
|
-
|
|
69
|
-
/// Total number of messages sent, including those that have not been delivered.
|
|
70
|
-
/// Does not include `register` messages.
|
|
71
|
-
requests_sent: usize = 0,
|
|
72
|
-
|
|
73
|
-
idle: bool = false,
|
|
74
|
-
|
|
75
|
-
const Options = struct {
|
|
76
|
-
cluster: u32,
|
|
77
|
-
replica_count: u8,
|
|
78
|
-
client_count: u8,
|
|
79
|
-
message_bus_options: MessageBus.Options,
|
|
80
|
-
|
|
81
|
-
/// The total number of requests to send. Does not count `register` messages.
|
|
82
|
-
requests_max: usize,
|
|
83
|
-
|
|
84
|
-
request_probability: u8, // percent
|
|
85
|
-
idle_on_probability: u8, // percent
|
|
86
|
-
idle_off_probability: u8, // percent
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
pub fn init(
|
|
90
|
-
allocator: std.mem.Allocator,
|
|
91
|
-
random: std.rand.Random,
|
|
92
|
-
workload: *StateMachine.Workload,
|
|
93
|
-
options: Options,
|
|
94
|
-
) !Self {
|
|
95
|
-
assert(options.replica_count >= 1);
|
|
96
|
-
assert(options.replica_count <= 6);
|
|
97
|
-
assert(options.client_count > 0);
|
|
98
|
-
assert(options.client_count * 2 < stalled_queue_capacity);
|
|
99
|
-
assert(options.requests_max > 0);
|
|
100
|
-
|
|
101
|
-
assert(options.request_probability > 0);
|
|
102
|
-
assert(options.request_probability <= 100);
|
|
103
|
-
assert(options.idle_on_probability <= 100);
|
|
104
|
-
assert(options.idle_off_probability > 0);
|
|
105
|
-
assert(options.idle_off_probability <= 100);
|
|
106
|
-
|
|
107
|
-
// *2 for PendingReply.request and PendingReply.reply.
|
|
108
|
-
var message_pool = try MessagePool.init_capacity(allocator, stalled_queue_capacity * 2);
|
|
109
|
-
errdefer message_pool.deinit(allocator);
|
|
110
|
-
|
|
111
|
-
var client_pools = try allocator.alloc(MessagePool, options.client_count);
|
|
112
|
-
errdefer allocator.free(client_pools);
|
|
113
|
-
|
|
114
|
-
for (client_pools) |*pool, i| {
|
|
115
|
-
errdefer for (client_pools[0..i]) |*p| p.deinit(allocator);
|
|
116
|
-
pool.* = try MessagePool.init(allocator, .client);
|
|
117
|
-
}
|
|
118
|
-
errdefer for (client_pools) |*p| p.deinit(allocator);
|
|
119
|
-
|
|
120
|
-
var clients = try allocator.alloc(Client, options.client_count);
|
|
121
|
-
errdefer allocator.free(clients);
|
|
122
|
-
|
|
123
|
-
// Always use UUIDs because the simulator network expects client ids to never collide
|
|
124
|
-
// with replica indices.
|
|
125
|
-
const client_id_permutation = IdPermutation{ .random = random.int(u64) };
|
|
126
|
-
|
|
127
|
-
for (clients) |*client, i| {
|
|
128
|
-
errdefer for (clients[0..i]) |*c| c.deinit(allocator);
|
|
129
|
-
client.* = try Client.init(
|
|
130
|
-
allocator,
|
|
131
|
-
// +1 so that index=0 is encoded as a valid id.
|
|
132
|
-
client_id_permutation.encode(i + 1),
|
|
133
|
-
options.cluster,
|
|
134
|
-
options.replica_count,
|
|
135
|
-
&client_pools[i],
|
|
136
|
-
options.message_bus_options,
|
|
137
|
-
);
|
|
138
|
-
client.on_reply_callback = on_reply;
|
|
139
|
-
}
|
|
140
|
-
errdefer for (clients) |*c| c.deinit(allocator);
|
|
141
|
-
|
|
142
|
-
var stalled_queue = PendingReplyQueue.init(allocator, {});
|
|
143
|
-
errdefer stalled_queue.deinit();
|
|
144
|
-
try stalled_queue.ensureTotalCapacity(stalled_queue_capacity);
|
|
145
|
-
|
|
146
|
-
return Self{
|
|
147
|
-
.random = random,
|
|
148
|
-
.workload = workload,
|
|
149
|
-
.options = options,
|
|
150
|
-
.client_id_permutation = client_id_permutation,
|
|
151
|
-
.clients = clients,
|
|
152
|
-
.client_pools = client_pools,
|
|
153
|
-
.message_pool = message_pool,
|
|
154
|
-
.stalled_queue = stalled_queue,
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
|
|
159
|
-
while (self.stalled_queue.removeOrNull()) |pending| {
|
|
160
|
-
self.message_pool.unref(pending.request);
|
|
161
|
-
self.message_pool.unref(pending.reply);
|
|
162
|
-
}
|
|
163
|
-
self.stalled_queue.deinit();
|
|
164
|
-
self.message_pool.deinit(allocator);
|
|
165
|
-
|
|
166
|
-
for (self.clients) |*client| client.deinit(allocator);
|
|
167
|
-
allocator.free(self.clients);
|
|
168
|
-
|
|
169
|
-
for (self.client_pools) |*pool| pool.deinit(allocator);
|
|
170
|
-
allocator.free(self.client_pools);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/// The conductor is "done" when it has delivered `requests_max` requests and received all
|
|
174
|
-
/// replies.
|
|
175
|
-
pub fn done(self: *const Self) bool {
|
|
176
|
-
assert(self.requests_sent <= self.options.requests_max);
|
|
177
|
-
if (self.requests_sent < self.options.requests_max) return false;
|
|
178
|
-
|
|
179
|
-
for (self.clients) |*client| {
|
|
180
|
-
if (client.request_queue.count > 0) return false;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
assert(self.workload.done());
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
pub fn tick(self: *Self) void {
|
|
188
|
-
for (self.clients) |*client| {
|
|
189
|
-
// TODO(zig) Move this into init when `@returnAddress()` is available. It only needs to
|
|
190
|
-
// be set once, it just requires a stable pointer to the Conductor.
|
|
191
|
-
client.on_reply_context = self;
|
|
192
|
-
client.tick();
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (self.done()) return;
|
|
196
|
-
|
|
197
|
-
// Try to pick a client & queue a request.
|
|
198
|
-
|
|
199
|
-
if (self.idle) {
|
|
200
|
-
if (chance(self.random, self.options.idle_off_probability)) self.idle = false;
|
|
201
|
-
} else {
|
|
202
|
-
if (chance(self.random, self.options.idle_on_probability)) self.idle = true;
|
|
203
|
-
}
|
|
204
|
-
if (self.idle) return;
|
|
205
|
-
if (!chance(self.random, self.options.request_probability)) return;
|
|
206
|
-
|
|
207
|
-
if (self.requests_sent == self.options.requests_max) return;
|
|
208
|
-
assert(self.requests_sent < self.options.requests_max);
|
|
209
|
-
|
|
210
|
-
// Messages aren't added to `stalled_queue` until a reply arrives.
|
|
211
|
-
// Before sending a new message, make sure there will definitely be room for it.
|
|
212
|
-
var reserved: usize = 0;
|
|
213
|
-
for (self.clients) |*c| {
|
|
214
|
-
// Count the number of clients that are still waiting for a `register` to complete,
|
|
215
|
-
// since they may start one at any time.
|
|
216
|
-
reserved += @boolToInt(c.session == 0);
|
|
217
|
-
// Count the number of requests queued.
|
|
218
|
-
reserved += c.request_queue.count;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// +1 for the potential request — is there room in our queue?
|
|
222
|
-
if (self.stalled_queue.len + reserved + 1 > stalled_queue_capacity) return;
|
|
223
|
-
|
|
224
|
-
const client_index = self.random.uintLessThanBiased(usize, self.clients.len);
|
|
225
|
-
var client = &self.clients[client_index];
|
|
226
|
-
|
|
227
|
-
// Check for space in the client's own request queue.
|
|
228
|
-
if (client.request_queue.count + 1 > constants.client_request_queue_max) return;
|
|
229
|
-
|
|
230
|
-
var request_message = client.get_message();
|
|
231
|
-
defer client.unref(request_message);
|
|
232
|
-
|
|
233
|
-
const request_metadata = self.workload.build_request(
|
|
234
|
-
client_index,
|
|
235
|
-
@alignCast(
|
|
236
|
-
@alignOf(vsr.Header),
|
|
237
|
-
request_message.buffer[@sizeOf(vsr.Header)..constants.message_size_max],
|
|
238
|
-
),
|
|
239
|
-
);
|
|
240
|
-
assert(request_metadata.size <= constants.message_size_max - @sizeOf(vsr.Header));
|
|
241
|
-
|
|
242
|
-
client.request(
|
|
243
|
-
0,
|
|
244
|
-
request_callback,
|
|
245
|
-
request_metadata.operation,
|
|
246
|
-
request_message,
|
|
247
|
-
request_metadata.size,
|
|
248
|
-
);
|
|
249
|
-
// Since we already checked the client's request queue for free space, `client.request()`
|
|
250
|
-
// should always queue the request.
|
|
251
|
-
assert(request_message == client.request_queue.tail_ptr().?.message);
|
|
252
|
-
assert(request_message.header.client == client.id);
|
|
253
|
-
assert(request_message.header.request == client.request_number - 1);
|
|
254
|
-
assert(request_message.header.size == @sizeOf(vsr.Header) + request_metadata.size);
|
|
255
|
-
assert(request_message.header.operation.cast(StateMachine) == request_metadata.operation);
|
|
256
|
-
|
|
257
|
-
self.requests_sent += 1;
|
|
258
|
-
assert(self.requests_sent <= self.options.requests_max);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
/// The `request_callback` is not used. The Conductor needs access to the request/reply
|
|
262
|
-
/// Messages to process them in the proper (op) order.
|
|
263
|
-
///
|
|
264
|
-
/// See `on_reply`.
|
|
265
|
-
fn request_callback(
|
|
266
|
-
user_data: u128,
|
|
267
|
-
operation: StateMachine.Operation,
|
|
268
|
-
result: Client.Error![]const u8,
|
|
269
|
-
) void {
|
|
270
|
-
_ = user_data;
|
|
271
|
-
_ = operation;
|
|
272
|
-
_ = result catch |err| switch (err) {
|
|
273
|
-
error.TooManyOutstandingRequests => unreachable,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
fn on_reply(
|
|
278
|
-
context: ?*anyopaque,
|
|
279
|
-
client: *Client,
|
|
280
|
-
request_message: *Message,
|
|
281
|
-
reply_message: *Message,
|
|
282
|
-
) void {
|
|
283
|
-
const self = @ptrCast(*Self, @alignCast(@alignOf(*Self), context.?));
|
|
284
|
-
assert(reply_message.header.cluster == self.options.cluster);
|
|
285
|
-
assert(reply_message.header.invalid() == null);
|
|
286
|
-
assert(reply_message.header.client == client.id);
|
|
287
|
-
assert(reply_message.header.request == request_message.header.request);
|
|
288
|
-
assert(reply_message.header.op >= self.stalled_op);
|
|
289
|
-
assert(reply_message.header.command == .reply);
|
|
290
|
-
assert(reply_message.header.operation == request_message.header.operation);
|
|
291
|
-
|
|
292
|
-
const client_id = reply_message.header.client;
|
|
293
|
-
// -1 because id=0 is not valid, so index=0→id=1.
|
|
294
|
-
const client_index = @intCast(usize, self.client_id_permutation.decode(client_id) - 1);
|
|
295
|
-
self.stalled_queue.add(.{
|
|
296
|
-
.client_index = client_index,
|
|
297
|
-
.request = self.clone_message(request_message),
|
|
298
|
-
.reply = self.clone_message(reply_message),
|
|
299
|
-
}) catch unreachable;
|
|
300
|
-
|
|
301
|
-
if (reply_message.header.op == self.stalled_op) {
|
|
302
|
-
self.consume_stalled_replies();
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/// Copy the message from a Client's MessagePool to the Conductor's MessagePool.
|
|
307
|
-
///
|
|
308
|
-
/// The client has a finite amount of messages in its pool, and the Conductor needs to hold
|
|
309
|
-
/// onto requests/replies until all preceeding requests/replies have arrived.
|
|
310
|
-
///
|
|
311
|
-
/// Returns the Conductor's message.
|
|
312
|
-
fn clone_message(self: *Self, message_client: *const Message) *Message {
|
|
313
|
-
const message_conductor = self.message_pool.get_message();
|
|
314
|
-
util.copy_disjoint(.exact, u8, message_conductor.buffer, message_client.buffer);
|
|
315
|
-
return message_conductor;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
fn consume_stalled_replies(self: *Self) void {
|
|
319
|
-
assert(self.stalled_queue.len > 0);
|
|
320
|
-
assert(self.stalled_queue.len <= stalled_queue_capacity);
|
|
321
|
-
while (self.stalled_queue.peek()) |head| {
|
|
322
|
-
assert(head.reply.header.op >= self.stalled_op);
|
|
323
|
-
if (head.reply.header.op != self.stalled_op) break;
|
|
324
|
-
|
|
325
|
-
const commit = self.stalled_queue.remove();
|
|
326
|
-
defer self.message_pool.unref(commit.reply);
|
|
327
|
-
defer self.message_pool.unref(commit.request);
|
|
328
|
-
|
|
329
|
-
assert(commit.reply.references == 1);
|
|
330
|
-
assert(commit.reply.header.command == .reply);
|
|
331
|
-
assert(commit.reply.header.client == self.clients[commit.client_index].id);
|
|
332
|
-
assert(commit.reply.header.request == commit.request.header.request);
|
|
333
|
-
assert(commit.reply.header.op == self.stalled_op);
|
|
334
|
-
assert(commit.reply.header.operation == commit.request.header.operation);
|
|
335
|
-
|
|
336
|
-
assert(commit.request.references == 1);
|
|
337
|
-
assert(commit.request.header.command == .request);
|
|
338
|
-
assert(commit.request.header.client == self.clients[commit.client_index].id);
|
|
339
|
-
|
|
340
|
-
log.debug("consume_stalled_replies: op={} operation={} client={} request={}", .{
|
|
341
|
-
commit.reply.header.op,
|
|
342
|
-
commit.reply.header.operation,
|
|
343
|
-
commit.request.header.client,
|
|
344
|
-
commit.request.header.request,
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
if (commit.request.header.operation != .register) {
|
|
348
|
-
self.workload.on_reply(
|
|
349
|
-
commit.client_index,
|
|
350
|
-
commit.reply.header.operation,
|
|
351
|
-
commit.reply.header.timestamp,
|
|
352
|
-
commit.request.body(),
|
|
353
|
-
commit.reply.body(),
|
|
354
|
-
);
|
|
355
|
-
}
|
|
356
|
-
self.stalled_op += 1;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/// Returns true, `p` percent of the time, else false.
|
|
363
|
-
fn chance(random: std.rand.Random, p: u8) bool {
|
|
364
|
-
assert(p <= 100);
|
|
365
|
-
return random.uintLessThanBiased(u8, 100) < p;
|
|
366
|
-
}
|