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 / HeapPostCommit.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/access/heap/HeapPostCommit.java
new file mode 100644 (file)
index 0000000..cadb335
--- /dev/null
@@ -0,0 +1,394 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.access.heap.HeapPostCommit\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.context.ContextManager;\r
+import org.apache.derby.iapi.services.daemon.Serviceable;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+\r
+import org.apache.derby.iapi.store.access.AccessFactory;\r
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;\r
+\r
+import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.LockingPolicy;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+/**\r
+\r
+The HeapPostCommit class implements the Serviceable protocol.  \r
+\r
+In it's role as a Serviceable object, it stores the state necessary to \r
+find a page in a heap that may have committed delete's to reclaim.\r
+\r
+It looks up the page described, and reclaims space in the conglomerate.  \r
+It first trys to clean up any deleted commits on the page.  It will then \r
+deallocate the page if no rows remain on the page.  All work is done while\r
+holding the latch on the page, and locks are never "waited" on while holding\r
+this latch.\r
+\r
+This implementation uses record level locking to reclaim the space.  \r
+For the protocols to work correctly all other heap methods must be \r
+prepared for a record or a page to "disappear" if they don't hold a latch and/or\r
+a lock.  An example of the problem case is a scan which does not hold locks\r
+on it's current position (group scan works this way), which is positioned\r
+on a row deleted by another xact, it must be prepared to continue the \r
+scan after getting an error if the current page/row disapppears.\r
+\r
+**/\r
+\r
+class HeapPostCommit implements Serviceable\r
+{\r
+    /**************************************************************************\r
+     * Fields of the class\r
+     **************************************************************************\r
+     */\r
+\r
+    private AccessFactory access_factory  = null;\r
+    private Heap          heap            = null;\r
+    private long          page_number     = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+\r
+    /**************************************************************************\r
+     * Constructors for This class:\r
+     **************************************************************************\r
+     */\r
+    HeapPostCommit(\r
+    AccessFactory   access_factory,\r
+    Heap            heap,\r
+    long            input_page_number)\r
+    {\r
+        this.access_factory = access_factory; \r
+        this.heap           = heap; \r
+        this.page_number    = input_page_number; \r
+    }\r
+\r
+    /**************************************************************************\r
+     * Private/Protected methods of This class:\r
+     **************************************************************************\r
+     */\r
+\r
+    /**\r
+     * Reclaim space taken up by committed deleted rows.\r
+     * <p>\r
+     * This routine assumes it has been called by an internal transaction which\r
+     * has performed no work so far, and that it has an exclusive intent table \r
+     * lock.  It will attempt obtain exclusive row locks on deleted rows, where\r
+     * successful those rows can be reclaimed as they must be "committed \r
+     * deleted" rows.\r
+     * <p>\r
+     * This routine will latch the page and hold the latch due to interface\r
+     * requirement from Page.purgeAtSlot.\r
+     *\r
+     * @param heap_control  The heap, already opened.\r
+     * @param pageno        number of page to look for committed deletes.\r
+     *\r
+     * @see Page#purgeAtSlot\r
+     * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    private final void purgeCommittedDeletes(\r
+    HeapController      heap_control,\r
+    long                pageno)\r
+        throws StandardException\r
+    {\r
+        // The following can fail either if it can't get the latch or\r
+        // somehow the page requested no longer exists. \r
+       \r
+       //resolve - what will happen if the user page doesnt exist  \r
+\r
+        // wait to get the latch on the page \r
+        Page page = heap_control.getUserPageWait(pageno);\r
+        boolean purgingDone = false;\r
+\r
+        if (page != null)\r
+        {\r
+            try\r
+            {\r
+                // The number records that can be reclaimed is:\r
+                // total recs - recs_not_deleted\r
+                int num_possible_commit_delete = \r
+                    page.recordCount() - page.nonDeletedRecordCount();\r
+\r
+                if (num_possible_commit_delete > 0)\r
+                {\r
+                    // loop backward so that purges which affect the slot table \r
+                    // don't affect the loop (ie. they only move records we \r
+                    // have already looked at).\r
+                    for (int slot_no = page.recordCount() - 1; \r
+                         slot_no >= 0; \r
+                         slot_no--) \r
+                    {\r
+                        boolean row_is_committed_delete = \r
+                            page.isDeletedAtSlot(slot_no);\r
+\r
+                        if (row_is_committed_delete)\r
+                        {\r
+                            // At this point we only know that the row is\r
+                            // deleted, not whether it is committed.\r
+\r
+                            // see if we can purge the row, by getting an\r
+                            // exclusive lock on the row.  If it is marked\r
+                            // deleted and we can get this lock, then it\r
+                            // must be a committed delete and we can purge \r
+                            // it.\r
+\r
+                            RecordHandle rh =\r
+                                page.fetchFromSlot(\r
+                                    (RecordHandle) null,\r
+                                    slot_no,\r
+                                    RowUtil.EMPTY_ROW,\r
+                                    RowUtil.EMPTY_ROW_FETCH_DESCRIPTOR,\r
+                                    true);\r
+\r
+                            row_is_committed_delete =\r
+                                heap_control.lockRowAtSlotNoWaitExclusive(rh);\r
+\r
+                            if (row_is_committed_delete)\r
+                            {\r
+                                purgingDone = true;\r
+\r
+                                page.purgeAtSlot(slot_no, 1, false);\r
+\r
+                                if (SanityManager.DEBUG)\r
+                                {\r
+                                    if (SanityManager.DEBUG_ON(\r
+                                            "verbose_heap_post_commit"))\r
+                                    {\r
+                                        SanityManager.DEBUG_PRINT(\r
+                                            "HeapPostCommit", \r
+                                            "Purging row[" + slot_no + "]" + \r
+                                            "on page:" + pageno + ".\n");\r
+                                    }\r
+                                }\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+                if (page.recordCount() == 0)\r
+                {\r
+                    purgingDone = true;\r
+\r
+                    // Deallocate the current page with 0 rows on it.\r
+                    heap_control.removePage(page);\r
+\r
+                    // removePage guarantees to unlatch the page even if an\r
+                    // exception is thrown. The page is protected against reuse\r
+                    // because removePage locks it with a dealloc lock, so it\r
+                    // is OK to release the latch even after a purgeAtSlot is\r
+                    // called.\r
+                    // @see ContainerHandle#removePage\r
+\r
+                    if (SanityManager.DEBUG)\r
+                    {\r
+                        if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))\r
+                        {\r
+                            SanityManager.DEBUG_PRINT(\r
+                                "HeapPostCommit", \r
+                                "Calling Heap removePage().; pagenumber="+pageno+"\n");\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+            finally\r
+            {\r
+                // If no purge happened on the page and the page is not\r
+                // removed, feel free to unlatch it.  Otherwise, let\r
+                // transaction commit take care of it.\r
+                               if (!purgingDone)\r
+                {\r
+                    page.unlatch();\r
+                    page = null;\r
+                }\r
+            }\r
+        }\r
+        else\r
+        {\r
+            if (SanityManager.DEBUG)\r
+            {\r
+                if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))\r
+                {\r
+                    SanityManager.DEBUG_PRINT(\r
+                        "HeapPostCommit", \r
+                        "Get No Wait returned null. page num = " + \r
+                        pageno + "\n");\r
+\r
+                    SanityManager.showTrace(new Throwable());\r
+                }\r
+            }\r
+        }\r
+        return;\r
+    }\r
+\r
+    /**************************************************************************\r
+     * Public Methods implementing the Serviceable interface:\r
+     **************************************************************************\r
+     */\r
+\r
+    /**\r
+     * The urgency of this post commit work.\r
+     * <p>\r
+     * This determines where this Serviceable is put in the post commit \r
+     * queue.  Post commit work in the heap can be safely delayed until there\r
+     * is not user work to do.\r
+     *\r
+     * @return false, this work should not be serviced ASAP\r
+     **/\r
+    public boolean serviceASAP()\r
+    {\r
+        return(true);\r
+    }\r
+\r
+       // @return true, if this work needs to be done on a user thread immediately\r
+       public boolean serviceImmediately()\r
+       {\r
+               return false;\r
+       }       \r
+\r
+\r
+    /**\r
+     * perform the work described in the postcommit work.\r
+     * <p>\r
+     * In this implementation the only work that can be executed by this\r
+     * post commit processor is this class itself.\r
+     * <p>\r
+     *\r
+     * @return Returns Serviceable.DONE when work has completed, or\r
+     *         returns Serviceable.REQUEUE if work needs to be requeued.\r
+     *\r
+     * @param contextMgr the context manager started by the post commit daemon\r
+     *\r
+     * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public int performWork(ContextManager contextMgr)\r
+        throws StandardException\r
+    {\r
+        TransactionManager  tc             = (TransactionManager)\r
+            this.access_factory.getAndNameTransaction(\r
+                contextMgr, AccessFactoryGlobals.SYS_TRANS_NAME);\r
+\r
+        TransactionManager  internal_xact  = tc.getInternalTransaction();\r
+\r
+        // only requeue if work was not completed in this try.\r
+        boolean             requeue_work = false;\r
+\r
+        HeapController      heapcontroller;\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))\r
+                SanityManager.DEBUG_PRINT(\r
+                    "HeapPostCommit", "starting internal xact\n");\r
+        }\r
+\r
+        try\r
+        {\r
+            // This call will attempt to open the heap table locked with \r
+            // table level IX mode, preparing to do record level locked space \r
+            // reclamation.  \r
+            //\r
+            // The call will either succeed immediately, or throw an exception\r
+            // which could mean the container does not exist or that the lock\r
+            // could not be granted immediately. \r
+\r
+                       //Reversed the fix for 4255:\r
+                       //page reclaimation is done asynchronosly by raswstore daemon\r
+                       //not good to WAIT FOR LOCKS , as it can freeze the daemon\r
+                       //If we can not get the lock this reclamation request will \r
+                       //requeued.\r
+\r
+            heapcontroller = (HeapController)\r
+                heap.open(\r
+                    internal_xact,\r
+                    internal_xact.getRawStoreXact(),\r
+                    false,\r
+                    ContainerHandle.MODE_FORUPDATE |\r
+                    ContainerHandle.MODE_LOCK_NOWAIT,\r
+                    TransactionController.MODE_RECORD,\r
+                    internal_xact.getRawStoreXact().newLockingPolicy(\r
+                        LockingPolicy.MODE_RECORD,\r
+                        TransactionController.ISOLATION_REPEATABLE_READ, true),\r
+                    heap,\r
+                    (DynamicCompiledOpenConglomInfo) null);\r
+\r
+            // We got a table intent lock, all deleted rows we encounter can\r
+            // be reclaimed, once an "X" row lock is obtained on them.\r
+\r
+            // Process all the rows on the page while holding the latch.\r
+            purgeCommittedDeletes(heapcontroller, this.page_number);\r
+\r
+        }\r
+        catch (StandardException se)\r
+        {\r
+            // exception might have occured either container got dropper or lock not granted.\r
+            // It is possible by the time this post commit work gets scheduled \r
+            // that the container has been dropped and that the open container \r
+            // call will return null - in this case just return assuming no \r
+            // work to be done.\r
+\r
+                       //If this expcetion is because lock could not be obtained , work is requeued.\r
+                       if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT) || \r
+                               se.getMessageId().equals(SQLState.DEADLOCK))\r
+                       {\r
+                               requeue_work = true;\r
+                       }\r
+\r
+            // Do not close the controller because that will unlatch the\r
+            // page.  Let the commit and destroy do release the latch and\r
+            // close the controller.\r
+            // heapcontroller.close();\r
+        }\r
+            \r
+        // It is ok to not sync this post work.  If no subsequent log record\r
+        // is sync'd to disk then it is ok that this transaction not make\r
+        // it to the database.  If any subsequent transaction is sync'd to\r
+        // the log file, then this transaction will be sync'd as part of that\r
+        // work.\r
+\r
+        internal_xact.commitNoSync(Transaction.RELEASE_LOCKS);\r
+        internal_xact.destroy();\r
+\r
+\r
+        if (SanityManager.DEBUG)\r
+        {\r
+            if (SanityManager.DEBUG_ON("verbose_heap_post_commit"))\r
+            {\r
+                if (requeue_work)\r
+                    SanityManager.DEBUG_PRINT(\r
+                        "HeapPostCommit", \r
+                        "requeueing on page num = " + page_number);\r
+            }\r
+        }\r
+\r
+        return(requeue_work ? Serviceable.REQUEUE : Serviceable.DONE);\r
+    }\r
+}\r
+\r