DbtuxTree.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:20k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #define DBTUX_TREE_CPP
  14. #include "Dbtux.hpp"
  15. /*
  16.  * Add entry.  Handle the case when there is room for one more.  This
  17.  * is the common case given slack in nodes.
  18.  */
  19. void
  20. Dbtux::treeAdd(Frag& frag, TreePos treePos, TreeEnt ent)
  21. {
  22.   TreeHead& tree = frag.m_tree;
  23.   NodeHandle node(frag);
  24.   if (treePos.m_loc != NullTupLoc) {
  25.     // non-empty tree
  26.     jam();
  27.     selectNode(node, treePos.m_loc);
  28.     unsigned pos = treePos.m_pos;
  29.     if (node.getOccup() < tree.m_maxOccup) {
  30.       // node has room
  31.       jam();
  32.       nodePushUp(node, pos, ent, RNIL);
  33.       return;
  34.     }
  35.     treeAddFull(frag, node, pos, ent);
  36.     return;
  37.   }
  38.   jam();
  39.   insertNode(node);
  40.   nodePushUp(node, 0, ent, RNIL);
  41.   node.setSide(2);
  42.   tree.m_root = node.m_loc;
  43. }
  44. /*
  45.  * Add entry when node is full.  Handle the case when there is g.l.b
  46.  * node in left subtree with room for one more.  It will receive the min
  47.  * entry of this node.  The min entry could be the entry to add.
  48.  */
  49. void
  50. Dbtux::treeAddFull(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent)
  51. {
  52.   TreeHead& tree = frag.m_tree;
  53.   TupLoc loc = lubNode.getLink(0);
  54.   if (loc != NullTupLoc) {
  55.     // find g.l.b node
  56.     NodeHandle glbNode(frag);
  57.     do {
  58.       jam();
  59.       selectNode(glbNode, loc);
  60.       loc = glbNode.getLink(1);
  61.     } while (loc != NullTupLoc);
  62.     if (glbNode.getOccup() < tree.m_maxOccup) {
  63.       // g.l.b node has room
  64.       jam();
  65.       Uint32 scanList = RNIL;
  66.       if (pos != 0) {
  67.         jam();
  68.         // add the new entry and return min entry
  69.         nodePushDown(lubNode, pos - 1, ent, scanList);
  70.       }
  71.       // g.l.b node receives min entry from l.u.b node
  72.       nodePushUp(glbNode, glbNode.getOccup(), ent, scanList);
  73.       return;
  74.     }
  75.     treeAddNode(frag, lubNode, pos, ent, glbNode, 1);
  76.     return;
  77.   }
  78.   treeAddNode(frag, lubNode, pos, ent, lubNode, 0);
  79. }
  80. /*
  81.  * Add entry when there is no g.l.b node in left subtree or the g.l.b
  82.  * node is full.  We must add a new left or right child node which
  83.  * becomes the new g.l.b node.
  84.  */
  85. void
  86. Dbtux::treeAddNode(Frag& frag, NodeHandle lubNode, unsigned pos, TreeEnt ent, NodeHandle parentNode, unsigned i)
  87. {
  88.   NodeHandle glbNode(frag);
  89.   insertNode(glbNode);
  90.   // connect parent and child
  91.   parentNode.setLink(i, glbNode.m_loc);
  92.   glbNode.setLink(2, parentNode.m_loc);
  93.   glbNode.setSide(i);
  94.   Uint32 scanList = RNIL;
  95.   if (pos != 0) {
  96.     jam();
  97.     // add the new entry and return min entry
  98.     nodePushDown(lubNode, pos - 1, ent, scanList);
  99.   }
  100.   // g.l.b node receives min entry from l.u.b node
  101.   nodePushUp(glbNode, 0, ent, scanList);
  102.   // re-balance the tree
  103.   treeAddRebalance(frag, parentNode, i);
  104. }
  105. /*
  106.  * Re-balance tree after adding a node.  The process starts with the
  107.  * parent of the added node.
  108.  */
  109. void
  110. Dbtux::treeAddRebalance(Frag& frag, NodeHandle node, unsigned i)
  111. {
  112.   while (true) {
  113.     // height of subtree i has increased by 1
  114.     int j = (i == 0 ? -1 : +1);
  115.     int b = node.getBalance();
  116.     if (b == 0) {
  117.       // perfectly balanced
  118.       jam();
  119.       node.setBalance(j);
  120.       // height change propagates up
  121.     } else if (b == -j) {
  122.       // height of shorter subtree increased
  123.       jam();
  124.       node.setBalance(0);
  125.       // height of tree did not change - done
  126.       break;
  127.     } else if (b == j) {
  128.       // height of longer subtree increased
  129.       jam();
  130.       NodeHandle childNode(frag);
  131.       selectNode(childNode, node.getLink(i));
  132.       int b2 = childNode.getBalance();
  133.       if (b2 == b) {
  134.         jam();
  135.         treeRotateSingle(frag, node, i);
  136.       } else if (b2 == -b) {
  137.         jam();
  138.         treeRotateDouble(frag, node, i);
  139.       } else {
  140.         // height of subtree increased so it cannot be perfectly balanced
  141.         ndbrequire(false);
  142.       }
  143.       // height of tree did not increase - done
  144.       break;
  145.     } else {
  146.       ndbrequire(false);
  147.     }
  148.     TupLoc parentLoc = node.getLink(2);
  149.     if (parentLoc == NullTupLoc) {
  150.       jam();
  151.       // root node - done
  152.       break;
  153.     }
  154.     i = node.getSide();
  155.     selectNode(node, parentLoc);
  156.   }
  157. }
  158. /*
  159.  * Remove entry.  Optimize for nodes with slack.  Handle the case when
  160.  * there is no underflow i.e. occupancy remains at least minOccup.  For
  161.  * interior nodes this is a requirement.  For others it means that we do
  162.  * not need to consider merge of semi-leaf and leaf.
  163.  */
  164. void
  165. Dbtux::treeRemove(Frag& frag, TreePos treePos)
  166. {
  167.   TreeHead& tree = frag.m_tree;
  168.   unsigned pos = treePos.m_pos;
  169.   NodeHandle node(frag);
  170.   selectNode(node, treePos.m_loc);
  171.   TreeEnt ent;
  172.   if (node.getOccup() > tree.m_minOccup) {
  173.     // no underflow in any node type
  174.     jam();
  175.     nodePopDown(node, pos, ent, 0);
  176.     return;
  177.   }
  178.   if (node.getChilds() == 2) {
  179.     // underflow in interior node
  180.     jam();
  181.     treeRemoveInner(frag, node, pos);
  182.     return;
  183.   }
  184.   // remove entry in semi/leaf
  185.   nodePopDown(node, pos, ent, 0);
  186.   if (node.getLink(0) != NullTupLoc) {
  187.     jam();
  188.     treeRemoveSemi(frag, node, 0);
  189.     return;
  190.   }
  191.   if (node.getLink(1) != NullTupLoc) {
  192.     jam();
  193.     treeRemoveSemi(frag, node, 1);
  194.     return;
  195.   }
  196.   treeRemoveLeaf(frag, node);
  197. }
  198. /*
  199.  * Remove entry when interior node underflows.  There is g.l.b node in
  200.  * left subtree to borrow an entry from.  The max entry of the g.l.b
  201.  * node becomes the min entry of this node.
  202.  */
  203. void
  204. Dbtux::treeRemoveInner(Frag& frag, NodeHandle lubNode, unsigned pos)
  205. {
  206.   TreeHead& tree = frag.m_tree;
  207.   TreeEnt ent;
  208.   // find g.l.b node
  209.   NodeHandle glbNode(frag);
  210.   TupLoc loc = lubNode.getLink(0);
  211.   do {
  212.     jam();
  213.     selectNode(glbNode, loc);
  214.     loc = glbNode.getLink(1);
  215.   } while (loc != NullTupLoc);
  216.   // borrow max entry from semi/leaf
  217.   Uint32 scanList = RNIL;
  218.   nodePopDown(glbNode, glbNode.getOccup() - 1, ent, &scanList);
  219.   nodePopUp(lubNode, pos, ent, scanList);
  220.   if (glbNode.getLink(0) != NullTupLoc) {
  221.     jam();
  222.     treeRemoveSemi(frag, glbNode, 0);
  223.     return;
  224.   }
  225.   treeRemoveLeaf(frag, glbNode);
  226. }
  227. /*
  228.  * Handle semi-leaf after removing an entry.  Move entries from leaf to
  229.  * semi-leaf to bring semi-leaf occupancy above minOccup, if possible.
  230.  * The leaf may become empty.
  231.  */
  232. void
  233. Dbtux::treeRemoveSemi(Frag& frag, NodeHandle semiNode, unsigned i)
  234. {
  235.   TreeHead& tree = frag.m_tree;
  236.   ndbrequire(semiNode.getChilds() < 2);
  237.   TupLoc leafLoc = semiNode.getLink(i);
  238.   NodeHandle leafNode(frag);
  239.   selectNode(leafNode, leafLoc);
  240.   if (semiNode.getOccup() < tree.m_minOccup) {
  241.     jam();
  242.     unsigned cnt = min(leafNode.getOccup(), tree.m_minOccup - semiNode.getOccup());
  243.     nodeSlide(semiNode, leafNode, cnt, i);
  244.     if (leafNode.getOccup() == 0) {
  245.       // remove empty leaf
  246.       jam();
  247.       treeRemoveNode(frag, leafNode);
  248.     }
  249.   }
  250. }
  251. /*
  252.  * Handle leaf after removing an entry.  If parent is semi-leaf, move
  253.  * entries to it as in the semi-leaf case.  If parent is interior node,
  254.  * do nothing.
  255.  */
  256. void
  257. Dbtux::treeRemoveLeaf(Frag& frag, NodeHandle leafNode)
  258. {
  259.   TreeHead& tree = frag.m_tree;
  260.   TupLoc parentLoc = leafNode.getLink(2);
  261.   if (parentLoc != NullTupLoc) {
  262.     jam();
  263.     NodeHandle parentNode(frag);
  264.     selectNode(parentNode, parentLoc);
  265.     unsigned i = leafNode.getSide();
  266.     if (parentNode.getLink(1 - i) == NullTupLoc) {
  267.       // parent is semi-leaf
  268.       jam();
  269.       if (parentNode.getOccup() < tree.m_minOccup) {
  270.         jam();
  271.         unsigned cnt = min(leafNode.getOccup(), tree.m_minOccup - parentNode.getOccup());
  272.         nodeSlide(parentNode, leafNode, cnt, i);
  273.       }
  274.     }
  275.   }
  276.   if (leafNode.getOccup() == 0) {
  277.     jam();
  278.     // remove empty leaf
  279.     treeRemoveNode(frag, leafNode);
  280.   }
  281. }
  282. /*
  283.  * Remove empty leaf.
  284.  */
  285. void
  286. Dbtux::treeRemoveNode(Frag& frag, NodeHandle leafNode)
  287. {
  288.   TreeHead& tree = frag.m_tree;
  289.   ndbrequire(leafNode.getChilds() == 0);
  290.   TupLoc parentLoc = leafNode.getLink(2);
  291.   unsigned i = leafNode.getSide();
  292.   deleteNode(leafNode);
  293.   if (parentLoc != NullTupLoc) {
  294.     jam();
  295.     NodeHandle parentNode(frag);
  296.     selectNode(parentNode, parentLoc);
  297.     parentNode.setLink(i, NullTupLoc);
  298.     // re-balance the tree
  299.     treeRemoveRebalance(frag, parentNode, i);
  300.     return;
  301.   }
  302.   // tree is now empty
  303.   tree.m_root = NullTupLoc;
  304. }
  305. /*
  306.  * Re-balance tree after removing a node.  The process starts with the
  307.  * parent of the removed node.
  308.  */
  309. void
  310. Dbtux::treeRemoveRebalance(Frag& frag, NodeHandle node, unsigned i)
  311. {
  312.   while (true) {
  313.     // height of subtree i has decreased by 1
  314.     int j = (i == 0 ? -1 : +1);
  315.     int b = node.getBalance();
  316.     if (b == 0) {
  317.       // perfectly balanced
  318.       jam();
  319.       node.setBalance(-j);
  320.       // height of tree did not change - done
  321.       return;
  322.     } else if (b == j) {
  323.       // height of longer subtree has decreased
  324.       jam();
  325.       node.setBalance(0);
  326.       // height change propagates up
  327.     } else if (b == -j) {
  328.       // height of shorter subtree has decreased
  329.       jam();
  330.       // child on the other side
  331.       NodeHandle childNode(frag);
  332.       selectNode(childNode, node.getLink(1 - i));
  333.       int b2 = childNode.getBalance();
  334.       if (b2 == b) {
  335.         jam();
  336.         treeRotateSingle(frag, node, 1 - i);
  337.         // height of tree decreased and propagates up
  338.       } else if (b2 == -b) {
  339.         jam();
  340.         treeRotateDouble(frag, node, 1 - i);
  341.         // height of tree decreased and propagates up
  342.       } else {
  343.         jam();
  344.         treeRotateSingle(frag, node, 1 - i);
  345.         // height of tree did not change - done
  346.         return;
  347.       }
  348.     } else {
  349.       ndbrequire(false);
  350.     }
  351.     TupLoc parentLoc = node.getLink(2);
  352.     if (parentLoc == NullTupLoc) {
  353.       jam();
  354.       // root node - done
  355.       return;
  356.     }
  357.     i = node.getSide();
  358.     selectNode(node, parentLoc);
  359.   }
  360. }
  361. /*
  362.  * Single rotation about node 5.  One of LL (i=0) or RR (i=1).
  363.  *
  364.  *           0                   0
  365.  *           |                   |
  366.  *           5       ==>         3
  367.  *         /                  /   
  368.  *        3     6             2     5
  369.  *       /                  /     / 
  370.  *      2   4               1     4   6
  371.  *     /
  372.  *    1
  373.  *
  374.  * In this change 5,3 and 2 must always be there. 0, 1, 2, 4 and 6 are
  375.  * all optional. If 4 are there it changes side.
  376. */
  377. void
  378. Dbtux::treeRotateSingle(Frag& frag, NodeHandle& node, unsigned i)
  379. {
  380.   ndbrequire(i <= 1);
  381.   /*
  382.   5 is the old top node that have been unbalanced due to an insert or
  383.   delete. The balance is still the old balance before the update.
  384.   Verify that bal5 is 1 if RR rotate and -1 if LL rotate.
  385.   */
  386.   NodeHandle node5 = node;
  387.   const TupLoc loc5 = node5.m_loc;
  388.   const int bal5 = node5.getBalance();
  389.   const int side5 = node5.getSide();
  390.   ndbrequire(bal5 + (1 - i) == i);
  391.   /*
  392.   3 is the new root of this part of the tree which is to swap place with
  393.   node 5. For an insert to cause this it must have the same balance as 5.
  394.   For deletes it can have the balance 0.
  395.   */
  396.   TupLoc loc3 = node5.getLink(i);
  397.   NodeHandle node3(frag);
  398.   selectNode(node3, loc3);
  399.   const int bal3 = node3.getBalance();
  400.   /*
  401.   2 must always be there but is not changed. Thus we mereley check that it
  402.   exists.
  403.   */
  404.   ndbrequire(node3.getLink(i) != NullTupLoc);
  405.   /*
  406.   4 is not necessarily there but if it is there it will move from one
  407.   side of 3 to the other side of 5. For LL it moves from the right side
  408.   to the left side and for RR it moves from the left side to the right
  409.   side. This means that it also changes parent from 3 to 5.
  410.   */
  411.   TupLoc loc4 = node3.getLink(1 - i);
  412.   NodeHandle node4(frag);
  413.   if (loc4 != NullTupLoc) {
  414.     jam();
  415.     selectNode(node4, loc4);
  416.     ndbrequire(node4.getSide() == (1 - i) &&
  417.                node4.getLink(2) == loc3);
  418.     node4.setSide(i);
  419.     node4.setLink(2, loc5);
  420.   }//if
  421.   /*
  422.   Retrieve the address of 5's parent before it is destroyed
  423.   */
  424.   TupLoc loc0 = node5.getLink(2);
  425.   /*
  426.   The next step is to perform the rotation. 3 will inherit 5's parent 
  427.   and side. 5 will become a child of 3 on the right side for LL and on
  428.   the left side for RR.
  429.   5 will get 3 as the parent. It will get 4 as a child and it will be
  430.   on the right side of 3 for LL and left side of 3 for RR.
  431.   The final step of the rotate is to check whether 5 originally had any
  432.   parent. If it had not then 3 is the new root node.
  433.   We will also verify some preconditions for the change to occur.
  434.   1. 3 must have had 5 as parent before the change.
  435.   2. 3's side is left for LL and right for RR before change.
  436.   */
  437.   ndbrequire(node3.getLink(2) == loc5);
  438.   ndbrequire(node3.getSide() == i);
  439.   node3.setLink(1 - i, loc5);
  440.   node3.setLink(2, loc0);
  441.   node3.setSide(side5);
  442.   node5.setLink(i, loc4);
  443.   node5.setLink(2, loc3);
  444.   node5.setSide(1 - i);
  445.   if (loc0 != NullTupLoc) {
  446.     jam();
  447.     NodeHandle node0(frag);
  448.     selectNode(node0, loc0);
  449.     node0.setLink(side5, loc3);
  450.   } else {
  451.     jam();
  452.     frag.m_tree.m_root = loc3;
  453.   }//if
  454.   /* The final step of the change is to update the balance of 3 and
  455.   5 that changed places. There are two cases here. The first case is
  456.   when 3 unbalanced in the same direction by an insert or a delete.
  457.   In this case the changes will make the tree balanced again for both
  458.   3 and 5.
  459.   The second case only occurs at deletes. In this case 3 starts out
  460.   balanced. In the figure above this could occur if 4 starts out with
  461.   a right node and the rotate is triggered by a delete of 6's only child.
  462.   In this case 5 will change balance but still be unbalanced and 3 will
  463.   be unbalanced in the opposite direction of 5.
  464.   */
  465.   if (bal3 == bal5) {
  466.     jam();
  467.     node3.setBalance(0);
  468.     node5.setBalance(0);
  469.   } else if (bal3 == 0) {
  470.     jam();
  471.     node3.setBalance(-bal5);
  472.     node5.setBalance(bal5);
  473.   } else {
  474.     ndbrequire(false);
  475.   }//if
  476.   /*
  477.   Set node to 3 as return parameter for enabling caller to continue
  478.   traversing the tree.
  479.   */
  480.   node = node3;
  481. }
  482. /*
  483.  * Double rotation about node 6.  One of LR (i=0) or RL (i=1).
  484.  *
  485.  *        0                  0
  486.  *        |                  |
  487.  *        6      ==>         4
  488.  *       /                /   
  489.  *      2   7             2     6
  490.  *     /                /    / 
  491.  *    1   4             1   3 5   7
  492.  *       / 
  493.  *      3   5
  494.  *
  495.  * In this change 6, 2 and 4 must be there, all others are optional.
  496.  * We will start by proving a Lemma.
  497.  * Lemma:
  498.  *   The height of the sub-trees 1 and 7 and the maximum height of the
  499.  *   threes from 3 and 5 are all the same.
  500.  * Proof:
  501.  *   maxheight(3,5) is defined as the maximum height of 3 and 5.
  502.  *   If height(7) > maxheight(3,5) then the AVL condition is ok and we
  503.  *   don't need to perform a rotation.
  504.  *   If height(7) < maxheight(3,5) then the balance of 6 would be at least
  505.  *   -3 which cannot happen in an AVL tree even before a rotation.
  506.  *   Thus we conclude that height(7) == maxheight(3,5)
  507.  *
  508.  *   The next step is to prove that the height of 1 is equal to maxheight(3,5).
  509.  *   If height(1) - 1 > maxheight(3,5) then we would have
  510.  *   balance in 6 equal to -3 at least which cannot happen in an AVL-tree.
  511.  *   If height(1) - 1 = maxheight(3,5) then we should have solved the
  512.  *   unbalance with a single rotate and not with a double rotate.
  513.  *   If height(1) + 1 = maxheight(3,5) then we would be doing a rotate
  514.  *   with node 2 as the root of the rotation.
  515.  *   If height(1) + k = maxheight(3,5) where k >= 2 then the tree could not have
  516.  *   been an AVL-tree before the insert or delete.
  517.  *   Thus we conclude that height(1) = maxheight(3,5)
  518.  *
  519.  *   Thus we conclude that height(1) = maxheight(3,5) = height(7).
  520.  *
  521.  * Observation:
  522.  *   The balance of node 4 before the rotation can be any (-1, 0, +1).
  523.  *
  524.  * The following changes are needed:
  525.  * Node 6:
  526.  * 1) Changes parent from 0 -> 4
  527.  * 2) 1 - i link stays the same
  528.  * 3) i side link is derived from 1 - i side link from 4
  529.  * 4) Side is set to 1 - i
  530.  * 5) Balance change:
  531.  *    If balance(4) == 0 then balance(6) = 0
  532.  *      since height(3) = height(5) = maxheight(3,5) = height(7)
  533.  *    If balance(4) == +1 then balance(6) = 0 
  534.  *      since height(5) = maxheight(3,5) = height(7)
  535.  *    If balance(4) == -1 then balance(6) = 1
  536.  *      since height(5) + 1 = maxheight(3,5) = height(7)
  537.  *
  538.  * Node 2:
  539.  * 1) Changes parent from 6 -> 4
  540.  * 2) i side link stays the same
  541.  * 3) 1 - i side link is derived from i side link of 4
  542.  * 4) Side is set to i (thus not changed)
  543.  * 5) Balance change:
  544.  *    If balance(4) == 0 then balance(2) = 0
  545.  *      since height(3) = height(5) = maxheight(3,5) = height(1)
  546.  *    If balance(4) == -1 then balance(2) = 0 
  547.  *      since height(3) = maxheight(3,5) = height(1)
  548.  *    If balance(4) == +1 then balance(6) = 1
  549.  *      since height(3) + 1 = maxheight(3,5) = height(1)
  550.  *
  551.  * Node 4:
  552.  * 1) Inherits parent from 6
  553.  * 2) i side link is 2
  554.  * 3) 1 - i side link is 6
  555.  * 4) Side is inherited from 6
  556.  * 5) Balance(4) = 0 independent of previous balance
  557.  *    Proof:
  558.  *      If height(1) = 0 then only 2, 4 and 6 are involved and then it is
  559.  *      trivially true.
  560.  *      If height(1) >= 1 then we are sure that 1 and 7 exist with the same
  561.  *      height and that if 3 and 5 exist they are of the same height as 1 and
  562.  *      7 and thus we know that 4 is balanced since newheight(2) = newheight(6).
  563.  *
  564.  * If Node 3 exists:
  565.  * 1) Change parent from 4 to 2
  566.  * 2) Change side from i to 1 - i
  567.  *
  568.  * If Node 5 exists:
  569.  * 1) Change parent from 4 to 6
  570.  * 2) Change side from 1 - i to i
  571.  * 
  572.  * If Node 0 exists:
  573.  * 1) previous link to 6 is replaced by link to 4 on proper side
  574.  *
  575.  * Node 1 and 7 needs no changes at all.
  576.  * 
  577.  * Some additional requires are that balance(2) = - balance(6) = -1/+1 since
  578.  * otherwise we would do a single rotate.
  579.  *
  580.  * The balance(6) is -1 if i == 0 and 1 if i == 1
  581.  *
  582.  */
  583. void
  584. Dbtux::treeRotateDouble(Frag& frag, NodeHandle& node, unsigned i)
  585. {
  586.   TreeHead& tree = frag.m_tree;
  587.   // old top node
  588.   NodeHandle node6 = node;
  589.   const TupLoc loc6 = node6.m_loc;
  590.   // the un-updated balance
  591.   const int bal6 = node6.getBalance();
  592.   const unsigned side6 = node6.getSide();
  593.   // level 1
  594.   TupLoc loc2 = node6.getLink(i);
  595.   NodeHandle node2(frag);
  596.   selectNode(node2, loc2);
  597.   const int bal2 = node2.getBalance();
  598.   // level 2
  599.   TupLoc loc4 = node2.getLink(1 - i);
  600.   NodeHandle node4(frag);
  601.   selectNode(node4, loc4);
  602.   const int bal4 = node4.getBalance();
  603.   ndbrequire(i <= 1);
  604.   ndbrequire(bal6 + (1 - i) == i);
  605.   ndbrequire(bal2 == -bal6);
  606.   ndbrequire(node2.getLink(2) == loc6);
  607.   ndbrequire(node2.getSide() == i);
  608.   ndbrequire(node4.getLink(2) == loc2);
  609.   // level 3
  610.   TupLoc loc3 = node4.getLink(i);
  611.   TupLoc loc5 = node4.getLink(1 - i);
  612.   // fill up leaf before it becomes internal
  613.   if (loc3 == NullTupLoc && loc5 == NullTupLoc) {
  614.     jam();
  615.     if (node4.getOccup() < tree.m_minOccup) {
  616.       jam();
  617.       unsigned cnt = tree.m_minOccup - node4.getOccup();
  618.       ndbrequire(cnt < node2.getOccup());
  619.       nodeSlide(node4, node2, cnt, i);
  620.       ndbrequire(node4.getOccup() >= tree.m_minOccup);
  621.       ndbrequire(node2.getOccup() != 0);
  622.     }
  623.   } else {
  624.     if (loc3 != NullTupLoc) {
  625.       jam();
  626.       NodeHandle node3(frag);
  627.       selectNode(node3, loc3);
  628.       node3.setLink(2, loc2);
  629.       node3.setSide(1 - i);
  630.     }
  631.     if (loc5 != NullTupLoc) {
  632.       jam();
  633.       NodeHandle node5(frag);
  634.       selectNode(node5, loc5);
  635.       node5.setLink(2, node6.m_loc);
  636.       node5.setSide(i);
  637.     }
  638.   }
  639.   // parent
  640.   TupLoc loc0 = node6.getLink(2);
  641.   NodeHandle node0(frag);
  642.   // perform the rotation
  643.   node6.setLink(i, loc5);
  644.   node6.setLink(2, loc4);
  645.   node6.setSide(1 - i);
  646.   node2.setLink(1 - i, loc3);
  647.   node2.setLink(2, loc4);
  648.   node4.setLink(i, loc2);
  649.   node4.setLink(1 - i, loc6);
  650.   node4.setLink(2, loc0);
  651.   node4.setSide(side6);
  652.   if (loc0 != NullTupLoc) {
  653.     jam();
  654.     selectNode(node0, loc0);
  655.     node0.setLink(side6, loc4);
  656.   } else {
  657.     jam();
  658.     frag.m_tree.m_root = loc4;
  659.   }
  660.   // set balance of changed nodes
  661.   node4.setBalance(0);
  662.   if (bal4 == 0) {
  663.     jam();
  664.     node2.setBalance(0);
  665.     node6.setBalance(0);
  666.   } else if (bal4 == -bal2) {
  667.     jam();
  668.     node2.setBalance(0);
  669.     node6.setBalance(bal2);
  670.   } else if (bal4 == bal2) {
  671.     jam();
  672.     node2.setBalance(-bal2);
  673.     node6.setBalance(0);
  674.   } else {
  675.     ndbrequire(false);
  676.   }
  677.   // new top node
  678.   node = node4;
  679. }