Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / store / access / heap / HeapCompressScan.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/heap/HeapCompressScan.java
new file mode 100644 (file)
index 0000000..2f53fd7
--- /dev/null
@@ -0,0 +1,436 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.heap.HeapScan\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.heap;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.SpaceInfo;\r
+\r
+import org.apache.derby.impl.store.access.conglomerate.RowPosition;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+/**\r
+ * A heap scan object represents an instance of a scan on a heap conglomerate.\r
+ */\r
+class HeapCompressScan \r
+    extends HeapScan\r
+{\r
+\r
+    /**************************************************************************\r
+     * Constants of HeapScan\r
+     **************************************************************************\r
+     */\r
+\r
+    /**************************************************************************\r
+     * Fields of HeapScan\r
+     **************************************************************************\r
+     */\r
+    private long pagenum_to_start_moving_rows = -1;\r
+\r
+\r
+\r
+    /**************************************************************************\r
+     * Constructors for This class:\r
+     **************************************************************************\r
+     */\r
+\r
+       /**\r
+        ** The only constructor for a HeapCompressScan returns a scan in the\r
+        ** closed state, the caller must call open.\r
+        **/\r
+       \r
+       public HeapCompressScan()\r
+       {\r
+       }\r
+\r
+    /**************************************************************************\r
+     * Protected override implementation of routines in\r
+     *     GenericController class:\r
+     **************************************************************************\r
+     */\r
+\r
+    public int fetchNextGroup(\r
+    DataValueDescriptor[][] row_array,\r
+    RowLocation[]           old_rowloc_array,\r
+    RowLocation[]           new_rowloc_array)\r
+        throws StandardException\r
+       {\r
+        return(fetchRowsForCompress(\r
+                    row_array, old_rowloc_array, new_rowloc_array));\r
+    }\r
+\r
+    /**\r
+     * Fetch the next N rows from the table.\r
+     * <p>\r
+     * Utility routine used by both fetchSet() and fetchNextGroup().\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    private int fetchRowsForCompress(\r
+    DataValueDescriptor[][] row_array,\r
+    RowLocation[]           oldrowloc_array,\r
+    RowLocation[]           newrowloc_array)\r
+        throws StandardException\r
+       {\r
+        int                     ret_row_count           = 0;\r
+        DataValueDescriptor[]   fetch_row               = null;\r
+\r
+        // only fetch maximum number of rows per "group" as the size of\r
+        // the array.  If more than one group is available on page, just\r
+        // leave the scan on the page and the next group will come from\r
+        // this page also.\r
+        int                     max_rowcnt = row_array.length;\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            SanityManager.ASSERT(row_array != null);\r
+            SanityManager.ASSERT(row_array[0] != null,\r
+                    "first array slot in fetchNextGroup() must be non-null.");\r
+        }\r
+\r
+        if (getScanState() == SCAN_INPROGRESS)\r
+        {\r
+            positionAtResumeScan(scan_position);\r
+        }\r
+        else if (getScanState() == SCAN_INIT)\r
+        {\r
+            // For first implementation of defragment use a conservative\r
+            // approach, only move rows from the last "number of free pages"\r
+            // of the container.  Should always at least be able to empty\r
+            // that number of pages.\r
+            SpaceInfo info = \r
+                open_conglom.getContainer().getSpaceInfo();\r
+\r
+            pagenum_to_start_moving_rows = info.getNumAllocatedPages();\r
+\r
+            positionAtStartForForwardScan(scan_position);\r
+        }\r
+        else if (getScanState() == SCAN_HOLD_INPROGRESS)\r
+        {\r
+            reopenAfterEndTransaction();\r
+\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                SanityManager.ASSERT(\r
+                    scan_position.current_rh != null, this.toString()); \r
+            }\r
+\r
+            // reposition the scan at the row just before the next one to \r
+            // return.\r
+            // This routine handles the mess of repositioning if the row or \r
+            // the page has disappeared. This can happen if a lock was not \r
+            // held on the row while not holding the latch.\r
+            open_conglom.latchPageAndRepositionScan(scan_position);\r
+\r
+            setScanState(SCAN_INPROGRESS);\r
+        }\r
+        else if (getScanState() == SCAN_HOLD_INIT)\r
+        {\r
+            reopenAfterEndTransaction();\r
+\r
+            positionAtStartForForwardScan(scan_position);\r
+\r
+        }\r
+        else\r
+        {\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(getScanState() == SCAN_DONE);\r
+\r
+            return(0);\r
+        }\r
+\r
+        // At this point:\r
+        // scan_position.current_page is latched.  \r
+        // scan_position.current_slot is the slot on scan_position.current_page\r
+        // just before the "next" record this routine should process.\r
+\r
+        // loop through successive pages and successive slots on those\r
+        // pages.  Stop when either the last page is reached \r
+        // (scan_position.current_page will be null).  \r
+        // Along the way apply qualifiers to skip rows which don't qualify.\r
+\r
+               while (scan_position.current_page != null)\r
+               {\r
+                       while ((scan_position.current_slot + 1) < \r
+                    scan_position.current_page.recordCount())\r
+                       {\r
+\r
+                // Allocate a new row to read the row into.\r
+                if (fetch_row == null)\r
+                {\r
+                     // point at allocated row in array if one exists.\r
+                    if (row_array[ret_row_count] == null)\r
+                    {\r
+                        row_array[ret_row_count] = \r
+                          open_conglom.getRuntimeMem().get_row_for_export(\r
+                              open_conglom.getRawTran());\r
+                    }\r
+\r
+                    fetch_row = row_array[ret_row_count];\r
+                }\r
+\r
+                // move scan current position forward.\r
+                scan_position.positionAtNextSlot();\r
+                int restart_slot = scan_position.current_slot;\r
+\r
+                this.stat_numrows_visited++;\r
+\r
+                if (scan_position.current_page.isDeletedAtSlot(\r
+                        scan_position.current_slot))\r
+                {\r
+                    // At this point assume table level lock, and that this\r
+                    // transcation did not delete the row, so any\r
+                    // deleted row must be a committed deleted row which can\r
+                    // be purged.\r
+                    scan_position.current_page.purgeAtSlot(\r
+                        scan_position.current_slot, 1, false);\r
+\r
+                    // raw store shuffles following rows down, so \r
+                    // postion the scan at previous slot, so next trip\r
+                    // through loop will pick up correct row.\r
+                    scan_position.positionAtPrevSlot();\r
+                    continue;\r
+                }\r
+\r
+                if (scan_position.current_page.getPageNumber() > \r
+                        pagenum_to_start_moving_rows)\r
+                {\r
+                    // Give raw store a chance to move the row for compression\r
+                    RecordHandle[] old_handle = new RecordHandle[1];\r
+                    RecordHandle[] new_handle = new RecordHandle[1];\r
+                    long[]         new_pageno = new long[1];\r
+\r
+                    if (scan_position.current_page.moveRecordForCompressAtSlot(\r
+                            scan_position.current_slot,\r
+                            fetch_row,\r
+                            old_handle,\r
+                            new_handle) == 1)\r
+                    {\r
+                        // raw store moved the row, so bump the row count but \r
+                        // position the scan at previous slot, so next trip\r
+                        // through loop will pick up correct row.\r
+                        // The subsequent rows will have been moved forward\r
+                        // to take place of moved row.\r
+                        scan_position.positionAtPrevSlot();\r
+\r
+                        ret_row_count++;\r
+                        stat_numrows_qualified++;\r
+\r
+\r
+                        setRowLocationArray(\r
+                            oldrowloc_array, ret_row_count - 1, old_handle[0]);\r
+                        setRowLocationArray(\r
+                            newrowloc_array, ret_row_count - 1, new_handle[0]);\r
+\r
+                        fetch_row = null;\r
+\r
+                    }\r
+                }\r
+\r
+                // Derby-2549. If ret_row_count reaches the limit of the buffer,\r
+                // then return the maximum number and come back into the same \r
+                // method to fetch the remaining rows. In this block we ensure\r
+                // that the scan_position is appropriate.\r
+                if (ret_row_count >= max_rowcnt)\r
+                {\r
+                    // filled group buffer, exit fetch loop and return to caller\r
+\r
+                    // save current scan position by record handle.\r
+                    scan_position.current_rh =\r
+                        scan_position.current_page.getRecordHandleAtSlot(\r
+                            restart_slot);\r
+\r
+                    scan_position.unlatch();\r
+\r
+                    return(ret_row_count);\r
+                }\r
+                       }\r
+\r
+            this.stat_numpages_visited++;\r
+\r
+            if (scan_position.current_page.recordCount() == 0)\r
+            {\r
+                // need to set the scan position before removing page\r
+                scan_position.current_pageno = \r
+                    scan_position.current_page.getPageNumber();\r
+\r
+                open_conglom.getContainer().removePage(\r
+                    scan_position.current_page);\r
+\r
+                // removePage unlatches the page, and page not available\r
+                // again until after commit.\r
+                scan_position.current_page = null;\r
+            }\r
+            else\r
+            {\r
+                positionAfterThisPage(scan_position);\r
+                scan_position.unlatch();\r
+            }\r
+\r
+\r
+            if (ret_row_count > 0)\r
+            {\r
+                // rows were moved on this page, give caller a chance to\r
+                // process those and free up access to the table.\r
+                return(ret_row_count);\r
+            }\r
+            else\r
+            {\r
+                // no rows were moved so go ahead and commit the transaction\r
+                // to allow other threads a chance at table.  Compress does\r
+                // need to sync as long as transaction either completely \r
+                // commits or backs out, either is fine.\r
+                /*\r
+                open_conglom.getXactMgr().commitNoSync(\r
+                    TransactionController.RELEASE_LOCKS);\r
+                open_conglom.reopen();\r
+                */\r
+                positionAtResumeScan(scan_position);\r
+\r
+            }\r
+               }\r
+\r
+        // Reached last page of scan.\r
+        positionAtDoneScan(scan_position);\r
+\r
+        // we need to decrement when we stop scan at the end of the table.\r
+        this.stat_numpages_visited--;\r
+\r
+               return(ret_row_count);\r
+    }\r
+\r
+    /**\r
+     * Reposition the scan upon entering the fetchRows loop.\r
+     * <p>\r
+     * Called upon entering fetchRows() while in the SCAN_INPROGRESS state.\r
+     * Do work necessary to look at rows in the current page of the scan.\r
+     * <p>\r
+     * The default implementation uses a record handle to maintain a scan\r
+     * position.  It will get the latch again on the current\r
+     * scan position and set the slot to the current record handle.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    protected void positionAtResumeScan(\r
+    RowPosition pos)\r
+               throws StandardException\r
+    {\r
+        // reposition the scan at the row just before the next one to return.\r
+        // This routine handles the mess of repositioning if the row or the\r
+        // page has disappeared. This can happen if a lock was not held on the\r
+        // row while not holding the latch.\r
+        open_conglom.latchPageAndRepositionScan(scan_position);\r
+    }\r
+\r
+    /**\r
+     * Move the scan from SCAN_INIT to SCAN_INPROGRESS.\r
+     * <p>\r
+     * This routine is called to move the scan from SCAN_INIT to \r
+     * SCAN_INPROGRESS.  Upon return from this routine it is expected\r
+     * that scan_position is set such that calling the generic \r
+     * scan loop will reach the first row of the scan.  Note that this\r
+     * usually means setting the scan_postion to one before the 1st \r
+     * row to be returned.\r
+     * <p>\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    protected void positionAtStartForForwardScan(\r
+    RowPosition pos)\r
+        throws StandardException\r
+    {\r
+        if (pos.current_rh == null)\r
+        {\r
+            // 1st positioning of scan (delayed from openScan).  Do not\r
+            // compress the first page, there is no previous page to move\r
+            // rows to, and moving the special Heap metadata row from the\r
+            // first page would cause problems.  Setting to next page is\r
+            // why this scan overrides generic implementation.\r
+            pos.current_page = \r
+                open_conglom.getContainer().getNextPage(\r
+                    ContainerHandle.FIRST_PAGE_NUMBER);\r
+\r
+            // set up for scan to continue at beginning of page following\r
+            // the first page of the container.\r
+            pos.current_slot = Page.FIRST_SLOT_NUMBER - 1;\r
+        }\r
+        else\r
+        {\r
+            // 1st positioning of scan following a reopenScanByRowLocation\r
+\r
+            // reposition the scan at the row just before the next one to \r
+            // return.  This routine handles the mess of repositioning if the \r
+            // row or the page has disappeared. This can happen if a lock was \r
+            // not held on the row while not holding the latch.\r
+            open_conglom.latchPageAndRepositionScan(pos);\r
+\r
+            // set up for scan to at the specified record handle (position one\r
+            // before it so that the loop increment and find it).\r
+            pos.current_slot -= 1;\r
+        }\r
+\r
+        pos.current_rh              = null;\r
+        this.stat_numpages_visited  = 1;\r
+        this.setScanState(SCAN_INPROGRESS);\r
+    }\r
+\r
+\r
+    /**************************************************************************\r
+     * Private/Protected methods of This class:\r
+     **************************************************************************\r
+     */\r
+\r
+    /**\r
+     * Set scan position to just after current page.\r
+     * <p>\r
+     * Used to set the position of the scan if a record handle is not\r
+     * avaliable.  In this case current_rh will be set to null, and \r
+     * current_pageno will be set to the current page number.\r
+     * On resume of the scan, the scan will be set to just before the first\r
+     * row returned form a getNextPage(current_pageno) call.\r
+     * <p>\r
+     * A positionAtResumeScan(scan_position) is necessary to continue the\r
+     * scan after this call.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    private void positionAfterThisPage(\r
+    RowPosition pos)\r
+        throws StandardException\r
+    {\r
+        pos.current_rh = null;\r
+        pos.current_pageno = pos.current_page.getPageNumber();\r
+    }\r
+\r
+       /*\r
+       ** Methods of ScanManager\r
+       */\r
+\r
+}\r