merged trunk changes into the branch
diff --git a/mavibot/img/BTree.graphml b/mavibot/img/BTree.graphml
index fb610cd..ed6d1bb 100644
--- a/mavibot/img/BTree.graphml
+++ b/mavibot/img/BTree.graphml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
- <!--Created by yFiles for Java 2.10-->
+ <!--Created by yEd 3.12.2-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
@@ -38,7 +38,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="-302.008" y="97.3560000000002"/>
<y:Fill color="#CCFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999984" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999967" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -53,10 +53,10 @@
<node id="n2">
<data key="d6">
<y:ShapeNode>
- <y:Geometry height="20.0" width="110.69599999999997" x="-412.7679999999999" y="-49.75199999999998"/>
+ <y:Geometry height="20.0" width="110.69599999999997" x="-232.89782271999988" y="-7.503999999999962"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499985" y="0.93359375">BTree header 1<y:LabelModel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499956" y="0.93359375">BTree header 1<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
@@ -73,7 +73,7 @@
<y:Geometry height="31.26399999999998" width="6.4523545600000105" x="-302.008" y="97.3560000000002"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="8.4326171875" x="-0.9901313137499947" y="-0.5008125000000234">N
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="8.4326171875" x="-0.9901313137499983" y="-0.5008125000000234">N
E
X
T<y:LabelModel>
@@ -93,7 +93,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="-59.54399999999973" y="96.84400000000018"/>
<y:Fill color="#00CCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999995" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.80217727999998" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -149,7 +149,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="-241.39199999999994" y="97.3560000000002"/>
<y:Fill color="#CCFFFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.80217727999998" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999995" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -187,7 +187,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="1.072000000000287" y="96.84400000000018"/>
<y:Fill color="#00CCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999995" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999984" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -205,7 +205,7 @@
<y:Geometry height="31.26399999999998" width="6.4523545600000105" x="1.072000000000287" y="96.84400000000018"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="8.4326171875" x="-0.9901313137499983" y="-0.5008125000000092">N
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="8.4326171875" x="-0.9901313137499947" y="-0.5008125000000092">N
E
X
T<y:LabelModel>
@@ -225,7 +225,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="182.9200000000004" y="96.84400000000018"/>
<y:Fill color="#3366FF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999967" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999995" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -243,7 +243,7 @@
<y:Geometry height="31.26399999999998" width="55.60435455999997" x="61.68800000000033" y="96.8440000000002"/>
<y:Fill color="#00CCFF" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.802177279999967" y="13.63199999999999">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="25.80217727999998" y="13.63199999999999">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -261,7 +261,7 @@
<y:Geometry height="31.26399999999998" width="6.4523545600000105" x="-295.55564544" y="97.3560000000002"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="7.626953125" x="-0.5872992824999947" y="-0.5008125000000234">S
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="6" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="32.265625" modelName="custom" textColor="#000000" visible="true" width="7.626953125" x="-0.5872992824999983" y="-0.5008125000000234">S
I
Z
E<y:LabelModel>
@@ -381,7 +381,7 @@
<y:Geometry height="5.424000000000007" width="5.424000000000007" x="-180.26182271999988" y="65.49600000000007"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="0.7120000000000033" y="0.7120000000000033">
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="custom" textColor="#000000" visible="true" width="4.0" x="0.7119999999999891" y="0.7120000000000033">
<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
@@ -432,10 +432,10 @@
<node id="n22">
<data key="d6">
<y:ShapeNode>
- <y:Geometry height="20.0" width="110.69599999999997" x="-412.7679999999999" y="-24.503999999999962"/>
+ <y:Geometry height="20.0" width="110.69599999999997" x="1.072000000000287" y="-7.503999999999962"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499985" y="0.93359375">BTree header 2<y:LabelModel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499956" y="0.93359375">BTree header 2<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
@@ -449,10 +449,10 @@
<node id="n23">
<data key="d6">
<y:ShapeNode>
- <y:Geometry height="20.0" width="110.69599999999997" x="-412.7679999999999" y="0.7440000000000566"/>
+ <y:Geometry height="20.0" width="110.69599999999997" x="188.44435456000048" y="-7.503999999999962"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#000000" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499985" y="0.9335937499999716">BTree header 3<y:LabelModel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="91.861328125" x="9.417335937499956" y="0.93359375">BTree header 3<y:LabelModel>
<y:SmartNodeLabelModel distance="4.0"/>
</y:LabelModel>
<y:ModelParameter>
@@ -634,10 +634,18 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="-55.347999999999985" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="-274.20582272" y="-39.75199999999998"/>
+ <y:Point x="-274.20582272" y="2.4960000000000377"/>
</y:Path>
<y:LineStyle color="#FF0000" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="26.69921875" x="-54.61727596707033" y="8.362964129197486">info<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.21572713406743133" segment="-1"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
@@ -646,10 +654,18 @@
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="-31.741822719999732" y="-14.503999999999962"/>
+ <y:Point x="-31.741822719999732" y="2.4960000000000377"/>
</y:Path>
<y:LineStyle color="#FF0000" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="26.69921875" x="-46.16343212170262" y="7.079135975280693">info<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.2011113821065497" segment="-1"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
@@ -657,52 +673,53 @@
<edge id="e9" source="n23" target="n11">
<data key="d10">
<y:PolyLineEdge>
- <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="210.7221772800004" y="10.744000000000057"/>
- </y:Path>
+ <y:Path sx="-33.07017728000005" sy="-9.988187500000038" tx="0.0" ty="0.0"/>
<y:LineStyle color="#FF0000" type="line" width="2.0"/>
<y:Arrows source="none" target="standard"/>
+ <y:EdgeLabel alignment="center" configuration="AutoFlippingLabel" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" visible="true" width="26.69921875" x="-13.349615322538682" y="4.983726211547889">info<y:LabelModel>
+ <y:SmartEdgeLabelModel autoRotationEnabled="false" defaultAngle="0.0" defaultDistance="10.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartEdgeLabelModelParameter angle="0.0" distance="30.0" distanceToCenter="true" position="center" ratio="0.0" segment="0"/>
+ </y:ModelParameter>
+ <y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/>
+ </y:EdgeLabel>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
- <edge id="e10" source="n1" target="n24">
+ <edge id="e10" source="n2" target="n24">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="-274.20582272" y="162.0"/>
- <y:Point x="-92.35782271999983" y="162.0"/>
+ <y:Point x="-92.35782271999983" y="2.4960000000000377"/>
</y:Path>
- <y:LineStyle color="#999999" type="line" width="3.0"/>
+ <y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
- <edge id="e11" source="n4" target="n25">
+ <edge id="e11" source="n22" target="n25">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
<y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="-31.741822719999746" y="163.0"/>
- <y:Point x="150.10617728000037" y="163.0"/>
+ <y:Point x="150.10617728000034" y="2.4960000000000377"/>
</y:Path>
- <y:LineStyle color="#999999" type="line" width="3.0"/>
+ <y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
</data>
</edge>
- <edge id="e12" source="n11" target="n26">
+ <edge id="e12" source="n23" target="n26">
<data key="d9"/>
<data key="d10">
<y:PolyLineEdge>
- <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
- <y:Point x="210.7221772800004" y="163.5031185031185"/>
- <y:Point x="271.3381772800004" y="163.5031185031185"/>
- </y:Path>
- <y:LineStyle color="#999999" type="line" width="3.0"/>
+ <y:Path sx="27.54582271999996" sy="10.011812499999962" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#FF0000" type="line" width="1.0"/>
<y:Arrows source="none" target="standard"/>
<y:BendStyle smoothed="false"/>
</y:PolyLineEdge>
diff --git a/mavibot/img/BTree.png b/mavibot/img/BTree.png
index 5dcb295..783abb5 100644
--- a/mavibot/img/BTree.png
+++ b/mavibot/img/BTree.png
Binary files differ
diff --git a/mavibot/img/RMHeader.graphml b/mavibot/img/RMHeader.graphml
index 517ff48..784ac8e 100644
--- a/mavibot/img/RMHeader.graphml
+++ b/mavibot/img/RMHeader.graphml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
- <!--Created by yFiles for Java 2.10-->
+ <!--Created by yEd 3.12.2-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
@@ -17,10 +17,10 @@
<node id="n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="152.0" width="229.0" x="648.5" y="248.0"/>
+ <y:Geometry height="263.0" width="229.0" x="648.5" y="248.0"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="139.4453125" x="-143.4453125" y="4.0">RecordManager Header</y:NodeLabel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="139.4453125" x="44.77734375" y="-28.06640625">RecordManager Header</y:NodeLabel>
</y:GenericNode>
</data>
</node>
@@ -426,7 +426,424 @@
<y:Geometry height="30.0" width="216.0" x="654.5" y="362.0"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="79.7734375" x="4.0" y="5.93359375">LastFreePage</y:NodeLabel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="187.99609375" x="4.0" y="5.93359375">Current B-tree of B-trees offset</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n29">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="654.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n30">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="681.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n31">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="708.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n32">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="735.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n33">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="762.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n34">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="789.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n35">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="816.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n36">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="843.5" y="398.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n37">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="654.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n38">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="681.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n39">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="708.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n40">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="735.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n41">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="762.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n42">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="789.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n43">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="816.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n44">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="843.5" y="435.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n45">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="654.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n46">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="681.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n47">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="708.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n48">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="735.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n49">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="762.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n50">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="789.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n51">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="816.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n52">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="843.5" y="471.5"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n53">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="655.0" y="398.5"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="192.6484375" x="4.0" y="5.93359375">Previous B-tree of B-trees offset</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n54">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="655.0" y="435.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="207.958984375" x="4.0" y="5.93359375">Current Copied Pages B-tree offset</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n55">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="654.5" y="471.5"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="207.958984375" x="4.0" y="5.93359375">Current Copied Pages B-tree offset</y:NodeLabel>
</y:GenericNode>
</data>
</node>
diff --git a/mavibot/img/RMHeader.png b/mavibot/img/RMHeader.png
index 145e1c2..937969d 100644
--- a/mavibot/img/RMHeader.png
+++ b/mavibot/img/RMHeader.png
Binary files differ
diff --git a/mavibot/img/btreeHeader.graphml b/mavibot/img/btreeHeader.graphml
index 999c2eb..3bcdca6 100644
--- a/mavibot/img/btreeHeader.graphml
+++ b/mavibot/img/btreeHeader.graphml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
- <!--Created by yFiles for Java 2.10-->
+ <!--Created by yFiles for Java 2.11-->
<key for="graphml" id="d0" yfiles.type="resources"/>
<key for="port" id="d1" yfiles.type="portgraphics"/>
<key for="port" id="d2" yfiles.type="portgeometry"/>
@@ -17,10 +17,10 @@
<node id="n0">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="346.0256" width="229.0" x="93.0" y="24.0"/>
+ <y:Geometry height="157.0256" width="229.0" x="93.0" y="24.0"/>
<y:Fill color="#FFCC99" transparent="false"/>
<y:BorderStyle hasColor="false" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="81.84765625" x="-85.84765625" y="4.0">BTree Header</y:NodeLabel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="81.84765625" x="73.576171875" y="-22.1328125">BTree Header</y:NodeLabel>
</y:GenericNode>
</data>
</node>
@@ -444,34 +444,27 @@
<node id="n28">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="181.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
+ <y:Geometry height="199.0256" width="229.0" x="93.0" y="211.0256"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="59.458984375" x="73.576171875" y="-22.1328125">BTreeInfo</y:NodeLabel>
</y:GenericNode>
</data>
</node>
<node id="n29">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="126.0" y="181.0"/>
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="220.0384"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
-<y:LabelModel>
- <y:SmartNodeLabelModel distance="4.0"/>
- </y:LabelModel>
- <y:ModelParameter>
- <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
- </y:ModelParameter>
- </y:NodeLabel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
</y:GenericNode>
</data>
</node>
<node id="n30">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="153.0" y="181.0"/>
+ <y:Geometry height="30.0" width="27.0" x="126.0" y="220.0384"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -488,37 +481,7 @@
<node id="n31">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="180.0" y="181.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n32">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="108.0" x="99.0" y="181.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="87.6953125" x="4.0" y="5.93359375">BTreePageSize</y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n33">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="219.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n34">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="126.0" y="219.0"/>
+ <y:Geometry height="30.0" width="27.0" x="153.0" y="220.0384"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -532,10 +495,40 @@
</y:GenericNode>
</data>
</node>
+ <node id="n32">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="180.0" y="220.0384"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n33">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="108.0" x="99.0" y="220.0384"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="87.6953125" x="4.0" y="5.93359375">BTreePageSize</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n34">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="258.0384"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
<node id="n35">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="153.0" y="219.0"/>
+ <y:Geometry height="30.0" width="27.0" x="126.0" y="258.0384"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -552,70 +545,7 @@
<node id="n36">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="180.0" y="219.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n37">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="108.0" x="99.0" y="219.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="72.53125" x="4.0" y="5.93359375">BTree name</y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n38">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="219.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="31.1015625" y="5.93359375">
-<y:LabelModel>
- <y:SmartNodeLabelModel distance="4.0"/>
- </y:LabelModel>
- <y:ModelParameter>
- <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
- </y:ModelParameter>
- </y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n39">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="219.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="35.8984375" x="17.05078125" y="5.93359375">xyz...<y:LabelModel>
- <y:SmartNodeLabelModel distance="4.0"/>
- </y:LabelModel>
- <y:ModelParameter>
- <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
- </y:ModelParameter>
- </y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n40">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="257.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n41">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="126.0" y="257.0"/>
+ <y:Geometry height="30.0" width="27.0" x="153.0" y="258.0384"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -629,10 +559,73 @@
</y:GenericNode>
</data>
</node>
+ <node id="n37">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="180.0" y="258.0384"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n38">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="108.0" x="99.0" y="258.0384"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="72.53125" x="4.0" y="5.93359375">BTree name</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n39">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="258.0384"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="31.1015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n40">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="258.0384"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="35.8984375" x="17.05078125" y="5.93359375">xyz...<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n41">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="296.03839999999997"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
<node id="n42">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="153.0" y="257.0"/>
+ <y:Geometry height="30.0" width="27.0" x="126.0" y="296.03839999999997"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -649,70 +642,7 @@
<node id="n43">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="180.0" y="257.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n44">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="108.0" x="99.0" y="257.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="78.35546875" x="4.0" y="5.93359375">KeySerializer</y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n45">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="257.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="31.1015625" y="5.93359375">
-<y:LabelModel>
- <y:SmartNodeLabelModel distance="4.0"/>
- </y:LabelModel>
- <y:ModelParameter>
- <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
- </y:ModelParameter>
- </y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n46">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="257.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="35.8984375" x="17.05078125" y="5.93359375">xyz...<y:LabelModel>
- <y:SmartNodeLabelModel distance="4.0"/>
- </y:LabelModel>
- <y:ModelParameter>
- <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
- </y:ModelParameter>
- </y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
- <node id="n47">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="295.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
- </y:GenericNode>
- </data>
- </node>
- <node id="n48">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="126.0" y="295.0"/>
+ <y:Geometry height="30.0" width="27.0" x="153.0" y="296.03839999999997"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -726,10 +656,73 @@
</y:GenericNode>
</data>
</node>
+ <node id="n44">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="180.0" y="296.03839999999997"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n45">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="108.0" x="99.0" y="296.03839999999997"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="78.35546875" x="4.0" y="5.93359375">KeySerializer</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n46">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="296.03839999999997"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="31.1015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n47">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="296.03839999999997"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="35.8984375" x="17.05078125" y="5.93359375">xyz...<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n48">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="334.0383999999999"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
<node id="n49">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="153.0" y="295.0"/>
+ <y:Geometry height="30.0" width="27.0" x="126.0" y="334.0383999999999"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
@@ -746,27 +739,44 @@
<node id="n50">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="180.0" y="295.0"/>
+ <y:Geometry height="30.0" width="27.0" x="153.0" y="334.0383999999999"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n51">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="180.0" y="334.0383999999999"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-78.4619140625" y="5.93359375"/>
</y:GenericNode>
</data>
</node>
- <node id="n51">
+ <node id="n52">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="108.0" x="99.0" y="295.0"/>
+ <y:Geometry height="30.0" width="108.0" x="99.0" y="334.0383999999999"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle color="#0000FF" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="89.640625" x="4.0" y="5.93359375">ValueSerializer</y:NodeLabel>
</y:GenericNode>
</data>
</node>
- <node id="n52">
+ <node id="n53">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="295.0"/>
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="334.0383999999999"/>
<y:Fill color="#FFFF99" transparent="false"/>
<y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="31.1015625" y="5.93359375">
@@ -780,10 +790,10 @@
</y:GenericNode>
</data>
</node>
- <node id="n53">
+ <node id="n54">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="70.0" x="210.0" y="295.0"/>
+ <y:Geometry height="30.0" width="70.0" x="210.0" y="334.0383999999999"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle color="#0000FF" type="line" width="1.0"/>
<y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="35.8984375" x="17.05078125" y="5.93359375">xyz...<y:LabelModel>
@@ -796,7 +806,27 @@
</y:GenericNode>
</data>
</node>
- <node id="n54">
+ <node id="n55">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="372.0383999999999"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n56">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="27.0" x="99.0" y="372.0383999999999"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="78.7421875" x="4.0" y="5.93359375">dupsAllowed</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n57">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="99.0" y="143.0"/>
@@ -813,7 +843,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n55">
+ <node id="n58">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="126.0" y="143.0"/>
@@ -830,7 +860,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n56">
+ <node id="n59">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="153.0" y="143.0"/>
@@ -847,7 +877,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n57">
+ <node id="n60">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="180.0" y="143.0"/>
@@ -864,7 +894,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n58">
+ <node id="n61">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="207.0" y="143.0"/>
@@ -881,7 +911,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n59">
+ <node id="n62">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="234.0" y="143.0"/>
@@ -898,7 +928,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n60">
+ <node id="n63">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="261.0" y="143.0"/>
@@ -915,7 +945,7 @@
</y:GenericNode>
</data>
</node>
- <node id="n61">
+ <node id="n64">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNodeWithShadow">
<y:Geometry height="30.0" width="27.0" x="288.0" y="143.0"/>
@@ -925,36 +955,30 @@
</y:GenericNode>
</data>
</node>
- <node id="n62">
+ <node id="n65">
<data key="d6">
<y:GenericNode configuration="ShinyPlateNode">
<y:Geometry height="30.0" width="216.0" x="99.0" y="143.0"/>
<y:Fill hasColor="false" transparent="false"/>
<y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="102.349609375" x="4.0" y="5.93359375">NextBtreeHeader</y:NodeLabel>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="94.896484375" x="4.0" y="5.93359375">BTreeInfoOffset</y:NodeLabel>
</y:GenericNode>
</data>
</node>
- <node id="n63">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNodeWithShadow">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="333.0"/>
- <y:Fill color="#FFFF99" transparent="false"/>
- <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="4.0" x="11.5" y="13.0"/>
- </y:GenericNode>
+ <edge id="e0" source="n65" target="n28">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="373.0" y="158.0"/>
+ <y:Point x="373.0" y="310.5384"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
</data>
- </node>
- <node id="n64">
- <data key="d6">
- <y:GenericNode configuration="ShinyPlateNode">
- <y:Geometry height="30.0" width="27.0" x="99.0" y="333.0"/>
- <y:Fill hasColor="false" transparent="false"/>
- <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="78.7421875" x="4.0" y="5.93359375">dupsAllowed</y:NodeLabel>
- </y:GenericNode>
- </data>
- </node>
+ </edge>
</graph>
<data key="d0">
<y:Resources/>
diff --git a/mavibot/img/btreeHeader.png b/mavibot/img/btreeHeader.png
index cff1f78..2bc53ae 100644
--- a/mavibot/img/btreeHeader.png
+++ b/mavibot/img/btreeHeader.png
Binary files differ
diff --git a/mavibot/img/leaves.graphml b/mavibot/img/leaves.graphml
new file mode 100644
index 0000000..dbc796a
--- /dev/null
+++ b/mavibot/img/leaves.graphml
@@ -0,0 +1,1173 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="71.0" width="229.0" x="342.5" y="260.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="178.7734375" x="25.11328125" y="-29.06640625">Leaf with N/2 keys and values</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="266.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="71.0" width="229.0" x="342.5" y="374.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="164.892578125" x="32.0537109375" y="-29.06640625">Leaf with N keys and values</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n16">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n17">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n18">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n19">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="380.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n20">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="71.0" width="229.0" x="611.5" y="260.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="195.912109375" x="16.5439453125" y="-29.06640625">Root Leaf with one key and value</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n21">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="618.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n22">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="645.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n23">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="672.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n24">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="699.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n25">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="726.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n26">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="753.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n27">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="780.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n28">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="807.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n29">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="618.0" y="266.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n30">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="296.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n31">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="296.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n32">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="296.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n33">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="296.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n34">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n35">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n36">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n37">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n38">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="296.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n39">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n40">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n41">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n42">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n43">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n44">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n45">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n46">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="410.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n47">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="410.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n48">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="618.0" y="296.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n49">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="645.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n50">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="672.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n51">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="699.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n52">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="726.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n53">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="753.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n54">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="780.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n55">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="807.0" y="296.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n56">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="618.0" y="296.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n57">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="71.0" width="229.0" x="611.5" y="374.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="179.880859375" x="16.5439453125" y="-29.06640625">Root Leaf with no key or value</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n58">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="618.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n59">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="645.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n60">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="672.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n61">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="699.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n62">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="726.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n63">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="753.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n64">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="780.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n65">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="807.0" y="380.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n66">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="618.0" y="380.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n67">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="618.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n68">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="645.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n69">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="672.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n70">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="699.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n71">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="726.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n72">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="753.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n73">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="780.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n74">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="807.0" y="410.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n75">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="618.0" y="410.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/leaves.png b/mavibot/img/leaves.png
new file mode 100644
index 0000000..86a72bd
--- /dev/null
+++ b/mavibot/img/leaves.png
Binary files differ
diff --git a/mavibot/img/nodes.graphml b/mavibot/img/nodes.graphml
new file mode 100644
index 0000000..0ef2aa0
--- /dev/null
+++ b/mavibot/img/nodes.graphml
@@ -0,0 +1,468 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="42.0" width="229.0" x="342.5" y="260.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="123.14453125" x="52.927734375" y="-29.06640625">Node with N/2 keys </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="266.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="266.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="266.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="42.0" width="229.0" x="342.5" y="374.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="105.466796875" x="61.7666015625" y="-29.06640625">Node with N keys</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n16">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n17">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n18">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="380.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n19">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="380.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n20">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="42.0" width="229.0" x="342.5" y="488.0"/>
+ <y:Fill color="#FFCC99" transparent="false"/>
+ <y:BorderStyle hasColor="false" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="142.603515625" x="43.1982421875" y="-29.06640625">Root Node with one key</y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n21">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="349.0" y="494.0"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n22">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="376.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n23">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="403.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n24">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="430.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n25">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="457.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n26">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="484.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n27">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="511.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="custom" textColor="#000000" visible="true" width="7.796875" x="9.6015625" y="5.93359375">
+<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n28">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="27.0" x="538.0" y="494.0"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="free" modelPosition="anywhere" textColor="#000000" visible="true" width="4.0" x="-184.7802734375" y="5.93359375"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n29">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNode">
+ <y:Geometry height="30.0" width="216.0" x="349.0" y="494.0"/>
+ <y:Fill hasColor="false" transparent="false"/>
+ <y:BorderStyle color="#0000FF" type="line" width="1.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" hasText="false" height="4.0" modelName="internal" modelPosition="l" textColor="#000000" visible="true" width="4.0" x="4.0" y="13.0"/>
+ </y:GenericNode>
+ </data>
+ </node>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/nodes.png b/mavibot/img/nodes.png
new file mode 100644
index 0000000..19dbb7d
--- /dev/null
+++ b/mavibot/img/nodes.png
Binary files differ
diff --git a/mavibot/img/trans1.graphml b/mavibot/img/trans1.graphml
new file mode 100644
index 0000000..e1e400f
--- /dev/null
+++ b/mavibot/img/trans1.graphml
@@ -0,0 +1,236 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="229.08480000000054" y="262.0799999999999"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 7<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="229.08480000000054" y="232.07999999999993"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="229.08480000000054" y="330.15999999999985"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 14<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="229.08480000000054" y="300.15999999999985"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="229.08480000000054" y="398.2399999999998"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="229.08480000000054" y="368.2399999999998"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.953125" x="5.5234375" y="3.578125">B-tree C<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="229.08480000000054" y="142.15999999999985"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 25<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="229.08480000000054" y="112.15999999999985"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="119.0" x="355.1696000000011" y="12.319999999999709"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="82.9375" x="18.03125" y="3.578125">RMHeader<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="119.0" x="355.1696000000011" y="42.31999999999971"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="90.8828125" x="14.05859375" y="0.078125">currentBOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <edge id="e0" source="n6" target="n1">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="182.0" y="153.65999999999985"/>
+ <y:Point x="182.0" y="247.07999999999993"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n6" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="162.0" y="153.65999999999985"/>
+ <y:Point x="162.0" y="315.15999999999985"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n6" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="140.0" y="153.65999999999985"/>
+ <y:Point x="140.0" y="383.2399999999998"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n9" target="n6">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="414.6696000000011" y="153.65999999999985"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/trans1.png b/mavibot/img/trans1.png
new file mode 100644
index 0000000..e1a581d
--- /dev/null
+++ b/mavibot/img/trans1.png
Binary files differ
diff --git a/mavibot/img/trans2.graphml b/mavibot/img/trans2.graphml
new file mode 100644
index 0000000..0ac569e
--- /dev/null
+++ b/mavibot/img/trans2.graphml
@@ -0,0 +1,407 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.1696000000011" y="287.39999999999964"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 7<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.1696000000011" y="257.39999999999964"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.1696000000011" y="355.47999999999956"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 14<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.1696000000011" y="325.47999999999956"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.1696000000011" y="423.5599999999995"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.1696000000011" y="393.5599999999995"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.953125" x="5.5234375" y="3.578125">B-tree C<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.1696000000011" y="167.47999999999956"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 25<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.1696000000011" y="137.47999999999956"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="119.0" x="469.2544000000016" y="37.63999999999942"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="82.9375" x="18.03125" y="3.578125">RMHeader<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="119.0" x="469.2544000000016" y="67.63999999999942"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="90.8828125" x="14.05859375" y="0.078125">currentBOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.3392000000022" y="287.39999999999964"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 8<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.3392000000022" y="257.39999999999964"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.3392000000022" y="355.47999999999956"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 15<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.3392000000022" y="325.47999999999956"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.3392000000022" y="167.47999999999956"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 27<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.3392000000022" y="137.47999999999956"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <edge id="e0" source="n6" target="n1">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="296.08480000000054" y="178.97999999999956"/>
+ <y:Point x="296.08480000000054" y="272.39999999999964"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n6" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="276.08480000000054" y="178.97999999999956"/>
+ <y:Point x="276.08480000000054" y="340.47999999999956"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n6" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="254.08480000000054" y="178.97999999999956"/>
+ <y:Point x="254.08480000000054" y="408.5599999999995"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n9" target="n7">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="528.7544000000016" y="152.47999999999956"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e4" source="n3" target="n13">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#0000FF" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e5" source="n1" target="n11">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#0000FF" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e6" source="n6" target="n14">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/>
+ <y:LineStyle color="#0000FF" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e7" source="n14" target="n11">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="795.0" y="178.97999999999956"/>
+ <y:Point x="795.0" y="272.39999999999964"/>
+ </y:Path>
+ <y:LineStyle color="#0000FF" type="line" width="3.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e8" source="n14" target="n13">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="815.0" y="178.97999999999956"/>
+ <y:Point x="815.0" y="340.47999999999956"/>
+ </y:Path>
+ <y:LineStyle color="#0000FF" type="line" width="3.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e9" source="n14" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="836.0" y="178.97999999999956"/>
+ <y:Point x="836.0" y="408.5599999999995"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/trans2.png b/mavibot/img/trans2.png
new file mode 100644
index 0000000..3577130
--- /dev/null
+++ b/mavibot/img/trans2.png
Binary files differ
diff --git a/mavibot/img/transko.graphml b/mavibot/img/transko.graphml
new file mode 100644
index 0000000..0b94f2c
--- /dev/null
+++ b/mavibot/img/transko.graphml
@@ -0,0 +1,332 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.33920000000217" y="349.03999999999905"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 7<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.33920000000217" y="319.03999999999905"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.33920000000217" y="417.119999999999"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 14<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.33920000000217" y="387.119999999999"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.33920000000217" y="485.1999999999989"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.33920000000217" y="455.1999999999989"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.953125" x="5.5234375" y="3.578125">B-tree C<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="343.33920000000217" y="229.11999999999898"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 25<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="343.33920000000217" y="199.11999999999898"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="119.0" x="469.4240000000027" y="99.27999999999884"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="82.9375" x="18.03125" y="3.578125">RMHeader<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="119.0" x="469.4240000000027" y="129.27999999999884"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="90.8828125" x="14.05859375" y="0.078125">currentBOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.5088000000032" y="349.03999999999905"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 8<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.5088000000032" y="319.03999999999905"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.5088000000032" y="417.119999999999"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 15<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.5088000000032" y="387.119999999999"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="660.5088000000032" y="229.11999999999898"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 27<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="660.5088000000032" y="199.11999999999898"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <edge id="e0" source="n6" target="n1">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="296.2544000000016" y="240.61999999999898"/>
+ <y:Point x="296.2544000000016" y="334.03999999999905"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n6" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="276.2544000000016" y="240.61999999999898"/>
+ <y:Point x="276.2544000000016" y="402.119999999999"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n6" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="254.25440000000162" y="240.61999999999898"/>
+ <y:Point x="254.25440000000162" y="470.1999999999989"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n9" target="n7">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="528.9240000000027" y="214.11999999999898"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/transko.png b/mavibot/img/transko.png
new file mode 100644
index 0000000..9bae17a
--- /dev/null
+++ b/mavibot/img/transko.png
Binary files differ
diff --git a/mavibot/img/transok.graphml b/mavibot/img/transok.graphml
new file mode 100644
index 0000000..0ab9321
--- /dev/null
+++ b/mavibot/img/transok.graphml
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd">
+ <!--Created by yEd 3.12.2-->
+ <key for="graphml" id="d0" yfiles.type="resources"/>
+ <key for="port" id="d1" yfiles.type="portgraphics"/>
+ <key for="port" id="d2" yfiles.type="portgeometry"/>
+ <key for="port" id="d3" yfiles.type="portuserdata"/>
+ <key attr.name="url" attr.type="string" for="node" id="d4"/>
+ <key attr.name="description" attr.type="string" for="node" id="d5"/>
+ <key for="node" id="d6" yfiles.type="nodegraphics"/>
+ <key attr.name="Description" attr.type="string" for="graph" id="d7"/>
+ <key attr.name="url" attr.type="string" for="edge" id="d8"/>
+ <key attr.name="description" attr.type="string" for="edge" id="d9"/>
+ <key for="edge" id="d10" yfiles.type="edgegraphics"/>
+ <graph edgedefault="directed" id="G">
+ <data key="d7"/>
+ <node id="n0">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="294.33920000000217" y="358.03999999999905"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 7<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n1">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="294.33920000000217" y="328.03999999999905"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n2">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="294.33920000000217" y="426.119999999999"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 14<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n3">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="294.33920000000217" y="396.119999999999"/>
+ <y:Fill color="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n4">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="294.33920000000217" y="494.1999999999989"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 3<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n5">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="294.33920000000217" y="464.1999999999989"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.953125" x="5.5234375" y="3.578125">B-tree C<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n6">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="294.33920000000217" y="238.11999999999898"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 25<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n7">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="294.33920000000217" y="208.11999999999898"/>
+ <y:Fill color="#C0C0C0" color2="#C0C0C0" transparent="false"/>
+ <y:BorderStyle color="#C0C0C0" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n8">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="119.0" x="420.4240000000027" y="108.27999999999884"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="82.9375" x="18.03125" y="3.578125">RMHeader<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n9">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="119.0" x="420.4240000000027" y="138.27999999999884"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="90.8828125" x="14.05859375" y="0.078125">currentBOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n10">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="611.5088000000032" y="358.03999999999905"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="25.7265625" x="27.13671875" y="0.078125">r 8<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n11">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="611.5088000000032" y="328.03999999999905"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="68.921875" x="5.5390625" y="3.578125">B-tree A<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n12">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="611.5088000000032" y="426.119999999999"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 15<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n13">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="611.5088000000032" y="396.119999999999"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="67.0859375" x="6.45703125" y="3.578125">B-tree B<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n14">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="23.0" width="80.0" x="611.5088000000032" y="238.11999999999898"/>
+ <y:Fill color="#CCFFCC" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="35.84375" x="22.078125" y="0.078125">r 27<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <node id="n15">
+ <data key="d6">
+ <y:GenericNode configuration="ShinyPlateNodeWithShadow">
+ <y:Geometry height="30.0" width="80.0" x="611.5088000000032" y="208.11999999999898"/>
+ <y:Fill color="#FFFF99" transparent="false"/>
+ <y:BorderStyle color="#800000" type="line" width="2.0"/>
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="16" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="22.84375" modelName="custom" textColor="#000000" visible="true" width="34.8359375" x="22.58203125" y="3.578125">BOB<y:LabelModel>
+ <y:SmartNodeLabelModel distance="4.0"/>
+ </y:LabelModel>
+ <y:ModelParameter>
+ <y:SmartNodeLabelModelParameter labelRatioX="0.0" labelRatioY="0.0" nodeRatioX="0.0" nodeRatioY="0.0" offsetX="0.0" offsetY="0.0" upX="0.0" upY="-1.0"/>
+ </y:ModelParameter>
+ </y:NodeLabel>
+ </y:GenericNode>
+ </data>
+ </node>
+ <edge id="e0" source="n6" target="n1">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="247.25440000000162" y="249.61999999999898"/>
+ <y:Point x="247.25440000000162" y="343.03999999999905"/>
+ </y:Path>
+ <y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e1" source="n6" target="n3">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="227.25440000000162" y="249.61999999999898"/>
+ <y:Point x="227.25440000000162" y="411.119999999999"/>
+ </y:Path>
+ <y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e2" source="n6" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="205.25440000000162" y="249.61999999999898"/>
+ <y:Point x="205.25440000000162" y="479.1999999999989"/>
+ </y:Path>
+ <y:LineStyle color="#C0C0C0" type="dashed" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e3" source="n9" target="n15">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="479.9240000000027" y="223.11999999999898"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e4" source="n14" target="n11">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="746.1696000000011" y="249.61999999999898"/>
+ <y:Point x="746.1696000000011" y="343.03999999999905"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e5" source="n14" target="n13">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="766.1696000000011" y="249.61999999999898"/>
+ <y:Point x="766.1696000000011" y="411.119999999999"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ <edge id="e6" source="n14" target="n5">
+ <data key="d9"/>
+ <data key="d10">
+ <y:PolyLineEdge>
+ <y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0">
+ <y:Point x="787.1696000000011" y="249.61999999999898"/>
+ <y:Point x="787.1696000000011" y="479.1999999999989"/>
+ </y:Path>
+ <y:LineStyle color="#000000" type="line" width="1.0"/>
+ <y:Arrows source="none" target="standard"/>
+ <y:BendStyle smoothed="false"/>
+ </y:PolyLineEdge>
+ </data>
+ </edge>
+ </graph>
+ <data key="d0">
+ <y:Resources/>
+ </data>
+</graphml>
diff --git a/mavibot/img/transok.png b/mavibot/img/transok.png
new file mode 100644
index 0000000..8ac423f
--- /dev/null
+++ b/mavibot/img/transok.png
Binary files differ
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
index 4e05724..1951516 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractBTree.java
@@ -23,9 +23,13 @@
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Comparator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
@@ -44,11 +48,8 @@
/** The read transaction timeout */
protected long readTimeOut = DEFAULT_READ_TIMEOUT;
- /** The Header for a managed BTree */
- protected BTreeHeader btreeHeader;
-
- /** The current rootPage */
- protected volatile Page<K, V> rootPage;
+ /** The current Header for a managed BTree */
+ protected BTreeHeader<K, V> currentBtreeHeader;
/** The Key serializer used for this tree.*/
protected ElementSerializer<K> keySerializer;
@@ -62,20 +63,46 @@
/** The size of the buffer used to write data in disk */
protected int writeBufferSize;
- /** A lock used to protect the write operation against concurrent access */
- protected ReentrantLock writeLock;
-
/** Flag to enable duplicate key support */
- private boolean allowDuplicates;
+ protected boolean allowDuplicates;
+
+ /** The number of elements in a page for this B-tree */
+ protected int pageSize;
+
+ /** The BTree name */
+ protected String name;
+
+ /** The FQCN of the Key serializer */
+ protected String keySerializerFQCN;
+
+ /** The FQCN of the Value serializer */
+ protected String valueSerializerFQCN;
/** The thread responsible for the cleanup of timed out reads */
protected Thread readTransactionsThread;
/** The BTree type : either in-memory, disk backed or persisted */
- private BTreeTypeEnum type;
+ protected BTreeTypeEnum btreeType;
/** The current transaction */
- protected WriteTransaction writeTransaction;
+ protected AtomicBoolean transactionStarted = new AtomicBoolean( false );
+
+ /** The map of all the used BtreeHeaders */
+ protected Map<Long, BTreeHeader<K, V>> btreeRevisions = new ConcurrentHashMap<Long, BTreeHeader<K, V>>();
+
+ /** The current revision */
+ protected AtomicLong currentRevision = new AtomicLong( 0L );
+
+ /** The TransactionManager used for this BTree */
+ protected TransactionManager transactionManager;
+
+ /**
+ * Starts a Read Only transaction. If the transaction is not closed, it will be
+ * automatically closed after the timeout
+ *
+ * @return The created transaction
+ */
+ protected abstract ReadTransaction<K, V> beginReadTransaction();
/**
@@ -84,33 +111,37 @@
*
* @return The created transaction
*/
- protected ReadTransaction<K, V> beginReadTransaction()
- {
- ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( rootPage, btreeHeader.getRevision() - 1,
- System.currentTimeMillis() );
-
- readTransactions.add( readTransaction );
-
- return readTransaction;
- }
+ protected abstract ReadTransaction<K, V> beginReadTransaction( long revision );
/**
* {@inheritDoc}
*/
- public TupleCursor<K, V> browse() throws IOException
+ public TupleCursor<K, V> browse() throws IOException, KeyNotFoundException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
ReadTransaction<K, V> transaction = beginReadTransaction();
- // Fetch the root page for this revision
- ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
+ if ( transaction == null )
+ {
+ return new EmptyTupleCursor<K, V>( 0L );
+ }
+ else
+ {
+ ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
- TupleCursor<K, V> cursor = rootPage.browse( transaction, stack, 0 );
+ TupleCursor<K, V> cursor = getRootPage().browse( transaction, stack, 0 );
- // Set the position before the first element
- cursor.beforeFirst();
+ // Set the position before the first element
+ cursor.beforeFirst();
- return cursor;
+ return cursor;
+ }
}
@@ -119,17 +150,27 @@
*/
public TupleCursor<K, V> browse( long revision ) throws IOException, KeyNotFoundException
{
- ReadTransaction<K, V> transaction = beginReadTransaction();
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
- // Fetch the root page for this revision
- Page<K, V> revisionRootPage = getRootPage( revision );
+ ReadTransaction<K, V> transaction = beginReadTransaction( revision );
- ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
+ if ( transaction == null )
+ {
+ return new EmptyTupleCursor<K, V>( revision );
+ }
+ else
+ {
+ ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
- // And get the cursor
- TupleCursor<K, V> cursor = revisionRootPage.browse( transaction, stack, 0 );
+ // And get the cursor
+ TupleCursor<K, V> cursor = getRootPage( transaction.getRevision() ).browse( transaction, stack, 0 );
- return cursor;
+ return cursor;
+ }
}
@@ -138,14 +179,27 @@
*/
public TupleCursor<K, V> browseFrom( K key ) throws IOException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
ReadTransaction<K, V> transaction = beginReadTransaction();
- // Fetch the root page for this revision
ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
- TupleCursor<K, V> cursor = rootPage.browse( key, transaction, stack, 0 );
-
- return cursor;
+ TupleCursor<K, V> cursor;
+ try
+ {
+ cursor = getRootPage( transaction.getRevision() ).browse( key, transaction, stack, 0 );
+
+ return cursor;
+ }
+ catch ( KeyNotFoundException e )
+ {
+ throw new IOException( e.getMessage() );
+ }
}
@@ -154,17 +208,27 @@
*/
public TupleCursor<K, V> browseFrom( long revision, K key ) throws IOException, KeyNotFoundException
{
- ReadTransaction<K, V> transaction = beginReadTransaction();
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
- // Fetch the rootPage for this revision
- Page<K, V> revisionRootPage = getRootPage( revision );
+ ReadTransaction<K, V> transaction = beginReadTransaction( revision );
- ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
+ if ( transaction == null )
+ {
+ return new EmptyTupleCursor<K, V>( revision );
+ }
+ else
+ {
+ ParentPos<K, V>[] stack = (ParentPos<K, V>[]) Array.newInstance( ParentPos.class, 32 );
- // And get the cursor
- TupleCursor<K, V> cursor = revisionRootPage.browse( key, transaction, stack, 0 );
+ // And get the cursor
+ TupleCursor<K, V> cursor = getRootPage( transaction.getRevision() ).browse( key, transaction, stack, 0 );
- return cursor;
+ return cursor;
+ }
}
@@ -173,7 +237,33 @@
*/
public boolean contains( K key, V value ) throws IOException
{
- return rootPage.contains( key, value );
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).contains( key, value );
+ }
+ catch ( KeyNotFoundException knfe )
+ {
+ throw new IOException( knfe.getMessage() );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -182,10 +272,30 @@
*/
public boolean contains( long revision, K key, V value ) throws IOException, KeyNotFoundException
{
- // Fetch the root page for this revision
- Page<K, V> revisionRootPage = getRootPage( revision );
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
- return revisionRootPage.contains( key, value );
+ // Fetch the root page for this revision
+ ReadTransaction<K, V> transaction = beginReadTransaction( revision );
+
+ if ( transaction == null )
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).contains( key, value );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -194,16 +304,36 @@
*/
public Tuple<K, V> delete( K key ) throws IOException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
if ( key == null )
{
throw new IllegalArgumentException( "Key must not be null" );
}
- long revision = generateRevision();
+ // Take the lock if it's not already taken by another thread
+ transactionManager.beginTransaction();
- Tuple<K, V> deleted = delete( key, revision );
+ try
+ {
+ Tuple<K, V> deleted = delete( key, currentRevision.get() + 1 );
- return deleted;
+ // Commit now
+ transactionManager.commit();
+
+ return deleted;
+ }
+ catch ( IOException ioe )
+ {
+ // We have had an exception, we must rollback the transaction
+ transactionManager.rollback();
+
+ return null;
+ }
}
@@ -212,6 +342,12 @@
*/
public Tuple<K, V> delete( K key, V value ) throws IOException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
if ( key == null )
{
throw new IllegalArgumentException( "Key must not be null" );
@@ -222,11 +358,22 @@
throw new IllegalArgumentException( "Value must not be null" );
}
- long revision = generateRevision();
+ transactionManager.beginTransaction();
- Tuple<K, V> deleted = delete( key, value, revision );
-
- return deleted;
+ try
+ {
+ Tuple<K, V> deleted = delete( key, value, currentRevision.get() + 1 );
+
+ transactionManager.commit();
+
+ return deleted;
+ }
+ catch ( IOException ioe )
+ {
+ transactionManager.rollback();
+
+ throw ioe;
+ }
}
@@ -251,34 +398,54 @@
*/
public V insert( K key, V value ) throws IOException
{
- long revision = generateRevision();
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
V existingValue = null;
+ if ( key == null )
+ {
+ throw new IllegalArgumentException( "Key must not be null" );
+ }
+
+ // Take the lock if it's not already taken by another thread and if we
+ // aren't on a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.beginTransaction();
+ }
+
try
{
- if ( writeTransaction == null )
- {
- writeLock.lock();
- }
-
- InsertResult<K, V> result = insert( key, value, revision );
+ InsertResult<K, V> result = insert( key, value, -1L );
if ( result instanceof ModifyResult )
{
existingValue = ( ( ModifyResult<K, V> ) result ).getModifiedValue();
}
- }
- finally
- {
- // See above
- if ( writeTransaction == null )
+
+ // Commit now if it's not a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
{
- writeLock.unlock();
+ transactionManager.commit();
}
+
+ return existingValue;
}
-
- return existingValue;
+ catch ( IOException ioe )
+ {
+ // We have had an exception, we must rollback the transaction
+ // if it's not a sub-btree
+ if ( btreeType != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.rollback();
+ }
+
+ return null;
+ }
}
@@ -302,7 +469,29 @@
*/
public V get( K key ) throws IOException, KeyNotFoundException
{
- return rootPage.get( key );
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return null;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).get( key );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -311,29 +500,42 @@
*/
public V get( long revision, K key ) throws IOException, KeyNotFoundException
{
- // Fetch the root page for this revision
- Page<K, V> revisionRootPage = getRootPage( revision );
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
- return revisionRootPage.get( key );
+ ReadTransaction<K, V> transaction = beginReadTransaction( revision );
+
+ if ( transaction == null )
+ {
+ return null;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).get( key );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
/**
* {@inheritDoc}
*/
- public Page<K, V> getRootPage()
- {
- return rootPage;
- }
+ public abstract Page<K, V> getRootPage();
/**
* {@inheritDoc}
*/
- /* no qualifier */void setRootPage( Page<K, V> root )
- {
- rootPage = root;
- }
+ /* no qualifier */abstract void setRootPage( Page<K, V> root );
/**
@@ -341,21 +543,65 @@
*/
public ValueCursor<V> getValues( K key ) throws IOException, KeyNotFoundException
{
- return rootPage.getValues( key );
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return new EmptyValueCursor<V>( 0L );
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).getValues( key );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
/**
* {@inheritDoc}
*/
- public boolean hasKey( K key ) throws IOException
+ public boolean hasKey( K key ) throws IOException, KeyNotFoundException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
if ( key == null )
{
return false;
}
- return rootPage.hasKey( key );
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).hasKey( key );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -364,15 +610,34 @@
*/
public boolean hasKey( long revision, K key ) throws IOException, KeyNotFoundException
{
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
if ( key == null )
{
return false;
}
- // Fetch the root page for this revision
- Page<K, V> revisionRootPage = getRootPage( revision );
+ ReadTransaction<K, V> transaction = beginReadTransaction( revision );
- return revisionRootPage.hasKey( key );
+ if ( transaction == null )
+ {
+ return false;
+ }
+ else
+ {
+ try
+ {
+ return getRootPage( transaction.getRevision() ).hasKey( key );
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -391,7 +656,7 @@
public void setKeySerializer( ElementSerializer<K> keySerializer )
{
this.keySerializer = keySerializer;
- btreeHeader.setKeySerializerFQCN( keySerializer.getClass().getName() );
+ keySerializerFQCN = keySerializer.getClass().getName();
}
@@ -400,7 +665,7 @@
*/
public String getKeySerializerFQCN()
{
- return btreeHeader.getKeySerializerFQCN();
+ return keySerializerFQCN;
}
@@ -419,7 +684,7 @@
public void setValueSerializer( ElementSerializer<V> valueSerializer )
{
this.valueSerializer = valueSerializer;
- btreeHeader.setValueSerializerFQCN( valueSerializer.getClass().getName() );
+ valueSerializerFQCN = valueSerializer.getClass().getName();
}
@@ -428,7 +693,7 @@
*/
public String getValueSerializerFQCN()
{
- return btreeHeader.getValueSerializerFQCN();
+ return valueSerializerFQCN;
}
@@ -437,7 +702,29 @@
*/
public long getRevision()
{
- return btreeHeader.getRevision();
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return -1L;
+ }
+ else
+ {
+ try
+ {
+ return transaction.getRevision();
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -446,18 +733,56 @@
*/
/* no qualifier */void setRevision( long revision )
{
- btreeHeader.setRevision( revision );
+ transactionManager.getBTreeHeader( getName() ).setRevision( revision );
}
/**
- * Generates a new revision number. It's only used by the Page instances.
- *
- * @return a new incremental revision number
+ * Store the new revision in the map of btrees, increment the current revision
*/
- /* no qualifier */long generateRevision()
+ protected void storeRevision( BTreeHeader<K, V> btreeHeader, boolean keepRevisions )
{
- return btreeHeader.incrementRevision();
+ long revision = btreeHeader.getRevision();
+
+ if ( keepRevisions )
+ {
+ synchronized ( btreeRevisions )
+ {
+ btreeRevisions.put( revision, btreeHeader );
+ }
+ }
+
+ currentRevision.set( revision );
+ currentBtreeHeader = btreeHeader;
+
+ // And update the newBTreeHeaders map
+ if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.updateNewBTreeHeaders( btreeHeader );
+ }
+ }
+
+
+ /**
+ * Store the new revision in the map of btrees, increment the current revision
+ */
+ protected void storeRevision( BTreeHeader<K, V> btreeHeader )
+ {
+ long revision = btreeHeader.getRevision();
+
+ synchronized ( btreeRevisions )
+ {
+ btreeRevisions.put( revision, btreeHeader );
+ }
+
+ currentRevision.set( revision );
+ currentBtreeHeader = btreeHeader;
+
+ // And update the newBTreeHeaders map
+ if ( btreeHeader.getBtree().getType() != BTreeTypeEnum.PERSISTED_SUB )
+ {
+ transactionManager.updateNewBTreeHeaders( btreeHeader );
+ }
}
@@ -484,7 +809,29 @@
*/
public long getNbElems()
{
- return btreeHeader.getNbElems();
+ // Check that we have a TransactionManager
+ if ( transactionManager == null )
+ {
+ throw new BTreeCreationException( "We don't have a transactionLManager" );
+ }
+
+ ReadTransaction<K, V> transaction = beginReadTransaction();
+
+ if ( transaction == null )
+ {
+ return -1L;
+ }
+ else
+ {
+ try
+ {
+ return transaction.getBtreeHeader().getNbElems();
+ }
+ finally
+ {
+ transaction.close();
+ }
+ }
}
@@ -493,7 +840,7 @@
*/
/* no qualifier */void setNbElems( long nbElems )
{
- btreeHeader.setNbElems( nbElems );
+ transactionManager.getBTreeHeader( getName() ).setNbElems( nbElems );
}
@@ -502,7 +849,7 @@
*/
public int getPageSize()
{
- return btreeHeader.getPageSize();
+ return pageSize;
}
@@ -513,11 +860,11 @@
{
if ( pageSize <= 2 )
{
- btreeHeader.setPageSize( DEFAULT_PAGE_SIZE );
+ this.pageSize = DEFAULT_PAGE_SIZE;
}
else
{
- btreeHeader.setPageSize( getPowerOf2( pageSize ) );
+ this.pageSize = getPowerOf2( pageSize );
}
}
@@ -527,7 +874,7 @@
*/
public String getName()
{
- return btreeHeader.getName();
+ return name;
}
@@ -536,7 +883,7 @@
*/
public void setName( String name )
{
- btreeHeader.setName( name );
+ this.name = name;
}
@@ -572,7 +919,7 @@
*/
public boolean isAllowDuplicates()
{
- return btreeHeader.isAllowDuplicates();
+ return allowDuplicates;
}
@@ -581,7 +928,7 @@
*/
public void setAllowDuplicates( boolean allowDuplicates )
{
- btreeHeader.setAllowDuplicates( allowDuplicates );
+ this.allowDuplicates = allowDuplicates;
}
@@ -590,7 +937,7 @@
*/
public BTreeTypeEnum getType()
{
- return type;
+ return btreeType;
}
@@ -599,7 +946,7 @@
*/
public void setType( BTreeTypeEnum type )
{
- this.type = type;
+ this.btreeType = type;
}
@@ -621,6 +968,24 @@
/**
+ * @return The current BtreeHeader
+ */
+ protected BTreeHeader<K, V> getBtreeHeader()
+ {
+ return currentBtreeHeader;
+ }
+
+
+ /**
+ * @return The current BtreeHeader
+ */
+ protected BTreeHeader<K, V> getBtreeHeader( long revision )
+ {
+ return btreeRevisions.get( revision );
+ }
+
+
+ /**
* Create a thread that is responsible of cleaning the transactions when
* they hit the timeout
*/
@@ -657,6 +1022,12 @@
{
transaction.close();
readTransactions.poll();
+
+ synchronized ( btreeRevisions )
+ {
+ btreeRevisions.remove( transaction.getRevision() );
+ }
+
continue;
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractPage.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractPage.java
index 168f078..b5458b1 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractPage.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractPage.java
@@ -23,8 +23,6 @@
import java.io.IOException;
import java.lang.reflect.Array;
-import org.apache.directory.mavibot.btree.KeyHolder;
-import org.apache.directory.mavibot.btree.Page;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
@@ -32,7 +30,7 @@
/**
* A MVCC abstract Page. It stores the field and the methods shared by the Node and Leaf
* classes.
- *
+ *
* @param <K> The type for the Key
* @param <V> The type for the stored value
*
@@ -61,14 +59,9 @@
/** The last {@link PageIO} storing the serialized Page on disk */
protected long lastOffset = -1L;
- /** A static Exception used to avoid creating a new one every time */
- protected KeyNotFoundException KEY_NOT_FOUND_EXCEPTION = new KeyNotFoundException(
- "Cannot find an entry associated with this key" );
-
-
/**
* Creates a default empty AbstractPage
- *
+ *
* @param btree The associated BTree
*/
protected AbstractPage( BTree<K, V> btree )
@@ -216,6 +209,30 @@
/**
* {@inheritDoc}
*/
+ public DeleteResult<K, V> delete( K key, V value, long revision ) throws IOException
+ {
+ return delete( key, value, revision, null, -1 );
+ }
+
+
+ /**
+ * The real delete implementation. It can be used for internal deletion in the B-tree.
+ *
+ * @param key The key to delete
+ * @param value The value to delete
+ * @param revision The revision for which we want to delete a tuple
+ * @param parent The parent page
+ * @param parentPos The position of this page in the parent page
+ * @return The result
+ * @throws IOException If we had an issue while processing the deletion
+ */
+ /* no qualifier */abstract DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
+ throws IOException;
+
+
+ /**
+ * {@inheritDoc}
+ */
public V get( K key ) throws IOException, KeyNotFoundException
{
int pos = findPos( key );
@@ -299,7 +316,7 @@
/**
* Selects the sibling (the previous or next page with the same parent) which has
* the more element assuming it's above N/2
- *
+ *
* @param parent The parent of the current page
* @param The position of the current page reference in its parent
* @return The position of the sibling, or -1 if we have'nt found any sibling
@@ -403,7 +420,7 @@
/**
* Sets the key at a give position
- *
+ *
* @param pos The position in the keys array
* @param key the key to inject
*/
@@ -452,7 +469,7 @@
/**
* Compares two keys
- *
+ *
* @param key1 The first key
* @param key2 The second key
* @return -1 if the first key is above the second one, 1 if it's below, and 0
@@ -510,8 +527,8 @@
* <li>'h' will return -4</li>
* <li>'i' will return 4</li>
* </ul>
- *
- *
+ *
+ *
* @param key The key to find
* @return The position in the page.
*/
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
new file mode 100644
index 0000000..4ac5c52
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractTransactionManager.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * An abstract class implementing the TransactionManager interface.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public abstract class AbstractTransactionManager implements TransactionManager
+{
+ /** A lock to protect the transaction handling */
+ private ReadWriteLock transactionLock = new ReentrantReadWriteLock();
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractValueHolder.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractValueHolder.java
index 4da7f76..053d3e1 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractValueHolder.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/AbstractValueHolder.java
@@ -24,6 +24,7 @@
import java.lang.reflect.Array;
import java.util.Comparator;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
@@ -244,6 +245,10 @@
e.printStackTrace();
return false;
}
+ catch ( KeyNotFoundException knfe )
+ {
+ knfe.printStackTrace();return false;
+ }
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTree.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTree.java
index af3a66b..972377c 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTree.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTree.java
@@ -28,7 +28,7 @@
/**
- * A BTree interface, to be implemented by the PersistedBTree or the InMemoryBTree
+ * A B-tree interface, to be implemented by the PersistedBTree or the InMemoryBTree
*
* @param <K> The Key type
* @param <V> The Value type
@@ -46,23 +46,15 @@
/** Define a default delay for a read transaction. This is 10 seconds */
static final long DEFAULT_READ_TIMEOUT = 10 * 1000L;
- /** The BTree allows duplicate values */
+ /** The B-tree allows duplicate values */
static final boolean ALLOW_DUPLICATES = true;
- /** The BTree forbids duplicate values */
+ /** The B-tree forbids duplicate values */
static final boolean FORBID_DUPLICATES = false;
/**
- * Initialize the BTree.
- *
- * @throws IOException If we get some exception while initializing the BTree
- */
- void init() throws IOException;
-
-
- /**
- * Close the BTree, cleaning up all the data structure
+ * Close the B-tree, cleaning up all the data structure
*/
void close() throws IOException;
@@ -87,10 +79,10 @@
/**
- * Insert an entry in the BTree.
+ * Insert an entry in the B-tree.
* <p>
* We will replace the value if the provided key already exists in the
- * btree.
+ * B-tree.
*
* @param key Inserted key
* @param value Inserted value
@@ -130,7 +122,7 @@
*
* @param key The key we are looking at
* @return The found value, or null if the key is not present in the tree
- * @throws KeyNotFoundException If the key is not found in the BTree
+ * @throws KeyNotFoundException If the key is not found in the B-tree
* @throws IOException TODO
*/
V get( K key ) throws IOException, KeyNotFoundException;
@@ -142,7 +134,7 @@
* @param revision The revision we are looking for
* @return The rootPage associated to this revision
* @throws IOException If we had an issue while accessing the underlying file
- * @throws KeyNotFoundException If the revision does not exist for this Btree
+ * @throws KeyNotFoundException If the revision does not exist for this B-tree
*/
Page<K, V> getRootPage( long revision ) throws IOException, KeyNotFoundException;
@@ -169,7 +161,7 @@
* @param revision The revision for which we want to find a key
* @param key The key we are looking at
* @return The found value, or null if the key is not present in the tree
- * @throws KeyNotFoundException If the key is not found in the BTree
+ * @throws KeyNotFoundException If the key is not found in the B-tree
* @throws IOException If there was an issue while fetching data from the disk
*/
V get( long revision, K key ) throws IOException, KeyNotFoundException;
@@ -181,8 +173,9 @@
* @param key The key we are looking at
* @return true if the key is present, false otherwise
* @throws IOException If we have an error while trying to access the page
+ * @throws KeyNotFoundException If the key is not found in the B-tree
*/
- boolean hasKey( K key ) throws IOException;
+ boolean hasKey( K key ) throws IOException, KeyNotFoundException;
/**
@@ -192,13 +185,13 @@
* @param key The key we are looking at
* @return true if the key is present, false otherwise
* @throws IOException If we have an error while trying to access the page
- * @throws KeyNotFoundException If the key is not found in the BTree
+ * @throws KeyNotFoundException If the key is not found in the B-tree
*/
boolean hasKey( long revision, K key ) throws IOException, KeyNotFoundException;
/**
- * Checks if the BTree contains the given key with the given value.
+ * Checks if the B-tree contains the given key with the given value.
*
* @param key The key we are looking for
* @param value The value associated with the given key
@@ -208,13 +201,13 @@
/**
- * Checks if the BTree contains the given key with the given value for a given revision
+ * Checks if the B-tree contains the given key with the given value for a given revision
*
* @param revision The revision we would like to browse
* @param key The key we are looking for
* @param value The value associated with the given key
* @return true if the key and value are associated with each other, false otherwise
- * @throws KeyNotFoundException If the key is not found in the BTree
+ * @throws KeyNotFoundException If the key is not found in the B-tree
*/
boolean contains( long revision, K key, V value ) throws IOException, KeyNotFoundException;
@@ -222,19 +215,19 @@
/**
* Creates a cursor starting at the beginning of the tree
*
- * @return A cursor on the btree
+ * @return A cursor on the B-tree
* @throws IOException
*/
- TupleCursor<K, V> browse() throws IOException;
+ TupleCursor<K, V> browse() throws IOException, KeyNotFoundException;
/**
* Creates a cursor starting at the beginning of the tree, for a given revision
*
* @param revision The revision we would like to browse
- * @return A cursor on the btree
+ * @return A cursor on the B-tree
* @throws IOException If we had an issue while fetching data from the disk
- * @throws KeyNotFoundException If the key is not found in the BTree
+ * @throws KeyNotFoundException If the key is not found in the B-tree
*/
TupleCursor<K, V> browse( long revision ) throws IOException, KeyNotFoundException;
@@ -244,7 +237,7 @@
*
* @param key The key which is the starting point. If the key is not found,
* then the cursor will always return null.
- * @return A cursor on the btree
+ * @return A cursor on the B-tree
* @throws IOException
*/
TupleCursor<K, V> browseFrom( K key ) throws IOException;
@@ -256,8 +249,8 @@
* @param The revision we are looking for
* @param key The key which is the starting point. If the key is not found,
* then the cursor will always return null.
- * @return A cursor on the btree
- * @throws IOException If wxe had an issue reading the BTree from disk
+ * @return A cursor on the B-tree
+ * @throws IOException If wxe had an issue reading the B-tree from disk
* @throws KeyNotFoundException If we can't find a rootPage for this revision
*/
TupleCursor<K, V> browseFrom( long revision, K key ) throws IOException, KeyNotFoundException;
@@ -349,25 +342,25 @@
/**
- * @return The current BTree revision
+ * @return The current B-tree revision
*/
long getRevision();
/**
- * @return The current number of elements in the BTree
+ * @return The current number of elements in the B-tree
*/
long getNbElems();
/**
- * @return true if this BTree allow duplicate values
+ * @return true if this B-tree allow duplicate values
*/
boolean isAllowDuplicates();
/**
- * @param allowDuplicates True if the BTree will allow duplicate values
+ * @param allowDuplicates True if the B-tree will allow duplicate values
*/
void setAllowDuplicates( boolean allowDuplicates );
@@ -376,22 +369,4 @@
* @return the type
*/
BTreeTypeEnum getType();
-
-
- /**
- * Starts a transaction
- */
- void beginTransaction();
-
-
- /**
- * Commits a transaction
- */
- void commit();
-
-
- /**
- * Rollback a transaction
- */
- void rollback();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
index 7a93d63..3bdd4f4 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeFactory.java
@@ -20,31 +20,31 @@
package org.apache.directory.mavibot.btree;
-import java.io.IOException;
import java.util.LinkedList;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
/**
- * This class construct a BTree from a serialized version of a BTree. We need it
- * to avoid exposing all the methods of the BTree class.<br>
- *
+ * This class construct a B-tree from a serialized version of a B-tree. We need it
+ * to avoid exposing all the methods of the B-tree class.<br>
+ *
* All its methods are static.
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*
- * @param <K> The BTree key type
- * @param <V> The BTree valye type
+ * @param <K> The B-tree key type
+ * @param <V> The B-tree value type
*/
public class BTreeFactory<K, V>
{
//--------------------------------------------------------------------------------------------
// Create persisted btrees
//--------------------------------------------------------------------------------------------
-
/**
- * Creates a new persisted BTree, with no initialization.
+ * Creates a new persisted B-tree, with no initialization.
+ *
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree()
{
@@ -55,10 +55,36 @@
/**
- * Creates a new persisted BTree using the BTreeConfiguration to initialize the
- * BTree
- *
+ * Creates a new persisted B-tree, with no initialization.
+ *
+ * @return a new B-tree instance
+ */
+ public static <K, V> BTree<K, V> createPersistedBTree( BTreeTypeEnum type )
+ {
+ BTree<K, V> btree = new PersistedBTree<K, V>();
+ ((AbstractBTree<K, V>)btree).setType( type );
+
+ return btree;
+ }
+
+
+ /**
+ * Sets the btreeHeader offset for a Persisted BTree
+ *
+ * @param btree The btree to update
+ * @param btreeHeaderOffset The offset
+ */
+ public static <K, V> void setBtreeHeaderOffset( PersistedBTree<K, V> btree, long btreeHeaderOffset )
+ {
+ btree.setBtreeHeaderOffset( btreeHeaderOffset );
+ }
+
+ /**
+ * Creates a new persisted B-tree using the BTreeConfiguration to initialize the
+ * B-tree
+ *
* @param configuration The configuration to use
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( PersistedBTreeConfiguration<K, V> configuration )
{
@@ -69,14 +95,13 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @throws IOException
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer )
@@ -98,14 +123,14 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, boolean allowDuplicates )
@@ -127,15 +152,15 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @param cacheSize The size to be used for this BTree cache
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @param cacheSize The size to be used for this B-tree cache
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, boolean allowDuplicates, int cacheSize )
@@ -157,14 +182,14 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @throws IOException
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, int pageSize )
@@ -186,15 +211,15 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, int pageSize, boolean allowDuplicates )
@@ -216,16 +241,16 @@
/**
- * Creates a new persisted BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new persisted B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @param cacheSize The size to be used for this BTree cache
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @param cacheSize The size to be used for this B-tree cache
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createPersistedBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, int pageSize, boolean allowDuplicates, int cacheSize )
@@ -247,10 +272,12 @@
//--------------------------------------------------------------------------------------------
- // Create in-memory btrees
+ // Create in-memory B-trees
//--------------------------------------------------------------------------------------------
/**
- * Creates a new in-memory BTree, with no initialization.
+ * Creates a new in-memory B-tree, with no initialization.
+ *
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree()
{
@@ -261,10 +288,11 @@
/**
- * Creates a new in-memory BTree using the BTreeConfiguration to initialize the
- * BTree
- *
+ * Creates a new in-memory B-tree using the BTreeConfiguration to initialize the
+ * B-tree
+ *
* @param configuration The configuration to use
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( InMemoryBTreeConfiguration<K, V> configuration )
{
@@ -275,12 +303,13 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer )
@@ -301,14 +330,14 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, boolean allowDuplicates )
@@ -329,14 +358,14 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @throws IOException
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, ElementSerializer<K> keySerializer,
ElementSerializer<V> valueSerializer, int pageSize )
@@ -357,14 +386,14 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param filePath The name of the data directory with absolute path
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
- * @throws IOException
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, String filePath,
ElementSerializer<K> keySerializer,
@@ -387,19 +416,18 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param filePath The name of the data directory with absolute path
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @throws IOException
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, String filePath,
- ElementSerializer<K> keySerializer,
- ElementSerializer<V> valueSerializer, int pageSize )
+ ElementSerializer<K> keySerializer, ElementSerializer<V> valueSerializer, int pageSize )
{
InMemoryBTreeConfiguration<K, V> configuration = new InMemoryBTreeConfiguration<K, V>();
@@ -418,16 +446,16 @@
/**
- * Creates a new in-memory BTree using the parameters to initialize the
- * BTree
- *
- * @param name The BTree's name
+ * Creates a new in-memory B-tree using the parameters to initialize the
+ * B-tree
+ *
+ * @param name The B-tree's name
* @param filePath The name of the data directory with absolute path
* @param keySerializer Key serializer
* @param valueSerializer Value serializer
* @param pageSize Size of the page
- * @param allowDuplicates Tells if the BTree allows multiple value for a given key
- * @throws IOException
+ * @param allowDuplicates Tells if the B-tree allows multiple value for a given key
+ * @return a new B-tree instance
*/
public static <K, V> BTree<K, V> createInMemoryBTree( String name, String filePath,
ElementSerializer<K> keySerializer,
@@ -453,17 +481,17 @@
// Create Pages
//--------------------------------------------------------------------------------------------
/**
- * Create a new Leaf for the given BTree.
- *
- * @param btree The BTree which will contain this leaf
+ * Create a new Leaf for the given B-tree.
+ *
+ * @param btree The B-tree which will contain this leaf
* @param revision The Leaf's revision
* @param nbElems The number or elements in this leaf
- *
+ *
* @return A Leaf instance
*/
/* no qualifier*/static <K, V> Page<K, V> createLeaf( BTree<K, V> btree, long revision, int nbElems )
{
- if ( btree.getType() == BTreeTypeEnum.PERSISTED )
+ if ( btree.getType() != BTreeTypeEnum.IN_MEMORY )
{
return new PersistedLeaf<K, V>( btree, revision, nbElems );
}
@@ -475,16 +503,16 @@
/**
- * Create a new Node for the given BTree.
- *
- * @param btree The BTree which will contain this node
+ * Create a new Node for the given B-tree.
+ *
+ * @param btree The B-tree which will contain this node
* @param revision The Node's revision
* @param nbElems The number or elements in this node
* @return A Node instance
*/
/* no qualifier*/static <K, V> Page<K, V> createNode( BTree<K, V> btree, long revision, int nbElems )
{
- if ( btree.getType() == BTreeTypeEnum.PERSISTED )
+ if ( btree.getType() != BTreeTypeEnum.IN_MEMORY )
{
return new PersistedNode<K, V>( btree, revision, nbElems );
}
@@ -500,8 +528,8 @@
//--------------------------------------------------------------------------------------------
/**
* Set the key at a give position
- *
- * @param btree The BTree to update
+ *
+ * @param btree The B-tree to update
* @param page The page to update
* @param pos The position in the keys array
* @param key The key to inject
@@ -510,7 +538,7 @@
{
KeyHolder<K> keyHolder;
- if ( btree.getType() == BTreeTypeEnum.PERSISTED )
+ if ( btree.getType() != BTreeTypeEnum.IN_MEMORY )
{
keyHolder = new PersistedKeyHolder<K>( btree.getKeySerializer(), key );
}
@@ -525,12 +553,15 @@
/**
* Set the value at a give position
+ *
+ * @param btree The B-tree to update
+ * @param page The page to update
* @param pos The position in the values array
* @param value the value to inject
*/
/* no qualifier*/static <K, V> void setValue( BTree<K, V> btree, Page<K, V> page, int pos, ValueHolder<V> value )
{
- if ( btree.getType() == BTreeTypeEnum.PERSISTED )
+ if ( btree.getType() != BTreeTypeEnum.IN_MEMORY )
{
( ( PersistedLeaf<K, V> ) page ).setValue( pos, value );
}
@@ -543,15 +574,15 @@
/**
* Set the page at a give position
- *
- * @param btree The BTree to update
+ *
+ * @param btree The B-tree to update
* @param page The page to update
* @param pos The position in the values array
- * @param value the value to inject
+ * @param child the child page to inject
*/
/* no qualifier*/static <K, V> void setPage( BTree<K, V> btree, Page<K, V> page, int pos, Page<K, V> child )
{
- if ( btree.getType() == BTreeTypeEnum.PERSISTED )
+ if ( btree.getType() != BTreeTypeEnum.IN_MEMORY )
{
( ( PersistedNode<K, V> ) page ).setValue( pos, new PersistedPageHolder<K, V>( btree, child ) );
}
@@ -563,42 +594,76 @@
//--------------------------------------------------------------------------------------------
- // Update BTree
+ // Update B-tree
//--------------------------------------------------------------------------------------------
/**
- * Sets the KeySerializer into the BTree
- *
- * @param btree The BTree to update
+ * Sets the KeySerializer into the B-tree
+ *
+ * @param btree The B-tree to update
* @param keySerializerFqcn the Key serializer FQCN to set
- * @throws ClassNotFoundException
- * @throws InstantiationException
- * @throws IllegalAccessException
+ * @throws ClassNotFoundException If the key serializer class cannot be found
+ * @throws InstantiationException If the key serializer class cannot be instanciated
+ * @throws IllegalAccessException If the key serializer class cannot be accessed
+ * @throws NoSuchFieldException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
*/
/* no qualifier*/static <K, V> void setKeySerializer( BTree<K, V> btree, String keySerializerFqcn )
- throws ClassNotFoundException, IllegalAccessException, InstantiationException
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException
{
Class<?> keySerializer = Class.forName( keySerializerFqcn );
@SuppressWarnings("unchecked")
- ElementSerializer<K> instance = ( ElementSerializer<K> ) keySerializer.newInstance();
+ ElementSerializer<K> instance = null;
+ try
+ {
+ instance = ( ElementSerializer<K> ) keySerializer.getDeclaredField( "INSTANCE" ).get( null );
+ }
+ catch( NoSuchFieldException e )
+ {
+ // ignore
+ }
+
+ if ( instance == null )
+ {
+ instance = ( ElementSerializer<K> ) keySerializer.newInstance();
+ }
+
btree.setKeySerializer( instance );
}
/**
- * Sets the ValueSerializer into the BTree
- *
- * @param btree The BTree to update
+ * Sets the ValueSerializer into the B-tree
+ *
+ * @param btree The B-tree to update
* @param valueSerializerFqcn the Value serializer FQCN to set
- * @throws ClassNotFoundException
- * @throws InstantiationException
- * @throws IllegalAccessException
+ * @throws ClassNotFoundException If the value serializer class cannot be found
+ * @throws InstantiationException If the value serializer class cannot be instanciated
+ * @throws IllegalAccessException If the value serializer class cannot be accessed
+ * @throws NoSuchFieldException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
*/
/* no qualifier*/static <K, V> void setValueSerializer( BTree<K, V> btree, String valueSerializerFqcn )
- throws ClassNotFoundException, IllegalAccessException, InstantiationException
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException
{
Class<?> valueSerializer = Class.forName( valueSerializerFqcn );
@SuppressWarnings("unchecked")
- ElementSerializer<V> instance = ( ElementSerializer<V> ) valueSerializer.newInstance();
+ ElementSerializer<V> instance = null;
+ try
+ {
+ instance = ( ElementSerializer<V> ) valueSerializer.getDeclaredField( "INSTANCE" ).get( null );
+ }
+ catch( NoSuchFieldException e )
+ {
+ // ignore
+ }
+
+ if ( instance == null )
+ {
+ instance = ( ElementSerializer<V> ) valueSerializer.newInstance();
+ }
+
btree.setValueSerializer( instance );
}
@@ -606,8 +671,8 @@
/**
* Set the new root page for this tree. Used for debug purpose only. The revision
* will always be 0;
- *
- * @param btree The BTree to update
+ *
+ * @param btree The B-tree to update
* @param root the new root page.
*/
/* no qualifier*/static <K, V> void setRootPage( BTree<K, V> btree, Page<K, V> root )
@@ -617,9 +682,9 @@
/**
- * Return the BTree root page
- *
- * @param btree The Btree we want to root page from
+ * Return the B-tree root page
+ *
+ * @param btree The B-tree we want to root page from
* @return The root page
*/
/* no qualifier */static <K, V> Page<K, V> getRootPage( BTree<K, V> btree )
@@ -629,9 +694,9 @@
/**
- * update the BTree number of elements
- *
- * @param btree The BTree to update
+ * Update the B-tree number of elements
+ *
+ * @param btree The B-tree to update
* @param nbElems the nbElems to set
*/
/* no qualifier */static <K, V> void setNbElems( BTree<K, V> btree, long nbElems )
@@ -641,9 +706,9 @@
/**
- * Update the btree revision
- *
- * @param btree The BTree to update
+ * Update the B-tree revision
+ *
+ * @param btree The B-tree to update
* @param revision the revision to set
*/
/* no qualifier*/static <K, V> void setRevision( BTree<K, V> btree, long revision )
@@ -653,9 +718,9 @@
/**
- * Set the BTree name
- *
- * @param btree The BTree to update
+ * Set the B-tree name
+ *
+ * @param btree The B-tree to update
* @param name the name to set
*/
/* no qualifier */static <K, V> void setName( BTree<K, V> btree, String name )
@@ -666,8 +731,8 @@
/**
* Set the maximum number of elements we can store in a page.
- *
- * @param btree The BTree to update
+ *
+ * @param btree The B-tree to update
* @param pageSize The requested page size
*/
/* no qualifier */static <K, V> void setPageSize( BTree<K, V> btree, int pageSize )
@@ -681,8 +746,8 @@
//--------------------------------------------------------------------------------------------
/**
* Includes the intermediate nodes in the path up to and including the right most leaf of the tree
- *
- * @param btree the btree
+ *
+ * @param btree the B-tree
* @return a LinkedList of all the nodes and the final leaf
*/
/* no qualifier*/static <K, V> LinkedList<ParentPos<K, V>> getPathToRightMostLeaf( BTree<K, V> btree )
@@ -724,50 +789,31 @@
//--------------------------------------------------------------------------------------------
- // Persisted BTree methods
+ // Persisted B-tree methods
//--------------------------------------------------------------------------------------------
/**
- * Set the rootPage offset of the BTree
- *
- * @param btree The btree to update
+ * Set the rootPage offset of the B-tree
+ *
+ * @param btree The B-tree to update
* @param rootPageOffset The rootPageOffset to set
*/
/* no qualifier*/static <K, V> void setRootPageOffset( BTree<K, V> btree, long rootPageOffset )
{
if ( btree instanceof PersistedBTree )
{
- ( ( PersistedBTree<K, V> ) btree ).setRootPageOffset( rootPageOffset );
+ ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader().setRootPageOffset( rootPageOffset );
}
else
{
- throw new IllegalArgumentException( "The BTree must be a PersistedBTree" );
- }
- }
-
-
- /**
- * Set the nextBTree offset
- *
- * @param btree The btree to update
- * @param nextBTreeOffset The nextBTreeOffset to set
- */
- /* no qualifier*/static <K, V> void setNextBTreeOffset( BTree<K, V> btree, long nextBTreeOffset )
- {
- if ( btree instanceof PersistedBTree )
- {
- ( ( PersistedBTree<K, V> ) btree ).setNextBTreeOffset( nextBTreeOffset );
- }
- else
- {
- throw new IllegalArgumentException( "The BTree must be a PersistedBTree" );
+ throw new IllegalArgumentException( "The B-tree must be a PersistedBTree" );
}
}
/**
* Set the RecordManager
- *
- * @param btree The btree to update
+ *
+ * @param btree The B-tree to update
* @param recordManager The injected RecordManager
*/
/* no qualifier*/static <K, V> void setRecordManager( BTree<K, V> btree, RecordManager recordManager )
@@ -778,15 +824,15 @@
}
else
{
- throw new IllegalArgumentException( "The BTree must be a PersistedBTree" );
+ throw new IllegalArgumentException( "The B-tree must be a PersistedBTree" );
}
}
/**
* Set the key at a give position
- *
- * @param btree The btree to update
+ *
+ * @param btree The B-tree to update
* @param page The page to update
* @param pos The position of this key in the page
* @param buffer The byte[] containing the serialized key
@@ -800,15 +846,15 @@
}
else
{
- throw new IllegalArgumentException( "The BTree must be a PersistedBTree" );
+ throw new IllegalArgumentException( "The B-tree must be a PersistedBTree" );
}
}
/**
* Includes the intermediate nodes in the path up to and including the left most leaf of the tree
- *
- * @param btree The btree to process
+ *
+ * @param btree The B-tree to process
* @return a LinkedList of all the nodes and the final leaf
*/
/* no qualifier*/static <K, V> LinkedList<ParentPos<K, V>> getPathToLeftMostLeaf( BTree<K, V> btree )
@@ -850,7 +896,7 @@
}
else
{
- throw new IllegalArgumentException( "The BTree must be a PersistedBTree" );
+ throw new IllegalArgumentException( "The B-tree must be a PersistedBTree" );
}
}
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeHeader.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeHeader.java
index a6ec76d..2202551 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeHeader.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeHeader.java
@@ -19,13 +19,12 @@
*/
package org.apache.directory.mavibot.btree;
-
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicInteger;
/**
- * Store in memory the information associated with a BTree. <br>
- * A BTree Header on disk contains the following elements :
+ * Store in memory the information associated with a B-tree. <br>
+ * A B-tree Header on disk contains the following elements :
* <pre>
* +--------------------+-------------+
* | revision | 8 bytes |
@@ -34,55 +33,42 @@
* +--------------------+-------------+
* | rootPageOffset | 8 bytes |
* +--------------------+-------------+
- * | nextBtreeHeader | 8 bytes |
- * +--------------------+-------------+
- * | pageSize | 4 bytes |
- * +--------------------+-------------+
- * | name | 4 bytes + N |
- * +--------------------+-------------+
- * | keySerializeFQCN | 4 bytes + N |
- * +--------------------+-------------+
- * | valueSerializeFQCN | 4 bytes + N |
+ * | BtreeOffset | 8 bytes |
* +--------------------+-------------+
* </pre>
- * Each BtreeHeader will be written starting on a new page.
+ * Each B-tree Header will be written starting on a new page.
+ * In memory, a B-tree Header store a bit more of information :
+ * <li>
+ * <ul>rootPage : the associated rootPage in memory</lu>
+ * <ul>nbUsers : the number of readThreads using this revision</lu>
+ * <ul>offset : the offset of this B-tre header</lu>
+ * </li>
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-/* No qualifier*/class BTreeHeader
+/* No qualifier*/class BTreeHeader<K, V> implements Cloneable
{
/** The current revision */
- private AtomicLong revision = new AtomicLong( 0L );
+ private long revision = 0L;
- /** The number of elements in this BTree */
- private AtomicLong nbElems = new AtomicLong( 0L );
+ /** The number of elements in this B-tree */
+ private Long nbElems = 0L;
- /** The offset of the BTree RootPage */
+ /** The offset of the B-tree RootPage */
private long rootPageOffset;
- /** The offset of the next BTree */
- private long nextBTreeOffset;
-
- /** The number of elements in a page for this BTree */
- private int pageSize;
-
- /** The BTree name */
- private String name;
-
- /** The FQCN of the Key serializer */
- private String keySerializerFQCN;
-
- /** The FQCN of the Value serializer */
- private String valueSerializerFQCN;
+ /** The position of the B-tree header in the file */
+ private long btreeHeaderOffset;
// Those are data which aren't serialized : they are in memory only */
- /** The position in the file */
- private long btreeOffset;
+ /** A Map containing the rootPage for this tree */
+ private Page<K, V> rootPage;
- /** The existing versions */
- private long[] versions;
+ /** The number of users for this BtreeHeader */
+ private AtomicInteger nbUsers = new AtomicInteger( 0 );
- private int allowDuplicates = 0;
+ /** The B-tree this header is associated with */
+ private BTree<K, V> btree;
/**
@@ -94,56 +80,61 @@
/**
- * @return the name
+ * @return the B-tree info Offset
*/
- public String getName()
+ public long getBTreeInfoOffset()
{
- return name;
+ return ((PersistedBTree<K, V>)btree).getBtreeInfoOffset();
}
/**
- * @param name the name to set
+ * @return the B-tree header Offset
*/
- /* no qualifier */void setName( String name )
+ public long getBTreeHeaderOffset()
{
- this.name = name;
+ return btreeHeaderOffset;
+ }
+
+
+ public BTreeHeader<K, V> clone()
+ {
+ try
+ {
+ BTreeHeader<K, V> copy = (BTreeHeader<K, V>)super.clone();
+
+ return copy;
+ }
+ catch ( CloneNotSupportedException cnse )
+ {
+ return null;
+ }
}
/**
- * @return the versions
+ * Copy the current B-tre header and return the copy
+ * @return
*/
- public long[] getVersions()
+ /* no qualifier */ BTreeHeader<K, V> copy()
{
- return versions;
+ BTreeHeader<K, V> copy = clone();
+
+ // Clear the fields that should not be copied
+ copy.rootPage = null;
+ copy.rootPageOffset = -1L;
+ copy.btreeHeaderOffset = -1L;
+
+ return copy;
}
/**
- * @param versions the versions to set
+ * @param btreeOffset the B-tree header Offset to set
*/
- /* no qualifier */void setVersions( long[] versions )
+ /* no qualifier */void setBTreeHeaderOffset( long btreeHeaderOffset )
{
- this.versions = versions;
- }
-
-
- /**
- * @return the btreeOffset
- */
- public long getBTreeOffset()
- {
- return btreeOffset;
- }
-
-
- /**
- * @param btreeOffset the btreeOffset to set
- */
- /* no qualifier */void setBTreeOffset( long btreeOffset )
- {
- this.btreeOffset = btreeOffset;
+ this.btreeHeaderOffset = btreeHeaderOffset;
}
@@ -170,7 +161,7 @@
*/
public long getRevision()
{
- return revision.get();
+ return revision;
}
@@ -179,18 +170,7 @@
*/
/* no qualifier */void setRevision( long revision )
{
- this.revision.set( revision );
- }
-
-
- /**
- * Increment the revision
- *
- * @return the new revision
- */
- /* no qualifier */long incrementRevision()
- {
- return revision.incrementAndGet();
+ this.revision = revision;
}
@@ -199,25 +179,7 @@
*/
public long getNbElems()
{
- return nbElems.get();
- }
-
-
- /**
- * Increment the number of elements
- */
- /* no qualifier */void incrementNbElems()
- {
- nbElems.incrementAndGet();
- }
-
-
- /**
- * Decrement the number of elements
- */
- public void decrementNbElems()
- {
- nbElems.decrementAndGet();
+ return nbElems;
}
@@ -226,91 +188,89 @@
*/
/* no qualifier */void setNbElems( long nbElems )
{
- this.nbElems.set( nbElems );
+ this.nbElems = nbElems;
}
/**
- * @return the nextBTreeOffset
+ * Increment the number of elements
*/
- public long getNextBTreeOffset()
+ /* no qualifier */void incrementNbElems()
{
- return nextBTreeOffset;
+ nbElems++;
}
/**
- * @param nextBtreeOffset the nextBtreeOffset to set
+ * Decrement the number of elements
*/
- /* no qualifier */void setNextBTreeOffset( long nextBTreeOffset )
+ /* no qualifier */void decrementNbElems()
{
- this.nextBTreeOffset = nextBTreeOffset;
+ nbElems--;
}
/**
- * @return the pageSize
+ * @return the rootPage
*/
- public int getPageSize()
+ /* no qualifier */ Page<K, V> getRootPage()
{
- return pageSize;
+ return rootPage;
}
/**
- * @param pageSize the pageSize to set
+ * @param rootPage the rootPage to set
*/
- /* no qualifier */void setPageSize( int pageSize )
+ /* no qualifier */ void setRootPage( Page<K, V> rootPage )
{
- this.pageSize = pageSize;
+ this.rootPage = rootPage;
+ this.rootPageOffset = ((AbstractPage<K, V>)rootPage).getOffset();
}
/**
- * @return the keySerializerFQCN
+ * @return the nbUsers
*/
- public String getKeySerializerFQCN()
+ /* no qualifier */ int getNbUsers()
{
- return keySerializerFQCN;
+ return nbUsers.get();
}
/**
- * @param keySerializerFQCN the keySerializerFQCN to set
+ * Increment the number of users
*/
- /* no qualifier */void setKeySerializerFQCN( String keySerializerFQCN )
+ /* no qualifier */ void incrementNbUsers()
{
- this.keySerializerFQCN = keySerializerFQCN;
+ nbUsers.incrementAndGet();
}
/**
- * @return the valueSerializerFQCN
+ * Decrement the number of users
*/
- public String getValueSerializerFQCN()
+ /* no qualifier */ void decrementNbUsers()
{
- return valueSerializerFQCN;
+ nbUsers.decrementAndGet();
}
/**
- * @param valueSerializerFQCN the valueSerializerFQCN to set
+ * @return the btree
*/
- /* no qualifier */void setValueSerializerFQCN( String valueSerializerFQCN )
+ /* no qualifier */ BTree<K, V> getBtree()
{
- this.valueSerializerFQCN = valueSerializerFQCN;
+ return btree;
}
- public boolean isAllowDuplicates()
+ /**
+ * @param btree the btree to set
+ */
+ /* no qualifier */ void setBtree( BTree<K, V> btree )
{
- return ( allowDuplicates == 1 );
- }
-
-
- /* no qualifier */void setAllowDuplicates( boolean allowDuplicates )
- {
- this.allowDuplicates = ( allowDuplicates ? 1 : 0 );
+ this.btree = btree;
}
@@ -321,42 +281,14 @@
{
StringBuilder sb = new StringBuilder();
- sb.append( "Btree '" ).append( name ).append( "'" );
+ sb.append( "B-treeHeader " );
+ sb.append( ", offset[0x" ).append( Long.toHexString( btreeHeaderOffset ) ).append( "]" );
+ sb.append( ", name[" ).append( btree.getName() ).append( "]" );
sb.append( ", revision[" ).append( revision ).append( "]" );
- sb.append( ", btreeOffset[" ).append( btreeOffset ).append( "]" );
- sb.append( ", rootPageOffset[" ).append( rootPageOffset ).append( "]" );
- sb.append( ", nextBTree[" ).append( nextBTreeOffset ).append( "]" );
+ sb.append( ", btreeInfoOffset[0x" ).append( Long.toHexString( ((PersistedBTree<K, V>)btree).getBtreeInfoOffset() ) ).append( "]" );
+ sb.append( ", rootPageOffset[0x" ).append( Long.toHexString( rootPageOffset ) ).append( "]" );
sb.append( ", nbElems[" ).append( nbElems ).append( "]" );
- sb.append( ", pageSize[" ).append( pageSize ).append( "]" );
- sb.append( ", hasDuplicates[" ).append( isAllowDuplicates() ).append( "]" );
- sb.append( "{\n" );
- sb.append( " Key serializer : " ).append( keySerializerFQCN ).append( "\n" );
- sb.append( " Value serializer : " ).append( valueSerializerFQCN ).append( "\n" );
- sb.append( "}\n" );
-
- if ( ( versions != null ) && ( versions.length != 0 ) )
- {
- sb.append( "Versions : \n" );
- sb.append( "{\n" );
-
- boolean isFirst = true;
-
- for ( long version : versions )
- {
- if ( isFirst )
- {
- isFirst = false;
- }
- else
- {
- sb.append( ",\n" );
- }
-
- sb.append( " " ).append( version );
- }
-
- sb.append( "}\n" );
- }
+ sb.append( ", nbUsers[" ).append( nbUsers.get() ).append( "]" );
return sb.toString();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeTypeEnum.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeTypeEnum.java
index ffa6fbe..0a2db9c 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeTypeEnum.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/BTreeTypeEnum.java
@@ -21,24 +21,35 @@
/**
- * An enum to describe the BTree type. We have three possible type :
+ * An enum to describe the B-tree type. We have three possible type :
* <ul>
- * <li>IN_MEMORY : the BTree will remain in memory, and won't be persisted on disk</li>
- * <li>PERSISTENT : the BTree is in memory, but will be persisted on disk</li>
- * <li>MANAGED : the BTree is managed by a RecordManager, and some pages may
+ * <li>IN_MEMORY : the B-tree will remain in memory, and won't be persisted on disk</li>
+ * <li>BACKED_ON_DISK : the B-tree is in memory, but will be persisted on disk</li>
+ * <li>PERSISTED : the B-tree is managed by a RecordManager, and some pages may
* be swapped out from memory on demand</li>
+ * <li>PERSISTED_SUB : The B-tree is a Persisted B-tree, but a Sub B-tree one</li>
+ * <li>PERSISTED_MANAGEMENT : This is a Persisted B-tree used to manage the other B-trees</li>
* </ul>
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public enum BTreeTypeEnum
{
- /** Pure in-memory BTree, not persisted on disk */
+ /** Pure in-memory B-tree, not persisted on disk */
IN_MEMORY,
- /** Persisted BTree */
+ /** Persisted B-tree */
PERSISTED,
- /** In-memory BTree but saved on disk */
+ /** Persisted sub B-tree */
+ PERSISTED_SUB,
+
+ /** Persisted Management B-tree */
+ BTREE_OF_BTREES,
+
+ /** Persisted Management B-tree */
+ COPIED_PAGES_BTREE,
+
+ /** In-memory B-tree but saved on disk */
BACKED_ON_DISK
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyTupleCursor.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyTupleCursor.java
new file mode 100644
index 0000000..4afefb2
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyTupleCursor.java
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+
+import java.io.IOException;
+import java.util.NoSuchElementException;
+
+import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
+
+
+/**
+ * A Cursor which is used when we have no element to return
+ * <p>
+ *
+ * @param <K> The type for the Key
+ * @param <V> The type for the stored value
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EmptyTupleCursor<K, V> extends TupleCursor<K, V>
+{
+ private long revision;
+ private long creationDate;
+
+ /**
+ * Creates a new instance of Cursor, starting on a page at a given position.
+ *
+ * @param transaction The transaction this operation is protected by
+ * @param stack The stack of parent's from root to this page
+ */
+ public EmptyTupleCursor( long revision )
+ {
+ super();
+
+ this.revision = revision;
+ creationDate = System.currentTimeMillis();
+ }
+
+
+ /**
+ * Change the position in the current cursor to set it after the last key
+ */
+ public void afterLast() throws IOException
+ {
+ }
+
+
+ /**
+ * Change the position in the current cursor before the first key
+ */
+ public void beforeFirst() throws IOException
+ {
+ }
+
+
+ /**
+ * Tells if the cursor can return a next element
+ *
+ * @return true if there are some more elements
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasNext() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Find the next key/value
+ *
+ * @return A Tuple containing the found key and value
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public Tuple<K, V> next() throws EndOfFileExceededException, IOException
+ {
+ throw new NoSuchElementException( "No tuple present" );
+ }
+
+
+ /**
+ * Get the next non-duplicate key.
+ * If the BTree contains :
+ *
+ * <ul>
+ * <li><1,0></li>
+ * <li><1,1></li>
+ * <li><1,2></li>
+ * <li><2,0></li>
+ * <li><2,1></li>
+ * </ul>
+ *
+ * and cursor is present at <1,1> then the returned tuple will be <2,0> (not <1,2>)
+ *
+ * @return A Tuple containing the found key and value
+ * @throws EndOfFileExceededException
+ * @throws IOException
+ */
+ public Tuple<K, V> nextKey() throws EndOfFileExceededException, IOException
+ {
+ // This is the end : no more value
+ throw new NoSuchElementException( "No more tuples present" );
+ }
+
+
+ /**
+ * Tells if the cursor can return a next key
+ *
+ * @return true if there are some more keys
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasNextKey() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Tells if the cursor can return a previous element
+ *
+ * @return true if there are some more elements
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasPrev() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Find the previous key/value
+ *
+ * @return A Tuple containing the found key and value
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public Tuple<K, V> prev() throws EndOfFileExceededException, IOException
+ {
+ throw new NoSuchElementException( "No more tuple present" );
+ }
+
+
+ /**
+ * Get the previous non-duplicate key.
+ * If the BTree contains :
+ *
+ * <ul>
+ * <li><1,0></li>
+ * <li><1,1></li>
+ * <li><1,2></li>
+ * <li><2,0></li>
+ * <li><2,1></li>
+ * </ul>
+ *
+ * and cursor is present at <2,1> then the returned tuple will be <1,0> (not <2,0>)
+ *
+ * @return A Tuple containing the found key and value
+ * @throws EndOfFileExceededException
+ * @throws IOException
+ */
+ public Tuple<K, V> prevKey() throws EndOfFileExceededException, IOException
+ {
+ throw new NoSuchElementException( "No more tuples present" );
+ }
+
+
+ /**
+ * Tells if the cursor can return a previous key
+ *
+ * @return true if there are some more keys
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasPrevKey() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close()
+ {
+ }
+
+
+ /**
+ * Get the creation date
+ * @return The creation date for this cursor
+ */
+ public long getCreationDate()
+ {
+ return creationDate;
+ }
+
+
+ /**
+ * Get the current revision
+ *
+ * @return The revision this cursor is based on
+ */
+ public long getRevision()
+ {
+ return revision;
+ }
+
+
+ public String toString()
+ {
+ return "EmptyTupleCursor";
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyValueCursor.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyValueCursor.java
new file mode 100644
index 0000000..f38e7a4
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/EmptyValueCursor.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+
+import java.io.IOException;
+
+import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
+
+
+/**
+ * A Cursor which is used when we have no value to return
+ * <p>
+ *
+ * @param <K> The type for the Key
+ * @param <V> The type for the stored value
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class EmptyValueCursor<V> implements ValueCursor<V>
+{
+ private long revision;
+ private long creationDate;
+
+ /**
+ * Creates a new instance of Cursor, starting on a page at a given position.
+ *
+ * @param transaction The transaction this operation is protected by
+ * @param stack The stack of parent's from root to this page
+ */
+ public EmptyValueCursor( long revision )
+ {
+ super();
+
+ this.revision = revision;
+ creationDate = System.currentTimeMillis();
+ }
+
+
+ /**
+ * Change the position in the current cursor to set it after the last key
+ */
+ public void afterLast() throws IOException
+ {
+ }
+
+
+ /**
+ * Change the position in the current cursor before the first key
+ */
+ public void beforeFirst() throws IOException
+ {
+ }
+
+
+ /**
+ * Tells if the cursor can return a next element
+ *
+ * @return true if there are some more elements
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasNext() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Tells if the cursor can return a next key
+ *
+ * @return true if there are some more keys
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasNextKey() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Tells if the cursor can return a previous element
+ *
+ * @return true if there are some more elements
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasPrev() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * Tells if the cursor can return a previous key
+ *
+ * @return true if there are some more keys
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ public boolean hasPrevKey() throws EndOfFileExceededException, IOException
+ {
+ return false;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V prev() throws EndOfFileExceededException, IOException
+ {
+ return null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public V next() throws EndOfFileExceededException, IOException
+ {
+ return null;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void close()
+ {
+ }
+
+
+ /**
+ * Get the creation date
+ * @return The creation date for this cursor
+ */
+ public long getCreationDate()
+ {
+ return creationDate;
+ }
+
+
+ /**
+ * Get the current revision
+ *
+ * @return The revision this cursor is based on
+ */
+ public long getRevision()
+ {
+ return revision;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+
+
+ public String toString()
+ {
+ return "EmptyValueCursor";
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
index 0be326c..fb09eac 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryBTree.java
@@ -29,7 +29,6 @@
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.locks.ReentrantLock;
import org.apache.directory.mavibot.btree.exception.InitializationException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
@@ -72,18 +71,18 @@
/** The associated journal. If null, this is an in-memory btree */
private File journal;
+ /** The directory where the journal will be stored */
private File envDir;
+ /** The Journal channel */
private FileChannel journalChannel = null;
-
/**
* Creates a new BTree, with no initialization.
*/
/* no qualifier */InMemoryBTree()
{
super();
- btreeHeader = new BTreeHeader();
setType( BTreeTypeEnum.IN_MEMORY );
}
@@ -97,9 +96,9 @@
/* no qualifier */InMemoryBTree( InMemoryBTreeConfiguration<K, V> configuration )
{
super();
- String name = configuration.getName();
+ String btreeName = configuration.getName();
- if ( name == null )
+ if ( btreeName == null )
{
throw new IllegalArgumentException( "BTree name cannot be null" );
}
@@ -111,29 +110,35 @@
envDir = new File( filePath );
}
- btreeHeader = new BTreeHeader();
- btreeHeader.setName( name );
- btreeHeader.setPageSize( configuration.getPageSize() );
-
- keySerializer = configuration.getKeySerializer();
- btreeHeader.setKeySerializerFQCN( keySerializer.getClass().getName() );
-
- valueSerializer = configuration.getValueSerializer();
- btreeHeader.setValueSerializerFQCN( valueSerializer.getClass().getName() );
+ // Store the configuration in the B-tree
+ setName( btreeName );
+ setPageSize( configuration.getPageSize() );
+ setKeySerializer( configuration.getKeySerializer() );
+ setValueSerializer( configuration.getValueSerializer() );
+ setAllowDuplicates( configuration.isAllowDuplicates() );
+ setType( configuration.getType() );
readTimeOut = configuration.getReadTimeOut();
writeBufferSize = configuration.getWriteBufferSize();
- btreeHeader.setAllowDuplicates( configuration.isAllowDuplicates() );
- setType( configuration.getType() );
if ( keySerializer.getComparator() == null )
{
throw new IllegalArgumentException( "Comparator should not be null" );
}
+ // Create the B-tree header
+ BTreeHeader<K, V> newBtreeHeader = new BTreeHeader<K, V>();
+
// Create the first root page, with revision 0L. It will be empty
// and increment the revision at the same time
- rootPage = new InMemoryLeaf<K, V>( this );
+ newBtreeHeader.setBTreeHeaderOffset( 0L );
+ newBtreeHeader.setRevision( 0L );
+ newBtreeHeader.setNbElems( 0L );
+ newBtreeHeader.setRootPage( new InMemoryLeaf<K, V>( this ) );
+ newBtreeHeader.setRootPageOffset( 0L );
+
+ btreeRevisions.put( 0L, newBtreeHeader );
+ currentBtreeHeader = newBtreeHeader;
// Now, initialize the BTree
try
@@ -152,7 +157,7 @@
*
* @throws IOException If we get some exception while initializing the BTree
*/
- public void init() throws IOException
+ private void init() throws IOException
{
// if not in-memory then default to persist mode instead of managed
if ( envDir != null )
@@ -160,13 +165,14 @@
if ( !envDir.exists() )
{
boolean created = envDir.mkdirs();
+
if ( !created )
{
throw new IllegalStateException( "Could not create the directory " + envDir + " for storing data" );
}
}
- this.file = new File( envDir, btreeHeader.getName() + DATA_SUFFIX );
+ this.file = new File( envDir, getName() + DATA_SUFFIX );
this.journal = new File( envDir, file.getName() + JOURNAL_SUFFIX );
setType( BTreeTypeEnum.BACKED_ON_DISK );
@@ -174,8 +180,9 @@
// Create the queue containing the pending read transactions
readTransactions = new ConcurrentLinkedQueue<ReadTransaction<K, V>>();
-
- writeLock = new ReentrantLock();
+
+ // Create the transaction manager
+ transactionManager = new InMemoryTransactionManager();
// Check the files and create them if missing
// Create the queue containing the modifications, if it's not a in-memory btree
@@ -202,6 +209,12 @@
else
{
setType( BTreeTypeEnum.IN_MEMORY );
+
+ // This is a new Btree, we have to store the BtreeHeader
+ BTreeHeader<K, V> btreeHeader = new BTreeHeader<K, V>();
+ btreeHeader.setRootPage( new InMemoryLeaf<K, V>( this ) );
+ btreeHeader.setBtree( this );
+ storeRevision( btreeHeader );
}
// Initialize the txnManager thread
@@ -211,6 +224,43 @@
/**
+ * {@inheritDoc}
+ */
+ protected ReadTransaction<K, V> beginReadTransaction()
+ {
+ BTreeHeader<K, V> btreeHeader = getBtreeHeader();
+
+ ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( btreeHeader, readTransactions );
+
+ readTransactions.add( readTransaction );
+
+ return readTransaction;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected ReadTransaction<K, V> beginReadTransaction( long revision )
+ {
+ BTreeHeader<K, V> btreeHeader = getBtreeHeader( revision );
+
+ if ( btreeHeader != null )
+ {
+ ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( btreeHeader, readTransactions );
+
+ readTransactions.add( readTransaction );
+
+ return readTransaction;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
+ /**
* Close the BTree, cleaning up all the data structure
*/
public void close() throws IOException
@@ -225,8 +275,6 @@
flush();
journalChannel.close();
}
-
- rootPage = null;
}
@@ -244,59 +292,65 @@
*/
protected Tuple<K, V> delete( K key, V value, long revision ) throws IOException
{
- writeLock.lock();
-
- try
+ if ( revision == -1L )
{
- // If the key exists, the existing value will be replaced. We store it
- // to return it to the caller.
- Tuple<K, V> tuple = null;
-
- // Try to delete the entry starting from the root page. Here, the root
- // page may be either a Node or a Leaf
- DeleteResult<K, V> result = rootPage.delete( revision, key, value, null, -1 );
-
- if ( result instanceof NotPresentResult )
- {
- // Key not found.
- return null;
- }
-
- // Keep the oldRootPage so that we can later access it
- Page<K, V> oldRootPage = rootPage;
-
- if ( result instanceof RemoveResult )
- {
- // The element was found, and removed
- RemoveResult<K, V> removeResult = ( RemoveResult<K, V> ) result;
-
- Page<K, V> modifiedPage = removeResult.getModifiedPage();
-
- // This is a new root
- rootPage = modifiedPage;
- tuple = removeResult.getRemovedElement();
- }
-
- if ( withJournal )
- {
- // Inject the modification into the modification queue
- writeToJournal( new Deletion<K, V>( key ) );
- }
-
- // Decrease the number of elements in the current tree if the deletion is successful
- if ( tuple != null )
- {
- btreeHeader.decrementNbElems();
- }
-
- // Return the value we have found if it was modified
- return tuple;
+ revision = currentRevision.get() + 1;
}
- finally
+
+ BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
+ BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+ newBtreeHeader.setBtree( this );
+
+ // If the key exists, the existing value will be replaced. We store it
+ // to return it to the caller.
+ Tuple<K, V> tuple = null;
+
+ // Try to delete the entry starting from the root page. Here, the root
+ // page may be either a Node or a Leaf
+ DeleteResult<K, V> result = getRootPage().delete( key, value, revision );
+
+ if ( result instanceof NotPresentResult )
{
- // See above
- writeLock.unlock();
+ // Key not found.
+ return null;
}
+
+ // Keep the oldRootPage so that we can later access it
+ //Page<K, V> oldRootPage = rootPage;
+
+ if ( result instanceof RemoveResult )
+ {
+ // The element was found, and removed
+ RemoveResult<K, V> removeResult = ( RemoveResult<K, V> ) result;
+
+ Page<K, V> modifiedPage = removeResult.getModifiedPage();
+
+ // This is a new root
+ newBtreeHeader.setRootPage( modifiedPage );
+ tuple = removeResult.getRemovedElement();
+ }
+
+ if ( withJournal )
+ {
+ // Inject the modification into the modification queue
+ writeToJournal( new Deletion<K, V>( key ) );
+ }
+
+ // Decrease the number of elements in the current tree if the deletion is successful
+ if ( tuple != null )
+ {
+ newBtreeHeader.decrementNbElems();
+ }
+
+ storeRevision( newBtreeHeader );
+
+ // Return the value we have found if it was modified
+ if ( oldBtreeHeader.getNbUsers() == 0 )
+ {
+ btreeRevisions.remove( oldBtreeHeader.getRevision() );
+ }
+
+ return tuple;
}
@@ -315,11 +369,17 @@
*/
/* no qualifier */InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
- if ( key == null )
+ // We have to start a new transaction, which will be committed or rollbacked
+ // locally. This will duplicate the current BtreeHeader during this phase.
+ if ( revision == -1L )
{
- throw new IllegalArgumentException( "Key must not be null" );
+ revision = currentRevision.get() + 1;
}
+ BTreeHeader<K, V> oldBtreeHeader = getBtreeHeader();
+ BTreeHeader<K, V> newBtreeHeader = createNewBtreeHeader( oldBtreeHeader, revision );
+ newBtreeHeader.setBtree( this );
+
// If the key exists, the existing value will be replaced. We store it
// to return it to the caller.
V modifiedValue = null;
@@ -327,7 +387,7 @@
// Try to insert the new value in the tree at the right place,
// starting from the root page. Here, the root page may be either
// a Node or a Leaf
- InsertResult<K, V> result = rootPage.insert( revision, key, value );
+ InsertResult<K, V> result = newBtreeHeader.getRootPage().insert( key, value, revision );
if ( result instanceof ModifyResult )
{
@@ -337,7 +397,7 @@
// The root has just been modified, we haven't split it
// Get it and make it the current root page
- rootPage = modifiedPage;
+ newBtreeHeader.setRootPage( modifiedPage );
modifiedValue = modifyResult.getModifiedValue();
}
@@ -350,12 +410,9 @@
K pivot = splitResult.getPivot();
Page<K, V> leftPage = splitResult.getLeftPage();
Page<K, V> rightPage = splitResult.getRightPage();
- Page<K, V> newRootPage = null;
// Create the new rootPage
- newRootPage = new InMemoryNode<K, V>( this, revision, pivot, leftPage, rightPage );
-
- rootPage = newRootPage;
+ newBtreeHeader.setRootPage( new InMemoryNode<K, V>( this, revision, pivot, leftPage, rightPage ) );
}
// Inject the modification into the modification queue
@@ -368,7 +425,19 @@
// and does not replace an element
if ( modifiedValue == null )
{
- btreeHeader.incrementNbElems();
+ newBtreeHeader.incrementNbElems();
+ }
+
+ storeRevision( newBtreeHeader );
+
+ if ( oldBtreeHeader.getNbUsers() == 0 )
+ {
+ long oldRevision = oldBtreeHeader.getRevision();
+
+ if ( oldRevision < newBtreeHeader.getRevision() )
+ {
+ btreeRevisions.remove( oldBtreeHeader.getRevision() );
+ }
}
// Return the value we have found if it was modified
@@ -443,45 +512,53 @@
// Create a buffer containing 200 4Kb pages (around 1Mb)
ByteBuffer bb = ByteBuffer.allocateDirect( writeBufferSize );
- TupleCursor<K, V> cursor = browse();
-
- if ( keySerializer == null )
+ try
{
- throw new MissingSerializerException( "Cannot flush the btree without a Key serializer" );
+ TupleCursor<K, V> cursor = browse();
+
+ if ( keySerializer == null )
+ {
+ throw new MissingSerializerException( "Cannot flush the btree without a Key serializer" );
+ }
+
+ if ( valueSerializer == null )
+ {
+ throw new MissingSerializerException( "Cannot flush the btree without a Value serializer" );
+ }
+
+ // Write the number of elements first
+ bb.putLong( getBtreeHeader().getNbElems() );
+
+ while ( cursor.hasNext() )
+ {
+ Tuple<K, V> tuple = cursor.next();
+
+ byte[] keyBuffer = keySerializer.serialize( tuple.getKey() );
+
+ writeBuffer( ch, bb, keyBuffer );
+
+ byte[] valueBuffer = valueSerializer.serialize( tuple.getValue() );
+
+ writeBuffer( ch, bb, valueBuffer );
+ }
+
+ // Write the buffer if needed
+ if ( bb.position() > 0 )
+ {
+ bb.flip();
+ ch.write( bb );
+ }
+
+ // Flush to the disk for real
+ ch.force( true );
+ ch.close();
}
-
- if ( valueSerializer == null )
+ catch ( KeyNotFoundException knfe )
{
- throw new MissingSerializerException( "Cannot flush the btree without a Value serializer" );
+ knfe.printStackTrace();
+ throw new IOException( knfe.getMessage() );
}
- // Write the number of elements first
- bb.putLong( btreeHeader.getNbElems() );
-
- while ( cursor.hasNext() )
- {
- Tuple<K, V> tuple = cursor.next();
-
- byte[] keyBuffer = keySerializer.serialize( tuple.getKey() );
-
- writeBuffer( ch, bb, keyBuffer );
-
- byte[] valueBuffer = valueSerializer.serialize( tuple.getValue() );
-
- writeBuffer( ch, bb, valueBuffer );
- }
-
- // Write the buffer if needed
- if ( bb.position() > 0 )
- {
- bb.flip();
- ch.write( bb );
- }
-
- // Flush to the disk for real
- ch.force( true );
- ch.close();
-
// Rename the current file to save a backup
File backupFile = File.createTempFile( "mavibot", null, baseDirectory );
file.renameTo( backupFile );
@@ -501,8 +578,6 @@
*/
private void applyJournal() throws IOException
{
- long revision = generateRevision();
-
if ( !journal.exists() )
{
throw new IOException( "The journal does not exist" );
@@ -535,7 +610,7 @@
//values.add( value );
// Inject the data in the tree. (to be replaced by a bulk load)
- insert( key, value, revision );
+ insert( key, value, getBtreeHeader().getRevision() );
}
else
{
@@ -543,7 +618,7 @@
K key = keySerializer.deserialize( bufferHandler );
// Remove the key from the tree
- delete( key, revision );
+ delete( key, getBtreeHeader().getRevision() );
}
}
}
@@ -565,8 +640,6 @@
*/
public void load( File file ) throws IOException
{
- long revision = generateRevision();
-
if ( !file.exists() )
{
throw new IOException( "The file does not exist" );
@@ -579,11 +652,6 @@
BufferHandler bufferHandler = new BufferHandler( channel, buffer );
long nbElems = LongSerializer.deserialize( bufferHandler.read( 8 ) );
- btreeHeader.setNbElems( nbElems );
-
- // Prepare a list of keys and values read from the disk
- //List<K> keys = new ArrayList<K>();
- //List<V> values = new ArrayList<V>();
// desactivate the journal while we load the file
boolean isJournalActivated = withJournal;
@@ -596,15 +664,11 @@
// Read the key
K key = keySerializer.deserialize( bufferHandler );
- //keys.add( key );
-
// Read the value
V value = valueSerializer.deserialize( bufferHandler );
- //values.add( value );
-
// Inject the data in the tree. (to be replaced by a bulk load)
- insert( key, value, revision );
+ insert( key, value, getBtreeHeader().getRevision() );
}
// Restore the withJournal value
@@ -616,7 +680,7 @@
/**
- * Get the rootPzge associated to a give revision.
+ * Get the rootPage associated to a give revision.
*
* @param revision The revision we are looking for
* @return The rootPage associated to this revision
@@ -626,7 +690,24 @@
public Page<K, V> getRootPage( long revision ) throws IOException, KeyNotFoundException
{
// Atm, the in-memory BTree does not support searches in many revisions
- return rootPage;
+ return getBtreeHeader().getRootPage();
+ }
+
+
+ /**
+ * Get the current rootPage
+ *
+ * @return The rootPage
+ */
+ public Page<K, V> getRootPage()
+ {
+ return getBtreeHeader().getRootPage();
+ }
+
+
+ /* no qualifier */void setRootPage( Page<K, V> root )
+ {
+ getBtreeHeader().setRootPage( root );
}
@@ -718,29 +799,19 @@
/**
- * Starts a transaction
+ * Create a new B-tree header to be used for update operations
+ * @param revision The reclaimed revision
*/
- public void beginTransaction()
+ private BTreeHeader<K, V> createNewBtreeHeader( BTreeHeader<K, V> btreeHeader, long revision )
{
- // Does nothing...
- }
+ BTreeHeader<K, V> newBtreeHeader = new BTreeHeader<K, V>();
+ newBtreeHeader.setBTreeHeaderOffset( btreeHeader.getBTreeHeaderOffset() );
+ newBtreeHeader.setRevision( revision );
+ newBtreeHeader.setNbElems( btreeHeader.getNbElems() );
+ newBtreeHeader.setRootPage( btreeHeader.getRootPage() );
- /**
- * Commits a transaction
- */
- public void commit()
- {
- // Does nothing...
- }
-
-
- /**
- * Rollback a transaction
- */
- public void rollback()
- {
- // Does nothing...
+ return newBtreeHeader;
}
@@ -760,16 +831,19 @@
case BACKED_ON_DISK:
sb.append( "Persistent " );
break;
-
+
+ default :
+ sb.append( "Wrong type... " );
+ break;
}
sb.append( "BTree" );
- sb.append( "[" ).append( btreeHeader.getName() ).append( "]" );
- sb.append( "( pageSize:" ).append( btreeHeader.getPageSize() );
+ sb.append( "[" ).append( getName() ).append( "]" );
+ sb.append( "( pageSize:" ).append( getPageSize() );
- if ( rootPage != null )
+ if ( getBtreeHeader().getRootPage() != null )
{
- sb.append( ", nbEntries:" ).append( btreeHeader.getNbElems() );
+ sb.append( ", nbEntries:" ).append( getBtreeHeader().getNbElems() );
}
else
{
@@ -787,7 +861,7 @@
sb.append( keySerializer.getComparator().getClass().getSimpleName() );
}
- sb.append( ", DuplicatesAllowed: " ).append( btreeHeader.isAllowDuplicates() );
+ sb.append( ", DuplicatesAllowed: " ).append( isAllowDuplicates() );
if ( getType() == BTreeTypeEnum.BACKED_ON_DISK )
{
@@ -822,7 +896,7 @@
}
sb.append( ") : \n" );
- sb.append( rootPage.dumpPage( "" ) );
+ sb.append( getRootPage().dumpPage( "" ) );
return sb.toString();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryLeaf.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryLeaf.java
index e9a8660..2aab808 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryLeaf.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryLeaf.java
@@ -27,7 +27,6 @@
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
-
/**
* A MVCC Leaf. It stores the keys and values. It does not have any children.
*
@@ -72,7 +71,7 @@
/**
* {@inheritDoc}
*/
- public InsertResult<K, V> insert( long revision, K key, V value ) throws IOException
+ public InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
// Find the key into this leaf
int pos = findPos( key );
@@ -117,7 +116,7 @@
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
- public DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos )
+ /* no qualifier */ DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
throws IOException
{
// Check that the leaf is not empty
@@ -486,7 +485,7 @@
}
else
{
- throw KEY_NOT_FOUND_EXCEPTION;
+ throw KeyNotFoundException.INSTANCE;
}
}
@@ -512,7 +511,7 @@
}
else
{
- throw KEY_NOT_FOUND_EXCEPTION;
+ throw KeyNotFoundException.INSTANCE;
}
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryNode.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryNode.java
index fa0e59f..4f5d681 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryNode.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryNode.java
@@ -28,7 +28,7 @@
/**
* A MVCC Node. It stores the keys and references to its children page. It does not
* contain any value.
- *
+ *
* @param <K> The type for the Key
* @param <V> The type for the stored value
*
@@ -40,7 +40,7 @@
* Creates a new Node which will contain only one key, with references to
* a left and right page. This is a specific constructor used by the btree
* when the root was full when we added a new value.
- *
+ *
* @param btree the parent BTree
* @param revision the Node revision
* @param nbElems The number of elements in this Node
@@ -59,7 +59,7 @@
* Creates a new Node which will contain only one key, with references to
* a left and right page. This is a specific constructor used by the btree
* when the root was full when we added a new value.
- *
+ *
* @param btree the parent BTree
* @param revision the Node revision
* @param key The new key
@@ -89,7 +89,7 @@
/**
* {@inheritDoc}
*/
- public InsertResult<K, V> insert( long revision, K key, V value ) throws IOException
+ public InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
// Find the key into this leaf
int pos = findPos( key );
@@ -105,7 +105,7 @@
Page<K, V> child = children[pos].getValue();
// and insert the <K, V> into this child
- InsertResult<K, V> result = child.insert( revision, key, value );
+ InsertResult<K, V> result = child.insert( key, value, revision );
// Ok, now, we have injected the <K, V> tuple down the tree. Let's check
// the result to see if we have to split the current page
@@ -145,7 +145,7 @@
/**
* Modifies the current node after a remove has been done in one of its children.
* The node won't be merged with another node.
- *
+ *
* @param removeResult The result of a remove operation
* @param index the position of the key, not transformed
* @param pos The position of the key, as a positive value
@@ -188,7 +188,7 @@
/**
* Handles the removal of an element from the root page, when two of its children
* have been merged.
- *
+ *
* @param mergedResult The merge result
* @param pos The position in the current root
* @param found Tells if the removed key is present in the root page
@@ -223,7 +223,7 @@
* Borrows an element from the right sibling, creating a new sibling with one
* less element and creating a new page where the element to remove has been
* deleted and the borrowed element added on the right.
- *
+ *
* @param revision The new revision for all the pages
* @param sibling The right sibling
* @param pos The position of the element to remove
@@ -308,7 +308,7 @@
* Borrows an element from the left sibling, creating a new sibling with one
* less element and creating a new page where the element to remove has been
* deleted and the borrowed element added on the left.
- *
+ *
* @param revision The new revision for all the pages
* @param sibling The left sibling
* @param pos The position of the element to remove
@@ -392,7 +392,7 @@
/**
* We have to merge the node with its sibling, both have N/2 elements before the element
* removal.
- *
+ *
* @param revision The revision
* @param mergedResult The result of the merge
* @param sibling The Page we will merge the current page with
@@ -523,7 +523,7 @@
/**
* {@inheritDoc}
*/
- public DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos )
+ /* no qualifier */ DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
throws IOException
{
// We first try to delete the element from the child it belongs to
@@ -538,12 +538,12 @@
{
index = -( pos + 1 );
child = children[-pos].getValue();
- deleteResult = child.delete( revision, key, value, this, -pos );
+ deleteResult = ((AbstractPage<K, V>)child).delete( key, value, revision, this, -pos );
}
else
{
child = children[pos].getValue();
- deleteResult = child.delete( revision, key, value, this, pos );
+ deleteResult = ((AbstractPage<K, V>)child).delete( key, value, revision, this, pos );
}
// If the key is not present in the tree, we simply return
@@ -604,7 +604,7 @@
// We will remove one element from a page that will have less than N/2 elements,
// which will lead to some reorganization : either we can borrow an element from
// a sibling, or we will have to merge two pages
- int siblingPos = selectSibling( ( InMemoryNode<K, V> ) parent, parentPos );
+ int siblingPos = selectSibling( parent, parentPos );
InMemoryNode<K, V> sibling = ( InMemoryNode<K, V> ) ( ( ( InMemoryNode<K, V> ) parent ).children[siblingPos]
.getValue() );
@@ -717,7 +717,7 @@
/**
* Remove the key at a given position.
- *
+ *
* @param mergedResult The page we will remove a key from
* @param revision The revision of the modified page
* @param pos The position into the page of the element to remove
@@ -780,7 +780,7 @@
/**
* Set the value at a give position
- *
+ *
* @param pos The position in the values array
* @param value the value to inject
*/
@@ -794,7 +794,7 @@
* This method is used when we have to replace a child in a page when we have
* found the key in the tree (the value will be changed, so we have made
* copies of the existing pages).
- *
+ *
* @param revision The current revision
* @param result The modified page
* @param pos The position of the found key
@@ -825,7 +825,7 @@
/**
* Adds a new key into a copy of the current page at a given position. We return the
* modified page. The new page will have one more key than the current page.
- *
+ *
* @param copiedPages the list of copied pages
* @param revision The revision of the modified page
* @param key The key to insert
@@ -880,7 +880,7 @@
* If the newly added element is in the middle, we will use it
* as a pivot. Otherwise, we will use either the last element in the left page if the element is added
* on the left, or the first element in the right page if it's added on the right.
- *
+ *
* @param copiedPages the list of copied pages
* @param revision The new revision for all the created pages
* @param pivot The key that will be move up after the split
@@ -978,7 +978,7 @@
/**
* Copies the current page and all its keys, with a new revision.
- *
+ *
* @param revision The new revision
* @return The copied page
*/
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
new file mode 100644
index 0000000..ef9afb5
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryTransactionManager.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * An implementation of a TransactionManager for in-memory B-trees
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InMemoryTransactionManager extends AbstractTransactionManager
+{
+ /** A lock to protect the transaction handling */
+ private Lock transactionLock = new ReentrantLock();
+
+ /** A ThreadLocalStorage used to store the current transaction */
+ private static final ThreadLocal<Integer> context = new ThreadLocal<Integer>();
+
+ /** A Map keeping the latest revisions for each managed BTree */
+ private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A Map storing the new revisions when some change have been made in some BTrees */
+ private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A lock to protect the BtreeHeader maps */
+ private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void beginTransaction()
+ {
+ // First, take the lock
+ transactionLock.lock();
+
+ // Now, check the TLS state
+ Integer nbTxnLevel = context.get();
+
+ if ( nbTxnLevel == null )
+ {
+ context.set( 1 );
+ }
+ else
+ {
+ // And increment the counter of inner txn.
+ context.set( nbTxnLevel + 1 );
+ }
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void commit()
+ {
+ int nbTxnStarted = context.get();
+
+ if ( nbTxnStarted == 0 )
+ {
+ // The transaction was rollbacked, quit immediatelly
+ transactionLock.unlock();
+
+ return;
+ }
+ else
+ {
+
+ // And decrement the number of started transactions
+ context.set( nbTxnStarted - 1 );
+ }
+
+ // Finally, release the global lock
+ transactionLock.unlock();
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void rollback()
+ {
+ // Reset the counter
+ context.set( 0 );
+
+ // Finally, release the global lock
+ transactionLock.unlock();
+ }
+
+
+ /**
+ * Get the current BTreeHeader for a given Btree. It might not exist
+ */
+ public BTreeHeader getBTreeHeader( String name )
+ {
+ // Get a lock
+ btreeHeadersLock.readLock().lock();
+
+ // get the current BTree Header for this BTree and revision
+ BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+
+ // And unlock
+ btreeHeadersLock.readLock().unlock();
+
+ return btreeHeader;
+ }
+
+
+
+
+ /**
+ * {@inheritDoc}
+ */
+ public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
+ {
+ newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryValueHolder.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryValueHolder.java
index db1aa73..369c23b 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryValueHolder.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/InMemoryValueHolder.java
@@ -27,6 +27,7 @@
import org.apache.directory.mavibot.btree.exception.BTreeOperationException;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
/**
@@ -201,6 +202,10 @@
{
throw new BTreeOperationException( e );
}
+ catch ( KeyNotFoundException knfe )
+ {
+ throw new BTreeOperationException( knfe );
+ }
}
return returnedValue;
@@ -249,6 +254,12 @@
e.printStackTrace();
return false;
}
+ catch ( KeyNotFoundException knfe )
+ {
+ // TODO Auto-generated catch block
+ knfe.printStackTrace();
+ return false;
+ }
}
else
{
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/MavibotInspector.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/MavibotInspector.java
new file mode 100644
index 0000000..2777243
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/MavibotInspector.java
@@ -0,0 +1,1345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.RandomAccessFile;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.directory.mavibot.btree.exception.InvalidBTreeException;
+import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.LongSerializer;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.mavibot.btree.util.Strings;
+
+
+/**
+ * A class to examine a Mavibot database file.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotInspector
+{
+ // The file to be read
+ private File dbFile;
+
+ // The recordManager
+ private RecordManager rm;
+
+ private BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
+
+ // The name of the two page arrays for the global file and teh free pages
+ private static final String GLOBAL_PAGES_NAME = "__global__";
+ private static final String FREE_PAGES_NAME = "__free-pages__";
+
+ // The set of page array we already know about
+ private static Set<String> knownPagesArrays = new HashSet<String>();
+
+ static
+ {
+ knownPagesArrays.add( GLOBAL_PAGES_NAME );
+ knownPagesArrays.add( FREE_PAGES_NAME );
+ knownPagesArrays.add( RecordManager.BTREE_OF_BTREES_NAME );
+ knownPagesArrays.add( RecordManager.COPIED_PAGE_BTREE_NAME );
+ }
+
+ /**
+ * A private class to store a few informations about a btree
+ *
+
+ private static BtreeInfo btreeInfo;
+
+ static
+ {
+ btreeInfo = new BtreeInfo();
+ }
+
+ /**
+ * Create an instance of MavibotInspector
+ * @param dbFile The file to read
+ */
+ public MavibotInspector( File dbFile )
+ {
+ this.dbFile = dbFile;
+ }
+
+
+ /**
+ * Check that the file exists
+ */
+ private boolean checkFilePresence()
+ {
+ if ( dbFile == null )
+ {
+ System.out.println( "No mavibot database file was given" );
+ return false;
+ }
+
+ if ( !dbFile.exists() )
+ {
+ System.out.println( "Given mavibot database file " + dbFile + " doesn't exist" );
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Pretty print the file size
+ */
+ public void printFileSize() throws IOException
+ {
+ FileChannel fileChannel = new RandomAccessFile( dbFile, "r" ).getChannel();
+
+ long l = fileChannel.size();
+
+ fileChannel.close();
+
+ String msg;
+
+ if ( l < 1024 )
+ {
+ msg = l + " bytes";
+ }
+ else
+ {
+ msg = ( l / 1024 ) + " KB";
+ }
+
+ System.out.println( msg );
+
+ fileChannel.close();
+ }
+
+
+ /**
+ * Print the number of B-trees
+ */
+ public void printNumberOfBTrees()
+ {
+ int nbBtrees = 0;
+
+ if ( rm != null )
+ {
+ nbBtrees = rm.getNbManagedTrees();
+ }
+
+ // The number of trees. It must be at least 2 and > 0
+ System.out.println( "Total Number of BTrees: " + nbBtrees );
+ }
+
+
+ /**
+ * Print the B-tree's name
+ */
+ public void printBTreeNames()
+ {
+ if ( rm == null )
+ {
+ System.out.println( "Couldn't find the number of managed btrees" );
+ return;
+ }
+
+ Set<String> trees = rm.getManagedTrees();
+ System.out.println( "\nManaged BTrees:" );
+
+ for ( String tree : trees )
+ {
+ System.out.println( tree );
+ }
+
+ System.out.println();
+ }
+
+
+ /**
+ * Check a B-tree
+ */
+ public void checkBTree()
+ {
+ if ( rm == null )
+ {
+ System.out.println( "Cannot check BTree(s)" );
+ return;
+ }
+
+ System.out.print( "BTree Name: " );
+ String name = readLine();
+
+ PersistedBTree<?, ?> pb = ( PersistedBTree<?, ?> ) rm.getManagedTree( name );
+
+ if ( pb == null )
+ {
+ System.out.println( "No BTree exists with the name '" + name + "'" );
+ return;
+ }
+
+ System.out.println( "\nBTree offset: " + String.format( "0x%1$08x", pb.getBtreeOffset() ) );
+ System.out.println( "BTree _info_ offset: " + String.format( "0x%1$08x", pb.getBtreeInfoOffset() ) );
+ System.out.println( "BTree root page offset: " + String.format( "0x%1$08x", pb.getRootPageOffset() ) );
+ System.out.println( "Number of elements present: " + pb.getNbElems() );
+ System.out.println( "BTree Page size: " + pb.getPageSize() );
+ System.out.println( "BTree revision: " + pb.getRevision() );
+ System.out.println( "Key serializer: " + pb.getKeySerializerFQCN() );
+ System.out.println( "Value serializer: " + pb.getValueSerializerFQCN() );
+ System.out.println();
+ }
+
+
+ /**
+ * Load the full fie into a new RecordManager
+ */
+ private boolean loadRm()
+ {
+ try
+ {
+ if( rm != null )
+ {
+ System.out.println("Closing record manager");
+ rm.close();
+ }
+
+ rm = new RecordManager( dbFile.getAbsolutePath() );
+ System.out.println("Loaded record manager");
+ }
+ catch ( Exception e )
+ {
+ System.out.println( "Given database file seems to be corrupted. " + e.getMessage() );
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * Check the whole file
+ */
+ /* no qualifier */ static void check( RecordManager recordManager )
+ {
+ try
+ {
+ // First check the RMheader
+ ByteBuffer recordManagerHeader = ByteBuffer.allocate( RecordManager.RECORD_MANAGER_HEADER_SIZE );
+ long fileSize = recordManager.fileChannel.size();
+
+ if ( fileSize < RecordManager.RECORD_MANAGER_HEADER_SIZE )
+ {
+ throw new InvalidBTreeException( "File size too small : " + fileSize );
+ }
+
+ // Read the RMHeader
+ recordManager.fileChannel.read( recordManagerHeader, 0L );
+ recordManagerHeader.flip();
+
+ // The page size. It must be a power of 2, and above 16.
+ int pageSize = recordManagerHeader.getInt();
+
+ if ( ( pageSize != recordManager.pageSize ) || ( pageSize < 32 ) || ( ( pageSize & ( ~pageSize + 1 ) ) != pageSize ) )
+ {
+ throw new InvalidBTreeException( "Wrong page size : " + pageSize );
+ }
+
+ // Compute the number of pages in this file
+ long nbPages = ( fileSize - RecordManager.RECORD_MANAGER_HEADER_SIZE ) / pageSize;
+
+ // The number of trees. It must be at least 2 and > 0
+ int nbBtrees = recordManagerHeader.getInt();
+
+ if ( ( nbBtrees < 0 ) || ( nbBtrees != recordManager.nbBtree ) )
+ {
+ throw new InvalidBTreeException( "Wrong nb trees : " + nbBtrees );
+ }
+
+ // The first free page offset. It must be either -1 or below file size
+ // and its value must be a modulo of pageSize
+ long firstFreePage = recordManagerHeader.getLong();
+
+ checkOffset( recordManager, firstFreePage );
+
+ int nbPageBits = ( int ) ( nbPages / 32 );
+
+ // Create an array of pages to be checked for each B-tree, plus
+ // two others for the free pages and the global one
+ // We use one bit per page. It's 0 when the page
+ // hasn't been checked, 1 otherwise.
+ Map<String, int[]> checkedPages = new HashMap<String, int[]>(nbBtrees + 4);
+
+ // The global page array
+ checkedPages.put( GLOBAL_PAGES_NAME, new int[nbPageBits + 1] );
+
+ // The freePages array
+ checkedPages.put( FREE_PAGES_NAME, new int[nbPageBits + 1] );
+
+ // The B-tree of B-trees array
+ checkedPages.put( RecordManager.BTREE_OF_BTREES_NAME, new int[nbPageBits + 1] );
+
+ // Last, the Copied Pages B-tree array
+ checkedPages.put( RecordManager.COPIED_PAGE_BTREE_NAME, new int[nbPageBits + 1] );
+
+ // Check the free files
+ checkFreePages( recordManager, checkedPages );
+
+ // The B-trees offsets
+ long currentBtreeOfBtreesOffset = recordManagerHeader.getLong();
+ long previousBtreeOfBtreesOffset = recordManagerHeader.getLong();
+ long currentCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+ long previousCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+
+ // Check that the previous BOB offset is not pointing to something
+ if ( previousBtreeOfBtreesOffset != RecordManager.NO_PAGE )
+ {
+ System.out.println( "The previous Btree of Btrees offset is not valid : "
+ + previousBtreeOfBtreesOffset );
+ return;
+ }
+
+ // Check that the previous CPB offset is not pointing to something
+ if ( previousCopiedPagesBtreeOffset != RecordManager.NO_PAGE )
+ {
+ System.out.println( "The previous Copied Pages Btree offset is not valid : "
+ + previousCopiedPagesBtreeOffset );
+ return;
+ }
+
+ // Check that the current BOB offset is valid
+ checkOffset( recordManager, currentBtreeOfBtreesOffset );
+
+ // Check that the current CPB offset is valid
+ checkOffset( recordManager, currentCopiedPagesBtreeOffset );
+
+ // Now, check the BTree of Btrees
+ checkBtreeOfBtrees( recordManager, checkedPages );
+
+ // And the Copied Pages BTree
+ checkBtree( recordManager, currentCopiedPagesBtreeOffset, checkedPages );
+
+ // We can now dump the checked pages
+ dumpCheckedPages( recordManager, checkedPages );
+ }
+ catch ( Exception e )
+ {
+ // We catch the exception and rethrow it immediately to be able to
+ // put a breakpoint here
+ e.printStackTrace();
+ throw new InvalidBTreeException( "Error : " + e.getMessage() );
+ }
+ }
+
+
+ /**
+ * Check the Btree of Btrees
+ */
+ private static <K, V> void checkBtreeOfBtrees( RecordManager recordManager, Map<String, int[]> checkedPages ) throws Exception
+ {
+ // Read the BOB header
+ PageIO[] bobHeaderPageIos = recordManager.readPageIOs( recordManager.currentBtreeOfBtreesOffset, Long.MAX_VALUE );
+
+ // update the checkedPages
+ updateCheckedPages( checkedPages.get( RecordManager.BTREE_OF_BTREES_NAME), recordManager.pageSize, bobHeaderPageIos );
+ updateCheckedPages( checkedPages.get( GLOBAL_PAGES_NAME ), recordManager.pageSize, bobHeaderPageIos );
+
+ long dataPos = 0L;
+
+ // The B-tree current revision
+ recordManager.readLong( bobHeaderPageIos, dataPos );
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The nb elems in the tree
+ recordManager.readLong( bobHeaderPageIos, dataPos );
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The B-tree rootPage offset
+ long rootPageOffset = recordManager.readLong( bobHeaderPageIos, dataPos );
+
+ checkOffset( recordManager, rootPageOffset );
+
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The B-tree info offset
+ long btreeInfoOffset = recordManager.readLong( bobHeaderPageIos, dataPos );
+
+ checkOffset( recordManager, btreeInfoOffset );
+
+ checkBtreeInfo( recordManager, checkedPages, btreeInfoOffset, -1L );
+
+ // Check the elements in the btree itself
+ // We will read every single page
+ checkBtreeOfBtreesPage( recordManager, checkedPages, rootPageOffset );
+ }
+
+
+ /**
+ * Check a user's B-tree
+ */
+ private static <K, V> void checkBtree( RecordManager recordManager, long btreeOffset, Map<String, int[]> checkedPages ) throws Exception
+ {
+ // Read the B-tree header
+ PageIO[] btreeHeaderPageIos = recordManager.readPageIOs( btreeOffset, Long.MAX_VALUE );
+
+ long dataPos = 0L;
+
+ // The B-tree current revision
+ long btreeRevision = recordManager.readLong( btreeHeaderPageIos, dataPos );
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The nb elems in the tree
+ recordManager.readLong( btreeHeaderPageIos, dataPos );
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The B-tree rootPage offset
+ long rootPageOffset = recordManager.readLong( btreeHeaderPageIos, dataPos );
+
+ checkOffset( recordManager, rootPageOffset );
+
+ dataPos += RecordManager.LONG_SIZE;
+
+ // The B-tree info offset
+ long btreeInfoOffset = recordManager.readLong( btreeHeaderPageIos, dataPos );
+
+ checkOffset( recordManager, btreeInfoOffset );
+
+ BtreeInfo<K, V> btreeInfo = checkBtreeInfo( recordManager, checkedPages, btreeInfoOffset, btreeRevision );
+
+ // Update the checked pages
+ updateCheckedPages( checkedPages.get( btreeInfo.btreeName ), recordManager.pageSize, btreeHeaderPageIos );
+ updateCheckedPages( checkedPages.get( GLOBAL_PAGES_NAME ), recordManager.pageSize, btreeHeaderPageIos );
+
+ // And now, process the rootPage
+ checkBtreePage( recordManager, btreeInfo, checkedPages, rootPageOffset );
+ }
+
+
+ /**
+ * Check the Btree of Btrees rootPage
+ */
+ private static <K, V> void checkBtreePage( RecordManager recordManager, BtreeInfo<K, V> btreeInfo, Map<String, int[]> checkedPages, long pageOffset ) throws Exception
+ {
+ PageIO[] pageIos = recordManager.readPageIOs( pageOffset, Long.MAX_VALUE );
+
+ // Update the checkedPages array
+ updateCheckedPages( checkedPages.get( btreeInfo.btreeName ), recordManager.pageSize, pageIos );
+ updateCheckedPages( checkedPages.get( GLOBAL_PAGES_NAME ), recordManager.pageSize, pageIos );
+
+ // Deserialize the page now
+ long position = 0L;
+
+ // The revision
+ long revision = recordManager.readLong( pageIos, position );
+ position += RecordManager.LONG_SIZE;
+
+ // The number of elements in the page
+ int nbElems = recordManager.readInt( pageIos, position );
+ position += RecordManager.INT_SIZE;
+
+ // The size of the data containing the keys and values
+ // Reads the bytes containing all the keys and values, if we have some
+ // We read big blob of data into ByteBuffer, then we will process
+ // this ByteBuffer
+ ByteBuffer byteBuffer = recordManager.readBytes( pageIos, position );
+
+ // Now, deserialize the data block. If the number of elements
+ // is positive, it's a Leaf, otherwise it's a Node
+ // Note that only a leaf can have 0 elements, and it's the root page then.
+ if ( nbElems >= 0 )
+ {
+ // It's a leaf, process it as we may have sub-btrees
+ checkBtreeLeaf( recordManager, btreeInfo, checkedPages, nbElems, revision, byteBuffer, pageIos );
+ }
+ else
+ {
+ // It's a node
+ long[] children = checkBtreeNode( recordManager, btreeInfo, checkedPages, -nbElems, revision, byteBuffer, pageIos );
+
+ for ( int pos = 0; pos <= -nbElems; pos++ )
+ {
+ // Recursively check the children
+ checkBtreePage( recordManager, btreeInfo, checkedPages, children[pos] );
+ }
+ }
+ }
+
+
+ /**
+ * Check the Btree info page
+ * @throws ClassNotFoundException
+ */
+ private static <K, V> BtreeInfo<K, V> checkBtreeInfo( RecordManager recordManager, Map<String, int[]> checkedPages, long btreeInfoOffset, long btreeRevision ) throws IOException
+ {
+ BtreeInfo<K, V> btreeInfo = new BtreeInfo<K, V>();
+
+ PageIO[] btreeInfoPagesIos = recordManager.readPageIOs( btreeInfoOffset, Long.MAX_VALUE );
+
+ long dataPos = 0L;
+
+ // The B-tree page size
+ recordManager.readInt( btreeInfoPagesIos, dataPos );
+ dataPos += RecordManager.INT_SIZE;
+
+ // The tree name
+ ByteBuffer btreeNameBytes = recordManager.readBytes( btreeInfoPagesIos, dataPos );
+ dataPos += RecordManager.INT_SIZE + btreeNameBytes.limit();
+ String btreeName = Strings.utf8ToString( btreeNameBytes );
+
+ // The keySerializer FQCN
+ ByteBuffer keySerializerBytes = recordManager.readBytes( btreeInfoPagesIos, dataPos );
+
+ if ( keySerializerBytes != null )
+ {
+ String keySerializerFqcn = Strings.utf8ToString( keySerializerBytes );
+
+ btreeInfo.keySerializer = getSerializer( keySerializerFqcn );
+ }
+
+ dataPos += RecordManager.INT_SIZE + keySerializerBytes.limit();
+
+ // The valueSerialier FQCN
+ ByteBuffer valueSerializerBytes = recordManager.readBytes( btreeInfoPagesIos, dataPos );
+
+ if ( valueSerializerBytes != null )
+ {
+ String valueSerializerFqcn = Strings.utf8ToString( valueSerializerBytes );
+
+ btreeInfo.valueSerializer = getSerializer( valueSerializerFqcn );
+ }
+
+ dataPos += RecordManager.INT_SIZE + valueSerializerBytes.limit();
+
+ // The B-tree allowDuplicates flag
+ recordManager.readInt( btreeInfoPagesIos, dataPos );
+ dataPos += RecordManager.INT_SIZE;
+
+ // update the checkedPages
+ if ( !RecordManager.COPIED_PAGE_BTREE_NAME.equals( btreeName ) && !RecordManager.BTREE_OF_BTREES_NAME.equals( btreeName ) )
+ {
+ btreeName = btreeName + "<" + btreeRevision + ">";
+ }
+
+ btreeInfo.btreeName = btreeName;
+
+ // Update the checkedPages
+ int[] checkedPagesArray = checkedPages.get( btreeName );
+
+ if ( checkedPagesArray == null )
+ {
+ // Add the new name in the checkedPage name if it's not already there
+ checkedPagesArray = createPageArray( recordManager );
+ checkedPages.put( btreeName, checkedPagesArray );
+ }
+
+ updateCheckedPages( checkedPagesArray, recordManager.pageSize, btreeInfoPagesIos );
+ updateCheckedPages( checkedPages.get( GLOBAL_PAGES_NAME ), recordManager.pageSize, btreeInfoPagesIos );
+
+ return btreeInfo;
+ }
+
+
+ /**
+ * Get back the serializer instance
+ */
+ @SuppressWarnings("unchecked")
+ private static <T> ElementSerializer<T> getSerializer( String serializerFqcn )
+ {
+ try
+ {
+ Class<?> serializerClass = Class.forName( serializerFqcn );
+ ElementSerializer<T> serializer = null;
+
+ try
+ {
+ serializer = ( ElementSerializer<T> ) serializerClass.getDeclaredField( "INSTANCE" ).get( null );
+ }
+ catch( NoSuchFieldException e )
+ {
+ // ignore
+ }
+
+ if ( serializer == null )
+ {
+ serializer = ( ElementSerializer<T> ) serializerClass.newInstance();
+ }
+
+ return serializer;
+ }
+ catch ( Exception e )
+ {
+ throw new InvalidBTreeException( "Error : " + e.getMessage() );
+ }
+ }
+
+
+ /**
+ * Check the Btree of Btrees rootPage
+ */
+ private static <K, V> void checkBtreeOfBtreesPage( RecordManager recordManager, Map<String, int[]> checkedPages, long pageOffset ) throws Exception
+ {
+ PageIO[] pageIos = recordManager.readPageIOs( pageOffset, Long.MAX_VALUE );
+
+ // Update the checkedPages array
+ updateCheckedPages( checkedPages.get( RecordManager.BTREE_OF_BTREES_NAME), recordManager.pageSize, pageIos );
+ updateCheckedPages( checkedPages.get( GLOBAL_PAGES_NAME ), recordManager.pageSize, pageIos );
+
+ // Deserialize the page now
+ long position = 0L;
+
+ // The revision
+ long revision = recordManager.readLong( pageIos, position );
+ position += RecordManager.LONG_SIZE;
+
+ // The number of elements in the page
+ int nbElems = recordManager.readInt( pageIos, position );
+ position += RecordManager.INT_SIZE;
+
+ // The size of the data containing the keys and values
+ // Reads the bytes containing all the keys and values, if we have some
+ // We read big blob of data into ByteBuffer, then we will process
+ // this ByteBuffer
+ ByteBuffer byteBuffer = recordManager.readBytes( pageIos, position );
+
+ // Now, deserialize the data block. If the number of elements
+ // is positive, it's a Leaf, otherwise it's a Node
+ // Note that only a leaf can have 0 elements, and it's the root page then.
+ if ( nbElems >= 0 )
+ {
+ // It's a leaf, process it as we may have sub-btrees
+ checkBtreeOfBtreesLeaf( recordManager, checkedPages, nbElems, revision, byteBuffer, pageIos );
+ }
+ else
+ {
+ // It's a node
+ long[] children = checkBtreeOfBtreesNode( recordManager, checkedPages, -nbElems, revision, byteBuffer, pageIos );
+
+ for ( int pos = 0; pos <= -nbElems; pos++ )
+ {
+ // Recursively check the children
+ checkBtreeOfBtreesPage( recordManager, checkedPages, children[pos] );
+ }
+ }
+ }
+
+
+ /**
+ * Check a Btree of Btrees leaf. It contains <revision, name> -> offset.
+ */
+ private static <K, V> void checkBtreeOfBtreesLeaf( RecordManager recordManager, Map<String, int[]> checkedPages, int nbElems, long revision, ByteBuffer byteBuffer, PageIO[] pageIos ) throws Exception
+ {
+ // Read each key and value
+ for ( int i = 0; i < nbElems; i++ )
+ {
+ try
+ {
+ // Read the number of values
+ int nbValues = byteBuffer.getInt();
+
+ if ( nbValues != 1 )
+ {
+ throw new InvalidBTreeException( "We should have only one value for a BOB " + nbValues );
+ }
+
+ // This is a normal value
+ // First, the value, which is an offset, which length should be 12
+ int valueLength = byteBuffer.getInt();
+
+ if ( valueLength != RecordManager.LONG_SIZE + RecordManager.INT_SIZE )
+ {
+ throw new InvalidBTreeException( "The BOB value length is invalid " + valueLength );
+ }
+
+ // Second, the offset length, which should be 8
+ int offsetLength = byteBuffer.getInt();
+
+ if ( offsetLength != RecordManager.LONG_SIZE )
+ {
+ throw new InvalidBTreeException( "The BOB value offset length is invalid " + offsetLength );
+ }
+
+ // Then the offset
+ long btreeOffset = byteBuffer.getLong();
+
+ checkOffset( recordManager, btreeOffset );
+
+ // Now, process the key
+ // First the key length
+ int keyLength = byteBuffer.getInt();
+
+ // The length should be at least 12 bytes long
+ if ( keyLength < RecordManager.LONG_SIZE + RecordManager.INT_SIZE )
+ {
+ throw new InvalidBTreeException( "The BOB key length is invalid " + keyLength );
+ }
+
+ // Read the revision
+ long btreeRevision = byteBuffer.getLong();
+
+ // read the btreeName
+ int btreeNameLength = byteBuffer.getInt();
+
+ // The length should be equals to the btreeRevision + btreeNameLength + 4
+ if ( keyLength != RecordManager.LONG_SIZE + RecordManager.INT_SIZE + btreeNameLength )
+ {
+ throw new InvalidBTreeException( "The BOB key length is not the expected value " +
+ ( RecordManager.LONG_SIZE + RecordManager.INT_SIZE + btreeNameLength ) + ", expected " + keyLength );
+ }
+
+ byte[] bytes = new byte[btreeNameLength];
+ byteBuffer.get( bytes );
+ String btreeName = Strings.utf8ToString( bytes );
+
+ // Add the new name in the checkedPage name if it's not already there
+ int[] btreePagesArray = createPageArray( recordManager );
+ checkedPages.put( btreeName + "<" + btreeRevision + ">", btreePagesArray );
+
+ // Now, we can check the Btree we just found
+ checkBtree( recordManager, btreeOffset, checkedPages );
+
+ //System.out.println( "read <" + btreeName + "," + btreeRevision + "> : 0x" + Long.toHexString( btreeOffset ) );
+ }
+ catch ( BufferUnderflowException bue )
+ {
+ throw new InvalidBTreeException( "The BOB leaf byte buffer is too short : " + bue.getMessage() );
+ }
+ }
+ }
+
+
+ /**
+ * Check a Btree leaf.
+ */
+ private static <K, V> void checkBtreeLeaf( RecordManager recordManager, BtreeInfo<K, V> btreeInfo, Map<String, int[]> checkedPages, int nbElems, long revision, ByteBuffer byteBuffer, PageIO[] pageIos ) throws Exception
+ {
+ // Read each key and value
+ for ( int i = 0; i < nbElems; i++ )
+ {
+ try
+ {
+ // Read the number of values
+ int nbValues = byteBuffer.getInt();
+
+ if ( nbValues < 0 )
+ {
+ // This is a sub-btree. Read the offset
+ long subBtreeOffset = byteBuffer.getLong();
+
+ // And process the sub-btree
+ checkBtree( recordManager, subBtreeOffset, checkedPages );
+
+ // Now, process the key
+ // The key length
+ byteBuffer.getInt();
+
+ // The key itself
+ btreeInfo.keySerializer.deserialize( byteBuffer );
+ }
+ else
+ {
+ // just deserialize the keys and values
+ // The value
+ byteBuffer.getInt();
+ btreeInfo.valueSerializer.deserialize( byteBuffer );
+
+ // the key
+ byteBuffer.getInt();
+
+ btreeInfo.keySerializer.deserialize( byteBuffer );
+ }
+ }
+ catch ( BufferUnderflowException bue )
+ {
+ throw new InvalidBTreeException( "The BOB leaf byte buffer is too short : " + bue.getMessage() );
+ }
+ }
+ }
+
+ /**
+ * Check a Btree of Btrees Node
+ */
+ private static <K, V> long[] checkBtreeOfBtreesNode( RecordManager recordManager, Map<String, int[]> checkedPages, int nbElems, long revision,
+ ByteBuffer byteBuffer, PageIO[] pageIos ) throws IOException
+ {
+ long[] children = new long[nbElems + 1];
+
+ // Read each value
+ for ( int i = 0; i < nbElems; i++ )
+ {
+ // The offsets of the child
+ long firstOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, firstOffset );
+
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, lastOffset );
+
+ children[i] = firstOffset;
+
+ // Read the key length
+ int keyLength = byteBuffer.getInt();
+
+ // The length should be at least 12 bytes long
+ if ( keyLength < RecordManager.LONG_SIZE + RecordManager.INT_SIZE )
+ {
+ throw new InvalidBTreeException( "The BOB key length is invalid " + keyLength );
+ }
+
+ // Read the revision
+ byteBuffer.getLong();
+
+ // read the btreeName
+ int btreeNameLength = byteBuffer.getInt();
+
+ // The length should be equals to the btreeRevision + btreeNameLength + 4
+ if ( keyLength != RecordManager.LONG_SIZE + RecordManager.INT_SIZE + btreeNameLength )
+ {
+ throw new InvalidBTreeException( "The BOB key length is not the expected value " +
+ ( RecordManager.LONG_SIZE + RecordManager.INT_SIZE + btreeNameLength ) + ", expected " + keyLength );
+ }
+
+ // Read the Btree name
+ byte[] bytes = new byte[btreeNameLength];
+ byteBuffer.get( bytes );
+ }
+
+ // And read the last child
+ // The offsets of the child
+ long firstOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, firstOffset );
+
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, lastOffset );
+
+ children[nbElems] = firstOffset;
+
+ // and read the last value, as it's a node
+ return children;
+ }
+
+
+ /**
+ * Check a Btree node.
+ */
+ private static <K, V> long[] checkBtreeNode( RecordManager recordManager, BtreeInfo<K, V> btreeInfo, Map<String, int[]> checkedPages, int nbElems, long revision, ByteBuffer byteBuffer, PageIO[] pageIos ) throws Exception
+ {
+ long[] children = new long[nbElems + 1];
+
+ // Read each key and value
+ for ( int i = 0; i < nbElems; i++ )
+ {
+ try
+ {
+ // The offsets of the child
+ long firstOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, firstOffset );
+
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, lastOffset );
+
+ children[i] = firstOffset;
+
+ // Now, read the key
+ // The key lenth
+ byteBuffer.getInt();
+
+ // The key itself
+ btreeInfo.keySerializer.deserialize( byteBuffer );
+ }
+ catch ( BufferUnderflowException bue )
+ {
+ throw new InvalidBTreeException( "The BOB leaf byte buffer is too short : " + bue.getMessage() );
+ }
+ }
+
+ // The last child
+ // The offsets of the child
+ long firstOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, firstOffset );
+
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+
+ checkOffset( recordManager, lastOffset );
+
+ children[nbElems] = firstOffset;
+
+ return children;
+ }
+
+
+ /**
+ * Create an array of bits for pages
+ */
+ private static int[] createPageArray( RecordManager recordManager ) throws IOException
+ {
+ long fileSize = recordManager.fileChannel.size();
+ int pageSize = recordManager.pageSize;
+ long nbPages = ( fileSize - RecordManager.RECORD_MANAGER_HEADER_SIZE ) / pageSize;
+ int nbPageBits = ( int ) ( nbPages / 32 );
+
+ return new int[nbPageBits + 1];
+ }
+
+
+ /**
+ * Update the array of seen pages.
+ */
+ private static void updateCheckedPages( int[] checkedPages, int pageSize, PageIO... pageIos )
+ {
+ for ( PageIO pageIO : pageIos )
+ {
+ long offset = pageIO.getOffset();
+
+ if ( ( offset % pageSize ) != 0 )
+ {
+ throw new InvalidBTreeException( "Offset invalid : " + offset );
+ }
+
+ int pageNumber = (int)(offset / pageSize);
+ int nbBitsPage = ( RecordManager.INT_SIZE << 3 );
+ int pageMask = checkedPages[ pageNumber / nbBitsPage ];
+ int mask = 1 << pageNumber % nbBitsPage;
+
+ if ( ( pageMask & mask ) != 0 )
+ {
+ //throw new InvalidBTreeException( "The page " + offset + " has already been referenced" );
+ }
+
+ pageMask |= mask;
+ checkedPages[ pageNumber / nbBitsPage ] = pageMask;
+ }
+ }
+
+
+ /**
+ * Check the offset to be sure it's a valid one :
+ * <ul>
+ * <li>It's >= 0</li>
+ * <li>It's below the end of the file</li>
+ * <li>It's a multiple of the pageSize
+ * </ul>
+ */
+ private static void checkOffset( RecordManager recordManager, long offset ) throws IOException
+ {
+ if ( ( offset == RecordManager.NO_PAGE ) ||
+ ( ( ( offset - RecordManager.RECORD_MANAGER_HEADER_SIZE ) % recordManager.pageSize ) != 0 ) ||
+ ( offset > recordManager.fileChannel.size() ) )
+ {
+ throw new InvalidBTreeException( "Invalid Offset : " + offset );
+ }
+ }
+
+
+ /**
+ * Check the free pages
+ */
+ private static void checkFreePages( RecordManager recordManager, Map<String, int[]> checkedPages )
+ throws IOException
+ {
+ if ( recordManager.firstFreePage == RecordManager.NO_PAGE )
+ {
+ return;
+ }
+
+ // Now, read all the free pages
+ long currentOffset = recordManager.firstFreePage;
+ long fileSize = recordManager.fileChannel.size();
+
+ while ( currentOffset != RecordManager.NO_PAGE )
+ {
+ if ( currentOffset > fileSize )
+ {
+ System.out.println( "Wrong free page offset, above file size : " + currentOffset );
+ return;
+ }
+
+ try
+ {
+ PageIO pageIo = recordManager.fetchPage( currentOffset );
+
+ if ( currentOffset != pageIo.getOffset() )
+ {
+ System.out.println( "PageIO offset is incorrect : " + currentOffset + "-"
+ + pageIo.getOffset() );
+ return;
+ }
+
+ setCheckedPage( recordManager, checkedPages.get( GLOBAL_PAGES_NAME ), currentOffset );
+ setCheckedPage( recordManager, checkedPages.get( FREE_PAGES_NAME ), currentOffset );
+
+ long newOffset = pageIo.getNextPage();
+ currentOffset = newOffset;
+ }
+ catch ( IOException ioe )
+ {
+ throw new InvalidBTreeException( "Cannot fetch page at : " + currentOffset );
+ }
+ }
+ }
+
+
+ /**
+ * Update the ChekcedPages array
+ */
+ private static void setCheckedPage( RecordManager recordManager, int[] checkedPages, long offset )
+ {
+ int pageNumber = ( int ) offset / recordManager.pageSize;
+ int nbBitsPage = ( RecordManager.INT_SIZE << 3 );
+ long pageMask = checkedPages[ pageNumber / nbBitsPage ];
+ long mask = 1L << pageNumber % nbBitsPage;
+
+ if ( ( pageMask & mask ) != 0 )
+ {
+ //throw new InvalidBTreeException( "The page " + offset + " has already been referenced" );
+ }
+
+ pageMask |= mask;
+
+ checkedPages[ pageNumber / nbBitsPage ] |= pageMask;
+ }
+
+
+ /**
+ * Output the pages that has been seen ('1') and those which has not been seen ('0'). The '.' represent non-pages
+ * at the end of the file.
+ */
+ private static void dumpCheckedPages( RecordManager recordManager, Map<String, int[]> checkedPages ) throws IOException
+ {
+ // First dump the global array
+ int[] globalArray = checkedPages.get( GLOBAL_PAGES_NAME );
+ String result = dumpPageArray( recordManager, globalArray );
+
+ String dump = String.format( "%1$-40s : %2$s", GLOBAL_PAGES_NAME, result );
+ System.out.println( dump );
+
+ // The free pages array
+ int[] freePagesArray = checkedPages.get( FREE_PAGES_NAME );
+ result = dumpPageArray( recordManager, freePagesArray );
+
+ dump = String.format( "%1$-40s : %2$s", FREE_PAGES_NAME, result );
+ System.out.println( dump );
+
+ // The B-tree of B-trees pages array
+ int[] btreeOfBtreesArray = checkedPages.get( RecordManager.BTREE_OF_BTREES_NAME );
+ result = dumpPageArray( recordManager, btreeOfBtreesArray );
+
+ dump = String.format( "%1$-40s : %2$s", RecordManager.BTREE_OF_BTREES_NAME, result );
+ System.out.println( dump );
+
+ // The Copied page B-tree pages array
+ int[] copiedPagesArray = checkedPages.get( RecordManager.COPIED_PAGE_BTREE_NAME );
+ result = dumpPageArray( recordManager, copiedPagesArray );
+
+ dump = String.format( "%1$-40s : %2$s", RecordManager.COPIED_PAGE_BTREE_NAME, result );
+ System.out.println( dump );
+
+ // And now, all the other btree arrays
+ for ( String btreeName : checkedPages.keySet() )
+ {
+ // Don't do the array we have already processed
+ if ( knownPagesArrays.contains( btreeName ) )
+ {
+ continue;
+ }
+
+ int[] btreePagesArray = checkedPages.get( btreeName );
+ result = dumpPageArray( recordManager, btreePagesArray );
+
+ dump = String.format( "%1$-40s : %2$s", btreeName, result );
+ System.out.println( dump );
+ }
+ }
+
+
+ /**
+ * Process a page array
+ */
+ private static String dumpPageArray( RecordManager recordManager, int[] checkedPages ) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+ int i = -1;
+ int nbPagesChecked = 0;
+ long fileSize = recordManager.fileChannel.size();
+ long nbPages = ( fileSize - RecordManager.RECORD_MANAGER_HEADER_SIZE ) / recordManager.pageSize;
+
+ for ( int checkedPage : checkedPages )
+ {
+ if ( i == 0 )
+ {
+ sb.append( " " );
+ i++;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ sb.append( "[" ).append( i ).append( "] " );
+
+
+ for ( int j = 0; j < 32; j++ )
+ {
+ if ( nbPagesChecked >= nbPages + 1 )
+ {
+ sb.append( "." );
+ }
+ else
+ {
+ if ( ( checkedPage & ( 1 << j ) ) == 0 )
+ {
+ sb.append( "0" );
+ }
+ else
+ {
+ sb.append( "1" );
+ }
+ }
+
+ nbPagesChecked++;
+ }
+ }
+
+ return sb.toString();
+ }
+
+
+ /**
+ * The entry point method
+ */
+ public void start() throws Exception
+ {
+ if ( !checkFilePresence() )
+ {
+ return;
+ }
+
+ if ( !loadRm() )
+ {
+ return;
+ }
+
+ boolean stop = false;
+
+ while ( !stop )
+ {
+ System.out.println( "Choose an option:" );
+ System.out.println( "1. Print Number of BTrees" );
+ System.out.println( "2. Print BTree Names" );
+ System.out.println( "3. Inspect BTree" );
+ System.out.println( "4. Check Free Pages" );
+ System.out.println( "5. Get database file size" );
+ System.out.println( "6. Dump RecordManager" );
+ System.out.println( "7. Reload RecordManager" );
+ System.out.println( "q. Quit" );
+
+ char c = readOption();
+
+ switch ( c )
+ {
+ case '1':
+ printNumberOfBTrees();
+ break;
+
+ case '2':
+ printBTreeNames();
+ break;
+
+ case '3':
+ checkBTree();
+ break;
+
+ case '4':
+ long fileSize = rm.fileChannel.size();
+ long nbPages = fileSize / rm.pageSize;
+ int nbPageBits = ( int ) ( nbPages / RecordManager.INT_SIZE );
+
+ Map<String, int[]> checkedPages = new HashMap<String, int[]>(2);
+
+ // The global page array
+ checkedPages.put( GLOBAL_PAGES_NAME, new int[nbPageBits + 1] );
+
+ // The freePages array
+ checkedPages.put( FREE_PAGES_NAME, new int[nbPageBits + 1] );
+
+ checkFreePages( rm, checkedPages );
+ break;
+
+ case '5':
+ printFileSize();
+ break;
+
+ case '6':
+ check( rm );
+ break;
+
+ case '7':
+ loadRm();
+ break;
+
+ case 'q':
+ stop = true;
+ break;
+
+ default:
+ System.out.println( "Invalid option" );
+ //c = readOption( br );
+ break;
+ }
+ }
+
+ try
+ {
+ rm.close();
+ br.close();
+ }
+ catch ( Exception e )
+ {
+ //ignore
+ }
+ }
+
+
+ /**
+ * Read the user's interaction
+ */
+ private String readLine()
+ {
+ try
+ {
+ return br.readLine().trim();
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e );
+ }
+ }
+
+
+ /**
+ * Process the input and get back the selected choice
+ */
+ private char readOption()
+ {
+ try
+ {
+ String s = br.readLine();
+
+ if ( s.length() == 0 )
+ {
+ return ' ';
+ }
+
+ return s.charAt( 0 );
+ }
+ catch ( Exception e )
+ {
+ throw new RuntimeException( e );
+ }
+ }
+
+
+ /**
+ * Main method
+ */
+ public static void main( String[] args ) throws Exception
+ {
+ File f = new File( "/tmp/mavibotispector.db" );
+
+ RecordManager rm = new RecordManager( f.getAbsolutePath() );
+ String name1 = "corpus";
+ String name2 = "multiValues";
+ /*
+ if ( !rm.getManagedTrees().contains( name1 ) )
+ {
+ rm.addBTree( name1, StringSerializer.INSTANCE, StringSerializer.INSTANCE, true );
+ }
+ */
+ if ( !rm.getManagedTrees().contains( name2 ) )
+ {
+ rm.addBTree( name2, StringSerializer.INSTANCE, StringSerializer.INSTANCE, true );
+ }
+
+ /*
+ // Load some elements in the single value btree
+ BTree<String, String> btree1 = rm.getManagedTree( name1 );
+
+ for ( int i = 0; i < 10; i++ )
+ {
+ btree1.insert( Integer.toString( i ), Integer.toString( i ) );
+ }
+ */
+
+ // Load some elements in the multi value btree
+ BTree<String, String> btree2 = rm.getManagedTree( name2 );
+
+ for ( int i = 0; i < 1; i++ )
+ {
+ for ( int j = 0; j < 10; j++)
+ {
+ btree2.insert( Integer.toString( i ), Integer.toString( j ) );
+ }
+ }
+
+ rm.close();
+
+ MavibotInspector mi = new MavibotInspector( f );
+ mi.start();
+ }
+}
+
+
+/**
+ * A class used to store some information about the Btree
+ */
+final class BtreeInfo<K, V>
+{
+ // The btree name
+ /* no qualifier */ String btreeName;
+
+ // The key serializer
+ /* no qualifier */ElementSerializer<K> keySerializer;
+
+ // The value serializer
+ /* no qualifier */ElementSerializer<V> valueSerializer;
+
+ public String toString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( "B-tree Info :" );
+ sb.append( "\n name : " ).append( btreeName );
+ sb.append( "\n key serializer : " ).append( keySerializer.getClass().getName() );
+ sb.append( "\n value serializer : " ).append( valueSerializer.getClass().getName() );
+
+ return sb.toString();
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionComparator.java
index 215dea0..00ea577 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionComparator.java
@@ -30,6 +30,17 @@
*/
/* no qualifier*/class NameRevisionComparator implements Comparator<NameRevision>
{
+ /** A static instance of a NameRevisionComparator */
+ public static final NameRevisionComparator INSTANCE = new NameRevisionComparator();
+
+ /**
+ * A private constructor of the NameRevisionComparator class
+ */
+ private NameRevisionComparator()
+ {
+ }
+
+
/**
* {@inheritDoc}
*/
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionSerializer.java
index aac218d..a6c7a9d 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/NameRevisionSerializer.java
@@ -41,12 +41,15 @@
*/
/* no qualifier*/class NameRevisionSerializer extends AbstractElementSerializer<NameRevision>
{
+ /** A static instance of a NameRevisionSerializer */
+ /*No qualifier*/ final static NameRevisionSerializer INSTANCE = new NameRevisionSerializer();
+
/**
* Create a new instance of a NameRevisionSerializer
*/
- /* no qualifier*/NameRevisionSerializer()
+ private NameRevisionSerializer()
{
- super( new NameRevisionComparator() );
+ super( NameRevisionComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/Page.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/Page.java
index 5724e20..8056e54 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/Page.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/Page.java
@@ -31,7 +31,7 @@
* (containing keys and references to child pages).<br/>
* A Page can be stored on disk. If so, we store the serialized value of this Page into
* one or more {@link PageIO} (they will be linked)
- *
+ *
* @param <K> The type for the Key
* @param <V> The type for the stored value
*
@@ -56,22 +56,22 @@
* the Page is full, we split it and propagate the new pivot up into the tree</li>
* </ul>
* <p>
- *
- * @param revision The new revision for the modified pages
+ *
* @param key Inserted key
* @param value Inserted value
+ * @param revision The new revision for the modified pages
* @return Either a modified Page or an Overflow element if the Page was full
* @throws IOException If we have an error while trying to access the page
*/
- InsertResult<K, V> insert( long revision, K key, V value ) throws IOException;
+ InsertResult<K, V> insert( K key, V value, long revision ) throws IOException;
/**
- * Deletes the value from an entry associated with the given key in this page. We first find
+ * Deletes the value from an entry associated with the given key in this page. We first find
* the place were to remove the <K,V> into the tree, by recursively browsing the pages.
- * If the value is present, it will be deleted first, later if there are no other values associated with
+ * If the value is present, it will be deleted first, later if there are no other values associated with
* this key(which can happen when duplicates are enabled), we will remove the key from the tree.
- *
+ *
* @param revision The new revision for the modified pages
* @param key The key to delete
* @param value The value to delete (can be null)
@@ -80,15 +80,15 @@
* @return Either a modified Page if the key has been removed from the page, or a NotPresentResult.
* @throws IOException If we have an error while trying to access the page
*/
- DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos ) throws IOException;
+ DeleteResult<K, V> delete( K key, V value, long revision /*, Page<K, V> parent, int parentPos*/ ) throws IOException;
/**
- * Gets the value associated with the given key, if any. If we don't have
+ * Gets the value associated with the given key, if any. If we don't have
* one, this method will throw a KeyNotFoundException.<br/>
- * Note that we may get back null if a null value has been associated
+ * Note that we may get back null if a null value has been associated
* with the key.
- *
+ *
* @param key The key we are looking for
* @return The associated value, which can be null
* @throws KeyNotFoundException If no entry with the given key can be found
@@ -98,23 +98,23 @@
/**
- * Gets the values associated with the given key, if any. If we don't have
+ * Gets the values associated with the given key, if any. If we don't have
* the key, this method will throw a KeyNotFoundException.<br/>
- * Note that we may get back null if a null value has been associated
+ * Note that we may get back null if a null value has been associated
* with the key.
- *
+ *
* @param key The key we are looking for
* @return The associated value, which can be null
* @throws KeyNotFoundException If no entry with the given key can be found
* @throws IOException If we have an error while trying to access the page
- * @throws IllegalArgumentException If duplicates are not enabled
+ * @throws IllegalArgumentException If duplicates are not enabled
*/
ValueCursor<V> getValues( K key ) throws KeyNotFoundException, IOException, IllegalArgumentException;
/**
* Checks if the page contains the given key with the given value.
- *
+ *
* @param key The key we are looking for
* @param value The value associated with the given key
* @return true if the key and value are associated with each other, false otherwise
@@ -125,7 +125,7 @@
/**
* Browses the tree, looking for the given key, and creates a Cursor on top
* of the found result.
- *
+ *
* @param key The key we are looking for.
* @param transaction The started transaction for this operation
* @param stack The stack of parents we go through to get to this page
@@ -138,7 +138,7 @@
/**
* Browses the whole tree, and creates a Cursor on top of it.
- *
+ *
* @param transaction The started transaction for this operation
* @param stack The stack of parents we go through to get to this page
* @return A Cursor to browse the next elements
@@ -156,7 +156,7 @@
/**
* Returns the key at a given position
- *
+ *
* @param pos The position of the key we want to retrieve
* @return The key found at the given position
*/
@@ -166,7 +166,7 @@
/**
* Finds the leftmost key in this page. If the page is a node, it will go
* down in the leftmost children to recursively find the leftmost key.
- *
+ *
* @return The leftmost key in the tree
*/
K getLeftMostKey();
@@ -175,7 +175,7 @@
/**
* Finds the rightmost key in this page. If the page is a node, it will go
* down in the rightmost children to recursively find the rightmost key.
- *
+ *
* @return The rightmost key in the tree
*/
K getRightMostKey();
@@ -184,7 +184,7 @@
/**
* Finds the leftmost element in this page. If the page is a node, it will go
* down in the leftmost children to recursively find the leftmost element.
- *
+ *
* @return The leftmost element in the tree
* @throws IOException If we have an error while trying to access the page
*/
@@ -194,7 +194,7 @@
/**
* Finds the rightmost element in this page. If the page is a node, it will go
* down in the rightmost children to recursively find the rightmost element.
- *
+ *
* @return The rightmost element in the tree
* @throws IOException If we have an error while trying to access the page
*/
@@ -240,8 +240,8 @@
* <li>'h' will return -4</li>
* <li>'i' will return 4</li>
* </ul>
- *
- *
+ *
+ *
* @param key The key to find
* @return The position in the page.
*/
@@ -250,7 +250,7 @@
/**
* Checks if the given key exists.
- *
+ *
* @param key The key we are looking at
* @return true if the key is present, false otherwise
* @throws IOException If we have an error while trying to access the page
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PageIO.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PageIO.java
index a395566..dbff0ed 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PageIO.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PageIO.java
@@ -34,25 +34,25 @@
* Here is the logical structure of a PageIO :
* <pre>
* For a first page :
- *
+ *
* +----------+------+----------------------+
* | nextPage | size | XXXXXXXXXXXXXXXXXXXX |
* +----------+------+----------------------+
- *
+ *
* for any page but the first :
- *
+ *
* +----------+-----------------------------+
* | nextPage | XXXXXXXXXXXXXXXXXXXXXXXXXXX |
* +----------+-----------------------------+
- *
+ *
* for the last page :
* +----------+-----------------------------+
* | -1 | XXXXXXXXXXXXXXXXXXXXXXXXXXX |
* +----------+-----------------------------+
- *
+ *
* In any case, the page length is always PageSize.
* </pre>
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
/* No qualifier*/class PageIO
@@ -70,7 +70,7 @@
private long offset;
- /**
+ /**
* A default constructor for a PageIO
*/
/* no qualifier */PageIO()
@@ -81,7 +81,7 @@
}
- /**
+ /**
* A constructor for a PageIO when we know the offset of this page on disk
*/
/* no qualifier */PageIO( long offset )
@@ -179,6 +179,45 @@
}
+ /* no qualifier */PageIO copy( PageIO copy )
+ {
+ // The data
+ if ( data.isDirect() )
+ {
+ copy.data = ByteBuffer.allocateDirect( data.capacity() );
+ }
+ else
+ {
+ copy.data = ByteBuffer.allocate( data.capacity() );
+ }
+
+ // Save the original buffer position and limit
+ int start = data.position();
+ int limit = data.limit();
+
+ // The data is extended to get all the bytes in it
+ data.position( 0 );
+ data.limit( data.capacity() );
+
+ // Copy the data
+ copy.data.put( data );
+
+ // Restore the original buffer to the initial position and limit
+ data.position( start );
+ data.limit( limit );
+
+ // Set those position and limit in the copied buffer
+ copy.data.position( start );
+ copy.data.limit( limit );
+
+ // The size
+ copy.size = size;
+
+ // The offset and next page pointers are not copied.
+ return copy;
+ }
+
+
/**
* @see Object#toString()
*/
@@ -186,7 +225,7 @@
{
StringBuilder sb = new StringBuilder();
- sb.append( "PageIO[offset:" ).append( offset );
+ sb.append( "PageIO[offset:0x" ).append( Long.toHexString( offset ) );
if ( size != -1 )
{
@@ -195,7 +234,7 @@
if ( nextPage != -1L )
{
- sb.append( ", next:" ).append( nextPage );
+ sb.append( ", next:0x" ).append( Long.toHexString( nextPage ) );
}
sb.append( "]" );
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
index dbb6a51..e5c9c2d 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTree.java
@@ -24,9 +24,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
-import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
-import java.util.concurrent.locks.ReentrantLock;
import net.sf.ehcache.Cache;
import net.sf.ehcache.Status;
@@ -50,47 +48,44 @@
/** The LoggerFactory used by this class */
protected static final Logger LOG = LoggerFactory.getLogger( PersistedBTree.class );
- /** The RecordManager if the BTree is managed */
- private RecordManager recordManager;
+ protected static final Logger LOG_PAGES = LoggerFactory.getLogger( "LOG_PAGES" );
- /** The cache associated with this BTree */
+ /** The cache associated with this B-tree */
protected Cache cache;
/** The default number of pages to keep in memory */
- static final int DEFAULT_CACHE_SIZE = 1000;
+ public static final int DEFAULT_CACHE_SIZE = 1000;
/** The cache size, default to 1000 elements */
protected int cacheSize = DEFAULT_CACHE_SIZE;
- /** A flag indicating if this BTree is a Sub BTree */
- private boolean isSubBtree = false;
-
- /** The number of stored Values before we switch to a BTree */
+ /** The number of stored Values before we switch to a B-tree */
private static final int DEFAULT_VALUE_THRESHOLD_UP = 8;
/** The number of stored Values before we switch back to an array */
private static final int DEFAULT_VALUE_THRESHOLD_LOW = 1;
- /** The configuration for the array <-> BTree switch */
+ /** The configuration for the array <-> B-tree switch */
/*No qualifier*/static int valueThresholdUp = DEFAULT_VALUE_THRESHOLD_UP;
/*No qualifier*/static int valueThresholdLow = DEFAULT_VALUE_THRESHOLD_LOW;
- /** A lock to protect the creation of the transaction */
- protected ReentrantLock createTransaction = new ReentrantLock();
-
+ /** The BtreeInfo offset */
+ private long btreeInfoOffset;
+
+ /** The internal recordManager */
+ private RecordManager recordManager;
/**
* Creates a new BTree, with no initialization.
*/
/* no qualifier */PersistedBTree()
{
- btreeHeader = new BTreeHeader();
setType( BTreeTypeEnum.PERSISTED );
}
/**
- * Creates a new persisted BTree using the BTreeConfiguration to initialize the
+ * Creates a new persisted B-tree using the BTreeConfiguration to initialize the
* BTree
*
* @param configuration The configuration to use
@@ -105,22 +100,16 @@
throw new IllegalArgumentException( "BTree name cannot be null" );
}
- btreeHeader = new BTreeHeader();
- btreeHeader.setName( name );
- btreeHeader.setPageSize( configuration.getPageSize() );
- isSubBtree = configuration.isSubBtree();
-
- keySerializer = configuration.getKeySerializer();
- btreeHeader.setKeySerializerFQCN( keySerializer.getClass().getName() );
-
- valueSerializer = configuration.getValueSerializer();
- btreeHeader.setValueSerializerFQCN( valueSerializer.getClass().getName() );
+ setName( name );
+ setPageSize( configuration.getPageSize() );
+ setKeySerializer( configuration.getKeySerializer() );
+ setValueSerializer( configuration.getValueSerializer() );
+ setAllowDuplicates( configuration.isAllowDuplicates() );
+ setType( configuration.getBtreeType() );
readTimeOut = configuration.getReadTimeOut();
writeBufferSize = configuration.getWriteBufferSize();
- btreeHeader.setAllowDuplicates( configuration.isAllowDuplicates() );
cacheSize = configuration.getCacheSize();
- setType( BTreeTypeEnum.PERSISTED );
if ( keySerializer.getComparator() == null )
{
@@ -129,18 +118,35 @@
// Create the first root page, with revision 0L. It will be empty
// and increment the revision at the same time
- rootPage = new PersistedLeaf<K, V>( this );
+ Page<K, V> rootPage = new PersistedLeaf<K, V>( this );
- if ( isSubBtree )
+ // Create a B-tree header, and initialize it
+ BTreeHeader<K, V> btreeHeader = new BTreeHeader<K, V>();
+ btreeHeader.setRootPage( rootPage );
+ btreeHeader.setBtree( this );
+
+ switch ( btreeType )
{
- // The subBTree inherit its cache from its parent BTree
- this.cache = ( ( PersistedBTree<K, V> ) configuration.getParentBTree() ).getCache();
- this.writeLock = ( ( PersistedBTree<K, V> ) configuration.getParentBTree() ).getWriteLock();
- readTransactions = new ConcurrentLinkedQueue<ReadTransaction<K, V>>();
- }
+ case BTREE_OF_BTREES :
+ case COPIED_PAGES_BTREE :
+ // We will create a new cache and a new readTransactions map
+ init( null );
+ currentBtreeHeader = btreeHeader;
+ break;
- // Now, initialize the BTree
- init();
+ case PERSISTED_SUB :
+ init( ( PersistedBTree<K, V> ) configuration.getParentBTree() );
+ btreeRevisions.put( 0L, btreeHeader );
+ currentBtreeHeader = btreeHeader;
+ break;
+
+ default :
+ // We will create a new cache and a new readTransactions map
+ init( null );
+ btreeRevisions.put( 0L, btreeHeader );
+ currentBtreeHeader = btreeHeader;
+ break;
+ }
}
@@ -149,17 +155,15 @@
*
* @throws IOException If we get some exception while initializing the BTree
*/
- public void init()
+ public void init( BTree<K, V> parentBTree )
{
- if ( !isSubBtree )
+ if ( parentBTree == null )
{
// This is not a subBtree, we have to initialize the cache
// Create the queue containing the pending read transactions
readTransactions = new ConcurrentLinkedQueue<ReadTransaction<K, V>>();
- writeLock = new ReentrantLock();
-
// Initialize the caches
CacheConfiguration cacheConfiguration = new CacheConfiguration();
cacheConfiguration.setName( "pages" );
@@ -172,6 +176,11 @@
cache = new Cache( cacheConfiguration );
cache.initialise();
}
+ else
+ {
+ this.cache = ((PersistedBTree<K, V>)parentBTree).getCache();
+ this.readTransactions = ((PersistedBTree<K, V>)parentBTree).getReadTransactions();
+ }
// Initialize the txnManager thread
//FIXME we should NOT create a new transaction manager thread for each BTree
@@ -191,15 +200,6 @@
/**
* Return the cache we use in this BTree
*/
- /* No qualifier */ReentrantLock getWriteLock()
- {
- return writeLock;
- }
-
-
- /**
- * Return the cache we use in this BTree
- */
/* No qualifier */ConcurrentLinkedQueue<ReadTransaction<K, V>> getReadTransactions()
{
return readTransactions;
@@ -222,8 +222,6 @@
}
cache.dispose();
-
- rootPage = null;
}
@@ -232,16 +230,16 @@
*/
/* No qualifier*/long getBtreeOffset()
{
- return btreeHeader.getBTreeOffset();
+ return getBTreeHeader( getName() ).getBTreeHeaderOffset();
}
/**
- * @param btreeOffset the btreeOffset to set
+ * @param btreeOffset the B-tree header Offset to set
*/
- /* No qualifier*/void setBtreeOffset( long btreeOffset )
+ /* No qualifier*/void setBtreeHeaderOffset( long btreeHeaderOffset )
{
- btreeHeader.setBTreeOffset( btreeOffset );
+ getBTreeHeader( getName() ).setBTreeHeaderOffset( btreeHeaderOffset );
}
@@ -250,41 +248,14 @@
*/
/* No qualifier*/long getRootPageOffset()
{
- return btreeHeader.getRootPageOffset();
- }
-
-
- /**
- * @param rootPageOffset the rootPageOffset to set
- */
- /* No qualifier*/void setRootPageOffset( long rootPageOffset )
- {
- btreeHeader.setRootPageOffset( rootPageOffset );
- }
-
-
- /**
- * @return the nextBTreeOffset
- */
- /* No qualifier*/long getNextBTreeOffset()
- {
- return btreeHeader.getNextBTreeOffset();
- }
-
-
- /**
- * @param nextBTreeOffset the nextBTreeOffset to set
- */
- /* No qualifier*/void setNextBTreeOffset( long nextBTreeOffset )
- {
- btreeHeader.setNextBTreeOffset( nextBTreeOffset );
+ return getBTreeHeader( getName() ).getRootPageOffset();
}
/**
* Gets the RecordManager for a managed BTree
*
- * @return The recordManager if the BTree is managed
+ * @return The recordManager if the B-tree is managed
*/
/* No qualifier */RecordManager getRecordManager()
{
@@ -299,6 +270,8 @@
*/
/* No qualifier */void setRecordManager( RecordManager recordManager )
{
+ // The RecordManager is also the TransactionManager
+ transactionManager = recordManager;
this.recordManager = recordManager;
}
@@ -315,85 +288,162 @@
* @return
* @throws IOException
*/
- protected Tuple<K, V> delete( K key, V value, long revision ) throws IOException
+ /* no qualifier */ Tuple<K, V> delete( K key, V value, long revision ) throws IOException
{
- writeLock.lock();
+ // We have to start a new transaction, which will be committed or rollbacked
+ // locally. This will duplicate the current BtreeHeader during this phase.
+ if ( revision == -1L )
+ {
+ revision = currentRevision.get() + 1;
+ }
try
{
- // If the key exists, the existing value will be replaced. We store it
- // to return it to the caller.
- Tuple<K, V> tuple = null;
-
// Try to delete the entry starting from the root page. Here, the root
// page may be either a Node or a Leaf
- DeleteResult<K, V> result = rootPage.delete( revision, key, value, null, -1 );
+ DeleteResult<K, V> result = processDelete( key, value, revision );
+ // Check that we have found the element to delete
if ( result instanceof NotPresentResult )
{
- // Key not found.
+ // We haven't found the element in the B-tree, just get out
+ // without updating the recordManager
+
return null;
}
- // Keep the oldRootPage so that we can later access it
- Page<K, V> oldRootPage = rootPage;
+ // The element was found, and removed
+ AbstractDeleteResult<K, V> deleteResult = ( AbstractDeleteResult<K, V> ) result;
- if ( result instanceof RemoveResult )
- {
- // The element was found, and removed
- RemoveResult<K, V> removeResult = ( RemoveResult<K, V> ) result;
+ Tuple<K, V> tuple = deleteResult.getRemovedElement();
- Page<K, V> modifiedPage = removeResult.getModifiedPage();
-
- // Write the modified page on disk
- // Note that we don't use the holder, the new root page will
- // remain in memory.
- PageHolder<K, V> holder = writePage( modifiedPage, revision );
-
- // Store the offset on disk in the page in memory
- ( ( AbstractPage<K, V> ) modifiedPage ).setOffset( ( ( PersistedPageHolder<K, V> ) holder )
- .getOffset() );
-
- // Store the last offset on disk in the page in memory
- ( ( AbstractPage<K, V> ) modifiedPage )
- .setLastOffset( ( ( PersistedPageHolder<K, V> ) holder )
- .getLastOffset() );
-
- // This is a new root
- rootPage = modifiedPage;
- tuple = removeResult.getRemovedElement();
- }
-
- // Decrease the number of elements in the current tree if the deletion is successful
- if ( tuple != null )
- {
- btreeHeader.decrementNbElems();
-
- // We have to update the rootPage on disk
- // Update the BTree header now
- recordManager.updateBtreeHeader( this, ( ( AbstractPage<K, V> ) rootPage ).getOffset() );
- }
-
- recordManager.addFreePages( this, result.getCopiedPages() );
-
+ // If the B-tree is managed, we have to update the rootPage on disk
// Update the RecordManager header
- recordManager.updateRecordManagerHeader();
-
- // Store the created rootPage into the revision BTree, this will be stored in RecordManager only if revisions are set to keep
- recordManager.storeRootPage( this, rootPage );
// Return the value we have found if it was modified
return tuple;
}
- finally
+ catch ( IOException ioe )
{
- // See above
- writeLock.unlock();
+ // if we've got an error, we have to rollback
+ throw ioe;
}
}
/**
+ * Insert the tuple into the B-tree rootPage, get back the new rootPage
+ */
+ private DeleteResult<K, V> processDelete( K key, V value, long revision ) throws IOException
+ {
+ // Get the current B-tree header, and delete the value from it
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
+
+ // Try to delete the entry starting from the root page. Here, the root
+ // page may be either a Node or a Leaf
+ DeleteResult<K, V> result = btreeHeader.getRootPage().delete( key, value, revision);
+
+ if ( result instanceof NotPresentResult )
+ {
+ // Key not found.
+ return result;
+ }
+
+ // Create a new BTreeHeader
+ BTreeHeader<K, V> newBtreeHeader = btreeHeader.copy();
+
+ // Inject the old B-tree header into the pages to be freed
+ // if we are deleting an element from a management BTree
+ if ( ( btreeType == BTreeTypeEnum.BTREE_OF_BTREES ) || ( btreeType == BTreeTypeEnum.COPIED_PAGES_BTREE ) )
+ {
+ PageIO[] pageIos = recordManager.readPageIOs( btreeHeader.getBTreeHeaderOffset(), -1L );
+
+ for ( PageIO pageIo : pageIos )
+ {
+ recordManager.freedPages.add( pageIo );
+ }
+ }
+
+ // The element was found, and removed
+ AbstractDeleteResult<K, V> removeResult = ( AbstractDeleteResult<K, V> ) result;
+
+ // This is a new root
+ Page<K, V> newRootPage = removeResult.getModifiedPage();
+
+ // Write the modified page on disk
+ // Note that we don't use the holder, the new root page will
+ // remain in memory.
+ PageHolder<K, V> holder = writePage( newRootPage, revision );
+
+ // Decrease the number of elements in the current tree
+ newBtreeHeader.decrementNbElems();
+ newBtreeHeader.setRootPage( newRootPage );
+ newBtreeHeader.setRevision( revision );
+
+ // Write down the data on disk
+ long newBtreeHeaderOffset = recordManager.writeBtreeHeader( this, newBtreeHeader );
+
+
+ // Update the B-tree of B-trees with this new offset, if we are not already doing so
+ switch ( btreeType )
+ {
+ case PERSISTED :
+ // We have a new B-tree header to inject into the B-tree of btrees
+ recordManager.addInBtreeOfBtrees( getName(), revision, newBtreeHeaderOffset );
+
+ recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ case PERSISTED_SUB :
+ // Sub-B-trees are only updating the CopiedPage B-tree
+ recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+
+ //btreeRevisions.put( revision, newBtreeHeader );
+
+ currentRevision.set( revision );
+
+
+ break;
+
+ case BTREE_OF_BTREES :
+ // The B-tree of B-trees or the copiedPages B-tree has been updated, update the RMheader parameters
+ recordManager.updateRecordManagerHeader( newBtreeHeaderOffset, -1L );
+
+ // We can free the copied pages
+ recordManager.freePages( this, revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ case COPIED_PAGES_BTREE :
+ // The B-tree of B-trees or the copiedPages B-tree has been updated, update the RMheader parameters
+ recordManager.updateRecordManagerHeader( -1L, newBtreeHeaderOffset );
+
+ // We can free the copied pages
+ recordManager.freePages( this, revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ default:
+ // Nothing to do for sub-btrees
+ break;
+ }
+
+ // Return the value we have found if it was modified
+ return result;
+ }
+
+
+ /**
* Insert an entry in the BTree.
* <p>
* We will replace the value if the provided key already exists in the
@@ -408,36 +458,79 @@
*/
/* no qualifier */InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
- if ( key == null )
+ // We have to start a new transaction, which will be committed or rollbacked
+ // locally. This will duplicate the current BtreeHeader during this phase.
+ if ( revision == -1L )
{
- throw new IllegalArgumentException( "Key must not be null" );
+ revision = currentRevision.get() + 1;
}
- // If the key exists, the existing value will be replaced. We store it
- // to return it to the caller.
- V modifiedValue = null;
+ try
+ {
+ // Try to insert the new value in the tree at the right place,
+ // starting from the root page. Here, the root page may be either
+ // a Node or a Leaf
+ InsertResult<K, V> result = processInsert( key, value, revision );
- // Try to insert the new value in the tree at the right place,
- // starting from the root page. Here, the root page may be either
- // a Node or a Leaf
- InsertResult<K, V> result = rootPage.insert( revision, key, value );
+ // Return the value we have found if it was modified
+ return result;
+ }
+ catch ( IOException ioe )
+ {
+ throw ioe;
+ }
+ }
+
+
+ private BTreeHeader<K, V> getBTreeHeader( String name )
+ {
+ if ( btreeType == BTreeTypeEnum.PERSISTED_SUB )
+ {
+ return getBtreeHeader();
+ }
+
+ BTreeHeader<K, V> btreeHeader = recordManager.getBTreeHeader( getName() );
+
+ return btreeHeader;
+ }
+
+ /**
+ * Insert the tuple into the B-tree rootPage, get back the new rootPage
+ */
+ private InsertResult<K, V> processInsert( K key, V value, long revision ) throws IOException
+ {
+ // Get the current B-tree header, and insert the value into it
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
+ InsertResult<K, V> result = btreeHeader.getRootPage().insert( key, value, revision );
+
+ // Create a new BTreeHeader
+ BTreeHeader<K, V> newBtreeHeader = btreeHeader.copy();
+
+ // Inject the old B-tree header into the pages to be freed
+ // if we are inserting an element in a management BTree
+ if ( ( btreeType == BTreeTypeEnum.BTREE_OF_BTREES ) || ( btreeType == BTreeTypeEnum.COPIED_PAGES_BTREE ) )
+ {
+ PageIO[] pageIos = recordManager.readPageIOs( btreeHeader.getBTreeHeaderOffset(), -1L );
+
+ for ( PageIO pageIo : pageIos )
+ {
+ recordManager.freedPages.add( pageIo );
+ }
+ }
+
+ Page<K, V> newRootPage;
if ( result instanceof ModifyResult )
{
ModifyResult<K, V> modifyResult = ( ( ModifyResult<K, V> ) result );
- Page<K, V> modifiedPage = modifyResult.getModifiedPage();
+ newRootPage = modifyResult.getModifiedPage();
- // Write the modified page on disk
- // Note that we don't use the holder, the new root page will
- // remain in memory.
- writePage( modifiedPage, revision );
-
- // The root has just been modified, we haven't split it
- // Get it and make it the current root page
- rootPage = modifiedPage;
-
- modifiedValue = modifyResult.getModifiedValue();
+ // Increment the counter if we have inserted a new value
+ if ( modifyResult.getModifiedValue() == null )
+ {
+ newBtreeHeader.incrementNbElems();
+ }
}
else
{
@@ -448,9 +541,8 @@
K pivot = splitResult.getPivot();
Page<K, V> leftPage = splitResult.getLeftPage();
Page<K, V> rightPage = splitResult.getRightPage();
- Page<K, V> newRootPage = null;
- // If the BTree is managed, we have to write the two pages that were created
+ // If the B-tree is managed, we have to write the two pages that were created
// and to keep a track of the two offsets for the upper node
PageHolder<K, V> holderLeft = writePage( leftPage, revision );
@@ -459,41 +551,81 @@
// Create the new rootPage
newRootPage = new PersistedNode<K, V>( this, revision, pivot, holderLeft, holderRight );
- // If the BTree is managed, we now have to write the page on disk
- // and to add this page to the list of modified pages
- PageHolder<K, V> holder = writePage( newRootPage, revision );
-
- rootPage = newRootPage;
+ // Always increment the counter : we have added a new value
+ newBtreeHeader.incrementNbElems();
}
- // Increase the number of element in the current tree if the insertion is successful
- // and does not replace an element
- if ( modifiedValue == null )
+ // Write the new root page on disk
+ LOG_PAGES.debug( "Writing the new rootPage revision {} for {}", revision, name );
+ writePage( newRootPage, revision );
+
+ // Update the new B-tree header
+ newBtreeHeader.setRootPage( newRootPage );
+ newBtreeHeader.setRevision( revision );
+
+ // Write down the data on disk
+ long newBtreeHeaderOffset = recordManager.writeBtreeHeader( this, newBtreeHeader );
+
+ // Update the B-tree of B-trees with this new offset, if we are not already doing so
+ switch ( btreeType )
{
- btreeHeader.incrementNbElems();
+ case PERSISTED :
+ // We have a new B-tree header to inject into the B-tree of btrees
+ recordManager.addInBtreeOfBtrees( getName(), revision, newBtreeHeaderOffset );
+
+ recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ case PERSISTED_SUB :
+ // Sub-B-trees are only updating the CopiedPage B-tree
+ recordManager.addInCopiedPagesBtree( getName(), revision, result.getCopiedPages() );
+
+ //btreeRevisions.put( revision, newBtreeHeader );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ currentRevision.set( revision );
+
+ break;
+
+ case BTREE_OF_BTREES :
+ // The B-tree of B-trees or the copiedPages B-tree has been updated, update the RMheader parameters
+ recordManager.updateRecordManagerHeader( newBtreeHeaderOffset, -1L );
+
+ // We can free the copied pages
+ recordManager.freePages( this, revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ case COPIED_PAGES_BTREE :
+ // The B-tree of B-trees or the copiedPages B-tree has been updated, update the RMheader parameters
+ recordManager.updateRecordManagerHeader( -1L, newBtreeHeaderOffset );
+
+ // We can free the copied pages
+ recordManager.freePages( this, revision, result.getCopiedPages() );
+
+ // Store the new revision
+ storeRevision( newBtreeHeader, recordManager.isKeepRevisions() );
+
+ break;
+
+ default:
+ // Nothing to do for sub-btrees
+ break;
}
- // If the BTree is managed, we have to update the rootPage on disk
- // Update the RecordManager header
- if ( ( writeTransaction == null ) || !writeTransaction.isStarted() )
- {
- recordManager.updateRecordManagerHeader();
-
- // Update the BTree header now
- recordManager.updateBtreeHeader( this, ( ( AbstractPage<K, V> ) rootPage ).getOffset() );
-
- // Moved the free pages into the list of free pages
- recordManager.addFreePages( this, result.getCopiedPages() );
-
- // Store the created rootPage into the revision BTree, this will be stored in RecordManager only if revisions are set to keep
- recordManager.storeRootPage( this, rootPage );
- }
-
- // Return the value we have found if it was modified
+ // Get the new root page and make it the current root page
return result;
}
-
/**
* Write the data in the ByteBuffer, and eventually on disk if needed.
*
@@ -541,21 +673,9 @@
*/
private PageHolder<K, V> writePage( Page<K, V> modifiedPage, long revision ) throws IOException
{
- if ( ( writeTransaction != null ) && writeTransaction.isStarted() )
- {
- Map<Page<?, ?>, BTree<?, ?>> pendingPages = recordManager.getPendingPages();
- pendingPages.put( modifiedPage, this );
+ PageHolder<K, V> pageHolder = recordManager.writePage( this, modifiedPage, revision );
- PageHolder<K, V> pageHolder = new PageHolder<K, V>( this, modifiedPage );
-
- return pageHolder;
- }
- else
- {
- PageHolder<K, V> pageHolder = recordManager.writePage( this, modifiedPage, revision );
-
- return pageHolder;
- }
+ return pageHolder;
}
/**
@@ -573,60 +693,76 @@
/**
- * Starts a transaction
+ * Get the current rootPage
+ *
+ * @return The rootPage
*/
- public void beginTransaction()
+ public Page<K, V> getRootPage()
{
- createTransaction.lock();
+ return getBTreeHeader( getName() ).getRootPage();
+ }
- if ( writeTransaction == null )
- {
- writeTransaction = new WriteTransaction( recordManager );
- }
- createTransaction.unlock();
-
- writeTransaction.start();
+ /* no qualifier */void setRootPage( Page<K, V> root )
+ {
+ getBTreeHeader( getName() ).setRootPage( root );
}
/**
- * Commits a transaction
+ * @return the btreeInfoOffset
*/
- public void commit()
+ public long getBtreeInfoOffset()
{
- createTransaction.lock();
-
- if ( writeTransaction == null )
- {
- writeTransaction = new WriteTransaction( recordManager );
- }
-
- createTransaction.unlock();
-
- writeTransaction.commit();
+ return btreeInfoOffset;
}
/**
- * Rollback a transaction
+ * @param btreeInfoOffset the btreeInfoOffset to set
*/
- public void rollback()
+ public void setBtreeInfoOffset( long btreeInfoOffset )
{
- createTransaction.lock();
-
- if ( writeTransaction == null )
- {
- writeTransaction = new WriteTransaction( recordManager );
- }
-
- createTransaction.unlock();
-
- writeTransaction.rollback();
+ this.btreeInfoOffset = btreeInfoOffset;
}
+ /**
+ * {@inheritDoc}
+ */
+ protected ReadTransaction<K, V> beginReadTransaction()
+ {
+ BTreeHeader<K, V> btreeHeader = getBTreeHeader( getName() );
+ ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( recordManager, btreeHeader, readTransactions );
+
+ readTransactions.add( readTransaction );
+
+ return readTransaction;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected ReadTransaction<K, V> beginReadTransaction( long revision )
+ {
+ BTreeHeader<K, V> btreeHeader = getBtreeHeader( revision );
+
+ if ( btreeHeader != null )
+ {
+ ReadTransaction<K, V> readTransaction = new ReadTransaction<K, V>( recordManager, btreeHeader, readTransactions );
+
+ readTransactions.add( readTransaction );
+
+ return readTransaction;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
/**
* @see Object#toString()
@@ -636,12 +772,12 @@
StringBuilder sb = new StringBuilder();
sb.append( "Managed BTree" );
- sb.append( "[" ).append( btreeHeader.getName() ).append( "]" );
- sb.append( "( pageSize:" ).append( btreeHeader.getPageSize() );
+ sb.append( "[" ).append( getName() ).append( "]" );
+ sb.append( "( pageSize:" ).append( getPageSize() );
- if ( rootPage != null )
+ if ( getBTreeHeader( getName() ).getRootPage() != null )
{
- sb.append( ", nbEntries:" ).append( btreeHeader.getNbElems() );
+ sb.append( ", nbEntries:" ).append( getBTreeHeader( getName() ).getNbElems() );
}
else
{
@@ -659,10 +795,10 @@
sb.append( keySerializer.getComparator().getClass().getSimpleName() );
}
- sb.append( ", DuplicatesAllowed: " ).append( btreeHeader.isAllowDuplicates() );
+ sb.append( ", DuplicatesAllowed: " ).append( isAllowDuplicates() );
sb.append( ") : \n" );
- sb.append( rootPage.dumpPage( "" ) );
+ sb.append( getBTreeHeader( getName() ).getRootPage().dumpPage( "" ) );
return sb.toString();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilder.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilder.java
index 0db1a7a..d7474ea 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilder.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilder.java
@@ -32,7 +32,7 @@
/**
- * A BTree builder that builds a tree from the bottom.
+ * A B-tree builder that builds a tree from the bottom.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
@@ -138,7 +138,7 @@
rm.updateBtreeHeader( btree, ( ( AbstractPage<K, V> ) rootPage ).getOffset() );
- rm.addFreePages( btree, Arrays.asList( btree.getRootPage() ) );
+ rm.freePages( btree, btree.getRootPage().getRevision(), Arrays.asList( btree.getRootPage() ) );
( ( AbstractBTree<K, V> ) btree ).setRootPage( rootPage );
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeConfiguration.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeConfiguration.java
index 3fd4d0a..20c7020 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeConfiguration.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedBTreeConfiguration.java
@@ -25,11 +25,11 @@
/**
* The B+Tree Configuration. This class can be used to store all the configurable
- * parameters used by the BTree class
- *
+ * parameters used by the B-tree class
+ *
* @param <K> The type for the keys
* @param <V> The type for the stored values
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class PersistedBTreeConfiguration<K, V>
@@ -40,23 +40,23 @@
/** The size of the buffer used to write data in disk */
private int writeBufferSize = BTree.DEFAULT_WRITE_BUFFER_SIZE;
- /** The Key and Value serializer used for this tree. If none is provided,
- * the BTree will deduce the serializer to use from the generic type, and
+ /** The Key and Value serializer used for this tree. If none is provided,
+ * the B-tree will deduce the serializer to use from the generic type, and
* use the default Java serialization */
private ElementSerializer<K> keySerializer;
private ElementSerializer<V> valueSerializer;
- /** The BTree name */
+ /** The B-tree name */
private String name;
- /** The path where the BTree file will be stored. Default to the local
+ /** The path where the B-tree file will be stored. Default to the local
* temporary directory.
*/
private String filePath;
- /**
+ /**
* The maximum delay to wait before a revision is considered as unused.
- * This delay is necessary so that a read that does not ends does not
+ * This delay is necessary so that a read that does not ends does not
* hold a revision in memory forever.
* The default value is 10000 (10 seconds). If the value is 0 or below,
* the delay is considered as infinite
@@ -66,13 +66,13 @@
/** Flag to enable duplicate key support */
private boolean allowDuplicates;
- /** A flag set when the BTree is a sub btree */
- private boolean isSubBtree = false;
+ /** The B-tree type */
+ private BTreeTypeEnum btreeType = BTreeTypeEnum.PERSISTED;
/** The cache size, if it's <= 0, we don't have cache */
private int cacheSize;
- /** The inherited BTree if we create a sub BTree */
+ /** The inherited B-tree if we create a sub B-tree */
private BTree<?, V> parentBTree;
@@ -224,10 +224,10 @@
/**
* enable duplicate key support
- *
+ *
* @param allowDuplicates
- * @throws IllegalStateException if the btree was already initialized or when tried to turn off duplicate suport on
- * an existing btree containing duplicate keys
+ * @throws IllegalStateException if the B-tree was already initialized or when tried to turn off duplicate suport on
+ * an existing B-tree containing duplicate keys
*/
public void setAllowDuplicates( boolean allowDuplicates )
{
@@ -272,19 +272,19 @@
/**
- * @return True if this is a sub btree, false otherwise
+ * @return The BtreeType for this Btree
*/
- public boolean isSubBtree()
+ public BTreeTypeEnum getBtreeType()
{
- return isSubBtree;
+ return btreeType;
}
/**
- * @param isSubBtree True if the BTree will be a sub btree, false otherwise
+ * @param btreeType The BtreeType
*/
- public void setSubBtree( boolean isSubBtree )
+ public void setBtreeType( BTreeTypeEnum btreeType )
{
- this.isSubBtree = isSubBtree;
+ this.btreeType = btreeType;
}
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedLeaf.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedLeaf.java
index 505bc43..013fd67 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedLeaf.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedLeaf.java
@@ -71,7 +71,7 @@
/**
* {@inheritDoc}
*/
- public InsertResult<K, V> insert( long revision, K key, V value ) throws IOException
+ public InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
// Find the key into this leaf
int pos = findPos( key );
@@ -116,7 +116,7 @@
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
- public DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos )
+ /* no qualifier */ DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
throws IOException
{
// Check that the leaf is not empty
@@ -519,7 +519,7 @@
}
else
{
- throw KEY_NOT_FOUND_EXCEPTION;
+ throw KeyNotFoundException.INSTANCE;
}
}
@@ -561,7 +561,7 @@
}
else
{
- throw KEY_NOT_FOUND_EXCEPTION;
+ throw KeyNotFoundException.INSTANCE;
}
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedNode.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedNode.java
index 8526862..52711c4 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedNode.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedNode.java
@@ -120,7 +120,7 @@
/**
* {@inheritDoc}
*/
- public InsertResult<K, V> insert( long revision, K key, V value ) throws IOException
+ public InsertResult<K, V> insert( K key, V value, long revision ) throws IOException
{
// Find the key into this leaf
int pos = findPos( key );
@@ -136,7 +136,7 @@
Page<K, V> child = children[pos].getValue();
// and insert the <K, V> into this child
- InsertResult<K, V> result = child.insert( revision, key, value );
+ InsertResult<K, V> result = child.insert( key, value, revision );
// Ok, now, we have injected the <K, V> tuple down the tree. Let's check
// the result to see if we have to split the current page
@@ -567,7 +567,7 @@
/**
* {@inheritDoc}
*/
- public DeleteResult<K, V> delete( long revision, K key, V value, Page<K, V> parent, int parentPos )
+ /* no qualifier */ DeleteResult<K, V> delete( K key, V value, long revision, Page<K, V> parent, int parentPos )
throws IOException
{
// We first try to delete the element from the child it belongs to
@@ -582,12 +582,12 @@
{
index = -( pos + 1 );
child = children[-pos].getValue();
- deleteResult = child.delete( revision, key, value, this, -pos );
+ deleteResult = ((AbstractPage<K, V>)child).delete( key, value, revision, this, -pos );
}
else
{
child = children[pos].getValue();
- deleteResult = child.delete( revision, key, value, this, pos );
+ deleteResult = ((AbstractPage<K, V>)child).delete( key, value, revision, this, pos );
}
// If the key is not present in the tree, we simply return
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
index 1e819cc..794d51f 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/PersistedValueHolder.java
@@ -28,6 +28,7 @@
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyCreatedException;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
@@ -82,7 +83,7 @@
/**
* Creates a new instance of a ValueHolder, containing Values. This constructor is called
- * whe we need to create a new ValueHolder with deserialized values.
+ * when we need to create a new ValueHolder with deserialized values.
*
* @param parentBtree The parent BTree
* @param values The Values stored in the ValueHolder
@@ -248,12 +249,13 @@
configuration.setName( UUID.randomUUID().toString() );
configuration.setValueSerializer( valueSerializer );
configuration.setParentBTree( parentBtree );
- configuration.setSubBtree( true );
+ configuration.setBtreeType( BTreeTypeEnum.PERSISTED_SUB );
valueBtree = BTreeFactory.createPersistedBTree( configuration );
try
{
+ // The sub-btree will not be added into the BOB.
parentBtree.getRecordManager().manage( valueBtree, RecordManager.INTERNAL_BTREE );
raw = null;
}
@@ -419,6 +421,12 @@
e.printStackTrace();
return null;
}
+ catch ( KeyNotFoundException knfe )
+ {
+ // TODO Auto-generated catch block
+ knfe.printStackTrace();
+ return null;
+ }
}
else
{
@@ -655,7 +663,7 @@
long offset = LongSerializer.deserialize( raw );
// and reload the sub btree
- valueBtree = parentBtree.getRecordManager().loadDupsBTree( offset );
+ valueBtree = parentBtree.getRecordManager().loadDupsBtree( offset, parentBtree );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/ReadTransaction.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/ReadTransaction.java
index 3646d13..5128e28 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/ReadTransaction.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/ReadTransaction.java
@@ -21,6 +21,7 @@
import java.util.Date;
+import java.util.concurrent.ConcurrentLinkedQueue;
/**
@@ -35,7 +36,7 @@
* A Transaction can be hold for quite a long time, for instance while doing
* a browse against a big BTree. At some point, transactions which are pending
* for too long will be closed by the transaction manager.
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*
* @param <K> The type for the Key
@@ -49,26 +50,54 @@
/** The date of creation */
private long creationDate;
- /** The revision on which we are having a transaction */
- private volatile Page<K, V> root;
+ /** The associated B-tree header */
+ private BTreeHeader<K, V> btreeHeader;
/** A flag used to tell if a transaction is closed or not */
private volatile boolean closed;
+
+ /** The list of read transactions being executed */
+ private ConcurrentLinkedQueue<ReadTransaction<K, V>> readTransactions;
-
+ /** The reference to the recordManager, if any */
+ private RecordManager recordManager;
+
/**
* Creates a new transaction instance
- *
- * @param root The associated root
- * @param revision The revision this transaction is using
- * @param creationDate The creation date for this transaction
+ *
+ * @param btreeHeader The BtreeHeader we will use for this read transaction
*/
- public ReadTransaction( Page<K, V> root, long revision, long creationDate )
+ public ReadTransaction( RecordManager recordManager, BTreeHeader<K, V> btreeHeader, ConcurrentLinkedQueue<ReadTransaction<K, V>> readTransactions )
{
- this.revision = revision;
- this.creationDate = creationDate;
- this.root = root;
- closed = false;
+ if ( btreeHeader != null )
+ {
+ this.revision = btreeHeader.getRevision();
+ this.creationDate = System.currentTimeMillis();
+ this.btreeHeader = btreeHeader;
+ this.recordManager = recordManager;
+ closed = false;
+ }
+
+ this.readTransactions = readTransactions;
+ }
+
+
+ /**
+ * Creates a new transaction instance
+ *
+ * @param btreeHeader The BtreeHeader we will use for this read transaction
+ */
+ public ReadTransaction( BTreeHeader<K, V> btreeHeader, ConcurrentLinkedQueue<ReadTransaction<K, V>> readTransactions )
+ {
+ if ( btreeHeader != null )
+ {
+ this.revision = btreeHeader.getRevision();
+ this.creationDate = System.currentTimeMillis();
+ this.btreeHeader = btreeHeader;
+ closed = false;
+ }
+
+ this.readTransactions = readTransactions;
}
@@ -82,15 +111,6 @@
/**
- * @return the associated root
- */
- public Page<K, V> getRoot()
- {
- return root;
- }
-
-
- /**
* @return the creationDate
*/
public long getCreationDate()
@@ -100,12 +120,31 @@
/**
+ * @return the btreeHeader
+ */
+ public BTreeHeader<K, V> getBtreeHeader()
+ {
+ return btreeHeader;
+ }
+
+
+ /**
* Close the transaction, releasing the revision it was using.
*/
public void close()
{
- root = null;
closed = true;
+
+ // Remove the transaction from the list of opened transactions
+ readTransactions.remove( this );
+
+ // and push the
+ if ( recordManager != null )
+ {
+ recordManager.releaseTransaction( this );
+ }
+
+ // Now, get back the copied pages
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
index a3004ad..3f6ef0e 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RecordManager.java
@@ -26,18 +26,25 @@
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.BTreeCreationException;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
-import org.apache.directory.mavibot.btree.exception.FreePageException;
-import org.apache.directory.mavibot.btree.exception.InvalidBTreeException;
+import org.apache.directory.mavibot.btree.exception.FileException;
+import org.apache.directory.mavibot.btree.exception.InvalidOffsetException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.exception.RecordManagerException;
import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
@@ -50,33 +57,36 @@
/**
- * The RecordManager is used to manage the file in which we will store the BTrees.
- * A RecordManager will manage more than one BTree.<br/>
+ * The RecordManager is used to manage the file in which we will store the B-trees.
+ * A RecordManager will manage more than one B-tree.<br/>
*
* It stores data in fixed size pages (default size is 512 bytes), which may be linked one to
* the other if the data we want to store is too big for a page.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
-public class RecordManager
+public class RecordManager extends AbstractTransactionManager
{
/** The LoggerFactory used by this class */
protected static final Logger LOG = LoggerFactory.getLogger( RecordManager.class );
+ /** The LoggerFactory used by this class */
+ protected static final Logger LOG_PAGES = LoggerFactory.getLogger( "LOG_PAGES" );
+
/** A dedicated logger for the check */
- protected static final Logger LOG_CHECK = LoggerFactory.getLogger( "RM_CHECK" );
+ protected static final Logger LOG_CHECK = LoggerFactory.getLogger( "LOG_CHECK" );
/** The associated file */
private File file;
/** The channel used to read and write data */
- private FileChannel fileChannel;
+ /* no qualifier */ FileChannel fileChannel;
- /** The number of stored BTrees */
- private int nbBtree;
+ /** The number of managed B-trees */
+ /* no qualifier */ int nbBtree;
/** The first and last free page */
- private long firstFreePage;
+ /* no qualifier */ long firstFreePage;
/** The list of available free pages */
List<PageIO> freePages = new ArrayList<PageIO>();
@@ -86,25 +96,22 @@
public AtomicLong nbCreatedPages = new AtomicLong( 0 );
public AtomicLong nbReusedPages = new AtomicLong( 0 );
public AtomicLong nbUpdateRMHeader = new AtomicLong( 0 );
- public AtomicLong nbUpdateBTreeHeader = new AtomicLong( 0 );
+ public AtomicLong nbUpdateBtreeHeader = new AtomicLong( 0 );
public AtomicLong nbUpdatePageIOs = new AtomicLong( 0 );
/** The offset of the end of the file */
private long endOfFileOffset;
/**
- * A Btree used to manage the page that has been copied in a new version.
+ * A B-tree used to manage the page that has been copied in a new version.
* Those pages can be reclaimed when the associated version is dead.
**/
- private BTree<RevisionName, long[]> copiedPageBTree;
-
- /** A BTree used to store all the valid revisions for all the stored BTrees */
- private BTree<RevisionName, Long> revisionBTree;
+ private BTree<RevisionName, long[]> copiedPageBtree;
/** A constant for an offset on a non existing page */
- private static final long NO_PAGE = -1L;
+ public static final long NO_PAGE = -1L;
- /** The header page size */
+ /** The number of element we can store in a page */
private static final int PAGE_SIZE = 4;
/** The size of the link to next page */
@@ -112,44 +119,40 @@
/** Some constants */
private static final int BYTE_SIZE = 1;
- private static final int INT_SIZE = 4;
- private static final int LONG_SIZE = 8;
+ /* no qualifier */ static final int INT_SIZE = 4;
+ /* no qualifier */ static final int LONG_SIZE = 8;
/** The default page size */
- private static final int DEFAULT_PAGE_SIZE = 512;
+ public static final int DEFAULT_PAGE_SIZE = 512;
- /** The header size */
- private static int HEADER_SIZE = DEFAULT_PAGE_SIZE;
+ /** The minimal page size. Can't be below 64, as we have to store many thing sin the RMHeader */
+ private static final int MIN_PAGE_SIZE = 64;
- /** A global buffer used to store the header */
- private static ByteBuffer HEADER_BUFFER;
+ /** The RecordManager header size */
+ /* no qualifier */ static int RECORD_MANAGER_HEADER_SIZE = DEFAULT_PAGE_SIZE;
- /** A static buffer used to store the header */
- private static byte[] HEADER_BYTES;
+ /** A global buffer used to store the RecordManager header */
+ private static ByteBuffer RECORD_MANAGER_HEADER_BUFFER;
+
+ /** A static buffer used to store the RecordManager header */
+ private static byte[] RECORD_MANAGER_HEADER_BYTES;
/** The length of an Offset, as a negative value */
private static byte[] LONG_LENGTH = new byte[]
{ ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xF8 };
/** The RecordManager underlying page size. */
- private int pageSize = DEFAULT_PAGE_SIZE;
+ /* no qualifier */ int pageSize = DEFAULT_PAGE_SIZE;
- /** The set of managed BTrees */
- private Map<String, BTree<Object, Object>> managedBTrees;
-
- /** The offset on the last added BTree */
- private long lastAddedBTreeOffset = NO_PAGE;
+ /** The set of managed B-trees */
+ private Map<String, BTree<Object, Object>> managedBtrees;
+
+ /** The queue of recently closed transactions */
+ private Queue<RevisionName> closedTransactionsQueue = new LinkedBlockingQueue<RevisionName>();
/** The default file name */
private static final String DEFAULT_FILE_NAME = "mavibot.db";
- /** A deserializer for Offsets */
- private static final LongSerializer OFFSET_SERIALIZER = new LongSerializer();
-
- private static final String REVISION_BTREE_NAME = "_revisionBTree_";
-
- private static final String COPIED_PAGE_BTREE_NAME = "_copiedPageBTree_";
-
/** A flag set to true if we want to keep old revisions */
private boolean keepRevisions;
@@ -159,18 +162,48 @@
/** A flag used by internal btrees */
public static final boolean NORMAL_BTREE = false;
- /** A map of pending pages */
- private Map<Page<?, ?>, BTree<?, ?>> pendingPages = new LinkedHashMap<Page<?, ?>, BTree<?, ?>>();
-
- /** The Btree of Btrees */
+ /** The B-tree of B-trees */
private BTree<NameRevision, Long> btreeOfBtrees;
- private static final String BOB_ONE_NAME = "_BTREE_OF_BTREES_";
+ /** The B-tree of B-trees management btree name */
+ /* no qualifier */ static final String BTREE_OF_BTREES_NAME = "_btree_of_btrees_";
- /** The two latest revisions of the BOB */
- private long bobCurrentRevision;
- private long bobOldRevision;
+ /** The CopiedPages management btree name */
+ /* no qualifier */ static final String COPIED_PAGE_BTREE_NAME = "_copiedPageBtree_";
+ /** The current B-tree of B-trees header offset */
+ /* no qualifier */ long currentBtreeOfBtreesOffset;
+
+ /** The previous B-tree of B-trees header offset */
+ private long previousBtreeOfBtreesOffset = NO_PAGE;
+
+ /** The offset on the current copied pages B-tree */
+ /* no qualifier */ long currentCopiedPagesBtreeOffset = NO_PAGE;
+
+ /** The offset on the previous copied pages B-tree */
+ private long previousCopiedPagesBtreeOffset = NO_PAGE;
+
+ /** A lock to protect the transaction handling */
+ private Lock transactionLock = new ReentrantLock();
+
+ /** A ThreadLocalStorage used to store the current transaction */
+ private static final ThreadLocal<Integer> context = new ThreadLocal<Integer>();
+
+ /** The list of PageIO that can be freed after a commit */
+ List<PageIO> freedPages = new ArrayList<PageIO>();
+
+ /** The list of PageIO that can be freed after a roolback */
+ private List<PageIO> allocatedPages = new ArrayList<PageIO>();
+
+ /** A Map keeping the latest revisions for each managed BTree */
+ private Map<String, BTreeHeader<?, ?>> currentBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A Map storing the new revisions when some change have been made in some BTrees */
+ private Map<String, BTreeHeader<?, ?>> newBTreeHeaders = new HashMap<String, BTreeHeader<?, ?>>();
+
+ /** A lock to protect the BtreeHeader maps */
+ private ReadWriteLock btreeHeadersLock = new ReentrantReadWriteLock();
+
/**
* Create a Record manager which will either create the underlying file
* or load an existing one. If a folder is provided, then we will create
@@ -190,15 +223,24 @@
* a file with a default name : mavibot.db
*
* @param name The file name, or a folder name
- * @param pageSize the size of a page on disk
+ * @param pageSize the size of a page on disk, in bytes
*/
public RecordManager( String fileName, int pageSize )
{
- managedBTrees = new LinkedHashMap<String, BTree<Object, Object>>();
+ managedBtrees = new LinkedHashMap<String, BTree<Object, Object>>();
- HEADER_BUFFER = ByteBuffer.allocate( pageSize );
- HEADER_BYTES = new byte[pageSize];
- HEADER_SIZE = pageSize;
+ if ( pageSize < MIN_PAGE_SIZE )
+ {
+ this.pageSize = MIN_PAGE_SIZE;
+ }
+ else
+ {
+ this.pageSize = pageSize;
+ }
+
+ RECORD_MANAGER_HEADER_BUFFER = ByteBuffer.allocate( this.pageSize );
+ RECORD_MANAGER_HEADER_BYTES = new byte[this.pageSize];
+ RECORD_MANAGER_HEADER_SIZE = this.pageSize;
// Open the file or create it
File tmpFile = new File( fileName );
@@ -222,7 +264,6 @@
if ( isNewFile )
{
- this.pageSize = pageSize;
initRecordManager();
}
else
@@ -264,33 +305,35 @@
LOG.error( "Cannot create the file {}", mavibotFile.getName() );
return false;
}
-
}
+
/**
- * We will create a brand new RecordManager file, containing nothing, but the header,
- * a BTree to manage the old revisions we want to keep and
- * a BTree used to manage pages associated with old versions.
+ * We will create a brand new RecordManager file, containing nothing, but the RecordManager header,
+ * a B-tree to manage the old revisions we want to keep and
+ * a B-tree used to manage pages associated with old versions.
* <br/>
- * The Header contains the following details :
+ * The RecordManager header contains the following details :
* <pre>
- * +---------------+
- * | PageSize | 4 bytes : The size of a physical page (default to 4096)
- * +---------------+
- * | NbTree | 4 bytes : The number of managed BTrees (at least 1)
- * +---------------+
- * | FirstFree | 8 bytes : The offset of the first free page
- * +---------------+
- * | currentBoB | 1 byte : The current BoB in use
- * +---------------+
- * | BoB offset[0] | 8 bytes : The offset of the first BoB
- * +---------------+
- * | BoB offset[1] | 8 bytes : The offset of the second BoB
- * +---------------+
+ * +--------------------------+
+ * | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ * +--------------------------+
+ * | NbTree | 4 bytes : The number of managed B-trees (at least 1)
+ * +--------------------------+
+ * | FirstFree | 8 bytes : The offset of the first free page
+ * +--------------------------+
+ * | current BoB offset | 8 bytes : The offset of the current BoB
+ * +--------------------------+
+ * | previous BoB offset | 8 bytes : The offset of the previous BoB
+ * +--------------------------+
+ * | current CP btree offset | 8 bytes : The offset of the current BoB
+ * +--------------------------+
+ * | previous CP btree offset | 8 bytes : The offset of the previous BoB
+ * +--------------------------+
* </pre>
*
- * We then store the BTree managing the pages that have been copied when we have added
- * or deleted an element in the BTree. They are associated with a version.
+ * We then store the B-tree managing the pages that have been copied when we have added
+ * or deleted an element in the B-tree. They are associated with a version.
*
* Last, we add the bTree that keep a track on each revision we can have access to.
*/
@@ -299,8 +342,7 @@
// Create a new Header
nbBtree = 0;
firstFreePage = NO_PAGE;
- bobCurrentRevision = 0L;
- bobOldRevision = 0L;
+ currentBtreeOfBtreesOffset = 0L;
updateRecordManagerHeader();
@@ -308,22 +350,32 @@
endOfFileOffset = fileChannel.size();
// First, create the btree of btrees <NameRevision, Long>
- btreeOfBtrees = BTreeFactory.createPersistedBTree( BOB_ONE_NAME, new NameRevisionSerializer(),
- new LongSerializer() );
+ createBtreeOfBtrees();
- // Now, initialize the Copied Page BTree
- copiedPageBTree = BTreeFactory.createPersistedBTree( COPIED_PAGE_BTREE_NAME, new RevisionNameSerializer(),
- new LongArraySerializer() );
+ // Now, initialize the Copied Page B-tree
+ createCopiedPagesBtree();
- // and initialize the Revision BTree
- revisionBTree = BTreeFactory.createPersistedBTree( REVISION_BTREE_NAME, new RevisionNameSerializer(),
- new LongSerializer() );
-
- // Inject these BTrees into the RecordManager
+ // Inject these B-trees into the RecordManager. They are internal B-trees.
try
{
- manage( copiedPageBTree );
- manage( revisionBTree );
+ manage( btreeOfBtrees, INTERNAL_BTREE );
+
+ currentBtreeOfBtreesOffset = ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader().getBTreeHeaderOffset();
+ updateRecordManagerHeader();
+
+ // Inject the BtreeOfBtrees into the currentBtreeHeaders map
+ currentBTreeHeaders.put( BTREE_OF_BTREES_NAME, ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
+ newBTreeHeaders.put( BTREE_OF_BTREES_NAME, ((PersistedBTree<NameRevision, Long>)btreeOfBtrees).getBtreeHeader() );
+
+ // The FreePage B-tree
+ manage( copiedPageBtree, INTERNAL_BTREE );
+
+ currentCopiedPagesBtreeOffset = ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader().getBTreeHeaderOffset();
+ updateRecordManagerHeader();
+
+ // Inject the CopiedPagesBTree into the currentBtreeHeaders map
+ currentBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
+ newBTreeHeaders.put( COPIED_PAGE_BTREE_NAME, ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader() );
}
catch ( BTreeAlreadyManagedException btame )
{
@@ -335,109 +387,164 @@
/**
+ * Create the B-treeOfBtrees
+ */
+ private void createBtreeOfBtrees()
+ {
+ PersistedBTreeConfiguration<NameRevision, Long> configuration = new PersistedBTreeConfiguration<NameRevision, Long>();
+ configuration.setKeySerializer( NameRevisionSerializer.INSTANCE );
+ configuration.setName( BTREE_OF_BTREES_NAME );
+ configuration.setValueSerializer( LongSerializer.INSTANCE );
+ configuration.setBtreeType( BTreeTypeEnum.BTREE_OF_BTREES );
+ configuration.setCacheSize( PersistedBTree.DEFAULT_CACHE_SIZE );
+
+ btreeOfBtrees = BTreeFactory.createPersistedBTree( configuration );
+ }
+
+
+ /**
+ * Create the CopiedPagesBtree
+ */
+ private void createCopiedPagesBtree()
+ {
+ PersistedBTreeConfiguration<RevisionName, long[]> configuration = new PersistedBTreeConfiguration<RevisionName, long[]>();
+ configuration.setKeySerializer( RevisionNameSerializer.INSTANCE );
+ configuration.setName( COPIED_PAGE_BTREE_NAME );
+ configuration.setValueSerializer( LongArraySerializer.INSTANCE );
+ configuration.setBtreeType( BTreeTypeEnum.COPIED_PAGES_BTREE );
+ configuration.setCacheSize( PersistedBTree.DEFAULT_CACHE_SIZE );
+
+ copiedPageBtree = BTreeFactory.createPersistedBTree( configuration );
+ }
+
+
+ /**
* Load the BTrees from the disk.
*
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
+ * @throws NoSuchFieldException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
*/
private void loadRecordManager() throws IOException, ClassNotFoundException, IllegalAccessException,
- InstantiationException
+ InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException, KeyNotFoundException
{
if ( fileChannel.size() != 0 )
{
- ByteBuffer header = ByteBuffer.allocate( HEADER_SIZE );
+ ByteBuffer recordManagerHeader = ByteBuffer.allocate( RECORD_MANAGER_HEADER_SIZE );
// The file exists, we have to load the data now
- fileChannel.read( header );
+ fileChannel.read( recordManagerHeader );
- header.rewind();
+ recordManagerHeader.rewind();
// read the RecordManager Header :
- // +----------------+
- // | PageSize | 4 bytes : The size of a physical page (default to 4096)
- // +----------------+
- // | NbTree | 4 bytes : The number of managed BTrees (at least 1)
- // +----------------+
- // | FirstFree | 8 bytes : The offset of the first free page
- // +----------------+
- // | BoB old offset | 8 bytes : The previous BoB revision
- // +----------------+
- // | BoB new offset | 8 bytes : The current BoB revision
- // +----------------+
+ // +---------------------+
+ // | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ // +---------------------+
+ // | NbTree | 4 bytes : The number of managed B-trees (at least 1)
+ // +---------------------+
+ // | FirstFree | 8 bytes : The offset of the first free page
+ // +---------------------+
+ // | current BoB offset | 8 bytes : The offset of the current B-tree of B-trees
+ // +---------------------+
+ // | previous BoB offset | 8 bytes : The offset of the previous B-tree of B-trees
+ // +---------------------+
+ // | current CP offset | 8 bytes : The offset of the current Copied Pages B-tree
+ // +---------------------+
+ // | previous CP offset | 8 bytes : The offset of the previous Copied Pages B-tree
+ // +---------------------+
// The page size
- pageSize = header.getInt();
+ pageSize = recordManagerHeader.getInt();
- // The number of managed BTrees
- nbBtree = header.getInt();
+ // The number of managed B-trees
+ nbBtree = recordManagerHeader.getInt();
// The first and last free page
- firstFreePage = header.getLong();
+ firstFreePage = recordManagerHeader.getLong();
- // The BOB revisions
- long bobRevision1 = header.getLong();
- long bobRevision2 = header.getLong();
+ // The current BOB offset
+ currentBtreeOfBtreesOffset = recordManagerHeader.getLong();
- if ( bobRevision1 < bobRevision2 )
+ // The previous BOB offset
+ previousBtreeOfBtreesOffset = recordManagerHeader.getLong();
+
+ // The current Copied Pages B-tree offset
+ currentCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+
+ // The previous Copied Pages B-tree offset
+ previousCopiedPagesBtreeOffset = recordManagerHeader.getLong();
+
+ // read the B-tree of B-trees
+ PageIO[] bobHeaderPageIos = readPageIOs( currentBtreeOfBtreesOffset, Long.MAX_VALUE );
+
+ btreeOfBtrees = BTreeFactory.<NameRevision, Long> createPersistedBTree( BTreeTypeEnum.BTREE_OF_BTREES );
+ //BTreeFactory.<NameRevision, Long> setBtreeHeaderOffset( ( PersistedBTree<NameRevision, Long> )btreeOfBtrees, currentBtreeOfBtreesOffset );
+
+ loadBtree( bobHeaderPageIos, btreeOfBtrees );
+
+ // read the copied page B-tree
+ PageIO[] copiedPagesPageIos = readPageIOs( currentCopiedPagesBtreeOffset, Long.MAX_VALUE );
+
+ copiedPageBtree = BTreeFactory.<RevisionName, long[]> createPersistedBTree( BTreeTypeEnum.COPIED_PAGES_BTREE );
+ //( ( PersistedBTree<RevisionName, long[]> ) copiedPageBtree ).setBtreeHeaderOffset( currentCopiedPagesBtreeOffset );
+
+ loadBtree( copiedPagesPageIos, copiedPageBtree );
+
+ // Now, read all the B-trees from the btree of btrees
+ TupleCursor<NameRevision, Long> btreeCursor = btreeOfBtrees.browse();
+ Map<String, Long> loadedBtrees = new HashMap<String, Long>();
+
+ // loop on all the btrees we have, and keep only the latest revision
+ long currentRevision = -1L;
+
+ while ( btreeCursor.hasNext() )
{
- bobOldRevision = bobRevision1;
- bobCurrentRevision = bobRevision2;
- }
- else if ( bobRevision1 > bobRevision2 )
- {
- bobOldRevision = bobRevision2;
- bobCurrentRevision = bobRevision1;
- }
- else
- {
- // Special case : the RecordManage has been shtudown correctly
- bobOldRevision = bobRevision1;
- bobCurrentRevision = bobRevision2;
+ Tuple<NameRevision, Long> btreeTuple = btreeCursor.next();
+ NameRevision nameRevision = btreeTuple.getKey();
+ long btreeOffset = btreeTuple.getValue();
+ long revision = nameRevision.getValue();
+
+ // Check if we already have processed this B-tree
+ Long loadedBtreeRevision = loadedBtrees.get( nameRevision.getName() );
+
+ if ( loadedBtreeRevision != null )
+ {
+ // The btree has already been loaded. The revision is necessarily higher
+ if ( revision > currentRevision )
+ {
+ // We have a newer revision : switch to the new revision (we keep the offset atm)
+ loadedBtrees.put( nameRevision.getName(), btreeOffset );
+ currentRevision = revision;
+ }
+ }
+ else
+ {
+ // This is a new B-tree
+ loadedBtrees.put( nameRevision.getName(), btreeOffset );
+ currentRevision = nameRevision.getRevision();
+ }
}
- // Now read each BTree. The first one is the one which
- // manage the modified pages. Once read, we can discard all
- // the pages that are stored in it, as we have restarted
- // the RecordManager.
- long btreeOffset = HEADER_SIZE;
+ // TODO : clean up the old revisions...
- PageIO[] pageIos = readPageIOs( HEADER_SIZE, Long.MAX_VALUE );
- // Create the BTree
- copiedPageBTree = BTreeFactory.<RevisionName, long[]> createPersistedBTree();
- ( ( PersistedBTree<RevisionName, long[]> ) copiedPageBTree ).setBtreeOffset( btreeOffset );
-
- loadBTree( pageIos, copiedPageBTree );
- long nextBtreeOffset = ( ( PersistedBTree<RevisionName, long[]> ) copiedPageBTree ).getNextBTreeOffset();
-
- // And the Revision BTree
- pageIos = readPageIOs( nextBtreeOffset, Long.MAX_VALUE );
-
- revisionBTree = BTreeFactory.<RevisionName, Long> createPersistedBTree();
- ( ( PersistedBTree<RevisionName, Long> ) revisionBTree ).setBtreeOffset( nextBtreeOffset );
-
- loadBTree( pageIos, revisionBTree );
- nextBtreeOffset = ( ( PersistedBTree<RevisionName, Long> ) revisionBTree ).getNextBTreeOffset();
-
- // Then process the next ones
- for ( int i = 2; i < nbBtree; i++ )
+ // Now, we can load the real btrees using the offsets
+ for ( String btreeName : loadedBtrees.keySet() )
{
- // Create the BTree
- BTree<Object, Object> btree = BTreeFactory.createPersistedBTree();
- ( ( PersistedBTree<Object, Object> ) btree ).setRecordManager( this );
- ( ( PersistedBTree<Object, Object> ) btree ).setBtreeOffset( nextBtreeOffset );
- lastAddedBTreeOffset = nextBtreeOffset;
+ long btreeOffset = loadedBtrees.get( btreeName );
- // Read the associated pages
- pageIos = readPageIOs( nextBtreeOffset, Long.MAX_VALUE );
+ PageIO[] btreePageIos = readPageIOs( btreeOffset, Long.MAX_VALUE );
- // Load the BTree
- loadBTree( pageIos, btree );
- nextBtreeOffset = ( ( PersistedBTree<Object, Object> ) btree ).getNextBTreeOffset();
+ BTree<?, ?> btree = BTreeFactory.<NameRevision, Long> createPersistedBTree();
+ //( ( PersistedBTree<NameRevision, Long> ) btree ).setBtreeHeaderOffset( btreeOffset );
+ loadBtree( btreePageIos, btree );
- // Store it into the managedBtrees map
- managedBTrees.put( btree.getName(), btree );
+ // Add the btree into the map of managed B-trees
+ managedBtrees.put( btreeName, ( BTree<Object, Object> ) btree );
}
// We are done ! Let's finish with the last initialization parts
@@ -447,13 +554,170 @@
/**
+ * Starts a transaction
+ */
+ public void beginTransaction()
+ {
+ // First, take the lock
+ transactionLock.lock();
+
+ // Now, check the TLS state
+ Integer nbTxnLevel = context.get();
+
+ if ( nbTxnLevel == null )
+ {
+ context.set( 1 );
+ }
+ else
+ {
+ // And increment the counter of inner txn.
+ context.set( nbTxnLevel + 1 );
+ }
+ }
+
+
+ /**
+ * Commits a transaction
+ */
+ public void commit()
+ {
+ if ( !fileChannel.isOpen() )
+ {
+ // The file has been closed, nothing remains to commit, let's get out
+ transactionLock.unlock();
+ return;
+ }
+
+ int nbTxnStarted = context.get();
+
+ switch ( nbTxnStarted )
+ {
+ case 0 :
+ // The transaction was rollbacked, quit immediatelly
+ transactionLock.unlock();
+
+ return;
+
+ case 1 :
+ // We are done with the transaction, we can update the RMHeader and swap the BTreeHeaders
+ // First update the RMHeader to be sure that we have a way to restore from a crash
+ updateRecordManagerHeader();
+
+ // Swap the BtreeHeaders maps
+ swapCurrentBtreeHeaders();
+
+ // We can now free pages
+ for ( PageIO pageIo : freedPages )
+ {
+ try
+ {
+ free( pageIo );
+ }
+ catch ( IOException ioe )
+ {
+ throw new RecordManagerException( ioe.getMessage() );
+ }
+ }
+
+ // Release the allocated and freed pages list
+ freedPages.clear();
+ allocatedPages.clear();
+
+ // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
+ // here, we have to erase the old references to keep only the new ones.
+ updateRecordManagerHeader();
+
+ // And decrement the number of started transactions
+ context.set( nbTxnStarted - 1 );
+
+ // Finally, release the global lock
+ transactionLock.unlock();
+
+ return;
+
+ default :
+ // We are inner an existing transaction. Just update the necessary elements
+ // Update the RMHeader to be sure that we have a way to restore from a crash
+ updateRecordManagerHeader();
+
+ // Swap the BtreeHeaders maps
+ swapCurrentBtreeHeaders();
+
+ // We can now free pages
+ for ( PageIO pageIo : freedPages )
+ {
+ try
+ {
+ free( pageIo );
+ }
+ catch ( IOException ioe )
+ {
+ throw new RecordManagerException( ioe.getMessage() );
+ }
+ }
+
+ // Release the allocated and freed pages list
+ freedPages.clear();
+ allocatedPages.clear();
+
+ // And update the RMHeader again, removing the old references to BOB and CPB b-tree headers
+ // here, we have to erase the old references to keep only the new ones.
+ updateRecordManagerHeader();
+
+ // And decrement the number of started transactions
+ context.set( nbTxnStarted - 1 );
+
+ // Finally, release the global lock
+ transactionLock.unlock();
+ return;
+ }
+ }
+
+
+ /**
+ * Rollback a transaction
+ */
+ public void rollback()
+ {
+ // Reset the counter
+ context.set( 0 );
+
+ // We can now free allocated pages, this is the end of the transaction
+ for ( PageIO pageIo : allocatedPages )
+ {
+ try
+ {
+ free( pageIo );
+ }
+ catch ( IOException ioe )
+ {
+ throw new RecordManagerException( ioe.getMessage() );
+ }
+ }
+
+ // Release the allocated and freed pages list
+ freedPages.clear();
+ allocatedPages.clear();
+
+ // And update the RMHeader
+ updateRecordManagerHeader();
+
+ // And restore the BTreeHeaders new Map to the current state
+ revertBtreeHeaders();
+
+ transactionLock.unlock();
+ }
+
+
+ /**
* Reads all the PageIOs that are linked to the page at the given position, including
* the first page.
*
* @param position The position of the first page
+ * @param limit The maximum bytes to read. Set this value to -1 when the size is unknown.
* @return An array of pages
*/
- private PageIO[] readPageIOs( long position, long limit ) throws IOException, EndOfFileExceededException
+ /*no qualifier*/ PageIO[] readPageIOs( long position, long limit ) throws IOException, EndOfFileExceededException
{
LOG.debug( "Read PageIOs at position {}", position );
@@ -497,52 +761,105 @@
/**
- * Read a BTree from the disk. The meta-data are at the given position in the list of pages.
+ * Check the offset to be sure it's a valid one :
+ * <ul>
+ * <li>It's >= 0</li>
+ * <li>It's below the end of the file</li>
+ * <li>It's a multipl of the pageSize
+ * </ul>
+ * @param offset The offset to check
+ * @throws InvalidOffsetException If the offset is not valid
+ */
+ private void checkOffset( long offset )
+ {
+ if ( ( offset < 0 ) || ( offset > endOfFileOffset ) || ( ( offset % pageSize ) != 0 ) )
+ {
+ throw new InvalidOffsetException( "Bad Offset : " + offset );
+ }
+ }
+
+
+ /**
+ * Read a B-tree from the disk. The meta-data are at the given position in the list of pages.
+ * We load a B-tree in two steps : first, we load the B-tree header, then the common informations
*
* @param pageIos The list of pages containing the meta-data
- * @param btree The BTree we have to initialize
+ * @param btree The B-tree we have to initialize
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ClassNotFoundException
+ * @throws NoSuchFieldException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
*/
- private <K, V> void loadBTree( PageIO[] pageIos, BTree<K, V> btree ) throws EndOfFileExceededException,
- IOException, ClassNotFoundException, IllegalAccessException, InstantiationException
+ private <K, V> void loadBtree( PageIO[] pageIos, BTree<K, V> btree ) throws EndOfFileExceededException,
+ IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException
+ {
+ loadBtree( pageIos, btree, null );
+ }
+
+
+ /**
+ * Read a B-tree from the disk. The meta-data are at the given position in the list of pages.
+ * We load a B-tree in two steps : first, we load the B-tree header, then the common informations
+ *
+ * @param pageIos The list of pages containing the meta-data
+ * @param btree The B-tree we have to initialize
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ * @throws ClassNotFoundException
+ * @throws NoSuchFieldException
+ * @throws SecurityException
+ * @throws IllegalArgumentException
+ */
+ /* no qualifier */ <K, V> void loadBtree( PageIO[] pageIos, BTree btree, BTree<K, V> parentBTree ) throws EndOfFileExceededException,
+ IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, IllegalArgumentException, SecurityException, NoSuchFieldException
{
long dataPos = 0L;
- // The BTree current revision
+ // Process the B-tree header
+ BTreeHeader<K, V> btreeHeader = new BTreeHeader<K, V>();
+ btreeHeader.setBtree( btree );
+
+ // The BtreeHeader offset
+ btreeHeader.setBTreeHeaderOffset( pageIos[0].getOffset() );
+
+ // The B-tree current revision
long revision = readLong( pageIos, dataPos );
- BTreeFactory.setRevision( btree, revision );
+ btreeHeader.setRevision( revision );
dataPos += LONG_SIZE;
// The nb elems in the tree
long nbElems = readLong( pageIos, dataPos );
- BTreeFactory.setNbElems( btree, nbElems );
+ btreeHeader.setNbElems( nbElems );
dataPos += LONG_SIZE;
- // The BTree rootPage offset
+ // The B-tree rootPage offset
long rootPageOffset = readLong( pageIos, dataPos );
- BTreeFactory.setRootPageOffset( btree, rootPageOffset );
+ btreeHeader.setRootPageOffset( rootPageOffset );
dataPos += LONG_SIZE;
- // The next BTree offset
- long nextBTreeOffset = readLong( pageIos, dataPos );
- BTreeFactory.setNextBTreeOffset( btree, nextBTreeOffset );
- dataPos += LONG_SIZE;
+ // The B-tree information offset
+ long btreeInfoOffset = readLong( pageIos, dataPos );
- // The BTree page size
- int btreePageSize = readInt( pageIos, dataPos );
+ // Now, process the common informations
+ PageIO[] infoPageIos = readPageIOs( btreeInfoOffset, Long.MAX_VALUE );
+ ((PersistedBTree<K, V>)btree).setBtreeInfoOffset( infoPageIos[0].getOffset() );
+ dataPos = 0L;
+
+ // The B-tree page size
+ int btreePageSize = readInt( infoPageIos, dataPos );
BTreeFactory.setPageSize( btree, btreePageSize );
dataPos += INT_SIZE;
// The tree name
- ByteBuffer btreeNameBytes = readBytes( pageIos, dataPos );
+ ByteBuffer btreeNameBytes = readBytes( infoPageIos, dataPos );
dataPos += INT_SIZE + btreeNameBytes.limit();
String btreeName = Strings.utf8ToString( btreeNameBytes );
BTreeFactory.setName( btree, btreeName );
// The keySerializer FQCN
- ByteBuffer keySerializerBytes = readBytes( pageIos, dataPos );
+ ByteBuffer keySerializerBytes = readBytes( infoPageIos, dataPos );
dataPos += INT_SIZE + keySerializerBytes.limit();
String keySerializerFqcn = "";
@@ -555,7 +872,7 @@
BTreeFactory.setKeySerializer( btree, keySerializerFqcn );
// The valueSerialier FQCN
- ByteBuffer valueSerializerBytes = readBytes( pageIos, dataPos );
+ ByteBuffer valueSerializerBytes = readBytes( infoPageIos, dataPos );
String valueSerializerFqcn = "";
dataPos += INT_SIZE + valueSerializerBytes.limit();
@@ -567,19 +884,25 @@
BTreeFactory.setValueSerializer( btree, valueSerializerFqcn );
- // The BTree allowDuplicates flag
- int allowDuplicates = readInt( pageIos, dataPos );
+ // The B-tree allowDuplicates flag
+ int allowDuplicates = readInt( infoPageIos, dataPos );
( ( PersistedBTree<K, V> ) btree ).setAllowDuplicates( allowDuplicates != 0 );
dataPos += INT_SIZE;
- // Now, init the BTree
- btree.init();
-
+ // Set the recordManager in the btree
( ( PersistedBTree<K, V> ) btree ).setRecordManager( this );
- // Now, load the rootPage, which can be a Leaf or a Node, depending
- // on the number of elements in the tree : if it's above the pageSize,
- // it's a Node, otherwise it's a Leaf
+ // Set the current revision to the one stored in the B-tree header
+ // Here, we have to tell the BTree to keep this revision in the
+ // btreeRevisions Map, thus the 'true' parameter at the end.
+ ((PersistedBTree<K, V>)btree).storeRevision( btreeHeader, true );
+
+ // Now, init the B-tree
+ ( ( PersistedBTree<K, V> ) btree ).init( parentBTree );
+
+ // Update the BtreeHeaders Maps
+ currentBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
+ newBTreeHeaders.put( btree.getName(), ( ( PersistedBTree<K, V> ) btree ).getBtreeHeader() );
// Read the rootPage pages on disk
PageIO[] rootPageIos = readPageIOs( rootPageOffset, Long.MAX_VALUE );
@@ -591,31 +914,33 @@
}
- private <K, V> Page<K, V> readNode( BTree<K, V> btree, long offset, long revision, int nbElems ) throws IOException
- {
- Page<K, V> node = BTreeFactory.createNode( btree, revision, nbElems );
-
- // Read the rootPage pages on disk
- PageIO[] pageIos = readPageIOs( offset, Long.MAX_VALUE );
-
- return node;
- }
-
-
+ /**
+ * Deserialize a Page from a B-tree at a give position
+ *
+ * @param btree The B-tree we want to read a Page from
+ * @param offset The position in the file for this page
+ * @return The read page
+ * @throws EndOfFileExceededException If we have reached the end of the file while reading the page
+ */
public <K, V> Page<K, V> deserialize( BTree<K, V> btree, long offset ) throws EndOfFileExceededException,
IOException
{
+ checkOffset( offset );
PageIO[] rootPageIos = readPageIOs( offset, Long.MAX_VALUE );
Page<K, V> page = readPage( btree, rootPageIos );
- ( ( AbstractPage<K, V> ) page ).setOffset( rootPageIos[0].getOffset() );
- ( ( AbstractPage<K, V> ) page ).setLastOffset( rootPageIos[rootPageIos.length - 1].getOffset() );
-
return page;
}
+ /**
+ * Read a page from some PageIO for a given B-tree
+ * @param btree The B-tree we want to read a page for
+ * @param pageIos The PageIO containing the raw data
+ * @return The read Page if successful
+ * @throws IOException If the deserialization failed
+ */
private <K, V> Page<K, V> readPage( BTree<K, V> btree, PageIO[] pageIos ) throws IOException
{
// Deserialize the rootPage now
@@ -651,6 +976,12 @@
page = readNodeKeysAndValues( btree, -nbElems, revision, byteBuffer, pageIos );
}
+ ( ( AbstractPage<K, V> ) page ).setOffset( pageIos[0].getOffset() );
+ if ( pageIos.length > 1 )
+ {
+ ( ( AbstractPage<K, V> ) page ).setLastOffset( pageIos[pageIos.length - 1].getOffset() );
+ }
+
return page;
}
@@ -659,8 +990,7 @@
* Deserialize a Leaf from some PageIOs
*/
private <K, V> PersistedLeaf<K, V> readLeafKeysAndValues( BTree<K, V> btree, int nbElems, long revision,
- ByteBuffer byteBuffer,
- PageIO[] pageIos )
+ ByteBuffer byteBuffer, PageIO[] pageIos )
{
// Its a leaf, create it
PersistedLeaf<K, V> leaf = ( PersistedLeaf<K, V> ) BTreeFactory.createLeaf( btree, revision, nbElems );
@@ -717,8 +1047,7 @@
* Deserialize a Node from some PageIos
*/
private <K, V> PersistedNode<K, V> readNodeKeysAndValues( BTree<K, V> btree, int nbElems, long revision,
- ByteBuffer byteBuffer,
- PageIO[] pageIos ) throws IOException
+ ByteBuffer byteBuffer, PageIO[] pageIos ) throws IOException
{
PersistedNode<K, V> node = ( PersistedNode<K, V> ) BTreeFactory.createNode( btree, revision, nbElems );
@@ -726,8 +1055,8 @@
for ( int i = 0; i < nbElems; i++ )
{
// This is an Offset
- long offset = OFFSET_SERIALIZER.deserialize( byteBuffer );
- long lastOffset = OFFSET_SERIALIZER.deserialize( byteBuffer );
+ long offset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
PersistedPageHolder<K, V> valueHolder = new PersistedPageHolder<K, V>( btree, null, offset, lastOffset );
node.setValue( i, valueHolder );
@@ -747,8 +1076,8 @@
}
// and read the last value, as it's a node
- long offset = OFFSET_SERIALIZER.deserialize( byteBuffer );
- long lastOffset = OFFSET_SERIALIZER.deserialize( byteBuffer );
+ long offset = LongSerializer.INSTANCE.deserialize( byteBuffer );
+ long lastOffset = LongSerializer.INSTANCE.deserialize( byteBuffer );
PersistedPageHolder<K, V> valueHolder = new PersistedPageHolder<K, V>( btree, null, offset, lastOffset );
node.setValue( nbElems, valueHolder );
@@ -759,11 +1088,12 @@
/**
* Read a byte[] from pages.
+ *
* @param pageIos The pages we want to read the byte[] from
* @param position The position in the data stored in those pages
* @return The byte[] we have read
*/
- private ByteBuffer readBytes( PageIO[] pageIos, long position )
+ /* no qualifier */ ByteBuffer readBytes( PageIO[] pageIos, long position )
{
// Read the byte[] length first
int length = readInt( pageIos, position );
@@ -787,7 +1117,6 @@
else
{
ByteBuffer bytes = ByteBuffer.allocate( length );
- int bytesPos = 0;
while ( length > 0 )
{
@@ -814,7 +1143,6 @@
pageData.reset();
pageNb++;
pagePos = LINK_SIZE;
- bytesPos += remaining;
pageData = pageIos[pageNb].getData();
length -= remaining;
remaining = pageData.capacity() - pagePos;
@@ -833,7 +1161,7 @@
* @param position The position in the data stored in those pages
* @return The int we have read
*/
- private int readInt( PageIO[] pageIos, long position )
+ /* no qualifier */ int readInt( PageIO[] pageIos, long position )
{
// Compute the page in which we will store the data given the
// current position
@@ -923,7 +1251,7 @@
* @param position The position in the data stored in those pages
* @return The long we have read
*/
- private long readLong( PageIO[] pageIos, long position )
+ /* no qualifier */ long readLong( PageIO[] pageIos, long position )
{
// Compute the page in which we will store the data given the
// current position
@@ -1014,158 +1342,96 @@
/**
- * Manage a BTree. The btree will be added and managed by this RecordManager. We will create a
- * new RootPage for this added BTree, which will contain no data.
+ * Manage a B-tree. The btree will be added and managed by this RecordManager. We will create a
+ * new RootPage for this added B-tree, which will contain no data.<br/>
+ * This method is threadsafe.
*
- * @param btree The new BTree to manage.
+ * @param btree The new B-tree to manage.
+ * @throws BTreeAlreadyManagedException if the B-tree is already managed
+ * @throws IOException if there was a problem while accessing the file
*/
public synchronized <K, V> void manage( BTree<K, V> btree ) throws BTreeAlreadyManagedException, IOException
{
+ beginTransaction();
+
manage( ( BTree<Object, Object> ) btree, NORMAL_BTREE );
+
+ commit();
}
/**
- * works the same as @see #manage(BTree) except the given tree will not be linked to top level trees that will be
- * loaded initially if the internalTree flag is set to true
+ * Managing a btree is a matter of storing an reference to the managed B-tree in the B-tree Of B-trees.
+ * We store a tuple of NameRevision (where revision is 0L) and a offset to the B-tree header.
+ * At the same time, we keep a track of the managed B-trees in a Map.
*
- * @param btree The new BTree to manage.
- * @param internalTree flag indicating if this is an internal tree
+ * @param btree The new B-tree to manage.
+ * @param treeType flag indicating if this is an internal tree
*
- * @throws BTreeAlreadyManagedException
+ * @throws BTreeAlreadyManagedException If the B-tree is already managed
* @throws IOException
*/
- public synchronized <K, V> void manage( BTree<K, V> btree, boolean internalTree )
- throws BTreeAlreadyManagedException,
- IOException
+ public synchronized <K, V> void manage( BTree<K, V> btree, boolean treeType )
+ throws BTreeAlreadyManagedException, IOException
{
- LOG.debug( "Managing the btree {} which is an internam tree : {}", btree.getName(), internalTree );
+ LOG.debug( "Managing the btree {} which is an internam tree : {}", btree.getName(), treeType );
BTreeFactory.setRecordManager( btree, this );
String name = btree.getName();
- if ( managedBTrees.containsKey( name ) )
+ if ( managedBtrees.containsKey( name ) )
{
- // There is already a BTree with this name in the recordManager...
- LOG.error( "There is already a BTree named '{}' managed by this recordManager", name );
+ // There is already a B-tree with this name in the recordManager...
+ LOG.error( "There is already a B-tree named '{}' managed by this recordManager", name );
throw new BTreeAlreadyManagedException( name );
}
- // Do not add the BTree if it's internal into the Map of managed btrees, otherwise we will
- // not discard it when reloading a page wth internal btrees
- if ( !internalTree )
- {
- managedBTrees.put( name, ( BTree<Object, Object> ) btree );
- }
+ // Now, write the B-tree informations
+ long btreeInfoOffset = writeBtreeInfo( btree );
+ BTreeHeader<K, V> btreeHeader = ((AbstractBTree<K,V>)btree).getBtreeHeader();
+ ((PersistedBTree<K, V>)btree).setBtreeInfoOffset( btreeInfoOffset );
- // We will add the newly managed BTree at the end of the header.
- byte[] btreeNameBytes = Strings.getBytesUtf8( name );
- byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() );
- byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() );
+ // Serialize the B-tree root page
+ Page<K, V> rootPage = btreeHeader.getRootPage();
- int bufferSize =
- INT_SIZE + // The name size
- btreeNameBytes.length + // The name
- INT_SIZE + // The keySerializerBytes size
- keySerializerBytes.length + // The keySerializerBytes
- INT_SIZE + // The valueSerializerBytes size
- valueSerializerBytes.length + // The valueSerializerBytes
- INT_SIZE + // The page size
- LONG_SIZE + // The revision
- LONG_SIZE + // the number of element
- LONG_SIZE + // the nextBtree offset
- LONG_SIZE + // The root offset
- INT_SIZE; // The allowDuplicates flag
-
- // Get the pageIOs we need to store the data. We may need more than one.
- PageIO[] pageIos = getFreePageIOs( bufferSize );
-
- // Store the BTree Offset into the BTree
- long btreeOffset = pageIos[0].getOffset();
- ( ( PersistedBTree<K, V> ) btree ).setBtreeOffset( btreeOffset );
-
- // Now store the BTree data in the pages :
- // - the BTree revision
- // - the BTree number of elements
- // - The RootPage offset
- // - The next Btree offset
- // - the BTree page size
- // - the BTree name
- // - the keySerializer FQCN
- // - the valueSerializer FQCN
- // - the flags that tell if the dups are allowed
- // Starts at 0
- long position = 0L;
-
- // The BTree current revision
- position = store( position, btree.getRevision(), pageIos );
-
- // The nb elems in the tree
- position = store( position, btree.getNbElems(), pageIos );
-
- // Serialize the BTree root page
- Page<K, V> rootPage = BTreeFactory.getRootPage( btree );
-
- PageIO[] rootPageIos = serializePage( btree, btree.getRevision(), rootPage );
+ PageIO[] rootPageIos = serializePage( btree, btreeHeader.getRevision(), rootPage );
// Get the reference on the first page
- PageIO rootPageIo = rootPageIos[0];
+ long rootPageOffset = rootPageIos[0].getOffset();
- // Now, we can inject the BTree rootPage offset into the BTree header
- position = store( position, rootPageIo.getOffset(), pageIos );
- ( ( PersistedBTree<K, V> ) btree ).setRootPageOffset( rootPageIo.getOffset() );
- ( ( PersistedLeaf<K, V> ) rootPage ).setOffset( rootPageIo.getOffset() );
+ // Store the rootPageOffset into the Btree header and into the rootPage
+ btreeHeader.setRootPageOffset( rootPageOffset );
+ ( ( PersistedLeaf<K, V> ) rootPage ).setOffset( rootPageOffset );
- // The next BTree Header offset (-1L, as it's a new BTree)
- position = store( position, NO_PAGE, pageIos );
-
- // The BTree page size
- position = store( position, btree.getPageSize(), pageIos );
-
- // The tree name
- position = store( position, btreeNameBytes, pageIos );
-
- // The keySerializer FQCN
- position = store( position, keySerializerBytes, pageIos );
-
- // The valueSerialier FQCN
- position = store( position, valueSerializerBytes, pageIos );
-
- // The allowDuplicates flag
- position = store( position, ( btree.isAllowDuplicates() ? 1 : 0 ), pageIos );
-
- // And flush the pages to disk now
- LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
- flushPages( pageIos );
LOG.debug( "Flushing the newly managed '{}' btree rootpage", btree.getName() );
flushPages( rootPageIos );
- // Now, if this added BTree is not the first BTree, we have to link it with the
- // latest added BTree
- if ( !internalTree )
+ // And the B-tree header
+ long btreeHeaderOffset = writeBtreeHeader( btree, btreeHeader );
+
+ // Now, if this is a new B-tree, add it to the B-tree of B-trees
+ if ( treeType != INTERNAL_BTREE )
{
+ // Add the btree into the map of managed B-trees
+ managedBtrees.put( name, ( BTree<Object, Object> ) btree );
+
+ // And in the Map of currentBtreeHeaders and newBtreeHeaders
+ currentBTreeHeaders.put( name, btreeHeader );
+ newBTreeHeaders.put( name, btreeHeader );
+
+ // We can safely increment the number of managed B-trees
nbBtree++;
- if ( lastAddedBTreeOffset != NO_PAGE )
- {
- // We have to update the nextBtreeOffset from the previous BTreeHeader
- pageIos = readPageIOs( lastAddedBTreeOffset, LONG_SIZE + LONG_SIZE + LONG_SIZE + LONG_SIZE );
- store( LONG_SIZE + LONG_SIZE + LONG_SIZE, btreeOffset, pageIos );
+ // Create the new NameRevision
+ NameRevision nameRevision = new NameRevision( name, 0L );
- // Write the pages on disk
- LOG.debug( "Updated the previous btree pointer on the added BTree {}", btree.getName() );
- flushPages( pageIos );
- }
-
- lastAddedBTreeOffset = btreeOffset;
-
- // Last, not least, update the number of managed BTrees in the header
- updateRecordManagerHeader();
+ // Inject it into the B-tree of B-tree
+ btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
}
if ( LOG_CHECK.isDebugEnabled() )
{
- check();
+ MavibotInspector.check( this );
}
}
@@ -1352,7 +1618,7 @@
/**
- * Serialize a Leaf's Value. We store
+ * Serialize a Leaf's Value.
*/
private <K, V> int serializeLeafValue( PersistedLeaf<K, V> leaf, int pos, List<byte[]> serializedData )
throws IOException
@@ -1403,7 +1669,7 @@
serializedData.add( buffer );
dataSize += buffer.length;
- // the BTree offset
+ // the B-tree offset
buffer = LongSerializer.serialize( ( ( PersistedValueHolder<V> ) valueHolder ).getOffset() );
serializedData.add( buffer );
dataSize += buffer.length;
@@ -1464,131 +1730,581 @@
/**
- * Update the header, injecting the following data :
+ * Update the RecordManager header, injecting the following data :
+ *
* <pre>
- * +---------------+
- * | PageSize | 4 bytes : The size of a physical page (default to 4096)
- * +---------------+
- * | NbTree | 4 bytes : The number of managed BTrees (at least 1)
- * +---------------+
- * | FirstFree | 8 bytes : The offset of the first free page
- * +---------------+
- * | currentBoB | 1 byte : The current BoB in use
- * +---------------+
- * | BoB offset[0] | 8 bytes : The offset of the first BoB
- * +---------------+
- * | BoB offset[1] | 8 bytes : The offset of the second BoB
- * +---------------+
+ * +---------------------+
+ * | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ * +---------------------+
+ * | NbTree | 4 bytes : The number of managed B-trees (at least 1)
+ * +---------------------+
+ * | FirstFree | 8 bytes : The offset of the first free page
+ * +---------------------+
+ * | current BoB offset | 8 bytes : The offset of the current B-tree of B-trees
+ * +---------------------+
+ * | previous BoB offset | 8 bytes : The offset of the previous B-tree of B-trees
+ * +---------------------+
+ * | current CP offset | 8 bytes : The offset of the current CopiedPages B-tree
+ * +---------------------+
+ * | previous CP offset | 8 bytes : The offset of the previous CopiedPages B-tree
+ * +---------------------+
* </pre>
*/
- public void updateRecordManagerHeader() throws IOException
+ public void updateRecordManagerHeader()
{
// The page size
- HEADER_BYTES[0] = ( byte ) ( pageSize >>> 24 );
- HEADER_BYTES[1] = ( byte ) ( pageSize >>> 16 );
- HEADER_BYTES[2] = ( byte ) ( pageSize >>> 8 );
- HEADER_BYTES[3] = ( byte ) ( pageSize );
+ int position = writeData( RECORD_MANAGER_HEADER_BYTES, 0, pageSize );
- // The number of managed BTree (currently we have only one : the discardedPage BTree
- HEADER_BYTES[4] = ( byte ) ( nbBtree >>> 24 );
- HEADER_BYTES[5] = ( byte ) ( nbBtree >>> 16 );
- HEADER_BYTES[6] = ( byte ) ( nbBtree >>> 8 );
- HEADER_BYTES[7] = ( byte ) ( nbBtree );
+ // The number of managed B-tree
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, nbBtree );
// The first free page
- HEADER_BYTES[8] = ( byte ) ( firstFreePage >>> 56 );
- HEADER_BYTES[9] = ( byte ) ( firstFreePage >>> 48 );
- HEADER_BYTES[10] = ( byte ) ( firstFreePage >>> 40 );
- HEADER_BYTES[11] = ( byte ) ( firstFreePage >>> 32 );
- HEADER_BYTES[12] = ( byte ) ( firstFreePage >>> 24 );
- HEADER_BYTES[13] = ( byte ) ( firstFreePage >>> 16 );
- HEADER_BYTES[14] = ( byte ) ( firstFreePage >>> 8 );
- HEADER_BYTES[15] = ( byte ) ( firstFreePage );
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, firstFreePage );
- // The offset of the first BoB
- HEADER_BYTES[17] = ( byte ) ( bobOldRevision >>> 56 );
- HEADER_BYTES[18] = ( byte ) ( bobOldRevision >>> 48 );
- HEADER_BYTES[19] = ( byte ) ( bobOldRevision >>> 40 );
- HEADER_BYTES[20] = ( byte ) ( bobOldRevision >>> 32 );
- HEADER_BYTES[21] = ( byte ) ( bobOldRevision >>> 24 );
- HEADER_BYTES[22] = ( byte ) ( bobOldRevision >>> 16 );
- HEADER_BYTES[23] = ( byte ) ( bobOldRevision >>> 8 );
- HEADER_BYTES[24] = ( byte ) ( bobOldRevision );
+ // The offset of the current B-tree of B-trees
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, currentBtreeOfBtreesOffset );
- // The offset of the second BoB
- HEADER_BYTES[17] = ( byte ) ( bobCurrentRevision >>> 56 );
- HEADER_BYTES[18] = ( byte ) ( bobCurrentRevision >>> 48 );
- HEADER_BYTES[19] = ( byte ) ( bobCurrentRevision >>> 40 );
- HEADER_BYTES[20] = ( byte ) ( bobCurrentRevision >>> 32 );
- HEADER_BYTES[21] = ( byte ) ( bobCurrentRevision >>> 24 );
- HEADER_BYTES[22] = ( byte ) ( bobCurrentRevision >>> 16 );
- HEADER_BYTES[23] = ( byte ) ( bobCurrentRevision >>> 8 );
- HEADER_BYTES[24] = ( byte ) ( bobCurrentRevision );
+ // The offset of the copied pages B-tree
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, previousBtreeOfBtreesOffset );
- // Write the header on disk
- HEADER_BUFFER.put( HEADER_BYTES );
- HEADER_BUFFER.flip();
+ // The offset of the current B-tree of B-trees
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, currentCopiedPagesBtreeOffset );
- LOG.debug( "Update RM header, FF : {}", firstFreePage );
- fileChannel.write( HEADER_BUFFER, 0 );
- HEADER_BUFFER.clear();
+ // The offset of the copied pages B-tree
+ position = writeData( RECORD_MANAGER_HEADER_BYTES, position, previousCopiedPagesBtreeOffset );
+
+ // Write the RecordManager header on disk
+ RECORD_MANAGER_HEADER_BUFFER.put( RECORD_MANAGER_HEADER_BYTES );
+ RECORD_MANAGER_HEADER_BUFFER.flip();
+
+ LOG.debug( "Update RM header" );
+
+ if ( LOG_PAGES.isDebugEnabled() )
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( "First free page : 0x" ).append( Long.toHexString( firstFreePage ) ).append( "\n" );
+ sb.append( "Current BOB header : 0x" ).append( Long.toHexString( currentBtreeOfBtreesOffset ) ).append( "\n" );
+ sb.append( "Previous BOB header : 0x" ).append( Long.toHexString( previousBtreeOfBtreesOffset ) ).append( "\n" );
+ sb.append( "Current CPB header : 0x" ).append( Long.toHexString( currentCopiedPagesBtreeOffset ) ).append( "\n" );
+ sb.append( "Previous CPB header : 0x" ).append( Long.toHexString( previousCopiedPagesBtreeOffset ) ).append( "\n" );
+
+ if ( firstFreePage != NO_PAGE )
+ {
+ long freePage = firstFreePage;
+ sb.append( "free pages list : " );
+
+ boolean isFirst = true;
+
+ while ( freePage != NO_PAGE )
+ {
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( " -> " );
+ }
+
+ sb.append( "0x" ).append( Long.toHexString( freePage ) );
+
+ try
+ {
+ PageIO[] freePageIO = readPageIOs( freePage, 8 );
+
+ freePage = freePageIO[0].getNextPage();
+ }
+ catch ( EndOfFileExceededException e )
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ catch ( IOException e )
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ }
+
+ LOG_PAGES.debug( "Update RM Header : \n{}", sb.toString() );
+ }
+
+ try
+ {
+ fileChannel.write( RECORD_MANAGER_HEADER_BUFFER, 0 );
+ }
+ catch ( IOException ioe )
+ {
+ throw new FileException( ioe.getMessage() );
+ }
+
+ RECORD_MANAGER_HEADER_BUFFER.clear();
+
+ // Reset the old versions
+ previousBtreeOfBtreesOffset = -1L;
+ previousCopiedPagesBtreeOffset = -1L;
nbUpdateRMHeader.incrementAndGet();
}
/**
- * Update the BTree header after a BTree modification. This will make the latest modification
- * visible.
- * We update the following fields :
- * <ul>
- * <li>the revision</li>
- * <li>the number of elements</li>
- * <li>the reference to the current BTree revisions</li>
- * <li>the reference to the old BTree revisions</li>
- * </ul>
- * @param btree
- * @throws IOException
- * @throws EndOfFileExceededException
+ * Update the RecordManager header, injecting the following data :
+ *
+ * <pre>
+ * +---------------------+
+ * | PageSize | 4 bytes : The size of a physical page (default to 4096)
+ * +---------------------+
+ * | NbTree | 4 bytes : The number of managed B-trees (at least 1)
+ * +---------------------+
+ * | FirstFree | 8 bytes : The offset of the first free page
+ * +---------------------+
+ * | current BoB offset | 8 bytes : The offset of the current B-tree of B-trees
+ * +---------------------+
+ * | previous BoB offset | 8 bytes : The offset of the previous B-tree of B-trees
+ * +---------------------+
+ * | current CP offset | 8 bytes : The offset of the current CopiedPages B-tree
+ * +---------------------+
+ * | previous CP offset | 8 bytes : The offset of the previous CopiedPages B-tree
+ * +---------------------+
+ * </pre>
*/
- /* No qualifier*/<K, V> void updateBtreeHeader( BTree<K, V> btree, long rootPageOffset )
- throws EndOfFileExceededException,
- IOException
+ public void updateRecordManagerHeader( long newBtreeOfBtreesOffset, long newCopiedPageBtreeOffset )
{
- // Read the pageIOs associated with this BTree
- long offset = ( ( PersistedBTree<K, V> ) btree ).getBtreeOffset();
- long headerSize = LONG_SIZE + LONG_SIZE + LONG_SIZE;
-
- PageIO[] pageIos = readPageIOs( offset, headerSize );
-
- // Now, update the revision
- long position = 0;
-
- position = store( position, btree.getRevision(), pageIos );
- position = store( position, btree.getNbElems(), pageIos );
- position = store( position, rootPageOffset, pageIos );
-
- // Write the pages on disk
- if ( LOG.isDebugEnabled() )
+ if ( newBtreeOfBtreesOffset != -1L )
{
- LOG.debug( "-----> Flushing the '{}' BTreeHeader", btree.getName() );
- LOG.debug( " revision : " + btree.getRevision() + ", NbElems : " + btree.getNbElems() + ", root offset : "
- + rootPageOffset );
+ previousBtreeOfBtreesOffset = currentBtreeOfBtreesOffset;
+ currentBtreeOfBtreesOffset = newBtreeOfBtreesOffset;
}
- flushPages( pageIos );
-
- nbUpdateBTreeHeader.incrementAndGet();
-
- if ( LOG_CHECK.isDebugEnabled() )
+ if ( newCopiedPageBtreeOffset != -1L )
{
- check();
+ previousCopiedPagesBtreeOffset = currentCopiedPagesBtreeOffset;
+ currentCopiedPagesBtreeOffset = newCopiedPageBtreeOffset;
}
}
/**
- * Write the pages in the disk, either at the end of the file, or at
+ * Inject an int into a byte[] at a given position.
+ */
+ private int writeData( byte[] buffer, int position, int value )
+ {
+ RECORD_MANAGER_HEADER_BYTES[position] = ( byte ) ( value >>> 24 );
+ RECORD_MANAGER_HEADER_BYTES[position+1] = ( byte ) ( value >>> 16 );
+ RECORD_MANAGER_HEADER_BYTES[position+2] = ( byte ) ( value >>> 8 );
+ RECORD_MANAGER_HEADER_BYTES[position+3] = ( byte ) ( value );
+
+ return position + 4;
+ }
+
+
+ /**
+ * Inject a long into a byte[] at a given position.
+ */
+ private int writeData( byte[] buffer, int position, long value )
+ {
+ RECORD_MANAGER_HEADER_BYTES[position] = ( byte ) ( value >>> 56 );
+ RECORD_MANAGER_HEADER_BYTES[position+1] = ( byte ) ( value >>> 48 );
+ RECORD_MANAGER_HEADER_BYTES[position+2] = ( byte ) ( value >>> 40 );
+ RECORD_MANAGER_HEADER_BYTES[position+3] = ( byte ) ( value >>> 32 );
+ RECORD_MANAGER_HEADER_BYTES[position+4] = ( byte ) ( value >>> 24 );
+ RECORD_MANAGER_HEADER_BYTES[position+5] = ( byte ) ( value >>> 16 );
+ RECORD_MANAGER_HEADER_BYTES[position+6] = ( byte ) ( value >>> 8 );
+ RECORD_MANAGER_HEADER_BYTES[position+7] = ( byte ) ( value );
+
+ return position + 8;
+ }
+
+
+ /**
+ * Add a new <btree, revision> tuple into the B-tree of B-trees.
+ *
+ * @param name The B-tree name
+ * @param revision The B-tree revision
+ * @param btreeHeaderOffset The B-tree offset
+ * @throws IOException If the update failed
+ */
+ /* no qualifier */ <K, V> void addInBtreeOfBtrees( String name, long revision, long btreeHeaderOffset ) throws IOException
+ {
+ checkOffset( btreeHeaderOffset );
+ NameRevision nameRevision = new NameRevision( name, revision );
+
+ btreeOfBtrees.insert( nameRevision, btreeHeaderOffset );
+
+ // Update the B-tree of B-trees offset
+ currentBtreeOfBtreesOffset = getBTreeHeader( BTREE_OF_BTREES_NAME ).getBTreeHeaderOffset();
+ }
+
+
+ /**
+ * Add a new <btree, revision> tuple into the CopiedPages B-tree.
+ *
+ * @param name The B-tree name
+ * @param revision The B-tree revision
+ * @param btreeHeaderOffset The B-tree offset
+ * @throws IOException If the update failed
+ */
+ /* no qualifier */ <K, V> void addInCopiedPagesBtree( String name, long revision, List<Page<K, V>> pages ) throws IOException
+ {
+ RevisionName revisionName = new RevisionName( revision, name );
+
+ long[] pageOffsets = new long[pages.size()];
+ int pos = 0;
+
+ for ( Page<K, V> page : pages )
+ {
+ pageOffsets[pos++] = ((AbstractPage<K, V>)page).getOffset();
+ }
+
+ copiedPageBtree.insert( revisionName, pageOffsets );
+
+ // Update the CopiedPageBtree offset
+ currentCopiedPagesBtreeOffset = ((AbstractBTree<RevisionName, long[]>)copiedPageBtree).getBtreeHeader().getBTreeHeaderOffset();
+ }
+
+
+ /**
+ * Internal method used to update the B-tree of B-trees offset
+ * @param btreeOfBtreesOffset The new offset
+ */
+ /* no qualifier */ void setBtreeOfBtreesOffset( long btreeOfBtreesOffset )
+ {
+ checkOffset( btreeOfBtreesOffset );
+ this.currentBtreeOfBtreesOffset = btreeOfBtreesOffset;
+ }
+
+
+ /**
+ * Write the B-tree header on disk. We will write the following informations :
+ * <pre>
+ * +------------+
+ * | revision | The B-tree revision
+ * +------------+
+ * | nbElems | The B-tree number of elements
+ * +------------+
+ * | rootPage | The root page offset
+ * +------------+
+ * | BtreeInfo | The B-tree info offset
+ * +------------+
+ * </pre>
+ * @param btree The B-tree which header has to be written
+ * @param btreeInfoOffset The offset of the B-tree informations
+ * @return The B-tree header offset
+ * @throws IOException If we weren't able to write the B-tree header
+ */
+ /* no qualifier */ <K, V> long writeBtreeHeader( BTree<K, V> btree, BTreeHeader<K, V> btreeHeader ) throws IOException
+ {
+ int bufferSize =
+ LONG_SIZE + // The revision
+ LONG_SIZE + // the number of element
+ LONG_SIZE + // The root page offset
+ LONG_SIZE; // The B-tree info page offset
+
+ // Get the pageIOs we need to store the data. We may need more than one.
+ PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize );
+
+ // Store the B-tree header Offset into the B-tree
+ long btreeHeaderOffset = btreeHeaderPageIos[0].getOffset();
+
+ // Now store the B-tree data in the pages :
+ // - the B-tree revision
+ // - the B-tree number of elements
+ // - the B-tree root page offset
+ // - the B-tree info page offset
+ // Starts at 0
+ long position = 0L;
+
+ // The B-tree current revision
+ position = store( position, btreeHeader.getRevision(), btreeHeaderPageIos );
+
+ // The nb elems in the tree
+ position = store( position, btreeHeader.getNbElems(), btreeHeaderPageIos );
+
+
+ // Now, we can inject the B-tree rootPage offset into the B-tree header
+ position = store( position, btreeHeader.getRootPageOffset(), btreeHeaderPageIos );
+
+ // The B-tree info page offset
+ position = store( position, ((PersistedBTree<K, V>)btree).getBtreeInfoOffset(), btreeHeaderPageIos );
+
+ // And flush the pages to disk now
+ LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
+
+ if ( LOG_PAGES.isDebugEnabled() )
+ {
+ LOG_PAGES.debug( "Writing BTreeHeader revision {} for {}", btreeHeader.getRevision(), btree.getName() );
+ StringBuilder sb = new StringBuilder();
+
+ sb.append( "Offset : " ).append( Long.toHexString( btreeHeaderOffset ) ).append( "\n" );
+ sb.append( " Revision : " ).append( btreeHeader.getRevision() ).append( "\n" );
+ sb.append( " NbElems : " ).append( btreeHeader.getNbElems() ).append( "\n" );
+ sb.append( " RootPage : 0x" ).append( Long.toHexString( btreeHeader.getRootPageOffset() ) ).append( "\n" );
+ sb.append( " Info : 0x" ).append( Long.toHexString( ((PersistedBTree<K, V>)btree).getBtreeInfoOffset() ) ).append( "\n" );
+
+ LOG_PAGES.debug( "Btree Header[{}]\n{}", btreeHeader.getRevision(), sb.toString() );
+ }
+
+ flushPages( btreeHeaderPageIos );
+
+ btreeHeader.setBTreeHeaderOffset( btreeHeaderOffset );
+
+ return btreeHeaderOffset;
+ }
+
+
+ /**
+ * Write the B-tree informations on disk. We will write the following informations :
+ * <pre>
+ * +------------+
+ * | pageSize | The B-tree page size (ie, the number of elements per page max)
+ * +------------+
+ * | nameSize | The B-tree name size
+ * +------------+
+ * | name | The B-tree name
+ * +------------+
+ * | keySerSize | The keySerializer FQCN size
+ * +------------+
+ * | keySerFQCN | The keySerializer FQCN
+ * +------------+
+ * | valSerSize | The Value serializer FQCN size
+ * +------------+
+ * | valSerKQCN | The valueSerializer FQCN
+ * +------------+
+ * | dups | The flags that tell if the dups are allowed
+ * +------------+
+ * </pre>
+ * @param btree The B-tree which header has to be written
+ * @return The B-tree header offset
+ * @throws IOException If we weren't able to write the B-tree header
+ */
+ private <K, V> long writeBtreeInfo( BTree<K, V> btree ) throws IOException
+ {
+ // We will add the newly managed B-tree at the end of the header.
+ byte[] btreeNameBytes = Strings.getBytesUtf8( btree.getName() );
+ byte[] keySerializerBytes = Strings.getBytesUtf8( btree.getKeySerializerFQCN() );
+ byte[] valueSerializerBytes = Strings.getBytesUtf8( btree.getValueSerializerFQCN() );
+
+ int bufferSize =
+ INT_SIZE + // The page size
+ INT_SIZE + // The name size
+ btreeNameBytes.length + // The name
+ INT_SIZE + // The keySerializerBytes size
+ keySerializerBytes.length + // The keySerializerBytes
+ INT_SIZE + // The valueSerializerBytes size
+ valueSerializerBytes.length + // The valueSerializerBytes
+ INT_SIZE; // The allowDuplicates flag
+
+ // Get the pageIOs we need to store the data. We may need more than one.
+ PageIO[] btreeHeaderPageIos = getFreePageIOs( bufferSize );
+
+ // Keep the B-tree header Offset into the B-tree
+ long btreeInfoOffset = btreeHeaderPageIos[0].getOffset();
+
+ // Now store the B-tree information data in the pages :
+ // - the B-tree page size
+ // - the B-tree name
+ // - the keySerializer FQCN
+ // - the valueSerializer FQCN
+ // - the flags that tell if the dups are allowed
+ // Starts at 0
+ long position = 0L;
+
+ // The B-tree page size
+ position = store( position, btree.getPageSize(), btreeHeaderPageIos );
+
+ // The tree name
+ position = store( position, btreeNameBytes, btreeHeaderPageIos );
+
+ // The keySerializer FQCN
+ position = store( position, keySerializerBytes, btreeHeaderPageIos );
+
+ // The valueSerialier FQCN
+ position = store( position, valueSerializerBytes, btreeHeaderPageIos );
+
+ // The allowDuplicates flag
+ position = store( position, ( btree.isAllowDuplicates() ? 1 : 0 ), btreeHeaderPageIos );
+
+ // And flush the pages to disk now
+ LOG.debug( "Flushing the newly managed '{}' btree header", btree.getName() );
+ flushPages( btreeHeaderPageIos );
+
+ return btreeInfoOffset;
+ }
+
+
+ /**
+ * Update the B-tree header after a B-tree modification. This will make the latest modification
+ * visible.<br/>
+ * We update the following fields :
+ * <ul>
+ * <li>the revision</li>
+ * <li>the number of elements</li>
+ * <li>the B-tree root page offset</li>
+ * </ul>
+ * <br/>
+ * As a result, a new version of the BtreHeader will be created, which will replace the previous
+ * B-tree header
+ * @param btree TheB-tree to update
+ * @param btreeHeaderOffset The offset of the modified btree header
+ * @return The offset of the new B-tree Header
+ * @throws IOException If we weren't able to write the file on disk
+ * @throws EndOfFileExceededException If we tried to write after the end of the file
+ */
+ /* no qualifier */ <K, V> long updateBtreeHeader( BTree<K, V> btree, long btreeHeaderOffset )
+ throws EndOfFileExceededException, IOException
+ {
+ return updateBtreeHeader( btree, btreeHeaderOffset, false );
+ }
+
+
+ /**
+ * Update the B-tree header after a B-tree modification. This will make the latest modification
+ * visible.<br/>
+ * We update the following fields :
+ * <ul>
+ * <li>the revision</li>
+ * <li>the number of elements</li>
+ * <li>the reference to the current B-tree revisions</li>
+ * <li>the reference to the old B-tree revisions</li>
+ * </ul>
+ * <br/>
+ * As a result, we new version of the BtreHeader will be created
+ * @param btree The B-tree to update
+ * @param btreeHeaderOffset The offset of the modified btree header
+ * @return The offset of the new B-tree Header if it has changed (ie, when the onPlace flag is set to true)
+ * @throws IOException
+ * @throws EndOfFileExceededException
+ */
+ /* no qualifier */ <K, V> void updateBtreeHeaderOnPlace( BTree<K, V> btree, long btreeHeaderOffset )
+ throws EndOfFileExceededException,
+ IOException
+ {
+ updateBtreeHeader( btree, btreeHeaderOffset, true );
+ }
+
+
+ /**
+ * Update the B-tree header after a B-tree modification. This will make the latest modification
+ * visible.<br/>
+ * We update the following fields :
+ * <ul>
+ * <li>the revision</li>
+ * <li>the number of elements</li>
+ * <li>the reference to the current B-tree revisions</li>
+ * <li>the reference to the old B-tree revisions</li>
+ * </ul>
+ * <br/>
+ * As a result, a new version of the BtreHeader will be created, which may replace the previous
+ * B-tree header (if the onPlace flag is set to true) or a new set of pageIos will contain the new
+ * version.
+ *
+ * @param btree The B-tree to update
+ * @param rootPageOffset The offset of the modified rootPage
+ * @param onPlace Tells if we modify the B-tree on place, or if we create a copy
+ * @return The offset of the new B-tree Header if it has changed (ie, when the onPlace flag is set to true)
+ * @throws EndOfFileExceededException If we tried to write after the end of the file
+ * @throws IOException If tehre were some error while writing the data on disk
+ */
+ private <K, V> long updateBtreeHeader( BTree<K, V> btree, long btreeHeaderOffset, boolean onPlace )
+ throws EndOfFileExceededException, IOException
+ {
+ // Read the pageIOs associated with this B-tree
+ PageIO[] pageIos;
+ long newBtreeHeaderOffset = NO_PAGE;
+ long offset = ( ( PersistedBTree<K, V> ) btree ).getBtreeOffset();
+
+ if ( onPlace )
+ {
+ // We just have to update the existing BTreeHeader
+ long headerSize = LONG_SIZE + LONG_SIZE + LONG_SIZE;
+
+ pageIos = readPageIOs( offset, headerSize );
+
+ // Now, update the revision
+ long position = 0;
+
+ position = store( position, btree.getRevision(), pageIos );
+ position = store( position, btree.getNbElems(), pageIos );
+ position = store( position, btreeHeaderOffset, pageIos );
+
+ // Write the pages on disk
+ if ( LOG.isDebugEnabled() )
+ {
+ LOG.debug( "-----> Flushing the '{}' B-treeHeader", btree.getName() );
+ LOG.debug( " revision : " + btree.getRevision() + ", NbElems : " + btree.getNbElems() + ", btreeHeader offset : 0x"
+ + Long.toHexString( btreeHeaderOffset ) );
+ }
+
+ // Get new place on disk to store the modified BTreeHeader if it's not onPlace
+ // Rewrite the pages at the same place
+ LOG.debug( "Rewriting the B-treeHeader on place for B-tree " + btree.getName() );
+ flushPages( pageIos );
+ }
+ else
+ {
+ // We have to read and copy the existing BTreeHeader and to create a new one
+ pageIos = readPageIOs( offset, Long.MAX_VALUE );
+
+ // Now, copy every read page
+ PageIO[] newPageIOs = new PageIO[pageIos.length];
+ int pos = 0;
+
+ for ( PageIO pageIo : pageIos )
+ {
+ // Fetch a free page
+ newPageIOs[pos] = fetchNewPage();
+
+ // keep a track of the allocated and copied pages so that we can
+ // free them when we do a commit or rollback, if the btree is an management one
+ if ( ( btree.getType() == BTreeTypeEnum.BTREE_OF_BTREES ) || ( btree.getType() == BTreeTypeEnum.COPIED_PAGES_BTREE ) )
+ {
+ freedPages.add( pageIo );
+ allocatedPages.add( newPageIOs[pos] );
+ }
+
+ pageIo.copy( newPageIOs[pos] );
+
+ if ( pos > 0 )
+ {
+ newPageIOs[pos - 1].setNextPage( newPageIOs[pos].getOffset() );
+ }
+
+ pos++;
+ }
+
+ // store the new btree header offset
+ // and update the revision
+ long position = 0;
+
+ position = store( position, btree.getRevision(), newPageIOs );
+ position = store( position, btree.getNbElems(), newPageIOs );
+ position = store( position, btreeHeaderOffset, newPageIOs );
+
+ // Get new place on disk to store the modified BTreeHeader if it's not onPlace
+ // Flush the new B-treeHeader on disk
+ LOG.debug( "Rewriting the B-treeHeader on place for B-tree " + btree.getName() );
+ flushPages( newPageIOs );
+
+ newBtreeHeaderOffset = newPageIOs[0].getOffset();
+ }
+
+ nbUpdateBtreeHeader.incrementAndGet();
+
+ if ( LOG_CHECK.isDebugEnabled() )
+ {
+ MavibotInspector.check( this );
+ }
+
+ return newBtreeHeaderOffset;
+ }
+
+
+ /**
+ * Write the pages on disk, either at the end of the file, or at
* the position they were taken from.
*
* @param pageIos The list of pages to write
@@ -1660,7 +2376,7 @@
* @param position The position in a virtual byte[] if all the pages were contiguous
* @param bytes The byte[] to serialize
* @param pageIos The pageIOs we have to store the data in
- * @return The new position
+ * @return The new offset
*/
private long store( long position, byte[] bytes, PageIO... pageIos )
{
@@ -1729,7 +2445,7 @@
* @param position The position in a virtual byte[] if all the pages were contiguous
* @param bytes The byte[] to serialize
* @param pageIos The pageIOs we have to store the data in
- * @return The new position
+ * @return The new offset
*/
private long storeRaw( long position, byte[] bytes, PageIO... pageIos )
{
@@ -1801,7 +2517,7 @@
* @param position The position in a virtual byte[] if all the pages were contiguous
* @param value The int to serialize
* @param pageIos The pageIOs we have to store the data in
- * @return The new position
+ * @return The new offset
*/
private long store( long position, int value, PageIO... pageIos )
{
@@ -1876,7 +2592,7 @@
* @param position The position in a virtual byte[] if all the pages were contiguous
* @param value The long to serialize
* @param pageIos The pageIOs we have to store the data in
- * @return The new position
+ * @return The new offset
*/
private long store( long position, long value, PageIO... pageIos )
{
@@ -1977,10 +2693,9 @@
/**
- * Stores a new page on disk. We will add the modified page into the tree of copied pages.
- * The new page is serialized and saved on disk.
+ * Write the page in a serialized form.
*
- * @param btree The persistedBTree we will create a new PageHolder for
+ * @param btree The persistedBtree we will create a new PageHolder for
* @param newPage The page to write on disk
* @param newRevision The page's revision
* @return A PageHolder containing the copied page
@@ -1992,7 +2707,12 @@
// We first need to save the new page on disk
PageIO[] pageIos = serializePage( btree, newRevision, newPage );
- LOG.debug( "Write data for '{}' btree ", btree.getName() );
+ if ( LOG_PAGES.isDebugEnabled() )
+ {
+ LOG_PAGES.debug( "Write data for '{}' btree", btree.getName() );
+
+ logPageIos( pageIos );
+ }
// Write the page on disk
flushPages( pageIos );
@@ -2005,13 +2725,69 @@
if ( LOG_CHECK.isDebugEnabled() )
{
- check();
+ MavibotInspector.check( this );
}
return pageHolder;
}
+ /* No qualifier */ static void logPageIos( PageIO[] pageIos )
+ {
+ int pageNb = 0;
+
+ for ( PageIO pageIo : pageIos )
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append( "PageIO[" ).append( pageNb ).append( "]:0x" );
+ sb.append( Long.toHexString( pageIo.getOffset() ) ).append( "/");
+ sb.append( pageIo.getSize() );
+ pageNb++;
+
+ ByteBuffer data = pageIo.getData();
+
+ int position = data.position();
+ byte[] bytes = new byte[(int)pageIo.getSize() + 12];
+
+ data.get( bytes );
+ data.position( position );
+ int pos = 0;
+
+ for ( byte b : bytes )
+ {
+ int mod = pos%16;
+
+ switch ( mod )
+ {
+ case 0:
+ sb.append( "\n " );
+ // No break
+ case 4:
+ case 8:
+ case 12:
+ sb.append( " " );
+ case 1:
+ case 2:
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ case 9:
+ case 10:
+ case 11:
+ case 13:
+ case 14:
+ case 15:
+ sb.append( Strings.dumpByte( b ) ).append( " " );
+ }
+ pos++;
+ }
+
+ LOG_PAGES.debug( sb.toString() );
+ }
+ }
+
+
/**
* Compute the number of pages needed to store some specific size of data.
*
@@ -2053,7 +2829,8 @@
/**
- * Get as many pages as needed to store the data of the given size
+ * Get as many pages as needed to store the data of the given size. The returned
+ * PageIOs are all linked together.
*
* @param dataSize The data size
* @return An array of pages, enough to store the full data
@@ -2094,6 +2871,8 @@
*/
private PageIO fetchNewPage() throws IOException
{
+ //dumpFreePages( firstFreePage );
+
if ( firstFreePage == NO_PAGE )
{
nbCreatedPages.incrementAndGet();
@@ -2144,8 +2923,10 @@
* @param offset The position in the file
* @return The found page
*/
- private PageIO fetchPage( long offset ) throws IOException, EndOfFileExceededException
+ /* no qualifier */ PageIO fetchPage( long offset ) throws IOException, EndOfFileExceededException
{
+ checkOffset( offset );
+
if ( fileChannel.size() < offset + pageSize )
{
// Error : we are past the end of the file
@@ -2178,14 +2959,20 @@
}
- public void setPageSize( int pageSize )
+ /**
+ * Set the page size, ie the number of bytes a page can store.
+ *
+ * @param pageSize The number of bytes for a page
+ */
+ /* no qualifier */ void setPageSize( int pageSize )
{
- if ( this.pageSize != -1 )
+ if ( this.pageSize >= 13 )
{
+ this.pageSize = pageSize;
}
else
{
- this.pageSize = pageSize;
+ this.pageSize = DEFAULT_PAGE_SIZE;
}
}
@@ -2195,22 +2982,30 @@
*/
public void close() throws IOException
{
- // TODO : we must wait for the last write to finish
+ beginTransaction();
- for ( BTree<Object, Object> tree : managedBTrees.values() )
+ // Close all the managed B-trees
+ for ( BTree<Object, Object> tree : managedBtrees.values() )
{
tree.close();
}
- managedBTrees.clear();
+ // Close the management B-trees
+ copiedPageBtree.close();
+ btreeOfBtrees.close();
+
+ managedBtrees.clear();
// Write the data
fileChannel.force( true );
// And close the channel
fileChannel.close();
+
+ commit();
}
+
/** Hex chars */
private static final byte[] HEX_CHAR = new byte[]
{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
@@ -2248,8 +3043,6 @@
System.out.println( " 0 1 2 3 4 5 6 7 8 9 A B C D E F " );
System.out.println( "+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+" );
- int position = buffer.position();
-
for ( int i = 0; i < buffer.limit(); i += 16 )
{
System.out.print( "|" );
@@ -2279,87 +3072,267 @@
* Dump the RecordManager file
* @throws IOException
*/
- public void dump() throws IOException
+ public void dump()
{
- RandomAccessFile randomFile = new RandomAccessFile( file, "r" );
- FileChannel fileChannel = randomFile.getChannel();
+ System.out.println( "/---------------------------- Dump ----------------------------\\" );
- ByteBuffer header = ByteBuffer.allocate( HEADER_SIZE );
-
- // load the header
- fileChannel.read( header );
-
- header.rewind();
-
- // The page size
- int pageSize = header.getInt();
-
- // The number of managed BTrees
- int nbBTree = header.getInt();
-
- // The first and last free page
- long firstFreePage = header.getLong();
-
- if ( LOG.isDebugEnabled() )
+ try
{
- LOG.debug( "RecordManager" );
- LOG.debug( "-------------" );
- LOG.debug( " Header " );
- LOG.debug( " '{}'", Strings.dumpBytes( header.array() ) );
- LOG.debug( " page size : {}", pageSize );
- LOG.debug( " nbTree : {}", nbBTree );
- LOG.debug( " firstFreePage : {}", firstFreePage );
+ RandomAccessFile randomFile = new RandomAccessFile( file, "r" );
+ FileChannel fileChannel = randomFile.getChannel();
+
+ ByteBuffer recordManagerHeader = ByteBuffer.allocate( RECORD_MANAGER_HEADER_SIZE );
+
+ // load the RecordManager header
+ fileChannel.read( recordManagerHeader );
+
+ recordManagerHeader.rewind();
+
+ // The page size
+ long fileSize = fileChannel.size();
+ int pageSize = recordManagerHeader.getInt();
+ long nbPages = fileSize / pageSize;
+
+ // The number of managed B-trees
+ int nbBtree = recordManagerHeader.getInt();
+
+ // The first free page
+ long firstFreePage = recordManagerHeader.getLong();
+
+ // The current B-tree of B-trees
+ long currentBtreeOfBtreesPage = recordManagerHeader.getLong();
+
+ // The previous B-tree of B-trees
+ long previousBtreeOfBtreesPage = recordManagerHeader.getLong();
+
+ // The current CopiedPages B-tree
+ long currentCopiedPagesBtreePage = recordManagerHeader.getLong();
+
+ // The previous CopiedPages B-tree
+ long previousCopiedPagesBtreePage = recordManagerHeader.getLong();
+
+ System.out.println( " RecordManager" );
+ System.out.println( " -------------" );
+ System.out.println( " Size = 0x" + Long.toHexString( fileSize ) );
+ System.out.println( " NbPages = " + nbPages );
+ System.out.println( " Header " );
+ System.out.println( " page size : " + pageSize );
+ System.out.println( " nbTree : " + nbBtree );
+ System.out.println( " firstFreePage : 0x" + Long.toHexString( firstFreePage ) );
+ System.out.println( " current BOB : 0x" + Long.toHexString( currentBtreeOfBtreesPage ) );
+ System.out.println( " previous BOB : 0x" + Long.toHexString( previousBtreeOfBtreesPage ) );
+ System.out.println( " current CopiedPages : 0x" + Long.toHexString( currentCopiedPagesBtreePage ) );
+ System.out.println( " previous CopiedPages : 0x" + Long.toHexString( previousCopiedPagesBtreePage ) );
+
+ // Dump the Free pages list
+ dumpFreePages( firstFreePage );
+
+ // Dump the B-tree of B-trees
+ dumpBtreeHeader( currentBtreeOfBtreesPage );
+
+ // Dump the previous B-tree of B-trees if any
+ if ( previousBtreeOfBtreesPage != NO_PAGE )
+ {
+ dumpBtreeHeader( previousBtreeOfBtreesPage );
+ }
+
+ // Dump the CopiedPages B-tree
+ dumpBtreeHeader( currentCopiedPagesBtreePage );
+
+
+ // Dump the previous B-tree of B-trees if any
+ if ( previousCopiedPagesBtreePage != NO_PAGE )
+ {
+ dumpBtreeHeader( previousCopiedPagesBtreePage );
+ }
+
+ // Dump all the user's B-tree
+ randomFile.close();
+ System.out.println( "\\---------------------------- Dump ----------------------------/" );
+ }
+ catch ( IOException ioe )
+ {
+ System.out.println( "Exception while dumping the file : " + ioe.getMessage() );
+ }
+ }
+
+
+ /**
+ * Dump the free pages
+ */
+ private void dumpFreePages( long freePageOffset ) throws EndOfFileExceededException, IOException
+ {
+ System.out.println( "\n FreePages : " );
+ int pageNb = 1;
+
+ while ( freePageOffset != NO_PAGE )
+ {
+ PageIO pageIo = fetchPage( freePageOffset );
+
+ System.out.println( " freePage[" + pageNb + "] : 0x" + Long.toHexString( pageIo.getOffset() ) );
+
+ freePageOffset = pageIo.getNextPage();
+ pageNb++;
+ }
+ }
+
+
+ /**
+ * Dump a B-tree Header
+ */
+ private long dumpBtreeHeader( long btreeOffset ) throws EndOfFileExceededException, IOException
+ {
+ // First read the B-tree header
+ PageIO[] pageIos = readPageIOs( btreeOffset, Long.MAX_VALUE );
+
+ long dataPos = 0L;
+
+ // The B-tree current revision
+ long revision = readLong( pageIos, dataPos );
+ dataPos += LONG_SIZE;
+
+ // The nb elems in the tree
+ long nbElems = readLong( pageIos, dataPos );
+ dataPos += LONG_SIZE;
+
+ // The B-tree rootPage offset
+ long rootPageOffset = readLong( pageIos, dataPos );
+ dataPos += LONG_SIZE;
+
+ // The B-tree page size
+ int btreePageSize = readInt( pageIos, dataPos );
+ dataPos += INT_SIZE;
+
+ // The tree name
+ ByteBuffer btreeNameBytes = readBytes( pageIos, dataPos );
+ dataPos += INT_SIZE + btreeNameBytes.limit();
+ String btreeName = Strings.utf8ToString( btreeNameBytes );
+
+ // The keySerializer FQCN
+ ByteBuffer keySerializerBytes = readBytes( pageIos, dataPos );
+ dataPos += INT_SIZE + keySerializerBytes.limit();
+
+ String keySerializerFqcn = "";
+
+ if ( keySerializerBytes != null )
+ {
+ keySerializerFqcn = Strings.utf8ToString( keySerializerBytes );
}
- long position = HEADER_SIZE;
+ // The valueSerialier FQCN
+ ByteBuffer valueSerializerBytes = readBytes( pageIos, dataPos );
- // Dump the BTrees
- for ( int i = 0; i < nbBTree; i++ )
+ String valueSerializerFqcn = "";
+ dataPos += INT_SIZE + valueSerializerBytes.limit();
+
+ if ( valueSerializerBytes != null )
{
- LOG.debug( " Btree[{}]", i );
- PageIO[] pageIos = readPageIOs( position, Long.MAX_VALUE );
+ valueSerializerFqcn = Strings.utf8ToString( valueSerializerBytes );
+ }
+
+ // The B-tree allowDuplicates flag
+ int allowDuplicates = readInt( pageIos, dataPos );
+ boolean dupsAllowed = allowDuplicates != 0;
+
+ dataPos += INT_SIZE;
+
+// System.out.println( "\n B-Tree " + btreeName );
+// System.out.println( " ------------------------- " );
+
+// System.out.println( " nbPageIOs[" + pageIos.length + "] = " + pageIoList );
+ if ( LOG.isDebugEnabled() )
+ {
+ StringBuilder sb = new StringBuilder();
+ boolean isFirst = true;
for ( PageIO pageIo : pageIos )
{
- LOG.debug( " {}", pageIo );
+ if ( isFirst )
+ {
+ isFirst = false;
+ }
+ else
+ {
+ sb.append( ", " );
+ }
+
+ sb.append( "0x" ).append( Long.toHexString( pageIo.getOffset() ) );
}
+
+ String pageIoList = sb.toString();
+
+ LOG.debug( " PageIOs[{}] = {}", pageIos.length, pageIoList );
+
+// System.out.println( " dataSize = "+ pageIos[0].getSize() );
+ LOG.debug( " dataSize = {}", pageIos[0].getSize() );
+
+ LOG.debug( " B-tree '{}'", btreeName );
+ LOG.debug( " revision : {}", revision );
+ LOG.debug( " nbElems : {}", nbElems );
+ LOG.debug( " rootPageOffset : 0x{}", Long.toHexString( rootPageOffset ) );
+ LOG.debug( " B-tree page size : {}", btreePageSize );
+ LOG.debug( " keySerializer : '{}'", keySerializerFqcn );
+ LOG.debug( " valueSerializer : '{}'", valueSerializerFqcn );
+ LOG.debug( " dups allowed : {}", dupsAllowed );
+//
+// System.out.println( " B-tree '" + btreeName + "'" );
+// System.out.println( " revision : " + revision );
+// System.out.println( " nbElems : " + nbElems );
+// System.out.println( " rootPageOffset : 0x" + Long.toHexString( rootPageOffset ) );
+// System.out.println( " B-tree page size : " + btreePageSize );
+// System.out.println( " keySerializer : " + keySerializerFqcn );
+// System.out.println( " valueSerializer : " + valueSerializerFqcn );
+// System.out.println( " dups allowed : " + dupsAllowed );
}
- randomFile.close();
+ return rootPageOffset;
}
/**
- * Get the number of managed trees. We don't count the CopiedPage BTree. and the Revsion BTree
+ * Get the number of managed trees. We don't count the CopiedPage B-tree and the B-tree of B-trees
*
- * @return The number of managed BTrees
+ * @return The number of managed B-trees
*/
public int getNbManagedTrees()
{
- return nbBtree - 2;
+ return nbBtree;
}
/**
- * Get the managed trees. We don't return the CopiedPage BTree nor the Revision BTree.
+ * Get the managed B-trees. We don't return the CopiedPage B-tree nor the B-tree of B-trees.
*
- * @return The managed BTrees
+ * @return The managed B-trees
*/
public Set<String> getManagedTrees()
{
- Set<String> btrees = new HashSet<String>( managedBTrees.keySet() );
-
- btrees.remove( COPIED_PAGE_BTREE_NAME );
- btrees.remove( REVISION_BTREE_NAME );
+ Set<String> btrees = new HashSet<String>( managedBtrees.keySet() );
return btrees;
}
/**
- * Store a reference to an old rootPage into the Revision BTree
+ * Stores the copied pages into the CopiedPages B-tree
*
- * @param btree The BTree we want to keep an old RootPage for
+ * @param name The B-tree name
+ * @param revision The revision
+ * @param copiedPages The pages that have been copied while creating this revision
+ * @throws IOException If we weren't able to store the data on disk
+ */
+ /* No Qualifier */ void storeCopiedPages( String name, long revision, long[] copiedPages ) throws IOException
+ {
+ RevisionName revisionName = new RevisionName( revision, name );
+
+ copiedPageBtree.insert( revisionName, copiedPages );
+ }
+
+
+ /**
+ * Store a reference to an old rootPage into the Revision B-tree
+ *
+ * @param btree The B-tree we want to keep an old RootPage for
* @param rootPage The old rootPage
* @throws IOException If we have an issue while writing on disk
*/
@@ -2370,30 +3343,30 @@
return;
}
- if ( ( btree == copiedPageBTree ) || ( btree == revisionBTree ) )
+ if ( btree == copiedPageBtree )
{
return;
}
- RevisionName revisionName = new RevisionName( rootPage.getRevision(), btree.getName() );
+ NameRevision nameRevision = new NameRevision( btree.getName(), rootPage.getRevision() );
- ( ( AbstractBTree<RevisionName, Long> ) revisionBTree ).insert( revisionName,
+ ( ( AbstractBTree<NameRevision, Long> ) btreeOfBtrees ).insert( nameRevision,
( ( AbstractPage<K, V> ) rootPage ).getOffset(), 0 );
if ( LOG_CHECK.isDebugEnabled() )
{
- check();
+ MavibotInspector.check( this );
}
}
/**
- * Fetch the rootPage of a given BTree for a given revision.
+ * Fetch the rootPage of a given B-tree for a given revision.
*
- * @param btree The BTree we are interested in
+ * @param btree The B-tree we are interested in
* @param revision The revision we want to get back
- * @return The rootPage for this BTree and this revision, if any
- * @throws KeyNotFoundException If we can't find the rootPage for this revision and this BTree
+ * @return The rootPage for this B-tree and this revision, if any
+ * @throws KeyNotFoundException If we can't find the rootPage for this revision and this B-tree
* @throws IOException If we had an ise while accessing the data on disk
*/
/* No qualifier */<K, V> Page<K, V> getRootPage( BTree<K, V> btree, long revision ) throws KeyNotFoundException,
@@ -2405,12 +3378,33 @@
return btree.getRootPage();
}
- RevisionName revisionName = new RevisionName( revision, btree.getName() );
- long rootPageOffset = revisionBTree.get( revisionName );
+ // Get the B-tree header offset
+ NameRevision nameRevision = new NameRevision( btree.getName(), revision );
+ long btreeHeaderOffset = btreeOfBtrees.get( nameRevision );
+
+ // get the B-tree rootPage
+ Page<K, V> btreeRoot = readRootPage( btree, btreeHeaderOffset );
+
+ return btreeRoot;
+ }
+
+
+ /**
+ * Read a root page from the B-tree header offset
+ */
+ private <K, V> Page<K, V> readRootPage( BTree<K, V> btree, long btreeHeaderOffset ) throws EndOfFileExceededException, IOException
+ {
+ // Read the B-tree header pages on disk
+ PageIO[] btreeHeaderPageIos = readPageIOs( btreeHeaderOffset, Long.MAX_VALUE );
+ long dataPos = LONG_SIZE + LONG_SIZE;
+
+ // The B-tree rootPage offset
+ long rootPageOffset = readLong( btreeHeaderPageIos, dataPos );
// Read the rootPage pages on disk
PageIO[] rootPageIos = readPageIOs( rootPageOffset, Long.MAX_VALUE );
+ // Now, convert it to a Page
Page<K, V> btreeRoot = readPage( btree, rootPageIos );
return btreeRoot;
@@ -2420,34 +3414,30 @@
/**
* Get one managed trees, knowing its name.
*
- * @return The managed BTrees
+ * @param name The B-tree name we are looking for
+ * @return The managed B-trees
*/
public <K, V> BTree<K, V> getManagedTree( String name )
{
- return ( BTree<K, V> ) managedBTrees.get( name );
+ return ( BTree<K, V> ) managedBtrees.get( name );
}
/**
- * Move a list of pages to the free page list. A logical page is associated with on
- * or physical PageIO, which are on the disk. We have to move all those PagIO instance
+ * Move a list of pages to the free page list. A logical page is associated with one
+ * or more physical PageIOs, which are on the disk. We have to move all those PagIO instances
* to the free list, and do the same in memory (we try to keep a reference to a set of
* free pages.
*
- * @param btree The BTree which were owning the pages
+ * @param btree The B-tree which were owning the pages
+ * @param revision The current revision
* @param pages The pages to free
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException If we had a problem while updating the file
+ * @throws EndOfFileExceededException If we tried to write after the end of the file
*/
- /* Package protected */<K, V> void addFreePages( BTree<K, V> btree, List<Page<K, V>> pages )
- throws EndOfFileExceededException,
- IOException
+ /* Package protected */<K, V> void freePages( BTree<K, V> btree, long revision, List<Page<K, V>> pages )
+ throws EndOfFileExceededException, IOException
{
- if ( ( btree == copiedPageBTree ) || ( btree == revisionBTree ) )
- {
- return;
- }
-
if ( ( pages == null ) || pages.isEmpty() )
{
return;
@@ -2455,111 +3445,104 @@
if ( !keepRevisions )
{
- // if the btree doesn't keep revisions, we can safely move
- // the pages to the free page list.
- // NOTE : potential improvement : we can update the header only when
- // we have processed all the logical pages.
+ // if the B-tree doesn't keep revisions, we can safely move
+ // the pages to the freed page list.
+ if ( LOG.isDebugEnabled() )
+ {
+ LOG.debug( "Freeing the following pages :" );
+
+ for ( Page<K, V> page : pages )
+ {
+ LOG.debug( " {}", page );
+ }
+ }
for ( Page<K, V> page : pages )
{
- // Retrieve all the PageIO associated with this logical page
- long firstOffset = ( ( AbstractPage<K, V> ) page ).getOffset();
+ long pageOffset = ((AbstractPage<K, V>)page).getOffset();
- // skip the page with offset 0, this is the first in-memory root page that
- // was copied during first insert in a BTree.
- // a Node or Leaf will *never* have 0 or -1 as its offset
- if ( firstOffset == NO_PAGE )
+ PageIO[] pageIos = readPageIOs( pageOffset, Long.MAX_VALUE );
+
+ for ( PageIO pageIo : pageIos )
{
- continue;
- }
-
- long lastOffset = ( ( AbstractPage<K, V> ) page ).getLastOffset();
-
- // Update the pointers
- if ( firstFreePage == NO_PAGE )
- {
- // We don't have yet any free pageIos. The
- // PageIOs for this Page will be used
- firstFreePage = firstOffset;
- }
- else
- {
- // We add the Page's PageIOs before the
- // existing free pages.
- long offset = ( ( AbstractPage<K, V> ) page ).getLastOffset();
-
- if ( offset == NO_PAGE )
- {
- offset = ( ( AbstractPage<K, V> ) page ).getOffset();
- }
-
- // Fetch the pageIO
- PageIO pageIo = fetchPage( offset );
-
- // Link it to the first free page
- pageIo.setNextPage( firstFreePage );
-
- LOG.debug( "Flushing the first free page" );
-
- // And flush it to disk
- flushPages( pageIo );
-
- // We can update the firstFreePage offset
- firstFreePage = firstOffset;
+ freedPages.add( pageIo );
}
}
}
else
{
- LOG.debug( "We should not get there" );
-
- for ( Page<K, V> p : pages )
+ // We are keeping revisions of standard B-trees, so we move the pages to the CopiedPages B-tree
+ // but only for non managed B-trees
+ if ( LOG.isDebugEnabled() )
{
- addFreePage( btree, p );
+ LOG.debug( "Moving the following pages to the CopiedBtree :" );
+
+ for ( Page<K, V> page : pages )
+ {
+ LOG.debug( " {}", page );
+ }
}
- }
- }
+ long[] pageOffsets = new long[pages.size()];
+ int pos = 0;
- /**
- *
- * TODO addFreePage.
- *
- * @param btree
- * @param freePage
- */
- private <K, V> void addFreePage( BTree<K, V> btree, Page<K, V> freePage )
- {
- try
- {
- RevisionName revision = new RevisionName( freePage.getRevision(), btree.getName() );
- long[] offsetArray = null;
-
- if ( copiedPageBTree.hasKey( revision ) )
+ for ( Page<K, V> page : pages )
{
- offsetArray = copiedPageBTree.get( revision );
- long[] tmp = new long[offsetArray.length + 1];
- System.arraycopy( offsetArray, 0, tmp, 0, offsetArray.length );
- offsetArray = tmp;
+ pageOffsets[pos++] = ((AbstractPage<K, V>)page).offset;
+ }
+
+ if ( ( btree.getType() != BTreeTypeEnum.BTREE_OF_BTREES ) && ( btree.getType() != BTreeTypeEnum.COPIED_PAGES_BTREE ) )
+ {
+ // Deal with standard B-trees
+ RevisionName revisionName = new RevisionName( revision, btree.getName() );
+
+ copiedPageBtree.insert( revisionName, pageOffsets );
+
+ // Update the RecordManager Copiedpage Offset
+ currentCopiedPagesBtreeOffset = ((PersistedBTree<RevisionName, long[]>)copiedPageBtree).getBtreeOffset();
}
else
{
- offsetArray = new long[1];
+ // Managed B-trees : we simply free the copied pages
+ for ( long pageOffset : pageOffsets )
+ {
+ PageIO[] pageIos = readPageIOs( pageOffset, Long.MAX_VALUE );
+
+ for ( PageIO pageIo : pageIos )
+ {
+ freedPages.add( pageIo );
+ }
+ }
}
-
- offsetArray[offsetArray.length - 1] = ( ( AbstractPage<K, V> ) freePage ).getOffset();
-
- ( ( AbstractBTree<RevisionName, long[]> ) copiedPageBTree ).insert( revision, offsetArray, 0 );
- }
- catch ( Exception e )
- {
- throw new FreePageException( e );
}
}
/**
- * @return the keepRevisions
+ * Add a PageIO to the list of free PageIOs
+ *
+ * @param pageIo The page to free
+ * @throws IOException If we weren't capable of updating the file
+ */
+ private void free( PageIO pageIo ) throws IOException
+ {
+ // We add the Page's PageIOs before the
+ // existing free pages.
+ // Link it to the first free page
+ pageIo.setNextPage( firstFreePage );
+
+ LOG.debug( "Flushing the first free page" );
+
+ // And flush it to disk
+ flushPages( pageIo );
+
+ // We can update the firstFreePage offset
+ firstFreePage = pageIo.getOffset();
+ }
+
+
+ /**
+ * @return the keepRevisions flag
*/
public boolean isKeepRevisions()
{
@@ -2568,7 +3551,7 @@
/**
- * @param keepRevisions the keepRevisions to set
+ * @param keepRevisions the keepRevisions flag to set
*/
public void setKeepRevisions( boolean keepRevisions )
{
@@ -2577,20 +3560,20 @@
/**
- * Creates a BTree and automatically adds it to the list of managed btrees
+ * Creates a B-tree and automatically adds it to the list of managed btrees
*
- * @param name the name of the BTree
+ * @param name the name of the B-tree
* @param keySerializer key serializer
* @param valueSerializer value serializer
* @param allowDuplicates flag for allowing duplicate keys
- * @return a managed BTree
- * @throws IOException
- * @throws BTreeAlreadyManagedException
+ * @return a managed B-tree
+ * @throws IOException If we weren't able to update the file on disk
+ * @throws BTreeAlreadyManagedException If the B-tree is already managed
*/
@SuppressWarnings("all")
public <K, V> BTree<K, V> addBTree( String name, ElementSerializer<K> keySerializer,
- ElementSerializer<V> valueSerializer,
- boolean allowDuplicates ) throws IOException, BTreeAlreadyManagedException
+ ElementSerializer<V> valueSerializer, boolean allowDuplicates )
+ throws IOException, BTreeAlreadyManagedException
{
PersistedBTreeConfiguration config = new PersistedBTreeConfiguration();
@@ -2604,459 +3587,109 @@
if ( LOG_CHECK.isDebugEnabled() )
{
- check();
+ MavibotInspector.check( this );
}
return btree;
}
-
- private void setCheckedPage( long[] checkedPages, long offset, int pageSize )
- {
- long pageOffset = ( offset - HEADER_SIZE ) / pageSize;
- int index = ( int ) ( pageOffset / 64L );
- long mask = ( 1L << ( pageOffset % 64L ) );
- long bits = checkedPages[index];
-
- if ( ( bits & mask ) == 1 )
- {
- throw new RecordManagerException( "The page at : " + offset + " has already been checked" );
- }
-
- checkedPages[index] |= mask;
-
- }
-
-
+
/**
- * Check the free pages
- *
- * @param checkedPages
- * @throws IOException
+ * Add a newly closd transaction into the closed transaction queue
*/
- private void checkFreePages( long[] checkedPages, int pageSize, long firstFreePage )
- throws IOException
+ /* no qualifier */ <K, V> void releaseTransaction( ReadTransaction<K, V> readTransaction )
{
- if ( firstFreePage == NO_PAGE )
- {
- return;
- }
-
- // Now, read all the free pages
- long currentOffset = firstFreePage;
- long fileSize = fileChannel.size();
-
- while ( currentOffset != NO_PAGE )
- {
- if ( currentOffset > fileSize )
- {
- throw new FreePageException( "Wrong free page offset, above file size : " + currentOffset );
- }
-
- try
- {
- PageIO pageIo = fetchPage( currentOffset );
-
- if ( currentOffset != pageIo.getOffset() )
- {
- throw new InvalidBTreeException( "PageIO offset is incorrect : " + currentOffset + "-"
- + pageIo.getOffset() );
- }
-
- setCheckedPage( checkedPages, currentOffset, pageSize );
-
- long newOffset = pageIo.getNextPage();
- currentOffset = newOffset;
- }
- catch ( IOException ioe )
- {
- throw new InvalidBTreeException( "Cannot fetch page at : " + currentOffset );
- }
- }
+ RevisionName revisionName = new RevisionName(
+ readTransaction.getRevision(),
+ readTransaction.getBtreeHeader().getBtree().getName() );
+ //closedTransactionsQueue.add( revisionName );
}
-
-
+
+
/**
- * Check the root page for a given BTree
- * @throws IOException
- * @throws EndOfFileExceededException
+ * Get the current BTreeHeader for a given Btree. It might not exist
*/
- private void checkRoot( long[] checkedPages, long offset, int pageSize, long nbBTreeElems,
- ElementSerializer keySerializer, ElementSerializer valueSerializer, boolean allowDuplicates )
- throws EndOfFileExceededException, IOException
+ public BTreeHeader getBTreeHeader( String name )
{
- // Read the rootPage pages on disk
- PageIO[] rootPageIos = readPageIOs( offset, Long.MAX_VALUE );
+ // Get a lock
+ btreeHeadersLock.readLock().lock();
+
+ // get the current BTree Header for this BTree and revision
+ BTreeHeader<?, ?> btreeHeader = currentBTreeHeaders.get( name );
+
+ // And unlock
+ btreeHeadersLock.readLock().unlock();
- // Deserialize the rootPage now
- long position = 0L;
-
- // The revision
- long revision = readLong( rootPageIos, position );
- position += LONG_SIZE;
-
- // The number of elements in the page
- int nbElems = readInt( rootPageIos, position );
- position += INT_SIZE;
-
- // The size of the data containing the keys and values
- ByteBuffer byteBuffer = null;
-
- // Reads the bytes containing all the keys and values, if we have some
- ByteBuffer data = readBytes( rootPageIos, position );
-
- if ( nbElems >= 0 )
- {
- // Its a leaf
-
- // Check the page offset
- long pageOffset = rootPageIos[0].getOffset();
-
- if ( ( pageOffset < 0 ) || ( pageOffset > fileChannel.size() ) )
- {
- throw new InvalidBTreeException( "The page offset is incorrect : " + pageOffset );
- }
-
- // Check the page last offset
- long pageLastOffset = rootPageIos[rootPageIos.length - 1].getOffset();
-
- if ( ( pageLastOffset <= 0 ) || ( pageLastOffset > fileChannel.size() ) )
- {
- throw new InvalidBTreeException( "The page last offset is incorrect : " + pageLastOffset );
- }
-
- // Read each value and key
- for ( int i = 0; i < nbElems; i++ )
- {
- // Just deserialize all the keys and values
- if ( allowDuplicates )
- {
- /*
- long value = OFFSET_SERIALIZER.deserialize( byteBuffer );
-
- rootPageIos = readPageIOs( value, Long.MAX_VALUE );
-
- BTree dupValueContainer = BTreeFactory.createBTree();
- dupValueContainer.setBtreeOffset( value );
-
- try
- {
- loadBTree( pageIos, dupValueContainer );
- }
- catch ( Exception e )
- {
- // should not happen
- throw new InvalidBTreeException( e );
- }
- */
- }
- else
- {
- valueSerializer.deserialize( byteBuffer );
- }
-
- keySerializer.deserialize( byteBuffer );
- }
- }
- else
- {
- /*
- // It's a node
- int nodeNbElems = -nbElems;
-
- // Read each value and key
- for ( int i = 0; i < nodeNbElems; i++ )
- {
- // This is an Offset
- long offset = OFFSET_SERIALIZER.deserialize( byteBuffer );
- long lastOffset = OFFSET_SERIALIZER.deserialize( byteBuffer );
-
- ElementHolder valueHolder = new ReferenceHolder( btree, null, offset, lastOffset );
- ( ( Node ) page ).setValue( i, valueHolder );
-
- Object key = btree.getKeySerializer().deserialize( byteBuffer );
- BTreeFactory.setKey( page, i, key );
- }
-
- // and read the last value, as it's a node
- long offset = OFFSET_SERIALIZER.deserialize( byteBuffer );
- long lastOffset = OFFSET_SERIALIZER.deserialize( byteBuffer );
-
- ElementHolder valueHolder = new ReferenceHolder( btree, null, offset, lastOffset );
- ( ( Node ) page ).setValue( nodeNbElems, valueHolder );*/
- }
+ return btreeHeader;
}
-
-
+
+
/**
- * Check a BTree
- * @throws IllegalAccessException
- * @throws InstantiationException
- * @throws ClassNotFoundException
+ * {@inheritDoc}
*/
- private long checkBTree( long[] checkedPages, PageIO[] pageIos, int pageSize, boolean isLast )
- throws EndOfFileExceededException, IOException, InstantiationException, IllegalAccessException,
- ClassNotFoundException
+ public void updateNewBTreeHeaders( BTreeHeader btreeHeader )
{
- long dataPos = 0L;
-
- // The BTree current revision
- long revision = readLong( pageIos, dataPos );
- dataPos += LONG_SIZE;
-
- // The nb elems in the tree
- long nbElems = readLong( pageIos, dataPos );
- dataPos += LONG_SIZE;
-
- // The BTree rootPage offset
- long rootPageOffset = readLong( pageIos, dataPos );
-
- if ( ( rootPageOffset < 0 ) || ( rootPageOffset > fileChannel.size() ) )
- {
- throw new InvalidBTreeException( "The rootpage is incorrect : " + rootPageOffset );
- }
-
- dataPos += LONG_SIZE;
-
- // The next BTree offset
- long nextBTreeOffset = readLong( pageIos, dataPos );
-
- if ( ( ( rootPageOffset < 0 ) && ( !isLast ) ) || ( nextBTreeOffset > fileChannel.size() ) )
- {
- throw new InvalidBTreeException( "The rootpage is incorrect : " + rootPageOffset );
- }
-
- dataPos += LONG_SIZE;
-
- // The BTree page size
- int btreePageSize = readInt( pageIos, dataPos );
-
- if ( ( btreePageSize < 2 ) || ( ( btreePageSize & ( ~btreePageSize + 1 ) ) != btreePageSize ) )
- {
- throw new InvalidBTreeException( "The BTree page size is not a power of 2 : " + btreePageSize );
- }
-
- dataPos += INT_SIZE;
-
- // The tree name
- ByteBuffer btreeNameBytes = readBytes( pageIos, dataPos );
- dataPos += INT_SIZE;
-
- dataPos += btreeNameBytes.limit();
- String btreeName = Strings.utf8ToString( btreeNameBytes );
-
- // The keySerializer FQCN
- ByteBuffer keySerializerBytes = readBytes( pageIos, dataPos );
-
- String keySerializerFqcn = null;
- dataPos += INT_SIZE;
-
- if ( keySerializerBytes != null )
- {
- dataPos += keySerializerBytes.limit();
- keySerializerFqcn = Strings.utf8ToString( keySerializerBytes );
- }
- else
- {
- keySerializerFqcn = "";
- }
-
- // The valueSerialier FQCN
- ByteBuffer valueSerializerBytes = readBytes( pageIos, dataPos );
-
- String valueSerializerFqcn = null;
- dataPos += INT_SIZE;
-
- if ( valueSerializerBytes != null )
- {
- dataPos += valueSerializerBytes.limit();
- valueSerializerFqcn = Strings.utf8ToString( valueSerializerBytes );
- }
- else
- {
- valueSerializerFqcn = "";
- }
-
- // The BTree allowDuplicates flag
- int allowDuplicates = readInt( pageIos, dataPos );
- dataPos += INT_SIZE;
-
- // Now, check the rootPage, which can be a Leaf or a Node, depending
- // on the number of elements in the tree : if it's above the pageSize,
- // it's a Node, otherwise it's a Leaf
- Class<?> valueSerializer = Class.forName( valueSerializerFqcn );
- Class<?> keySerializer = Class.forName( keySerializerFqcn );
-
- /*
- checkRoot( checkedPages, rootPageOffset, pageSize, nbElems,
- ( ElementSerializer<?> ) keySerializer.newInstance(),
- ( ElementSerializer<?> ) valueSerializer.newInstance(), allowDuplicates != 0 );
- */
-
- return nextBTreeOffset;
+ newBTreeHeaders.put( btreeHeader.getBtree().getName(), btreeHeader );
}
-
-
+
+
/**
- * Check each BTree we manage
- * @throws IOException
- * @throws EndOfFileExceededException
- * @throws ClassNotFoundException
- * @throws IllegalAccessException
- * @throws InstantiationException
+ * Swap the current BtreeHeader map with the new one. This method will only
+ * be called in a single trhead, when the current transaction will be committed.
*/
- private void checkBTrees( long[] checkedPages, int pageSize, int nbBTrees ) throws EndOfFileExceededException,
- IOException, InstantiationException, IllegalAccessException, ClassNotFoundException
+ private void swapCurrentBtreeHeaders()
{
- // Iterate on each BTree until we have exhausted all of them. The number
- // of btrees is just used to check that we have the correct number
- // of stored BTrees, as they are all linked.
- long position = HEADER_SIZE;
+ // Copy the reference to the current BtreeHeader Map
+ Map<String, BTreeHeader<?, ?>> tmp = currentBTreeHeaders;
+
+ // Get a write lock
+ btreeHeadersLock.writeLock().lock();
- for ( int i = 0; i < nbBTrees; i++ )
- {
- // Load the pageIOs containing the BTree
- PageIO[] pageIos = readPageIOs( position, Long.MAX_VALUE );
+ // Swap the new BTreeHeader Map
+ currentBTreeHeaders = newBTreeHeaders;
+
+ // And unlock
+ btreeHeadersLock.writeLock().unlock();
- // Check that they are correctly linked and not already used
- int pageNb = 0;
+ // Last, not least, clear the Map and reinject the latest revision in it
+ tmp.clear();
+ tmp.putAll( currentBTreeHeaders );
- for ( PageIO currentPageIo : pageIos )
- {
- //
- long nextPageOffset = currentPageIo.getNextPage();
-
- if ( pageNb == pageIos.length - 1 )
- {
- if ( nextPageOffset != NO_PAGE )
- {
- throw new InvalidBTreeException( "The pointer to the next page is not valid, expected NO_PAGE" );
- }
- }
- else
- {
- if ( nextPageOffset == NO_PAGE )
- {
- throw new InvalidBTreeException( "The pointer to the next page is not valid, NO_PAGE" );
- }
- }
-
- if ( ( nextPageOffset != NO_PAGE ) && ( ( nextPageOffset - HEADER_SIZE ) % pageSize != 0 ) )
- {
- throw new InvalidBTreeException( "The pointer to the next page is not valid" );
- }
-
- // Update the array of processed pages
- setCheckedPage( checkedPages, currentPageIo.getOffset(), pageSize );
- }
-
- // Now check the BTree
- long nextBTree = checkBTree( checkedPages, pageIos, pageSize, i == nbBTrees - 1 );
-
- if ( ( nextBTree == NO_PAGE ) && ( i < nbBTrees - 1 ) )
- {
- throw new InvalidBTreeException( "The pointer to the next BTree is incorrect" );
- }
-
- position = nextBTree;
- }
+ // And update the new BTreeHeader map
+ newBTreeHeaders = tmp;
}
-
-
+
+
/**
- * Check the whole file
+ * revert the new BTreeHeaders Map to the current BTreeHeader Map. This method
+ * is called when we have to rollback a transaction.
*/
- private void check()
+ private void revertBtreeHeaders()
{
- try
- {
- // First check the header
- ByteBuffer header = ByteBuffer.allocate( HEADER_SIZE );
- long fileSize = fileChannel.size();
-
- if ( fileSize < HEADER_SIZE )
- {
- throw new InvalidBTreeException( "File size too small : " + fileSize );
- }
-
- // Read the header
- fileChannel.read( header, 0L );
- header.flip();
-
- // The page size. It must be a power of 2, and above 16.
- int pageSize = header.getInt();
-
- if ( ( pageSize < 0 ) || ( pageSize < 32 ) || ( ( pageSize & ( ~pageSize + 1 ) ) != pageSize ) )
- {
- throw new InvalidBTreeException( "Wrong page size : " + pageSize );
- }
-
- // Compute the number of pages in this file
- long nbPages = ( fileSize - HEADER_SIZE ) / pageSize;
-
- // The number of trees. It must be at least 2 and > 0
- int nbBTrees = header.getInt();
-
- if ( nbBTrees < 0 )
- {
- throw new InvalidBTreeException( "Wrong nb trees : " + nbBTrees );
- }
-
- // The first free page offset. It must be either -1 or below file size
- // and its value must be a modulo of pageSize
- long firstFreePage = header.getLong();
-
- if ( firstFreePage > fileSize )
- {
- throw new InvalidBTreeException( "First free page pointing after the end of the file : "
- + firstFreePage );
- }
-
- if ( ( firstFreePage != NO_PAGE ) && ( ( ( firstFreePage - HEADER_SIZE ) % pageSize ) != 0 ) )
- {
- throw new InvalidBTreeException( "First free page not pointing to a correct offset : " + firstFreePage );
- }
-
- int nbPageBits = ( int ) ( nbPages / 64 );
-
- // Create an array of pages to be checked
- // We use one bit per page. It's 0 when the page
- // hasn't been checked, 1 otherwise.
- long[] checkedPages = new long[nbPageBits + 1];
-
- // Then the free files
- checkFreePages( checkedPages, pageSize, firstFreePage );
-
- // The BTrees
- checkBTrees( checkedPages, pageSize, nbBTrees );
- }
- catch ( Exception e )
- {
- // We catch the exception and rethrow it immediately to be able to
- // put a breakpoint here
- e.printStackTrace();
- throw new InvalidBTreeException( "Error : " + e.getMessage() );
- }
+ // Clean up teh new BTreeHeaders Map
+ newBTreeHeaders.clear();
+
+ // Reinject the latest revision in it
+ newBTreeHeaders.putAll( currentBTreeHeaders );
}
-
+
/**
- * Loads a BTree holding the values of a duplicate key
+ * Loads a B-tree holding the values of a duplicate key
* This tree is also called as dups tree or sub tree
*
- * @param offset the offset of the BTree header
- * @return the deserialized BTree
+ * @param offset the offset of the B-tree header
+ * @return the deserialized B-tree
*/
- /* No qualifier */<K, V> BTree<K, V> loadDupsBTree( long offset )
+ /* No qualifier */<K, V> BTree<V, V> loadDupsBtree( long btreeHeaderOffset, BTree<K, V> parentBtree )
{
try
{
- PageIO[] pageIos = readPageIOs( offset, Long.MAX_VALUE );
+ PageIO[] pageIos = readPageIOs( btreeHeaderOffset, Long.MAX_VALUE );
- BTree<K, V> subBtree = BTreeFactory.createPersistedBTree();
- ( ( PersistedBTree<K, V> ) subBtree ).setBtreeOffset( offset );
-
- loadBTree( pageIos, subBtree );
+ BTree<V, V> subBtree = BTreeFactory.<V, V> createPersistedBTree( BTreeTypeEnum.PERSISTED_SUB );
+ loadBtree( pageIos, subBtree, parentBtree );
+
return subBtree;
}
@@ -3069,15 +3702,6 @@
/**
- * @return the pendingPages
- */
- /* no qualifier*/ <K, V> Map<Page<?, ?>, BTree<?, ?>> getPendingPages()
- {
- return pendingPages;
- }
-
-
- /**
* @see Object#toString()
*/
public String toString()
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameComparator.java
index c0aebef..1d3e62d 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameComparator.java
@@ -30,6 +30,17 @@
*/
/* no qualifier*/class RevisionNameComparator implements Comparator<RevisionName>
{
+ /** A static instance of a RevisionNameComparator */
+ public static final RevisionNameComparator INSTANCE = new RevisionNameComparator();
+
+ /**
+ * A private constructor of the RevisionNameComparator class
+ */
+ private RevisionNameComparator()
+ {
+ }
+
+
/**
* {@inheritDoc}
*/
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameSerializer.java
index f64a419..b5920e3 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/RevisionNameSerializer.java
@@ -41,12 +41,15 @@
*/
/* no qualifier*/class RevisionNameSerializer extends AbstractElementSerializer<RevisionName>
{
+ /** A static instance of a RevisionNameSerializer */
+ /*No qualifier*/ final static RevisionNameSerializer INSTANCE = new RevisionNameSerializer();
+
/**
* Create a new instance of a RevisionNameSerializer
*/
- /* no qualifier*/RevisionNameSerializer()
+ private RevisionNameSerializer()
{
- super( new RevisionNameComparator() );
+ super( RevisionNameComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
new file mode 100644
index 0000000..aa458e7
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/TransactionManager.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree;
+
+/**
+ * An interface used to manage the transactions mechanism in B-trees. Transactions are cross
+ * B-trees.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public interface TransactionManager
+{
+ /**
+ * Starts a transaction
+ */
+ void beginTransaction();
+
+
+ /**
+ * Commits a transaction
+ */
+ void commit();
+
+
+ /**
+ * Rollback a transaction
+ */
+ void rollback();
+
+
+ /**
+ * Gets the current BtreeHeader for a given BTree.
+ *
+ * @param btreeName The Btree name we are looking the BtreeHeader for
+ * @return the current BTreeHeader
+ */
+ BTreeHeader<?, ?> getBTreeHeader( String btreeName );
+
+
+ /**
+ * Updates the map of new BTreeHeaders
+ *
+ * @param btreeHeader The new BtreeHeader
+ */
+ void updateNewBTreeHeaders( BTreeHeader<?, ?> btreeHeader );
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java
index 9462ee1..4650eb4 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/TupleCursor.java
@@ -34,7 +34,7 @@
*
* @param <K> The type for the Key
* @param <V> The type for the stored value
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class TupleCursor<K, V>
@@ -59,8 +59,16 @@
/**
+ * Creates a new instance of Cursor.
+ */
+ protected TupleCursor()
+ {
+ }
+
+
+ /**
* Creates a new instance of Cursor, starting on a page at a given position.
- *
+ *
* @param transaction The transaction this operation is protected by
* @param stack The stack of parent's from root to this page
*/
@@ -167,10 +175,10 @@
/**
* Tells if the cursor can return a next element
- *
+ *
* @return true if there are some more elements
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public boolean hasNext() throws EndOfFileExceededException, IOException
{
@@ -207,7 +215,7 @@
return true;
}
- // Ok, here, we have reached the last value in the leaf. We have to go up and
+ // Ok, here, we have reached the last value in the leaf. We have to go up and
// see if we have some remaining values
int currentDepth = depth - 1;
@@ -234,10 +242,10 @@
/**
* Find the next key/value
- *
+ *
* @return A Tuple containing the found key and value
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public Tuple<K, V> next() throws EndOfFileExceededException, IOException
{
@@ -324,7 +332,7 @@
/**
* Get the next non-duplicate key.
* If the BTree contains :
- *
+ *
* <ul>
* <li><1,0></li>
* <li><1,1></li>
@@ -332,9 +340,9 @@
* <li><2,0></li>
* <li><2,1></li>
* </ul>
- *
+ *
* and cursor is present at <1,1> then the returned tuple will be <2,0> (not <1,2>)
- *
+ *
* @return A Tuple containing the found key and value
* @throws EndOfFileExceededException
* @throws IOException
@@ -402,10 +410,10 @@
/**
* Tells if the cursor can return a next key
- *
+ *
* @return true if there are some more keys
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public boolean hasNextKey() throws EndOfFileExceededException, IOException
{
@@ -439,10 +447,10 @@
/**
* Tells if the cursor can return a previous element
- *
+ *
* @return true if there are some more elements
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public boolean hasPrev() throws EndOfFileExceededException, IOException
{
@@ -480,7 +488,7 @@
return true;
}
- // Ok, here, we have reached the first value in the leaf. We have to go up and
+ // Ok, here, we have reached the first value in the leaf. We have to go up and
// see if we have some remaining values
int currentDepth = depth - 1;
@@ -506,10 +514,10 @@
/**
* Find the previous key/value
- *
+ *
* @return A Tuple containing the found key and value
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public Tuple<K, V> prev() throws EndOfFileExceededException, IOException
{
@@ -597,7 +605,7 @@
/**
* Get the previous non-duplicate key.
* If the BTree contains :
- *
+ *
* <ul>
* <li><1,0></li>
* <li><1,1></li>
@@ -605,9 +613,9 @@
* <li><2,0></li>
* <li><2,1></li>
* </ul>
- *
+ *
* and cursor is present at <2,1> then the returned tuple will be <1,0> (not <2,0>)
- *
+ *
* @return A Tuple containing the found key and value
* @throws EndOfFileExceededException
* @throws IOException
@@ -653,7 +661,7 @@
}
}
- // Update the Tuple
+ // Update the Tuple
AbstractPage<K, V> leaf = ( AbstractPage<K, V> ) ( parentPos.page );
// The key
@@ -671,10 +679,10 @@
/**
* Tells if the cursor can return a previous key
- *
+ *
* @return true if there are some more keys
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
public boolean hasPrevKey() throws EndOfFileExceededException, IOException
{
@@ -693,25 +701,30 @@
return false;
}
- if ( parentPos.pos == 0 )
+ switch ( parentPos.pos )
{
- // Beginning of the leaf. We have to go back into the stack up to the
- // parent, and down to the leaf
- return hasPrevParentPos();
- }
- else
- {
- return true;
+ case 0 :
+ // Beginning of the leaf. We have to go back into the stack up to the
+ // parent, and down to the leaf
+ return hasPrevParentPos();
+
+ case -1 :
+ // no previous key
+ return false;
+
+ default :
+ // we have a previous key
+ return true;
}
}
/**
* Tells if there is a next ParentPos
- *
+ *
* @return the new ParentPos instance, or null if we have no following leaf
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
private boolean hasNextParentPos() throws EndOfFileExceededException, IOException
{
@@ -758,10 +771,10 @@
/**
* Find the leaf containing the following elements.
- *
+ *
* @return the new ParentPos instance, or null if we have no following leaf
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
private ParentPos<K, V> findNextParentPos() throws EndOfFileExceededException, IOException
{
@@ -818,10 +831,10 @@
/**
* Find the leaf containing the previous elements.
- *
+ *
* @return the new ParentPos instance, or null if we have no previous leaf
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
private ParentPos<K, V> findPrevParentPos() throws EndOfFileExceededException, IOException
{
@@ -880,10 +893,10 @@
/**
* Tells if there is a prev ParentPos
- *
+ *
* @return the new ParentPos instance, or null if we have no previous leaf
- * @throws IOException
- * @throws EndOfFileExceededException
+ * @throws IOException
+ * @throws EndOfFileExceededException
*/
private boolean hasPrevParentPos() throws EndOfFileExceededException, IOException
{
@@ -949,7 +962,7 @@
/**
* Get the current revision
- *
+ *
* @return The revision this cursor is based on
*/
public long getRevision()
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueBTreeCursor.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueBTreeCursor.java
index f9ba802..ba1e0e6 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueBTreeCursor.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/ValueBTreeCursor.java
@@ -23,6 +23,7 @@
import java.io.IOException;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.BTree;
@@ -60,6 +61,11 @@
// TODO Auto-generated catch block
e.printStackTrace();
}
+ catch ( KeyNotFoundException knfe )
+ {
+ // TODO Auto-generated catch block
+ knfe.printStackTrace();
+ }
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/WriteTransaction.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/WriteTransaction.java
index 752c3d0..b6f9b68 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/WriteTransaction.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/WriteTransaction.java
@@ -19,8 +19,6 @@
*/
package org.apache.directory.mavibot.btree;
-import java.io.IOException;
-import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.directory.mavibot.btree.exception.BadTransactionStateException;
@@ -32,28 +30,29 @@
*/
/* no qualifier */ class WriteTransaction
{
- /** The recordManager on which this transaction is applied */
- private RecordManager recordManager;
-
/** A lock used to protect the write operation against concurrent access */
protected ReentrantLock writeLock;
- /* no qualifier */WriteTransaction( RecordManager recordManager )
+ /* no qualifier */WriteTransaction()
{
- System.out.println( "Creating the transaction oject" );
- this.recordManager = recordManager;
+ //System.out.println( "Creating the transaction oject" );
writeLock = new ReentrantLock();
}
/* no qualifier */ void start()
{
+ /*
if ( writeLock.isLocked() )
{
throw new BadTransactionStateException( "Cannot start a write transaction when it's already started" );
}
+ */
+
+ //System.out.println( "Start a TXN [" + Thread.currentThread().getName() + "]" );
writeLock.lock();
+ //System.out.println( "WriteTransaction " + Thread.currentThread().getName() );
}
@@ -64,37 +63,7 @@
throw new BadTransactionStateException( "Cannot commit a write transaction when it's not started" );
}
- Map<?, ?> pendingPages = recordManager.getPendingPages();
-
- for ( Object object : pendingPages.keySet() )
- {
- BTree btree = (BTree)pendingPages.get( object );
-
- try
- {
- recordManager.writePage( btree, (Page)object, ((Page)object).getRevision() );
- }
- catch ( IOException e )
- {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- /*
- recordManager.updateRecordManagerHeader();
-
- // Update the BTree header now
- recordManager.updateBtreeHeader( btree, ( ( AbstractPage<K, V> ) rootPage ).getOffset() );
-
- // Moved the free pages into the list of free pages
- recordManager.addFreePages( this, result.getCopiedPages() );
-
- // Store the created rootPage into the revision BTree, this will be stored in RecordManager only if revisions are set to keep
- recordManager.storeRootPage( this, rootPage );
- */
-
- pendingPages.clear();
+ //System.out.println( "Commit a TXN[" + Thread.currentThread().getName() + "]" );
writeLock.unlock();
}
@@ -107,6 +76,7 @@
throw new BadTransactionStateException( "Cannot commit a write transaction when it's not started" );
}
+ //System.out.println( "Rollback a TXN" );
writeLock.unlock();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparator.java
index 2e044dd..7c052a5 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -26,14 +26,25 @@
/**
* Compares boolean arrays. A boolean is considered as below the other one if the first boolean
* is false when the second one is true.
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BooleanArrayComparator implements Comparator<boolean[]>
{
+ /** A static instance of a BooleanArrayComparator */
+ public static final BooleanArrayComparator INSTANCE = new BooleanArrayComparator();
+
+ /**
+ * A private constructor of the BooleanArrayComparator class
+ */
+ private BooleanArrayComparator()
+ {
+ }
+
+
/**
* Compare two boolean arrays.
- *
+ *
* @param booleanArray1 First boolean array
* @param booleanArray2 Second boolean array
* @return 1 if booleanArray1 > booleanArray2, 0 if booleanArray1 == booleanArray2, -1 if booleanArray1 < booleanArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanComparator.java
index 4d29875..4ffbb88 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/BooleanComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares booleans
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BooleanComparator implements Comparator<Boolean>
{
+ /** A static instance of a BooleanComparator */
+ public static final BooleanComparator INSTANCE = new BooleanComparator();
+
+ /**
+ * A private constructor of the BooleanComparator class
+ */
+ private BooleanComparator()
+ {
+ }
+
+
/**
* Compare two booleans.
- *
+ *
* @param boolean1 First boolean
* @param boolean2 Second boolean
* @return 1 if boolean1 > boolean2, 0 if boolean1 == boolean2, -1 if boolean1 < boolean2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparator.java
index 8fac153..0b74659 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares byte arrays.
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteArrayComparator implements Comparator<byte[]>
{
+ /** A static instance of a ByteArrayComparator */
+ public static final ByteArrayComparator INSTANCE = new ByteArrayComparator();
+
+ /**
+ * A private constructor of the ByteArrayComparator class
+ */
+ private ByteArrayComparator()
+ {
+ }
+
+
/**
* Compare two byte arrays.
- *
+ *
* @param byteArray1 First byteArray
* @param byteArray2 Second byteArray
* @return 1 if byteArray1 > byteArray2, 0 if byteArray1 == byteArray2, -1 if byteArray1 < byteArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteComparator.java
index 291517d..e6f673d 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ByteComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares bytes
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteComparator implements Comparator<Byte>
{
+ /** A static instance of a ByteComparator */
+ public static final ByteComparator INSTANCE = new ByteComparator();
+
+ /**
+ * A private constructor of the ByteComparator class
+ */
+ private ByteComparator()
+ {
+ }
+
+
/**
* Compare two bytes.
- *
+ *
* @param byte1 First byte
* @param byte2 Second byte
* @return 1 if byte1 > byte2, 0 if byte1 == byte2, -1 if byte1 < byte2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparator.java
index ce79319..5f1a847 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares char arrays
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CharArrayComparator implements Comparator<char[]>
{
+ /** A static instance of a CharArrayComparator */
+ public static final CharArrayComparator INSTANCE = new CharArrayComparator();
+
+ /**
+ * A private constructor of the CharArrayComparator class
+ */
+ private CharArrayComparator()
+ {
+ }
+
+
/**
* Compare two char arrays.
- *
+ *
* @param charArray1 First char array
* @param charArray2 Second char array
* @return 1 if charArray1 > charArray2, 0 if charArray1 == charArray2, -1 if charArray1 < charArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharComparator.java
index ba3acfd..9c4302b 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/CharComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares chars
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CharComparator implements Comparator<Character>
{
+ /** A static instance of a CharComparator */
+ public static final CharComparator INSTANCE = new CharComparator();
+
+ /**
+ * A private constructor of the CharComparator class
+ */
+ private CharComparator()
+ {
+ }
+
+
/**
* Compare two chars.
- *
+ *
* @param char1 First char
* @param char2 Second char
* @return 1 if char1 > char2, 0 if char1 == char2, -1 if char1 < char2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparator.java
index 39c9068..7253b97 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares int arrays
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class IntArrayComparator implements Comparator<int[]>
{
+ /** A static instance of a IntArrayComparator */
+ public static final IntArrayComparator INSTANCE = new IntArrayComparator();
+
+ /**
+ * A private constructor of the IntArrayComparator class
+ */
+ private IntArrayComparator()
+ {
+ }
+
+
/**
* Compare two long arrays.
- *
+ *
* @param intArray1 First int array
* @param intArray2 Second int array
* @return 1 if intArray1 > intArray2, 0 if intArray1 == intArray2, -1 if intArray1 < intArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntComparator.java
index aece0cc..8c6b38a 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/IntComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares integers
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class IntComparator implements Comparator<Integer>
{
+ /** A static instance of a IntComparator */
+ public static final IntComparator INSTANCE = new IntComparator();
+
+ /**
+ * A private constructor of the IntComparator class
+ */
+ private IntComparator()
+ {
+ }
+
+
/**
* Compare two integers.
- *
+ *
* @param integer1 First integer
* @param integer2 Second integer
* @return 1 if integer1 > integer2, 0 if integer1 == integer2, -1 if integer1 < integer2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparator.java
index 80c54be..80f681c 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares long arrays
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongArrayComparator implements Comparator<long[]>
{
+ /** A static instance of a LongArrayComparator */
+ public static final LongArrayComparator INSTANCE = new LongArrayComparator();
+
+ /**
+ * A private constructor of the LongArrayComparator class
+ */
+ private LongArrayComparator()
+ {
+ }
+
+
/**
* Compare two long arrays.
- *
+ *
* @param longArray1 First long array
* @param longArray2 Second long array
* @return 1 if longArray1 > longArray2, 0 if longArray1 == longArray2, -1 if longArray1 < longArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongComparator.java
index 22ceb3b..53bf82b 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/LongComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,23 @@
/**
* Compares Longs
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongComparator implements Comparator<Long>
{
+ /** A static instance of a LongComparator */
+ public static final LongComparator INSTANCE = new LongComparator();
+
+ /**
+ * A private constructor of the BooleanArrayComparator class
+ */
+ private LongComparator()
+ {
+ }
/**
* Compare two longs.
- *
+ *
* @param long1 First long
* @param long2 Second long
* @return 1 if long1 > long2, 0 if long1 == long2, -1 if long1 < long2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparator.java
index da500ad..dea7430 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares short arrays
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ShortArrayComparator implements Comparator<short[]>
{
+ /** A static instance of a ShortArrayComparator */
+ public static final ShortArrayComparator INSTANCE = new ShortArrayComparator();
+
+ /**
+ * A private constructor of the ShortArrayComparator class
+ */
+ private ShortArrayComparator()
+ {
+ }
+
+
/**
* Compare two short arrays.
- *
+ *
* @param shortArray1 First short array
* @param shortArray2 Second short array
* @return 1 if shortArray1 > shortArray2, 0 if shortArray1 == shortArray2, -1 if shortArray1 < shortArray2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortComparator.java
index 246782e..117209a 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/ShortComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares shorts
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ShortComparator implements Comparator<Short>
{
+ /** A static instance of a ShortComparator */
+ public static final ShortComparator INSTANCE = new ShortComparator();
+
+ /**
+ * A private constructor of the ShortComparator class
+ */
+ private ShortComparator()
+ {
+ }
+
+
/**
* Compare two shorts.
- *
+ *
* @param short1 First short
* @param short2 Second short
* @return 1 if short1 > short2, 0 if short1 == short2, -1 if short1 < short2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/StringComparator.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/StringComparator.java
index 512061a..0bd5bc9 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/StringComparator.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/comparator/StringComparator.java
@@ -6,16 +6,16 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
package org.apache.directory.mavibot.btree.comparator;
@@ -25,14 +25,25 @@
/**
* Compares Strings
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class StringComparator implements Comparator<String>
{
+ /** A static instance of a StringComparator */
+ public static final StringComparator INSTANCE = new StringComparator();
+
+ /**
+ * A private constructor of the StringComparator class
+ */
+ private StringComparator()
+ {
+ }
+
+
/**
* Compare two Strings.
- *
+ *
* @param string1 First String
* @param string2 Second String
* @return 1 if string1 > String2, 0 if string1 == String2, -1 if string1 < String2
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/FileException.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/FileException.java
new file mode 100644
index 0000000..320a994
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/FileException.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree.exception;
+
+
+/**
+ * An exception thrown when there is a problem writing data on disk
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class FileException extends RuntimeException
+{
+ /** The serial version UUID */
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * Creates a new instance of FileException.
+ */
+ public FileException()
+ {
+ }
+
+
+ /**
+ * Creates a new instance of FileException.
+ *
+ * @param explanation The message associated with the exception
+ */
+ public FileException( String explanation )
+ {
+ super( explanation );
+ }
+
+
+ /**
+ * Creates a new instance of FileException.
+ */
+ public FileException( Throwable cause )
+ {
+ super( cause );
+ }
+
+
+ /**
+ * Creates a new instance of FileException.
+ *
+ * @param explanation The message associated with the exception
+ * @param cause The root cause for this exception
+ */
+ public FileException( String explanation, Throwable cause )
+ {
+ super( explanation, cause );
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/InvalidOffsetException.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/InvalidOffsetException.java
new file mode 100644
index 0000000..c5658c6
--- /dev/null
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/InvalidOffsetException.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree.exception;
+
+
+/**
+ * An exception thrown when the offset is incorrect
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class InvalidOffsetException extends RuntimeException
+{
+ /** The serial version UUID */
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * Creates a new instance of InvalidOffsetException.
+ */
+ public InvalidOffsetException()
+ {
+ }
+
+
+ /**
+ * Creates a new instance of InvalidOffsetException.
+ *
+ * @param explanation The message associated with the exception
+ */
+ public InvalidOffsetException( String explanation )
+ {
+ super( explanation );
+ }
+
+
+ /**
+ * Creates a new instance of InvalidOffsetException.
+ */
+ public InvalidOffsetException( Throwable cause )
+ {
+ super( cause );
+ }
+
+
+ /**
+ * Creates a new instance of BTreeCreationException.
+ *
+ * @param explanation The message associated with the exception
+ * @param cause The root cause for this exception
+ */
+ public InvalidOffsetException( String explanation, Throwable cause )
+ {
+ super( explanation, cause );
+ }
+}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/KeyNotFoundException.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/KeyNotFoundException.java
index c3c2f1d..d2fcf03 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/KeyNotFoundException.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/exception/KeyNotFoundException.java
@@ -29,6 +29,10 @@
{
/** The serial version UUID */
private static final long serialVersionUID = 1L;
+
+ /** A static Exception used to avoid creating a new one every time */
+ public static final KeyNotFoundException INSTANCE = new KeyNotFoundException(
+ "Cannot find an entry associated with this key" );
/**
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/AbstractElementSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/AbstractElementSerializer.java
index e525f9c..894f077 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/AbstractElementSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/AbstractElementSerializer.java
@@ -29,7 +29,7 @@
/**
* An abstract ElementSerializer that implements comon methods
- *
+ *
* @param <T> The type for the element to serialize and compare
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializer.java
index c96d95c..6abdc33 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializer.java
@@ -34,12 +34,15 @@
*/
public class BooleanSerializer extends AbstractElementSerializer<Boolean>
{
+ /** A static instance of a BooleanSerializer */
+ public static final BooleanSerializer INSTANCE = new BooleanSerializer();
+
/**
* Create a new instance of BooleanSerializer
*/
- public BooleanSerializer()
+ private BooleanSerializer()
{
- super( new BooleanComparator() );
+ super( BooleanComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializer.java
index 20512bd..cd78e7f 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializer.java
@@ -35,12 +35,15 @@
*/
public class ByteArraySerializer extends AbstractElementSerializer<byte[]>
{
+ /** A static instance of a BytearraySerializer */
+ public static final ByteArraySerializer INSTANCE = new ByteArraySerializer();
+
/**
* Create a new instance of ByteArraySerializer
*/
- public ByteArraySerializer()
+ private ByteArraySerializer()
{
- super( new ByteArrayComparator() );
+ super( ByteArrayComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteSerializer.java
index cbea0f0..425dc38 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ByteSerializer.java
@@ -34,12 +34,15 @@
*/
public class ByteSerializer extends AbstractElementSerializer<Byte>
{
+ /** A static instance of a ByteSerializer */
+ public static final ByteSerializer INSTANCE = new ByteSerializer();
+
/**
* Create a new instance of ByteSerializer
*/
- public ByteSerializer()
+ private ByteSerializer()
{
- super( new ByteComparator() );
+ super( ByteComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharArraySerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharArraySerializer.java
index 642a9ee..0b54569 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharArraySerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharArraySerializer.java
@@ -34,12 +34,15 @@
*/
public class CharArraySerializer extends AbstractElementSerializer<char[]>
{
+ /** A static instance of a CharArraySerializer */
+ public static final CharArraySerializer INSTANCE = new CharArraySerializer();
+
/**
* Create a new instance of CharArraySerializer
*/
- public CharArraySerializer()
+ private CharArraySerializer()
{
- super( new CharArrayComparator() );
+ super( CharArrayComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharSerializer.java
index c1c45d9..6e443a9 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/CharSerializer.java
@@ -34,12 +34,15 @@
*/
public class CharSerializer extends AbstractElementSerializer<Character>
{
+ /** A static instance of a CharSerializer */
+ public static final CharSerializer INSTANCE = new CharSerializer();
+
/**
* Create a new instance of CharSerializer
*/
- public CharSerializer()
+ private CharSerializer()
{
- super( new CharComparator() );
+ super( CharComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/IntSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/IntSerializer.java
index 251d9bd..b2a6ea2 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/IntSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/IntSerializer.java
@@ -34,12 +34,15 @@
*/
public class IntSerializer extends AbstractElementSerializer<Integer>
{
+ /** A static instance of a IntSerializer */
+ public static final IntSerializer INSTANCE = new IntSerializer();
+
/**
* Create a new instance of IntSerializer
*/
- public IntSerializer()
+ private IntSerializer()
{
- super( new IntComparator() );
+ super( IntComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializer.java
index 2cd1f9b..4e32b36 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializer.java
@@ -28,17 +28,20 @@
/**
* A serializer for a Long[].
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongArraySerializer extends AbstractElementSerializer<long[]>
{
+ /** A static instance of a LongArraySerializer */
+ public static final LongArraySerializer INSTANCE = new LongArraySerializer();
+
/**
* Create a new instance of LongSerializer
*/
- public LongArraySerializer()
+ private LongArraySerializer()
{
- super( new LongArrayComparator() );
+ super( LongArrayComparator.INSTANCE );
}
@@ -55,32 +58,35 @@
}
byte[] bytes = null;
+ int pos = 0;
switch ( len )
{
case 0:
bytes = new byte[4];
- bytes[0] = 0x00;
- bytes[1] = 0x00;
- bytes[2] = 0x00;
- bytes[3] = 0x00;
+ // The number of Long. Here, 0
+ bytes[pos++] = 0x00;
+ bytes[pos++] = 0x00;
+ bytes[pos++] = 0x00;
+ bytes[pos++] = 0x00;
break;
case -1:
bytes = new byte[4];
- bytes[0] = ( byte ) 0xFF;
- bytes[1] = ( byte ) 0xFF;
- bytes[2] = ( byte ) 0xFF;
- bytes[3] = ( byte ) 0xFF;
+ // The number of Long. Here, null
+ bytes[pos++] = ( byte ) 0xFF;
+ bytes[pos++] = ( byte ) 0xFF;
+ bytes[pos++] = ( byte ) 0xFF;
+ bytes[pos++] = ( byte ) 0xFF;
break;
default:
- bytes = new byte[len * 8 + 4];
- int pos = 0;
+ int dataLen = len * 8 + 4;
+ bytes = new byte[dataLen];
// The number of longs
bytes[pos++] = ( byte ) ( len >>> 24 );
@@ -111,11 +117,17 @@
*/
public long[] deserialize( BufferHandler bufferHandler ) throws IOException
{
+ // Read the DataLength first. Note that we don't use it here.
byte[] in = bufferHandler.read( 4 );
- int len = IntSerializer.deserialize( in );
+ IntSerializer.deserialize( in );
- switch ( len )
+ // Now, read the number of Longs
+ in = bufferHandler.read( 4 );
+
+ int nbLongs = IntSerializer.deserialize( in );
+
+ switch ( nbLongs )
{
case 0:
return new long[]
@@ -125,11 +137,12 @@
return null;
default:
- long[] longs = new long[len];
+ long[] longs = new long[nbLongs];
+ in = bufferHandler.read( nbLongs * 8 );
- int pos = 4;
+ int pos = 0;
- for ( int i = 0; i < len; i++ )
+ for ( int i = 0; i < nbLongs; i++ )
{
longs[i] = ( ( long ) in[pos++] << 56 ) +
( ( in[pos++] & 0xFFL ) << 48 ) +
@@ -151,9 +164,13 @@
*/
public long[] deserialize( ByteBuffer buffer ) throws IOException
{
- int len = buffer.getInt();
+ // Read the dataLength. Note that we don't use it here.
+ buffer.getInt();
+
+ // The number of longs
+ int nbLongs = buffer.getInt();
- switch ( len )
+ switch ( nbLongs )
{
case 0:
return new long[]
@@ -163,9 +180,9 @@
return null;
default:
- long[] longs = new long[len];
+ long[] longs = new long[nbLongs];
- for ( int i = 0; i < len; i++ )
+ for ( int i = 0; i < nbLongs; i++ )
{
longs[i] = buffer.getLong();
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongSerializer.java
index ae9bf45..1fedd7a 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/LongSerializer.java
@@ -34,12 +34,15 @@
*/
public class LongSerializer extends AbstractElementSerializer<Long>
{
+ /** A static instance of a LongSerializer */
+ public final static LongSerializer INSTANCE = new LongSerializer();
+
/**
* Create a new instance of LongSerializer
*/
- public LongSerializer()
+ private LongSerializer()
{
- super( new LongComparator() );
+ super( LongComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ShortSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ShortSerializer.java
index f367f31..2f34103 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ShortSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/ShortSerializer.java
@@ -34,12 +34,15 @@
*/
public class ShortSerializer extends AbstractElementSerializer<Short>
{
+ /** A static instance of a ShortSerializer */
+ public final static ShortSerializer INSTANCE = new ShortSerializer();
+
/**
* Create a new instance of ShortSerializer
*/
- public ShortSerializer()
+ private ShortSerializer()
{
- super( new ShortComparator() );
+ super( ShortComparator.INSTANCE );
}
diff --git a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/StringSerializer.java b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/StringSerializer.java
index f7648c5..1e20f4b 100644
--- a/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/StringSerializer.java
+++ b/mavibot/src/main/java/org/apache/directory/mavibot/btree/serializer/StringSerializer.java
@@ -37,15 +37,15 @@
*/
public class StringSerializer extends AbstractElementSerializer<String>
{
+ /** A static instance of a StringSerializer */
public static final StringSerializer INSTANCE = new StringSerializer();
-
/**
* Create a new instance of StringSerializer
*/
- public StringSerializer()
+ private StringSerializer()
{
- super( new StringComparator() );
+ super( StringComparator.INSTANCE );
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeBuilderTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeBuilderTest.java
index b3e90b8..e4e8d22 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeBuilderTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeBuilderTest.java
@@ -27,10 +27,7 @@
import java.util.ArrayList;
import java.util.List;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.InMemoryBTreeBuilder;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.junit.Test;
@@ -43,7 +40,7 @@
public class InMemoryBTreeBuilderTest
{
@Test
- public void testIntegerTree() throws IOException
+ public void testIntegerTree() throws IOException, KeyNotFoundException
{
List<Tuple<Integer, Integer>> sortedTuple = new ArrayList<Tuple<Integer, Integer>>();
@@ -53,7 +50,7 @@
sortedTuple.add( t );
}
- IntSerializer ser = new IntSerializer();
+ IntSerializer ser = IntSerializer.INSTANCE;
InMemoryBTreeBuilder<Integer, Integer> bb = new InMemoryBTreeBuilder<Integer, Integer>( "master", 4, ser, ser );
// contains 1, 2, 3, 4, 5, 6, 7
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeConfigurationTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeConfigurationTest.java
index 56fb253..2d48b38 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeConfigurationTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeConfigurationTest.java
@@ -25,8 +25,6 @@
import java.io.File;
import java.io.IOException;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.InMemoryBTree;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
@@ -37,7 +35,7 @@
/**
* Test the creation of a BTree with a configuration.
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class InMemoryBTreeConfigurationTest
@@ -123,7 +121,7 @@
InMemoryBTreeConfiguration<Integer, String> config = new InMemoryBTreeConfiguration<Integer, String>();
config.setName( "basic" );
config.setPageSize( 32 );
- config.setSerializers( new IntSerializer(), new StringSerializer() );
+ config.setSerializers( IntSerializer.INSTANCE, StringSerializer.INSTANCE );
try
{
@@ -170,7 +168,7 @@
/**
- * Test the creation of a BTree using the BTreeConfiguration, flushing the
+ * Test the creation of a BTree using the BTreeConfiguration, flushing the
* tree on disk, then reloading it in another BTree.
*/
@Test
@@ -184,7 +182,7 @@
{
InMemoryBTreeConfiguration<Integer, String> config = new InMemoryBTreeConfiguration<Integer, String>();
config.setPageSize( 32 );
- config.setSerializers( new IntSerializer(), new StringSerializer() );
+ config.setSerializers( IntSerializer.INSTANCE, StringSerializer.INSTANCE );
config.setFilePath( parent );
config.setName( "mavibot" );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeDuplicateKeyTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeDuplicateKeyTest.java
index 8da7604..68b7a88 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeDuplicateKeyTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeDuplicateKeyTest.java
@@ -33,6 +33,7 @@
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.DuplicateValueNotAllowedException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
@@ -47,9 +48,9 @@
public class InMemoryBTreeDuplicateKeyTest
{
@Test
- public void testInsertNullValue() throws IOException
+ public void testInsertNullValue() throws IOException, KeyNotFoundException
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
BTree<Integer, Integer> btree = BTreeFactory.createInMemoryBTree( "master", serializer, serializer );
@@ -69,9 +70,9 @@
@Test
- public void testBrowseEmptyTree() throws IOException
+ public void testBrowseEmptyTree() throws IOException, KeyNotFoundException
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
BTree<Integer, Integer> btree = BTreeFactory.createInMemoryBTree( "master", serializer, serializer );
@@ -105,9 +106,9 @@
@Test
- public void testDuplicateKey() throws IOException
+ public void testDuplicateKey() throws IOException, KeyNotFoundException
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -163,7 +164,7 @@
@Test
public void testGetDuplicateKey() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -199,7 +200,7 @@
@Test
public void testRemoveDuplicateKey() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -235,7 +236,7 @@
@Test
public void testFullPage() throws Exception
{
- StringSerializer serializer = new StringSerializer();
+ StringSerializer serializer = StringSerializer.INSTANCE;
InMemoryBTreeConfiguration<String, String> config = new InMemoryBTreeConfiguration<String, String>();
config.setAllowDuplicates( true );
@@ -298,7 +299,7 @@
@Test
public void testMoveFirst() throws Exception
{
- StringSerializer serializer = new StringSerializer();
+ StringSerializer serializer = StringSerializer.INSTANCE;
InMemoryBTreeConfiguration<String, String> config = new InMemoryBTreeConfiguration<String, String>();
config.setAllowDuplicates( true );
@@ -387,7 +388,7 @@
@Test(expected = NoSuchElementException.class)
public void testMoveLast() throws Exception
{
- StringSerializer serializer = new StringSerializer();
+ StringSerializer serializer = StringSerializer.INSTANCE;
InMemoryBTreeConfiguration<String, String> config = new InMemoryBTreeConfiguration<String, String>();
config.setAllowDuplicates( true );
@@ -433,7 +434,7 @@
@Test(expected = NoSuchElementException.class)
public void testNextPrevKey() throws Exception
{
- StringSerializer serializer = new StringSerializer();
+ StringSerializer serializer = StringSerializer.INSTANCE;
InMemoryBTreeConfiguration<String, String> config = new InMemoryBTreeConfiguration<String, String>();
config.setAllowDuplicates( true );
@@ -546,7 +547,7 @@
@Test
public void testMoveToNextAndPrevWithPageBoundaries() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -621,7 +622,7 @@
@Test
public void testNextAfterPrev() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -667,7 +668,7 @@
@Test
public void testMoveToNextAndTraverseBackward() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -706,7 +707,7 @@
@Test
public void testMoveToPrevAndTraverseForward() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setAllowDuplicates( true );
@@ -744,8 +745,8 @@
@Test(expected = DuplicateValueNotAllowedException.class)
public void testBTreeForbidDups() throws IOException, BTreeAlreadyManagedException
{
- BTree<Long, String> singleValueBtree = BTreeFactory.createInMemoryBTree( "test2", new LongSerializer(),
- new StringSerializer(), BTree.FORBID_DUPLICATES );
+ BTree<Long, String> singleValueBtree = BTreeFactory.createInMemoryBTree( "test2", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE, BTree.FORBID_DUPLICATES );
for ( long i = 0; i < 64; i++ )
{
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeFlushTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeFlushTest.java
index 5ffcc2a..7946378 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeFlushTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeFlushTest.java
@@ -29,10 +29,6 @@
import java.util.Random;
import java.util.Set;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.InMemoryBTree;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
@@ -44,7 +40,7 @@
/**
* A unit test class for BTree flush() operation
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class InMemoryBTreeFlushTest
@@ -132,8 +128,8 @@
long delta = l1;
int nbElems = 100000;
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 32 );
for ( int i = 0; i < nbElems; i++ )
@@ -224,8 +220,8 @@
// Create a BTree with pages containing 8 elements
String path = tempFolder.getRoot().getCanonicalPath();
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", path, new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", path, IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
File journal = ( ( InMemoryBTree<Integer, String> ) btree ).getJournal();
@@ -251,8 +247,8 @@
assertEquals( 0, journal.length() );
// Load the data into a new tree
- BTree<Integer, String> btreeLoaded = BTreeFactory.createInMemoryBTree( "test", path, new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btreeLoaded = BTreeFactory.createInMemoryBTree( "test", path, IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
TupleCursor<Integer, String> cursor1 = btree.browse();
@@ -294,8 +290,8 @@
BTree<Long, String> btree = BTreeFactory.createInMemoryBTree(
"test",
dataFile.getParent(),
- new LongSerializer(),
- new StringSerializer() );
+ LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 32 );
btree.close();
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTest.java
index 5cb2a81..f32cebf 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTest.java
@@ -168,8 +168,8 @@
for ( int j = 0; j < nbTrees; j++ )
{
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 32 );
for ( int i = 0; i < nbElems; i++ )
@@ -271,8 +271,8 @@
for ( int j = 0; j < nbTrees; j++ )
{
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
for ( int i = 0; i < nbElems; i++ )
@@ -387,8 +387,8 @@
368, 245, 1005, 226, 939, 320, 396, 437, 373, 61
};
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
for ( long value : values )
@@ -447,8 +447,8 @@
Random random = new Random( System.nanoTime() );
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
// Insert some values
@@ -508,8 +508,8 @@
@Ignore("This is a debug test")
public void testPageInsertDebug() throws Exception
{
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 4 );
Long[] elems = new Long[]
@@ -615,8 +615,8 @@
public void testBrowseForward() throws Exception
{
// Create a BTree with pages containing 8 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
// Inject the values
@@ -700,8 +700,8 @@
public void testBrowseBackward() throws Exception
{
// Create a BTree with pages containing 8 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
// Inject the values
@@ -776,8 +776,8 @@
public void testBrowseEmptyTree() throws Exception
{
// Create a BTree with pages containing 8 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
TupleCursor<Integer, String> cursor = btree.browse();
@@ -797,8 +797,8 @@
public void testBrowseForwardBackward() throws Exception
{
// Create a BTree with pages containing 4 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( int i = 0; i < 16; i++ )
@@ -911,7 +911,7 @@
* Test the exist() method
*/
@Test
- public void testExist() throws IOException
+ public void testExist() throws IOException, KeyNotFoundException
{
// Create a BTree with pages containing 4 elements
BTree<Integer, String> btree = createTwoLevelBTreeFullLeaves();
@@ -1026,8 +1026,8 @@
public void testBrowseNonExistingKey() throws Exception
{
// Create a BTree with pages containing 8 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 8 );
for ( int i = 0; i < 11; i++ )
{
@@ -1091,8 +1091,8 @@
*/
private BTree<Integer, String> createTwoLevelBTreeFullLeaves() throws IOException
{
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 4 );
// Create a tree with 5 children containing 4 elements each. The tree is full.
@@ -1114,8 +1114,8 @@
*/
private BTree<Integer, String> createTwoLevelBTreeHalfFullLeaves() throws IOException
{
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 4 );
// Create a tree with 5 children containing 4 elements each. The tree is full.
@@ -1146,8 +1146,8 @@
// Create a BTree with pages containing 4 elements
int pageSize = 4;
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer(),
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE,
pageSize );
InMemoryNode<Integer, String> root = new InMemoryNode<Integer, String>( btree, 1L, pageSize );
@@ -1193,7 +1193,7 @@
* @param element The removed element
* @param expected The expected set of elements
*/
- private void checkRemoval( BTree<Integer, String> btree, int element, Set<Integer> expected ) throws IOException
+ private void checkRemoval( BTree<Integer, String> btree, int element, Set<Integer> expected ) throws IOException, KeyNotFoundException
{
Tuple<Integer, String> removed = btree.delete( element );
assertEquals( element, removed.getKey().intValue() );
@@ -1213,7 +1213,7 @@
* @param btree The tree to check
* @param expected The set with the expected elements
*/
- private void checkTree( BTree<Integer, String> btree, Set<Integer> expected )
+ private void checkTree( BTree<Integer, String> btree, Set<Integer> expected ) throws KeyNotFoundException
{
try
{
@@ -1723,7 +1723,7 @@
* Test the addition of elements with null values
*/
@Test
- public void testAdditionNullValues() throws IOException
+ public void testAdditionNullValues() throws IOException, KeyNotFoundException
{
BTree<Integer, String> btree = createMultiLevelBTreeLeavesHalfFull();
@@ -1766,8 +1766,8 @@
long delta = System.currentTimeMillis();
// Create a BTree with 5 million entries
- BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(),
- new StringSerializer() );
+ BTree<Long, String> btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 32 );
for ( int i = 0; i < nbElems; i++ )
@@ -1869,8 +1869,8 @@
public void testBrowseForwardBackwardExtremes() throws Exception
{
// Create a BTree with pages containing 4 elements
- BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", new IntSerializer(),
- new StringSerializer() );
+ BTree<Integer, String> btree = BTreeFactory.createInMemoryBTree( "test", IntSerializer.INSTANCE,
+ StringSerializer.INSTANCE );
btree.setPageSize( 4 );
for ( int i = 8; i < 13; i++ )
@@ -1925,7 +1925,7 @@
@Test
public void testNextAfterPrev() throws Exception
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
InMemoryBTreeConfiguration<Integer, Integer> config = new InMemoryBTreeConfiguration<Integer, Integer>();
config.setName( "master" );
@@ -1965,7 +1965,7 @@
@Test
public void testCheckRootPageContents() throws Exception
{
- IntSerializer ser = new IntSerializer();
+ IntSerializer ser = IntSerializer.INSTANCE;
BTree<Integer, Integer> btree = BTreeFactory.createInMemoryBTree( "master1", ser, ser, 4 );
for ( int i = 1; i < 8; i++ )
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTestOps.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTestOps.java
index 33235c6..c887c71 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTestOps.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryBTreeTestOps.java
@@ -23,7 +23,6 @@
import java.io.IOException;
import java.util.Random;
-import org.apache.directory.mavibot.btree.BTree;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.AfterClass;
@@ -33,7 +32,7 @@
/**
* A class to test multi-threaded operations on the btree
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class InMemoryBTreeTestOps
@@ -49,7 +48,7 @@
@BeforeClass
public static void setup() throws IOException
{
- btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(), new StringSerializer() );
+ btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE );
}
@@ -71,7 +70,7 @@
{
Random random = new Random( System.nanoTime() );
- int nbElems = 500000;
+ int nbElems = 50000;
// Create a BTree with 500 000 entries
btree.setPageSize( 32 );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryLeafTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryLeafTest.java
index d5deaec..2f6786e 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryLeafTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/InMemoryLeafTest.java
@@ -26,18 +26,6 @@
import java.io.IOException;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.BorrowedFromLeftResult;
-import org.apache.directory.mavibot.btree.BorrowedFromRightResult;
-import org.apache.directory.mavibot.btree.DeleteResult;
-import org.apache.directory.mavibot.btree.InsertResult;
-import org.apache.directory.mavibot.btree.KeyHolder;
-import org.apache.directory.mavibot.btree.MergedWithSiblingResult;
-import org.apache.directory.mavibot.btree.NotPresentResult;
-import org.apache.directory.mavibot.btree.Page;
-import org.apache.directory.mavibot.btree.PageHolder;
-import org.apache.directory.mavibot.btree.RemoveResult;
-import org.apache.directory.mavibot.btree.Tuple;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
@@ -48,7 +36,7 @@
/**
* A unit test class for Leaf
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class InMemoryLeafTest
@@ -62,7 +50,7 @@
@Before
public void setup() throws IOException
{
- btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(), new StringSerializer() );
+ btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE );
btree.setPageSize( 8 );
}
@@ -76,12 +64,12 @@
/**
* A helper method to insert elements in a Leaf
- * @throws IOException
+ * @throws IOException
*/
private InMemoryLeaf<Long, String> insert( InMemoryLeaf<Long, String> leaf, long key, String value )
throws IOException
{
- InsertResult<Long, String> result = leaf.insert( 1L, key, value );
+ InsertResult<Long, String> result = leaf.insert( key, value, 1L );
return ( InMemoryLeaf<Long, String> ) ( ( ModifyResult<Long, String> ) result ).getModifiedPage();
}
@@ -96,7 +84,7 @@
{
InMemoryLeaf<Long, String> leaf = new InMemoryLeaf<Long, String>( btree );
- DeleteResult<Long, String> result = leaf.delete( 1L, 1L, null, null, -1 );
+ DeleteResult<Long, String> result = leaf.delete( 1L, null, 1L, null, -1 );
assertEquals( NotPresentResult.NOT_PRESENT, result );
}
@@ -115,7 +103,7 @@
leaf = insert( leaf, 3L, "v3" );
leaf = insert( leaf, 4L, "v4" );
- DeleteResult<Long, String> result = leaf.delete( 2L, 5L, null, null, -1 );
+ DeleteResult<Long, String> result = leaf.delete( 5L, null, 2L, null, -1 );
assertEquals( NotPresentResult.NOT_PRESENT, result );
}
@@ -134,7 +122,7 @@
leaf = insert( leaf, 3L, "v3" );
leaf = insert( leaf, 4L, "v4" );
- DeleteResult<Long, String> result = leaf.delete( 4L, 3L, null, null, -1 );
+ DeleteResult<Long, String> result = leaf.delete( 3L, null, 4L, null, -1 );
assertTrue( result instanceof RemoveResult );
@@ -181,7 +169,7 @@
leaf = insert( leaf, 3L, "v3" );
leaf = insert( leaf, 4L, "v4" );
- DeleteResult<Long, String> result = leaf.delete( 4L, 1L, null, null, -1 );
+ DeleteResult<Long, String> result = leaf.delete( 1L, null, 4L, null, -1 );
assertTrue( result instanceof RemoveResult );
@@ -224,7 +212,7 @@
* +--[1, 2, 3, 4, 5]
* [6, 10]-+--[6, 7, 8, 9]
* +--[10, 11, 12, 13]
- * @throws IOException
+ * @throws IOException
*/
@Test
public void testDeleteBorrowingFromLeftSibling() throws IOException
@@ -262,7 +250,7 @@
parent.setKey( 1, new KeyHolder<Long>( 10L ) );
// Now, delete the element from the target page
- DeleteResult<Long, String> result = target.delete( 2L, 7L, null, parent, 1 );
+ DeleteResult<Long, String> result = target.delete( 7L, null, 2L, parent, 1 );
assertTrue( result instanceof BorrowedFromLeftResult );
@@ -294,7 +282,7 @@
/**
* Check that deleting an element from a leaf with N/2 element works when we borrow
* an element in a right page with more than N/2 elements
- * @throws IOException
+ * @throws IOException
*/
@Test
public void testDeleteBorrowingFromRightSibling() throws IOException
@@ -332,7 +320,7 @@
parent.setKey( 1, new KeyHolder<Long>( 10L ) );
// Now, delete the element from the target page
- DeleteResult<Long, String> result = target.delete( 2L, 7L, null, parent, 1 );
+ DeleteResult<Long, String> result = target.delete( 7L, null, 2L, parent, 1 );
assertTrue( result instanceof BorrowedFromRightResult );
@@ -365,7 +353,7 @@
/**
* Check that deleting an element from a leaf with N/2 element works when we merge
* it with one of its sibling, if both has N/2 elements
- * @throws IOException
+ * @throws IOException
*/
@Test
public void testDeleteMergeWithSibling() throws IOException
@@ -402,7 +390,7 @@
parent.setKey( 1, new KeyHolder<Long>( 9L ) );
// Now, delete the element from the target page
- DeleteResult<Long, String> result = target.delete( 2L, 7L, null, parent, 1 );
+ DeleteResult<Long, String> result = target.delete( 7L, null, 2L, parent, 1 );
assertTrue( result instanceof MergedWithSiblingResult );
@@ -438,7 +426,7 @@
for ( long i = 0; i < 8; i++ )
{
long value = i + i + 1;
- leaf = ( InMemoryLeaf<Long, String> ) ( ( ModifyResult<Long, String> ) leaf.insert( 0L, value, "V" + value ) )
+ leaf = ( InMemoryLeaf<Long, String> ) ( ( ModifyResult<Long, String> ) leaf.insert( value, "V" + value, 0L ) )
.getModifiedPage();
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/MultiThreadedInMemoryBtreeTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/MultiThreadedInMemoryBtreeTest.java
index 7d969d4..26e70b6 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/MultiThreadedInMemoryBtreeTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/MultiThreadedInMemoryBtreeTest.java
@@ -21,26 +21,24 @@
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.junit.Ignore;
/**
* A class to test multi-threaded operations on the btree
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class MultiThreadedInMemoryBtreeTest
@@ -56,7 +54,7 @@
@BeforeClass
public static void setup() throws IOException
{
- btree = BTreeFactory.createInMemoryBTree( "test", new LongSerializer(), new StringSerializer() );
+ btree = BTreeFactory.createInMemoryBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE );
}
@@ -110,10 +108,10 @@
/**
* Browse the btree in its current revision, reading all of its elements
- * @return The number of read elements
+ * @return The number of read elements
* @throws IOException If the browse failed
*/
- private int testBrowse() throws IOException
+ private int testBrowse() throws IOException, KeyNotFoundException
{
TupleCursor<Long, String> cursor = btree.browse();
@@ -140,7 +138,7 @@
/**
* Check that we can read the btree while it is being modified. We will start
* 100 readers for one writer.
- *
+ *
* @throws InterruptedException If the btree access failed.
*/
@Test
@@ -217,42 +215,62 @@
{
int nbThreads = 100;
final CountDownLatch latch = new CountDownLatch( nbThreads );
+ final AtomicBoolean error = new AtomicBoolean(false);
//Thread.sleep( 60000L );
long t0 = System.currentTimeMillis();
+ class MyThread extends Thread
+ {
+ private int prefix = 0;
+
+ public void run()
+ {
+ try
+ {
+ // Inject 1000 elements
+ for ( int j = 0; j < 1000; j++ )
+ {
+ long value = prefix * 1000 + j;
+ String valStr = Long.toString( value );
+ //System.out.println( "---------------------------Inserting " + valStr + " for Thread " + Thread.currentThread().getName() );
+ btree.insert( value, valStr );
+
+ if ( j % 100 == 0 )
+ {
+ //System.out.println( "---------------------------Inserting " + valStr + " for Thread " + Thread.currentThread().getName() );
+// long res = checkBtree( prefix, 1000, j );
+//
+// if ( res != -1L )
+// {
+// //retry
+// System.out.println( "Failure to retrieve " + j );
+// latch.countDown();
+// error.set( true );
+// return;
+// }
+ }
+ }
+
+ latch.countDown();
+ }
+ catch ( Exception e )
+ {
+ e.printStackTrace();
+ System.out.println( e.getMessage() );
+ }
+ }
+
+ public MyThread( int prefix )
+ {
+ this.prefix = prefix;
+ }
+ }
+
for ( int i = 0; i < nbThreads; i++ )
{
- final long prefix = i;
- Thread test = new Thread()
- {
- public void run()
- {
- try
- {
- // Inject 1000 elements
- for ( int j = 0; j < 1000; j++ )
- {
- long value = prefix * 1000 + j;
- btree.insert( value, Long.toString( value ) );
-
- /*
- if ( j % 10000 == 0 )
- {
- System.out.println( "Thread " + Thread.currentThread().getName() + " flushed " + j
- + " elements" );
- }
- */
- }
-
- latch.countDown();
- }
- catch ( Exception e )
- {
- }
- }
- };
+ MyThread test = new MyThread( i );
// Start each reader
test.start();
@@ -261,22 +279,65 @@
// Wait for all the readers to be done
latch.await();
+ if ( error.get() )
+ {
+ System.out.println( "ERROR -----------------" );
+ return;
+ }
+
long t1 = System.currentTimeMillis();
// Check that the tree contains all the values
+ assertEquals( -1L, checkBtree( 1000, nbThreads ) );
+
+ System.out.println( " Time to create 1M entries : "
+ + ( ( t1 - t0 ) ) + " milliseconds" );
+ }
+
+
+ private long checkBtree( int prefix, int nbElems, int currentElem ) throws IOException
+ {
+ long i = 0L;
+
try
{
- for ( long i = 0L; i < 10000L; i++ )
+ for ( i = 0L; i < currentElem; i++ )
{
- assertEquals( Long.toString( i ), btree.get( i ) );
+ long key = prefix * nbElems + i;
+ assertEquals( Long.toString( key ), btree.get( key ) );
}
+
+ return -1L;
}
catch ( KeyNotFoundException knfe )
{
- fail();
+ System.out.println( "cannot find " + ( prefix * nbElems + i ) );
+ return i;
}
+ }
- System.out.println( " Time to create 1M entries : "
- + ( ( t1 - t0 ) / 1000 ) + " seconds" );
+
+ private long checkBtree( int nbElems, int nbThreads ) throws IOException
+ {
+ long i = 0L;
+
+ try
+ {
+ for ( long j = 0; j < nbThreads; j++ )
+ {
+ for ( i = 0L; i < nbElems; i++ )
+ {
+ long key = j * nbElems + i;
+ assertEquals( Long.toString( key ), btree.get( key ) );
+ }
+ }
+
+ return -1L;
+ }
+ catch ( KeyNotFoundException knfe )
+ {
+ System.out.println( "cannot find " + i );
+ return i;
+ }
}
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBrowseTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBrowseTest.java
index 8f34cac..f393b86 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBrowseTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBrowseTest.java
@@ -32,16 +32,14 @@
import java.util.UUID;
import org.apache.commons.io.FileUtils;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.RecordManager;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.EndOfFileExceededException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
@@ -49,7 +47,7 @@
/**
* Tests the browse methods on a managed BTree
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class PersistedBTreeBrowseTest
@@ -77,7 +75,7 @@
try
{
// Create a new BTree which allows duplicate values
- btree = recordManager1.addBTree( "test", new LongSerializer(), new StringSerializer(), true );
+ btree = recordManager1.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, true );
}
catch ( Exception e )
{
@@ -196,10 +194,11 @@
// The Browse tests
//----------------------------------------------------------------------------------------
/**
- * Test the browse methods on an empty btree
+ * Test the browse methods on an empty btree
+ * @throws KeyNotFoundException
*/
@Test
- public void testBrowseEmptyBTree() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseEmptyBTree() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
TupleCursor<Long, String> cursor = btree.browse();
@@ -226,7 +225,7 @@
// Expected
}
- assertEquals( -1L, cursor.getRevision() );
+ assertEquals( 0L, cursor.getRevision() );
}
@@ -234,7 +233,7 @@
* Test the browse methods on a btree containing just a leaf
*/
@Test
- public void testBrowseBTreeLeafNext() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafNext() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
btree.insert( 1L, "1" );
@@ -264,7 +263,7 @@
* Test the browse methods on a btree containing just a leaf
*/
@Test
- public void testBrowseBTreeLeafPrev() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
btree.insert( 1L, "1" );
@@ -292,7 +291,7 @@
* move at the end or at the beginning
*/
@Test
- public void testBrowseBTreeLeafFirstLast() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafFirstLast() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
btree.insert( 1L, "1" );
@@ -374,7 +373,7 @@
* move back and forth
*/
@Test
- public void testBrowseBTreeLeafNextPrev() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafNextPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
btree.insert( 1L, "1" );
@@ -426,7 +425,7 @@
* Test the browse methods on a btree containing many nodes
*/
@Test
- public void testBrowseBTreeNodesNext() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeNodesNext() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
@@ -458,7 +457,7 @@
* Test the browse methods on a btree containing many nodes
*/
@Test
- public void testBrowseBTreeNodesPrev() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeNodesPrev() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
@@ -490,7 +489,7 @@
* Test the browse methods on a btree containing just a leaf with duplicate values
*/
@Test
- public void testBrowseBTreeLeafNextDups1() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafNextDups1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data
btree.insert( 1L, "1" );
@@ -520,7 +519,7 @@
* Test the browse methods on a btree containing just a leaf with duplicate values
*/
@Test
- public void testBrowseBTreeLeafNextDupsN() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafNextDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data
btree.insert( 1L, "1" );
@@ -554,7 +553,7 @@
* Test the browse methods on a btree containing just a leaf with duplicate values
*/
@Test
- public void testBrowseBTreeLeafPrevDups1() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafPrevDups1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data
btree.insert( 1L, "1" );
@@ -584,7 +583,7 @@
* Test the browse methods on a btree containing just a leaf with duplicate values
*/
@Test
- public void testBrowseBTreeLeafPrevDupsN() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafPrevDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data
btree.insert( 1L, "1" );
@@ -618,7 +617,7 @@
* Test the browse methods on a btree containing nodes with duplicate values
*/
@Test
- public void testBrowseBTreeNodesNextDupsN() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeNodesNextDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
@@ -664,7 +663,7 @@
* Test the browse methods on a btree containing nodes with duplicate values
*/
@Test
- public void testBrowseBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeNodesPrevDupsN() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
@@ -711,7 +710,7 @@
* stored into a sub btree
*/
@Test
- public void testBrowseBTreeLeafNextDupsSubBTree1() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafNextDupsSubBTree1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data which will be stored into a sub btree
for ( long i = 1L; i < 32L; i++ )
@@ -743,7 +742,7 @@
* Test the browse methods on a btree containing just a leaf with duplicate values
*/
@Test
- public void testBrowseBTreeLeafPrevDupsSubBTree1() throws IOException, BTreeAlreadyManagedException
+ public void testBrowseBTreeLeafPrevDupsSubBTree1() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some duplicate data which will be stored into a sub btree
for ( long i = 1L; i < 32L; i++ )
@@ -805,7 +804,7 @@
// Expected
}
- assertEquals( -1L, cursor.getRevision() );
+ assertEquals( 0L, cursor.getRevision() );
}
@@ -893,6 +892,27 @@
/**
+ * Test the browseFrom method on a btree with a non existing key
+ */
+ @Test
+ public void testBrowseFromBTreeNodesNotExistingKey() throws IOException, BTreeAlreadyManagedException
+ {
+ // Inject some data
+ for ( long i = 0; i <= 1000L; i += 2 )
+ {
+ btree.insert( i, Long.toString( i ) );
+ }
+
+ // Create the cursor
+ TupleCursor<Long, String> cursor = btree.browseFrom( 1500L );
+
+ assertFalse( cursor.hasNext() );
+ assertTrue( cursor.hasPrev() );
+ assertEquals( 1000L, cursor.prev().getKey().longValue() );
+ }
+
+
+ /**
* Test the browseFrom method on a btree containing nodes with duplicate values
*/
@Test
@@ -936,11 +956,11 @@
// The TupleCursor.moveToNext/PrevNonDuplicateKey method tests
//----------------------------------------------------------------------------------------
/**
- * Test the TupleCursor.nextKey method on a btree containing nodes
+ * Test the TupleCursor.nextKey method on a btree containing nodes
* with duplicate values.
*/
@Test
- public void testNextKey() throws IOException, BTreeAlreadyManagedException
+ public void testNextKey() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
@@ -983,13 +1003,63 @@
}
}
+
+ /**
+ * Test the TupleCursor.nextKey method on a btree containing nodes
+ * with duplicate values.
+ */
+ @Test
+ @Ignore
+ public void testNextKeyDups() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
+ {
+ // Inject some data
+ //for ( long i = 1; i < 3; i++ )
+ {
+ for ( long j = 1; j < 9; j++ )
+ {
+ btree.insert( 1L, Long.toString( j ) );
+ }
+ }
+
+ btree.insert( 1L, "10" );
+
+ // Create the cursor
+ TupleCursor<Long, String> cursor = btree.browse();
+
+ // Move forward
+ cursor.beforeFirst();
+
+ assertFalse( cursor.hasPrevKey() );
+ assertTrue( cursor.hasNextKey() );
+
+ Tuple<Long, String> tuple = cursor.nextKey();
+
+ checkTuple( tuple, 1L, "1" );
+
+ cursor.beforeFirst();
+ long val = 1L;
+
+ while ( cursor.hasNext() )
+ {
+ tuple = cursor.next();
+
+ assertEquals( Long.valueOf( 1L ), tuple.getKey() );
+ assertEquals( Long.toString( val ), tuple.getValue() );
+
+ val++;
+ }
+
+ assertFalse( cursor.hasNextKey() );
+ assertFalse( cursor.hasPrevKey() );
+ }
+
/**
- * Test the TupleCursor.moveToPrevNonDuplicateKey method on a btree containing nodes
+ * Test the TupleCursor.moveToPrevNonDuplicateKey method on a btree containing nodes
* with duplicate values.
*/
@Test
- public void testPrevKey() throws IOException, BTreeAlreadyManagedException
+ public void testPrevKey() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
// Inject some data
for ( long i = 1; i < 1000L; i++ )
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilderTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilderTest.java
index 8f98e3a..6552d8d 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilderTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeBuilderTest.java
@@ -27,12 +27,8 @@
import java.util.ArrayList;
import java.util.List;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.PersistedBTreeBuilder;
-import org.apache.directory.mavibot.btree.RecordManager;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
+import org.junit.Ignore;
import org.junit.Test;
@@ -41,6 +37,7 @@
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
+@Ignore( "until ApacheDS works with mavibot" )
public class PersistedBTreeBuilderTest
{
@@ -60,7 +57,7 @@
RecordManager rm = new RecordManager( file.getAbsolutePath() );
- IntSerializer ser = new IntSerializer();
+ IntSerializer ser = IntSerializer.INSTANCE;
PersistedBTreeBuilder<Integer, Integer> bb = new PersistedBTreeBuilder<Integer, Integer>( rm, "master", 4, ser,
ser );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
index 71e2a38..b261e8a 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeDuplicateKeyTest.java
@@ -35,6 +35,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.DuplicateValueNotAllowedException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.IntSerializer;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
@@ -72,7 +73,7 @@
try
{
// Create a new BTree
- btree = recordManager1.addBTree( "test", new LongSerializer(), new StringSerializer(),
+ btree = recordManager1.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE,
BTree.ALLOW_DUPLICATES );
}
catch ( Exception e )
@@ -122,7 +123,7 @@
@Test
- public void testInsertNullValue() throws IOException
+ public void testInsertNullValue() throws IOException, KeyNotFoundException
{
btree.insert( 1L, null );
@@ -141,11 +142,14 @@
@Test
- public void testBrowseEmptyTree() throws IOException
+ public void testBrowseEmptyTree() throws IOException, KeyNotFoundException, BTreeAlreadyManagedException
{
- IntSerializer serializer = new IntSerializer();
+ IntSerializer serializer = IntSerializer.INSTANCE;
BTree<Integer, Integer> btree = BTreeFactory.createPersistedBTree( "master", serializer, serializer );
+
+ // Inject the newly created BTree into teh recordManager
+ recordManager1.manage( btree );
TupleCursor<Integer, Integer> cursor = btree.browse();
assertFalse( cursor.hasNext() );
@@ -177,7 +181,7 @@
@Test
- public void testDuplicateKey() throws IOException
+ public void testDuplicateKey() throws IOException, KeyNotFoundException
{
btree.insert( 1L, "1" );
btree.insert( 1L, "2" );
@@ -792,8 +796,8 @@
@Test(expected = DuplicateValueNotAllowedException.class)
public void testBTreeForbidDups() throws IOException, BTreeAlreadyManagedException
{
- BTree<Long, String> singleValueBtree = recordManager1.addBTree( "test2", new LongSerializer(),
- new StringSerializer(), BTree.FORBID_DUPLICATES );
+ BTree<Long, String> singleValueBtree = recordManager1.addBTree( "test2", LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE, BTree.FORBID_DUPLICATES );
for ( long i = 0; i < 64; i++ )
{
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeTransactionTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeTransactionTest.java
index 706545f..aa91342 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeTransactionTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedBTreeTransactionTest.java
@@ -59,8 +59,8 @@
try
{
// Create a new BTree with transaction and another one without
- btreeWithTransactions = recordManagerTxn.addBTree( "testWithTxn", new LongSerializer(), new StringSerializer(), false );
- btreeNoTransactions = recordManagerNoTxn.addBTree( "testNoTxn", new LongSerializer(), new StringSerializer(), false );
+ btreeWithTransactions = recordManagerTxn.addBTree( "testWithTxn", LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
+ btreeNoTransactions = recordManagerNoTxn.addBTree( "testNoTxn", LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
}
catch ( Exception e )
{
@@ -130,9 +130,9 @@
for ( long i = 0L; i < 1000L; i++ )
{
System.out.println( i );
- btreeWithTransactions.beginTransaction();
+ //btreeWithTransactions.beginTransaction();
btreeWithTransactions.insert( i, Long.toString( i ) );
- btreeWithTransactions.commit();
+ //btreeWithTransactions.commit();
}
long t1 = System.currentTimeMillis();
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedStoreTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedStoreTest.java
index 9a57731..47f8057 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedStoreTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/PersistedStoreTest.java
@@ -325,15 +325,15 @@
storeMethod.setAccessible( true );
// Allocate some Pages
- PageIO[] pageIos = new PageIO[4];
+ PageIO[] pageIos = new PageIO[3];
pageIos[0] = new PageIO();
pageIos[0].setData( ByteBuffer.allocate( recordManager.getPageSize() ) );
pageIos[1] = new PageIO();
pageIos[1].setData( ByteBuffer.allocate( recordManager.getPageSize() ) );
pageIos[2] = new PageIO();
pageIos[2].setData( ByteBuffer.allocate( recordManager.getPageSize() ) );
- pageIos[3] = new PageIO();
- pageIos[3].setData( ByteBuffer.allocate( recordManager.getPageSize() ) );
+// pageIos[3] = new PageIO();
+// pageIos[3].setData( ByteBuffer.allocate( recordManager.getPageSize() ) );
// We start with 4 bytes
byte[] bytes = new byte[]
@@ -396,10 +396,10 @@
}
// Write the bytes over 2 pages
- position = ( Long ) storeMethod.invoke( recordManager, 15L, bytes, pageIos );
+ position = ( Long ) storeMethod.invoke( recordManager, 47L, bytes, pageIos );
- assertEquals( 35, position );
- pos = 27;
+ assertEquals( 67, position );
+ pos = 59;
// The byte length
assertEquals( 0x00, pageIos[0].getData().get( pos++ ) );
assertEquals( 0x00, pageIos[0].getData().get( pos++ ) );
@@ -418,25 +418,25 @@
}
// Write the bytes over 4 pages
- bytes = new byte[80];
+ bytes = new byte[112];
- for ( int i = 0; i < 80; i++ )
+ for ( int i = 0; i < 112; i++ )
{
bytes[i] = ( byte ) ( i + 1 );
}
position = ( Long ) storeMethod.invoke( recordManager, 2L, bytes, pageIos );
- assertEquals( 86, position );
+ assertEquals( 118, position );
pos = 14;
// The byte length
assertEquals( 0x00, pageIos[0].getData().get( pos++ ) );
assertEquals( 0x00, pageIos[0].getData().get( pos++ ) );
assertEquals( 0x00, pageIos[0].getData().get( pos++ ) );
- assertEquals( 0x50, pageIos[0].getData().get( pos++ ) );
+ assertEquals( 0x70, pageIos[0].getData().get( pos++ ) );
// The data in the first page
- for ( int i = 0; i < 14; i++ )
+ for ( int i = 0; i < 46; i++ )
{
assertEquals( ( byte ) ( i + 1 ), pageIos[0].getData().get( pos++ ) );
}
@@ -444,7 +444,7 @@
// The data in the second page
pos = 8;
- for ( int i = 14; i < 38; i++ )
+ for ( int i = 46; i < 102; i++ )
{
assertEquals( ( byte ) ( i + 1 ), pageIos[1].getData().get( pos++ ) );
}
@@ -452,19 +452,11 @@
// The data in the third page
pos = 8;
- for ( int i = 38; i < 62; i++ )
+ for ( int i = 102; i < 112; i++ )
{
assertEquals( ( byte ) ( i + 1 ), pageIos[2].getData().get( pos++ ) );
}
- // The data in the forth page
- pos = 8;
-
- for ( int i = 62; i < 80; i++ )
- {
- assertEquals( ( byte ) ( i + 1 ), pageIos[3].getData().get( pos++ ) );
- }
-
recordManager.close();
}
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerFreePageTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerFreePageTest.java
index 4c808e8..8a41deb 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerFreePageTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerFreePageTest.java
@@ -28,11 +28,8 @@
import java.util.Set;
import org.apache.commons.io.FileUtils;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.RecordManager;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.After;
@@ -42,7 +39,7 @@
/**
* test the RecordManager's free page management
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RecordManagerFreePageTest
@@ -71,7 +68,7 @@
try
{
// Create a new BTree
- btree = recordManager1.addBTree( "test", new LongSerializer(), new StringSerializer(), false );
+ btree = recordManager1.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
}
catch ( Exception e )
{
@@ -120,14 +117,14 @@
}
}
- private int nbElems = 100000;
+ private int nbElems = 10000;
/**
- * Test the creation of a RecordManager, and that we can read it back.
+ * Test the creation of a RecordManager, and that we can read it back.
*/
@Test
- public void testRecordManager() throws IOException, BTreeAlreadyManagedException
+ public void testRecordManager() throws IOException, BTreeAlreadyManagedException, KeyNotFoundException
{
assertEquals( 1, recordManager1.getNbManagedTrees() );
@@ -144,6 +141,7 @@
for ( int i = 0; i < nbElems; i++ )
{
+ // System.out.println( i );
Long key = ( long ) i;
String value = Long.toString( key );
@@ -178,7 +176,7 @@
units = "KB";
}
- System.out.println( size + units );
+ // System.out.println( size + units );
openRecordManagerAndBtree();
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerPrivateMethodTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerPrivateMethodTest.java
index 6f15b9b..da9f579 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerPrivateMethodTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerPrivateMethodTest.java
@@ -28,9 +28,6 @@
import java.lang.reflect.Method;
import java.util.UUID;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.PageIO;
-import org.apache.directory.mavibot.btree.RecordManager;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
import org.junit.After;
@@ -42,7 +39,7 @@
/**
* Test some of the RecordManager prvate methods
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RecordManagerPrivateMethodTest
@@ -62,11 +59,13 @@
{
dataDir = tempFolder.newFolder( UUID.randomUUID().toString() );
+ System.out.println( dataDir + "/mavibot.db" );
+
// Now, try to reload the file back
recordManager = new RecordManager( dataDir.getAbsolutePath(), 32 );
// Create a new BTree
- btree = recordManager.addBTree( "test", new LongSerializer(), new StringSerializer(), false );
+ btree = recordManager.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
}
@@ -91,19 +90,19 @@
assertEquals( 0, pages.length );
- for ( int i = 1; i < 20; i++ )
+ for ( int i = 1; i <= 52; i++ )
{
pages = ( org.apache.directory.mavibot.btree.PageIO[] ) getFreePageIOsMethod.invoke( recordManager, i );
assertEquals( 1, pages.length );
}
- for ( int i = 21; i < 44; i++ )
+ for ( int i = 53; i <= 108; i++ )
{
pages = ( org.apache.directory.mavibot.btree.PageIO[] ) getFreePageIOsMethod.invoke( recordManager, i );
assertEquals( 2, pages.length );
}
- for ( int i = 45; i < 68; i++ )
+ for ( int i = 109; i <= 164; i++ )
{
pages = ( org.apache.directory.mavibot.btree.PageIO[] ) getFreePageIOsMethod.invoke( recordManager, i );
assertEquals( 3, pages.length );
@@ -125,17 +124,17 @@
assertEquals( 0, ( ( Integer ) computeNbPagesMethod.invoke( recordManager, 0 ) ).intValue() );
- for ( int i = 1; i < 21; i++ )
+ for ( int i = 1; i < 53; i++ )
{
assertEquals( 1, ( ( Integer ) computeNbPagesMethod.invoke( recordManager, i ) ).intValue() );
}
- for ( int i = 21; i < 45; i++ )
+ for ( int i = 53; i < 109; i++ )
{
assertEquals( 2, ( ( Integer ) computeNbPagesMethod.invoke( recordManager, i ) ).intValue() );
}
- for ( int i = 45; i < 68; i++ )
+ for ( int i = 109; i < 164; i++ )
{
assertEquals( 3, ( ( Integer ) computeNbPagesMethod.invoke( recordManager, i ) ).intValue() );
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerTest.java
index e5a52c6..dac72ec 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerTest.java
@@ -35,11 +35,6 @@
import java.util.UUID;
import org.apache.commons.io.FileUtils;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.RecordManager;
-import org.apache.directory.mavibot.btree.Tuple;
-import org.apache.directory.mavibot.btree.TupleCursor;
-import org.apache.directory.mavibot.btree.ValueCursor;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
@@ -54,7 +49,7 @@
/**
* test the RecordManager
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RecordManagerTest
@@ -74,12 +69,14 @@
{
dataDir = tempFolder.newFolder( UUID.randomUUID().toString() );
+ System.out.println( dataDir + "/mavibot.db" );
+
openRecordManagerAndBtree();
try
{
// Create a new BTree
- btree = recordManager.addBTree( "test", new LongSerializer(), new StringSerializer(), false );
+ btree = recordManager.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, false );
}
catch ( Exception e )
{
@@ -126,7 +123,7 @@
/**
- * Test the creation of a RecordManager, and that we can read it back.
+ * Test the creation of a RecordManager, and that we can read it back.
*/
@Test
public void testRecordManager() throws IOException, BTreeAlreadyManagedException
@@ -397,7 +394,7 @@
/**
- * Test the creation of a RecordManager with a BTree containing data, where we keep the revisions,
+ * Test the creation of a RecordManager with a BTree containing data, where we keep the revisions,
* and browse the BTree.
*/
@Test
@@ -457,10 +454,10 @@
// Check that we can read the revision again
// revision 1
- checkBTreeRevisionBrowse( btree, rev1, 3L );
+ checkBTreeRevisionBrowse( btree, rev1 );
// Revision 2
- checkBTreeRevisionBrowse( btree, rev2, 1L, 3L );
+ checkBTreeRevisionBrowse( btree, rev2 );
// Revision 3
checkBTreeRevisionBrowse( btree, rev3, 1L, 3L, 5L );
@@ -468,7 +465,7 @@
/**
- * Test the creation of a RecordManager with a BTree containing data, where we keep the revision, and
+ * Test the creation of a RecordManager with a BTree containing data, where we keep the revision, and
* we browse from a key
*/
@Test
@@ -528,10 +525,10 @@
// Check that we can read the revision again
// revision 1
- checkBTreeRevisionBrowseFrom( btree, rev1, 3L, 3L );
+ checkBTreeRevisionBrowseFrom( btree, rev1, 3L );
// Revision 2
- checkBTreeRevisionBrowseFrom( btree, rev2, 3L, 3L );
+ checkBTreeRevisionBrowseFrom( btree, rev2, 3L );
// Revision 3
checkBTreeRevisionBrowseFrom( btree, rev3, 3L, 3L, 5L );
@@ -618,20 +615,16 @@
// Check that we can get a value from each revision
// revision 1
- assertEquals( "V3", btree.get( rev1, 3L ) );
+ checkBTreeRevisionBrowse( btree, rev1 );
// revision 2
- assertEquals( "V1", btree.get( rev2, 1L ) );
- assertEquals( "V3", btree.get( rev2, 3L ) );
+ checkBTreeRevisionBrowse( btree, rev2 );
// revision 3
- assertEquals( "V1", btree.get( rev3, 1L ) );
- assertEquals( "V3", btree.get( rev3, 3L ) );
- assertEquals( "V5", btree.get( rev3, 5L ) );
+ checkBTreeRevisionBrowse( btree, rev3 );
// revision 4
- assertEquals( "V1", btree.get( rev4, 1L ) );
- assertEquals( "V5", btree.get( rev4, 5L ) );
+ checkBTreeRevisionBrowse( btree, rev4, 1L, 5L );
try
{
@@ -720,18 +713,18 @@
// Check that we can get a value from each revision
// revision 1
assertFalse( btree.contains( rev1, 1L, "V1" ) );
- assertTrue( btree.contains( rev1, 3L, "V3" ) );
+ assertFalse( btree.contains( rev1, 3L, "V3" ) );
assertFalse( btree.contains( rev1, 5L, "V5" ) );
// revision 2
- assertTrue( btree.contains( rev2, 1L, "V1" ) );
- assertTrue( btree.contains( rev2, 3L, "V3" ) );
+ assertFalse( btree.contains( rev2, 1L, "V1" ) );
+ assertFalse( btree.contains( rev2, 3L, "V3" ) );
assertFalse( btree.contains( rev2, 5L, "V5" ) );
// revision 3
- assertTrue( btree.contains( rev3, 1L, "V1" ) );
- assertTrue( btree.contains( rev3, 3L, "V3" ) );
- assertTrue( btree.contains( rev3, 5L, "V5" ) );
+ assertFalse( btree.contains( rev3, 1L, "V1" ) );
+ assertFalse( btree.contains( rev3, 3L, "V3" ) );
+ assertFalse( btree.contains( rev3, 5L, "V5" ) );
// revision 4
assertTrue( btree.contains( rev4, 1L, "V1" ) );
@@ -815,18 +808,18 @@
// Check that we can get a value from each revision
// revision 1
assertFalse( btree.hasKey( rev1, 1L ) );
- assertTrue( btree.hasKey( rev1, 3L ) );
+ assertFalse( btree.hasKey( rev1, 3L ) );
assertFalse( btree.hasKey( rev1, 5L ) );
// revision 2
- assertTrue( btree.hasKey( rev2, 1L ) );
- assertTrue( btree.hasKey( rev2, 3L ) );
+ assertFalse( btree.hasKey( rev2, 1L ) );
+ assertFalse( btree.hasKey( rev2, 3L ) );
assertFalse( btree.hasKey( rev2, 5L ) );
// revision 3
- assertTrue( btree.hasKey( rev3, 1L ) );
- assertTrue( btree.hasKey( rev3, 3L ) );
- assertTrue( btree.hasKey( rev3, 5L ) );
+ assertFalse( btree.hasKey( rev3, 1L ) );
+ assertFalse( btree.hasKey( rev3, 3L ) );
+ assertFalse( btree.hasKey( rev3, 5L ) );
// revision 4
assertTrue( btree.hasKey( rev4, 1L ) );
@@ -848,8 +841,8 @@
String[] testValues = new String[]
{ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10" };
- BTree<Long, String> dupsTree = BTreeFactory.createPersistedBTree( name, new LongSerializer(),
- new StringSerializer(), pageSize, true );
+ BTree<Long, String> dupsTree = BTreeFactory.createPersistedBTree( name, LongSerializer.INSTANCE,
+ StringSerializer.INSTANCE, pageSize, true );
recordManager.manage( dupsTree );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerWithDuplicatesTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerWithDuplicatesTest.java
index 1599601..a59b3a7 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerWithDuplicatesTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RecordManagerWithDuplicatesTest.java
@@ -30,8 +30,6 @@
import java.util.UUID;
import org.apache.commons.io.FileUtils;
-import org.apache.directory.mavibot.btree.BTree;
-import org.apache.directory.mavibot.btree.RecordManager;
import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
@@ -45,7 +43,7 @@
/**
* test the RecordManager whith duplicate values
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RecordManagerWithDuplicatesTest
@@ -70,7 +68,7 @@
try
{
// Create a new BTree which allows duplicate values
- btree = recordManager.addBTree( "test", new LongSerializer(), new StringSerializer(), true );
+ btree = recordManager.addBTree( "test", LongSerializer.INSTANCE, StringSerializer.INSTANCE, true );
}
catch ( Exception e )
{
@@ -114,7 +112,7 @@
/**
- * Test the creation of a RecordManager, and that we can read it back.
+ * Test the creation of a RecordManager, and that we can read it back.
*/
@Test
public void testRecordManager() throws IOException, BTreeAlreadyManagedException
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameComparatorTest.java
index 81a1160..8491a61 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameComparatorTest.java
@@ -22,14 +22,12 @@
import static org.junit.Assert.assertEquals;
-import org.apache.directory.mavibot.btree.RevisionName;
-import org.apache.directory.mavibot.btree.RevisionNameComparator;
import org.junit.Test;
/**
* Test the RevisionNameComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RevisionNameComparatorTest
@@ -37,7 +35,7 @@
@Test
public void testRevisionNameComparator()
{
- RevisionNameComparator comparator = new RevisionNameComparator();
+ RevisionNameComparator comparator = RevisionNameComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( new RevisionName( 0L, "test" ), new RevisionName( 0L, "test" ) ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameSerializerTest.java
index a23ec56..30ce23b 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/RevisionNameSerializerTest.java
@@ -26,8 +26,6 @@
import java.io.IOException;
-import org.apache.directory.mavibot.btree.RevisionName;
-import org.apache.directory.mavibot.btree.RevisionNameSerializer;
import org.apache.directory.mavibot.btree.serializer.BufferHandler;
import org.apache.directory.mavibot.btree.serializer.LongSerializer;
import org.apache.directory.mavibot.btree.serializer.StringSerializer;
@@ -36,12 +34,12 @@
/**
* Test the RevisionNameSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class RevisionNameSerializerTest
{
- private static RevisionNameSerializer serializer = new RevisionNameSerializer();
+ private static RevisionNameSerializer serializer = RevisionNameSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparatorTest.java
index 5fe5493..709ae15 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the BooleanArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BooleanArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testBooleanArrayComparator()
{
- BooleanArrayComparator comparator = new BooleanArrayComparator();
+ BooleanArrayComparator comparator = BooleanArrayComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanComparatorTest.java
index 6b34fe8..e2daf9c 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/BooleanComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the BooleanComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BooleanComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testBooleanComparator()
{
- BooleanComparator comparator = new BooleanComparator();
+ BooleanComparator comparator = BooleanComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( true, true ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparatorTest.java
index 261d367..9a256d0 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the ByteArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testByteArrayComparator()
{
- ByteArrayComparator comparator = new ByteArrayComparator();
+ ByteArrayComparator comparator = ByteArrayComparator.INSTANCE;
// Check equality
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteComparatorTest.java
index 07f5098..b72c5e9 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ByteComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the ByteComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testByteComparator()
{
- ByteComparator comparator = new ByteComparator();
+ ByteComparator comparator = ByteComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( ( byte ) 0x00, ( byte ) 0x00 ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparatorTest.java
index 6bbda18..288bb58 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the CharArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CharArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testCharArrayComparator()
{
- CharArrayComparator comparator = new CharArrayComparator();
+ CharArrayComparator comparator = CharArrayComparator.INSTANCE;
// Check equality
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharComparatorTest.java
index 7312370..ec84861 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/CharComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the CharComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CharComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testCharComparator()
{
- CharComparator comparator = new CharComparator();
+ CharComparator comparator = CharComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( 'a', 'a' ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparatorTest.java
index 8feb043..1e88ee0 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the IntArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class IntArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testIntArrayComparator()
{
- IntArrayComparator comparator = new IntArrayComparator();
+ IntArrayComparator comparator = IntArrayComparator.INSTANCE;
// Check equality
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntComparatorTest.java
index a27ca1d..27c9cf0 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/IntComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the IntComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class IntComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testIntComparator()
{
- IntComparator comparator = new IntComparator();
+ IntComparator comparator = IntComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( 1, 1 ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparatorTest.java
index 4832508..b2de9ac 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the LongArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testLongArrayComparator()
{
- LongArrayComparator comparator = new LongArrayComparator();
+ LongArrayComparator comparator = LongArrayComparator.INSTANCE;
// Check equality
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongComparatorTest.java
index 327e5aa..ad3a59b 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/LongComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the LongComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testLongComparator()
{
- LongComparator comparator = new LongComparator();
+ LongComparator comparator = LongComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( 1L, 1L ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparatorTest.java
index 6832a50..bc53670 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortArrayComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the ShortArrayComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ShortArrayComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testShortArrayComparator()
{
- ShortArrayComparator comparator = new ShortArrayComparator();
+ ShortArrayComparator comparator = ShortArrayComparator.INSTANCE;
// Check equality
assertEquals( 0, comparator.compare( null, null ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortComparatorTest.java
index 5a6cac2..4844f4a 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/ShortComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the ShortComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ShortComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testShortComparator()
{
- ShortComparator comparator = new ShortComparator();
+ ShortComparator comparator = ShortComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( ( short ) 1, ( short ) 1 ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/StringComparatorTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/StringComparatorTest.java
index 5018c6e..21fe3dc 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/StringComparatorTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/comparator/StringComparatorTest.java
@@ -27,7 +27,7 @@
/**
* Test the StringComparator class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class StringComparatorTest
@@ -35,7 +35,7 @@
@Test
public void testStringComparator()
{
- StringComparator comparator = new StringComparator();
+ StringComparator comparator = StringComparator.INSTANCE;
assertEquals( 0, comparator.compare( null, null ) );
assertEquals( 0, comparator.compare( "", "" ) );
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializerTest.java
index f4ba67a..37417c9 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/BooleanSerializerTest.java
@@ -29,12 +29,12 @@
/**
* Test the BooleanSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class BooleanSerializerTest
{
- private static BooleanSerializer serializer = new BooleanSerializer();
+ private static BooleanSerializer serializer = BooleanSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializerTest.java
index 427583b..9c8ccf0 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteArraySerializerTest.java
@@ -31,12 +31,12 @@
/**
* Test the BytesSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteArraySerializerTest
{
- private static ByteArraySerializer serializer = new ByteArraySerializer();
+ private static ByteArraySerializer serializer = ByteArraySerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteSerializerTest.java
index e99c8d5..5c9adff 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ByteSerializerTest.java
@@ -29,12 +29,12 @@
/**
* Test the ByteSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ByteSerializerTest
{
- private static ByteSerializer serializer = new ByteSerializer();
+ private static ByteSerializer serializer = ByteSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/CharSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/CharSerializerTest.java
index eb6d6b7..abd588a 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/CharSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/CharSerializerTest.java
@@ -29,12 +29,12 @@
/**
* Test the CharSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class CharSerializerTest
{
- private static CharSerializer serializer = new CharSerializer();
+ private static CharSerializer serializer = CharSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/IntSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/IntSerializerTest.java
index f852ffe..0b11aaf 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/IntSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/IntSerializerTest.java
@@ -29,12 +29,12 @@
/**
* Test the IntSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class IntSerializerTest
{
- private static IntSerializer serializer = new IntSerializer();
+ private static IntSerializer serializer = IntSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializerTest.java
new file mode 100644
index 0000000..fe45b39
--- /dev/null
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongArraySerializerTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.directory.mavibot.btree.serializer;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+
+/**
+ * Test the LongArraySerializer class
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LongArraySerializerTest
+{
+ LongArraySerializer longArraySerializer = LongArraySerializer.INSTANCE;
+
+ @Test
+ @Ignore
+ public void testLongArraySerializer() throws IOException
+ {
+ long[] value = null;
+ byte[] result = longArraySerializer.serialize( value );
+ int pos = 0;
+
+ assertEquals( 4, result.length );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+
+ assertEquals( value, longArraySerializer.deserialize( new BufferHandler( result ) ) );
+
+ // ------------------------------------------------------------------
+ value = new long[]{};
+ result = longArraySerializer.serialize( value );
+ pos = 0;
+
+ assertEquals( 4, result.length );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+
+ assertTrue( Arrays.equals( value, longArraySerializer.deserialize( new BufferHandler( result ) ) ) );
+
+ // ------------------------------------------------------------------
+ value = new long[]{ 1L };
+ result = longArraySerializer.serialize( value );
+ pos = 0;
+
+ assertEquals( 12, result.length );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x01, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x01, result[pos++] );
+
+ assertTrue( Arrays.equals( value, longArraySerializer.deserialize( new BufferHandler( result ) ) ) );
+
+ // ------------------------------------------------------------------
+ value = new long[]{ 1L, 0x00000000FFFFFFFFL, 0xFFFFFFFFFFFFFFFFL };
+ result = longArraySerializer.serialize( value );
+ pos = 0;
+
+ assertEquals( 28, result.length );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x03, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x01, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0x00, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+ assertEquals( ( byte ) 0xFF, result[pos++] );
+
+ assertTrue( Arrays.equals( value, longArraySerializer.deserialize( new BufferHandler( result ) ) ) );
+ }
+}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongSerializerTest.java
index 269f6b8..856920d 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/LongSerializerTest.java
@@ -29,14 +29,11 @@
/**
* Test the LongSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LongSerializerTest
{
- private static LongSerializer serializer = new LongSerializer();
-
-
@Test
public void testLongSerializer() throws IOException
{
@@ -52,7 +49,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000000000001L;
@@ -67,7 +64,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x00000000000000FFL;
@@ -82,7 +79,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000000000100L;
@@ -97,7 +94,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x000000000000FFFFL;
@@ -112,7 +109,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000000010000L;
@@ -127,7 +124,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000000FFFFFFL;
@@ -142,7 +139,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000001000000L;
@@ -157,7 +154,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x000000007FFFFFFFL;
@@ -172,7 +169,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000080000000L;
@@ -187,7 +184,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x00000000FFFFFFFFL;
@@ -202,7 +199,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000000100000000L;
@@ -217,7 +214,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x000000FFFFFFFFFFL;
@@ -232,7 +229,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000010000000000L;
@@ -247,7 +244,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0000FFFFFFFFFFFFL;
@@ -262,7 +259,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0001000000000000L;
@@ -277,7 +274,7 @@
assertEquals( ( byte ) 0x01, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x00FFFFFFFFFFFFFFL;
@@ -292,7 +289,7 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x0100000000000000L;
@@ -307,7 +304,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x01, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x7FFFFFFFFFFFFFFFL;
@@ -322,7 +319,7 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0x7F, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0x8000000000000000L;
@@ -337,7 +334,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x80, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
// ------------------------------------------------------------------
value = 0xFFFFFFFFFFFFFFFFL;
@@ -352,6 +349,6 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0xFF, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).longValue() );
+ assertEquals( value, LongSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).longValue() );
}
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ShortSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ShortSerializerTest.java
index 255ca42..0ad6050 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ShortSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/ShortSerializerTest.java
@@ -29,14 +29,11 @@
/**
* Test the ShortSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class ShortSerializerTest
{
- private static ShortSerializer serializer = new ShortSerializer();
-
-
@Test
public void testShortSerializer() throws IOException
{
@@ -46,7 +43,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = 0x0001;
@@ -55,7 +52,7 @@
assertEquals( ( byte ) 0x01, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = 0x00FF;
@@ -64,7 +61,7 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0x00, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = 0x0100;
@@ -73,7 +70,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x01, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = 0x7FFF;
@@ -82,7 +79,7 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0x7F, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = ( short ) 0x8000;
@@ -91,7 +88,7 @@
assertEquals( ( byte ) 0x00, result[1] );
assertEquals( ( byte ) 0x80, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
// ------------------------------------------------------------------
value = ( short ) 0xFFFF;
@@ -100,6 +97,6 @@
assertEquals( ( byte ) 0xFF, result[1] );
assertEquals( ( byte ) 0xFF, result[0] );
- assertEquals( value, serializer.deserialize( new BufferHandler( result ) ).shortValue() );
+ assertEquals( value, ShortSerializer.INSTANCE.deserialize( new BufferHandler( result ) ).shortValue() );
}
}
diff --git a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/StringSerializerTest.java b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/StringSerializerTest.java
index d3e6ce3..a76bd52 100644
--- a/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/StringSerializerTest.java
+++ b/mavibot/src/test/java/org/apache/directory/mavibot/btree/serializer/StringSerializerTest.java
@@ -29,12 +29,12 @@
/**
* Test the StringSerializer class
- *
+ *
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class StringSerializerTest
{
- private static StringSerializer serializer = new StringSerializer();
+ private static StringSerializer serializer = StringSerializer.INSTANCE;
@Test
diff --git a/mavibot/src/test/resources/log4j.properties b/mavibot/src/test/resources/log4j.properties
index b20ba58..c6e0497 100644
--- a/mavibot/src/test/resources/log4j.properties
+++ b/mavibot/src/test/resources/log4j.properties
@@ -14,11 +14,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#############################################################################
-log4j.rootCategory=OFF, stdout
+log4j.rootCategory=DEBUG, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c-%X{Replica}] - %m%n
+log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c] - %m%n
#log4j.appender.stdout.layout.ConversionPattern=[%d{HH:mm:ss}] %p [%c-%X{Replica}] %C{1}.%M@%L - %m%n
log4j.appender.file=org.apache.log4j.RollingFileAppender
@@ -30,3 +30,6 @@
#log4j.logger.org=FATAL
log4j.logger.org.apache.directory.mavibot.btree=ERROR
+log4j.logger.LOG_PAGES=ERROR
+log4j.logger.LOG_CHECK=ERROR
+log4j.logger.net.sf.ehcache.Cache=ERROR