##// END OF EJS Templates
rust-nodemap: input/output primitives...
Georges Racinet -
r44869:a98ba698 default
parent child Browse files
Show More
@@ -1,790 +1,936 b''
1 1 // Copyright 2018-2020 Georges Racinet <georges.racinet@octobus.net>
2 2 // and Mercurial contributors
3 3 //
4 4 // This software may be used and distributed according to the terms of the
5 5 // GNU General Public License version 2 or any later version.
6 6 //! Indexing facilities for fast retrieval of `Revision` from `Node`
7 7 //!
8 8 //! This provides a variation on the 16-ary radix tree that is
9 9 //! provided as "nodetree" in revlog.c, ready for append-only persistence
10 10 //! on disk.
11 11 //!
12 12 //! Following existing implicit conventions, the "nodemap" terminology
13 13 //! is used in a more abstract context.
14 14
15 15 use super::{
16 16 Node, NodeError, NodePrefix, NodePrefixRef, Revision, RevlogIndex,
17 17 };
18 18
19 19 use std::fmt;
20 use std::mem;
20 21 use std::ops::Deref;
21 22 use std::ops::Index;
23 use std::slice;
22 24
23 25 #[derive(Debug, PartialEq)]
24 26 pub enum NodeMapError {
25 27 MultipleResults,
26 28 InvalidNodePrefix(NodeError),
27 29 /// A `Revision` stored in the nodemap could not be found in the index
28 30 RevisionNotInIndex(Revision),
29 31 }
30 32
31 33 impl From<NodeError> for NodeMapError {
32 34 fn from(err: NodeError) -> Self {
33 35 NodeMapError::InvalidNodePrefix(err)
34 36 }
35 37 }
36 38
37 39 /// Mapping system from Mercurial nodes to revision numbers.
38 40 ///
39 41 /// ## `RevlogIndex` and `NodeMap`
40 42 ///
41 43 /// One way to think about their relationship is that
42 44 /// the `NodeMap` is a prefix-oriented reverse index of the `Node` information
43 45 /// carried by a [`RevlogIndex`].
44 46 ///
45 47 /// Many of the methods in this trait take a `RevlogIndex` argument
46 48 /// which is used for validation of their results. This index must naturally
47 49 /// be the one the `NodeMap` is about, and it must be consistent.
48 50 ///
49 51 /// Notably, the `NodeMap` must not store
50 52 /// information about more `Revision` values than there are in the index.
51 53 /// In these methods, an encountered `Revision` is not in the index, a
52 54 /// [`RevisionNotInIndex`] error is returned.
53 55 ///
54 56 /// In insert operations, the rule is thus that the `NodeMap` must always
55 57 /// be updated after the `RevlogIndex`
56 58 /// be updated first, and the `NodeMap` second.
57 59 ///
58 60 /// [`RevisionNotInIndex`]: enum.NodeMapError.html#variant.RevisionNotInIndex
59 61 /// [`RevlogIndex`]: ../trait.RevlogIndex.html
60 62 pub trait NodeMap {
61 63 /// Find the unique `Revision` having the given `Node`
62 64 ///
63 65 /// If no Revision matches the given `Node`, `Ok(None)` is returned.
64 66 fn find_node(
65 67 &self,
66 68 index: &impl RevlogIndex,
67 69 node: &Node,
68 70 ) -> Result<Option<Revision>, NodeMapError> {
69 71 self.find_bin(index, node.into())
70 72 }
71 73
72 74 /// Find the unique Revision whose `Node` starts with a given binary prefix
73 75 ///
74 76 /// If no Revision matches the given prefix, `Ok(None)` is returned.
75 77 ///
76 78 /// If several Revisions match the given prefix, a [`MultipleResults`]
77 79 /// error is returned.
78 80 fn find_bin<'a>(
79 81 &self,
80 82 idx: &impl RevlogIndex,
81 83 prefix: NodePrefixRef<'a>,
82 84 ) -> Result<Option<Revision>, NodeMapError>;
83 85
84 86 /// Find the unique Revision whose `Node` hexadecimal string representation
85 87 /// starts with a given prefix
86 88 ///
87 89 /// If no Revision matches the given prefix, `Ok(None)` is returned.
88 90 ///
89 91 /// If several Revisions match the given prefix, a [`MultipleResults`]
90 92 /// error is returned.
91 93 fn find_hex(
92 94 &self,
93 95 idx: &impl RevlogIndex,
94 96 prefix: &str,
95 97 ) -> Result<Option<Revision>, NodeMapError> {
96 98 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
97 99 }
98 100 }
99 101
100 102 pub trait MutableNodeMap: NodeMap {
101 103 fn insert<I: RevlogIndex>(
102 104 &mut self,
103 105 index: &I,
104 106 node: &Node,
105 107 rev: Revision,
106 108 ) -> Result<(), NodeMapError>;
107 109 }
108 110
109 111 /// Low level NodeTree [`Blocks`] elements
110 112 ///
111 113 /// These are exactly as for instance on persistent storage.
112 114 type RawElement = i32;
113 115
114 116 /// High level representation of values in NodeTree
115 117 /// [`Blocks`](struct.Block.html)
116 118 ///
117 119 /// This is the high level representation that most algorithms should
118 120 /// use.
119 121 #[derive(Clone, Debug, Eq, PartialEq)]
120 122 enum Element {
121 123 Rev(Revision),
122 124 Block(usize),
123 125 None,
124 126 }
125 127
126 128 impl From<RawElement> for Element {
127 129 /// Conversion from low level representation, after endianness conversion.
128 130 ///
129 131 /// See [`Block`](struct.Block.html) for explanation about the encoding.
130 132 fn from(raw: RawElement) -> Element {
131 133 if raw >= 0 {
132 134 Element::Block(raw as usize)
133 135 } else if raw == -1 {
134 136 Element::None
135 137 } else {
136 138 Element::Rev(-raw - 2)
137 139 }
138 140 }
139 141 }
140 142
141 143 impl From<Element> for RawElement {
142 144 fn from(element: Element) -> RawElement {
143 145 match element {
144 146 Element::None => 0,
145 147 Element::Block(i) => i as RawElement,
146 148 Element::Rev(rev) => -rev - 2,
147 149 }
148 150 }
149 151 }
150 152
151 153 /// A logical block of the `NodeTree`, packed with a fixed size.
152 154 ///
153 155 /// These are always used in container types implementing `Index<Block>`,
154 156 /// such as `&Block`
155 157 ///
156 158 /// As an array of integers, its ith element encodes that the
157 159 /// ith potential edge from the block, representing the ith hexadecimal digit
158 160 /// (nybble) `i` is either:
159 161 ///
160 162 /// - absent (value -1)
161 163 /// - another `Block` in the same indexable container (value β‰₯ 0)
162 164 /// - a `Revision` leaf (value ≀ -2)
163 165 ///
164 166 /// Endianness has to be fixed for consistency on shared storage across
165 167 /// different architectures.
166 168 ///
167 169 /// A key difference with the C `nodetree` is that we need to be
168 170 /// able to represent the [`Block`] at index 0, hence -1 is the empty marker
169 171 /// rather than 0 and the `Revision` range upper limit of -2 instead of -1.
170 172 ///
171 173 /// Another related difference is that `NULL_REVISION` (-1) is not
172 174 /// represented at all, because we want an immutable empty nodetree
173 175 /// to be valid.
174 176
175 #[derive(Clone, PartialEq)]
176 pub struct Block([RawElement; 16]);
177 #[derive(Copy, Clone)]
178 pub struct Block([u8; BLOCK_SIZE]);
179
180 /// Not derivable for arrays of length >32 until const generics are stable
181 impl PartialEq for Block {
182 fn eq(&self, other: &Self) -> bool {
183 &self.0[..] == &other.0[..]
184 }
185 }
186
187 pub const BLOCK_SIZE: usize = 64;
177 188
178 189 impl Block {
179 190 fn new() -> Self {
180 Block([-1; 16])
191 // -1 in 2's complement to create an absent node
192 let byte: u8 = 255;
193 Block([byte; BLOCK_SIZE])
181 194 }
182 195
183 196 fn get(&self, nybble: u8) -> Element {
184 Element::from(RawElement::from_be(self.0[nybble as usize]))
197 let index = nybble as usize * mem::size_of::<RawElement>();
198 Element::from(RawElement::from_be_bytes([
199 self.0[index],
200 self.0[index + 1],
201 self.0[index + 2],
202 self.0[index + 3],
203 ]))
185 204 }
186 205
187 206 fn set(&mut self, nybble: u8, element: Element) {
188 self.0[nybble as usize] = RawElement::to_be(element.into())
207 let values = RawElement::to_be_bytes(element.into());
208 let index = nybble as usize * mem::size_of::<RawElement>();
209 self.0[index] = values[0];
210 self.0[index + 1] = values[1];
211 self.0[index + 2] = values[2];
212 self.0[index + 3] = values[3];
189 213 }
190 214 }
191 215
192 216 impl fmt::Debug for Block {
193 217 /// sparse representation for testing and debugging purposes
194 218 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
195 219 f.debug_map()
196 220 .entries((0..16).filter_map(|i| match self.get(i) {
197 221 Element::None => None,
198 222 element => Some((i, element)),
199 223 }))
200 224 .finish()
201 225 }
202 226 }
203 227
204 228 /// A mutable 16-radix tree with the root block logically at the end
205 229 ///
206 230 /// Because of the append only nature of our node trees, we need to
207 231 /// keep the original untouched and store new blocks separately.
208 232 ///
209 233 /// The mutable root `Block` is kept apart so that we don't have to rebump
210 234 /// it on each insertion.
211 235 pub struct NodeTree {
212 236 readonly: Box<dyn Deref<Target = [Block]> + Send>,
213 237 growable: Vec<Block>,
214 238 root: Block,
215 239 }
216 240
217 241 impl Index<usize> for NodeTree {
218 242 type Output = Block;
219 243
220 244 fn index(&self, i: usize) -> &Block {
221 245 let ro_len = self.readonly.len();
222 246 if i < ro_len {
223 247 &self.readonly[i]
224 248 } else if i == ro_len + self.growable.len() {
225 249 &self.root
226 250 } else {
227 251 &self.growable[i - ro_len]
228 252 }
229 253 }
230 254 }
231 255
232 256 /// Return `None` unless the `Node` for `rev` has given prefix in `index`.
233 fn has_prefix_or_none<'p>(
257 fn has_prefix_or_none(
234 258 idx: &impl RevlogIndex,
235 prefix: NodePrefixRef<'p>,
259 prefix: NodePrefixRef,
236 260 rev: Revision,
237 261 ) -> Result<Option<Revision>, NodeMapError> {
238 262 idx.node(rev)
239 263 .ok_or_else(|| NodeMapError::RevisionNotInIndex(rev))
240 264 .map(|node| {
241 265 if prefix.is_prefix_of(node) {
242 266 Some(rev)
243 267 } else {
244 268 None
245 269 }
246 270 })
247 271 }
248 272
249 273 impl NodeTree {
250 274 /// Initiate a NodeTree from an immutable slice-like of `Block`
251 275 ///
252 276 /// We keep `readonly` and clone its root block if it isn't empty.
253 277 fn new(readonly: Box<dyn Deref<Target = [Block]> + Send>) -> Self {
254 278 let root = readonly
255 279 .last()
256 280 .map(|b| b.clone())
257 281 .unwrap_or_else(|| Block::new());
258 282 NodeTree {
259 283 readonly: readonly,
260 284 growable: Vec::new(),
261 285 root: root,
262 286 }
263 287 }
264 288
289 /// Create from an opaque bunch of bytes
290 ///
291 /// The created `NodeTreeBytes` from `buffer`,
292 /// of which exactly `amount` bytes are used.
293 ///
294 /// - `buffer` could be derived from `PyBuffer` and `Mmap` objects.
295 /// - `offset` allows for the final file format to include fixed data
296 /// (generation number, behavioural flags)
297 /// - `amount` is expressed in bytes, and is not automatically derived from
298 /// `bytes`, so that a caller that manages them atomically can perform
299 /// temporary disk serializations and still rollback easily if needed.
300 /// First use-case for this would be to support Mercurial shell hooks.
301 ///
302 /// panics if `buffer` is smaller than `amount`
303 pub fn load_bytes(
304 bytes: Box<dyn Deref<Target = [u8]> + Send>,
305 amount: usize,
306 ) -> Self {
307 NodeTree::new(Box::new(NodeTreeBytes::new(bytes, amount)))
308 }
309
310 /// Retrieve added `Block` and the original immutable data
311 pub fn into_readonly_and_added(
312 self,
313 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<Block>) {
314 let mut vec = self.growable;
315 let readonly = self.readonly;
316 if readonly.last() != Some(&self.root) {
317 vec.push(self.root);
318 }
319 (readonly, vec)
320 }
321
322 /// Retrieve added `Blocks` as bytes, ready to be written to persistent
323 /// storage
324 pub fn into_readonly_and_added_bytes(
325 self,
326 ) -> (Box<dyn Deref<Target = [Block]> + Send>, Vec<u8>) {
327 let (readonly, vec) = self.into_readonly_and_added();
328 // Prevent running `v`'s destructor so we are in complete control
329 // of the allocation.
330 let vec = mem::ManuallyDrop::new(vec);
331
332 // Transmute the `Vec<Block>` to a `Vec<u8>`. Blocks are contiguous
333 // bytes, so this is perfectly safe.
334 let bytes = unsafe {
335 // Assert that `Block` hasn't been changed and has no padding
336 let _: [u8; 4 * BLOCK_SIZE] =
337 std::mem::transmute([Block::new(); 4]);
338
339 // /!\ Any use of `vec` after this is use-after-free.
340 // TODO: use `into_raw_parts` once stabilized
341 Vec::from_raw_parts(
342 vec.as_ptr() as *mut u8,
343 vec.len() * BLOCK_SIZE,
344 vec.capacity() * BLOCK_SIZE,
345 )
346 };
347 (readonly, bytes)
348 }
349
265 350 /// Total number of blocks
266 351 fn len(&self) -> usize {
267 352 self.readonly.len() + self.growable.len() + 1
268 353 }
269 354
270 355 /// Implemented for completeness
271 356 ///
272 357 /// A `NodeTree` always has at least the mutable root block.
273 358 #[allow(dead_code)]
274 359 fn is_empty(&self) -> bool {
275 360 false
276 361 }
277 362
278 363 /// Main working method for `NodeTree` searches
279 364 ///
280 365 /// This partial implementation lacks special cases for NULL_REVISION
281 366 fn lookup<'p>(
282 367 &self,
283 368 prefix: NodePrefixRef<'p>,
284 369 ) -> Result<Option<Revision>, NodeMapError> {
285 370 for visit_item in self.visit(prefix) {
286 371 if let Some(opt) = visit_item.final_revision() {
287 372 return Ok(opt);
288 373 }
289 374 }
290 375 Err(NodeMapError::MultipleResults)
291 376 }
292 377
293 378 fn visit<'n, 'p>(
294 379 &'n self,
295 380 prefix: NodePrefixRef<'p>,
296 381 ) -> NodeTreeVisitor<'n, 'p> {
297 382 NodeTreeVisitor {
298 383 nt: self,
299 384 prefix: prefix,
300 385 visit: self.len() - 1,
301 386 nybble_idx: 0,
302 387 done: false,
303 388 }
304 389 }
305 390 /// Return a mutable reference for `Block` at index `idx`.
306 391 ///
307 392 /// If `idx` lies in the immutable area, then the reference is to
308 393 /// a newly appended copy.
309 394 ///
310 395 /// Returns (new_idx, glen, mut_ref) where
311 396 ///
312 397 /// - `new_idx` is the index of the mutable `Block`
313 398 /// - `mut_ref` is a mutable reference to the mutable Block.
314 399 /// - `glen` is the new length of `self.growable`
315 400 ///
316 401 /// Note: the caller wouldn't be allowed to query `self.growable.len()`
317 402 /// itself because of the mutable borrow taken with the returned `Block`
318 403 fn mutable_block(&mut self, idx: usize) -> (usize, &mut Block, usize) {
319 404 let ro_blocks = &self.readonly;
320 405 let ro_len = ro_blocks.len();
321 406 let glen = self.growable.len();
322 407 if idx < ro_len {
323 408 // TODO OPTIM I think this makes two copies
324 409 self.growable.push(ro_blocks[idx].clone());
325 410 (glen + ro_len, &mut self.growable[glen], glen + 1)
326 411 } else if glen + ro_len == idx {
327 412 (idx, &mut self.root, glen)
328 413 } else {
329 414 (idx, &mut self.growable[idx - ro_len], glen)
330 415 }
331 416 }
332 417
333 418 /// Main insertion method
334 419 ///
335 420 /// This will dive in the node tree to find the deepest `Block` for
336 421 /// `node`, split it as much as needed and record `node` in there.
337 422 /// The method then backtracks, updating references in all the visited
338 423 /// blocks from the root.
339 424 ///
340 425 /// All the mutated `Block` are copied first to the growable part if
341 426 /// needed. That happens for those in the immutable part except the root.
342 427 pub fn insert<I: RevlogIndex>(
343 428 &mut self,
344 429 index: &I,
345 430 node: &Node,
346 431 rev: Revision,
347 432 ) -> Result<(), NodeMapError> {
348 433 let ro_len = &self.readonly.len();
349 434
350 435 let mut visit_steps: Vec<_> = self.visit(node.into()).collect();
351 436 let read_nybbles = visit_steps.len();
352 437 // visit_steps cannot be empty, since we always visit the root block
353 438 let deepest = visit_steps.pop().unwrap();
354 439
355 440 let (mut block_idx, mut block, mut glen) =
356 441 self.mutable_block(deepest.block_idx);
357 442
358 443 if let Element::Rev(old_rev) = deepest.element {
359 444 let old_node = index
360 445 .node(old_rev)
361 446 .ok_or_else(|| NodeMapError::RevisionNotInIndex(old_rev))?;
362 447 if old_node == node {
363 448 return Ok(()); // avoid creating lots of useless blocks
364 449 }
365 450
366 451 // Looping over the tail of nybbles in both nodes, creating
367 452 // new blocks until we find the difference
368 453 let mut new_block_idx = ro_len + glen;
369 454 let mut nybble = deepest.nybble;
370 455 for nybble_pos in read_nybbles..node.nybbles_len() {
371 456 block.set(nybble, Element::Block(new_block_idx));
372 457
373 458 let new_nybble = node.get_nybble(nybble_pos);
374 459 let old_nybble = old_node.get_nybble(nybble_pos);
375 460
376 461 if old_nybble == new_nybble {
377 462 self.growable.push(Block::new());
378 463 block = &mut self.growable[glen];
379 464 glen += 1;
380 465 new_block_idx += 1;
381 466 nybble = new_nybble;
382 467 } else {
383 468 let mut new_block = Block::new();
384 469 new_block.set(old_nybble, Element::Rev(old_rev));
385 470 new_block.set(new_nybble, Element::Rev(rev));
386 471 self.growable.push(new_block);
387 472 break;
388 473 }
389 474 }
390 475 } else {
391 476 // Free slot in the deepest block: no splitting has to be done
392 477 block.set(deepest.nybble, Element::Rev(rev));
393 478 }
394 479
395 480 // Backtrack over visit steps to update references
396 481 while let Some(visited) = visit_steps.pop() {
397 482 let to_write = Element::Block(block_idx);
398 483 if visit_steps.is_empty() {
399 484 self.root.set(visited.nybble, to_write);
400 485 break;
401 486 }
402 487 let (new_idx, block, _) = self.mutable_block(visited.block_idx);
403 488 if block.get(visited.nybble) == to_write {
404 489 break;
405 490 }
406 491 block.set(visited.nybble, to_write);
407 492 block_idx = new_idx;
408 493 }
409 494 Ok(())
410 495 }
411 496 }
412 497
498 pub struct NodeTreeBytes {
499 buffer: Box<dyn Deref<Target = [u8]> + Send>,
500 len_in_blocks: usize,
501 }
502
503 impl NodeTreeBytes {
504 fn new(
505 buffer: Box<dyn Deref<Target = [u8]> + Send>,
506 amount: usize,
507 ) -> Self {
508 assert!(buffer.len() >= amount);
509 let len_in_blocks = amount / BLOCK_SIZE;
510 NodeTreeBytes {
511 buffer,
512 len_in_blocks,
513 }
514 }
515 }
516
517 impl Deref for NodeTreeBytes {
518 type Target = [Block];
519
520 fn deref(&self) -> &[Block] {
521 unsafe {
522 slice::from_raw_parts(
523 (&self.buffer).as_ptr() as *const Block,
524 self.len_in_blocks,
525 )
526 }
527 }
528 }
529
413 530 struct NodeTreeVisitor<'n, 'p> {
414 531 nt: &'n NodeTree,
415 532 prefix: NodePrefixRef<'p>,
416 533 visit: usize,
417 534 nybble_idx: usize,
418 535 done: bool,
419 536 }
420 537
421 538 #[derive(Debug, PartialEq, Clone)]
422 539 struct NodeTreeVisitItem {
423 540 block_idx: usize,
424 541 nybble: u8,
425 542 element: Element,
426 543 }
427 544
428 545 impl<'n, 'p> Iterator for NodeTreeVisitor<'n, 'p> {
429 546 type Item = NodeTreeVisitItem;
430 547
431 548 fn next(&mut self) -> Option<Self::Item> {
432 549 if self.done || self.nybble_idx >= self.prefix.len() {
433 550 return None;
434 551 }
435 552
436 553 let nybble = self.prefix.get_nybble(self.nybble_idx);
437 554 self.nybble_idx += 1;
438 555
439 556 let visit = self.visit;
440 557 let element = self.nt[visit].get(nybble);
441 558 if let Element::Block(idx) = element {
442 559 self.visit = idx;
443 560 } else {
444 561 self.done = true;
445 562 }
446 563
447 564 Some(NodeTreeVisitItem {
448 565 block_idx: visit,
449 566 nybble: nybble,
450 567 element: element,
451 568 })
452 569 }
453 570 }
454 571
455 572 impl NodeTreeVisitItem {
456 573 // Return `Some(opt)` if this item is final, with `opt` being the
457 574 // `Revision` that it may represent.
458 575 //
459 576 // If the item is not terminal, return `None`
460 577 fn final_revision(&self) -> Option<Option<Revision>> {
461 578 match self.element {
462 579 Element::Block(_) => None,
463 580 Element::Rev(r) => Some(Some(r)),
464 581 Element::None => Some(None),
465 582 }
466 583 }
467 584 }
468 585
469 586 impl From<Vec<Block>> for NodeTree {
470 587 fn from(vec: Vec<Block>) -> Self {
471 588 Self::new(Box::new(vec))
472 589 }
473 590 }
474 591
475 592 impl fmt::Debug for NodeTree {
476 593 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
477 594 let readonly: &[Block] = &*self.readonly;
478 595 write!(
479 596 f,
480 597 "readonly: {:?}, growable: {:?}, root: {:?}",
481 598 readonly, self.growable, self.root
482 599 )
483 600 }
484 601 }
485 602
486 603 impl Default for NodeTree {
487 604 /// Create a fully mutable empty NodeTree
488 605 fn default() -> Self {
489 606 NodeTree::new(Box::new(Vec::new()))
490 607 }
491 608 }
492 609
493 610 impl NodeMap for NodeTree {
494 611 fn find_bin<'a>(
495 612 &self,
496 613 idx: &impl RevlogIndex,
497 614 prefix: NodePrefixRef<'a>,
498 615 ) -> Result<Option<Revision>, NodeMapError> {
499 616 self.lookup(prefix.clone()).and_then(|opt| {
500 617 opt.map_or(Ok(None), |rev| has_prefix_or_none(idx, prefix, rev))
501 618 })
502 619 }
503 620 }
504 621
505 622 #[cfg(test)]
506 623 mod tests {
507 624 use super::NodeMapError::*;
508 625 use super::*;
509 626 use crate::revlog::node::{hex_pad_right, Node};
510 627 use std::collections::HashMap;
511 628
512 629 /// Creates a `Block` using a syntax close to the `Debug` output
513 630 macro_rules! block {
514 631 {$($nybble:tt : $variant:ident($val:tt)),*} => (
515 632 {
516 633 let mut block = Block::new();
517 634 $(block.set($nybble, Element::$variant($val)));*;
518 635 block
519 636 }
520 637 )
521 638 }
522 639
523 640 #[test]
524 641 fn test_block_debug() {
525 642 let mut block = Block::new();
526 643 block.set(1, Element::Rev(3));
527 644 block.set(10, Element::Block(0));
528 645 assert_eq!(format!("{:?}", block), "{1: Rev(3), 10: Block(0)}");
529 646 }
530 647
531 648 #[test]
532 649 fn test_block_macro() {
533 650 let block = block! {5: Block(2)};
534 651 assert_eq!(format!("{:?}", block), "{5: Block(2)}");
535 652
536 653 let block = block! {13: Rev(15), 5: Block(2)};
537 654 assert_eq!(format!("{:?}", block), "{5: Block(2), 13: Rev(15)}");
538 655 }
539 656
540 657 #[test]
541 658 fn test_raw_block() {
542 let mut raw = [-1; 16];
543 raw[0] = 0;
544 raw[1] = RawElement::to_be(15);
545 raw[2] = RawElement::to_be(-2);
546 raw[3] = RawElement::to_be(-1);
547 raw[4] = RawElement::to_be(-3);
659 let mut raw = [255u8; 64];
660
661 let mut counter = 0;
662 for val in [0, 15, -2, -1, -3].iter() {
663 for byte in RawElement::to_be_bytes(*val).iter() {
664 raw[counter] = *byte;
665 counter += 1;
666 }
667 }
548 668 let block = Block(raw);
549 669 assert_eq!(block.get(0), Element::Block(0));
550 670 assert_eq!(block.get(1), Element::Block(15));
551 671 assert_eq!(block.get(3), Element::None);
552 672 assert_eq!(block.get(2), Element::Rev(0));
553 673 assert_eq!(block.get(4), Element::Rev(1));
554 674 }
555 675
556 676 type TestIndex = HashMap<Revision, Node>;
557 677
558 678 impl RevlogIndex for TestIndex {
559 679 fn node(&self, rev: Revision) -> Option<&Node> {
560 680 self.get(&rev)
561 681 }
562 682
563 683 fn len(&self) -> usize {
564 684 self.len()
565 685 }
566 686 }
567 687
568 688 /// Pad hexadecimal Node prefix with zeros on the right
569 689 ///
570 690 /// This avoids having to repeatedly write very long hexadecimal
571 691 /// strings for test data, and brings actual hash size independency.
572 692 #[cfg(test)]
573 693 fn pad_node(hex: &str) -> Node {
574 694 Node::from_hex(&hex_pad_right(hex)).unwrap()
575 695 }
576 696
577 697 /// Pad hexadecimal Node prefix with zeros on the right, then insert
578 698 fn pad_insert(idx: &mut TestIndex, rev: Revision, hex: &str) {
579 699 idx.insert(rev, pad_node(hex));
580 700 }
581 701
582 702 fn sample_nodetree() -> NodeTree {
583 703 NodeTree::from(vec![
584 704 block![0: Rev(9)],
585 705 block![0: Rev(0), 1: Rev(9)],
586 706 block![0: Block(1), 1:Rev(1)],
587 707 ])
588 708 }
589 709
590 710 #[test]
591 711 fn test_nt_debug() {
592 712 let nt = sample_nodetree();
593 713 assert_eq!(
594 714 format!("{:?}", nt),
595 715 "readonly: \
596 716 [{0: Rev(9)}, {0: Rev(0), 1: Rev(9)}, {0: Block(1), 1: Rev(1)}], \
597 717 growable: [], \
598 718 root: {0: Block(1), 1: Rev(1)}",
599 719 );
600 720 }
601 721
602 722 #[test]
603 723 fn test_immutable_find_simplest() -> Result<(), NodeMapError> {
604 724 let mut idx: TestIndex = HashMap::new();
605 725 pad_insert(&mut idx, 1, "1234deadcafe");
606 726
607 727 let nt = NodeTree::from(vec![block! {1: Rev(1)}]);
608 728 assert_eq!(nt.find_hex(&idx, "1")?, Some(1));
609 729 assert_eq!(nt.find_hex(&idx, "12")?, Some(1));
610 730 assert_eq!(nt.find_hex(&idx, "1234de")?, Some(1));
611 731 assert_eq!(nt.find_hex(&idx, "1a")?, None);
612 732 assert_eq!(nt.find_hex(&idx, "ab")?, None);
613 733
614 734 // and with full binary Nodes
615 735 assert_eq!(nt.find_node(&idx, idx.get(&1).unwrap())?, Some(1));
616 736 let unknown = Node::from_hex(&hex_pad_right("3d")).unwrap();
617 737 assert_eq!(nt.find_node(&idx, &unknown)?, None);
618 738 Ok(())
619 739 }
620 740
621 741 #[test]
622 742 fn test_immutable_find_one_jump() {
623 743 let mut idx = TestIndex::new();
624 744 pad_insert(&mut idx, 9, "012");
625 745 pad_insert(&mut idx, 0, "00a");
626 746
627 747 let nt = sample_nodetree();
628 748
629 749 assert_eq!(nt.find_hex(&idx, "0"), Err(MultipleResults));
630 750 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
631 751 assert_eq!(nt.find_hex(&idx, "00"), Ok(Some(0)));
632 752 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
633 753 }
634 754
635 755 #[test]
636 756 fn test_mutated_find() -> Result<(), NodeMapError> {
637 757 let mut idx = TestIndex::new();
638 758 pad_insert(&mut idx, 9, "012");
639 759 pad_insert(&mut idx, 0, "00a");
640 760 pad_insert(&mut idx, 2, "cafe");
641 761 pad_insert(&mut idx, 3, "15");
642 762 pad_insert(&mut idx, 1, "10");
643 763
644 764 let nt = NodeTree {
645 765 readonly: sample_nodetree().readonly,
646 766 growable: vec![block![0: Rev(1), 5: Rev(3)]],
647 767 root: block![0: Block(1), 1:Block(3), 12: Rev(2)],
648 768 };
649 769 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
650 770 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
651 771 assert_eq!(nt.find_hex(&idx, "00")?, Some(0));
652 772 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
653 773 Ok(())
654 774 }
655 775
656 776 struct TestNtIndex {
657 777 index: TestIndex,
658 778 nt: NodeTree,
659 779 }
660 780
661 781 impl TestNtIndex {
662 782 fn new() -> Self {
663 783 TestNtIndex {
664 784 index: HashMap::new(),
665 785 nt: NodeTree::default(),
666 786 }
667 787 }
668 788
669 789 fn insert(
670 790 &mut self,
671 791 rev: Revision,
672 792 hex: &str,
673 793 ) -> Result<(), NodeMapError> {
674 794 let node = pad_node(hex);
675 795 self.index.insert(rev, node.clone());
676 796 self.nt.insert(&self.index, &node, rev)?;
677 797 Ok(())
678 798 }
679 799
680 800 fn find_hex(
681 801 &self,
682 802 prefix: &str,
683 803 ) -> Result<Option<Revision>, NodeMapError> {
684 804 self.nt.find_hex(&self.index, prefix)
685 805 }
686 806
687 807 /// Drain `added` and restart a new one
688 808 fn commit(self) -> Self {
689 809 let mut as_vec: Vec<Block> =
690 810 self.nt.readonly.iter().map(|block| block.clone()).collect();
691 811 as_vec.extend(self.nt.growable);
692 812 as_vec.push(self.nt.root);
693 813
694 814 Self {
695 815 index: self.index,
696 816 nt: NodeTree::from(as_vec).into(),
697 817 }
698 818 }
699 819 }
700 820
701 821 #[test]
702 822 fn test_insert_full_mutable() -> Result<(), NodeMapError> {
703 823 let mut idx = TestNtIndex::new();
704 824 idx.insert(0, "1234")?;
705 825 assert_eq!(idx.find_hex("1")?, Some(0));
706 826 assert_eq!(idx.find_hex("12")?, Some(0));
707 827
708 828 // let's trigger a simple split
709 829 idx.insert(1, "1a34")?;
710 830 assert_eq!(idx.nt.growable.len(), 1);
711 831 assert_eq!(idx.find_hex("12")?, Some(0));
712 832 assert_eq!(idx.find_hex("1a")?, Some(1));
713 833
714 834 // reinserting is a no_op
715 835 idx.insert(1, "1a34")?;
716 836 assert_eq!(idx.nt.growable.len(), 1);
717 837 assert_eq!(idx.find_hex("12")?, Some(0));
718 838 assert_eq!(idx.find_hex("1a")?, Some(1));
719 839
720 840 idx.insert(2, "1a01")?;
721 841 assert_eq!(idx.nt.growable.len(), 2);
722 842 assert_eq!(idx.find_hex("1a"), Err(NodeMapError::MultipleResults));
723 843 assert_eq!(idx.find_hex("12")?, Some(0));
724 844 assert_eq!(idx.find_hex("1a3")?, Some(1));
725 845 assert_eq!(idx.find_hex("1a0")?, Some(2));
726 846 assert_eq!(idx.find_hex("1a12")?, None);
727 847
728 848 // now let's make it split and create more than one additional block
729 849 idx.insert(3, "1a345")?;
730 850 assert_eq!(idx.nt.growable.len(), 4);
731 851 assert_eq!(idx.find_hex("1a340")?, Some(1));
732 852 assert_eq!(idx.find_hex("1a345")?, Some(3));
733 853 assert_eq!(idx.find_hex("1a341")?, None);
734 854
735 855 Ok(())
736 856 }
737 857
738 858 #[test]
739 859 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
740 860 // check that the splitting loop is long enough
741 861 let mut nt_idx = TestNtIndex::new();
742 862 let nt = &mut nt_idx.nt;
743 863 let idx = &mut nt_idx.index;
744 864
745 865 let node0_hex = hex_pad_right("444444");
746 866 let mut node1_hex = hex_pad_right("444444").clone();
747 867 node1_hex.pop();
748 868 node1_hex.push('5');
749 869 let node0 = Node::from_hex(&node0_hex).unwrap();
750 870 let node1 = Node::from_hex(&node1_hex).unwrap();
751 871
752 872 idx.insert(0, node0.clone());
753 873 nt.insert(idx, &node0, 0)?;
754 874 idx.insert(1, node1.clone());
755 875 nt.insert(idx, &node1, 1)?;
756 876
757 877 assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0));
758 878 assert_eq!(nt.find_bin(idx, (&node1).into())?, Some(1));
759 879 Ok(())
760 880 }
761 881
762 882 #[test]
763 883 fn test_insert_partly_immutable() -> Result<(), NodeMapError> {
764 884 let mut idx = TestNtIndex::new();
765 885 idx.insert(0, "1234")?;
766 886 idx.insert(1, "1235")?;
767 887 idx.insert(2, "131")?;
768 888 idx.insert(3, "cafe")?;
769 889 let mut idx = idx.commit();
770 890 assert_eq!(idx.find_hex("1234")?, Some(0));
771 891 assert_eq!(idx.find_hex("1235")?, Some(1));
772 892 assert_eq!(idx.find_hex("131")?, Some(2));
773 893 assert_eq!(idx.find_hex("cafe")?, Some(3));
774 894
775 895 idx.insert(4, "123A")?;
776 896 assert_eq!(idx.find_hex("1234")?, Some(0));
777 897 assert_eq!(idx.find_hex("1235")?, Some(1));
778 898 assert_eq!(idx.find_hex("131")?, Some(2));
779 899 assert_eq!(idx.find_hex("cafe")?, Some(3));
780 900 assert_eq!(idx.find_hex("123A")?, Some(4));
781 901
782 902 idx.insert(5, "c0")?;
783 903 assert_eq!(idx.find_hex("cafe")?, Some(3));
784 904 assert_eq!(idx.find_hex("c0")?, Some(5));
785 905 assert_eq!(idx.find_hex("c1")?, None);
786 906 assert_eq!(idx.find_hex("1234")?, Some(0));
787 907
788 908 Ok(())
789 909 }
910
911 #[test]
912 fn test_into_added_empty() {
913 assert!(sample_nodetree().into_readonly_and_added().1.is_empty());
914 assert!(sample_nodetree()
915 .into_readonly_and_added_bytes()
916 .1
917 .is_empty());
918 }
919
920 #[test]
921 fn test_into_added_bytes() -> Result<(), NodeMapError> {
922 let mut idx = TestNtIndex::new();
923 idx.insert(0, "1234")?;
924 let mut idx = idx.commit();
925 idx.insert(4, "cafe")?;
926 let (_, bytes) = idx.nt.into_readonly_and_added_bytes();
927
928 // only the root block has been changed
929 assert_eq!(bytes.len(), BLOCK_SIZE);
930 // big endian for -2
931 assert_eq!(&bytes[4..2 * 4], [255, 255, 255, 254]);
932 // big endian for -6
933 assert_eq!(&bytes[12 * 4..13 * 4], [255, 255, 255, 250]);
934 Ok(())
935 }
790 936 }
General Comments 0
You need to be logged in to leave comments. Login now