@peerbit/native-backbone 0.1.0
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/LICENSE +202 -0
- package/README.md +27 -0
- package/dist/src/benchmark.d.ts +19 -0
- package/dist/src/benchmark.d.ts.map +1 -0
- package/dist/src/benchmark.js +12 -0
- package/dist/src/benchmark.js.map +1 -0
- package/dist/src/index.d.ts +1561 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3406 -0
- package/dist/src/index.js.map +1 -0
- package/dist/wasm/README.md +27 -0
- package/dist/wasm/native_backbone.d.ts +1609 -0
- package/dist/wasm/native_backbone.js +10221 -0
- package/dist/wasm/native_backbone_bg.wasm +0 -0
- package/dist/wasm/native_backbone_bg.wasm.d.ts +625 -0
- package/package.json +64 -0
- package/src/append_tx/committed_latest.rs +2063 -0
- package/src/append_tx/committed_no_next.rs +1165 -0
- package/src/append_tx/facts.rs +791 -0
- package/src/append_tx/mod.rs +751 -0
- package/src/append_tx/storage.rs +599 -0
- package/src/benchmark.ts +58 -0
- package/src/coordinates.rs +422 -0
- package/src/documents.rs +1698 -0
- package/src/graph_blocks.rs +362 -0
- package/src/index.ts +9134 -0
- package/src/js_interop.rs +448 -0
- package/src/lib.rs +144 -0
- package/src/profile.rs +164 -0
- package/src/raw_receive.rs +1724 -0
- package/src/shared_log_plan.rs +1464 -0
- package/src/sync_send.rs +180 -0
- package/src/wire_sync.rs +727 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
use js_sys::{Array, Uint8Array};
|
|
2
|
+
use peerbit_indexer_core::persistence::{
|
|
3
|
+
decode_journal, decode_key_value_snapshot, encode_key_value_snapshot, JournalRecord,
|
|
4
|
+
JOURNAL_MAGIC,
|
|
5
|
+
};
|
|
6
|
+
use peerbit_indexer_core::storage::ByteStorage;
|
|
7
|
+
use peerbit_indexer_core::wire::{self, WireError};
|
|
8
|
+
use peerbit_shared_log_rust::NativeLocalAppendCompactFacts;
|
|
9
|
+
use wasm_bindgen::prelude::*;
|
|
10
|
+
|
|
11
|
+
use crate::js_interop::{
|
|
12
|
+
append_journal_delete_record, append_journal_put_record, array_from_value, bool_field,
|
|
13
|
+
clear_journal_prefix, decode_error, number_strings_to_array, parse_u64_string, string_field,
|
|
14
|
+
stringish_field, strings_from_array, usize_field, wire_error_to_js, write_bytes, write_string,
|
|
15
|
+
};
|
|
16
|
+
use crate::shared_log_plan::coordinate_numbers_from_array;
|
|
17
|
+
use crate::NativePeerbitBackbone;
|
|
18
|
+
|
|
19
|
+
pub(crate) struct CoordinateCoreValue {
|
|
20
|
+
pub(crate) hash: String,
|
|
21
|
+
pub(crate) gid: String,
|
|
22
|
+
pub(crate) hash_number: u64,
|
|
23
|
+
pub(crate) coordinates: Vec<u64>,
|
|
24
|
+
pub(crate) assigned_to_range_boundary: bool,
|
|
25
|
+
pub(crate) requested_replicas: usize,
|
|
26
|
+
pub(crate) wall_time: u64,
|
|
27
|
+
pub(crate) meta_bytes: Vec<u8>,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
fn encode_coordinate_value(
|
|
31
|
+
hash: &str,
|
|
32
|
+
gid: &str,
|
|
33
|
+
hash_number: u64,
|
|
34
|
+
coordinates: &[u64],
|
|
35
|
+
assigned_to_range_boundary: bool,
|
|
36
|
+
requested_replicas: usize,
|
|
37
|
+
wall_time: u64,
|
|
38
|
+
meta_bytes: &[u8],
|
|
39
|
+
) -> Vec<u8> {
|
|
40
|
+
let mut out =
|
|
41
|
+
Vec::with_capacity(76 + hash.len() + gid.len() + coordinates.len() * 8 + meta_bytes.len());
|
|
42
|
+
write_string(&mut out, hash);
|
|
43
|
+
write_string(&mut out, gid);
|
|
44
|
+
out.extend_from_slice(&hash_number.to_le_bytes());
|
|
45
|
+
out.push(u8::from(assigned_to_range_boundary));
|
|
46
|
+
out.extend_from_slice(&(requested_replicas as u64).to_le_bytes());
|
|
47
|
+
out.extend_from_slice(&(coordinates.len() as u32).to_le_bytes());
|
|
48
|
+
for coordinate in coordinates {
|
|
49
|
+
out.extend_from_slice(&coordinate.to_le_bytes());
|
|
50
|
+
}
|
|
51
|
+
out.extend_from_slice(&wall_time.to_le_bytes());
|
|
52
|
+
write_bytes(&mut out, meta_bytes);
|
|
53
|
+
out
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pub(crate) fn coordinate_core_value_to_row(value: &CoordinateCoreValue) -> Array {
|
|
57
|
+
let row = Array::new();
|
|
58
|
+
row.push(&JsValue::from_str(&value.hash));
|
|
59
|
+
row.push(&JsValue::from_str(&value.hash_number.to_string()));
|
|
60
|
+
row.push(&JsValue::from_str(&value.gid));
|
|
61
|
+
row.push(&number_strings_to_array(&value.coordinates));
|
|
62
|
+
row.push(&JsValue::from_bool(value.assigned_to_range_boundary));
|
|
63
|
+
row.push(&JsValue::from_f64(value.requested_replicas as f64));
|
|
64
|
+
row.push(&JsValue::from_str(&value.wall_time.to_string()));
|
|
65
|
+
row.push(&Uint8Array::from(value.meta_bytes.as_slice()));
|
|
66
|
+
row
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pub(crate) fn decode_coordinate_value(bytes: &[u8]) -> Result<CoordinateCoreValue, JsValue> {
|
|
70
|
+
decode_coordinate_value_core(bytes).map_err(wire_error_to_js)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fn decode_coordinate_value_core(bytes: &[u8]) -> Result<CoordinateCoreValue, WireError> {
|
|
74
|
+
let mut offset = 0usize;
|
|
75
|
+
let hash = wire::read_encoded_string(bytes, &mut offset, "coordinate hash")?;
|
|
76
|
+
let gid = wire::read_encoded_string(bytes, &mut offset, "coordinate gid")?;
|
|
77
|
+
let hash_number = wire::read_u64(bytes, &mut offset, "coordinate hash number")?;
|
|
78
|
+
let assigned_to_range_boundary =
|
|
79
|
+
wire::read_bool(bytes, &mut offset, "assigned to range boundary")?;
|
|
80
|
+
let requested_replicas = wire::read_u64(bytes, &mut offset, "requested replicas")? as usize;
|
|
81
|
+
let coordinate_count = wire::read_u32(bytes, &mut offset, "coordinate count")? as usize;
|
|
82
|
+
if (coordinate_count as u64).saturating_mul(8) > bytes.len().saturating_sub(offset) as u64 {
|
|
83
|
+
return Err(WireError::Truncated("coordinate values"));
|
|
84
|
+
}
|
|
85
|
+
let mut coordinates = Vec::with_capacity(coordinate_count);
|
|
86
|
+
for _ in 0..coordinate_count {
|
|
87
|
+
coordinates.push(wire::read_u64(bytes, &mut offset, "coordinate value")?);
|
|
88
|
+
}
|
|
89
|
+
let (wall_time, meta_bytes) = if offset == bytes.len() {
|
|
90
|
+
(0, Vec::new())
|
|
91
|
+
} else {
|
|
92
|
+
let wall_time = wire::read_u64(bytes, &mut offset, "coordinate wall time")?;
|
|
93
|
+
let meta_bytes = wire::read_bytes(bytes, &mut offset, "coordinate meta bytes")?;
|
|
94
|
+
(wall_time, meta_bytes)
|
|
95
|
+
};
|
|
96
|
+
if offset != bytes.len() {
|
|
97
|
+
return Err(WireError::Trailing("coordinate value"));
|
|
98
|
+
}
|
|
99
|
+
Ok(CoordinateCoreValue {
|
|
100
|
+
hash,
|
|
101
|
+
gid,
|
|
102
|
+
hash_number,
|
|
103
|
+
coordinates,
|
|
104
|
+
assigned_to_range_boundary,
|
|
105
|
+
requested_replicas,
|
|
106
|
+
wall_time,
|
|
107
|
+
meta_bytes,
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#[wasm_bindgen]
|
|
112
|
+
impl NativePeerbitBackbone {
|
|
113
|
+
pub fn coordinate_index_len(&self) -> usize {
|
|
114
|
+
self.coordinate_index.len()
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
pub fn coordinate_value_len(&self) -> usize {
|
|
118
|
+
self.coordinate_values.len()
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
pub fn coordinate_index_has_hash(&self, hash: &str) -> bool {
|
|
122
|
+
self.coordinate_index.contains(hash)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
pub fn coordinate_journal_header(&self) -> Vec<u8> {
|
|
126
|
+
JOURNAL_MAGIC.to_vec()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
pub fn coordinate_pending_journal_len(&self) -> usize {
|
|
130
|
+
self.coordinate_journal_record_count
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
pub fn coordinate_pending_journal_byte_len(&self) -> usize {
|
|
134
|
+
self.coordinate_journal.len()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
pub fn coordinate_journal_enabled(&self) -> bool {
|
|
138
|
+
self.coordinate_journal_enabled
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
pub fn set_coordinate_journal_enabled(&mut self, enabled: bool) {
|
|
142
|
+
self.coordinate_journal_enabled = enabled;
|
|
143
|
+
if !enabled {
|
|
144
|
+
self.coordinate_journal.clear();
|
|
145
|
+
self.coordinate_journal_record_count = 0;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
pub fn coordinate_journal(&self) -> Vec<u8> {
|
|
150
|
+
self.coordinate_journal.clone()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
pub fn clear_coordinate_journal(&mut self) {
|
|
154
|
+
self.coordinate_journal.clear();
|
|
155
|
+
self.coordinate_journal_record_count = 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
pub fn clear_coordinate_journal_prefix(&mut self, byte_len: usize, record_count: usize) {
|
|
159
|
+
clear_journal_prefix(
|
|
160
|
+
&mut self.coordinate_journal,
|
|
161
|
+
&mut self.coordinate_journal_record_count,
|
|
162
|
+
byte_len,
|
|
163
|
+
record_count,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pub fn coordinate_snapshot(&self) -> Vec<u8> {
|
|
168
|
+
encode_key_value_snapshot(
|
|
169
|
+
self.coordinate_values
|
|
170
|
+
.entries()
|
|
171
|
+
.into_iter()
|
|
172
|
+
.map(|(key, value)| (key, value)),
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
pub fn load_coordinate_snapshot_and_journal(
|
|
177
|
+
&mut self,
|
|
178
|
+
snapshot: Uint8Array,
|
|
179
|
+
journal: Uint8Array,
|
|
180
|
+
) -> Result<usize, JsValue> {
|
|
181
|
+
let mut entries = if snapshot.length() == 0 {
|
|
182
|
+
Default::default()
|
|
183
|
+
} else {
|
|
184
|
+
decode_key_value_snapshot(&snapshot.to_vec()).map_err(decode_error)?
|
|
185
|
+
};
|
|
186
|
+
let journal_records = if journal.length() == 0 {
|
|
187
|
+
Vec::new()
|
|
188
|
+
} else {
|
|
189
|
+
decode_journal(&journal.to_vec()).map_err(decode_error)?
|
|
190
|
+
};
|
|
191
|
+
let operations = journal_records.len();
|
|
192
|
+
for record in journal_records {
|
|
193
|
+
match record {
|
|
194
|
+
JournalRecord {
|
|
195
|
+
key,
|
|
196
|
+
value: Some(value),
|
|
197
|
+
..
|
|
198
|
+
} => {
|
|
199
|
+
entries.insert(key, value);
|
|
200
|
+
}
|
|
201
|
+
JournalRecord { key, .. } => {
|
|
202
|
+
entries.shift_remove(&key);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
self.shared_log.clear_entry_coordinates();
|
|
208
|
+
self.clear_coordinate_core();
|
|
209
|
+
for (_, value) in entries {
|
|
210
|
+
let coordinate = decode_coordinate_value(&value)?;
|
|
211
|
+
self.put_decoded_coordinate_core(coordinate, false)?;
|
|
212
|
+
}
|
|
213
|
+
self.coordinate_journal.clear();
|
|
214
|
+
self.coordinate_journal_record_count = 0;
|
|
215
|
+
Ok(operations)
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
impl NativePeerbitBackbone {
|
|
220
|
+
pub(crate) fn clear_coordinate_core(&mut self) {
|
|
221
|
+
self.coordinate_index.clear();
|
|
222
|
+
self.coordinate_values.clear();
|
|
223
|
+
self.coordinate_journal.clear();
|
|
224
|
+
self.coordinate_journal_record_count = 0;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
pub(crate) fn put_coordinate_core_from_parts(
|
|
228
|
+
&mut self,
|
|
229
|
+
hash: String,
|
|
230
|
+
gid: String,
|
|
231
|
+
hash_number: &str,
|
|
232
|
+
coordinates: Array,
|
|
233
|
+
assigned_to_range_boundary: bool,
|
|
234
|
+
requested_replicas: usize,
|
|
235
|
+
wall_time: u64,
|
|
236
|
+
meta_bytes: Vec<u8>,
|
|
237
|
+
) -> Result<(), JsValue> {
|
|
238
|
+
let hash_number = parse_u64_string(hash_number, "coordinate hash number")?;
|
|
239
|
+
let coordinates = coordinate_numbers_from_array(coordinates)?;
|
|
240
|
+
self.put_coordinate_core(
|
|
241
|
+
hash,
|
|
242
|
+
&gid,
|
|
243
|
+
hash_number,
|
|
244
|
+
&coordinates,
|
|
245
|
+
assigned_to_range_boundary,
|
|
246
|
+
requested_replicas,
|
|
247
|
+
wall_time,
|
|
248
|
+
meta_bytes,
|
|
249
|
+
true,
|
|
250
|
+
);
|
|
251
|
+
Ok(())
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
pub(crate) fn commit_coordinate_core_from_compact_row(
|
|
255
|
+
&mut self,
|
|
256
|
+
coordinate_row: JsValue,
|
|
257
|
+
next_hashes: Array,
|
|
258
|
+
delete_hashes: Array,
|
|
259
|
+
wall_time: u64,
|
|
260
|
+
meta_bytes: Vec<u8>,
|
|
261
|
+
) -> Result<(), JsValue> {
|
|
262
|
+
let row = array_from_value(coordinate_row, "coordinate plan row")?;
|
|
263
|
+
let hash = string_field(&row, 0, "coordinate hash")?;
|
|
264
|
+
let hash_number = stringish_field(&row, 1, "coordinate hash number")?;
|
|
265
|
+
let gid = string_field(&row, 2, "coordinate gid")?;
|
|
266
|
+
let coordinates = array_from_value(row.get(3), "coordinate rows")?;
|
|
267
|
+
let assigned_to_range_boundary = bool_field(&row, 4, "assigned to range boundary")?;
|
|
268
|
+
let requested_replicas = usize_field(&row, 5, "requested replicas")?;
|
|
269
|
+
self.put_coordinate_core_from_parts(
|
|
270
|
+
hash,
|
|
271
|
+
gid,
|
|
272
|
+
&hash_number,
|
|
273
|
+
coordinates,
|
|
274
|
+
assigned_to_range_boundary,
|
|
275
|
+
requested_replicas,
|
|
276
|
+
wall_time,
|
|
277
|
+
meta_bytes,
|
|
278
|
+
)?;
|
|
279
|
+
self.delete_coordinate_core_batch(next_hashes)?;
|
|
280
|
+
self.delete_coordinate_core_batch(delete_hashes)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
pub(crate) fn commit_coordinate_core_from_compact_facts(
|
|
284
|
+
&mut self,
|
|
285
|
+
facts: &NativeLocalAppendCompactFacts,
|
|
286
|
+
next_hashes: &[String],
|
|
287
|
+
delete_hashes: &[String],
|
|
288
|
+
wall_time: u64,
|
|
289
|
+
meta_bytes: Vec<u8>,
|
|
290
|
+
) {
|
|
291
|
+
let coordinate = &facts.coordinate;
|
|
292
|
+
self.put_coordinate_core(
|
|
293
|
+
coordinate.hash.clone(),
|
|
294
|
+
&coordinate.gid,
|
|
295
|
+
coordinate.hash_number,
|
|
296
|
+
&coordinate.coordinates,
|
|
297
|
+
coordinate.assigned_to_range_boundary,
|
|
298
|
+
coordinate.requested_replicas,
|
|
299
|
+
wall_time,
|
|
300
|
+
meta_bytes,
|
|
301
|
+
true,
|
|
302
|
+
);
|
|
303
|
+
let profile_enabled = self.append_profile_enabled;
|
|
304
|
+
let coordinate_delete_started = profile_enabled.then(js_sys::Date::now);
|
|
305
|
+
self.delete_coordinate_core_strings(next_hashes);
|
|
306
|
+
self.delete_coordinate_core_strings(delete_hashes);
|
|
307
|
+
if let Some(started) = coordinate_delete_started {
|
|
308
|
+
self.append_profile.coordinate_delete_ms += js_sys::Date::now() - started;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
pub(crate) fn put_coordinate_core(
|
|
313
|
+
&mut self,
|
|
314
|
+
hash: String,
|
|
315
|
+
gid: &str,
|
|
316
|
+
hash_number: u64,
|
|
317
|
+
coordinates: &[u64],
|
|
318
|
+
assigned_to_range_boundary: bool,
|
|
319
|
+
requested_replicas: usize,
|
|
320
|
+
wall_time: u64,
|
|
321
|
+
meta_bytes: Vec<u8>,
|
|
322
|
+
record_journal: bool,
|
|
323
|
+
) {
|
|
324
|
+
let profile_enabled = self.append_profile_enabled;
|
|
325
|
+
let value_encode_started = profile_enabled.then(js_sys::Date::now);
|
|
326
|
+
let value = encode_coordinate_value(
|
|
327
|
+
&hash,
|
|
328
|
+
gid,
|
|
329
|
+
hash_number,
|
|
330
|
+
coordinates,
|
|
331
|
+
assigned_to_range_boundary,
|
|
332
|
+
requested_replicas,
|
|
333
|
+
wall_time,
|
|
334
|
+
&meta_bytes,
|
|
335
|
+
);
|
|
336
|
+
if let Some(started) = value_encode_started {
|
|
337
|
+
self.append_profile.coordinate_value_encode_ms += js_sys::Date::now() - started;
|
|
338
|
+
}
|
|
339
|
+
if record_journal && self.coordinate_journal_enabled {
|
|
340
|
+
let journal_started = profile_enabled.then(js_sys::Date::now);
|
|
341
|
+
self.push_coordinate_journal_put(&hash, &value);
|
|
342
|
+
if let Some(started) = journal_started {
|
|
343
|
+
self.append_profile.coordinate_journal_put_ms += js_sys::Date::now() - started;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
let index_put_started = profile_enabled.then(js_sys::Date::now);
|
|
347
|
+
self.coordinate_index.insert(hash.clone());
|
|
348
|
+
if let Some(started) = index_put_started {
|
|
349
|
+
self.append_profile.coordinate_index_put_ms += js_sys::Date::now() - started;
|
|
350
|
+
}
|
|
351
|
+
let value_put_started = profile_enabled.then(js_sys::Date::now);
|
|
352
|
+
self.coordinate_values.put(hash, value);
|
|
353
|
+
if let Some(started) = value_put_started {
|
|
354
|
+
self.append_profile.coordinate_value_put_ms += js_sys::Date::now() - started;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
pub(crate) fn delete_coordinate_core(&mut self, hash: &str) -> bool {
|
|
359
|
+
self.coordinate_index.remove(hash);
|
|
360
|
+
if self.coordinate_journal_enabled {
|
|
361
|
+
self.push_coordinate_journal_delete(hash);
|
|
362
|
+
}
|
|
363
|
+
self.coordinate_values.delete(hash)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
fn push_coordinate_journal_put(&mut self, key: &str, value: &[u8]) {
|
|
367
|
+
append_journal_put_record(&mut self.coordinate_journal, key, value);
|
|
368
|
+
self.coordinate_journal_record_count += 1;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
fn push_coordinate_journal_delete(&mut self, key: &str) {
|
|
372
|
+
append_journal_delete_record(&mut self.coordinate_journal, key);
|
|
373
|
+
self.coordinate_journal_record_count += 1;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
pub(crate) fn delete_coordinate_core_batch(&mut self, hashes: Array) -> Result<(), JsValue> {
|
|
377
|
+
for hash in strings_from_array(hashes)? {
|
|
378
|
+
self.delete_coordinate_core(&hash);
|
|
379
|
+
}
|
|
380
|
+
Ok(())
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
pub(crate) fn delete_coordinate_core_strings(&mut self, hashes: &[String]) {
|
|
384
|
+
for hash in hashes {
|
|
385
|
+
self.delete_coordinate_core(hash);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
#[cfg(test)]
|
|
391
|
+
mod tests {
|
|
392
|
+
use super::{decode_coordinate_value_core, encode_coordinate_value};
|
|
393
|
+
use peerbit_indexer_core::wire::WireError;
|
|
394
|
+
|
|
395
|
+
#[test]
|
|
396
|
+
fn coordinate_value_round_trips() {
|
|
397
|
+
let bytes = encode_coordinate_value("hash", "gid", 7, &[1, 2], true, 3, 11, &[9]);
|
|
398
|
+
let valid = decode_coordinate_value_core(&bytes).unwrap();
|
|
399
|
+
assert_eq!(valid.hash, "hash");
|
|
400
|
+
assert_eq!(valid.gid, "gid");
|
|
401
|
+
assert_eq!(valid.hash_number, 7);
|
|
402
|
+
assert_eq!(valid.coordinates, vec![1, 2]);
|
|
403
|
+
assert!(valid.assigned_to_range_boundary);
|
|
404
|
+
assert_eq!(valid.requested_replicas, 3);
|
|
405
|
+
assert_eq!(valid.wall_time, 11);
|
|
406
|
+
assert_eq!(valid.meta_bytes, vec![9]);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
#[test]
|
|
410
|
+
fn corrupt_coordinate_count_errors_instead_of_aborting() {
|
|
411
|
+
let mut bytes = encode_coordinate_value("hash", "gid", 7, &[1, 2], true, 3, 11, &[9]);
|
|
412
|
+
// The count sits after the hash and gid strings, the u64 hash number,
|
|
413
|
+
// the boundary flag byte, and the u64 requested replicas.
|
|
414
|
+
let count_offset = 4 + "hash".len() + 4 + "gid".len() + 8 + 1 + 8;
|
|
415
|
+
bytes[count_offset..count_offset + 4].copy_from_slice(&u32::MAX.to_le_bytes());
|
|
416
|
+
|
|
417
|
+
assert!(matches!(
|
|
418
|
+
decode_coordinate_value_core(&bytes),
|
|
419
|
+
Err(WireError::Truncated("coordinate values"))
|
|
420
|
+
));
|
|
421
|
+
}
|
|
422
|
+
}
|