--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.conglomerate.OpenConglomerate\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.conglomerate;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\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.conglomerate.Conglomerate;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\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.SpaceInfo;\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.Transaction;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+\r
+import org.apache.derby.iapi.types.RowLocation;\r
+\r
+import java.util.Properties; \r
+\r
+\r
+/**\r
+\r
+A Generic class which implements the basic functionality needed to operate\r
+on an "open" conglomerate. This class assumes the following general things\r
+about the access method.\r
+<p>\r
+The access method is page based and contained in a single container maintained\r
+by raw store. \r
+\r
+**/\r
+\r
+public abstract class OpenConglomerate\r
+{\r
+ /**************************************************************************\r
+ * Fields of the class\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * The following group of fields are all basic input parameters which are\r
+ * provided by the calling code when doing any sort of operation requiring\r
+ * an open conglomerate (openScan(), open(), openCostController(), ...).\r
+ * These are just saved values from what was initially input.\r
+ **/\r
+ private Conglomerate init_conglomerate;\r
+ private TransactionManager init_xact_manager;\r
+ private Transaction init_rawtran;\r
+ private int init_openmode;\r
+ private int init_lock_level;\r
+ private DynamicCompiledOpenConglomInfo init_dynamic_info;\r
+ private boolean init_hold;\r
+ private LockingPolicy init_locking_policy;\r
+\r
+\r
+ /**\r
+ * convenience boolean's for various mode's\r
+ **/\r
+ private boolean useUpdateLocks;\r
+ private boolean forUpdate;\r
+ private boolean getBaseTableLocks;\r
+\r
+ /**\r
+ * scratch space used for stuff like templates, export rows, ...\r
+ **/\r
+ private OpenConglomerateScratchSpace runtime_mem;\r
+\r
+\r
+ /*\r
+ * The open raw store container associated with this open conglomerate\r
+ **/\r
+ private ContainerHandle container;\r
+\r
+ /**************************************************************************\r
+ * Constructors for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**************************************************************************\r
+ * Private methods for This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**************************************************************************\r
+ * abstract methods of This class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Return an "empty" row location object of the correct type.\r
+ * <p>\r
+ *\r
+ * @return The empty Rowlocation.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ protected abstract RowLocation newRowLocationTemplate()\r
+ throws StandardException;\r
+\r
+ abstract public int[] getFormatIds();\r
+\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing standard store row locking interfaces:\r
+ * latchPage(RowPosition)\r
+ * latchPageAndRepositionScan(RowPosition)\r
+ * lockPositionForRead(RowPosition, aux_pos, moveForwardIfRowDisappears)\r
+ * lockPositionForWrite(RowPosition, forInsert, wait)\r
+ * unlockPositionAfterRead(RowPosition)\r
+ **************************************************************************\r
+ */\r
+ /**\r
+ * Latch the page containing the current RowPosition, and reposition scan.\r
+ * <p>\r
+ * Upon return the scan will hold a latch on the page to continue the\r
+ * scan on. The scan will positioned on the record, just before the\r
+ * next record to return.\r
+ *\r
+ * Note that for both hold cursor and read uncommitted support this routine\r
+ * handles all cases of either the current position "dissappearing" (either\r
+ * the row and/or page). The row and/or page can disappear by deleted \r
+ * space being reclaimed post commit of that delete, and for some reason \r
+ * the code requesting the reposition does not have locks which prevented\r
+ * the space reclamation. Both hold cursor and read uncommitted scans are \r
+ * examples of ways the caller will not prevent space reclamation from \r
+ * claiming the position.\r
+ *\r
+ * This implementation also automatically updates the RowPosition to\r
+ * point at the slot containing the current RowPosition. This slot \r
+ * value is only valid while the latch is held.\r
+ *\r
+ * @return true if scan had to reposition because a row disappeared.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean latchPageAndRepositionScan(RowPosition pos)\r
+ throws StandardException\r
+ {\r
+ boolean scan_repositioned = false;\r
+\r
+ // Get the page the record handle refers to.\r
+ pos.current_page = null;\r
+\r
+ try\r
+ {\r
+ if (pos.current_rh != null)\r
+ {\r
+ pos.current_page = \r
+ container.getPage(pos.current_rh.getPageNumber());\r
+ }\r
+\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ // Assume all errors are caused by the page "disappearing", will\r
+ // handle this by positioning on next page in code below.\r
+ // Note that in most cases if the page does not exist, getPage()\r
+ // will return null rather than throw an exception, so this path\r
+ // is hard to reach.\r
+\r
+ // just continue on first record of the next page.\r
+ // This should only happen if the page on which the scan was\r
+ // positioned had all of it's row deleted and the page was\r
+ // purged.\r
+\r
+ // This can happen in a cursor held across a commit, where the\r
+ // scan needs to be repositioned after the first "next()" in the\r
+ // subsequent reopen() of the held cursor.\r
+ }\r
+\r
+ if (pos.current_page != null)\r
+ {\r
+ try\r
+ {\r
+ // reposition scan at the old position, now that latch is held.\r
+ pos.current_slot = \r
+ pos.current_page.getSlotNumber(pos.current_rh);\r
+ }\r
+ catch (StandardException se)\r
+ {\r
+ scan_repositioned = true;\r
+\r
+ // The record that the scan was positioned on, no longer exists.\r
+ // The normal way this happens is if we were positioned on\r
+ // a deleted row, without holding a lock on it, and while\r
+ // the scan did not hold the latch on the page a post commit\r
+ // job purged the row as part of space reclamation. This can\r
+ // happen in all ISOLATION level scans below serializable.\r
+ pos.current_slot = \r
+ pos.current_page.getNextSlotNumber(pos.current_rh);\r
+\r
+ if (pos.current_slot == -1)\r
+ {\r
+ // in this case we there are no more rows on this page\r
+ // to visit, so position on the next page. In this case\r
+ // the row that the scan was positioned on was purged,\r
+ // and there exists no rows now which are greater than this\r
+ // record id.\r
+\r
+ pos.current_page.unlatch();\r
+ pos.current_page = null;\r
+ }\r
+ else\r
+ {\r
+ // The way scans work, need to position on the row just\r
+ // before the one to return "next". The first thing the\r
+ // next loop will do is move the scan forward one row.\r
+ pos.current_slot--;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (pos.current_page == null)\r
+ {\r
+ // position on the next page.\r
+ long current_pageno;\r
+\r
+ if (pos.current_rh != null)\r
+ {\r
+ current_pageno = pos.current_rh.getPageNumber();\r
+ }\r
+ else if (pos.current_pageno != ContainerHandle.INVALID_PAGE_NUMBER)\r
+ {\r
+ current_pageno = pos.current_pageno;\r
+ }\r
+ else\r
+ {\r
+ // no valid position, return a null page\r
+ return(false);\r
+ }\r
+\r
+ pos.current_page = container.getNextPage(current_pageno);\r
+\r
+ pos.current_slot = Page.FIRST_SLOT_NUMBER - 1;\r
+\r
+ // now position is tracked by active page\r
+ pos.current_pageno = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+ scan_repositioned = true;\r
+ }\r
+\r
+ if (scan_repositioned)\r
+ {\r
+ pos.current_rh = null;\r
+ }\r
+\r
+ return(scan_repositioned);\r
+ }\r
+\r
+ /**\r
+ * Latch the page containing the current RowPosition.\r
+ * <p>\r
+ * This implementation also automatically updates the RowPosition to\r
+ * point at the slot containing the current RowPosition. This slot \r
+ * value is only valid while the latch is held.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean latchPage(RowPosition pos)\r
+ throws StandardException\r
+ {\r
+ pos.current_page = null; \r
+\r
+ try\r
+ {\r
+ pos.current_page = \r
+ container.getPage(pos.current_rh.getPageNumber());\r
+\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ // Assume all errors are caused by the page "disappearing", will\r
+ // handle this by returning false indicating that row can't be \r
+ // found. This can easily happen when using read uncommitted \r
+ // isolation level.\r
+ }\r
+\r
+ if (pos.current_page != null)\r
+ {\r
+ try\r
+ {\r
+ pos.current_slot = \r
+ pos.current_page.getSlotNumber(pos.current_rh);\r
+ \r
+ return(true);\r
+ }\r
+ catch (Throwable t)\r
+ {\r
+ // Assume all errors are caused by the row "disappearing",\r
+ // will handle this by returning false indicating that row\r
+ // can't be found. This can easily happen when using read\r
+ // uncommitted isolation level.\r
+\r
+ pos.current_page.unlatch();\r
+ pos.current_page = null;\r
+ }\r
+ }\r
+\r
+ return(false);\r
+ }\r
+\r
+\r
+ /**\r
+ * Lock row at given row position for read.\r
+ * <p>\r
+ * This routine requests a row lock NOWAIT on the row located at the given\r
+ * RowPosition. If the lock is granted NOWAIT the \r
+ * routine will return true. If the lock cannot be granted NOWAIT, then \r
+ * the routine will release the latch on "page" and then it will request \r
+ * a WAIT lock on the row. \r
+ * <p>\r
+ * This implementation:\r
+ * Assumes latch held on current_page.\r
+ * If the current_rh field of RowPosition is non-null it is assumed that\r
+ * we want to lock that record handle and that we don't have a slot number.\r
+ * If the current_rh field of RowPosition is null, it is assumed the we\r
+ * want to lock the indicated current_slot. Upon return current_rh will\r
+ * point to the record handle associated with current_slot.\r
+ * <p>\r
+ * After waiting and getting the lock on the row, this routine will fix up\r
+ * RowPosition to point at the row locked. This means it will get the\r
+ * page latch again, and it will fix the current_slot to point at the \r
+ * waited for record handle - it may have moved while waiting on the lock.\r
+ *\r
+ * @param pos Position to lock.\r
+ * @param aux_pos If you have to give up latch to get lock, then also \r
+ * unlock this position if it is non-null.\r
+ * @param moveForwardIfRowDisappears\r
+ * If true, then this routine must handle the case where\r
+ * the row id we are waiting on disappears when the latch\r
+ * is released. If false an exception will be thrown if\r
+ * the row disappears.\r
+ * @param waitForLock\r
+ * if true wait for lock, if lock can't be granted NOWAIT,\r
+ * else if false, throw a lock timeout exception if the\r
+ * lock can't be granted without waiting.\r
+ *\r
+ * @return true if lock granted without releasing the latch, else return\r
+ * false.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean lockPositionForRead(\r
+ RowPosition pos,\r
+ RowPosition aux_pos,\r
+ boolean moveForwardIfRowDisappears,\r
+ boolean waitForLock)\r
+ throws StandardException\r
+ {\r
+ if (pos.current_rh == null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(\r
+ pos.current_page != null &&\r
+ pos.current_slot != Page.INVALID_SLOT_NUMBER);\r
+\r
+ }\r
+\r
+ // work around for lockmanager problem with lock/latch releasing.\r
+ // Get RecordHandle to lock.\r
+ pos.current_rh = \r
+ pos.current_page.getRecordHandleAtSlot(pos.current_slot);\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // make sure current_rh and current_slot are in sync\r
+ if (pos.current_slot !=\r
+ pos.current_page.getSlotNumber(pos.current_rh))\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "current_slot = " + pos.current_slot +\r
+ "current_rh = " + pos.current_rh +\r
+ "current_rh.slot = " + \r
+ pos.current_page.getSlotNumber(pos.current_rh));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(pos.current_rh != null);\r
+\r
+ boolean lock_granted_with_latch_held =\r
+ this.container.getLockingPolicy().lockRecordForRead(\r
+ init_rawtran, container, pos.current_rh, \r
+ false /* NOWAIT */, forUpdate);\r
+\r
+ if (!lock_granted_with_latch_held)\r
+ {\r
+\r
+ // Could not get the lock NOWAIT, release latch and wait for lock.\r
+ pos.current_page.unlatch();\r
+ pos.current_page = null;\r
+\r
+\r
+ if (aux_pos != null)\r
+ {\r
+ aux_pos.current_page.unlatch();\r
+ aux_pos.current_page = null;\r
+ }\r
+\r
+ if (!waitForLock)\r
+ {\r
+ // throw lock timeout error.\r
+ throw StandardException.newException(SQLState.LOCK_TIMEOUT);\r
+ }\r
+\r
+ this.container.getLockingPolicy().lockRecordForRead(\r
+ init_rawtran, container, pos.current_rh, \r
+ true /* WAIT */, forUpdate);\r
+\r
+ if (moveForwardIfRowDisappears)\r
+ {\r
+\r
+ if (latchPageAndRepositionScan(pos))\r
+ {\r
+ if (pos.current_slot != -1)\r
+ {\r
+ // If scan was repositioned to just before a valid row\r
+ // on the current page, then move forward and lock and\r
+ // return that row (slot != -1). \r
+ // \r
+ // Let the caller handle the "-1" \r
+ // case, which may be one of 3 cases - need to go to \r
+ // slot 1 on current page, need to go to next page, \r
+ // need to end scan as there is no "next" page. All\r
+ // 3 cases are handled by the generic scan loop in \r
+ // GenericScanController.fetchRows().\r
+\r
+ pos.positionAtNextSlot();\r
+ lockPositionForRead(pos, aux_pos, true, true);\r
+\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ latchPage(pos);\r
+ }\r
+ }\r
+\r
+ return(lock_granted_with_latch_held);\r
+ }\r
+\r
+ public boolean lockPositionForWrite(\r
+ RowPosition pos,\r
+ boolean forInsert,\r
+ boolean waitForLock)\r
+ throws StandardException\r
+ {\r
+ if (pos.current_rh == null)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.ASSERT(pos.current_page != null);\r
+ SanityManager.ASSERT(\r
+ pos.current_slot != Page.INVALID_SLOT_NUMBER);\r
+\r
+ }\r
+\r
+ // work around for lockmanager problem with lock/latch releasing.\r
+ // Get RecordHandle to lock.\r
+ pos.current_rh = \r
+ pos.current_page.fetchFromSlot(\r
+ null, \r
+ pos.current_slot, \r
+ RowUtil.EMPTY_ROW, \r
+ RowUtil.EMPTY_ROW_FETCH_DESCRIPTOR, \r
+ true);\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ // make sure current_rh and current_slot are in sync\r
+ if (pos.current_slot !=\r
+ pos.current_page.getSlotNumber(pos.current_rh))\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "current_slot = " + pos.current_slot +\r
+ "current_rh = " + pos.current_rh +\r
+ "current_rh.slot = " + \r
+ pos.current_page.getSlotNumber(pos.current_rh));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(pos.current_rh != null);\r
+\r
+ boolean lock_granted_with_latch_held =\r
+ this.container.getLockingPolicy().\r
+ lockRecordForWrite(\r
+ init_rawtran, pos.current_rh, \r
+ forInsert, false /* NOWAIT */);\r
+\r
+ if (!lock_granted_with_latch_held)\r
+ {\r
+ if (!waitForLock)\r
+ {\r
+ // throw lock timeout error.\r
+ throw StandardException.newException(SQLState.LOCK_TIMEOUT);\r
+ }\r
+\r
+ // Could not get the lock NOWAIT, release latch and wait for lock.\r
+ pos.current_page.unlatch();\r
+ pos.current_page = null;\r
+\r
+ if (!waitForLock)\r
+ {\r
+ // throw lock timeout error.\r
+ throw StandardException.newException(SQLState.LOCK_TIMEOUT);\r
+ }\r
+\r
+ this.container.getLockingPolicy().\r
+ lockRecordForWrite(\r
+ init_rawtran, pos.current_rh, forInsert, true /* WAIT */);\r
+\r
+ latchPage(pos);\r
+ }\r
+\r
+ return(lock_granted_with_latch_held);\r
+ }\r
+\r
+\r
+ /**\r
+ * Unlock the record after a previous request to lock it.\r
+ * <p>\r
+ * Unlock the record after a previous call to lockRecordForRead(). It is\r
+ * expected that RowPosition contains information used to lock the record,\r
+ * Thus it is important if using a single RowPosition to track a scan to\r
+ * call unlock before you move the position forward to the next record.\r
+ * <p>\r
+ * Note that this routine assumes that the row was locked forUpdate if\r
+ * the OpenConglomerate is forUpdate, else it assumes the record was\r
+ * locked for read.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void unlockPositionAfterRead(\r
+ RowPosition pos) \r
+ throws StandardException\r
+ {\r
+ if (!isClosed())\r
+ container.getLockingPolicy().\r
+ unlockRecordAfterRead(\r
+ init_rawtran, container, pos.current_rh, forUpdate, \r
+ pos.current_rh_qualified);\r
+ }\r
+\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing ConglomPropertyQueryable Interface: \r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Request set of properties associated with a table. \r
+ * <p>\r
+ * Returns a property object containing all properties that the store\r
+ * knows about, which are stored persistently by the store. This set\r
+ * of properties may vary from implementation to implementation of the\r
+ * store.\r
+ * <p>\r
+ * This call is meant to be used only for internal query of the properties\r
+ * by jbms, for instance by language during bulk insert so that it can\r
+ * create a new conglomerate which exactly matches the properties that\r
+ * the original container was created with. This call should not be used\r
+ * by the user interface to present properties to users as it may contain\r
+ * properties that are meant to be internal to jbms. Some properties are \r
+ * meant only to be specified by jbms code and not by users on the command\r
+ * line.\r
+ * <p>\r
+ * Note that not all properties passed into createConglomerate() are stored\r
+ * persistently, and that set may vary by store implementation.\r
+ *\r
+ * @param prop Property list to add properties to. If null, routine will\r
+ * create a new Properties object, fill it in and return it.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public Properties getInternalTablePropertySet(Properties prop)\r
+ throws StandardException\r
+ {\r
+ Properties ret_properties = \r
+ ConglomerateUtil.createRawStorePropertySet(prop);\r
+\r
+ getTableProperties(ret_properties);\r
+\r
+ return(ret_properties);\r
+ }\r
+\r
+ /**\r
+ * Request the system properties associated with a table. \r
+ * <p>\r
+ * Request the value of properties that are associated with a table. The\r
+ * following properties can be requested:\r
+ * derby.storage.pageSize \r
+ * derby.storage.pageReservedSpace\r
+ * derby.storage.minimumRecordSize\r
+ * derby.storage.initialPages\r
+ * <p>\r
+ * To get the value of a particular property add it to the property list,\r
+ * and on return the value of the property will be set to it's current \r
+ * value. For example:\r
+ *\r
+ * get_prop(ConglomerateController cc)\r
+ * {\r
+ * Properties prop = new Properties();\r
+ * prop.put("derby.storage.pageSize", "");\r
+ * cc.getTableProperties(prop);\r
+ *\r
+ * System.out.println(\r
+ * "table's page size = " + \r
+ * prop.getProperty("derby.storage.pageSize");\r
+ * }\r
+ *\r
+ * @param prop Property list to fill in.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void getTableProperties(Properties prop)\r
+ throws StandardException\r
+ {\r
+ container.getContainerProperties(prop);\r
+\r
+ return;\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Accessors of This class:\r
+ **************************************************************************\r
+ */\r
+ public final TransactionManager getXactMgr()\r
+ {\r
+ return(init_xact_manager);\r
+ }\r
+\r
+ public final Transaction getRawTran()\r
+ {\r
+ return(init_rawtran);\r
+ }\r
+\r
+ public final ContainerHandle getContainer()\r
+ {\r
+ return(container);\r
+ }\r
+\r
+ public final int getOpenMode()\r
+ {\r
+ return(init_openmode);\r
+ }\r
+ \r
+ public final Conglomerate getConglomerate()\r
+ {\r
+ return(init_conglomerate);\r
+ }\r
+\r
+ public final boolean getHold()\r
+ {\r
+ return(init_hold);\r
+ }\r
+\r
+\r
+ public final boolean isForUpdate()\r
+ {\r
+ return(forUpdate);\r
+ }\r
+\r
+ public final boolean isClosed()\r
+ {\r
+ return(container == null);\r
+ }\r
+\r
+ public final boolean isUseUpdateLocks()\r
+ {\r
+ return(useUpdateLocks);\r
+ }\r
+\r
+ public final OpenConglomerateScratchSpace getRuntimeMem()\r
+ {\r
+ return(runtime_mem);\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods implementing some ConglomerateController Interfaces: \r
+ **************************************************************************\r
+ */\r
+\r
+\r
+ /**\r
+ * Check consistency of a conglomerate.\r
+ * <p>\r
+ * Checks the consistency of the data within a given conglomerate, does not\r
+ * check consistency external to the conglomerate (ie. does not check that \r
+ * base table row pointed at by a secondary index actually exists).\r
+ * <p>\r
+ * There is no checking in the default implementation, you must override\r
+ * to get conglomerate specific consistency checking.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void checkConsistency()\r
+ throws StandardException\r
+ {\r
+ return;\r
+ }\r
+\r
+\r
+\r
+ public void debugConglomerate()\r
+ throws StandardException\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "p_heap", "\nHEAP DUMP:containerId " + container.getId());\r
+\r
+ // get a template.\r
+\r
+ DataValueDescriptor[] row = \r
+ runtime_mem.get_row_for_export(getRawTran());\r
+\r
+ // Print pages of the heap.\r
+ Page page = container.getFirstPage();\r
+\r
+ while (page != null)\r
+ {\r
+ SanityManager.DEBUG_PRINT(\r
+ "p_heap", ConglomerateUtil.debugPage(page, 0, false, row));\r
+\r
+ long pageid = page.getPageNumber();\r
+ page.unlatch();\r
+ page = container.getNextPage(pageid);\r
+ }\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+\r
+ /**\r
+ Get information about space used by the conglomerate.\r
+ **/\r
+ public SpaceInfo getSpaceInfo()\r
+ throws StandardException\r
+ {\r
+ return container.getSpaceInfo();\r
+ }\r
+\r
+ protected boolean isKeyed()\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /**\r
+ * is the open btree table locked?\r
+ **/\r
+ protected boolean isTableLocked()\r
+ {\r
+ return(init_lock_level == TransactionController.MODE_TABLE);\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods of this class:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Open the container.\r
+ * <p>\r
+ * Open the container, obtaining necessary locks. Most work is actually\r
+ * done by RawStore.openContainer(). \r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ContainerHandle init(\r
+ ContainerHandle open_container,\r
+ Conglomerate conglomerate,\r
+ int[] format_ids,\r
+ int[] collation_ids,\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int openmode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ // save state of all inputs.\r
+ init_conglomerate = conglomerate;\r
+ init_xact_manager = xact_manager;\r
+ init_rawtran = rawtran;\r
+ init_openmode = openmode;\r
+ init_lock_level = lock_level;\r
+ init_dynamic_info = dynamic_info;\r
+ init_hold = hold;\r
+ init_locking_policy = locking_policy;\r
+\r
+\r
+ // either use passed in "compiled" runtime scratch space, or create\r
+ // new space.\r
+ this.runtime_mem = \r
+ (dynamic_info != null ? \r
+ ((OpenConglomerateScratchSpace) dynamic_info) : \r
+ new OpenConglomerateScratchSpace(format_ids, collation_ids));\r
+\r
+ // Is this an open for update or read? This will\r
+ // be passed down to the raw store fetch methods, which allows\r
+ // it to do the appropriate locking.\r
+ this.forUpdate = \r
+ ((openmode & ContainerHandle.MODE_FORUPDATE) != 0); \r
+\r
+ // keep track of whether this open conglomerate should use update locks.\r
+ this.useUpdateLocks = \r
+ ((openmode & ContainerHandle.MODE_USE_UPDATE_LOCKS) != 0);\r
+\r
+ // If this flag is set, then the client has already locked the row\r
+ // by accessing it through the secondary index and has already locked\r
+ // the row, so the base conglomerate need not re-lock the row.\r
+ this.getBaseTableLocks =\r
+ ((openmode & ContainerHandle.MODE_SECONDARY_LOCKED) == 0);\r
+\r
+ // if the conglomerate is temporary, open with IS_KEPT set.\r
+ // RESOLVE(mikem): track 1825\r
+ // don't want to open temp cantainer with IS_KEPT always.\r
+ if (conglomerate.isTemporary())\r
+ {\r
+ init_openmode |= ContainerHandle.MODE_TEMP_IS_KEPT;\r
+ }\r
+\r
+ if (!getBaseTableLocks)\r
+ init_locking_policy = null;\r
+\r
+ // Open the container. \r
+ this.container = \r
+ (open_container != null ? \r
+ open_container : \r
+ rawtran.openContainer(\r
+ conglomerate.getId(), init_locking_policy, init_openmode));\r
+\r
+ return(this.container);\r
+ }\r
+\r
+ /**\r
+ * Open the container.\r
+ * <p>\r
+ * Open the container, obtaining necessary locks. Most work is actually\r
+ * done by RawStore.openContainer(). Will only reopen() if the container\r
+ * is not already open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ContainerHandle reopen()\r
+ throws StandardException\r
+ {\r
+ // reget transaction from context manager, in the case of XA\r
+ // transaction this may have changed.\r
+ //\r
+ /* TODO - XA transactions my change the current transaction on the \r
+ * context stack. Will want to something like:\r
+ *\r
+ * init_rawtran = context_manager.getcurrenttransaction()\r
+ */\r
+ \r
+ if (this.container == null)\r
+ {\r
+ this.container = \r
+ init_rawtran.openContainer(\r
+ init_conglomerate.getId(), \r
+ init_locking_policy, \r
+ init_openmode);\r
+ }\r
+\r
+ return(this.container);\r
+ }\r
+\r
+ /**\r
+ * Close the container.\r
+ * <p>\r
+ * Handles being closed more than once.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void close()\r
+ throws StandardException\r
+ {\r
+ if (container != null)\r
+ {\r
+ container.close();\r
+ container = null;\r
+ }\r
+ }\r
+}\r