Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / store / access / btree / ControlRow.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/btree/ControlRow.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/btree/ControlRow.java
new file mode 100644 (file)
index 0000000..1b96bc0
--- /dev/null
@@ -0,0 +1,2149 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.btree.ControlRow\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to you under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+      http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.store.access.btree;\r
+\r
+\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.io.TypedFormat;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+\r
+import org.apache.derby.iapi.store.raw.AuxObject;\r
+import org.apache.derby.iapi.store.raw.FetchDescriptor;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.types.SQLLongint;\r
+import org.apache.derby.impl.store.access.StorableFormatId;\r
+\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;\r
+\r
+/**\r
+\r
+Base class for leaf and branch control rows.\r
+<P>\r
+<B>Concurrency Notes</B>\r
+<P>\r
+All access through control rows is serialized by an exclusive latch on \r
+the page the control row is for.  The page is latched when the control\r
+row is "gotten" (ControlRow#Get), and unlatched when the control row\r
+is released (ControlRow#release).\r
+<P>\r
+<B>To Do List</B>\r
+<UL>\r
+<LI> <I>[NOTE1]</I>\r
+The code is arranged to fault in fields from the row as necessary.\r
+many of the fields of a control row are rarely used (left sibling, parent).\r
+The accessors fault in the underlying column only when\r
+requested by allocating the appropriate object and calling fetchFromSlot and\r
+only fetching the requested field.\r
+<LI> <I>[NOTE2]</I> \r
+Currently, all the fields of the control row are stored as StorableU8s\r
+for simplicity.  This is too few bits to hold the long page numbers, and\r
+too many to hold the version, level, and isRoot flag.  Some consideration\r
+will have to be given to the appropriate storage format for these values.\r
+<LI> <I>[NOTE3]</I>\r
+The implementation relies on the existance of page "auxiliary" pointers \r
+which keep Object versions of the control row.\r
+<P>\r
+@see ControlRow#get\r
+@see ControlRow#release\r
+\r
+**/\r
+\r
+public abstract class ControlRow implements AuxObject, TypedFormat\r
+{\r
+    /**\r
+     * Version indentifier of the control row within the page.  \r
+     * <p>\r
+     * This is the format id of the control row.  The format id is currently\r
+     * one of either StoredFormatIds.ACCESS_BTREE_LEAFCONTROLROW_ID or\r
+     * StoredFormatIds.ACCESS_BTREE_BRANCHCONTROLROW_ID.\r
+     **/\r
+    private StorableFormatId    version = null;\r
+\r
+    /**\r
+     * Pointer to page which is "left" at the current level.\r
+     * <p>\r
+     * Currently all pages at a level are doubly linked.  The leftmost page\r
+     * in a level has a leftSiblingPageNumber == \r
+     * ContainerHandle.INVALID_PAGE_NUMBER.  All key values on the page which\r
+     * is left must precede the first key value on the current page.\r
+     **/\r
+       private SQLLongint leftSiblingPageNumber;\r
+\r
+    /**\r
+     * Pointer to page which is "right" at the current level.\r
+     * <p>\r
+     * Currently all pages at a level are doubly linked.  The rightmost page\r
+     * in a level has a rightSiblingPageNumber == \r
+     * ContainerHandle.INVALID_PAGE_NUMBER.  All key values on the page which\r
+     * is right of the current page must follow the last key value on the \r
+     * current page.\r
+     **/\r
+       private SQLLongint rightSiblingPageNumber;\r
+\r
+    /**\r
+     * The parent page of the current page.\r
+     * <p>\r
+     * For consistency checking it is useful to maintain the parentPageNumber\r
+     * field of the current page.  The root page has a value of \r
+     * ContainerHandle.INVALID_PAGE_NUMBER in it's parentPageNumber field.\r
+     * <p>\r
+     * RESOLVE (mikem) - we need to come up with some way to not maintain these,\r
+     * maybe by providing a property on secondary index or a different 2nd \r
+     * index.\r
+     *\r
+     **/\r
+       private SQLLongint parentPageNumber; // for consistency checking\r
+\r
+\r
+    /**\r
+     * The level of the btree.\r
+     * <p>\r
+     * The leaf level of the btree is 0.  The first branch level (parent level\r
+     * of the leaf), is level 1.  The height of the btree is (level + 1).\r
+     * <p>\r
+     * The smallest btree is a one page btree with only a leaf, and no branch\r
+     * pages. \r
+     **/\r
+       private SQLLongint level;\r
+\r
+    /**\r
+     * Is this page the root of the btree?\r
+     * <p>\r
+     * Currently "1" if the page is the root page, else "0".\r
+     * <p>\r
+     * RESOLVE (mikem) When real datatype come about, this value should \r
+     * probably be just a bit in some status word.\r
+     **/\r
+       private SQLLongint isRoot = null;\r
+\r
+    /**\r
+     * A copy of the Conglomerate that describes the owning conglom.\r
+     * <p>\r
+     * This information is used during logical undo to get the type information\r
+     * so that rows can be compared and searched for.  We may be able to get\r
+     * away with a subset of the information stored in the conglomerate.\r
+     * <p>\r
+     * RESOLVE (mikem) - change this to only store the info on the root page.\r
+     **/\r
+    private BTree    btree = null;\r
+\r
+    /**\r
+     * The page that this control row describes.\r
+     **/\r
+       protected Page page;\r
+\r
+    /**\r
+     * The page that this control row describes.\r
+     **/\r
+       protected DataValueDescriptor row[];\r
+\r
+    /**\r
+     * row used to replace fetchFieldFromSlot() calls.\r
+     **/\r
+    protected DataValueDescriptor[] scratch_row;\r
+\r
+    /**\r
+     * FetchDescriptor used to replace fetchFieldFromSlot() calls.\r
+     **/\r
+    protected FetchDescriptor   fetchDesc;\r
+\r
+    /**\r
+     * In memory hint about whether to use the last_search_result hint during\r
+     * search.\r
+     **/\r
+    transient protected boolean use_last_search_result_hint = false;\r
+\r
+    /**\r
+     * In memory hint about where to begin the binary search to find a key\r
+     * on the the current control page.\r
+     **/\r
+    transient protected int last_search_result = 0;\r
+\r
+    /**\r
+     * Column number assignments for columns of the control row.\r
+     * <p>\r
+     * The control row is stored as the first row in a btree page.  The row\r
+     * is an array of columns.  The Control row columns are the columns numbered\r
+     * from ControlRow.CR_COLID_FIRST through ControlRow.CR_COLID_LAST.  The\r
+     * classes which implement the concrete derived classes of ControlRow may\r
+     * add columns to the control row, but they must be added after the \r
+     * ControlRow columns.\r
+     **/\r
+       protected static final int CR_COLID_FIRST               = 0;\r
+       protected static final int CR_VERSION_COLID             = CR_COLID_FIRST + 0;\r
+       protected static final int CR_LEFTSIB_COLID             = CR_COLID_FIRST + 1;\r
+       protected static final int CR_RIGHTSIB_COLID    = CR_COLID_FIRST + 2;\r
+       protected static final int CR_PARENT_COLID              = CR_COLID_FIRST + 3;\r
+       protected static final int CR_LEVEL_COLID               = CR_COLID_FIRST + 4;\r
+       protected static final int CR_ISROOT_COLID              = CR_COLID_FIRST + 5;\r
+       protected static final int CR_CONGLOM_COLID         = CR_COLID_FIRST + 6;\r
+       protected static final int CR_COLID_LAST                = CR_CONGLOM_COLID;\r
+       protected static final int CR_NCOLUMNS                  = CR_COLID_LAST + 1;\r
+\r
+    /**\r
+     * bit sets used to fetch single columns at a time.\r
+     **/\r
+    protected static final FormatableBitSet   CR_VERSION_BITSET = \r
+        new FormatableBitSet(CR_VERSION_COLID + 1);\r
+    protected static final FormatableBitSet   CR_LEFTSIB_BITSET = \r
+        new FormatableBitSet(CR_LEFTSIB_COLID + 1);\r
+    protected static final FormatableBitSet   CR_RIGHTSIB_BITSET =\r
+        new FormatableBitSet(CR_RIGHTSIB_COLID + 1);\r
+    protected static final FormatableBitSet   CR_PARENT_BITSET =\r
+        new FormatableBitSet(CR_PARENT_COLID + 1);\r
+    protected static final FormatableBitSet   CR_LEVEL_BITSET =\r
+        new FormatableBitSet(CR_LEVEL_COLID + 1);\r
+    protected static final FormatableBitSet   CR_ISROOT_BITSET =\r
+        new FormatableBitSet(CR_ISROOT_COLID + 1);\r
+    protected static final FormatableBitSet   CR_CONGLOM_BITSET =\r
+        new FormatableBitSet(CR_CONGLOM_COLID + 1);\r
+\r
+\r
+    /**\r
+     * Values passed in the flag argument to splitFor.\r
+     **/\r
+    /* row causing split would be last row on leaf page */\r
+    public static final int SPLIT_FLAG_LAST_ON_PAGE      = 0x000000001;\r
+    /* row causing split would be last row in table */\r
+    public static final int SPLIT_FLAG_LAST_IN_TABLE     = 0x000000002;\r
+    /* row causing split would be first row on page */\r
+    public static final int SPLIT_FLAG_FIRST_ON_PAGE     = 0x000000004;\r
+    /* row causing split would be first row in table */\r
+    public static final int SPLIT_FLAG_FIRST_IN_TABLE    = 0x000000008;\r
+\r
+    /**\r
+     * The slot at which all control rows reside.\r
+     **/\r
+       protected static final int CR_SLOT = 0;\r
+\r
+       /*\r
+       ** Constructors of ControlRow\r
+       */\r
+\r
+    static \r
+    {\r
+        CR_VERSION_BITSET.set(CR_VERSION_COLID);\r
+        CR_LEFTSIB_BITSET.set(CR_LEFTSIB_COLID);\r
+        CR_RIGHTSIB_BITSET.set(CR_RIGHTSIB_COLID);\r
+        CR_PARENT_BITSET.set(CR_PARENT_COLID);\r
+        CR_LEVEL_BITSET.set(CR_LEVEL_COLID);\r
+        CR_ISROOT_BITSET.set(CR_ISROOT_COLID);\r
+        CR_CONGLOM_BITSET.set(CR_CONGLOM_COLID);\r
+    }\r
+\r
+    /**\r
+     * No arg constructor.\r
+     * <p>\r
+     * GetControlRowForPage() will call this constructor when it uses the \r
+     * monitor to create a control row dynamically given a given format id.\r
+     **/\r
+    protected ControlRow()\r
+    {\r
+        this.scratch_row = \r
+            new DataValueDescriptor[getNumberOfControlRowColumns()];\r
+\r
+        this.fetchDesc   = \r
+            new FetchDescriptor(\r
+                this.scratch_row.length, (FormatableBitSet) null, (Qualifier[][]) null);\r
+    }\r
+\r
+    /**\r
+     * Constructor for making a new control row as part of allocating a new\r
+        * page.  Fills in all the fields but does not write them anywhere.\r
+     * <p>\r
+        * <P>\r
+        * Changes to this constructor will probably require changes to the\r
+        * corresponding accessor(s).\r
+     *\r
+     * @param btree      Static information about the btree.\r
+     * @param page       The page described by this control row.\r
+     * @param parent     The parent page of this page, "null" if this page is \r
+     *                   root or if not maintaining parent links.\r
+     * @param isRoot     Is this page the root of the tree?\r
+     *\r
+     *\r
+     * @exception StandardException Standard exception policy.\r
+     **/\r
+       protected ControlRow(\r
+    OpenBTree         btree,\r
+    Page                     page, \r
+    int                              level, \r
+    ControlRow       parent,\r
+    boolean           isRoot\r
+    )\r
+        throws StandardException\r
+       {\r
+               // The caller is expected to have latched the pages.\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(page.isLatched());\r
+            SanityManager.ASSERT(parent == null || parent.page.isLatched());\r
+        }\r
+\r
+               // Maintain which page this control row describes.\r
+               this.page = page;\r
+\r
+               // Page numbers start out "invalid".  Presumably the caller will\r
+               // link the page into a page chain as one of its next steps.\r
+               leftSiblingPageNumber  = \r
+            new SQLLongint(btree.container.INVALID_PAGE_NUMBER);\r
+               rightSiblingPageNumber = \r
+            new SQLLongint(btree.container.INVALID_PAGE_NUMBER);\r
+\r
+               // Remember the parent if there is one and we're remembering parents.\r
+        parentPageNumber = new SQLLongint( \r
+            (parent == null ?  \r
+                 btree.container.INVALID_PAGE_NUMBER : \r
+                 parent.page.getPageNumber()));\r
+\r
+               // All pages start out not being root pages.  The caller will setIsRoot\r
+               // if this is going to be a root page. Zero means false - see \r
+               // getIsRoot/setIsRoot.\r
+               this.isRoot = new SQLLongint(isRoot ? 1 : 0);\r
+\r
+        // set the rest of the state, as passed in.\r
+               this.level   = new SQLLongint(level);\r
+        this.version = new StorableFormatId(getTypeFormatId());\r
+\r
+        // If it is a root page then store the real btree conglomerate, if it\r
+        // is not a root page then set up an "empty" btree conglomerate which\r
+        // will be stored as "null".\r
+        this.btree = \r
+            (isRoot ? \r
+             btree.getConglomerate() : \r
+             (BTree) Monitor.newInstanceFromIdentifier(\r
+                btree.getConglomerate().getTypeFormatId()));\r
+\r
+        // Initialize the object array to be used for interacting with raw\r
+        // store to insert, fetch, and update the control row.\r
+        this.row = new DataValueDescriptor[getNumberOfControlRowColumns()];\r
+           this.row[CR_VERSION_COLID]  = this.version;\r
+           this.row[CR_LEFTSIB_COLID]  = this.leftSiblingPageNumber;\r
+           this.row[CR_RIGHTSIB_COLID] = this.rightSiblingPageNumber;\r
+           this.row[CR_PARENT_COLID]   = this.parentPageNumber;\r
+           this.row[CR_LEVEL_COLID]    = this.level;\r
+           this.row[CR_ISROOT_COLID]   = this.isRoot;\r
+           this.row[CR_CONGLOM_COLID]  = this.btree;\r
+\r
+\r
+               // Make the control row the aux object for the page so control row\r
+               // getters end up with the same row.\r
+               page.setAuxObject(this);\r
+       }\r
+\r
+    /**\r
+     * Constructor for making a control row for an existing page.\r
+     * <p>\r
+     * Not all the fields are filled in; their values will get faulted in from \r
+     * the page as necessary.\r
+     * <p>\r
+        * Classes which extend ControlRow must delegate to this constructor\r
+        * and may want to override it as well.\r
+        * Changes to this constructor will probably require changes to the\r
+        * corresponding accessor(s).\r
+     *\r
+     * @param container  Open container \r
+     * @param page       The page described by this control row.\r
+     *\r
+     * @exception StandardException Standard exception policy.\r
+     **/\r
+       protected ControlRow(ContainerHandle container, Page page)\r
+        throws StandardException\r
+       {\r
+        System.out.println("ControlRow construct 2.");\r
+\r
+               // The caller is expected to have latched the pages.\r
+        if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(page.isLatched());\r
+\r
+               // Remember the page.\r
+               this.page = page;\r
+\r
+               // The rest of the fields are left null; they'll get faulted\r
+               // in if/when necessary.  See the accessors.\r
+       }\r
+\r
+    /* Private/Protected methods of ControlRow: */\r
+\r
+    /**\r
+     * Get version of the control row.\r
+     * <p>\r
+     * Returns the version of the control row, faulting it in from the page\r
+     * if necessary.\r
+     *\r
+        * @return version of the control row.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected int getVersion()\r
+               throws StandardException\r
+       {\r
+               if (this.version == null)\r
+               {\r
+                       // Fault in the version.\r
+                       this.version = new StorableFormatId();\r
+\r
+            scratch_row[CR_VERSION_COLID] = this.version;\r
+\r
+            fetchDesc.setValidColumns(CR_VERSION_BITSET);\r
+\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+               return this.version.getValue();\r
+       }\r
+\r
+    /**\r
+     * Set version of the control row.\r
+     * <p>\r
+     * Sets the version of the control row.  Updates both the in-memory \r
+     * control row and the disk copy.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected void setVersion(int version)\r
+               throws StandardException\r
+       {\r
+               // Store the field.\r
+               if (this.version == null)\r
+                       this.version = new StorableFormatId();\r
+               this.version.setValue(version);\r
+\r
+               // Write the field through to the underlying row.\r
+               this.page.updateFieldAtSlot(\r
+            CR_SLOT, CR_VERSION_COLID, this.version, null);\r
+       }\r
+\r
+       /**\r
+        * Get the control row for this page's left sibling, or null if there is no\r
+        * left sibling (which probably means it's the leftmost page at its level).\r
+        * Since right-to-left traversal of an index level      is deadlock-prone, this \r
+        * method will only get get the left sibling if it can latch it without\r
+        * waiting.\r
+     *\r
+        * @exception WaitError if the latch request would have had to wait.\r
+     *\r
+     * @exception StandardException Standard exception policy.\r
+        **/\r
+       public ControlRow getLeftSibling(OpenBTree btree)\r
+               throws StandardException, WaitError\r
+       {\r
+               ControlRow cr;\r
+               \r
+               long pageno = this.getleftSiblingPageNumber();\r
+\r
+               // Is there a left sibling?\r
+               if (pageno == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       return null;\r
+\r
+               // Try to get the control row without waiting\r
+               cr = ControlRow.getNoWait(btree, pageno);\r
+               if (cr == null)\r
+                       throw new WaitError();\r
+\r
+               return cr;\r
+       }\r
+\r
+       protected void setLeftSibling(ControlRow leftsib)\r
+        throws StandardException\r
+       {\r
+        long left_sib_pageno = \r
+            (leftsib == null ? ContainerHandle.INVALID_PAGE_NUMBER : \r
+                               leftsib.page.getPageNumber());\r
+        \r
+               // Store the field.\r
+               if (leftSiblingPageNumber == null)\r
+                       leftSiblingPageNumber = new SQLLongint(left_sib_pageno);\r
+        else\r
+            this.leftSiblingPageNumber.setValue(left_sib_pageno);\r
+\r
+               // Write the field through to the underlying row\r
+        try\r
+        {\r
+            this.page.updateFieldAtSlot(\r
+                CR_SLOT, CR_LEFTSIB_COLID, this.leftSiblingPageNumber, null);\r
+        }\r
+        catch (StandardException se)\r
+        {\r
+            // Since this is an update of a fixed length field it should \r
+            // never fail, but it has happened enough that an assert helps\r
+            // with debugging.\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "setLeftSibling got an exception: " +\r
+                    "control_row = " + this +\r
+                    "trying to update field number " + CR_LEFTSIB_COLID + \r
+                    "to new value " + this.leftSiblingPageNumber, se);\r
+            }\r
+            throw(se);\r
+        }\r
+       }\r
+\r
+       /**\r
+       Return the control row for this page's right sibling.  Unlike getting\r
+       the left sibling, it's ok to wait for the right sibling latch since\r
+       left-to-right is the deadlock-free ordering.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       protected ControlRow getRightSibling(OpenBTree open_btree)\r
+               throws StandardException\r
+       {\r
+               long pageno = this.getrightSiblingPageNumber();\r
+\r
+               // Return the control row for the page.\r
+               if (pageno == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       return null;\r
+               else\r
+                       return ControlRow.get(open_btree, pageno);\r
+       }\r
+\r
+       // This method will have to update the row.\r
+       protected void setRightSibling(ControlRow rightsib)\r
+        throws StandardException\r
+       {\r
+        long right_sib_pageno = \r
+            (rightsib == null ? ContainerHandle.INVALID_PAGE_NUMBER : \r
+                                rightsib.page.getPageNumber());\r
+        \r
+               // Store the field.\r
+               if (rightSiblingPageNumber == null)\r
+                       rightSiblingPageNumber = new SQLLongint(right_sib_pageno);\r
+        else\r
+            this.rightSiblingPageNumber.setValue(right_sib_pageno);\r
+\r
+               // Write the field through to the underlying row\r
+        try\r
+        {\r
+               this.page.updateFieldAtSlot(\r
+            CR_SLOT, CR_RIGHTSIB_COLID, this.rightSiblingPageNumber, null);\r
+        }\r
+        catch (StandardException se)\r
+        {\r
+            // Since this is an update of a fixed length field it should \r
+            // never fail, but it has happened enough that an assert helps\r
+            // with debugging.\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "setRightSibling got an exception: " +\r
+                    "control_row = " + this +\r
+                    "trying to update field number " + CR_RIGHTSIB_COLID + \r
+                    "to new value " + this.rightSiblingPageNumber, se);\r
+            }\r
+            throw(se);\r
+        }\r
+       }\r
+\r
+       /**\r
+       Get the page number of the left sibling. Fault it's value in if it\r
+    hasn't been yet.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public long getleftSiblingPageNumber()\r
+        throws StandardException\r
+       {\r
+               if (this.leftSiblingPageNumber == null)\r
+               {\r
+                       // Fault in the page number.\r
+                       this.leftSiblingPageNumber = new SQLLongint();\r
+\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(scratch_row != null);\r
+\r
+            scratch_row[CR_LEFTSIB_COLID] = this.leftSiblingPageNumber;\r
+\r
+            fetchDesc.setValidColumns(CR_LEFTSIB_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+\r
+               }\r
+\r
+        return(leftSiblingPageNumber.getLong());\r
+       }\r
+\r
+       /**\r
+       Get the page number of the right sibling. Fault it's value in if it\r
+    hasn't been yet.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       protected long getrightSiblingPageNumber()\r
+        throws StandardException\r
+       {\r
+               if (this.rightSiblingPageNumber == null)\r
+               {\r
+                       // Fault in the page number.\r
+                       this.rightSiblingPageNumber = new SQLLongint();\r
+\r
+            scratch_row[CR_RIGHTSIB_COLID] = this.rightSiblingPageNumber;\r
+\r
+            fetchDesc.setValidColumns(CR_RIGHTSIB_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+\r
+        return(rightSiblingPageNumber.getLong());\r
+       }\r
+\r
+       /**\r
+       Get the page number of the parent, if it's being maintained.\r
+       Note that there is intentionally no way to get the control\r
+       row for the parent page - the b-tree code NEVER traverses\r
+       up the tree, even in consistency checks.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       protected long getParentPageNumber()\r
+        throws StandardException\r
+       {\r
+               if (this.parentPageNumber == null)\r
+               {\r
+                       // Fault in the page number.\r
+                       this.parentPageNumber = new SQLLongint();\r
+\r
+            scratch_row[CR_PARENT_COLID] = this.parentPageNumber;\r
+\r
+            fetchDesc.setValidColumns(CR_PARENT_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+\r
+               // See NOTE3 about converting from int to long.\r
+               long pageno = parentPageNumber.getLong();\r
+               return pageno;\r
+       }\r
+       \r
+       void setParent(long parent)\r
+        throws StandardException\r
+       {\r
+               // Store the field.\r
+               if (parentPageNumber == null)\r
+                       parentPageNumber = new SQLLongint();\r
+               this.parentPageNumber.setValue(parent);\r
+\r
+               // Write the field through to the underlying row\r
+        try\r
+        {\r
+            this.page.updateFieldAtSlot(\r
+                CR_SLOT, CR_PARENT_COLID, this.parentPageNumber, null);\r
+        }\r
+        catch (StandardException se)\r
+        {\r
+            // Since this is an update of a fixed length field it should \r
+            // never fail, but it has happened enough that an assert helps\r
+            // with debugging.\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "setParent got an exception: " +\r
+                    "control_row = " + this +\r
+                    "trying to update field number " + CR_PARENT_COLID + \r
+                    "to new value " + this.parentPageNumber, se);\r
+            }\r
+            throw(se);\r
+        }\r
+\r
+        return;\r
+       }\r
+\r
+       protected int getLevel()\r
+        throws StandardException\r
+       {\r
+               if (this.level == null)\r
+               {\r
+                       // Fault in the level\r
+                       this.level = new SQLLongint();\r
+\r
+            scratch_row[CR_LEVEL_COLID] = this.level;\r
+\r
+            fetchDesc.setValidColumns(CR_LEVEL_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+\r
+               return((int) this.level.getLong());\r
+       }\r
+\r
+       protected void setLevel(int newlevel)\r
+        throws StandardException\r
+       {\r
+               // Store the field.\r
+               if (this.level == null)\r
+                       this.level = new SQLLongint();\r
+               this.level.setValue((long) newlevel);\r
+\r
+               // Write the field through to the underlying row.\r
+               this.page.updateFieldAtSlot(CR_SLOT, CR_LEVEL_COLID, this.level, null);\r
+       }\r
+\r
+       protected boolean getIsRoot()\r
+        throws StandardException\r
+       {\r
+               // convert 1 to true, 0 to false;\r
+        \r
+               if (this.isRoot == null)\r
+               {\r
+                       // Fault in the level\r
+                       this.isRoot = new SQLLongint();\r
+\r
+            scratch_row[CR_ISROOT_COLID] = this.isRoot;\r
+\r
+            fetchDesc.setValidColumns(CR_ISROOT_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+\r
+               return((this.isRoot.getLong() == 1));\r
+       }\r
+       \r
+       protected void setIsRoot(boolean isRoot)\r
+        throws StandardException\r
+       {\r
+        // RESOLVE (mmm) - need to store more efficiently //\r
+\r
+               // Store the field.\r
+               if (this.isRoot == null)\r
+                       this.isRoot = new SQLLongint();\r
+\r
+               this.isRoot.setValue((isRoot) ? 1 : 0);\r
+\r
+               // Write the field through to the underlying row.\r
+               this.page.updateFieldAtSlot(\r
+            CR_SLOT, CR_ISROOT_COLID, this.isRoot, null);\r
+       }\r
+\r
+    /**\r
+     * Get format id information for row on page.\r
+     * <p>\r
+     * Returns the format id information for a row on the page. faulting it \r
+     * in from the page if necessary.\r
+     *\r
+        * @return format id of a row on the page.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       public BTree getConglom(int format_id)\r
+               throws StandardException\r
+       {\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // this call is only valid on root pages.  If called on non\r
+            // root pages it will return a "null" conglom object.\r
+            SanityManager.ASSERT(\r
+                (this.page.getPageNumber() == BTree.ROOTPAGEID) && getIsRoot());\r
+        }\r
+\r
+               if (this.btree == null)\r
+               {\r
+            // use format id to create empty instance of Conglomerate class\r
+            this.btree = (BTree) Monitor.newInstanceFromIdentifier(format_id);\r
+\r
+            scratch_row[CR_CONGLOM_COLID] = this.btree;\r
+\r
+            fetchDesc.setValidColumns(CR_CONGLOM_BITSET);\r
+            this.page.fetchFromSlot(\r
+               (RecordHandle) null, CR_SLOT, scratch_row, fetchDesc, false); \r
+               }\r
+               return this.btree;\r
+       }\r
+\r
+    /**\r
+     * Set the conglomerate field in the btree.\r
+     * <p>\r
+     * Sets the btree field of the control row.  Updates just the disk copy. \r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       private void setConglom(BTree btree)\r
+               throws StandardException\r
+       {\r
+               // Store the field.  Delay faulting value into object until getConlgom()\r
+        // call, which in general only happens during recovery.\r
+\r
+               // Write the field through to the underlying row.\r
+               this.page.updateFieldAtSlot(CR_SLOT, CR_CONGLOM_COLID, btree, null);\r
+       }\r
+\r
+       /*\r
+       ** Methods for getting control rows from pages.\r
+       */\r
+\r
+       /**\r
+         Get the control row from the given page in the b-tree.\r
+         The returned control row will be of the correct type\r
+         for the page (i.e., either a LeafControlRow or a\r
+         BranchControlRow).\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       public static ControlRow get(OpenBTree open_btree, long pageNumber)\r
+               throws StandardException\r
+       {\r
+        return(ControlRow.get(open_btree.container, pageNumber));\r
+       }\r
+\r
+       public static ControlRow get(ContainerHandle container, long pageNumber)\r
+               throws StandardException\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(container != null, \r
+                "ControlRow.Get() is being called on a closed container.");\r
+        }\r
+\r
+               // Get the page, waiting if necessary.  The page is returned latched.\r
+               Page page = container.getPage(pageNumber);\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+                       if (page == null)\r
+               SanityManager.THROWASSERT(\r
+                       "No page at pagenumber: " + pageNumber +\r
+                       "; ContainerHandle = "    + container);\r
+        }\r
+\r
+               // Return the corresponding control row.\r
+               return getControlRowForPage(container, page);\r
+       }\r
+\r
+       /**\r
+       Get the control row for the given page if the latch on the\r
+       page can be obtained without waiting, else return null.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public static ControlRow getNoWait(\r
+    OpenBTree       open_btree, \r
+    long            pageNumber)\r
+               throws StandardException\r
+       {\r
+               // Try to get the page without waiting.  If we would have\r
+               // to wait, return null.\r
+               Page page = open_btree.container.getUserPageNoWait(pageNumber);\r
+               if (page == null)\r
+                       return null; \r
+\r
+               // Got the page without waiting.  Return the corresponding\r
+               // control row.\r
+               return getControlRowForPage(open_btree.container, page);\r
+       }\r
+\r
+       protected static ControlRow getControlRowForPage(\r
+    ContainerHandle container,\r
+    Page            page)\r
+        throws StandardException\r
+       {\r
+        ControlRow cr = null;\r
+\r
+               // See if the control row is still cached with the page\r
+               // If so, just use the cached control row.\r
+               AuxObject auxobject = page.getAuxObject();\r
+               if (auxobject != null)\r
+                       return (ControlRow) auxobject;\r
+\r
+        if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(page.recordCount() >= 1);\r
+\r
+               // No cached control row, so create a new one.\r
+        \r
+        // Use the version field to determine the type of the row to\r
+        // create.  This routine depends on the version field being the same\r
+        // number column in all control rows.\r
+        \r
+        StorableFormatId version = new StorableFormatId();\r
+\r
+        DataValueDescriptor[] version_ret = new DataValueDescriptor[1];\r
+        \r
+        version_ret[0] = version;\r
+\r
+        // TODO (mikem) - get rid of this new.\r
+\r
+        page.fetchFromSlot(\r
+           (RecordHandle) null, CR_SLOT, version_ret,\r
+           new FetchDescriptor(1, CR_VERSION_BITSET, (Qualifier[][]) null), \r
+           false); \r
+\r
+        // use format id to create empty instance of right Conglomerate class\r
+        cr = (ControlRow) Monitor.newInstanceFromIdentifier(version.getValue());\r
+        cr.page = page;\r
+\r
+        // call page specific initialization.\r
+        cr.controlRowInit();\r
+\r
+        // cache this Control row with the page in the cache.\r
+               page.setAuxObject(cr);\r
+\r
+        return(cr);\r
+       }\r
+\r
+       /**\r
+       Release this control row's resources.\r
+       **/\r
+       public void release()\r
+       {\r
+        if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(page != null);\r
+\r
+        if (page != null)\r
+            page.unlatch();\r
+\r
+               // It might be nice to set the page object to null, but\r
+               // since there might be multiple control rows on this\r
+               // page, we'd have to maintain a use count.  Rather than\r
+               // doing that we'll let the garbage collector earn its\r
+               // keep.  We are also expecting that the raw store will\r
+               // throw errors if we attempt to use an unlatched page.\r
+       }\r
+\r
+    /**\r
+    Search this index page.\r
+    <P>\r
+    This method is very performance sensitive.  It is the intention that no\r
+    object allocations occur during the execution of this method.\r
+    <P>\r
+    This method performs a binary search on the page and finds the entry i on\r
+    the page such that entry[i] <= key < entry[i+1].  The result of the search\r
+    is filled into the passed in params structure.\r
+\r
+    @param params the parameters of the search\r
+\r
+    @exception StandardException could be thrown by underlying raw store \r
+    operations.\r
+\r
+    @see SearchParameters\r
+    **/\r
+    protected void searchForEntry(SearchParameters params)\r
+               throws StandardException\r
+    {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // System.out.println("searchForEntry() enter: params:" + params);\r
+            // System.out.println("searchForEntry() enter: this:"   + this);\r
+            // System.out.println("searchForEntry() enter: this page:"   + debugPage(params.btree));\r
+        }\r
+\r
+\r
+        // leftrange and rightrange indicates the range of slots to search.\r
+        // The range starts as all the slots on the page not including slot\r
+        // 0 which is the control row.\r
+        int leftrange  = 1;\r
+        int rightrange = page.recordCount() - 1;\r
+\r
+        // leftslot and rightslot if non-zero, mean that the key has been\r
+        // compared to the row at that slot.  If non-zero the key must be\r
+        // greater than the key at leftslot and the key must be lest than\r
+        // the key at rightslot.\r
+        int leftslot  = 0;\r
+        int rightslot = rightrange + 1;\r
+\r
+        int midslot;\r
+        int compare_ret;\r
+\r
+        // search until you either exactly find the key, or you have \r
+        // compared 2 adjacent rows and found the value must exist between\r
+        // the 2.\r
+\r
+\r
+        if (this.use_last_search_result_hint)\r
+        {\r
+            // make sure to set midslot to point to somwhere in the legal range.\r
+            midslot = \r
+                ((this.last_search_result == 0) ? 1 : this.last_search_result);\r
+\r
+            if (midslot > rightrange)\r
+                midslot = rightrange;\r
+        }\r
+        else\r
+        {\r
+            // if we don't think we have a good hint where to start the search\r
+            // just go to the middle.\r
+            midslot = (leftrange + rightrange) / 2;\r
+        }\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if ((leftslot != (rightslot - 1)) &&\r
+                !(midslot >= leftrange && midslot <= rightrange))\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "midslot = "     + midslot +\r
+                    ";leftrange = "  + leftrange +\r
+                    ";rightrange = " + rightrange);\r
+            }\r
+        }\r
+\r
+        \r
+        while (leftslot != (rightslot - 1))\r
+        {\r
+                       // Compare the index row to the key.\r
+                       compare_ret = \r
+                compareIndexRowFromPageToKey(\r
+                    this,\r
+                    midslot,\r
+                    params.template, params.searchKey, \r
+                    params.btree.getConglomerate().nUniqueColumns, \r
+                    params.partial_key_match_op,\r
+                    params.btree.getConglomerate().ascDescInfo);\r
+\r
+            if (compare_ret == 0)\r
+            {\r
+                // Found exact match\r
+                               params.resultSlot = midslot;\r
+                               params.resultExact = true;\r
+\r
+                // update the hints based on result of the search.\r
+                use_last_search_result_hint = \r
+                    (midslot == this.last_search_result) ? true : false;\r
+                this.last_search_result = midslot;\r
+\r
+                return;\r
+            }\r
+            else if (compare_ret > 0)\r
+            {\r
+                // key falls to the left of midslot\r
+                rightslot  = midslot;\r
+                rightrange = midslot - 1;\r
+            }\r
+            else\r
+            {\r
+                // key falls to the right of midslot\r
+                leftslot   = midslot;\r
+                leftrange  = midslot + 1;\r
+            }\r
+\r
+            midslot = (leftrange + rightrange) / 2;\r
+            //midslot = (leftrange + rightrange) >> 1;\r
+        }\r
+\r
+        // update the hints based on result of the search.\r
+        this.use_last_search_result_hint = \r
+            (leftslot == this.last_search_result);\r
+        this.last_search_result = leftslot;\r
+\r
+        // no exact match found, leftslot will point at the slot on the\r
+        // page just before where the row should be inserted.  In the case\r
+        // where the key is before rows on the page then leftslot will be\r
+        // 0 (an empty page is a special case of this).\r
+        if (SanityManager.DEBUG)\r
+        {\r
+                       if (leftslot != rightslot - 1)\r
+               SanityManager.THROWASSERT(\r
+                       "leftslot = " + leftslot + "; rightslot = " + rightslot);\r
+        }\r
+\r
+        params.resultSlot  = leftslot;\r
+        params.resultExact = false;\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // System.out.println("searchForEntry() exit: params:" + params);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+    protected void searchForEntryBackward(SearchParameters params)\r
+               throws StandardException\r
+    {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // System.out.println("searchForEntry() enter: params:" + params);\r
+            // System.out.println("searchForEntry() enter: this:"   + this);\r
+            // System.out.println("searchForEntry() enter: this page:"   + debugPage(params.btree));\r
+        }\r
+\r
+\r
+        // leftrange and rightrange indicates the range of slots to search.\r
+        // The range starts as all the slots on the page not including slot\r
+        // 0 which is the control row.\r
+        int leftrange  = 1;\r
+        int rightrange = page.recordCount() - 1;\r
+\r
+        // leftslot and rightslot if non-zero, mean that the key has been\r
+        // compared to the row at that slot.  If non-zero the key must be\r
+        // greater than the key at leftslot and the key must be lest than\r
+        // the key at rightslot.\r
+        int leftslot  = 0;\r
+        int rightslot = rightrange + 1;\r
+\r
+        int midslot;\r
+        int compare_ret;\r
+\r
+        // search until you either exactly find the key, or you have \r
+        // compared 2 adjacent rows and found the value must exist between\r
+        // the 2.\r
+\r
+\r
+        if (this.use_last_search_result_hint)\r
+        {\r
+            // make sure to set midslot to point to somwhere in the legal range.\r
+            midslot = \r
+                ((this.last_search_result == 0) ? 1 : this.last_search_result);\r
+\r
+            if (midslot > rightrange)\r
+                midslot = rightrange;\r
+        }\r
+        else\r
+        {\r
+            // if we don't think we have a good hint where to start the search\r
+            // just go to the middle.\r
+            midslot = (leftrange + rightrange) / 2;\r
+        }\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if ((leftslot != (rightslot - 1)) &&\r
+                !(midslot >= leftrange && midslot <= rightrange))\r
+            {\r
+                SanityManager.THROWASSERT(\r
+                    "midslot = "     + midslot +\r
+                    ";leftrange = "  + leftrange +\r
+                    ";rightrange = " + rightrange);\r
+            }\r
+        }\r
+\r
+        \r
+        while (leftslot != (rightslot - 1))\r
+        {\r
+                       // Compare the index row to the key.\r
+                       compare_ret = \r
+                compareIndexRowFromPageToKey(\r
+                    this,\r
+                    midslot,\r
+                    params.template, params.searchKey, \r
+                    params.btree.getConglomerate().nUniqueColumns, \r
+                    params.partial_key_match_op,\r
+                    params.btree.getConglomerate().ascDescInfo);\r
+\r
+            if (compare_ret == 0)\r
+            {\r
+                // Found exact match\r
+                               params.resultSlot = midslot;\r
+                               params.resultExact = true;\r
+\r
+                // update the hints based on result of the search.\r
+                use_last_search_result_hint = \r
+                    (midslot == this.last_search_result) ? true : false;\r
+                this.last_search_result = midslot;\r
+\r
+                return;\r
+            }\r
+            else if (compare_ret > 0)\r
+            {\r
+                // key falls to the left of midslot\r
+                rightslot  = midslot;\r
+                rightrange = midslot - 1;\r
+            }\r
+            else\r
+            {\r
+                // key falls to the right of midslot\r
+                leftslot   = midslot;\r
+                leftrange  = midslot + 1;\r
+            }\r
+\r
+            midslot = (leftrange + rightrange) / 2;\r
+            //midslot = (leftrange + rightrange) >> 1;\r
+        }\r
+\r
+        // update the hints based on result of the search.\r
+        this.use_last_search_result_hint = \r
+            (leftslot == this.last_search_result);\r
+        this.last_search_result = leftslot;\r
+\r
+        // no exact match found, leftslot will point at the slot on the\r
+        // page just before where the row should be inserted.  In the case\r
+        // where the key is before rows on the page then leftslot will be\r
+        // 0 (an empty page is a special case of this).\r
+        if (SanityManager.DEBUG)\r
+        {\r
+                       if (leftslot != rightslot - 1)\r
+               SanityManager.THROWASSERT(\r
+                       "leftslot = " + leftslot + "; rightslot = " + rightslot);\r
+        }\r
+\r
+        params.resultSlot  = leftslot;\r
+        params.resultExact = false;\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // System.out.println("searchForEntry() exit: params:" + params);\r
+        }\r
+\r
+        return;\r
+    }\r
+\r
+       /**\r
+       Compare two orderable rows, considering nCompareCols, and return -1, 0, or 1\r
+       depending on whether the first row (indexrow) is less than, equal to, or \r
+    greater than the second (key).  The key may have fewer columns present \r
+    than nCompareCols.\r
+\r
+       In such a case, if all the columns of the partial key match all of the \r
+    corresponding columns in the index row, then the value passed in in \r
+    partialKeyOrder is returned.  The caller should pass in partialKeyOrder=1 \r
+    if the index rows which match a partial key should be considered to be \r
+    greater than the partial key, and -1 if they should be considered to be \r
+    less.\r
+\r
+    This routine only reads objects off the page if it needs them, so if a \r
+    multi-part key differs in the first column the subsequent columns are not\r
+    read.\r
+\r
+    @param indexpage Controlrow of page to get target row from.\r
+    @param slot      Slot to get control row from.\r
+    @param indexrow template of the target row (the row in the index).\r
+       @param key the (possibly partial) search key.\r
+       @param nCompareCols the number of columns to compare.\r
+       @param partialKeyOrder what to return on a partial key match.\r
+       @param ascOrDesc column sort order information\r
+       @throws StandardException if lower levels have a problem.\r
+\r
+    @exception StandardException Standard exception policy.\r
+       **/\r
+       public static int compareIndexRowFromPageToKey(\r
+    ControlRow              indexpage,\r
+    int                     slot,\r
+    DataValueDescriptor[]   indexrow, \r
+    DataValueDescriptor[]      key,\r
+    int                     nCompareCols, \r
+    int                     partialKeyOrder,\r
+    boolean[]               ascOrDesc)\r
+        throws StandardException\r
+       {\r
+        int compare_result;\r
+\r
+               // Get the actual number of key columns present\r
+               // in the partial key.\r
+               int partialKeyCols = key.length;\r
+\r
+        // Fetch entire index row from page.\r
+        // RESOLVE (mikem) - it may be more efficient to fetch just the\r
+        // columns you need, but there is overhead currently in raw\r
+        // store, since to get to the n'th column you have to walk \r
+        // through the preceding n-1 columns.\r
+        indexpage.page.fetchFromSlot(\r
+            (RecordHandle) null, slot, indexrow, \r
+            (FetchDescriptor) null,\r
+            true);\r
+\r
+               // Compare corresponding columns in the index row and the key.\r
+               for (int i = 0; i < nCompareCols; i++)\r
+               {\r
+                       // See if we have run out of partial key columns.\r
+                       if (i >= partialKeyCols)\r
+                       {\r
+                               // All the columns of the partial key match, and \r
+                               // there are more columns in the index row.  We\r
+                               // want to return -1 or 1, depending on whether the\r
+                               // caller wants to direct the search to the beginning\r
+                               // of this key range or the beginning of the next\r
+                               // one.  If the caller passes in -1, the index row\r
+                               // will appear less than the partial key, sending the\r
+                               // search to the next range ("to the right").  If the\r
+                               // caller passes in 1, the index row will appear\r
+                               // to be greater than the search key, sending the search\r
+                               // to the beginning of the range ("to the left").\r
+                               return partialKeyOrder;\r
+                       }\r
+\r
+                       // Get the corresponding columns to compare\r
+\r
+                       // Orderable indexcol = (Orderable) indexrow[i];\r
+                       // Orderable keycol = (Orderable) key[i];\r
+\r
+                       // Compare them.\r
+                       // int r = indexcol.compare(keycol);\r
+\r
+            int r = indexrow[i].compare(key[i]);\r
+\r
+                       // If the columns don't compare equal, we're done.\r
+                       // Return the sense of the comparison.\r
+                       if (r != 0)\r
+                       {\r
+                               //coulmns could have been sorted in ascending or descending\r
+                               //order. depending on ascending/descending order search \r
+                               //direction will change.\r
+\r
+                               if (ascOrDesc[i])  // true - Ascending order\r
+                                       return r;\r
+                               else\r
+                                       return -r;\r
+                   }\r
+               }\r
+\r
+               // We made it through all the columns, and they must have\r
+               // all compared equal.  So return that the rows compare equal.\r
+               return 0;\r
+       }\r
+\r
+       public static int compareIndexRowToKey(\r
+    DataValueDescriptor[]   indexrow, \r
+    DataValueDescriptor[]   key,\r
+    int                     nCompareCols, \r
+    int                     partialKeyOrder,\r
+    boolean[]               ascOrDesc)\r
+        throws StandardException\r
+       {\r
+               // Get the actual number of key columns present\r
+               // in the partial key.\r
+               int partialKeyCols = key.length;\r
+\r
+               // Compare corresponding columns in the index row and the key.\r
+               for (int i = 0; i < nCompareCols; i++)\r
+               {\r
+                       // See if we have run out of partial key columns.\r
+                       if (i >= partialKeyCols)\r
+                       {\r
+                               // All the columns of the partial key match, and \r
+                               // there are more columns in the index row.  We\r
+                               // want to return -1 or 1, depending on whether the\r
+                               // caller wants to direct the search to the beginning\r
+                               // of this key range or the beginning of the next\r
+                               // one.  If the caller passes in -1, the index row\r
+                               // will appear less than the partial key, sending the\r
+                               // search to the next range ("to the right").  If the\r
+                               // caller passes in 1, the index row will appear\r
+                               // to be greater than the search key, sending the search\r
+                               // to the beginning of the range ("to the left").\r
+                               return partialKeyOrder;\r
+                       }\r
+\r
+                       // Get the corresponding columns to compare\r
+                       DataValueDescriptor indexcol = indexrow[i];\r
+                       DataValueDescriptor keycol = key[i];\r
+\r
+                       // Compare them.\r
+                       int r = indexcol.compare(keycol);\r
+\r
+                       // If the columns don't compare equal, we're done.\r
+                       // Return the sense of the comparison.\r
+                       if (r != 0)\r
+                       {\r
+                               if (ascOrDesc[i])  // true - column in ascending order\r
+                                       return r;\r
+                               else\r
+                                       return -r;\r
+                   }\r
+               }\r
+\r
+               // We made it through all the columns, and they must have\r
+               // all compared equal.  So return that the rows compare equal.\r
+               return 0;\r
+       }\r
+\r
+       /**\r
+        ** Perform consistency checks which are common to all\r
+        ** pages that derive from ControlRow (both leaf and \r
+        ** branch pages).  The checks are:\r
+        ** <menu>\r
+        ** <li> This page thinks the parent argument is actually\r
+        **      its parent.\r
+        ** <li> The level of this page is 1 less than the level of\r
+        **      the parent.\r
+        ** <li> All the rows on the page are in order.\r
+        ** <li> Both left and right siblings, if they exist, are at\r
+        **      the same level of this page.\r
+        ** <li> This page is the left sibling of its right sibling,\r
+        **      and it's the right sibling of its left sibling.\r
+        ** <li> The last row on the left sibling is < the first\r
+        **      row on this page.\r
+        ** <li> The first row on the right sibling is > than the\r
+        **      the last row on this page.\r
+        ** </menu>\r
+        ** Note that these last two are really only true if there\r
+        ** are never duplicate keys.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/  \r
+       protected void checkGeneric(\r
+    OpenBTree  btree, \r
+    ControlRow parent,\r
+    boolean    check_other_pages)\r
+        throws StandardException\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(this.page.recordCount() >= 1);\r
+            SanityManager.ASSERT(!this.page.isDeletedAtSlot(0));\r
+\r
+            // Make sure that we think we're a child of the parent.\r
+                       if (((parent != null) &&\r
+                 (parent.page.getPageNumber() != this.getParentPageNumber())))\r
+               SanityManager.THROWASSERT(this + " not child of " + parent);\r
+\r
+            // Check this page's level.\r
+                       if (((parent != null) &&\r
+                 (parent.getLevel() != this.getLevel() + 1)))\r
+               SanityManager.THROWASSERT(this +\r
+                                               " at wrong level when compared to parent:" + parent);\r
+            \r
+            // Check rows are in order.\r
+            checkRowOrder(btree, parent);\r
+\r
+            // Check siblings.\r
+            if (check_other_pages)\r
+                checkSiblings(btree);\r
+        }\r
+       }\r
+\r
+       /**\r
+        ** Check that all rows on the page are in order.  This\r
+        ** means that each key is > than the previous key.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       protected boolean checkRowOrder(OpenBTree btree, ControlRow parent)\r
+        throws StandardException\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            RecordHandle            lesser_handle   = null;\r
+            RecordHandle            greater_handle  = null;\r
+            DataValueDescriptor[]   lesser          = getRowTemplate(btree);\r
+            DataValueDescriptor[]   greater         = getRowTemplate(btree);\r
+            boolean                 is_consistent   = true;\r
+           \r
+            \r
+            int numslots = page.recordCount();\r
+            for (int i = ControlRow.CR_SLOT + 1; (i + 1) < numslots; i++)\r
+            {\r
+               lesser_handle = \r
+                   page.fetchFromSlot(\r
+                       (RecordHandle) null, i, lesser, \r
+                       (FetchDescriptor) null, true); \r
+               greater_handle = \r
+                   page.fetchFromSlot(\r
+                       (RecordHandle) null, i + 1, greater, \r
+                       (FetchDescriptor) null, true); \r
+\r
+               SanityManager.ASSERT(btree.getConglomerate().nUniqueColumns <= \r
+                                    btree.getConglomerate().nKeyFields);\r
+               int compare_result = \r
+                   compareIndexRowToKey(\r
+                       lesser, greater,\r
+                       btree.getConglomerate().nUniqueColumns, 0,\r
+                       btree.getConglomerate().ascDescInfo);\r
+\r
+               // >= 0 means that lesser >= greater\r
+                          if (compare_result >= 0)\r
+               {\r
+                   SanityManager.THROWASSERT(\r
+                       "Bad order of rows found in conglomerate: " + btree +\r
+                       "\n." +\r
+                       "compare result = " + compare_result + ".  " + \r
+                       "nKeyFields = "     + btree.getConglomerate().nKeyFields +\r
+                       ".\n" +  \r
+                       this + " rows " + (i) + " and " + (i + 1) +\r
+                       " out of order.\n" +\r
+                       "row[" + i + "] + "  + RowUtil.toString(lesser) + "\n" + \r
+                       "row[" + (i + 1) + "] + "  + RowUtil.toString(greater) +\r
+                       "\ndump of page = " + \r
+                           debugPage(btree) +\r
+                       "\ndump of parent page = " + \r
+                           ((parent != null) ? \r
+                                parent.debugPage(btree) : "null parent") +\r
+                       "\rawstore dump = " + this.page);\r
+\r
+                   is_consistent = false;\r
+               }\r
+            }\r
+            return(is_consistent);\r
+        }\r
+        else\r
+        {\r
+            return(true);\r
+        }\r
+       }\r
+\r
+    protected boolean compareRowsOnSiblings(\r
+        OpenBTree   btree,\r
+        ControlRow  left_sib,\r
+        ControlRow  right_sib)\r
+            throws StandardException\r
+    {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            boolean is_consistent = true;\r
+\r
+            // Check that left last row is < right page's first row.\r
+            if (left_sib.page.recordCount()  > 1 && \r
+                right_sib.page.recordCount() > 1)\r
+            {\r
+                DataValueDescriptor[] left_lastrow   = getRowTemplate(btree);\r
+                DataValueDescriptor[] right_firstrow = getRowTemplate(btree);\r
+\r
+                RecordHandle    left_lastrow_handle   = \r
+                    left_sib.page.fetchFromSlot(\r
+                        (RecordHandle) null, left_sib.page.recordCount() - 1, \r
+                        left_lastrow, \r
+                        (FetchDescriptor) null, true); \r
+\r
+                RecordHandle    right_firstrow_handle  = \r
+                    right_sib.page.fetchFromSlot(\r
+                        (RecordHandle) null, 1, right_firstrow, \r
+                        (FetchDescriptor) null, true); \r
+\r
+                int r = \r
+                    compareIndexRowToKey(\r
+                        left_lastrow, right_firstrow,\r
+                        btree.getConglomerate().nUniqueColumns,\r
+                        0, btree.getConglomerate().ascDescInfo);\r
+\r
+                               if (r >= 0)\r
+                {\r
+                       SanityManager.THROWASSERT(\r
+                      "last row on left page " + \r
+                          left_sib.page.getPageNumber() + \r
+                      " > than first row on right page " + \r
+                          right_sib.page.getPageNumber() + "\n" + \r
+                      "left last row = " + RowUtil.toString(left_lastrow) +\r
+                      "right first row = " + RowUtil.toString(right_firstrow)+\r
+                      left_sib + " last > first of " + right_sib);\r
+\r
+                    is_consistent = false;\r
+                }\r
+            }\r
+            return(is_consistent);\r
+        }\r
+        else\r
+        {\r
+            return(true);\r
+        }\r
+    }\r
+\r
+       /**\r
+        ** Perform checks on the siblings of this page: make sure\r
+        ** that they're at the same level as this page, that they're\r
+        ** mutually linked together, and that the first/last keys\r
+        ** on sibling pages are in order.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       protected void checkSiblings(OpenBTree btree)\r
+        throws StandardException\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            // Get this page's left sibling.\r
+            ControlRow leftsib  = null;\r
+            ControlRow rightsib = null;\r
+\r
+            try\r
+            {\r
+                try\r
+                {\r
+                    leftsib = this.getLeftSibling(btree);\r
+                }\r
+                catch (WaitError e)\r
+                {\r
+                    // In a normal system it may be possible to not get\r
+                    // the left sibling (some other thread either user\r
+                    // or daemon cache cleaner thread) may already have\r
+                    // the latch on the page, and waiting on it could cause\r
+                    // a latch/latch deadlock.  So for now just give up\r
+                    // doing the consistency check in this case.\r
+                    //\r
+                    // RESOLVE (mikem) - We could do fancier things than \r
+                    // ignore this error, but the only safe way to wait for\r
+                    // a right to left latch is to release current latch which\r
+                    // will complicate all the code, and this is only a sanity\r
+                    // check.\r
+\r
+                    // SanityManager.DEBUG_PRINT(\r
+                    //   "ControlRow.checkSiblings",\r
+                    //   this + " left sibling deadlock");\r
+\r
+                    // give up on checking the left sibling.\r
+                    leftsib = null;\r
+                }\r
+\r
+                // There may not be a left sibling; if there is, check it out.\r
+                if (leftsib != null)\r
+                {\r
+                    // Check that it's at the same level as this page.\r
+                                       if (leftsib.getLevel() != this.getLevel())\r
+                       SanityManager.THROWASSERT(\r
+                               (leftsib + "not at same level as " + this));\r
+\r
+                    // Check that its right sibling is this page.\r
+                    long hopefullythis_pageno = \r
+                        leftsib.getrightSiblingPageNumber();\r
+\r
+                                       if (hopefullythis_pageno != this.page.getPageNumber())\r
+                       SanityManager.THROWASSERT(\r
+                               "right sibling of " + leftsib + " isn't "  + this);\r
+\r
+                    // Check that its last row is < this page's first row.\r
+                    compareRowsOnSiblings(btree, leftsib, this);\r
+\r
+                    // Done looking at the left sibling.\r
+                    leftsib.release();\r
+                    leftsib = null;\r
+                }\r
+\r
+                // Get the right sibling page.\r
+                rightsib = this.getRightSibling(btree);\r
+\r
+                // There may not be a right sibling; if there is, check it out.\r
+                if (rightsib != null)\r
+                {\r
+                    // Check that it's at the same level as this page.\r
+                                       if (rightsib.getLevel() != this.getLevel())\r
+                       SanityManager.THROWASSERT(\r
+                               rightsib + "not at same level as " + this);\r
+\r
+                    // Check that its left sibling is this page.\r
+                    long hopefullythis_pageno = \r
+                        rightsib.getleftSiblingPageNumber();\r
+\r
+                                       if (hopefullythis_pageno != this.page.getPageNumber())\r
+                       SanityManager.THROWASSERT(\r
+                               "left sibling of " + rightsib + " isn't "  + this);\r
+\r
+                    // Check that its first row is > this page's last row.\r
+                    compareRowsOnSiblings(btree, this, rightsib);\r
+\r
+                    // Done looking at it.\r
+                    rightsib.release();\r
+                    rightsib = null;\r
+                }\r
+            }\r
+            finally\r
+            {\r
+                if (leftsib != null)\r
+                    leftsib.release();\r
+                if (rightsib != null)\r
+                    rightsib.release();\r
+            }\r
+        }\r
+       }\r
+\r
+       /**\r
+        ** Link this page to the right of the target page.\r
+        ** <P>\r
+        ** Upon entry, this page and the target must be\r
+        ** latched.  Upon exit, this page and the target\r
+        ** remain latched.\r
+        ** <P>\r
+        ** This method carefully acquires pages from left\r
+        ** to right in order to avoid deadlocks.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        */\r
+       void linkRight(OpenBTree btree, ControlRow target)\r
+        throws StandardException\r
+       {\r
+               ControlRow rightSibling = null;\r
+\r
+        try\r
+        {\r
+            rightSibling = target.getRightSibling(btree);\r
+            this.setRightSibling(rightSibling);\r
+            this.setLeftSibling(target);\r
+            if (rightSibling != null)\r
+                rightSibling.setLeftSibling(this);\r
+            target.setRightSibling(this);\r
+        }\r
+        finally\r
+        {\r
+            if (rightSibling != null)\r
+                rightSibling.release();\r
+        }\r
+       }\r
+\r
+       /**\r
+        ** Unlink this page from its siblings.  This method\r
+        ** will give up and return false rather than run the\r
+        ** risk of a deadlock.\r
+        ** <P>\r
+        ** On entry this page must be latched.  The siblings\r
+        ** are latched and unlatched during the operation.  Upon\r
+        ** exit, this page will remain latched, but unlinked from\r
+        ** its siblings and deallocated from the container.\r
+        ** <P>\r
+        ** The seemingly odd situation that this page will be\r
+        ** returned latched but deallocated is intentional.\r
+        ** The container will not be able to reuse this page\r
+        ** until the latch is released, and the caller may still\r
+        ** need to read information out of it.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       boolean unlink(OpenBTree btree)\r
+        throws StandardException\r
+       {\r
+               ControlRow leftsib  = null;\r
+               ControlRow rightsib = null;\r
+\r
+               \r
+        try \r
+        {\r
+            // Try to get the left sibling, and give up if \r
+            // it can't be obtained without waiting.\r
+\r
+            try\r
+            {\r
+                leftsib = this.getLeftSibling(btree);\r
+            }\r
+            catch (WaitError e)\r
+            {\r
+                return false;\r
+            }\r
+\r
+            // We can wait for the right sibling since it's\r
+            // in the deadlock-free direction.\r
+\r
+            rightsib = this.getRightSibling(btree);\r
+\r
+            // Change the links that pointed to this page to\r
+            // point to the appropriate sibling.\r
+\r
+            if (leftsib != null)\r
+                leftsib.setRightSibling(rightsib);\r
+            if (rightsib != null)\r
+                rightsib.setLeftSibling(leftsib);\r
+\r
+            // Deallocate the page.\r
+            // Would need to clear out aux object here.\r
+            //\r
+            // RESOLVE (mikem) - how to deallocate a page. //\r
+            btree.container.removePage(this.page);\r
+\r
+            // After removePage call the current page is unlatched, and should\r
+            // not be referenced anymore.\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                SanityManager.ASSERT(!this.page.isLatched());\r
+            }\r
+\r
+            return true;\r
+        }\r
+        finally\r
+        {\r
+            // Unlatch the siblings.\r
+            if (leftsib != null)\r
+                leftsib.release();\r
+            if (rightsib != null)\r
+                rightsib.release();\r
+        }\r
+       }\r
+\r
+    public Page getPage()\r
+    {\r
+        return(page);\r
+    }\r
+\r
+    /**\r
+     * Get the row.\r
+     * <p>\r
+     * Return the object array that represents the control row for use\r
+     * in raw store fetch, insert, and/or update.\r
+     *\r
+        * @return The row.\r
+     *\r
+     **/\r
+    protected final DataValueDescriptor[] getRow()\r
+    {\r
+        return(row);\r
+    }\r
+\r
+       /*\r
+        * The following methods must be implemented by all\r
+        * control rows.\r
+        */\r
+\r
+    /**\r
+     * Check consistency of the page and its children, returning the number of \r
+     * pages seen, and throwing errors if inconsistencies are found.\r
+     * <p>\r
+     *\r
+        * @return The identifier to be used to open the conglomerate later.\r
+     *\r
+     * @param btree  The open btree to associate latches/locks with.\r
+     * @param parent The parent page of this page, "null" if this page is \r
+     *               root or if not maintaining parent links.\r
+     * @param check_other_pages\r
+     *               Should the consistency check go to other pages (this \r
+     *               option breaks the latch protocol).\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       abstract protected int checkConsistency(\r
+    OpenBTree  btree, \r
+    ControlRow parent,\r
+    boolean    check_other_pages)\r
+        throws StandardException;\r
+\r
+    /**\r
+     * Return the left child pointer for the page.\r
+     * <p>\r
+     * Leaf pages don't have children, so they override this and return null.\r
+     *\r
+        * @return The page which is the leftmost child of this page.\r
+     *\r
+     * @param btree  The open btree to associate latches/locks with.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected abstract ControlRow getLeftChild(OpenBTree btree)\r
+        throws StandardException;\r
+\r
+    /**\r
+     * Return the right child pointer for the page.\r
+     * <p>\r
+     * Leaf pages don't have children, so they override this and return null.\r
+     *\r
+        * @return The page which is the rightmost child of this page.\r
+     *\r
+     * @param btree  The open btree to associate latches/locks with.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected abstract ControlRow getRightChild(OpenBTree btree)\r
+        throws StandardException;\r
+\r
+    /**\r
+     * Perform page specific initialization.\r
+     * <p>\r
+     *\r
+     **/\r
+    protected abstract void controlRowInit();\r
+\r
+    /**\r
+     * Is the current page the leftmost leaf of tree?\r
+     * <p>\r
+     *\r
+        * @return true if the current page is the leftmost leaf of the tree,\r
+     *              else return false.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public abstract boolean isLeftmostLeaf()\r
+               throws StandardException;\r
+\r
+    /**\r
+     * Is the current page the rightmost leaf of tree?\r
+     * <p>\r
+     *\r
+        * @return true if the current page is the rightmost leaf of the tree,\r
+     *              else return false.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public abstract boolean isRightmostLeaf()\r
+               throws StandardException;\r
+\r
+       /**\r
+        ** Perform a recursive search, ultimately returning the latched\r
+        ** leaf page and row slot after which the given key belongs.\r
+        ** The slot is returned in the result structure.  If the key\r
+        ** exists on the page, the resultExact field will be true.  Otherwise,\r
+        ** resultExact field will be false, and the row slot returned will be\r
+        ** the one immediately preceding the position at which the key\r
+        ** belongs.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       public abstract ControlRow search(\r
+        SearchParameters    search_params)\r
+            throws StandardException;\r
+    /**\r
+     * Get the number of columns in the control row.  \r
+     * <p>\r
+     * Control rows all share the first columns as defined by this class and\r
+     * then add columns to the end of the control row.  For instance a branch\r
+     * control row add a child page pointer field.\r
+     * <p>\r
+     *\r
+        * @return The total number of columns in the control row.\r
+     **/\r
+    protected abstract int getNumberOfControlRowColumns();\r
+       \r
+    /**\r
+     * Search and return the left most leaf page.\r
+     * <p>\r
+        * Perform a recursive search, ultimately returning the\r
+     * leftmost leaf page which is the first leaf page in the\r
+        * leaf sibling chain.  (This method might better be called\r
+        * getFirstLeafPage()).\r
+     *\r
+        * @return The leftmost leaf page.\r
+     *\r
+     * @param btree  The open btree to associate latches/locks with.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected abstract ControlRow searchLeft(OpenBTree btree)\r
+        throws StandardException;\r
+\r
+    /**\r
+     * Search and return the right most leaf page.\r
+     * <p>\r
+        * Perform a recursive search, ultimately returning the\r
+        * rightmost leaf page which is the last leaf page in the\r
+        * leaf sibling chain.  (This method might better be called\r
+        * getLastLeafPage()).\r
+     *\r
+        * @return The rightmost leaf page.\r
+     *\r
+     * @param btree  The open btree to associate latches/locks with.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected abstract ControlRow searchRight(OpenBTree btree)\r
+        throws StandardException;\r
+\r
+       /**\r
+        **     Perform a recursive shrink operation for the key.\r
+        ** If this method returns true, the caller should\r
+        ** remove the corresponding entry for the page.\r
+        ** This routine is not guaranteed to successfully\r
+        ** shrink anything.  The page lead to by the key might\r
+        ** turn out not to be empty by the time shrink gets\r
+        ** there, and shrinks will give up if there is a deadlock.\r
+     ** <P>\r
+     ** As currently implemented shrinkFor must be executed while holding\r
+     ** an exclusive container lock on the entire table.  It is expected that\r
+     ** this call is made within an internal transaction which has been called\r
+     ** by a post commit thread.  Latches are released by the code.  The raw \r
+     ** store guarantees that deallocated pages are not seen by other xacts\r
+     ** until the transaction has been committed.  \r
+        ** <P>\r
+     ** Note that a non-table level lock implementation must hold latches on\r
+     ** pages affected until end transaction.\r
+     ** <p>\r
+     ** On entry, the current page is latched.  On exit, all pages will have\r
+     ** been unlatched. \r
+     ** \r
+     ** @exception StandardException Standard exception policy.\r
+        **/\r
+       protected abstract boolean shrinkFor(\r
+    OpenBTree               btree, \r
+    DataValueDescriptor[]   key)\r
+        throws StandardException;\r
+\r
+    /**\r
+     * Perform a top down split pass making room for the the key in "row".\r
+     * <p>\r
+     * Perform a split such that a subsequent call to insert\r
+        * given the argument index row will likely find room for it.  Since \r
+     * latches are released the client must code for the case where another\r
+     * user has grabbed the space made available by the split pass and be\r
+     * ready to do another split.\r
+     * <p>\r
+     *\r
+        * @return page number of the newly allocated leaf page created by split.\r
+     *\r
+     * @param open_btree The open btree to associate latches with.\r
+     * @param template   A scratch area to use while searching for split pass.\r
+     * @param parentpage The parent page of the current page in the split pass.\r
+     *                   starts at null for root.\r
+     * @param row        The key to make room for during the split pass.\r
+     * @param flag       A flag used to direct where point of split should be\r
+     *                   chosen.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected abstract long splitFor(\r
+    OpenBTree               open_btree, \r
+    DataValueDescriptor[]   template, \r
+    BranchControlRow        parentpage, \r
+    DataValueDescriptor[]   row,\r
+    int                     flag)\r
+        throws StandardException;\r
+\r
+       /**\r
+        ** Recursively print the tree starting at current node in tree.\r
+\r
+    @exception StandardException Standard exception policy.\r
+        **/\r
+       public abstract void printTree(\r
+    OpenBTree  btree) \r
+        throws StandardException;\r
+       \r
+\r
+\r
+       /*\r
+       ** Methods of AuxObject\r
+       */\r
+\r
+       /**\r
+               Called when the page is being evicted from cache or when a rollback\r
+               happened on the page and may possibly have changed the control row's \r
+        value\r
+\r
+               @see AuxObject#auxObjectInvalidated\r
+       **/\r
+       public void auxObjectInvalidated()\r
+       {\r
+               version = null;\r
+               leftSiblingPageNumber = null;\r
+               rightSiblingPageNumber = null;\r
+               parentPageNumber = null;\r
+               level = null;\r
+               isRoot = null;\r
+               page = null;\r
+       }\r
+\r
+    /**\r
+     * Return a new template for reading a data row from the current page.\r
+     * <p>\r
+     * Default implementation for rows which are the same as the conglomerates\r
+     * template, sub-classes can alter if underlying template is different\r
+     * (for instance branch rows add an extra field at the end).\r
+     *\r
+        * @return Newly allocated template.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public DataValueDescriptor[] getRowTemplate(OpenBTree    open_btree)\r
+               throws StandardException\r
+    {\r
+        return(open_btree.getConglomerate().createTemplate(\r
+                    open_btree.getRawTran()));\r
+    }\r
+\r
+\r
+       /**\r
+        ** Debug toString() method's.\r
+        **/\r
+\r
+    /**\r
+     * Dump complete information about control row and rows on the page.\r
+     * <p>\r
+     *\r
+        * @return string with all info.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       public String debugPage(\r
+    OpenBTree   open_btree)\r
+        throws StandardException\r
+       {\r
+        String ret_str;\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            StringBuffer string = new StringBuffer(4096);\r
+            string.append(this.toString());\r
+            string.append("\n");\r
+\r
+            DataValueDescriptor[] row = getRowTemplate(open_btree);\r
+\r
+            string.append(\r
+                ConglomerateUtil.debugPage(\r
+                    page, ControlRow.CR_SLOT + 1, false, row));\r
+\r
+            ret_str = string.toString();\r
+        }\r
+        else\r
+        {\r
+            ret_str = null;\r
+        }\r
+\r
+        return(ret_str);\r
+       }\r
+\r
+    /**\r
+     * The standard toString().\r
+     * <p>\r
+     * This is a concise print out of the info in the control row, does not\r
+     * include anything the page.\r
+     * <p>\r
+     * \r
+     **/\r
+       public String toString()\r
+    {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            StringBuffer string = new StringBuffer(4096);\r
+\r
+            try {\r
+\r
+\r
+                // LEAF, BRANCH, LEAF-ROOT, BRANCH-ROOT\r
+                string.append((getLevel() == 0) ? "\nLEAF" : "\nBRANCH");\r
+                string.append((getIsRoot())     ? "-ROOT" : "");\r
+\r
+                // (PAGE NUMBER)(LEVEL):num recs \r
+                //     example: (107)(lev=2):num recs = 16\r
+                string.append("(");\r
+                string.append(this.page.getPageNumber());\r
+                string.append(")(lev=");\r
+                string.append(level);\r
+                string.append("): num recs = ");\r
+                string.append(this.page.recordCount());\r
+                string.append("\n");\r
+\r
+                // rest of info\r
+                string.append("\t");\r
+\r
+                string.append("left = ");\r
+                string.append(getleftSiblingPageNumber());\r
+                string.append(";");\r
+\r
+                string.append("right = ");\r
+                string.append(getrightSiblingPageNumber());\r
+                string.append(";");\r
+\r
+                string.append("parent = ");\r
+                string.append(getParentPageNumber());\r
+                string.append(";");\r
+\r
+                string.append("isRoot = ");\r
+                string.append(getIsRoot());\r
+                string.append(";");\r
+\r
+            }\r
+            catch (Throwable t)\r
+            {\r
+                string.append(\r
+                    "error encountered while doing ControlRow.toString()");\r
+            }\r
+\r
+            return(string.toString());\r
+        }\r
+        else\r
+        {\r
+            return(null);\r
+        }\r
+    }\r
+}\r