Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / store / access / sort / SortBuffer.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/sort/SortBuffer.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/access/sort/SortBuffer.java
new file mode 100644 (file)
index 0000000..8641c88
--- /dev/null
@@ -0,0 +1,715 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.sort.SortBuffer\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.sort;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+/**\r
+\r
+  This class implements an in-memory ordered set\r
+  based on the balanced binary tree algorithm from\r
+  Knuth Vol. 3, Sec. 6.2.3, pp. 451-471.\r
+  Nodes are always maintained in order,\r
+  so that inserts and deletes can be intermixed.\r
+  <P>\r
+  This algorithm will insert/delete N elements\r
+  in O(N log(N)) time using O(N) space. \r
+\r
+**/\r
+\r
+class SortBuffer\r
+{\r
+       /**\r
+       Returned from insert when the row was inserted\r
+       without incident.\r
+       **/\r
+       public static final int INSERT_OK = 0;\r
+\r
+       /**\r
+       Returned from insert when the row which was\r
+       inserted was a duplicate.  The set will have\r
+       aggregated it in.\r
+       **/\r
+       public static final int INSERT_DUPLICATE = 1;\r
+\r
+       /**\r
+       Returned from insert when the row was not able to be\r
+       inserted because the set was full.\r
+       **/\r
+       public static final int INSERT_FULL = 2;\r
+\r
+       /**\r
+       The sort this set is associated with.\r
+       **/\r
+       private MergeSort sort;\r
+\r
+       /**\r
+       Where to allocate nodes from.\r
+       **/\r
+       private NodeAllocator allocator = null;\r
+\r
+       /**\r
+       Special head node for the tree.  Head.rightLink is the\r
+       root of the tree.\r
+       **/\r
+       private Node head = null;\r
+\r
+       /**\r
+       The current height of the tree.\r
+       **/\r
+       private int height = 0;\r
+\r
+       /**\r
+       Set, as a side effect of deleteLeftMost (only), to the\r
+       key from the node that was deleted from the tree.  This\r
+       field is only valid after a call to deleteLeftMost.\r
+       **/\r
+       private DataValueDescriptor[] deletedKey;\r
+\r
+       /**\r
+       Set, as a side effect of deleteLeftMost and rotateRight,\r
+       if the subtree they're working on decreased in height.\r
+       This field is only valid after a call to deleteLeftMost\r
+       or rotateRight.\r
+       **/\r
+       private boolean subtreeShrunk;\r
+\r
+       /**\r
+       Set by the setNextAux() method.  This value is stuffed\r
+       into the aux field of the next node that's allocated.\r
+       **/\r
+       private int nextAux;\r
+\r
+       /**\r
+       Read by the getLastAux() method.  This value is read out\r
+       of the last node that was deallocated from the tree.\r
+       **/\r
+       private int lastAux;\r
+\r
+       /**\r
+       Arrange that the next node allocated in the tree have\r
+       it's aux field set to the argument.\r
+       **/\r
+       void setNextAux(int aux)\r
+       {\r
+               nextAux = aux;\r
+       }\r
+\r
+       /**\r
+       Retrieve the aux value from the last node deallocated\r
+       from the tree.\r
+       **/\r
+       int getLastAux()\r
+       {\r
+               return lastAux;\r
+       }\r
+\r
+       /**\r
+       Construct doesn't do anything, callers must call init\r
+       and check its return code.\r
+       **/\r
+       SortBuffer(MergeSort sort)\r
+       {\r
+               this.sort = sort;\r
+       }\r
+\r
+       /**\r
+       Initialize.  Returns false if the allocator\r
+       couldn't be initialized.\r
+       **/\r
+       boolean init()\r
+       {\r
+               allocator = new NodeAllocator();\r
+\r
+               boolean initOK = false;\r
+\r
+               if (sort.sortBufferMin > 0)\r
+                       initOK = allocator.init(sort.sortBufferMin, sort.sortBufferMax);\r
+               else\r
+                       initOK = allocator.init(sort.sortBufferMax);\r
+\r
+               if (initOK == false)\r
+               {\r
+                       allocator = null;\r
+                       return false;\r
+               }\r
+               reset();\r
+               return true;\r
+       }\r
+\r
+       void reset()\r
+       {\r
+               allocator.reset();\r
+               head = allocator.newNode();\r
+               height = 0;\r
+       }\r
+\r
+       void close()\r
+       {\r
+               if (allocator != null)\r
+                       allocator.close();\r
+               allocator = null;\r
+               height = 0;\r
+               head = null;\r
+       }\r
+\r
+       /**\r
+       Grow by a certain percent if we can\r
+       */\r
+       void grow(int percent)\r
+       {\r
+               if (percent > 0)\r
+                       allocator.grow(percent);\r
+       }\r
+\r
+\r
+       /**\r
+       Return the number of elements this sorter can sort.\r
+       It's the capacity of the node allocator minus one\r
+       because the sorter uses one node for the head.\r
+       **/\r
+       int capacity()\r
+       {\r
+               if (allocator == null)\r
+                       return 0;\r
+               return allocator.capacity() - 1;\r
+       }\r
+\r
+       /**\r
+       Insert a key k into the tree. Returns true if the\r
+       key was inserted, false if the tree is full.  Silently\r
+       ignores duplicate keys.\r
+       <P>\r
+       See Knuth Vol. 3, Sec. 6.2.3, pp. 455-457 for the algorithm.\r
+       **/\r
+       int insert(DataValueDescriptor[] k)\r
+               throws StandardException\r
+       {\r
+               int c;\r
+               Node p, q, r, s, t;\r
+\r
+               if (head.rightLink == null)\r
+               {\r
+                       if ((sort.sortObserver != null) && \r
+                               ((k = sort.sortObserver.insertNonDuplicateKey(k)) == null))\r
+                       {\r
+                               return INSERT_DUPLICATE;\r
+                       }\r
+\r
+                       q = allocator.newNode();\r
+                       q.key = k;\r
+                       q.aux = nextAux;\r
+                       head.rightLink = q;\r
+                       height = 1;\r
+                       return INSERT_OK;\r
+               }\r
+\r
+               // [A1. Initialize]\r
+               t = head;\r
+               p = s = head.rightLink;\r
+\r
+               // Search\r
+               while (true)\r
+               {\r
+                       // [A2. Compare]\r
+                       c = sort.compare(k, p.key);\r
+                       if (c == 0)\r
+                       {\r
+                               // The new key compares equal to the\r
+                               // current node's key.\r
+\r
+                               // See if we can use the aggregators\r
+                               // to get rid of the new key.\r
+                               if ((sort.sortObserver != null) &&\r
+                                       ((k = sort.sortObserver.insertDuplicateKey(k, p.key)) == null))\r
+                               {\r
+                                       return INSERT_DUPLICATE;\r
+                               }\r
+\r
+                               // Keep the duplicate key...\r
+                               // Allocate a new node for the key.\r
+                               q = allocator.newNode();\r
+                               if (q == null)\r
+                                       return INSERT_FULL;\r
+                               q.aux = nextAux;\r
+\r
+                               // Link the new node onto the current\r
+                               // node's duplicate chain.  The assumption\r
+                               // is made that a newly allocated node \r
+                               // has null left and right links.\r
+                               q.key = k;\r
+                               q.dupChain = p.dupChain;\r
+                               p.dupChain = q;\r
+\r
+                               // From the caller's perspective this was\r
+                               // not a duplicate insertion.\r
+                               return INSERT_OK;\r
+                       }\r
+\r
+                       if (c < 0)\r
+                       {\r
+                               // [A3. Move left]\r
+                               q = p.leftLink;\r
+                               if (q == null)\r
+                               {\r
+                                       q = allocator.newNode();\r
+                                       if (q == null)\r
+                                               return INSERT_FULL;\r
+                                       q.aux = nextAux;\r
+                                       p.leftLink = q;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       else // c > 0\r
+                       {\r
+                               // [A4. Move right]\r
+                               q = p.rightLink;\r
+                               if (q == null)\r
+                               {\r
+                                       q = allocator.newNode();\r
+                                       if (q == null)\r
+                                               return INSERT_FULL;\r
+                                       q.aux = nextAux;\r
+                                       p.rightLink = q;\r
+                                       break;\r
+                               }\r
+                       }\r
+\r
+                       if (q.balance != 0)\r
+                       {\r
+                               t = p;\r
+                               s = q;\r
+                       }\r
+                       p = q;\r
+               }\r
+\r
+               /*\r
+                * [A5. Insert]\r
+                * Node has been allocated and placed for k.\r
+                * Initialize it.\r
+                */\r
+\r
+               if ((sort.sortObserver != null) && \r
+                       ((k = sort.sortObserver.insertNonDuplicateKey(k)) == null))\r
+               {\r
+                       return INSERT_DUPLICATE;\r
+               }\r
+               q.key = k;\r
+\r
+               /*\r
+                * [A6. Adjust balance factors for nodes between\r
+                * s and q]\r
+                */\r
+\r
+               c = sort.compare(k, s.key);\r
+               if (c < 0)\r
+                       r = p = s.leftLink;\r
+               else\r
+                       r = p = s.rightLink;\r
+\r
+               while (p != q)\r
+               {\r
+                       if (sort.compare(k, p.key) < 0)\r
+                       {\r
+                               p.balance = -1;\r
+                               p = p.leftLink;\r
+                       }\r
+                       else // sort.compare(k, p.key) > 0\r
+                       {\r
+                               p.balance = 1;\r
+                               p = p.rightLink;\r
+                       }\r
+               }\r
+\r
+               // [A7. Balancing act]\r
+\r
+               int a = (c > 0 ? 1 : ((c == 0) ? 0 : -1));\r
+\r
+               if (s.balance == 0)\r
+               {\r
+                       //debug("A7 (i). The tree has gotten higher");\r
+                       s.balance = a;\r
+                       height++;\r
+                       return INSERT_OK;\r
+               }\r
+\r
+               if (s.balance == -a)\r
+               {\r
+                       //debug("A7 (ii). The tree has gotten more balanced");\r
+                       s.balance = 0;\r
+                       return INSERT_OK;\r
+               }\r
+\r
+               //debug("A7 (iii). The tree has gotten more out of balance");\r
+\r
+               // s.balance == a\r
+               if (r.balance == a)\r
+               {\r
+                       //debug("A8. Single rotation");\r
+                       p = r;\r
+                       s.setLink(a, r.link(-a));\r
+                       r.setLink(-a, s);\r
+                       s.balance = 0;\r
+                       r.balance = 0;\r
+               }\r
+               else // r.balance == -a\r
+               {\r
+                       //debug("A8. Double rotation");\r
+                       p = r.link(-a);\r
+                       r.setLink(-a, p.link(a));\r
+                       p.setLink(a, r);\r
+                       s.setLink(a, p.link(-a));\r
+                       p.setLink(-a, s);\r
+\r
+                       if (p.balance == a)\r
+                       {\r
+                               s.balance = -a;\r
+                               r.balance = 0;\r
+                       }\r
+                       else if (p.balance == 0)\r
+                       {\r
+                               s.balance = 0;\r
+                               r.balance = 0;\r
+                       }\r
+                       else // p.balance == -a\r
+                       {\r
+                               s.balance = 0;\r
+                               r.balance = a;\r
+                       }\r
+\r
+                       p.balance = 0;\r
+               }\r
+\r
+               // [A10. Finishing touch]\r
+               if (s == t.rightLink)\r
+                       t.rightLink = p;\r
+               else\r
+                       t.leftLink = p;\r
+\r
+               return INSERT_OK;\r
+       }\r
+\r
+       /**\r
+       Return the lowest key and delete it from \r
+       the tree, preserving the balance of the tree.\r
+       **/\r
+       DataValueDescriptor[] removeFirst()\r
+       {\r
+               if (head.rightLink == null)\r
+                       return null;\r
+               head.rightLink = deleteLeftmost(head.rightLink);\r
+               if (this.subtreeShrunk)\r
+                       height--;\r
+               return this.deletedKey;\r
+       }\r
+\r
+       /**\r
+       Delete the node with the lowest key from the subtree defined\r
+       by 'thisNode', maintaining balance in the subtree.  Returns\r
+       the node that should be the new root of the subtree.  This\r
+       method sets this.subtreeShrunk if the subtree of thisNode\r
+       decreased in height. Saves the key that was in the deleted\r
+       node in 'deletedKey'.\r
+       **/\r
+       private Node deleteLeftmost(Node thisNode)\r
+       {\r
+               // If this node has no left child, we've found the\r
+               // leftmost one, so delete it.\r
+               if (thisNode.leftLink == null)\r
+               {\r
+\r
+                       // See if the current node has duplicates.  If so, we'll\r
+                       // just return one of them and not change the tree.\r
+                       if (thisNode.dupChain != null)\r
+                       {\r
+                               Node dupNode = thisNode.dupChain;\r
+\r
+                               //System.out.println("deleteLeftmost(" + thisNode + "): found dup: " + dupNode);\r
+\r
+                               // Return the key from the duplicate.  Note that even\r
+                               // though the keys compare equal they may not be equal,\r
+                               // depending on how the column ordering was specified.\r
+                               this.deletedKey = dupNode.key;\r
+                               lastAux = dupNode.aux;\r
+\r
+                               // Unlink the dup node and free it.\r
+                               thisNode.dupChain = dupNode.dupChain;\r
+                               allocator.freeNode(dupNode);\r
+                               dupNode = null;\r
+\r
+                               // Tree is not changing height since we're just removing\r
+                               // a node from the duplicate chain.\r
+                               this.subtreeShrunk = false;\r
+\r
+                               // Preserve the current node as the root of this subtree..\r
+                               return thisNode;\r
+                       }\r
+                       else // thisNode.dupChain == null\r
+                       {\r
+                               //System.out.println("deleteLeftmost(" + thisNode + "): found key");\r
+\r
+                               // Key to return is this node's key.\r
+                               this.deletedKey = thisNode.key;\r
+                               lastAux = thisNode.aux;\r
+\r
+                               // We're removing this node, so it's subtree is shrinking\r
+                               // from height 1 to height 0.\r
+                               this.subtreeShrunk = true;\r
+\r
+                               // Save this node's right link which might be cleared\r
+                               // out by the allocator.\r
+                               Node newRoot = thisNode.rightLink;\r
+\r
+                               // Free the node we're deleting.\r
+                               allocator.freeNode(thisNode);\r
+\r
+                               // Rearrange the tree to put this node's right subtree where\r
+                               // this node was.\r
+                               return newRoot;\r
+                       }\r
+               }\r
+\r
+               // Since this wasn't the leftmost node, delete the leftmost\r
+               // node from this node's left subtree.  This operation may\r
+               // rearrange the subtree, including the possiblility that the\r
+               // root note changed, so set the root of the left subtree to\r
+               // what the delete operation wants it to be.\r
+               thisNode.leftLink = deleteLeftmost(thisNode.leftLink);\r
+\r
+               // If the left subtree didn't change size, then this subtree\r
+               // could not have changed size either.\r
+               if (this.subtreeShrunk == false)\r
+                       return thisNode;\r
+\r
+               // If the delete operation shrunk the subtree, we may have\r
+               // some rebalancing to do.\r
+\r
+               if (thisNode.balance == 1)\r
+               {\r
+                       // Tree got more unbalanced.  Need to do some\r
+                       // kind of rotation to fix it.  The rotateRight()\r
+                       // method will set subtreeShrunk appropriately\r
+                       // and return the node that should be the new\r
+                       // root of this subtree.\r
+                       return rotateRight(thisNode);\r
+               }\r
+\r
+               if (thisNode.balance == -1)\r
+               {\r
+                       // Tree became more balanced\r
+                       thisNode.balance = 0;\r
+\r
+                       // Since the left subtree was higher, and it\r
+                       // shrunk, then this subtree shrunk, too.\r
+                       this.subtreeShrunk = true;\r
+               }\r
+               else // thisNode.balance == 0\r
+               {\r
+                       // Tree became acceptably unbalanced\r
+                       thisNode.balance = 1;\r
+\r
+                       // We had a balanced tree, and just the left\r
+                       // subtree shrunk, so this subtree as a whole\r
+                       // has not changed in height.\r
+                       this.subtreeShrunk = false;\r
+               }\r
+\r
+               // We have not rearranged this subtree.\r
+               return thisNode;\r
+       }\r
+\r
+       /**\r
+       Perform either a single or double rotation, as appropriate, \r
+       to get the subtree 'thisNode' back in balance, assuming\r
+       that the right subtree of 'thisNode' is higher than the\r
+       left subtree.  Returns the node that should be the new\r
+       root of the subtree.\r
+       <P>\r
+       These are the cases depicted in diagrams (1) and (2) of\r
+       Knuth (p. 454), and the node names reflect these diagrams.\r
+       However, in deletion, the single rotation may encounter\r
+       a case where the "beta" and "gamma" subtrees are the same\r
+       height (b.balance == 0), so the resulting does not always\r
+       shrink.\r
+       <P>\r
+    Note: This code will not do the "mirror image" cases.\r
+       It only works when the right subtree is the higher one\r
+       (this is the only case encountered when deleting leftmost\r
+       nodes from the tree).\r
+       **/\r
+       private Node rotateRight(Node thisNode)\r
+       {\r
+               Node a = thisNode;\r
+               Node b = thisNode.rightLink;\r
+\r
+               if (b.balance >= 0)\r
+               {\r
+                       // single rotation\r
+\r
+                       a.rightLink = b.leftLink;\r
+                       b.leftLink = a;\r
+\r
+                       if (b.balance == 0)\r
+                       {\r
+                               a.balance = 1;\r
+                               b.balance = -1;\r
+                               this.subtreeShrunk = false;\r
+                       }\r
+                       else // b.balance == 1\r
+                       {\r
+                               a.balance = 0;\r
+                               b.balance = 0;\r
+                               this.subtreeShrunk = true;\r
+                       }\r
+\r
+                       return b;\r
+               }\r
+               else // b.balance == -1\r
+               {\r
+                       // double rotation\r
+\r
+                       Node x = b.leftLink;\r
+\r
+                       a.rightLink = x.leftLink;\r
+                       x.leftLink = a;\r
+                       b.leftLink = x.rightLink;\r
+                       x.rightLink = b;\r
+\r
+                       if (x.balance == 1)\r
+                       {\r
+                               a.balance = -1;\r
+                               b.balance = 0;\r
+                       }\r
+                       else if (x.balance == -1)\r
+                       {\r
+                               a.balance = 0;\r
+                               b.balance = 1;\r
+                       }\r
+                       else // x.balance == 0\r
+                       {\r
+                               a.balance = 0;\r
+                               b.balance = 0;\r
+                       }\r
+                       x.balance = 0;\r
+\r
+                       this.subtreeShrunk = true;\r
+\r
+                       return x;\r
+               }\r
+       }\r
+\r
+       public void check()\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            String error = null;\r
+            if (head.rightLink == null)\r
+            {\r
+                if (height != 0)\r
+                    error = "empty tree with height " + height;\r
+            } \r
+            else\r
+            {\r
+                if (depth(head.rightLink) != height)\r
+                    error = "tree height " + height + " != depth " + depth(head.rightLink);\r
+                else\r
+                    error = checkNode(head.rightLink);\r
+            }\r
+            if (error != null)\r
+            {\r
+                System.out.println("ERROR: " + error);\r
+                print();\r
+                System.exit(1);\r
+            }\r
+        }\r
+       }\r
+\r
+       private String checkNode(Node n)\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (n == null)\r
+                return null;\r
+            int ld = depth(n.leftLink);\r
+            int rd = depth(n.rightLink);\r
+            if (n.balance != (rd - ld))\r
+                return "node " + n + ": left height " + ld + " right height " + rd;\r
+            \r
+            String e;\r
+            e = checkNode(n.rightLink);\r
+            if (e == null)\r
+                e = checkNode(n.leftLink);\r
+            return e;\r
+        }\r
+        else\r
+        {\r
+            return(null);\r
+        }\r
+       }\r
+\r
+       private int depth(Node n)\r
+       {\r
+               int ld = 0;\r
+               int rd = 0;\r
+               if (n == null)\r
+                       return 0;\r
+               if (n.leftLink != null)\r
+                       ld = depth(n.leftLink);\r
+               if (n.rightLink != null)\r
+                       rd = depth(n.rightLink);\r
+               if (rd > ld)\r
+                       return rd + 1;\r
+               else\r
+                       return ld + 1;\r
+       }\r
+\r
+       public void print()\r
+       {\r
+               Node root = head.rightLink;\r
+               System.out.println("tree height: " + height\r
+                       + " root: " + ((root == null) ? -1 : root.id));\r
+               if (root != null)\r
+                       printRecursive(root, 0);\r
+       }\r
+\r
+       private void printRecursive(Node n, int depth)\r
+       {\r
+               if (n.rightLink != null)\r
+                       printRecursive(n.rightLink, depth + 1);\r
+               for (int i = 0; i < depth; i++)\r
+                       System.out.print("       ");\r
+               System.out.println(n);\r
+               if (n.leftLink != null)\r
+                       printRecursive(n.leftLink, depth + 1);\r
+       }\r
+\r
+       private void debug(String s)\r
+       {\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            System.out.println(" === [" + s + "] ===");\r
+        }\r
+       }\r
+}\r