1 /*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4:
3 #ident "$Id$"
4 /*======
5 This file is part of PerconaFT.
6 
7 
8 Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved.
9 
10     PerconaFT is free software: you can redistribute it and/or modify
11     it under the terms of the GNU General Public License, version 2,
12     as published by the Free Software Foundation.
13 
14     PerconaFT is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILIT or FITNESS FOR A PARTICULAR PURPOSE.  See the
17     GNU General Public License for more details.
18 
19     You should have received a copy of the GNU General Public License
20     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
21 
22 ----------------------------------------
23 
24     PerconaFT is free software: you can redistribute it and/or modify
25     it under the terms of the GNU Affero General Public License, version 3,
26     as published by the Free Software Foundation.
27 
28     PerconaFT is distributed in the hope that it will be useful,
29     but WITHOUT ANY WARRANTY; without even the implied warranty of
30     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31     GNU Affero General Public License for more details.
32 
33     You should have received a copy of the GNU Affero General Public License
34     along with PerconaFT.  If not, see <http://www.gnu.org/licenses/>.
35 ======= */
36 
37 #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved."
38 
39 #include "ft/serialize/rbtree_mhs.h"
40 #include "portability/toku_assert.h"
41 #include "portability/toku_portability.h"
42 #include <algorithm>
43 
44 namespace MhsRbTree {
45 
Tree()46     Tree::Tree() : _root(NULL), _align(1) {}
47 
Tree(uint64_t align)48     Tree::Tree(uint64_t align) : _root(NULL), _align(align) {}
49 
~Tree()50     Tree::~Tree() { Destroy(); }
51 
PreOrder(Node * tree) const52     void Tree::PreOrder(Node *tree) const {
53         if (tree != NULL) {
54             fprintf(stderr, "%" PRIu64 " ", rbn_offset(tree).ToInt());
55             PreOrder(tree->_left);
56             PreOrder(tree->_right);
57         }
58     }
59 
PreOrder()60     void Tree::PreOrder() { PreOrder(_root); }
61 
InOrder(Node * tree) const62     void Tree::InOrder(Node *tree) const {
63         if (tree != NULL) {
64             InOrder(tree->_left);
65             fprintf(stderr, "%" PRIu64 " ", rbn_offset(tree).ToInt());
66             InOrder(tree->_right);
67         }
68     }
69 
70     // yeah, i only care about in order visitor. -Jun
InOrderVisitor(Node * tree,void (* f)(void *,Node *,uint64_t),void * extra,uint64_t depth)71     void Tree::InOrderVisitor(Node *tree,
72                               void (*f)(void *, Node *, uint64_t),
73                               void *extra,
74                               uint64_t depth) {
75         if (tree != NULL) {
76             InOrderVisitor(tree->_left, f, extra, depth + 1);
77             f(extra, tree, depth);
78             InOrderVisitor(tree->_right, f, extra, depth + 1);
79         }
80     }
81 
InOrderVisitor(void (* f)(void *,Node *,uint64_t),void * extra)82     void Tree::InOrderVisitor(void (*f)(void *, Node *, uint64_t),
83                               void *extra) {
84         InOrderVisitor(_root, f, extra, 0);
85     }
86 
InOrder()87     void Tree::InOrder() { InOrder(_root); }
88 
PostOrder(Node * tree) const89     void Tree::PostOrder(Node *tree) const {
90         if (tree != NULL) {
91             PostOrder(tree->_left);
92             PostOrder(tree->_right);
93             fprintf(stderr, "%" PRIu64 " ", rbn_offset(tree).ToInt());
94         }
95     }
96 
PostOrder()97     void Tree::PostOrder() { PostOrder(_root); }
98 
SearchByOffset(uint64_t offset)99     Node *Tree::SearchByOffset(uint64_t offset) {
100         Node *x = _root;
101         while ((x != NULL) && (rbn_offset(x).ToInt() != offset)) {
102             if (offset < rbn_offset(x).ToInt())
103                 x = x->_left;
104             else
105                 x = x->_right;
106         }
107 
108         return x;
109     }
110 
111     // mostly for testing
SearchFirstFitBySize(uint64_t size)112     Node *Tree::SearchFirstFitBySize(uint64_t size) {
113         if (EffectiveSize(_root) < size && rbn_left_mhs(_root) < size &&
114             rbn_right_mhs(_root) < size) {
115             return nullptr;
116         } else {
117             return SearchFirstFitBySizeHelper(_root, size);
118         }
119     }
120 
SearchFirstFitBySizeHelper(Node * x,uint64_t size)121     Node *Tree::SearchFirstFitBySizeHelper(Node *x, uint64_t size) {
122         if (EffectiveSize(x) >= size) {
123             // only possible to go left
124             if (rbn_left_mhs(x) >= size)
125                 return SearchFirstFitBySizeHelper(x->_left, size);
126             else
127                 return x;
128         }
129         if (rbn_left_mhs(x) >= size)
130             return SearchFirstFitBySizeHelper(x->_left, size);
131 
132         if (rbn_right_mhs(x) >= size)
133             return SearchFirstFitBySizeHelper(x->_right, size);
134 
135         // this is an invalid state
136         Dump();
137         ValidateBalance();
138         ValidateMhs();
139         invariant(0);
140         return NULL;
141     }
142 
MinNode(Node * tree)143     Node *Tree::MinNode(Node *tree) {
144         if (tree == NULL)
145             return NULL;
146 
147         while (tree->_left != NULL)
148             tree = tree->_left;
149         return tree;
150     }
151 
MinNode()152     Node *Tree::MinNode() { return MinNode(_root); }
153 
MaxNode(Node * tree)154     Node *Tree::MaxNode(Node *tree) {
155         if (tree == NULL)
156             return NULL;
157 
158         while (tree->_right != NULL)
159             tree = tree->_right;
160         return tree;
161     }
162 
MaxNode()163     Node *Tree::MaxNode() { return MaxNode(_root); }
164 
SuccessorHelper(Node * y,Node * x)165     Node *Tree::SuccessorHelper(Node *y, Node *x) {
166         while ((y != NULL) && (x == y->_right)) {
167             x = y;
168             y = y->_parent;
169         }
170         return y;
171     }
Successor(Node * x)172     Node *Tree::Successor(Node *x) {
173         if (x->_right != NULL)
174             return MinNode(x->_right);
175 
176         Node *y = x->_parent;
177         return SuccessorHelper(y, x);
178     }
179 
PredecessorHelper(Node * y,Node * x)180     Node *Tree::PredecessorHelper(Node *y, Node *x) {
181         while ((y != NULL) && (x == y->_left)) {
182             x = y;
183             y = y->_parent;
184         }
185 
186         return y;
187     }
Predecessor(Node * x)188     Node *Tree::Predecessor(Node *x) {
189         if (x->_left != NULL)
190             return MaxNode(x->_left);
191 
192         Node *y = x->_parent;
193         return SuccessorHelper(y, x);
194     }
195 
196     /*
197     *      px                              px
198     *     /                               /
199     *    x                               y
200     *   /  \      --(left rotation)-->  / \               #
201     *  lx   y                          x  ry
202     *     /   \                       /  \
203     *    ly   ry                      lx  ly
204     *  max_hole_size updates are pretty local
205     */
206 
LeftRotate(Node * & root,Node * x)207     void Tree::LeftRotate(Node *&root, Node *x) {
208         Node *y = x->_right;
209 
210         x->_right = y->_left;
211         rbn_right_mhs(x) = rbn_left_mhs(y);
212 
213         if (y->_left != NULL)
214             y->_left->_parent = x;
215 
216         y->_parent = x->_parent;
217 
218         if (x->_parent == NULL) {
219             root = y;
220         } else {
221             if (x->_parent->_left == x) {
222                 x->_parent->_left = y;
223             } else {
224                 x->_parent->_right = y;
225             }
226         }
227         y->_left = x;
228         rbn_left_mhs(y) = mhs_of_subtree(x);
229 
230         x->_parent = y;
231     }
232 
233     /*            py                               py
234      *           /                                /
235      *          y                                x
236      *         /  \      --(right rotate)-->    /  \                     #
237      *        x   ry                           lx   y
238      *       / \                                   / \                   #
239      *      lx  rx                                rx  ry
240      *
241      */
242 
RightRotate(Node * & root,Node * y)243     void Tree::RightRotate(Node *&root, Node *y) {
244         Node *x = y->_left;
245 
246         y->_left = x->_right;
247         rbn_left_mhs(y) = rbn_right_mhs(x);
248 
249         if (x->_right != NULL)
250             x->_right->_parent = y;
251 
252         x->_parent = y->_parent;
253 
254         if (y->_parent == NULL) {
255             root = x;
256         } else {
257             if (y == y->_parent->_right)
258                 y->_parent->_right = x;
259             else
260                 y->_parent->_left = x;
261         }
262 
263         x->_right = y;
264         rbn_right_mhs(x) = mhs_of_subtree(y);
265         y->_parent = x;
266     }
267 
268     // walking from this node up to update the mhs info
269     // whenver there is change on left/right mhs or size we should recalculate.
270     // prerequisit: the children of the node are mhs up-to-date.
RecalculateMhs(Node * node)271     void Tree::RecalculateMhs(Node *node) {
272         uint64_t *p_node_mhs = 0;
273         Node *parent = node->_parent;
274 
275         if (!parent)
276             return;
277 
278         uint64_t max_mhs = mhs_of_subtree(node);
279         if (node == parent->_left) {
280             p_node_mhs = &rbn_left_mhs(parent);
281         } else if (node == parent->_right) {
282             p_node_mhs = &rbn_right_mhs(parent);
283         } else {
284             return;
285         }
286         if (*p_node_mhs != max_mhs) {
287             *p_node_mhs = max_mhs;
288             RecalculateMhs(parent);
289         }
290     }
291 
IsNewNodeMergable(Node * pred,Node * succ,Node::BlockPair pair,bool * left_merge,bool * right_merge)292     void Tree::IsNewNodeMergable(Node *pred,
293                                  Node *succ,
294                                  Node::BlockPair pair,
295                                  bool *left_merge,
296                                  bool *right_merge) {
297         if (pred) {
298             OUUInt64 end_of_pred = rbn_size(pred) + rbn_offset(pred);
299             if (end_of_pred < pair._offset)
300                 *left_merge = false;
301             else {
302                 invariant(end_of_pred == pair._offset);
303                 *left_merge = true;
304             }
305         }
306         if (succ) {
307             OUUInt64 begin_of_succ = rbn_offset(succ);
308             OUUInt64 end_of_node = pair._offset + pair._size;
309             if (end_of_node < begin_of_succ) {
310                 *right_merge = false;
311             } else {
312                 invariant(end_of_node == begin_of_succ);
313                 *right_merge = true;
314             }
315         }
316     }
317 
AbsorbNewNode(Node * pred,Node * succ,Node::BlockPair pair,bool left_merge,bool right_merge,bool is_right_child)318     void Tree::AbsorbNewNode(Node *pred,
319                              Node *succ,
320                              Node::BlockPair pair,
321                              bool left_merge,
322                              bool right_merge,
323                              bool is_right_child) {
324         invariant(left_merge || right_merge);
325         if (left_merge && right_merge) {
326             // merge to the succ
327             if (!is_right_child) {
328                 rbn_size(succ) += pair._size;
329                 rbn_offset(succ) = pair._offset;
330                 // merge to the pred
331                 rbn_size(pred) += rbn_size(succ);
332                 // to keep the invariant of the tree -no overlapping holes
333                 rbn_offset(succ) += rbn_size(succ);
334                 rbn_size(succ) = 0;
335                 RecalculateMhs(succ);
336                 RecalculateMhs(pred);
337                 // pred dominates succ. this is going to
338                 // update the pred labels separately.
339                 // remove succ
340                 RawRemove(_root, succ);
341             } else {
342                 rbn_size(pred) += pair._size;
343                 rbn_offset(succ) = rbn_offset(pred);
344                 rbn_size(succ) += rbn_size(pred);
345                 rbn_offset(pred) += rbn_size(pred);
346                 rbn_size(pred) = 0;
347                 RecalculateMhs(pred);
348                 RecalculateMhs(succ);
349                 // now remove pred
350                 RawRemove(_root, pred);
351             }
352         } else if (left_merge) {
353             rbn_size(pred) += pair._size;
354             RecalculateMhs(pred);
355         } else if (right_merge) {
356             rbn_offset(succ) -= pair._size;
357             rbn_size(succ) += pair._size;
358             RecalculateMhs(succ);
359         }
360     }
361     // this is the most tedious part, but not complicated:
362     // 1.find where to insert the pair
363     // 2.if the pred and succ can merge with the pair. merge with them. either
364     // pred
365     // or succ can be removed.
366     // 3. if only left-mergable or right-mergeable, just merge
367     // 4. non-mergable case. insert the node and run the fixup.
368 
Insert(Node * & root,Node::BlockPair pair)369     int Tree::Insert(Node *&root, Node::BlockPair pair) {
370         Node *x = _root;
371         Node *y = NULL;
372         bool left_merge = false;
373         bool right_merge = false;
374         Node *node = NULL;
375 
376         while (x != NULL) {
377             y = x;
378             if (pair._offset < rbn_key(x))
379                 x = x->_left;
380             else
381                 x = x->_right;
382         }
383 
384         // we found where to insert, lets find out the pred and succ for
385         // possible
386         // merges.
387         //  node->parent = y;
388         Node *pred, *succ;
389         if (y != NULL) {
390             if (pair._offset < rbn_key(y)) {
391                 // as the left child
392                 pred = PredecessorHelper(y->_parent, y);
393                 succ = y;
394                 IsNewNodeMergable(pred, succ, pair, &left_merge, &right_merge);
395                 if (left_merge || right_merge) {
396                     AbsorbNewNode(
397                         pred, succ, pair, left_merge, right_merge, false);
398                 } else {
399                     // construct the node
400                     Node::Pair mhsp {0, 0};
401                     node =
402                         new Node(EColor::BLACK, pair, mhsp, nullptr, nullptr, nullptr);
403                     if (!node)
404                         return -1;
405                     y->_left = node;
406                     node->_parent = y;
407                     RecalculateMhs(node);
408                 }
409 
410             } else {
411                 // as the right child
412                 pred = y;
413                 succ = SuccessorHelper(y->_parent, y);
414                 IsNewNodeMergable(pred, succ, pair, &left_merge, &right_merge);
415                 if (left_merge || right_merge) {
416                     AbsorbNewNode(
417                         pred, succ, pair, left_merge, right_merge, true);
418                 } else {
419                     // construct the node
420                     Node::Pair mhsp {0, 0};
421                     node =
422                         new Node(EColor::BLACK, pair, mhsp, nullptr, nullptr, nullptr);
423                     if (!node)
424                         return -1;
425                     y->_right = node;
426                     node->_parent = y;
427                     RecalculateMhs(node);
428                 }
429             }
430         } else {
431             Node::Pair mhsp {0, 0};
432             node = new Node(EColor::BLACK, pair, mhsp, nullptr, nullptr, nullptr);
433             if (!node)
434                 return -1;
435             root = node;
436         }
437         if (!left_merge && !right_merge) {
438             invariant_notnull(node);
439             node->_color = EColor::RED;
440             return InsertFixup(root, node);
441         }
442         return 0;
443     }
444 
InsertFixup(Node * & root,Node * node)445     int Tree::InsertFixup(Node *&root, Node *node) {
446         Node *parent, *gparent;
447         while ((parent = rbn_parent(node)) && rbn_is_red(parent)) {
448             gparent = rbn_parent(parent);
449             if (parent == gparent->_left) {
450                 {
451                     Node *uncle = gparent->_right;
452                     if (uncle && rbn_is_red(uncle)) {
453                         rbn_set_black(uncle);
454                         rbn_set_black(parent);
455                         rbn_set_red(gparent);
456                         node = gparent;
457                         continue;
458                     }
459                 }
460 
461                 if (parent->_right == node) {
462                     Node *tmp;
463                     LeftRotate(root, parent);
464                     tmp = parent;
465                     parent = node;
466                     node = tmp;
467                 }
468 
469                 rbn_set_black(parent);
470                 rbn_set_red(gparent);
471                 RightRotate(root, gparent);
472             } else {
473                 {
474                     Node *uncle = gparent->_left;
475                     if (uncle && rbn_is_red(uncle)) {
476                         rbn_set_black(uncle);
477                         rbn_set_black(parent);
478                         rbn_set_red(gparent);
479                         node = gparent;
480                         continue;
481                     }
482                 }
483 
484                 if (parent->_left == node) {
485                     Node *tmp;
486                     RightRotate(root, parent);
487                     tmp = parent;
488                     parent = node;
489                     node = tmp;
490                 }
491                 rbn_set_black(parent);
492                 rbn_set_red(gparent);
493                 LeftRotate(root, gparent);
494             }
495         }
496         rbn_set_black(root);
497         return 0;
498     }
499 
Insert(Node::BlockPair pair)500     int Tree::Insert(Node::BlockPair pair) { return Insert(_root, pair); }
501 
Remove(size_t size)502     uint64_t Tree::Remove(size_t size) {
503         Node *node = SearchFirstFitBySize(size);
504         return Remove(_root, node, size);
505     }
506 
RawRemove(Node * & root,Node * node)507     void Tree::RawRemove(Node *&root, Node *node) {
508         Node *child, *parent;
509         EColor color;
510 
511         if ((node->_left != NULL) && (node->_right != NULL)) {
512             Node *replace = node;
513             replace = replace->_right;
514             while (replace->_left != NULL)
515                 replace = replace->_left;
516 
517             if (rbn_parent(node)) {
518                 if (rbn_parent(node)->_left == node)
519                     rbn_parent(node)->_left = replace;
520                 else
521                     rbn_parent(node)->_right = replace;
522             } else {
523                 root = replace;
524             }
525             child = replace->_right;
526             parent = rbn_parent(replace);
527             color = rbn_color(replace);
528 
529             if (parent == node) {
530                 parent = replace;
531             } else {
532                 if (child)
533                     rbn_parent(child) = parent;
534 
535                 parent->_left = child;
536                 rbn_left_mhs(parent) = rbn_right_mhs(replace);
537                 RecalculateMhs(parent);
538                 replace->_right = node->_right;
539                 rbn_set_parent(node->_right, replace);
540                 rbn_right_mhs(replace) = rbn_right_mhs(node);
541             }
542 
543             replace->_parent = node->_parent;
544             replace->_color = node->_color;
545             replace->_left = node->_left;
546             rbn_left_mhs(replace) = rbn_left_mhs(node);
547             node->_left->_parent = replace;
548             RecalculateMhs(replace);
549             if (color == EColor::BLACK)
550                 RawRemoveFixup(root, child, parent);
551             delete node;
552             return;
553         }
554 
555         if (node->_left != NULL)
556             child = node->_left;
557         else
558             child = node->_right;
559 
560         parent = node->_parent;
561         color = node->_color;
562 
563         if (child)
564             child->_parent = parent;
565 
566         if (parent) {
567             if (parent->_left == node) {
568                 parent->_left = child;
569                 rbn_left_mhs(parent) = child ? mhs_of_subtree(child) : 0;
570             } else {
571                 parent->_right = child;
572                 rbn_right_mhs(parent) = child ? mhs_of_subtree(child) : 0;
573             }
574             RecalculateMhs(parent);
575         } else
576             root = child;
577         if (color == EColor::BLACK)
578             RawRemoveFixup(root, child, parent);
579         delete node;
580     }
581 
RawRemove(uint64_t offset)582     void Tree::RawRemove(uint64_t offset) {
583         Node *node = SearchByOffset(offset);
584         RawRemove(_root, node);
585     }
align(uint64_t value,uint64_t ba_alignment)586     static inline uint64_t align(uint64_t value, uint64_t ba_alignment) {
587         return ((value + ba_alignment - 1) / ba_alignment) * ba_alignment;
588     }
Remove(Node * & root,Node * node,size_t size)589     uint64_t Tree::Remove(Node *&root, Node *node, size_t size) {
590         OUUInt64 n_offset = rbn_offset(node);
591         OUUInt64 n_size = rbn_size(node);
592         OUUInt64 answer_offset(align(rbn_offset(node).ToInt(), _align));
593 
594         invariant((answer_offset + size) <= (n_offset + n_size));
595         if (answer_offset == n_offset) {
596             rbn_offset(node) += size;
597             rbn_size(node) -= size;
598             RecalculateMhs(node);
599             if (rbn_size(node) == 0) {
600                 RawRemove(root, node);
601             }
602 
603         } else {
604             if (answer_offset + size == n_offset + n_size) {
605                 rbn_size(node) -= size;
606                 RecalculateMhs(node);
607             } else {
608                 // well, cut in the middle...
609                 rbn_size(node) = answer_offset - n_offset;
610                 RecalculateMhs(node);
611                 Insert(_root,
612                        {(answer_offset + size),
613                         (n_offset + n_size) - (answer_offset + size)});
614             }
615         }
616         return answer_offset.ToInt();
617     }
618 
RawRemoveFixup(Node * & root,Node * node,Node * parent)619     void Tree::RawRemoveFixup(Node *&root, Node *node, Node *parent) {
620         Node *other;
621         while ((!node || rbn_is_black(node)) && node != root) {
622             if (parent->_left == node) {
623                 other = parent->_right;
624                 if (rbn_is_red(other)) {
625                     // Case 1: the brother of X, w, is read
626                     rbn_set_black(other);
627                     rbn_set_red(parent);
628                     LeftRotate(root, parent);
629                     other = parent->_right;
630                 }
631                 if ((!other->_left || rbn_is_black(other->_left)) &&
632                     (!other->_right || rbn_is_black(other->_right))) {
633                     // Case 2: w is black and both of w's children are black
634                     rbn_set_red(other);
635                     node = parent;
636                     parent = rbn_parent(node);
637                 } else {
638                     if (!other->_right || rbn_is_black(other->_right)) {
639                         // Case 3: w is black and left child of w is red but
640                         // right
641                         // child is black
642                         rbn_set_black(other->_left);
643                         rbn_set_red(other);
644                         RightRotate(root, other);
645                         other = parent->_right;
646                     }
647                     // Case 4: w is black and right child of w is red,
648                     // regardless of
649                     // left child's color
650                     rbn_set_color(other, rbn_color(parent));
651                     rbn_set_black(parent);
652                     rbn_set_black(other->_right);
653                     LeftRotate(root, parent);
654                     node = root;
655                     break;
656                 }
657             } else {
658                 other = parent->_left;
659                 if (rbn_is_red(other)) {
660                     // Case 1: w is red
661                     rbn_set_black(other);
662                     rbn_set_red(parent);
663                     RightRotate(root, parent);
664                     other = parent->_left;
665                 }
666                 if ((!other->_left || rbn_is_black(other->_left)) &&
667                     (!other->_right || rbn_is_black(other->_right))) {
668                     // Case 2: w is black and both children are black
669                     rbn_set_red(other);
670                     node = parent;
671                     parent = rbn_parent(node);
672                 } else {
673                     if (!other->_left || rbn_is_black(other->_left)) {
674                         // Case 3: w is black and left child of w is red whereas
675                         // right child is black
676                         rbn_set_black(other->_right);
677                         rbn_set_red(other);
678                         LeftRotate(root, other);
679                         other = parent->_left;
680                     }
681                     // Case 4:w is black and right child of w is red, regardless
682                     // of
683                     // the left child's color
684                     rbn_set_color(other, rbn_color(parent));
685                     rbn_set_black(parent);
686                     rbn_set_black(other->_left);
687                     RightRotate(root, parent);
688                     node = root;
689                     break;
690                 }
691             }
692         }
693         if (node)
694             rbn_set_black(node);
695     }
696 
Destroy(Node * & tree)697     void Tree::Destroy(Node *&tree) {
698         if (tree == NULL)
699             return;
700 
701         if (tree->_left != NULL)
702             Destroy(tree->_left);
703         if (tree->_right != NULL)
704             Destroy(tree->_right);
705 
706         delete tree;
707         tree = NULL;
708     }
709 
Destroy()710     void Tree::Destroy() { Destroy(_root); }
711 
Dump(Node * tree,Node::BlockPair pair,EDirection dir)712     void Tree::Dump(Node *tree, Node::BlockPair pair, EDirection dir) {
713         if (tree != NULL) {
714             if (dir == EDirection::NONE)
715                 fprintf(stderr,
716                         "(%" PRIu64 ",%" PRIu64 ", mhs:(%" PRIu64 ",%" PRIu64
717                         "))(B) is root\n",
718                         rbn_offset(tree).ToInt(),
719                         rbn_size(tree).ToInt(),
720                         rbn_left_mhs(tree),
721                         rbn_right_mhs(tree));
722             else
723                 fprintf(stderr,
724                         "(%" PRIu64 ",%" PRIu64 ",mhs:(%" PRIu64 ",%" PRIu64
725                         "))(%c) is %" PRIu64 "'s %s\n",
726                         rbn_offset(tree).ToInt(),
727                         rbn_size(tree).ToInt(),
728                         rbn_left_mhs(tree),
729                         rbn_right_mhs(tree),
730                         rbn_is_red(tree) ? 'R' : 'B',
731                         pair._offset.ToInt(),
732                         dir == EDirection::RIGHT ? "right child" : "left child");
733 
734             Dump(tree->_left, tree->_hole, EDirection::LEFT);
735             Dump(tree->_right, tree->_hole, EDirection::RIGHT);
736         }
737     }
738 
EffectiveSize(Node * node)739     uint64_t Tree::EffectiveSize(Node *node) {
740         OUUInt64 offset = rbn_offset(node);
741         OUUInt64 size = rbn_size(node);
742         OUUInt64 end = offset + size;
743         OUUInt64 aligned_offset(align(offset.ToInt(), _align));
744         if (aligned_offset > end) {
745             return 0;
746         }
747         return (end - aligned_offset).ToInt();
748     }
749 
Dump()750     void Tree::Dump() {
751         if (_root != NULL)
752             Dump(_root, _root->_hole, (EDirection)0);
753     }
754 
vis_bal_f(void * extra,Node * node,uint64_t depth)755     static void vis_bal_f(void *extra, Node *node, uint64_t depth) {
756         uint64_t **p = (uint64_t **)extra;
757         uint64_t min = *p[0];
758         uint64_t max = *p[1];
759         if (node->_left) {
760             Node *left = node->_left;
761             invariant(node == left->_parent);
762         }
763 
764         if (node->_right) {
765             Node *right = node->_right;
766             invariant(node == right->_parent);
767         }
768 
769         if (!node->_left || !node->_right) {
770             if (min > depth) {
771                 *p[0] = depth;
772             } else if (max < depth) {
773                 *p[1] = depth;
774             }
775         }
776     }
777 
ValidateBalance()778     void Tree::ValidateBalance() {
779         uint64_t min_depth = 0xffffffffffffffff;
780         uint64_t max_depth = 0;
781         if (!_root) {
782             return;
783         }
784         uint64_t *p[2] = {&min_depth, &max_depth};
785         InOrderVisitor(vis_bal_f, (void *)p);
786         invariant((min_depth + 1) * 2 >= max_depth + 1);
787     }
788 
vis_cmp_f(void * extra,Node * node,uint64_t UU (depth))789     static void vis_cmp_f(void *extra, Node *node, uint64_t UU(depth)) {
790         Node::BlockPair **p = (Node::BlockPair **)extra;
791 
792         invariant_notnull(*p);
793         invariant((*p)->_offset == node->_hole._offset);
794 
795         *p = *p + 1;
796     }
797 
798     // validate the input pairs matches with sorted pairs
ValidateInOrder(Node::BlockPair * pairs)799     void Tree::ValidateInOrder(Node::BlockPair *pairs) {
800         InOrderVisitor(vis_cmp_f, &pairs);
801     }
802 
ValidateMhs(Node * node)803     uint64_t Tree::ValidateMhs(Node *node) {
804         if (!node)
805             return 0;
806         else {
807             uint64_t mhs_left = ValidateMhs(node->_left);
808             uint64_t mhs_right = ValidateMhs(node->_right);
809             if (mhs_left != rbn_left_mhs(node)) {
810                 printf("assert failure: mhs_left = %" PRIu64 "\n", mhs_left);
811                 Dump(node, node->_hole, (EDirection)0);
812             }
813             invariant(mhs_left == rbn_left_mhs(node));
814 
815             if (mhs_right != rbn_right_mhs(node)) {
816                 printf("assert failure: mhs_right = %" PRIu64 "\n", mhs_right);
817                 Dump(node, node->_hole, (EDirection)0);
818             }
819             invariant(mhs_right == rbn_right_mhs(node));
820             return std::max(EffectiveSize(node), std::max(mhs_left, mhs_right));
821         }
822     }
823 
ValidateMhs()824     void Tree::ValidateMhs() {
825         if (!_root)
826             return;
827         uint64_t mhs_left = ValidateMhs(_root->_left);
828         uint64_t mhs_right = ValidateMhs(_root->_right);
829         invariant(mhs_left == rbn_left_mhs(_root));
830         invariant(mhs_right == rbn_right_mhs(_root));
831     }
832 
833 }  // namespace MhsRbTree
834