--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.store.access.heap.Heap\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
+\r
+package org.apache.derby.impl.store.access.heap;\r
+\r
+import java.io.ObjectOutput;\r
+import java.io.ObjectInput;\r
+import java.io.IOException;\r
+import java.util.Properties;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.io.ArrayInputStream;\r
+import org.apache.derby.iapi.services.io.FormatableBitSet;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.io.FormatIdUtil;\r
+import org.apache.derby.iapi.services.io.Storable;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\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.LogicalUndo;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+import org.apache.derby.iapi.store.access.conglomerate.ScanManager;\r
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;\r
+\r
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;\r
+import org.apache.derby.iapi.store.access.ColumnOrdering;\r
+import org.apache.derby.iapi.store.access.ConglomerateController;\r
+import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+import org.apache.derby.iapi.store.access.RowLocationRetRowSource;\r
+import org.apache.derby.iapi.store.access.RowUtil;\r
+import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;\r
+import org.apache.derby.iapi.store.access.StoreCostController;\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+\r
+import org.apache.derby.iapi.store.raw.ContainerKey;\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.Transaction;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+\r
+import org.apache.derby.iapi.services.cache.ClassSize;\r
+\r
+import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;\r
+import org.apache.derby.impl.store.access.conglomerate.GenericConglomerate;\r
+import org.apache.derby.impl.store.access.conglomerate.OpenConglomerate;\r
+import org.apache.derby.impl.store.access.conglomerate.OpenConglomerateScratchSpace;\r
+\r
+/**\r
+ * @format_id ACCESS_HEAP_V2_ID\r
+ *\r
+ * @purpose The tag that describes the on disk representation of the Heap\r
+ * conglomerate object. Access contains no "directory" of \r
+ * conglomerate information. In order to bootstrap opening a file\r
+ * it encodes the factory that can open the conglomerate in the \r
+ * conglomerate id itself. There exists a single HeapFactory which\r
+ * must be able to read all heap format id's. \r
+ *\r
+ * This format was used for all Derby database Heap's in version\r
+ * 10.2 and previous versions.\r
+ *\r
+ * @upgrade The format id of this object is currently always read from disk\r
+ * as the first field of the conglomerate itself. A bootstrap\r
+ * problem exists as we don't know the format id of the heap \r
+ * until we are in the "middle" of reading the Heap. Thus the\r
+ * base Heap implementation must be able to read and write \r
+ * all formats based on the reading the \r
+ * "format_of_this_conglomerate". \r
+ *\r
+ * soft upgrade to ACCESS_HEAP_V3_ID:\r
+ * read:\r
+ * old format is readable by current Heap implementation,\r
+ * with automatic in memory creation of default collation\r
+ * id needed by new format. No code other than\r
+ * readExternal and writeExternal need know about old format.\r
+ * write:\r
+ * will never write out new format id in soft upgrade mode.\r
+ * Code in readExternal and writeExternal handles writing\r
+ * correct version. Code in the factory handles making\r
+ * sure new conglomerates use the Heap_v10_2 class to \r
+ * that will write out old format info.\r
+ *\r
+ * hard upgrade to ACCESS_HEAP_V3_ID:\r
+ * read:\r
+ * old format is readable by current Heap implementation,\r
+ * with automatic in memory creation of default collation\r
+ * id needed by new format.\r
+ * write:\r
+ * Only "lazy" upgrade will happen. New format will only\r
+ * get written for new conglomerate created after the \r
+ * upgrade. Old conglomerates continue to be handled the\r
+ * same as soft upgrade.\r
+ *\r
+ * @disk_layout\r
+ * format_of_this_conlgomerate(byte[])\r
+ * containerid(long)\r
+ * segmentid(int)\r
+ * number_of_columns(int)\r
+ * array_of_format_ids(byte[][])\r
+ **/\r
+\r
+/**\r
+ * @format_id ACCESS_HEAP_V3_ID\r
+ *\r
+ * @purpose The tag that describes the on disk representation of the Heap\r
+ * conglomerate object. The Heap conglomerate object is stored in\r
+ * a field of a row in the Conglomerate directory.\r
+ *\r
+ * @purpose The tag that describes the on disk representation of the Heap\r
+ * conglomerate object. Access contains no "directory" of \r
+ * conglomerate information. In order to bootstrap opening a file\r
+ * it encodes the factory that can open the conglomerate in the \r
+ * conglomerate id itself. There exists a single HeapFactory which\r
+ * must be able to read all heap format id's. \r
+ *\r
+ * This format is used for all Derby database Heap's in versions\r
+ * subsequent to 10.2. The format is contains first the \r
+ * ACCESS_HEAP_V2_ID format, followed by a compressed representation\r
+ * of the collation id's of each column in the heap.\r
+ *\r
+ * @upgrade This is the current version, no upgrade necessary.\r
+ *\r
+ * @disk_layout\r
+ * format_of_this_conlgomerate(byte[])\r
+ * containerid(long)\r
+ * segmentid(int)\r
+ * number_of_columns(int)\r
+ * array_of_format_ids(byte[][])\r
+ * collation_ids(compressed array of ints)\r
+ **/\r
+\r
+/**\r
+\r
+ A heap object corresponds to an instance of a heap conglomerate. It caches\r
+ information which makes it fast to open heap controllers from it.\r
+\r
+**/\r
+\r
+public class Heap \r
+ extends GenericConglomerate\r
+ implements Conglomerate, StaticCompiledOpenConglomInfo\r
+{\r
+\r
+\r
+ /*\r
+ ** Fields of Heap.\r
+ */\r
+\r
+ /**\r
+ * Format id of the conglomerate.\r
+ **/\r
+ protected int conglom_format_id;\r
+\r
+ private ContainerKey id;\r
+\r
+ /**\r
+ * The format id's of each of the columns in the heap table.\r
+ **/\r
+ int[] format_ids;\r
+\r
+ /**\r
+ The array of collation id's for each column in the template.\r
+ **/\r
+ protected int[] collation_ids;\r
+\r
+ private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( Heap.class);\r
+ private static final int CONTAINER_KEY_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( ContainerKey.class);\r
+\r
+ public int estimateMemoryUsage()\r
+ {\r
+ int sz = BASE_MEMORY_USAGE;\r
+\r
+ if( null != id)\r
+ sz += CONTAINER_KEY_MEMORY_USAGE;\r
+ if( null != format_ids)\r
+ sz += format_ids.length*ClassSize.getIntSize();\r
+ return sz;\r
+ } // end of estimateMemoryUsage\r
+\r
+ /*\r
+ ** Methods of Heap.\r
+ */\r
+\r
+ /* Constructors for This class: */\r
+\r
+ /**\r
+ * Zero arg constructor for Monitor to create empty object.\r
+ **/\r
+ public Heap()\r
+ {\r
+ }\r
+\r
+ /* Private/Protected methods of This class: */\r
+\r
+ /**\r
+ * Create a heap conglomerate.\r
+ * <p>\r
+ * Create a heap conglomerate. This method is called from the heap factory\r
+ * to create a new instance of a heap.\r
+ * <p>\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ protected void create(\r
+ Transaction rawtran,\r
+ int segmentId,\r
+ long input_containerid,\r
+ DataValueDescriptor[] template,\r
+ ColumnOrdering[] columnOrder,\r
+ int[] collationIds,\r
+ Properties properties,\r
+ int conglom_format_id,\r
+ int tmpFlag)\r
+ throws StandardException\r
+ {\r
+ // Create a container for the heap table with\r
+ // default minimumRecordSize to be at least\r
+ // MINIMUM_RECORD_SIZE_DEFAULT (12),\r
+ // to guarantee there is enough room for updates\r
+ // of the row.\r
+ // Here we only take care of the case that\r
+ // that the properties are set with the create\r
+ // statement. For the case when properties are\r
+ // not set with the create statement, it is taken\r
+ // care of in fileContainer.java: createInfoFromProp().\r
+ if (properties != null) \r
+ {\r
+ String value = properties.getProperty(\r
+ RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER);\r
+\r
+ int minimumRecordSize =\r
+ (value == null) ? \r
+ RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT : \r
+ Integer.parseInt(value);\r
+\r
+ if (minimumRecordSize < RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT)\r
+ {\r
+ properties.put(\r
+ RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER,\r
+ Integer.toString(\r
+ RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT));\r
+ }\r
+ }\r
+\r
+ // Create a container for the heap with default page size.\r
+ long containerid = \r
+ rawtran.addContainer(\r
+ segmentId, input_containerid, \r
+ ContainerHandle.MODE_DEFAULT, properties, tmpFlag);\r
+\r
+ // Make sure the container was actually created.\r
+ if (containerid < 0)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CANT_CREATE_CONTAINER);\r
+ }\r
+\r
+ // Keep track of what segment the container's in.\r
+ id = new ContainerKey(segmentId, containerid);\r
+\r
+ // Heap requires a template representing every column in the table.\r
+ if ((template == null) || (template.length == 0))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_COULD_NOT_CREATE_CONGLOMERATE);\r
+ }\r
+\r
+ // get format id's from each column in template and store it in the\r
+ // conglomerate state.\r
+ this.format_ids = ConglomerateUtil.createFormatIds(template);\r
+\r
+ // copy the format id of the conglomerate.\r
+ this.conglom_format_id = conglom_format_id;\r
+\r
+ // get collation ids from input collation ids, store it in the \r
+ // conglom state.\r
+ collation_ids = \r
+ ConglomerateUtil.createCollationIds(\r
+ format_ids.length, collationIds);\r
+\r
+ // need to open the container and insert the row. Since we are\r
+ // creating it no need to bother with locking since no one can get\r
+ // to it until after we have created it and returned it's id.\r
+ ContainerHandle container = null;\r
+ Page page = null;\r
+\r
+ try\r
+ {\r
+ container = \r
+ rawtran.openContainer(\r
+ id, (LockingPolicy) null, \r
+ ContainerHandle.MODE_FORUPDATE | \r
+ (isTemporary() ? ContainerHandle.MODE_TEMP_IS_KEPT : 0));\r
+\r
+ // row in slot 0 of heap page 1 which is just a single column with\r
+ // the heap entry.\r
+ DataValueDescriptor[] control_row = new DataValueDescriptor[1];\r
+ control_row[0] = this;\r
+\r
+ page =\r
+ container.getPage(ContainerHandle.FIRST_PAGE_NUMBER);\r
+\r
+ page.insertAtSlot(\r
+ Page.FIRST_SLOT_NUMBER,\r
+ control_row,\r
+ (FormatableBitSet) null,\r
+ (LogicalUndo) null, \r
+ Page.INSERT_OVERFLOW,\r
+ AccessFactoryGlobals.HEAP_OVERFLOW_THRESHOLD);\r
+ page.unlatch();\r
+ page = null;\r
+\r
+ // Don't include the control row in the estimated row count.\r
+ container.setEstimatedRowCount(0, /* unused flag */ 0);\r
+ }\r
+ finally\r
+ {\r
+ if (container != null)\r
+ container.close();\r
+ if (page !=null)\r
+ page.unlatch();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Create a heap conglomerate during the boot process.\r
+ * <p>\r
+ * Manufacture a Heap Conglomerate out of "thin" air, to boot strap\r
+ * the system. Create an in-memory Heap Conglomerate with the input\r
+ * parameters, The caller will use this to open the conglomerate\r
+ * conglomerate and read the "real" values from disk. Conglom-conglom\r
+ * is always on segment 0.\r
+ *\r
+ *\r
+ * @param containerid The container id of the conglomerate.\r
+ * @param template Object array describing the columns of the heap.\r
+ **/\r
+ public void boot_create(\r
+ long containerid,\r
+ DataValueDescriptor[] template)\r
+ {\r
+ id = new ContainerKey(0, containerid);\r
+ this.format_ids = ConglomerateUtil.createFormatIds(template);\r
+ }\r
+\r
+ /*\r
+ ** Methods of Conglomerate\r
+ */\r
+\r
+ /**\r
+ * Add a column to the heap conglomerate.\r
+ * <p>\r
+ * This routine update's the in-memory object version of the Heap\r
+ * Conglomerate to have one more column of the type described by the\r
+ * input template column. \r
+ * \r
+ * @param column_id The column number to add this column at.\r
+ * @param template_column An instance of the column to be added to table.\r
+ * @param collation_id Collation id of the column added.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public void addColumn(\r
+ TransactionManager xact_manager,\r
+ int column_id,\r
+ Storable template_column,\r
+ int collation_id)\r
+ throws StandardException\r
+ {\r
+ // need to open the container and update the row containing the \r
+ // serialized format of the heap. \r
+ ContainerHandle container = null;\r
+ Page page = null;\r
+ Transaction rawtran = xact_manager.getRawStoreXact();\r
+\r
+ try\r
+ {\r
+ container = \r
+ rawtran.openContainer(\r
+ id, \r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_SERIALIZABLE, true),\r
+ ContainerHandle.MODE_FORUPDATE | \r
+ (isTemporary() ? ContainerHandle.MODE_TEMP_IS_KEPT : 0));\r
+\r
+ if (column_id != format_ids.length)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.THROWASSERT(\r
+ "column_id = " + column_id +\r
+ "format_ids.length = " + format_ids.length +\r
+ "format_ids = " + format_ids);\r
+\r
+ throw(StandardException.newException(\r
+ SQLState.HEAP_TEMPLATE_MISMATCH,\r
+ new Long(column_id), \r
+ new Long(this.format_ids.length)));\r
+ }\r
+\r
+ // create a new array, and copy old values to it.\r
+ int[] old_format_ids = format_ids;\r
+ format_ids = new int[old_format_ids.length + 1];\r
+ System.arraycopy(\r
+ old_format_ids, 0, format_ids, 0, old_format_ids.length);\r
+\r
+ // add the new column\r
+ format_ids[old_format_ids.length] = \r
+ template_column.getTypeFormatId();\r
+\r
+ // create a new collation array, and copy old values to it.\r
+ int[] old_collation_ids = collation_ids;\r
+ collation_ids = new int[old_collation_ids.length + 1];\r
+ System.arraycopy(\r
+ old_collation_ids, 0, collation_ids, 0, \r
+ old_collation_ids.length);\r
+\r
+ // add the new column's collation id.\r
+ collation_ids[old_collation_ids.length] = collation_id;\r
+ \r
+ // row in slot 0 of heap page 1 which is just a single column with\r
+ // the heap entry.\r
+ DataValueDescriptor[] control_row = new DataValueDescriptor[1];\r
+ control_row[0] = this;\r
+\r
+ page =\r
+ container.getPage(ContainerHandle.FIRST_PAGE_NUMBER);\r
+\r
+ page.updateAtSlot(\r
+ Page.FIRST_SLOT_NUMBER,\r
+ control_row,\r
+ (FormatableBitSet) null);\r
+\r
+ page.unlatch();\r
+ page = null;\r
+ }\r
+ finally\r
+ {\r
+ if (container != null)\r
+ container.close();\r
+ if (page !=null)\r
+ page.unlatch();\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+\r
+ /**\r
+ Drop this heap.\r
+ @see Conglomerate#drop\r
+\r
+ @exception StandardException Standard exception policy.\r
+ **/\r
+ public void drop(TransactionManager xact_manager)\r
+ throws StandardException\r
+ {\r
+ xact_manager.getRawStoreXact().dropContainer(id);\r
+ }\r
+\r
+ /**\r
+ * Retrieve the maximum value row in an ordered conglomerate.\r
+ * <p>\r
+ * Returns true and fetches the rightmost row of an ordered conglomerate \r
+ * into "fetchRow" if there is at least one row in the conglomerate. If\r
+ * there are no rows in the conglomerate it returns false.\r
+ * <p>\r
+ * Non-ordered conglomerates will not implement this interface, calls\r
+ * will generate a StandardException.\r
+ * <p>\r
+ * RESOLVE - this interface is temporary, long term equivalent (and more) \r
+ * functionality will be provided by the openBackwardScan() interface. \r
+ *\r
+ * @param conglomId The identifier of the conglomerate\r
+ * to open the scan for.\r
+ *\r
+ * @param open_mode Specifiy flags to control opening of table. \r
+ * OPENMODE_FORUPDATE - if set open the table for\r
+ * update otherwise open table shared.\r
+ * @param lock_level One of (MODE_TABLE, MODE_RECORD, or MODE_NONE).\r
+ *\r
+ * @param isolation_level The isolation level to lock the conglomerate at.\r
+ * One of (ISOLATION_READ_COMMITTED or \r
+ * ISOLATION_SERIALIZABLE).\r
+ *\r
+ * @param scanColumnList A description of which columns to return from \r
+ * every fetch in the scan. template, \r
+ * and scanColumnList work together\r
+ * to describe the row to be returned by the scan - \r
+ * see RowUtil for description of how these three \r
+ * parameters work together to describe a "row".\r
+ *\r
+ * @param fetchRow The row to retrieve the maximum value into.\r
+ *\r
+ * @return boolean indicating if a row was found and retrieved or not.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public boolean fetchMaxOnBTree(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ long conglomId,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] fetchRow)\r
+ throws StandardException\r
+ {\r
+ // no support for max on a heap table.\r
+ throw(StandardException.newException(\r
+ SQLState.HEAP_UNIMPLEMENTED_FEATURE));\r
+ }\r
+\r
+ /**\r
+ * Get the id of the container of the conglomerate.\r
+ * <p>\r
+ * Will have to change when a conglomerate could have more than one \r
+ * container. The ContainerKey is a combination of the container id\r
+ * and segment id.\r
+ *\r
+ * @return The ContainerKey.\r
+ **/\r
+ public final ContainerKey getId()\r
+ {\r
+ return(id);\r
+ }\r
+\r
+\r
+ public final long getContainerid()\r
+ {\r
+ return(id.getContainerId());\r
+ }\r
+\r
+ /**\r
+ * Return dynamic information about the conglomerate to be dynamically \r
+ * reused in repeated execution of a statement.\r
+ * <p>\r
+ * The dynamic info is a set of variables to be used in a given \r
+ * ScanController or ConglomerateController. It can only be used in one \r
+ * controller at a time. It is up to the caller to insure the correct \r
+ * thread access to this info. The type of info in this is a scratch \r
+ * template for btree traversal, other scratch variables for qualifier \r
+ * evaluation, ...\r
+ * <p>\r
+ *\r
+ * @return The dynamic information.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate to open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public DynamicCompiledOpenConglomInfo getDynamicCompiledConglomInfo(\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ return(new OpenConglomerateScratchSpace(format_ids, collation_ids));\r
+ }\r
+\r
+ /**\r
+ * Return static information about the conglomerate to be included in a\r
+ * a compiled plan.\r
+ * <p>\r
+ * The static info would be valid until any ddl was executed on the \r
+ * conglomid, and would be up to the caller to throw away when that \r
+ * happened. This ties in with what language already does for other \r
+ * invalidation of static info. The type of info in this would be \r
+ * containerid and array of format id's from which templates can be created.\r
+ * The info in this object is read only and can be shared among as many \r
+ * threads as necessary.\r
+ * <p>\r
+ *\r
+ * @return The static compiled information.\r
+ *\r
+ * @param conglomId The identifier of the conglomerate to open.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public StaticCompiledOpenConglomInfo getStaticCompiledConglomInfo(\r
+ TransactionController tc,\r
+ long conglomId)\r
+ throws StandardException\r
+ {\r
+ return(this);\r
+ }\r
+\r
+\r
+ /**\r
+ * Is this conglomerate temporary?\r
+ * <p>\r
+ *\r
+ * @return whether conglomerate is temporary or not.\r
+ **/\r
+ public boolean isTemporary()\r
+ {\r
+ return(id.getSegmentId() == ContainerHandle.TEMPORARY_SEGMENT);\r
+ }\r
+\r
+\r
+ /**\r
+ * Bulk load into the conglomerate.\r
+ * <p>\r
+ *\r
+ * @see Conglomerate#load\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public long load(\r
+ TransactionManager xact_manager,\r
+ boolean createConglom,\r
+ RowLocationRetRowSource rowSource)\r
+ throws StandardException\r
+ {\r
+ long num_rows_loaded = 0;\r
+\r
+ HeapController heapcontroller = new HeapController();\r
+\r
+ try\r
+ {\r
+ num_rows_loaded = \r
+ heapcontroller.load(\r
+ xact_manager,\r
+ this, \r
+ createConglom,\r
+ rowSource);\r
+ }\r
+ finally\r
+ {\r
+ // Done with this heap controller.\r
+ heapcontroller.close();\r
+ }\r
+\r
+ return(num_rows_loaded);\r
+ }\r
+\r
+ /**\r
+ * Open a heap controller.\r
+ * <p>\r
+ *\r
+ * @see Conglomerate#open\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ConglomerateController open(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ OpenConglomerate open_conglom = new OpenHeap();\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ locking_policy,\r
+ dynamic_info) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()).toString());\r
+ }\r
+\r
+ HeapController heapcontroller = new HeapController();\r
+\r
+ heapcontroller.init(open_conglom);\r
+\r
+ return(heapcontroller);\r
+ }\r
+\r
+ /**\r
+ * Open a heap scan controller.\r
+ * <p>\r
+ *\r
+ * @see Conglomerate#openScan\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ScanManager openScan(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level,\r
+ FormatableBitSet scanColumnList,\r
+ DataValueDescriptor[] startKeyValue,\r
+ int startSearchOperator,\r
+ Qualifier qualifier[][],\r
+ DataValueDescriptor[] stopKeyValue,\r
+ int stopSearchOperator,\r
+ StaticCompiledOpenConglomInfo static_info,\r
+ DynamicCompiledOpenConglomInfo dynamic_info)\r
+ throws StandardException\r
+ {\r
+ // Heap scans do not suppport start and stop scan positions (these\r
+ // only make sense for ordered storage structures).\r
+ if (!RowUtil.isRowEmpty(startKeyValue)\r
+ || !RowUtil.isRowEmpty(stopKeyValue))\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_UNIMPLEMENTED_FEATURE);\r
+ }\r
+\r
+ OpenConglomerate open_conglom = new OpenHeap();\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ locking_policy,\r
+ dynamic_info) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()));\r
+ }\r
+\r
+ HeapScan heapscan = new HeapScan();\r
+\r
+ heapscan.init(\r
+ open_conglom,\r
+ scanColumnList,\r
+ startKeyValue,\r
+ startSearchOperator,\r
+ qualifier,\r
+ stopKeyValue,\r
+ stopSearchOperator);\r
+\r
+ return(heapscan);\r
+ }\r
+\r
+ public void purgeConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ OpenConglomerate open_for_ddl_lock = null;\r
+ HeapController heapcontroller = null;\r
+ TransactionManager nested_xact = null;\r
+\r
+ try\r
+ {\r
+ open_for_ddl_lock = new OpenHeap();\r
+\r
+ // Open table in intended exclusive mode in the top level \r
+ // transaction, this will stop any ddl from happening until \r
+ // purge of whole table is finished.\r
+\r
+ if (open_for_ddl_lock.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ false,\r
+ TransactionController.OPENMODE_FORUPDATE,\r
+ TransactionController.MODE_RECORD,\r
+ null,\r
+ null) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()));\r
+ }\r
+\r
+ // perform all the "real" work in a non-readonly nested user \r
+ // transaction, so that as work is completed on each page resources\r
+ // can be released. Must be careful as all locks obtained in nested\r
+ // transaction will conflict with parent transaction - so this call\r
+ // must be made only if parent transaction can have no conflicting\r
+ // locks on the table, otherwise the purge will fail with a self\r
+ // deadlock.\r
+ nested_xact = (TransactionManager) \r
+ xact_manager.startNestedUserTransaction(false);\r
+\r
+ // now open the table in a nested user transaction so that each\r
+ // page worth of work can be committed after it is done.\r
+\r
+ OpenConglomerate open_conglom = new OpenHeap();\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ nested_xact,\r
+ nested_xact.getRawStoreXact(),\r
+ true,\r
+ TransactionController.OPENMODE_FORUPDATE,\r
+ TransactionController.MODE_RECORD,\r
+ nested_xact.getRawStoreXact().newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_REPEATABLE_READ, true),\r
+ null) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()).toString());\r
+ }\r
+\r
+ heapcontroller = new HeapController();\r
+\r
+ heapcontroller.init(open_conglom);\r
+\r
+ Page page = open_conglom.getContainer().getFirstPage();\r
+\r
+ boolean purgingDone = false;\r
+\r
+ while (page != null)\r
+ {\r
+ long pageno = page.getPageNumber();\r
+ purgingDone = heapcontroller.purgeCommittedDeletes(page);\r
+\r
+ if (purgingDone)\r
+ {\r
+ page = null;\r
+\r
+ // commit xact to free resouurces ASAP, commit will\r
+ // unlatch the page if it has not already been unlatched\r
+ // by a remove.\r
+ open_conglom.getXactMgr().commitNoSync(\r
+ TransactionController.RELEASE_LOCKS);\r
+\r
+ // the commit closes the underlying container, so let\r
+ // the heapcontroller know this has happened. Usually\r
+ // the transaction takes care of this, but this controller\r
+ // is internal, so the transaction does not know about it.\r
+ heapcontroller.closeForEndTransaction(false);\r
+ \r
+ // the commit will close the underlying \r
+ open_conglom.reopen();\r
+ }\r
+ else\r
+ {\r
+ page.unlatch();\r
+ page = null;\r
+ }\r
+\r
+ page = open_conglom.getContainer().getNextPage(pageno);\r
+ }\r
+ }\r
+ finally\r
+ {\r
+ if (open_for_ddl_lock != null)\r
+ open_for_ddl_lock.close();\r
+ if (heapcontroller != null)\r
+ heapcontroller.close();\r
+ if (nested_xact != null)\r
+ {\r
+ nested_xact.commitNoSync(TransactionController.RELEASE_LOCKS);\r
+ nested_xact.destroy();\r
+ }\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ public void compressConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ OpenConglomerate open_conglom = null;\r
+ HeapController heapcontroller = null;\r
+\r
+ try\r
+ {\r
+ open_conglom = new OpenHeap();\r
+\r
+ // Open table in intended exclusive mode in the top level \r
+ // transaction, this will stop any ddl from happening until \r
+ // purge of whole table is finished.\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ false,\r
+ TransactionController.OPENMODE_FORUPDATE,\r
+ TransactionController.MODE_TABLE,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_CONTAINER,\r
+ TransactionController.ISOLATION_REPEATABLE_READ, true),\r
+ null) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()));\r
+ }\r
+\r
+ heapcontroller = new HeapController();\r
+\r
+ heapcontroller.init(open_conglom);\r
+\r
+ open_conglom.getContainer().compressContainer();\r
+ }\r
+ finally\r
+ {\r
+ if (open_conglom != null)\r
+ open_conglom.close();\r
+ }\r
+\r
+ return;\r
+ }\r
+\r
+ /**\r
+ * Open a heap compress scan.\r
+ * <p>\r
+ *\r
+ * @see Conglomerate#defragmentConglomerate\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ **/\r
+ public ScanManager defragmentConglomerate(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran,\r
+ boolean hold,\r
+ int open_mode,\r
+ int lock_level,\r
+ LockingPolicy locking_policy,\r
+ int isolation_level)\r
+ throws StandardException\r
+ {\r
+ OpenConglomerate open_conglom = new OpenHeap();\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ hold,\r
+ open_mode,\r
+ lock_level,\r
+ rawtran.newLockingPolicy(\r
+ LockingPolicy.MODE_RECORD,\r
+ TransactionController.ISOLATION_REPEATABLE_READ, true),\r
+ null) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()));\r
+ }\r
+\r
+ HeapCompressScan heap_compress_scan = new HeapCompressScan();\r
+\r
+ heap_compress_scan.init(\r
+ open_conglom,\r
+ null,\r
+ null,\r
+ 0,\r
+ null,\r
+ null,\r
+ 0);\r
+\r
+ return(heap_compress_scan);\r
+ }\r
+\r
+\r
+ /**\r
+ * Return an open StoreCostController for the conglomerate.\r
+ * <p>\r
+ * Return an open StoreCostController which can be used to ask about \r
+ * the estimated row counts and costs of ScanController and \r
+ * ConglomerateController operations, on the given conglomerate.\r
+ * <p>\r
+ * @param xact_manager The TransactionController under which this \r
+ * operation takes place.\r
+ * @param rawtran raw transaction context in which scan is managed.\r
+ *\r
+ * @return The open StoreCostController.\r
+ *\r
+ * @exception StandardException Standard exception policy.\r
+ *\r
+ * @see StoreCostController\r
+ **/\r
+ public StoreCostController openStoreCost(\r
+ TransactionManager xact_manager,\r
+ Transaction rawtran)\r
+ throws StandardException\r
+ {\r
+ OpenHeap open_conglom = new OpenHeap();\r
+\r
+ if (open_conglom.init(\r
+ (ContainerHandle) null,\r
+ this,\r
+ this.format_ids,\r
+ this.collation_ids,\r
+ xact_manager,\r
+ rawtran,\r
+ false,\r
+ ContainerHandle.MODE_READONLY,\r
+ TransactionController.MODE_TABLE,\r
+ (LockingPolicy) null,\r
+ (DynamicCompiledOpenConglomInfo) null) == null)\r
+ {\r
+ throw StandardException.newException(\r
+ SQLState.HEAP_CONTAINER_NOT_FOUND, \r
+ new Long(id.getContainerId()));\r
+ }\r
+\r
+\r
+ HeapCostController heapcost = new HeapCostController();\r
+\r
+ heapcost.init(open_conglom);\r
+\r
+ return(heapcost);\r
+ }\r
+\r
+\r
+ /**\r
+ * Print this heap.\r
+ **/\r
+ public String toString()\r
+ {\r
+ return (id == null) ? "null" : id.toString();\r
+ }\r
+\r
+ /**************************************************************************\r
+ * Public Methods of StaticCompiledOpenConglomInfo Interface:\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * return the "Conglomerate".\r
+ * <p>\r
+ * For heap just return "this", which both implements Conglomerate and\r
+ * StaticCompiledOpenConglomInfo.\r
+ * <p>\r
+ *\r
+ * @return this\r
+ **/\r
+ public DataValueDescriptor getConglom()\r
+ {\r
+ return(this);\r
+ }\r
+\r
+\r
+ /**************************************************************************\r
+ * Methods of Storable (via Conglomerate)\r
+ * Storable interface, implies Externalizable, TypedFormat\r
+ **************************************************************************\r
+ */\r
+\r
+ /**\r
+ * Return my format identifier.\r
+ *\r
+ * @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId\r
+ **/\r
+ public int getTypeFormatId()\r
+ {\r
+ return StoredFormatIds.ACCESS_HEAP_V3_ID;\r
+ }\r
+\r
+ /**\r
+ * Return whether the value is null or not.\r
+ *\r
+ * @see org.apache.derby.iapi.services.io.Storable#isNull\r
+ **/\r
+ public boolean isNull()\r
+ {\r
+ return id == null;\r
+ }\r
+\r
+ /**\r
+ * Restore the in-memory representation to the null value.\r
+ *\r
+ * @see org.apache.derby.iapi.services.io.Storable#restoreToNull\r
+ *\r
+ **/\r
+ public void restoreToNull()\r
+ {\r
+ id = null;\r
+ }\r
+\r
+ /**\r
+ * Store the stored representation of the column value in the stream.\r
+ *\r
+ **/\r
+\r
+ /**\r
+ * Store the 10.2 format stored representation of column value in stream.\r
+ * <p>\r
+ * This routine stores the 10.2 version the Heap, ie. the ACCESS_HEAP_V2_ID\r
+ * format. It is used by any database which has been created in \r
+ * 10.2 or a previous release and has not been hard upgraded to a \r
+ * version subsequent to 10.2.\r
+ * <p>\r
+ **/\r
+ protected void writeExternal_v10_2(ObjectOutput out) throws IOException\r
+ {\r
+\r
+ // write the format id of this conglomerate\r
+ FormatIdUtil.writeFormatIdInteger(out, conglom_format_id);\r
+\r
+ out.writeInt((int) id.getSegmentId());\r
+ out.writeLong(id.getContainerId());\r
+\r
+ // write number of columns in heap.\r
+ out.writeInt(format_ids.length);\r
+\r
+ // write out array of format id's\r
+ ConglomerateUtil.writeFormatIdArray(format_ids, out);\r
+ }\r
+\r
+ /**\r
+ * Store the stored representation of column value in stream.\r
+ * <p>\r
+ * This routine uses the current database version to either store the\r
+ * the 10.2 format (ACCESS_HEAP_V2_ID) or the current format \r
+ * (ACCESS_HEAP_V3_ID). \r
+ * <p>\r
+ **/\r
+ public void writeExternal(ObjectOutput out) throws IOException\r
+ {\r
+ writeExternal_v10_2(out);\r
+\r
+ if (conglom_format_id == StoredFormatIds.ACCESS_HEAP_V3_ID)\r
+ {\r
+ // Now append sparse array of collation ids\r
+ ConglomerateUtil.writeCollationIdArray(collation_ids, out);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Restore the in-memory representation from the stream.\r
+ * <p>\r
+ *\r
+ * @exception ClassNotFoundException Thrown if the stored representation \r
+ * is serialized and a class named in \r
+ * the stream could not be found.\r
+ *\r
+ * @see java.io.Externalizable#readExternal\r
+ **/\r
+ private final void localReadExternal(ObjectInput in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+\r
+ // read the format id of this conglomerate.\r
+ conglom_format_id = FormatIdUtil.readFormatIdInteger(in);\r
+\r
+ int segmentid = in.readInt();\r
+ long containerid = in.readLong();\r
+\r
+ id = new ContainerKey(segmentid, containerid);\r
+\r
+ // read the number of columns in the heap.\r
+ int num_columns = in.readInt();\r
+\r
+ // read the array of format ids.\r
+ format_ids = ConglomerateUtil.readFormatIdArray(num_columns, in);\r
+\r
+ // In memory maintain a collation id per column in the template.\r
+ collation_ids = new int[format_ids.length];\r
+\r
+ // initialize all the entries to COLLATION_TYPE_UCS_BASIC, \r
+ // and then reset as necessary. For version ACCESS_HEAP_V2_ID,\r
+ // this is the default and no resetting is necessary.\r
+ for (int i = 0; i < format_ids.length; i++)\r
+ collation_ids[i] = StringDataValue.COLLATION_TYPE_UCS_BASIC;\r
+\r
+ if (conglom_format_id == StoredFormatIds.ACCESS_HEAP_V3_ID)\r
+ {\r
+ // current format id, read collation info from disk\r
+\r
+ ConglomerateUtil.readCollationIdArray(collation_ids, in);\r
+ }\r
+ else if (conglom_format_id != StoredFormatIds.ACCESS_HEAP_V2_ID)\r
+ {\r
+ // Currently only V2 and V3 should be possible in a Derby DB.\r
+ // Actual work for V2 is handled by default code above, so no\r
+ // special work is necessary.\r
+\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT(\r
+ "Unexpected format id: " + conglom_format_id);\r
+ }\r
+ }\r
+ }\r
+\r
+ public void readExternal(ObjectInput in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ localReadExternal(in);\r
+ }\r
+\r
+ public void readExternalFromArray(ArrayInputStream in)\r
+ throws IOException, ClassNotFoundException\r
+ {\r
+ localReadExternal(in);\r
+ }\r
+}\r