Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / MyDerby-10.3 / java / engine / org / apache / derby / impl / store / raw / data / FileContainer.java
diff --git a/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/raw/data/FileContainer.java b/JMCR-Stable/real-world application/MyDerby-10.3/java/engine/org/apache/derby/impl/store/raw/data/FileContainer.java
new file mode 100644 (file)
index 0000000..0fc264e
--- /dev/null
@@ -0,0 +1,3441 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.raw.data.FileContainer\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.raw.data;\r
+\r
+import org.apache.derby.iapi.reference.Property;\r
+\r
+import org.apache.derby.iapi.reference.Limits;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.cache.Cacheable;\r
+import org.apache.derby.iapi.services.cache.CacheManager;\r
+import org.apache.derby.iapi.services.context.ContextService;\r
+import org.apache.derby.iapi.services.monitor.Monitor;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.services.io.FormatIdOutputStream;\r
+import org.apache.derby.iapi.services.io.StoredFormatIds;\r
+import org.apache.derby.iapi.services.io.TypedFormat;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.store.raw.ContainerHandle;\r
+import org.apache.derby.iapi.store.raw.ContainerKey;\r
+import org.apache.derby.iapi.store.raw.Page;\r
+import org.apache.derby.iapi.store.raw.PageKey;\r
+import org.apache.derby.iapi.store.raw.RecordHandle;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+import org.apache.derby.iapi.store.raw.Transaction;\r
+\r
+import org.apache.derby.iapi.store.raw.log.LogInstant;\r
+import org.apache.derby.iapi.store.raw.xact.RawTransaction;\r
+\r
+import org.apache.derby.iapi.store.access.TransactionController;\r
+import org.apache.derby.iapi.store.access.AccessFactory;\r
+import org.apache.derby.iapi.store.access.SpaceInfo;\r
+\r
+import org.apache.derby.iapi.services.io.ArrayInputStream;\r
+import org.apache.derby.iapi.services.io.ArrayOutputStream;\r
+import org.apache.derby.iapi.services.property.PropertyUtil;\r
+import org.apache.derby.iapi.util.ByteArray;\r
+\r
+import java.io.IOException;\r
+import java.io.DataInput;\r
+\r
+import java.util.Properties;\r
+import java.util.zip.CRC32;\r
+\r
+import org.apache.derby.io.StorageRandomAccessFile;\r
+\r
+/**\r
+       FileContainer is an abstract base class for containers\r
+       which are based on files.\r
+\r
+       This class extends BaseContainer and implements Cacheable and TypedFormat\r
+*/\r
+\r
+abstract class FileContainer \r
+    extends BaseContainer implements Cacheable, TypedFormat\r
+{\r
+\r
+       /*\r
+        * typed format\r
+        */\r
+\r
+       protected static final int formatIdInteger = \r
+        StoredFormatIds.RAW_STORE_SINGLE_CONTAINER_FILE; \r
+\r
+       // format Id must fit in 4 bytes\r
+\r
+       /**\r
+               Return my format identifier.\r
+       */\r
+       public int getTypeFormatId() \r
+    {\r
+               return StoredFormatIds.RAW_STORE_SINGLE_CONTAINER_FILE;\r
+       }\r
+\r
+       /*\r
+       ** Immutable fields\r
+       */\r
+\r
+       protected final CacheManager          pageCache;                // my page's cache\r
+       protected final CacheManager          containerCache;   // cache I am in.\r
+       protected final BaseDataFileFactory   dataFactory;      // creating factory\r
+\r
+       /*\r
+       ** Fields that are mutable only during identity changes\r
+       */\r
+\r
+       protected int pageSize;                 // size of my pages\r
+       protected int spareSpace;               // % space kept free on page in inserts\r
+       protected int minimumRecordSize;        // minimum space a record should \r
+                                        // occupy on the page.\r
+\r
+       protected short initialPages;       // initial number of pages preallocated\r
+                                        // to the container when created\r
+                                        \r
+       protected boolean canUpdate;        // can I be written to?\r
+\r
+       private int PreAllocThreshold;      // how many pages before preallocation \r
+                                        // kicks in, only stored in memory\r
+       private int PreAllocSize;               // how many pages to preallocate at once\r
+                                                                       // only stored in memory\r
+       private boolean bulkIncreaseContainerSize;// if true, the next addPage will\r
+                                                                                // attempt to preallocate a larger\r
+                                                                                // than normal number of pages.\r
+                                         //\r
+       // preallocation parameters\r
+       private static final int PRE_ALLOC_THRESHOLD    = 8;\r
+       private static final int MIN_PRE_ALLOC_SIZE     = 1;\r
+       private static final int DEFAULT_PRE_ALLOC_SIZE = 8;\r
+       private static final int MAX_PRE_ALLOC_SIZE     = 1000;\r
+\r
+       /* \r
+       ** Mutable fields, only valid when the identity is valid.\r
+       */\r
+\r
+       // RESOLVE: if we run out of bytes in the container, we can change\r
+       // containerVersion from a long to an int because this number is only\r
+       // bumped when the container is dropped (and rolled back), so it is almost\r
+       // impossible for the containverVersion to get beyond a short, let alone\r
+       // and int - someone will have to write an application that attempt to drop\r
+       // the container 2 billion times for that to happen.\r
+       protected long                  firstAllocPageNumber; // first alloc page number\r
+       protected long                  firstAllocPageOffset; // first alloc page offset\r
+       protected long                  containerVersion;     // the logged version number\r
+       protected long                  estimatedRowCount;    // value is changed unlogged\r
+       protected LogInstant    lastLogInstant;       // last time this container \r
+                                                  // object was touched.\r
+       /** \r
+        * The sequence number for reusable recordIds . \r
+        * As long as this number does not change, recordIds will be stable within\r
+        * the container.\r
+        **/\r
+       private long reusableRecordIdSequenceNumber;\r
+\r
+\r
+       /**\r
+               The page that was last inserted into.  Use this for getPageForInsert.\r
+               Remember the last allocated non-overflow page, and remember it in\r
+               memory only.\r
+               Use Get/Set method to access this field except when we know it is\r
+               being single thread access.\r
+        */\r
+       private long lastInsertedPage[];\r
+       private int  lastInsertedPage_index;\r
+\r
+       /** \r
+               The last unfilled page found.  Use this for getPageForInsert.\r
+               Remember the last unfilled page found, and remember it in memory only.\r
+               Use Get/Set method to access this field except when we know it is\r
+               being single thread access.\r
+       */\r
+       private long lastUnfilledPage;\r
+\r
+       /**\r
+               The last allocated page.  This global var is access *without*\r
+               synchronization.  It is used as a hint for page allocation to find the\r
+               next reusable page.\r
+        */\r
+       private long lastAllocatedPage;\r
+\r
+       /**\r
+               An estimated page count. Use this for getEstimatedPagecount.\r
+               Remember it in memory only.\r
+        */\r
+       private long estimatedPageCount;\r
+\r
+\r
+       // The isDirty flag indicates if the container has been modified.  The\r
+       // preDirty flag indicates that the container is about to be modified.  The\r
+       // reason for these 2 flags instead of just one is to accomodate\r
+       // checkpoint.  After a clean container sends a log record to the log\r
+       // stream but before that conatiner is dirtied by the log operation, a\r
+       // checkpoint could be taken.  If so, then the redoLWM will be after the\r
+       // log record but, without preDirty, the cache cleaning will not have\r
+       // waited for the change.  So the preDirty bit is to stop the cache\r
+       // cleaning from skipping over this container even though it has not really\r
+       // been modified yet.\r
+       protected boolean                       preDirty;\r
+       protected boolean                       isDirty;\r
+\r
+       /*\r
+               allocation information cached by the container object.  \r
+\r
+               <P>MT -\r
+               Access to the allocation cache MUST be synchronized on the allocCache\r
+               object.  FileContainer manages all MT issue w/r to AllocationCache.\r
+               The AllocationCache object itself is not MT-safe.\r
+               <P>\r
+               The protocol for accessing both the allocation cache and the alloc page\r
+               is: get the alloc cache semaphore, then get the alloc page.  Once both\r
+               are held, they can be released in any order.\r
+               <BR>\r
+               It is legal to get one or the other, i.e, it is legal to only get the\r
+               alloc cache semaphore without latching the alloc page, and it is legal\r
+               to get the alloc page latch without the alloc cache semaphore.\r
+               <BR>\r
+               it is illegal to hold alloc page latch and then get the allocation\r
+               cache semaphore\r
+               <PRE>\r
+               Writer to alloc Page (to invalidate alloc cache)\r
+               1) synchronized(allocCache)\r
+               2) invalidate cache\r
+               3) get latch on alloc Page\r
+               4) release synchonized(allocCache)\r
+\r
+               Reader:\r
+               1) synchronized(allocCache)\r
+               2) if valid, read value and release synchronized(allocCache)\r
+               3) if cache is invalid, get latch on alloc page\r
+               4) validate cache\r
+               5) release alloc page latch\r
+               6) read value\r
+               7) release synchonized(allocCache)\r
+               </PRE>\r
+       */\r
+       protected AllocationCache       allocCache;\r
+\r
+       /*\r
+        * array to store persistently stored fields\r
+        */\r
+       byte[] containerInfo;\r
+\r
+       private CRC32           checksum;               // holder for the checksum\r
+\r
+       /*\r
+       ** buffer for encryption/decryption\r
+       */\r
+       private byte[] encryptionBuffer;\r
+\r
+       /*\r
+        * constants\r
+        */\r
+\r
+       /** the container format must fit in this many bytes */\r
+       private static final int CONTAINER_FORMAT_ID_SIZE = 4; \r
+\r
+       /* the checksum size */\r
+       protected static final int CHECKSUM_SIZE = 8;\r
+\r
+       /** \r
+               The size of the persistently stored container info\r
+               ContainerHeader contains the following information:\r
+               4 bytes int     FormatId\r
+               4 bytes int     status\r
+               4 bytes int     pageSize\r
+               4 bytes int     spareSpace\r
+               4 bytes int minimumRecordSize\r
+               2 bytes short initialPages\r
+               2 bytes short spare1\r
+               8 bytes long    first Allocation page number\r
+               8 bytes long    first Allocation page offset\r
+               8 bytes long    container version\r
+               8 bytes long    estimated number of rows\r
+               8 bytes long    reusable recordId sequence number\r
+               8 bytes long    spare3\r
+               8 bytes long    checksum\r
+               container info size is 80 bytes, with 10 bytes of spare space\r
+       */\r
+       protected static final int CONTAINER_INFO_SIZE = \r
+               CONTAINER_FORMAT_ID_SIZE+4+4+4+4+2+2+8+8+8+8+CHECKSUM_SIZE+8+8;\r
+\r
+       /**\r
+        * where the first alloc page is located - \r
+        * the logical page number and the physical page offset\r
+        * NOTE if it is not 0 this is not going to work for Stream \r
+        * file which doesn't support seek\r
+        */\r
+       public static final long FIRST_ALLOC_PAGE_NUMBER = 0L;\r
+       public static final long FIRST_ALLOC_PAGE_OFFSET = 0L;\r
+\r
+       // file status for persistent storage\r
+       private static final int FILE_DROPPED        = 0x1;\r
+       private static final int FILE_COMMITTED_DROP = 0x2;\r
+\r
+       // recordId in this container can be reused when a page is reused.\r
+       private static final int FILE_REUSABLE_RECORDID = 0x8;\r
+\r
+       protected static final String SPACE_TRACE = \r
+        (SanityManager.DEBUG ? "SpaceTrace" : null);\r
+\r
+       FileContainer(BaseDataFileFactory factory) \r
+    {\r
+               dataFactory = factory;\r
+               pageCache = factory.getPageCache();\r
+               containerCache = factory.getContainerCache();\r
+               \r
+               initContainerHeader(true);\r
+       }\r
+\r
+    /**\r
+    Get information about space used by the container.\r
+    **/\r
+    public SpaceInfo getSpaceInfo(BaseContainerHandle handle)\r
+            throws StandardException\r
+    {\r
+        SpaceInformation spaceInfo;\r
+        synchronized(allocCache)\r
+        {\r
+            spaceInfo = \r
+                allocCache.getAllPageCounts(handle,firstAllocPageNumber);\r
+        }\r
+        spaceInfo.setPageSize(pageSize);\r
+        return spaceInfo;\r
+    }\r
+\r
+       /*\r
+       ** Methods of Cacheable\r
+       **\r
+       ** getIdentity() and clearIdentity() are implemented by BaseContainer\r
+       */\r
+\r
+       /**\r
+               Containers\r
+       */\r
+\r
+       /**\r
+               Open the container.\r
+\r
+               @return a valid object if the container was successfully opened, null if\r
+               it does not exist.\r
+\r
+               @exception StandardException Some problem in opening a container.\r
+\r
+               @see Cacheable#setIdentity\r
+       */\r
+       public Cacheable setIdentity(Object key) throws StandardException \r
+    {\r
+               return setIdent((ContainerKey) key);\r
+       }\r
+\r
+    /**\r
+     * Open the container.\r
+     * <p>\r
+     * Open the container with key "newIdentity".\r
+     * <p>\r
+     * should be same name as setIdentity but seems to cause method resolution \r
+     * ambiguities\r
+     *\r
+     * @exception StandardException Some problem in opening a container.\r
+     *\r
+     * @see Cacheable#setIdentity\r
+     **/\r
+       protected Cacheable setIdent(ContainerKey newIdentity) \r
+        throws StandardException \r
+    {\r
+               boolean ok          = openContainer(newIdentity);\r
+\r
+        initializeLastInsertedPage(1);\r
+               lastUnfilledPage    = ContainerHandle.INVALID_PAGE_NUMBER;\r
+               lastAllocatedPage   = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+               estimatedPageCount  = -1;\r
+\r
+               if (ok) \r
+        {\r
+                       // set up our identity.\r
+                       // If we raise an exception after this we must clear our identity.\r
+                       fillInIdentity(newIdentity);\r
+                       return this;\r
+               }\r
+        else\r
+        { \r
+            return null;\r
+        }\r
+       }\r
+\r
+       public Cacheable createIdentity(Object key, Object createParameter) \r
+        throws StandardException \r
+    {\r
+               if (SanityManager.DEBUG) \r
+        {\r
+                       SanityManager.ASSERT(\r
+                !(key instanceof PageKey), "PageKey input to create container");\r
+               }\r
+\r
+               return createIdent((ContainerKey) key, createParameter);\r
+       }\r
+\r
+\r
+       // should be same name as createIdentity but seems to cause method \r
+    // resolution ambiguities\r
+       protected Cacheable createIdent(\r
+    ContainerKey    newIdentity, \r
+    Object          createParameter) \r
+                throws StandardException \r
+       {\r
+               // createParameter will be this object if this method is being called \r
+        // from itself to re-initialize the container (only for tempRAF)\r
+               // if createParameter == this, do not reinitialize the header, this\r
+               // object is not being reused for another container\r
+               if (createParameter != this) \r
+               {\r
+                       initContainerHeader(true /* change to different container */);\r
+\r
+                       if (createParameter != null && \r
+                               (createParameter instanceof ByteArray))\r
+                       {\r
+                               // this is called during load tran, the create container\r
+                               // Operation has a byte array created by logCreateContainerInfo\r
+                               // which contains all the information necessary to recreate the\r
+                               // container.  Use that to recreate the container properties.\r
+\r
+                               createInfoFromLog((ByteArray)createParameter);\r
+                       }\r
+                       else\r
+                       {\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       if (createParameter != null &&\r
+                                               !(createParameter instanceof Properties))\r
+                                       {\r
+                                               SanityManager.THROWASSERT(\r
+                                                       "Expecting a  non-null createParameter to a " +\r
+                            "Properties instead of " +\r
+                                                       createParameter.getClass().getName());\r
+                                       }\r
+                               }\r
+\r
+                               createInfoFromProp((Properties)createParameter);\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       // we don't need to completely re-initialize the header\r
+                       // just re-initialize the relavent fields\r
+                       initContainerHeader(false);\r
+               }\r
+\r
+               if (initialPages > 1)\r
+               {\r
+                       PreAllocThreshold           = 0;\r
+                       PreAllocSize                = initialPages;\r
+                       bulkIncreaseContainerSize   = true;\r
+               }\r
+               else\r
+               {\r
+                       PreAllocThreshold           = PRE_ALLOC_THRESHOLD;\r
+               }\r
+\r
+               createContainer(newIdentity);\r
+\r
+               setDirty(true);\r
+\r
+               // set up our identity.\r
+               // If we raise an exception after this we must clear our identity.\r
+               fillInIdentity(newIdentity);\r
+\r
+               return this;\r
+       }\r
+\r
+       public void clearIdentity() \r
+    {\r
+\r
+               closeContainer();\r
+\r
+        initializeLastInsertedPage(1);\r
+               lastUnfilledPage = ContainerHandle.INVALID_PAGE_NUMBER;\r
+               lastAllocatedPage = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+               canUpdate = false;\r
+               super.clearIdentity();\r
+       }\r
+\r
+       /**\r
+               We treat this container as dirty if it has the container file open.\r
+               @see Cacheable#isDirty\r
+       */\r
+       public boolean isDirty() \r
+    {\r
+               synchronized (this) \r
+        {\r
+                       return isDirty;\r
+               }\r
+       }\r
+\r
+       public void preDirty(boolean preDirtyOn) \r
+    {\r
+               synchronized (this) \r
+        {\r
+                       if (preDirtyOn)\r
+                       {\r
+                               // prevent the cleaner from cleaning this container or skipping\r
+                               // over it until the operation which preDirtied it got a chance\r
+                               // to do the change.\r
+                               preDirty = true;\r
+                       }\r
+                       else\r
+                       {\r
+                               preDirty = false;\r
+                               // if a cleaner is waiting on the dirty bit, wake it up\r
+                               notifyAll();\r
+                       }\r
+               }\r
+       }\r
+\r
+       protected void setDirty(boolean dirty)\r
+       {\r
+               synchronized(this) \r
+        {\r
+                       preDirty = false;\r
+                       isDirty  = dirty;\r
+\r
+                       // if a cleaner is waiting on the dirty bit, wake it up\r
+                       notifyAll();\r
+               }\r
+       }\r
+\r
+       /*\r
+       ** Container creation, opening, and closing\r
+       */\r
+\r
+    /**\r
+     * Create a new container.\r
+     * <p>\r
+     * Create a new container, all references to identity must be through the\r
+     * passed in identity, this object will no identity until after this \r
+     * method returns.\r
+     *\r
+     * @exception StandardException Derby Standard error policy\r
+     **/\r
+       abstract void createContainer(ContainerKey newIdentity) \r
+        throws StandardException;\r
+       \r
+\r
+    /**\r
+     * Open a container.\r
+     * <p>\r
+     * Longer descrption of routine.\r
+     * <p>\r
+     * Open a container. Open the file that maps to this container, if the\r
+     * file does not exist then we assume the container was never created.\r
+     * If the file exists but we have trouble opening it then we throw some \r
+     * exception.\r
+     *\r
+     * <BR> MT - single thread required - Enforced by cache manager.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       abstract boolean openContainer(ContainerKey newIdentity) \r
+        throws StandardException;\r
+\r
+       abstract void closeContainer();\r
+\r
+    /**\r
+     * Drop Container.\r
+     * <p>\r
+     *\r
+     * @see Transaction#dropContainer\r
+     *\r
+     **/\r
+       protected void dropContainer(\r
+    LogInstant  instant, \r
+    boolean     isDropped)\r
+       {\r
+               synchronized(this)\r
+               {\r
+                       setDroppedState(isDropped);\r
+                       setDirty(true);\r
+                       bumpContainerVersion(instant);\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+               increment the version by one and return the new version.\r
+\r
+               <BR> MT - caller must synchronized this in the same sync block that\r
+               modifies the container header.\r
+       */\r
+       protected final void bumpContainerVersion(LogInstant instant) \r
+       {       \r
+               lastLogInstant = instant;\r
+               ++containerVersion;\r
+       }\r
+\r
+       protected long getContainerVersion()\r
+       {\r
+               // it is not really necessary to synchronized this because the only time the\r
+               // container version is looked at is during recovery, which is single\r
+               // threaded at the moment.  Put it in an sync block anyway just in case\r
+               // some other people want to look at this for some bizarre reasons\r
+               synchronized(this)\r
+               {\r
+                       return containerVersion;\r
+               }\r
+       }\r
+\r
+    /**\r
+     * Request the system properties associated with a container. \r
+     * <p>\r
+     * Request the value of properties that are associated with a container. \r
+     * The following properties can be requested:\r
+     *     derby.storage.pageSize \r
+     *     derby.storage.pageReservedSpace\r
+     *     derby.storage.minimumRecordSize\r
+     *     derby.storage.reusableRecordId\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.getContainerProperties(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 getContainerProperties(Properties prop)\r
+               throws StandardException\r
+    {\r
+        // derby.storage.pageSize\r
+        if (prop.getProperty(Property.PAGE_SIZE_PARAMETER) != null)\r
+        {\r
+            prop.put(\r
+                Property.PAGE_SIZE_PARAMETER, \r
+                Integer.toString(pageSize));\r
+        }\r
+\r
+        // derby.storage.minimumRecordSize\r
+        if (prop.getProperty(RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER) != \r
+                null)\r
+        {\r
+            prop.put(\r
+                RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER, \r
+                Integer.toString(minimumRecordSize));\r
+        }\r
+\r
+        // derby.storage.pageReservedSpace\r
+        if (prop.getProperty(RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER) != \r
+                null)\r
+        {\r
+            prop.put(\r
+                RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER, \r
+                Integer.toString(spareSpace));\r
+        }\r
+\r
+               // derby.storage.reusableRecordId\r
+               if (prop.getProperty(RawStoreFactory.PAGE_REUSABLE_RECORD_ID) != null)\r
+               {\r
+                       Boolean bool = new Boolean(isReusableRecordId());\r
+                       prop.put(RawStoreFactory.PAGE_REUSABLE_RECORD_ID,\r
+                                        bool.toString());\r
+               }\r
+\r
+               // derby.storage.initialPages\r
+               if (prop.getProperty(RawStoreFactory.CONTAINER_INITIAL_PAGES) != null)\r
+               {\r
+                       prop.put(RawStoreFactory.CONTAINER_INITIAL_PAGES,\r
+                                        Integer.toString(initialPages));\r
+               }\r
+\r
+    }\r
+\r
+       /**\r
+        Read the container's header.\r
+\r
+        When this method is called, the embryonic page that is passed in must\r
+        have been read directly from the file or the input stream, even if the\r
+        alloc page may still be in cache.  This is because a stubbify operation\r
+        only writes the stub to disk, it does not get rid of any stale page\r
+        from the page cache.  So if it so happens that the stubbified container\r
+        object is aged out of the container cache but the first alloc page\r
+        hasn't, then when any stale page of this container wants to be written\r
+        out, the container needs to be reopened, which is when this routine is\r
+        called.  We must not get the alloc page in cache because it may be\r
+        stale page and it may still say the container has not been dropped.\r
+\r
+               <BR> MT - single thread required - Enforced by caller.\r
+\r
+        @param epage the embryonic page to read the header from\r
+               @exception StandardException Derby Standard error policy\r
+               @exception IOException error in reading the header from file\r
+       */\r
+       protected void readHeader(byte[] epage)\r
+                throws IOException, StandardException\r
+       {\r
+               // read persistent container header into containerInfo\r
+               AllocPage.ReadContainerInfo(containerInfo, epage);\r
+\r
+               // initialize header from information stored in containerInfo\r
+               readHeaderFromArray(containerInfo);\r
+       }\r
+\r
+       // initialize header information so this container object can be safely\r
+       // reused as if this container object has just been new'ed\r
+       private void initContainerHeader(boolean changeContainer)\r
+       {\r
+               if (containerInfo == null)\r
+                       containerInfo = new byte[CONTAINER_INFO_SIZE];\r
+\r
+               if (checksum == null)\r
+                       checksum = new CRC32();\r
+               else\r
+                       checksum.reset();\r
+\r
+               if (allocCache == null)\r
+                       allocCache = new AllocationCache();\r
+               else\r
+                       allocCache.reset();\r
+\r
+               if (changeContainer)\r
+               {\r
+                       pageSize = 0;\r
+                       spareSpace = 0;\r
+                       minimumRecordSize = 0;\r
+               }\r
+\r
+               initialPages = 1;\r
+               firstAllocPageNumber = ContainerHandle.INVALID_PAGE_NUMBER;     \r
+               firstAllocPageOffset = -1;\r
+               containerVersion = 0;\r
+               estimatedRowCount = 0;\r
+               reusableRecordIdSequenceNumber = 0;\r
+\r
+               setDroppedState(false);\r
+               setCommittedDropState(false);\r
+               setReusableRecordIdState(false);\r
+\r
+               // instance variables that are not stored on disk\r
+               lastLogInstant = null;\r
+\r
+        initializeLastInsertedPage(1);\r
+               lastUnfilledPage = ContainerHandle.INVALID_PAGE_NUMBER;\r
+               lastAllocatedPage = ContainerHandle.INVALID_PAGE_NUMBER;\r
+               estimatedPageCount = -1;\r
+\r
+               PreAllocThreshold = PRE_ALLOC_THRESHOLD;\r
+               PreAllocSize = DEFAULT_PRE_ALLOC_SIZE;\r
+               bulkIncreaseContainerSize = false;\r
+       }\r
+\r
+\r
+       /**\r
+               Read containerInfo from a byte array\r
+               The container Header array must be written by or of\r
+               the same format as put together by writeHeaderFromArray.\r
+\r
+               @exception StandardException Derby Standard error policy\r
+               @exception IOException error in reading the header from file\r
+       */\r
+       private void readHeaderFromArray(byte[] a)\r
+                throws StandardException, IOException\r
+       {\r
+               ArrayInputStream inStream = new ArrayInputStream(a);\r
+\r
+               inStream.setLimit(CONTAINER_INFO_SIZE);\r
+               int fid = inStream.readInt();\r
+               if (fid != formatIdInteger)\r
+        {\r
+                       throw StandardException.newException(\r
+                SQLState.DATA_UNKNOWN_CONTAINER_FORMAT, getIdentity(), \r
+                new Long(fid));\r
+        }\r
+\r
+               int status = inStream.readInt();\r
+               pageSize = inStream.readInt();\r
+               spareSpace = inStream.readInt();\r
+               minimumRecordSize = inStream.readInt();\r
+               initialPages = inStream.readShort(); \r
+               PreAllocSize = inStream.readShort();\r
+               firstAllocPageNumber = inStream.readLong();\r
+               firstAllocPageOffset = inStream.readLong();\r
+               containerVersion = inStream.readLong();\r
+               estimatedRowCount = inStream.readLong();\r
+               reusableRecordIdSequenceNumber = inStream.readLong();\r
+               lastLogInstant = null;\r
+\r
+               if (PreAllocSize == 0)  // pre 2.0, we don't store this.\r
+                       PreAllocSize = DEFAULT_PRE_ALLOC_SIZE;\r
+\r
+               long spare3 = inStream.readLong();      // read spare long\r
+\r
+               // upgrade - if this is a container that was created before\r
+               // initialPages was stored, it will have a zero value.  Set it to the\r
+               // default of 1.\r
+               if (initialPages == 0)  \r
+                       initialPages = 1;\r
+\r
+               // container read in from disk, reset preAllocation values\r
+               PreAllocThreshold = PRE_ALLOC_THRESHOLD;\r
+\r
+               // validate checksum\r
+               long onDiskChecksum = inStream.readLong();\r
+               checksum.reset();\r
+               checksum.update(a, 0, CONTAINER_INFO_SIZE - CHECKSUM_SIZE);\r
+\r
+               if (onDiskChecksum != checksum.getValue())\r
+               {\r
+                       PageKey pk = new PageKey(identity, FIRST_ALLOC_PAGE_NUMBER);\r
+\r
+                       throw dataFactory.markCorrupt\r
+                               (StandardException.newException(\r
+                    SQLState.FILE_BAD_CHECKSUM, \r
+                    pk, \r
+                    new Long(checksum.getValue()), \r
+                    new Long(onDiskChecksum), \r
+                    org.apache.derby.iapi.util.StringUtil.hexDump(a)));\r
+               }\r
+\r
+               allocCache.reset();\r
+\r
+               // set the in memory state\r
+               setDroppedState((status & FILE_DROPPED) != 0);\r
+               setCommittedDropState((status & FILE_COMMITTED_DROP) != 0);\r
+               setReusableRecordIdState((status & FILE_REUSABLE_RECORDID) != 0);\r
+       }\r
+\r
+\r
+       /**\r
+               Write the container header to a page array (the first allocation page)\r
+\r
+               @exception StandardException Derby Standard error policy\r
+               @exception IOException error in writing the header to file\r
+       */\r
+       protected void writeHeader(byte[] pageData)\r
+                throws StandardException, IOException\r
+       {\r
+               // write out the current containerInfo in the borrowed space to byte\r
+               // array containerInfo\r
+               writeHeaderToArray(containerInfo);\r
+\r
+               AllocPage.WriteContainerInfo(containerInfo, pageData, false);\r
+       }\r
+\r
+       /**\r
+               Write the container header directly to file.\r
+\r
+               Subclasses that can writes the container header is expected to\r
+               manufacture a DataOutput stream which is used here.\r
+\r
+               <BR> MT - single thread required - Enforced by caller\r
+\r
+               @exception StandardException Derby Standard error policy\r
+               @exception IOException error in writing the header to file\r
+        */\r
+       protected void writeHeader(StorageRandomAccessFile file,\r
+                               boolean create, byte[] epage)\r
+                throws IOException, StandardException\r
+       {\r
+               // write out the current containerInfo in the borrowed space to byte\r
+               // array containerInfo\r
+               writeHeaderToArray(containerInfo);\r
+\r
+               // RESOLVE: get no wait on the page cache to see if allocation page is\r
+               // there, if so, use that instead of making a new array and a static\r
+               // function.\r
+\r
+               AllocPage.WriteContainerInfo(containerInfo, epage, create);\r
+               // now epage has the containerInfo written inside it\r
+\r
+               // force WAL - and check to see if database is corrupt or is frozen.\r
+               dataFactory.flush(lastLogInstant);\r
+               if (lastLogInstant != null)\r
+                       lastLogInstant = null;\r
+\r
+               // write it out\r
+               dataFactory.writeInProgress();\r
+               try\r
+               {\r
+            writeAtOffset(file, epage, FIRST_ALLOC_PAGE_OFFSET);\r
+               }\r
+               finally\r
+               {\r
+                       dataFactory.writeFinished();\r
+               }\r
+       }\r
+\r
+    /**\r
+     * Write a sequence of bytes at the given offset in a file. This method\r
+     * is not thread safe, so the caller must make sure that no other thread\r
+     * is performing operations that may change current position in the file.\r
+     *\r
+     * @param file the file to write to\r
+     * @param bytes the bytes to write\r
+     * @param offset the offset to start writing at\r
+     * @throws IOException if an I/O error occurs while writing\r
+     */\r
+    void writeAtOffset(StorageRandomAccessFile file, byte[] bytes, long offset)\r
+            throws IOException\r
+    {\r
+        file.seek(offset);\r
+        file.write(bytes);\r
+    }\r
+\r
+       /**\r
+               Get an embryonic page from the dataInput stream.\r
+\r
+               If fileData is not null, then the embyronic page will be read \r
+               in from the input stream (fileData), which is assumed to be \r
+               positioned at the beginning of the first allocation page.\r
+\r
+               if fileData is null, then just manufacture an array which\r
+               is the size of an embryonic page.\r
+\r
+               @exception IOException error in read the embryonic page from file\r
+       */\r
+       protected byte[] getEmbryonicPage(DataInput fileData) throws IOException\r
+       {\r
+               byte[] epage = new byte[AllocPage.MAX_BORROWED_SPACE];\r
+\r
+               if (fileData != null)\r
+               {\r
+                       fileData.readFully(epage);\r
+               }\r
+               return epage;\r
+       }\r
+\r
+    /**\r
+     * Read an embryonic page (that is, a section of the first alloc page that\r
+     * is so large that we know all the borrowed space is included in it) from\r
+     * the specified offset in a {@code StorageRandomAccessFile}. This method\r
+     * is not thread safe, so the caller must make sure that no other thread\r
+     * is performing operations that may change current position in the file.\r
+     *\r
+     * @param file the file to read from\r
+     * @param offset where to start reading (normally\r
+     * {@code FileContainer.FIRST_ALLOC_PAGE_OFFSET})\r
+     * @return a byte array containing the embryonic page\r
+     * @throws IOException if an I/O error occurs while reading\r
+     */\r
+    byte[] getEmbryonicPage(StorageRandomAccessFile file, long offset)\r
+            throws IOException\r
+    {\r
+        file.seek(offset);\r
+        return getEmbryonicPage(file);\r
+    }\r
+\r
+       /**\r
+               Write containerInfo into a byte array\r
+               The container Header thus put together can be read by readHeaderFromArray.\r
+\r
+               @exception IOException error in writing the header\r
+       */\r
+       private void writeHeaderToArray(byte[] a) throws IOException\r
+       {\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(a.length >= CONTAINER_INFO_SIZE,\r
+                                                                "header won't fit in array");\r
+\r
+               ArrayOutputStream a_out = new ArrayOutputStream(a);\r
+               FormatIdOutputStream outStream = new FormatIdOutputStream(a_out);\r
+\r
+               int status = 0;\r
+               if (getDroppedState()) status |= FILE_DROPPED;\r
+               if (getCommittedDropState()) status |= FILE_COMMITTED_DROP;\r
+               if (isReusableRecordId()) status |= FILE_REUSABLE_RECORDID;\r
+\r
+               a_out.setPosition(0);\r
+               a_out.setLimit(CONTAINER_INFO_SIZE);\r
+               outStream.writeInt(formatIdInteger);\r
+               outStream.writeInt(status);\r
+               outStream.writeInt(pageSize);\r
+               outStream.writeInt(spareSpace);\r
+               outStream.writeInt(minimumRecordSize);\r
+               outStream.writeShort(initialPages);\r
+               outStream.writeShort(PreAllocSize);             // write spare1\r
+               outStream.writeLong(firstAllocPageNumber);\r
+               outStream.writeLong(firstAllocPageOffset);\r
+               outStream.writeLong(containerVersion);\r
+               outStream.writeLong(estimatedRowCount);\r
+               outStream.writeLong(reusableRecordIdSequenceNumber);\r
+               outStream.writeLong(0);         //Write spare3\r
+\r
+               checksum.reset();\r
+               checksum.update(a, 0, CONTAINER_INFO_SIZE - CHECKSUM_SIZE);\r
+\r
+               // write the checksum to the array\r
+               outStream.writeLong(checksum.getValue());\r
+\r
+               a_out.clearLimit();\r
+       }\r
+\r
+       /**\r
+               Log all information on the container creation necessary to recreate the\r
+               container during a load tran.\r
+\r
+               @exception StandardException Derby Standard error policy\r
+        */\r
+       protected ByteArray logCreateContainerInfo() \r
+                throws  StandardException\r
+       {\r
+               // just write out the whole container header\r
+               byte[] array = new byte[CONTAINER_INFO_SIZE];\r
+\r
+               try\r
+               {\r
+                       writeHeaderToArray(array);\r
+               }\r
+               catch (IOException ioe)\r
+               {\r
+                       throw StandardException.newException(\r
+                SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);\r
+               }\r
+\r
+               return new ByteArray(array);\r
+       }\r
+\r
+       /**\r
+               Set container properties from the passed in ByteArray, which is created\r
+               by logCreateContainerInfo.  This information is used to recreate the\r
+               container during recovery load tran.\r
+\r
+               The following container properties are set:\r
+\r
+               pageSize\r
+               spareSpace\r
+               minimumRecordSize\r
+               isReusableRecordId\r
+               initialPages\r
+\r
+        */\r
+       private void createInfoFromLog(ByteArray byteArray) \r
+                throws StandardException \r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(byteArray != null,\r
+                               "setCreateContainerInfoFromLog: ByteArray is null");\r
+                       SanityManager.ASSERT(byteArray.getLength() == \r
+                                                                CONTAINER_INFO_SIZE,\r
+                               "setCreateContainerInfoFromLog: ByteArrays.length() != CONTAINER_INFO_SIZE");\r
+               }\r
+\r
+               byte[] array = byteArray.getArray();\r
+               \r
+               // now extract the relavent information from array - basically \r
+               // duplicate the code in readHeaderFromArray \r
+               ArrayInputStream inStream = new ArrayInputStream(array);\r
+\r
+               int status = 0;\r
+\r
+               try\r
+               {                       \r
+                       inStream.setLimit(CONTAINER_INFO_SIZE);\r
+\r
+                       int fid = inStream.readInt();\r
+                       if (fid != formatIdInteger)\r
+                       {\r
+                               // RESOLVE: do something about this when we have > 1 container format\r
+                               throw StandardException.newException(\r
+                    SQLState.DATA_UNKNOWN_CONTAINER_FORMAT, \r
+                    getIdentity(), new Long(fid));\r
+                       }\r
+\r
+                       status = inStream.readInt();\r
+                       pageSize = inStream.readInt();\r
+                       spareSpace = inStream.readInt();\r
+                       minimumRecordSize = inStream.readInt();\r
+                       initialPages = inStream.readShort(); \r
+\r
+               }\r
+               catch (IOException ioe)\r
+               {\r
+                       throw StandardException.newException(\r
+                    SQLState.DATA_UNEXPECTED_EXCEPTION, ioe);\r
+               }\r
+\r
+               // set reusable record id property\r
+               setReusableRecordIdState((status & FILE_REUSABLE_RECORDID) != 0);\r
+\r
+               // sanity check to make sure we are not encoutering any\r
+               // dropped Container \r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT((status & FILE_DROPPED) == 0 &&\r
+                                                                (status & FILE_COMMITTED_DROP) == 0,\r
+                               "cannot load a dropped container");\r
+               }\r
+       }\r
+\r
+       /**\r
+               Set container properties from the passed in createArgs.  \r
+               The following container properties are set:\r
+\r
+               pageSize\r
+               spareSpace\r
+               minimumRecordSize\r
+               isReusableRecordId\r
+               initialPages\r
+\r
+               RESOLVE - in the future setting parameters should be overridable\r
+               by sub-class, e.g. one implementation of Container may require a\r
+               minimum page size of 4k.\r
+        */\r
+       private void createInfoFromProp(Properties createArgs)\r
+                throws StandardException\r
+       {\r
+               // Need a TransactionController to get database/service wide properties.\r
+               AccessFactory af = (AccessFactory)\r
+                       Monitor.getServiceModule(dataFactory, AccessFactory.MODULE);\r
+\r
+               // RESOLVE: sku defectid 2014\r
+               TransactionController tc = \r
+            (af == null) ? \r
+                null : \r
+                af.getTransaction(\r
+                        ContextService.getFactory().getCurrentContextManager());\r
+\r
+               pageSize = \r
+                       PropertyUtil.getServiceInt(tc, createArgs,\r
+                               Property.PAGE_SIZE_PARAMETER,  \r
+                               Limits.DB2_MIN_PAGE_SIZE, \r
+                               Limits.DB2_MAX_PAGE_SIZE, \r
+                               RawStoreFactory.PAGE_SIZE_DEFAULT); \r
+\r
+        // rather than throw error, just automatically set page size to \r
+        // default if bad value given.\r
+        if ((pageSize != 4096)  &&\r
+            (pageSize != 8192)  &&\r
+            (pageSize != 16384) &&\r
+            (pageSize != 32768))\r
+        {\r
+            pageSize= RawStoreFactory.PAGE_SIZE_DEFAULT;\r
+        }\r
+\r
+               spareSpace = \r
+                       PropertyUtil.getServiceInt(tc, createArgs,\r
+                               RawStoreFactory.PAGE_RESERVED_SPACE_PARAMETER, \r
+                               0, 100, 20);\r
+\r
+               PreAllocSize = \r
+                       PropertyUtil.getServiceInt(tc, createArgs,\r
+                                       RawStoreFactory.PRE_ALLOCATE_PAGE,\r
+                                       MIN_PRE_ALLOC_SIZE,\r
+                                       MAX_PRE_ALLOC_SIZE,                                \r
+                                       DEFAULT_PRE_ALLOC_SIZE /* default */);\r
+\r
+               // RESOLVE - in the future, we will allow user to set minimumRecordSize\r
+               // to be larger than pageSize, when long rows are supported.\r
+               if (createArgs == null) {\r
+                       // if the createArgs is null, then the following method call\r
+                       // will get the system properties from the appropriete places.\r
+                       // we want to make sure minimumRecrodSize is set to at least\r
+                       // the default value MINIMUM_RECORD_SIZE_DEFAULT (12)\r
+                       // as set in rawStoreFactory.\r
+                       minimumRecordSize = \r
+                               PropertyUtil.getServiceInt(tc,\r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER, \r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT, // this is different from the next call\r
+                                       // reserving 100 bytes for record/field headers\r
+                                       (pageSize * (1 - spareSpace/100) - 100), \r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT);\r
+               } else {\r
+                       // if the createArgs is not null, then it has already been set\r
+                       // by upper layer or create statement, then, we allow the minimum\r
+                       // value of this to be MINIMUM_RECORD_SIZE_MINIMUM (1).\r
+                       minimumRecordSize = \r
+                               PropertyUtil.getServiceInt(tc, createArgs,\r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_PARAMETER, \r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_MINIMUM,  // this is different from the last call\r
+                                       // reserving 100 bytes for record/field headers\r
+                                       (pageSize * (1 - spareSpace/100) - 100), \r
+                                       RawStoreFactory.MINIMUM_RECORD_SIZE_DEFAULT);\r
+               }\r
+\r
+               // For the following properties, do not check value set in global\r
+               // properties, we only listen to what access has to say about them.\r
+               //\r
+               // whether or not container's recordIds can be reused\r
+               // if container is to be created with a large number of pages\r
+               if (createArgs != null)\r
+               {\r
+                       String reusableRecordIdParameter = \r
+                               createArgs.getProperty(RawStoreFactory.PAGE_REUSABLE_RECORD_ID);\r
+                       if (reusableRecordIdParameter != null)\r
+                       {       \r
+                               Boolean reusableRecordId = new Boolean(reusableRecordIdParameter);\r
+                               setReusableRecordIdState(reusableRecordId.booleanValue());\r
+                       }\r
+\r
+                       String containerInitialPageParameter =\r
+                               createArgs.getProperty(RawStoreFactory.CONTAINER_INITIAL_PAGES);\r
+                       if (containerInitialPageParameter != null)\r
+                       {\r
+                               initialPages = \r
+                                       Short.parseShort(containerInitialPageParameter);\r
+                               if (initialPages > 1)\r
+                               {\r
+                                       if (initialPages > RawStoreFactory.MAX_CONTAINER_INITIAL_PAGES)\r
+                                               initialPages = RawStoreFactory.MAX_CONTAINER_INITIAL_PAGES;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+       */\r
+       protected boolean canUpdate() {\r
+               return canUpdate;\r
+       }\r
+\r
+       /**\r
+               Deallocate a page from the container.  \r
+\r
+               @param handle the container handle doing the deallocation\r
+               @param page the page to be deallocated.  It is latched upon entry and\r
+               will be unlatched by the caller of this function\r
+\r
+               @exception StandardException Derby Standard error policy\r
+       */\r
+       protected void deallocatePage(BaseContainerHandle handle, BasePage page)\r
+                throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG) {\r
+                       SanityManager.ASSERT(page.isLatched(), "page is not latched");\r
+                       SanityManager.ASSERT(page.getPageNumber() != FIRST_ALLOC_PAGE_NUMBER, \r
+                                                                "cannot deallocate an alloc page");\r
+               }\r
+\r
+               long pnum = page.getPageNumber();\r
+\r
+               // dealloc the page from the alloc page\r
+               deallocatePagenum(handle, pnum);\r
+\r
+               // mark the page as deallocated.  Page should not be touched after this\r
+               // the page latch is released by the BaseContainer upon return of this\r
+               // method.  Regardless of whether this operation is successful or not,\r
+               // the page will be unlatched by BaseContainer.\r
+               page.deallocatePage();\r
+               \r
+       }\r
+\r
+       /** deallocate the page from the alloc page */\r
+       private void deallocatePagenum(BaseContainerHandle handle, long pnum)\r
+                throws StandardException\r
+       {\r
+               synchronized(allocCache)\r
+               {\r
+                       long allocPageNum = allocCache.getAllocPageNumber(handle, pnum, firstAllocPageNumber);\r
+\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               if (allocPageNum == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                                       allocCache.dumpAllocationCache();\r
+\r
+                               if (allocPageNum == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                                       SanityManager.THROWASSERT(\r
+                                                                        "can't find alloc page for page number " +\r
+                                                                        pnum);\r
+                       }\r
+                       // get the alloc page to deallocate this pnum\r
+                       AllocPage allocPage = (AllocPage)handle.getAllocPage(allocPageNum);\r
+                       if (allocPage == null)\r
+                       {\r
+                               PageKey pkey = new PageKey(identity, allocPageNum);\r
+\r
+                               throw StandardException.newException(\r
+                        SQLState.FILE_NO_ALLOC_PAGE, pkey);\r
+                       }\r
+\r
+                       try\r
+                       {\r
+                               allocCache.invalidate(allocPage, allocPageNum); \r
+\r
+                               // Unlatch alloc page.  The page is protected by the dealloc\r
+                               // lock. \r
+                               allocPage.deallocatePage(handle, pnum);\r
+                       }\r
+                       finally\r
+                       {\r
+                               allocPage.unlatch();\r
+                       }\r
+               }\r
+               // make sure this page gets looked at when someone needs a new page\r
+               if (pnum <= lastAllocatedPage) \r
+               {\r
+                       lastAllocatedPage = pnum - 1;\r
+               }\r
+\r
+       }\r
+\r
+       /**\r
+         Compress free space from container.\r
+\r
+         <BR> MT - thread aware - It is assumed that our caller (our super class)\r
+         has already arranged a logical lock on page allocation to only allow a\r
+         single thread through here.\r
+\r
+      Compressing free space is done in allocation page units, working\r
+      it's way from the end of the container to the beginning.  Each\r
+      loop operates on the last allocation page in the container.\r
+\r
+      Freeing space in the container page involves 2 transactions, an\r
+      update to an allocation page, N data pages, and possibly the delete\r
+      of the allocation page.\r
+         The User Transaction (UT) initiated the compress call.\r
+         The Nested Top Transaction (NTT) is the transaction started by RawStore\r
+         inside the compress call.  This NTT is committed before compress returns.\r
+         The NTT is used to access high traffic data structures such as the \r
+      AllocPage.\r
+\r
+         This is outline of the algorithm used in compressing the container.\r
+\r
+      Until a non free page is found loop, in each loop return to the OS\r
+         all space at the end of the container occupied by free pages, including\r
+         the allocation page itself if all of it's pages are free.  \r
+      \r
+         1) Find last 2 allocation pages in container (last if there is only one).\r
+         2) invalidate the allocation information cached by the container.\r
+                Without the cache no page can be gotten from the container.  Pages\r
+                already in the page cache are not affected.  Thus by latching the \r
+                allocPage and invalidating the allocation cache, this NTT blocks out \r
+                all page gets from this container until it commits.\r
+         3) the allocPage determines which pages can be released to the OS, \r
+         mark that in its data structure (the alloc extent).  Mark the \r
+         contiguous block of nallocated/free pages at the end of the file\r
+         as unallocated.  This change is associated with the NTT.\r
+      4) The NTT calls the OS to deallocate the space from the file.  Note\r
+         that the system can handle being booted and asked to get an allocated\r
+         page which is past end of file, it just extends the file automatically.\r
+         5) If freeing all space on the alloc page, and there is more than one\r
+         alloc page, then free the alloc page - this requires an update to the \r
+         previous alloc page which the loop has kept latched also.\r
+      6) if the last alloc page was deleted, restart loop at #1\r
+\r
+      All NTT latches are released before this routine returns.\r
+         If we use an NTT, the caller has to commit the NTT to release the\r
+         allocPage latch.  If we don't use an NTT, the allocPage latch is released\r
+         as this routine returns.\r
+\r
+         @param ntt - the nested top transaction for the purpose of freeing space.\r
+                                               If ntt is null, use the user transaction for allocation.\r
+         #param allocHandle - the container handle opened by the ntt, \r
+                                               use this to latch the alloc page\r
+\r
+         @exception StandardException Standard Derby error policy \r
+       */\r
+       protected void compressContainer(\r
+    RawTransaction      ntt,\r
+    BaseContainerHandle allocHandle)\r
+                throws StandardException \r
+       {\r
+               AllocPage alloc_page      = null;\r
+               AllocPage prev_alloc_page = null;\r
+\r
+               if (firstAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER)\r
+        {\r
+            // no allocation pages in container, no work to do!\r
+                       return;\r
+        }\r
+\r
+        \r
+        // make sure we don't execute redo recovery on any page\r
+        // which is getting truncated.  At this point we have an exclusive\r
+        // table lock on the table, so after checkpoint no page change\r
+        // can happen between checkpoint log record and compress of space.\r
+        dataFactory.getRawStoreFactory().checkpoint();\r
+\r
+        // block the backup, If backup is already in progress wait \r
+        // for the backup to finish. Otherwise restore from the backup\r
+        // can start recovery at different checkpoint and possibly\r
+        // do redo on pages that are going to get truncated.\r
+        ntt.blockBackup(true);\r
+\r
+               try\r
+               {\r
+            synchronized(allocCache)\r
+            {\r
+                // loop until last 2 alloc pages are reached.\r
+                alloc_page = (AllocPage) \r
+                    allocHandle.getAllocPage(firstAllocPageNumber);\r
+\r
+                while (!alloc_page.isLast())\r
+                {\r
+                    if (prev_alloc_page != null)\r
+                    {\r
+                        // there are more than 2 alloc pages, unlatch the \r
+                        // earliest one.\r
+                        prev_alloc_page.unlatch();\r
+                    }\r
+                    prev_alloc_page = alloc_page;\r
+                    alloc_page      = null;\r
+\r
+                    long nextAllocPageNumber = \r
+                        prev_alloc_page.getNextAllocPageNumber();\r
+                    long nextAllocPageOffset = \r
+                        prev_alloc_page.getNextAllocPageOffset();\r
+\r
+                    alloc_page = (AllocPage) \r
+                        allocHandle.getAllocPage(nextAllocPageNumber);\r
+                }\r
+\r
+                // invalidate cache before compress changes cached information,\r
+                // while holding synchronization on cache and latch on \r
+                // allocation page.  This should guarantee that only new info\r
+                // is seen after this operation completes.\r
+                               allocCache.invalidate(); \r
+\r
+                // reset, as pages may not exist after compress\r
+                lastUnfilledPage    = ContainerHandle.INVALID_PAGE_NUMBER;\r
+                lastAllocatedPage   = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+\r
+                alloc_page.compress(ntt, this);\r
+            }\r
+\r
+               }\r
+        finally\r
+        {\r
+                       if (alloc_page != null)\r
+            {\r
+                               alloc_page.unlatch();\r
+                alloc_page = null;\r
+            }\r
+                       if (prev_alloc_page != null)\r
+            {\r
+                               prev_alloc_page.unlatch();\r
+                               prev_alloc_page = null;\r
+            }\r
+\r
+            // flush all changes to this file from cache.\r
+            flushAll();\r
+\r
+            // make sure all truncated pages are removed from the cache,\r
+            // as it will get confused in the future if we allocate the same\r
+            // page again, but find an existing copy of it in the cache - \r
+            // it expects to not find new pages in the cache.  Could just\r
+            // get rid of truncated pages, iterface allows one page or\r
+            // all pages.\r
+            pageCache.discard(identity);\r
+        }\r
+       }\r
+\r
+       /**\r
+        * Get the reusable RecordId sequence number for the container.\r
+        * @see BaseContainer#getReusableRecordIdSequenceNumber\r
+        * @return reusable RecordId sequence number for the container.\r
+        */\r
+       public final long getReusableRecordIdSequenceNumber() {\r
+               synchronized(this) {\r
+                       return reusableRecordIdSequenceNumber;\r
+               }\r
+       }\r
+       \r
+       /**\r
+        * Increment the reusable RecordId version sequence number.\r
+        */\r
+       protected final void incrementReusableRecordIdSequenceNumber()\r
+       {\r
+               final boolean readOnly = dataFactory.isReadOnly();\r
+               \r
+               synchronized (this) {\r
+                       reusableRecordIdSequenceNumber++;\r
+                       if (!readOnly)\r
+                       {\r
+                               isDirty = true;\r
+                       }\r
+               }\r
+       }\r
+\r
+       /**\r
+         Create a new page in the container.\r
+\r
+         <BR> MT - thread aware - It is assumed that our caller (our super class)\r
+         has already arranged a logical lock on page allocation to only allow a\r
+         single thread through here.\r
+\r
+         Adding a new page involves 2 transactions and 2 pages.  \r
+         The User Transaction (UT) initiated the addPage call and expects a\r
+         latched page (owns by the UT) to be returned.\r
+         The Nested Top Transaction (NTT) is the transaction started by RawStore\r
+         inside an addPage call.  This NTT is committed before the page is\r
+         returned.  The NTT is used to accessed high traffic data structure such\r
+         as the AllocPage.\r
+\r
+         This is outline of the algorithm used in adding a page:\r
+         1) find or make an allocPage which can handle the addding of a new page.\r
+               Latch the allocPage with the NTT.\r
+         2) invalidate the allocation information cached by the container.\r
+               Without the cache no page can be gotten from the container.  Pages\r
+               already in the page cache is not affected.  Thus by latching the \r
+               allocPage and invalidating the allocation cache, this NTT blocks out \r
+               all page gets from this container until it commits.\r
+         3) the allocPage determines which page can be allocated, mark that in its\r
+               data structure (the alloc extent) and returns the page number of the\r
+               new page.  This change is associated with the NTT.\r
+         4) the NTT gets or creates the new page in the page cache (bypassing the\r
+               lookup of the allocPage since that is already latched by the NTT and\r
+               will deadlock).\r
+         5) the NTT initializes the page (mark it is being a VALID page).\r
+         6) the page latch is transfered to the UT from the NTT.\r
+         7) the new page is returned, latched by UT\r
+\r
+         If we use an NTT, the caller has to commit the NTT to release the\r
+         allocPage latch.  If we don't use an NTT, the allocPage latch is released\r
+         as this routine returns.\r
+\r
+         @param userHandle - the container handle opened by the user transaction, \r
+                                               use this to latch the new user page\r
+         @param ntt - the nested top transaction for the purpose of allocating the new page\r
+                                               If ntt is null, use the user transaction for allocation.\r
+         #param allocHandle - the container handle opened by the ntt, \r
+                                               use this to latch the alloc page\r
+\r
+         @exception StandardException Standard Derby error policy \r
+       */\r
+       protected BasePage newPage(BaseContainerHandle userHandle,\r
+                                                          RawTransaction ntt,\r
+                                                          BaseContainerHandle allocHandle,\r
+                                                          boolean isOverflow) \r
+                throws StandardException \r
+       {\r
+               // NOTE: we are single threaded thru this method, see MT comment\r
+\r
+               boolean useNTT = (ntt != null);\r
+\r
+               // if ntt is null, use user transaction\r
+               if (!useNTT)\r
+                       ntt = userHandle.getTransaction();\r
+\r
+               long lastPage;                  // last allocated page\r
+               long lastPreallocPage;  // last pre-allcated page\r
+               long pageNumber;                // the page number of the new page\r
+               PageKey pkey;                   // the identity of the new page\r
+               boolean reuse;                  // if true, we are trying to reuse a page\r
+\r
+               /* in case the page recommeded by allocPage is not committed yet, may\r
+               /* need to retry a couple of times */\r
+               boolean retry;\r
+               int numtries = 0;\r
+               long startSearch = lastAllocatedPage;\r
+\r
+               AllocPage allocPage = null;     // the alloc page\r
+               BasePage page = null;   // the new page\r
+\r
+               try\r
+               {\r
+                       do\r
+                       {\r
+                               retry = false;          // we don't expect we need to retry\r
+\r
+                               synchronized(allocCache)\r
+                               {\r
+                                       if (SanityManager.DEBUG)\r
+                                       {\r
+                                               SanityManager.ASSERT(\r
+                            ntt.getId().equals(\r
+                                allocHandle.getTransaction().getId()));\r
+\r
+                                               if (useNTT)\r
+                                                       SanityManager.ASSERT(\r
+                                !ntt.getId().equals(\r
+                                    userHandle.getTransaction().getId()));\r
+                                       }\r
+\r
+                    /* find an allocation page that can handle adding a new \r
+                     * page.\r
+                     *\r
+                     * allocPage is unlatched when the ntt commits. The new \r
+                     * page is initialized by the ntt but the latch is \r
+                     * transfered to the user transaction before the allocPage \r
+                     * is unlatched.  The allocPage latch prevents almost any \r
+                     * other reader or writer from finding the new page until \r
+                     * the ntt is committed and the new page is latched by the\r
+                     * user transaction.\r
+                     *\r
+                     * (If the page is being reused, it is possible for another\r
+                     * xact which kept a handle on the reused page to find the \r
+                     * page during the transfer UT -> NTT. If this unlikely \r
+                     * even occurs and the transfer fails [see code relating \r
+                     * to transfer below], we retry from the beginning.)\r
+                     *\r
+                     * After the NTT commits a reader (getNextPageNumber) may \r
+                     * get the page number of the newly allocated page and it \r
+                     * will wait for the new page and latch it when the user \r
+                     * transaction commits, aborts or unlatches the new page. \r
+                     * Whether the user transaction commits or aborts, the new \r
+                     * page stay allocated.\r
+                     *\r
+                     * RESOLVE: before NTT rolls back (or commits) the latch is\r
+                     * released.  To repopulate the allocation cache, need to \r
+                     * get either the container lock on add page, or get a per \r
+                     * allocation page lock.\r
+                     *\r
+                     * This blocks all page read (getPage) from accessing this \r
+                     * alloc page in this container until the alloc page is \r
+                     * unlatched.  Those who already have a page handle into \r
+                     * this container are unaffected.\r
+                     *\r
+                     * In other words, allocation blocks out reader (of any \r
+                     * page that is managed by this alloc page) by the latch \r
+                     * on the allocation page.\r
+                     *\r
+                     * Note that write page can proceed as usual.\r
+                     */\r
+                                       allocPage = \r
+                        findAllocPageForAdd(allocHandle, ntt, startSearch);\r
+\r
+                                       allocCache.invalidate(allocPage, allocPage.getPageNumber());\r
+                               }\r
+\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       if (allocPage == null)\r
+                                               allocCache.dumpAllocationCache();\r
+\r
+                                       SanityManager.ASSERT(allocPage != null,\r
+                         "findAllocPageForAdd returned a null alloc page");\r
+                               }\r
+\r
+                               //\r
+                               // get the next free page's number.\r
+                               // for case 1, page number > lastPreallocPage\r
+                               // for case 2, page number <= lastPage\r
+                               // for case 3, lastPage < page number <= lastPreallocPage\r
+                               //\r
+                               pageNumber = allocPage.nextFreePageNumber(startSearch);\r
+\r
+                               // need to distinguish between the following 3 cases:\r
+                               // 1) the page has not been allocate or initalized.\r
+                               //              Create it in the page cache and sync it to disk.\r
+                               // 2) the page is being re-allocated.\r
+                               //              We need to read it in to re-initialize it\r
+                               // 3) the page has been preallocated.\r
+                               //              Create it in the page cache and don't sync it to disk\r
+                               //\r
+                               // first find out the current last initialized page and\r
+                               // preallocated page before the new page is added\r
+                               lastPage         = allocPage.getLastPagenum();\r
+                               lastPreallocPage = allocPage.getLastPreallocPagenum();\r
+\r
+                               reuse = pageNumber <= lastPage;\r
+\r
+                               // no address translation necessary\r
+                               pkey = new PageKey(identity, pageNumber);\r
+\r
+\r
+                               if (reuse)\r
+                               {\r
+                                       // if re-useing a page, make sure the deallocLock on the new\r
+                                       // page is not held.  We only need a zero duration lock on\r
+                                       // the new page because the allocPage is latched and this\r
+                                       // is the only thread which can be looking at this\r
+                                       // pageNumber.\r
+\r
+                                       RecordHandle deallocLock = BasePage.MakeRecordHandle(pkey,\r
+                                                                RecordHandle.DEALLOCATE_PROTECTION_HANDLE);\r
+\r
+                                       if (!getDeallocLock(allocHandle, deallocLock,\r
+                                                                               false /* nowait */,\r
+                                                                               true /* zeroDuration */))\r
+                                       {\r
+\r
+                                               // The transaction which deallocated this page has not\r
+                                               // committed yet. Try going to some other page.  If\r
+                                               // this is the first time we fail to get the dealloc\r
+                                               // lock, try from the beginning of the allocated page.\r
+                                               // If we already did that and still fail, keep going\r
+                                               // until we get a brand new page.\r
+                                               if (numtries == 0)\r
+                                               {\r
+                                                       startSearch = ContainerHandle.INVALID_PAGE_NUMBER;\r
+                                                       lastAllocatedPage = pageNumber;\r
+                                               }\r
+                                               else    // continue from where we were\r
+                                                       startSearch = pageNumber;\r
+\r
+                                               numtries++;\r
+\r
+                                               // We have to unlatch the allocPage so that if that\r
+                                               // transaction rolls back, it won't deadlock with this\r
+                                               // transaction.\r
+                                               allocPage.unlatch();\r
+                                               allocPage = null;\r
+\r
+                                               retry = true;\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               // we got the lock, next time start from there\r
+                                               lastAllocatedPage = pageNumber;\r
+                                       }\r
+                               }\r
+                               else\r
+                               {\r
+                                       // we got a new page, next time, start from beginning of\r
+                                       // the bit map again if we suspect there are some some\r
+                                       // deallocated pages\r
+                                       if (numtries > 0)\r
+                                               lastAllocatedPage = ContainerHandle.INVALID_PAGE_NUMBER;\r
+                                       else\r
+                                               lastAllocatedPage = pageNumber;\r
+                               }\r
+\r
+                // Retry from the beginning if necessary.\r
+                if (retry)\r
+                    continue;\r
+\r
+                // If we get past here must have (retry == false)\r
+                if (SanityManager.DEBUG)\r
+                {\r
+                    SanityManager.ASSERT(retry == false);\r
+                }\r
+\r
+                           // Now we have verified that the allocPage is latched and we \r
+                // can get the zeroDuration deallocLock nowait.  This means the\r
+                // transaction which freed the page has committed.  Had that \r
+                // transaction aborted, we would have retried.\r
+\r
+                           if (SanityManager.DEBUG)\r
+                           {\r
+                                   // ASSERT lastPage <= lastPreallocPage\r
+                                   if (lastPage > lastPreallocPage)\r
+                    {\r
+                                           SanityManager.THROWASSERT("last page " +\r
+                                                   lastPage + " > lastPreallocPage " + \r
+                            lastPreallocPage);\r
+                    }\r
+                           }\r
+\r
+                           // No I/O at all if this new page is requested as part of a \r
+                // create and load statement or this new page is in a temporary\r
+                // container.\r
+                //\r
+                           // In the former case, BaseContainer will allow the \r
+                // MODE_UNLOGGED bit to go thru to the nested top transaction \r
+                // alloc handle.  In the later case, there is no nested top \r
+                // transaction and the alloc handle is the user handle, which \r
+                // is UNLOGGED.\r
+                           boolean noIO = \r
+                    (allocHandle.getMode() & ContainerHandle.MODE_UNLOGGED) ==\r
+                        ContainerHandle.MODE_UNLOGGED;\r
+\r
+                           // If we do not need the I/O (either because we are in a\r
+                           // create_unlogged mode or we are dealing with a temp table), \r
+                // don't do any preallocation.  Otherwise, see if we should be\r
+                           // pre-Allocating page by now.  We don't call it before\r
+                           // nextFreePageNumber because finding a reusable page may be\r
+                           // expensive and we don't want to start preAllocation unless \r
+                // there is no more reusable page.  Unless we are called \r
+                // explicitly to bulk increase the container size in a preload \r
+                // or in a create container.\r
+                           if (!noIO && \r
+                    (bulkIncreaseContainerSize ||\r
+                                        (pageNumber > lastPreallocPage && \r
+                      pageNumber > PreAllocThreshold)))\r
+                           {\r
+                                   allocPage.preAllocatePage(\r
+                        this, PreAllocThreshold, PreAllocSize);\r
+                           }\r
+\r
+                           // update last preAllocated Page, it may have been changed by \r
+                // the preAllocatePage call.  We don't want to do the sync if \r
+                           // preAllocatePage already took care of it.\r
+                           lastPreallocPage = allocPage.getLastPreallocPagenum();\r
+                           boolean prealloced = pageNumber <= lastPreallocPage;\r
+\r
+                           // Argument to the create is an array of ints.\r
+                           // The array is only used for new page creation or for creating\r
+                // a preallocated page, not for reuse.\r
+                           // 0'th element is the page format\r
+                           // 1'st element is whether or not to sync the page to disk\r
+                           // 2'nd element is pagesize\r
+                           // 3'rd element is spareSpace\r
+\r
+                PageCreationArgs createPageArgs = new PageCreationArgs(\r
+                        StoredPage.FORMAT_NUMBER,\r
+                        prealloced ? 0 : (noIO ? 0 : CachedPage.WRITE_SYNC),\r
+                        pageSize,\r
+                        spareSpace,\r
+                        minimumRecordSize,\r
+                        0 /* containerInfoSize - unused for StoredPage */);\r
+\r
+                           // RESOLVE: right now, there is no re-mapping of pages, so\r
+                           // pageOffset = pageNumber*pageSize\r
+                           long pageOffset = pageNumber * pageSize;\r
+\r
+                           // initialize a new user page\r
+                           // we first use the NTT to initialize the new page - in case the\r
+                           // allocation failed, it is rolled back with the NTT.\r
+                           // Later, we transfer the latch to the userHandle so it won't be\r
+                           // released when the ntt commits\r
+\r
+                try\r
+                {\r
+                           page = initPage(allocHandle, pkey, createPageArgs, pageOffset,\r
+                                                       reuse, isOverflow);\r
+                }\r
+                catch (StandardException se)\r
+                {\r
+                    if (SanityManager.DEBUG) {\r
+                        SanityManager.DEBUG_PRINT("FileContainer",\r
+                            "got exception from initPage:"  +\r
+                            "\nreuse = " + reuse +\r
+                            "\nsyncFlag = " + createPageArgs.syncFlag +\r
+                            "\nallocPage = " + allocPage\r
+                            );\r
+                    }\r
+                    allocCache.dumpAllocationCache();\r
+\r
+                    throw se;\r
+                }\r
+\r
+                           if (SanityManager.DEBUG)\r
+                           {\r
+                                   SanityManager.ASSERT(\r
+                        page != null, "initPage returns null page");\r
+                                   SanityManager.ASSERT(\r
+                        page.isLatched(), "initPage returns unlatched page");\r
+                           }\r
+\r
+                           // allocate the page in the allocation page bit map\r
+                           allocPage.addPage(this, pageNumber, ntt, userHandle);\r
+\r
+                           if (useNTT)\r
+                           {\r
+                                   // transfer the page latch from NTT to UT.\r
+                    //\r
+                                   // after the page is unlatched by NTT, it is still \r
+                    // protected from being found by almost everybody else \r
+                    // because the alloc page is still latched and the alloc \r
+                    // cache is invalidated.\r
+                    //\r
+                    // However it is possible for the page to be \r
+                    // found by threads who specifically ask for this \r
+                    // pagenumber (e.g. HeapPostCommit).\r
+                    // We may find that such a thread has latched the page. \r
+                    // We shouldn't wait for it because we have the alloc page \r
+                    // latch, and this could cause deadlock (e.g. \r
+                    // HeapPostCommit might call removePage and this would wait\r
+                    // on the alloc page).\r
+                    //\r
+                    // We may instead find that we can latch the page, but that\r
+                    // another thread has managed to get hold of it during the \r
+                    // transfer and either deallocated it or otherwise change it\r
+                    // (add rows, delete rows etc.)\r
+                    //\r
+                    // Since this doesn't happen very often, we retry in these \r
+                    // 2 cases (we give up the alloc page and page and we start\r
+                    // this method from scratch).\r
+                    //\r
+                    // If the lock manager were changed to allow latches to be \r
+                    // transferred between transactions, wouldn't need to \r
+                    // unlatch to do the transfer, and would avoid having to \r
+                    // retry in these cases (DERBY-2337).\r
+\r
+                                   page.unlatch();\r
+                                   page = null;\r
+\r
+                                   // need to find it in the cache again since unlatch also \r
+                    // unkept the page from the cache\r
+                                   page = (BasePage)pageCache.find(pkey);\r
+                                   page = latchPage(\r
+                                userHandle, page, \r
+                                false /* don't wait, it might deadlock */);\r
+\r
+                    if (page == null ||\r
+                        // recordCount will only return true if there are no \r
+                        // rows (including deleted rows)\r
+                        page.recordCount() != 0 ||\r
+                        page.getPageStatus() != BasePage.VALID_PAGE)\r
+                    {\r
+                        retry = true;\r
+                        if (page != null)\r
+                        {\r
+                            page.unlatch();\r
+                            page = null;\r
+                        }\r
+                        allocPage.unlatch();\r
+                        allocPage = null;\r
+                    }\r
+\r
+                }\r
+                       // if ntt is null, no need to transfer.  Page is latched by user\r
+                       // transaction already.  Will be no need to retry.\r
+                       // the alloc page is unlatched in the finally block.\r
+            }\r
+            while (retry == true);\r
+\r
+            // At this point, should have a page suitable for returning\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(page.isLatched());\r
+               }\r
+               catch (StandardException se)\r
+               {\r
+                       if (page != null)\r
+                               page.unlatch();\r
+                       page = null;\r
+\r
+                       throw se;                       // rethrow error\r
+               }\r
+               finally\r
+               {\r
+                       if (!useNTT && allocPage != null)\r
+                       {\r
+                               allocPage.unlatch();\r
+                               allocPage = null;\r
+                       }\r
+\r
+                       // NTT is committed by the caller\r
+               }\r
+\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(page.isLatched());\r
+\r
+\r
+               // if bulkIncreaseContainerSize is set, that means this newPage call\r
+               // may have greatly expanded the container size due to preallocation.\r
+               // Regardless of how many page it actually created, reset preAllocSize\r
+               // to the default so we won't attempt to always preallocate 1000 pages\r
+               // at a time in the future.\r
+               if (bulkIncreaseContainerSize)\r
+               {\r
+                       bulkIncreaseContainerSize = false;\r
+                       PreAllocSize = DEFAULT_PRE_ALLOC_SIZE;\r
+               }\r
+\r
+               if (!isOverflow && page != null)\r
+                       setLastInsertedPage(pageNumber);\r
+\r
+\r
+               // increase estimated page count - without any synchronization or\r
+               // logging, this is an estimate only\r
+               if (estimatedPageCount >= 0)\r
+                       estimatedPageCount++;\r
+\r
+               if (!this.identity.equals(page.getPageId().getContainerId())) {\r
+\r
+                       if (SanityManager.DEBUG) {\r
+                               SanityManager.THROWASSERT(\r
+                    "just created a new page from a different container"\r
+                                       + "\n this.identity = " + this.identity\r
+                                       + "\n page.getPageId().getContainerId() = " + \r
+                        page.getPageId().getContainerId()\r
+                                       + "\n userHandle is: " + userHandle\r
+                                       + "\n allocHandle is: " + allocHandle\r
+                                       + "\n this container is: " + this);\r
+                       }\r
+\r
+                       throw StandardException.newException(\r
+                    SQLState.DATA_DIFFERENT_CONTAINER, \r
+                    this.identity, page.getPageId().getContainerId());\r
+               }\r
+\r
+               return page;                    // return the newly added page\r
+       }\r
+\r
+       protected void clearPreallocThreshold()\r
+       {\r
+               // start life with preallocated page if possible\r
+               PreAllocThreshold = 0;\r
+       }\r
+\r
+       protected void prepareForBulkLoad(BaseContainerHandle handle, int numPage)\r
+       {\r
+               clearPreallocThreshold();\r
+               RawTransaction tran = handle.getTransaction();\r
+\r
+               // find the last allocation page - do not invalidate the alloc cache,\r
+               // we don't want to prevent other people from reading or writing\r
+               // pages. \r
+               AllocPage allocPage = findLastAllocPage(handle, tran);\r
+\r
+               // preallocate numPages.  Do whatever this allocPage can handle, if it\r
+               // is full, too bad.  We don't guarentee that we will preallocate this\r
+               // many pages, we only promise to try.\r
+               if (allocPage != null)\r
+               {\r
+                       allocPage.preAllocatePage(this, 0, numPage); \r
+                       allocPage.unlatch();    \r
+               }\r
+       }\r
+\r
+       private boolean pageValid(BaseContainerHandle handle, long pagenum)\r
+                throws StandardException\r
+       {\r
+               boolean retval = false;\r
+\r
+               synchronized(allocCache)\r
+               {\r
+                       if (pagenum <= allocCache.getLastPageNumber(handle, firstAllocPageNumber) && \r
+                               allocCache.getPageStatus(handle, pagenum, firstAllocPageNumber) == AllocExtent.ALLOCATED_PAGE)\r
+                               retval = true;\r
+               }\r
+\r
+               return retval;\r
+       }\r
+\r
+       protected long getLastPageNumber(BaseContainerHandle handle) \r
+        throws StandardException\r
+       {\r
+               long retval;\r
+               synchronized(allocCache)\r
+               {\r
+            // check if the first alloc page number is valid, it is invalid \r
+            // if some one attempts to access the container info before the \r
+            // first alloc page got created. One such case is online backup. \r
+            // If first alloc page itself is invalid, then there are no pages\r
+            // on the disk yet for this container, just return\r
+            // ContainerHandle.INVALID_PAGE_NUMBER, caller can decide what to\r
+            // do. \r
+            \r
+            if (firstAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER)   \r
+            {\r
+                retval = ContainerHandle.INVALID_PAGE_NUMBER;\r
+            }\r
+            else\r
+            {\r
+                retval = \r
+                    allocCache.getLastPageNumber(handle, firstAllocPageNumber);\r
+            }\r
+               }\r
+               return retval;\r
+       }\r
+\r
+       /*\r
+               Find or allocate an allocation page which can handle adding a new page.\r
+               Return a latched allocPage.\r
+\r
+               <BR> MT - single thread required - called as part of add page\r
+       */\r
+       private AllocPage findAllocPageForAdd(BaseContainerHandle allocHandle,\r
+                                                                                 RawTransaction ntt, long lastAllocatedPage)\r
+                throws StandardException\r
+       {\r
+               AllocPage allocPage = null;\r
+               AllocPage oldAllocPage = null; // in case we need to walk the alloc page chain\r
+               boolean success = false; // set this for clean up\r
+\r
+               try\r
+               {\r
+                       if (firstAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       {\r
+                               // make and return a latched new allocation page\r
+                               allocPage = makeAllocPage(ntt, allocHandle, FIRST_ALLOC_PAGE_NUMBER,\r
+                                                                                 FIRST_ALLOC_PAGE_OFFSET, CONTAINER_INFO_SIZE);\r
+\r
+                               if (SanityManager.DEBUG)\r
+                               {\r
+                                       SanityManager.ASSERT(firstAllocPageNumber == FIRST_ALLOC_PAGE_NUMBER,\r
+                                                                                "first Alloc Page number is still not set");\r
+                                       SanityManager.ASSERT(firstAllocPageOffset == FIRST_ALLOC_PAGE_OFFSET,\r
+                                                                                "first Alloc Page offset is still not set");\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               // an allocation page already exist, go get it\r
+                               allocPage = (AllocPage)allocHandle.getAllocPage(firstAllocPageNumber);\r
+                       }\r
+\r
+                       /* allocPage is latched by allocHandle */\r
+\r
+                       if (!allocPage.canAddFreePage(lastAllocatedPage))\r
+                       {\r
+                               // allocPage cannot manage the addition of one more page, walk the\r
+                               // alloc page chain till we find an allocPage that can\r
+                               // RESOLVE: always start with the first page for now...\r
+\r
+                               boolean found = false; // found an alloc page that can handle \r
+                                                                               // adding a new page\r
+\r
+                               while(allocPage.isLast() != true)\r
+                               {\r
+                                       long nextAllocPageNumber = allocPage.getNextAllocPageNumber();\r
+                                       long nextAllocPageOffset = allocPage.getNextAllocPageOffset();\r
+\r
+                                       // RESOLVE (future): chain this info to in memory structure so\r
+                                       // getAllocPage can find this alloc page\r
+\r
+                                       allocPage.unlatch();\r
+                                       allocPage = null;\r
+\r
+                                       // the nextAllocPage is stable once set - even though it is\r
+                                       // save to get the next page latch before releasing this\r
+                                       // allocPage.\r
+                                       allocPage = (AllocPage)allocHandle.getAllocPage(nextAllocPageNumber);\r
+\r
+                                       if (allocPage.canAddFreePage(lastAllocatedPage))\r
+                                       {\r
+                                               found = true;\r
+                                               break;\r
+                                       }\r
+                               }\r
+\r
+                               if (!found)\r
+                               {\r
+                                       // allocPage is last and it is full\r
+                                       oldAllocPage = allocPage;\r
+                                       allocPage = null;\r
+\r
+                                       if (SanityManager.DEBUG)\r
+                                               SanityManager.ASSERT(oldAllocPage.getLastPagenum() ==\r
+                                                                                        oldAllocPage.getMaxPagenum(),\r
+                                                                                        "expect allocpage to be full but last pagenum != maxpagenum");\r
+\r
+                                       long newAllocPageNum = oldAllocPage.getMaxPagenum() + 1;\r
+                                       long newAllocPageOffset = newAllocPageNum; // no translation\r
+\r
+                                       allocPage = makeAllocPage(ntt, allocHandle,\r
+                                                                                         newAllocPageNum,\r
+                                                                                         newAllocPageOffset,\r
+                                                                                         0 /* no containerInfo */);\r
+\r
+                                       // this writes out the new alloc page and return a latched page\r
+                                       // nobody can find the new alloc page until oldAllocPage is unlatched.\r
+\r
+                                       // oldAllocPage is no longer the last alloc page, \r
+                                       // it has a pointer to the new last alloc page\r
+                                       oldAllocPage.chainNewAllocPage(allocHandle, newAllocPageNum, newAllocPageOffset);\r
+                                       oldAllocPage.unlatch();\r
+                                       oldAllocPage = null;\r
+                               }\r
+                       }\r
+\r
+                       /* no error handling necessary */\r
+                       success = true;\r
+               }\r
+               finally                                 // unlatch allocation page if any error happened\r
+               {\r
+                       if (!success)\r
+                       {\r
+                               if (oldAllocPage != null)\r
+                                       oldAllocPage.unlatch();\r
+\r
+                               if (allocPage != null)\r
+                                       allocPage.unlatch();\r
+\r
+                               allocPage = null;\r
+                       }\r
+\r
+                       // if success drop out of finally block\r
+               }\r
+\r
+               return allocPage;\r
+       }\r
+\r
+       /**\r
+               Find the last alloc page, returns null if no alloc page is found\r
+        */\r
+       private AllocPage findLastAllocPage(BaseContainerHandle handle,\r
+                                                                               RawTransaction tran)\r
+       {\r
+               AllocPage allocPage = null;\r
+               AllocPage oldAllocPage = null;\r
+\r
+               if (firstAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       return null;\r
+\r
+               try\r
+               {\r
+                       allocPage = (AllocPage)handle.getAllocPage(firstAllocPageNumber);\r
+                       while(!allocPage.isLast())\r
+                       {\r
+                               long nextAllocPageNumber = allocPage.getNextAllocPageNumber();\r
+                               long nextAllocPageOffset = allocPage.getNextAllocPageOffset();\r
+\r
+                               allocPage.unlatch();\r
+                               allocPage = null;\r
+\r
+                               allocPage = (AllocPage)handle.getAllocPage(nextAllocPageNumber);\r
+                       }\r
+               }\r
+               catch (StandardException se)\r
+               {\r
+                       if (allocPage != null)\r
+                               allocPage.unlatch();\r
+                       allocPage = null;\r
+               }\r
+\r
+               return allocPage;\r
+\r
+       }\r
+\r
+\r
+       /*\r
+               Make a new alloc page, latch it with the passed in container handle.\r
+       */\r
+       private AllocPage makeAllocPage(RawTransaction ntt, \r
+                                                                       BaseContainerHandle handle, \r
+                                                                       long pageNumber, \r
+                                                                       long pageOffset,\r
+                                                                       int containerInfoSize)\r
+                throws StandardException\r
+       {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       if (containerInfoSize != 0 && \r
+                                                                containerInfoSize != CONTAINER_INFO_SIZE)\r
+                               SanityManager.THROWASSERT(\r
+                                                                "expect 0 or " + CONTAINER_INFO_SIZE +\r
+                                                                ", got " + containerInfoSize);\r
+\r
+                       if (pageNumber != FIRST_ALLOC_PAGE_NUMBER &&\r
+                                                                containerInfoSize != 0)\r
+                               SanityManager.THROWASSERT(\r
+                                                                "Not first alloc page but container info size "\r
+                                                                + containerInfoSize);\r
+               }\r
+\r
+               // argument to the create is an array of ints\r
+               // 0'th element is the page format\r
+               // 1'st element is whether or not to sync the page to disk\r
+               // 2'nd element is the pagesize\r
+               // 3'rd element is spareSpace\r
+               // 4'th element is number of bytes to reserve for the container header\r
+               // 5'th element is the minimumRecordSize\r
+               // NOTE: the arg list here must match the one in allocPage\r
+\r
+               // No I/O at all if this new page is requested as part of a create\r
+               // and load statement or this new alloc page is in a temporary \r
+        // container.\r
+               // In the former case, BaseContainer will allow the MODE_UNLOGGED\r
+               // bit to go thru to the nested top transaction alloc handle.\r
+               // In the later case, there is no nested top transaction and the\r
+               // alloc handle is the user handle, which is UNLOGGED.\r
+\r
+               boolean noIO = (handle.getMode() & ContainerHandle.MODE_UNLOGGED) ==\r
+                       ContainerHandle.MODE_UNLOGGED;\r
+\r
+               PageCreationArgs createAllocPageArgs = new PageCreationArgs(\r
+                AllocPage.FORMAT_NUMBER,\r
+                noIO ? 0 : CachedPage.WRITE_SYNC,\r
+                pageSize,\r
+                0,        // allocation page has no need for spare\r
+                minimumRecordSize,\r
+                containerInfoSize);\r
+\r
+               if (SanityManager.DEBUG)\r
+        {\r
+            if (SanityManager.DEBUG_ON(SPACE_TRACE))\r
+            {\r
+                SanityManager.DEBUG(\r
+                    SPACE_TRACE, "making new allocation page at " + pageNumber);\r
+            }\r
+        }\r
+\r
+               if (pageNumber == FIRST_ALLOC_PAGE_NUMBER)\r
+               {\r
+                       // RESOLVE: make sure the following is true\r
+                       // \r
+                       // firstAllocPageNumber and Offset can be set and access without\r
+                       // synchronization since the first allocation page is\r
+                       // created as part of the container create, this value is set\r
+                       // before any other transaction has a chance to open the container.\r
+                       // Once set, the first allocation page does not move or change\r
+                       // position \r
+                       firstAllocPageNumber = pageNumber;\r
+                       firstAllocPageOffset = pageOffset;\r
+\r
+               }\r
+\r
+               PageKey pkey = new PageKey(identity, pageNumber);\r
+\r
+               // return a latched new alloc page\r
+               return (AllocPage)initPage(handle, pkey, createAllocPageArgs, \r
+                                                                  pageOffset,\r
+                                                                  false, /* not reuse */\r
+                                                                  false /* not overflow */);\r
+       }\r
+\r
+       /**\r
+               Initialize a page \r
+\r
+               @return a latched page that has been initialized.\r
+\r
+               @param allochandle the contianer handle to initialize the page with - the ntt\r
+               @param pkey the page number of the page to be initialized\r
+               @param createArgs the arguments for page creation\r
+               @param reuse is true if we are reusing a page that has \r
+                               already been initialized once\r
+\r
+               @exception StandardException Derby Standard error policy\r
+       */\r
+       protected BasePage initPage(BaseContainerHandle allochandle, \r
+                                                               PageKey pkey,\r
+                                                               PageCreationArgs createArgs,\r
+                                                               long pageOffset,\r
+                                                               boolean reuse,\r
+                                                               boolean overflow) throws StandardException\r
+       {\r
+               BasePage page = null;\r
+\r
+               boolean releasePage = true;\r
+\r
+               try\r
+               {\r
+                       if (reuse)                              //  read the page in first\r
+                       {\r
+                               // Cannot go thru the container handle because all read pages are blocked.  \r
+                               // do it underneath the handle and directly to the cache.  \r
+                               // Nobody can get thru becuase getPage will block at getting the alloc page.\r
+\r
+                               if (SanityManager.DEBUG)\r
+                {\r
+                    if (SanityManager.DEBUG_ON(SPACE_TRACE))\r
+                    {\r
+                        SanityManager.DEBUG(\r
+                            SPACE_TRACE, "reusing page " + pkey);\r
+                    }\r
+                }\r
+\r
+                               page = (BasePage)pageCache.find(pkey);\r
+                               if (page == null)       // hmmm?\r
+                {\r
+                                       throw StandardException.newException(\r
+                            SQLState.FILE_REUSE_PAGE_NOT_FOUND, pkey);\r
+                }\r
+                       }\r
+                       else\r
+                       {\r
+                               if (SanityManager.DEBUG)\r
+                {\r
+                    if (SanityManager.DEBUG_ON(SPACE_TRACE))\r
+                    {\r
+                        SanityManager.DEBUG(\r
+                            SPACE_TRACE, "allocation new page " + pkey);\r
+                    }\r
+                }\r
+\r
+                               // a brand new page, initialize and a new page in cache\r
+                               page = (BasePage) pageCache.create(pkey, createArgs);\r
+\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(page != null, "page Cache create return a null page");\r
+                       }\r
+                       releasePage = false;\r
+            page = latchPage(allochandle, page, true /* may need to wait, track3822 */);\r
+\r
+                       if (page == null)\r
+            {\r
+                               throw StandardException.newException(\r
+                        SQLState.FILE_NEW_PAGE_NOT_LATCHED, pkey);\r
+            }     \r
+\r
+                       // page is either brand new or is read from disk, in either case,\r
+                       // it knows how to get itself initialized.\r
+                       int initPageFlag = 0;\r
+                       if (reuse) initPageFlag |= BasePage.INIT_PAGE_REUSE;\r
+                       if (overflow) initPageFlag |= BasePage.INIT_PAGE_OVERFLOW;\r
+                       if (reuse && isReusableRecordId())\r
+                               initPageFlag |= BasePage.INIT_PAGE_REUSE_RECORDID;\r
+\r
+                       page.initPage(initPageFlag, pageOffset);\r
+                       page.setContainerRowCount(estimatedRowCount);\r
+\r
+               }\r
+               finally\r
+               {\r
+                       if (releasePage && page != null)\r
+                       {\r
+                               // release the new page from cache if it errors \r
+                               // out before the exclusive lock is set\r
+                               pageCache.release((Cacheable)page);\r
+                               page = null;\r
+                       }\r
+               }\r
+\r
+               return page;\r
+       }\r
+\r
+\r
+       /**\r
+               Get a page in the container.    \r
+\r
+               Get User page is the generic base routine for all user (client to raw\r
+               store) getPage.  This routine coordinate with allocation/deallocation\r
+               to ensure that no page can be gotten from the container while page is\r
+               in the middle of being allocated or deallocated.\r
+        This routine latches the page.\r
+\r
+               @param handle the container handle\r
+               @param pageNumber the page number of the page to get\r
+               @param overflowOK if true then an overflow page is OK,\r
+                               if false, then only non-overflow page is OK\r
+        @param wait if true then wait for a latch\r
+        @return the latched page\r
+\r
+               <BR> MT - thread safe\r
+\r
+               @exception StandardException Standard Derby error policy\r
+       */\r
+       private BasePage getUserPage(BaseContainerHandle handle, long pageNumber,\r
+        boolean overflowOK, boolean wait)\r
+                throws StandardException\r
+       {\r
+\r
+               if (SanityManager.DEBUG) \r
+        {\r
+                       SanityManager.ASSERT(\r
+                pageNumber != FIRST_ALLOC_PAGE_NUMBER,\r
+                "getUserPage trying to get an alloc page, pageNumber = " + \r
+                pageNumber);\r
+\r
+                       if (pageNumber < ContainerHandle.FIRST_PAGE_NUMBER)\r
+                               SanityManager.THROWASSERT("pageNumber = " + pageNumber);\r
+               }\r
+\r
+               if (pageNumber < ContainerHandle.FIRST_PAGE_NUMBER)\r
+                       return null;\r
+\r
+               if (getCommittedDropState()) // committed and dropped, cannot get a page\r
+                       return null;\r
+\r
+               if (!pageValid(handle, pageNumber))\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               // RESOLVE: no translation!\r
+\r
+               PageKey pageSearch = new PageKey(identity, pageNumber);\r
+               BasePage page = (BasePage)pageCache.find(pageSearch);\r
+\r
+               if (page == null)\r
+               {\r
+                       return page;\r
+               }\r
+\r
+        // latch the page\r
+        if (latchPage(handle,page,wait) == null)\r
+        {\r
+                       // page was already released from cache\r
+            return null;\r
+        }\r
+\r
+               // double check for overflow and deallocated page\r
+               // a page that was valid before maybe invalid by now if it was\r
+               // deallocated in the interum.\r
+               // a page that is invalid can also become valid in the interim, but\r
+               // we do not handle that.  The client must supply other locking\r
+               // mechanism to prevent that (an allocatino happenning where there are\r
+               // readers) if that is needed\r
+               if ((page.isOverflowPage() && !overflowOK) ||\r
+                       (page.getPageStatus() != BasePage.VALID_PAGE))\r
+               {\r
+                       // unlatch releases page from cache, see StoredPage.releaseExclusive()\r
+            page.unlatch();\r
+                       page = null;\r
+               }\r
+\r
+               return page;\r
+       }\r
+\r
+       protected void trackUnfilledPage(long pagenumber, boolean unfilled)\r
+       {\r
+               if (!dataFactory.isReadOnly())\r
+                       allocCache.trackUnfilledPage(pagenumber, unfilled);\r
+       }\r
+\r
+       /**\r
+               Get a valid (non-deallocated or free) page in the container.\r
+               Overflow page is OK. Resulting page is latched.\r
+\r
+               <BR> MT - thread safe\r
+\r
+               @exception StandardException Standard Derby error policy\r
+       */\r
+       protected BasePage getPage(BaseContainerHandle handle, long pageNumber,\r
+        boolean wait)\r
+                throws StandardException\r
+       {\r
+               return getUserPage(handle, pageNumber, true /* overflow page OK */,\r
+            wait);\r
+       }\r
+\r
+\r
+       /**\r
+               Get any old page - turn off all validation\r
+\r
+               @exception StandardException Derby Standard error policy\r
+       */\r
+       protected BasePage getAnyPage(BaseContainerHandle handle, long pageNumber) throws StandardException\r
+       {\r
+               // get AllocPage get a page without any validation (exception a\r
+               // committed dropped container)\r
+\r
+               if (getCommittedDropState()) // committed and dropped, cannot get a page\r
+                       return null;\r
+\r
+               // make sure alloc cache has no stale info\r
+               synchronized(allocCache)\r
+               {\r
+                       allocCache.invalidate();\r
+               }\r
+               \r
+               PageKey pageSearch = new PageKey(identity, pageNumber);\r
+               BasePage page = (BasePage) pageCache.find(pageSearch);\r
+\r
+               return page;\r
+       }\r
+\r
+    /**\r
+     * ReCreate a page for rollforward recovery.  \r
+     * <p>\r
+     * During redo recovery it is possible for the system to try to redo\r
+     * the creation of a page (ie. going from non-existence to version 0).\r
+     * It first trys to read the page from disk, but a few different types\r
+     * of errors can occur:\r
+     *     o the page does not exist at all on disk, this can happen during\r
+     *       rollforward recovery applied to a backup where the file was\r
+     *       copied and the page was added to the file during the time frame\r
+     *       of the backup but after the physical file was copied.\r
+     *     o space in the file exists, but it was never initalized.  This\r
+     *       can happen if you happen to crash at just the right moment during\r
+     *       the allocation process.  Also\r
+     *       on some OS's it is possible to read from a part of the file that\r
+     *       was not ever written - resulting in garbage from the store's \r
+     *       point of view (often the result is all 0's).  \r
+     *\r
+     * All these errors are easy to recover from as the system can easily \r
+     * create a version 0 from scratch and write it to disk.\r
+     *\r
+     * Because the system does not sync allocation of data pages, it is also\r
+     * possible at this point that whlie writing the version 0 to disk to \r
+     * create it we may encounter an out of disk space error (caught in this\r
+     * routine as a StandardException from the create() call.  We can't \r
+     * recovery from this without help from outside, so the caught exception\r
+     * is nested and a new exception thrown which the recovery system will\r
+     * output to the user asking them to check their disk for space/errors.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected BasePage reCreatePageForRedoRecovery(\r
+    BaseContainerHandle handle,\r
+    int                 pageFormat,\r
+    long                pageNumber,\r
+    long                pageOffset)\r
+                throws StandardException\r
+       {\r
+               // recreating a page should be done only if are in the middle of \r
+        // rollforward recovery or if derby.storage.patchInitPageRecoverError \r
+        // is set to true.\r
+\r
+               //check if we are in rollforward recovery\r
+               boolean rollForwardRecovery = \r
+                       ((RawTransaction)handle.getTransaction()).inRollForwardRecovery();\r
+\r
+               if (!rollForwardRecovery && !(PropertyUtil.getSystemBoolean(\r
+                    RawStoreFactory.PATCH_INITPAGE_RECOVER_ERROR)))\r
+               {\r
+                       return null;\r
+               }\r
+\r
+               // RESOLVE: first need to verify that the page is really NOT in the\r
+               // container!\r
+\r
+               // no address translation necessary\r
+               PageKey pkey = new PageKey(identity, pageNumber);\r
+\r
+               PageCreationArgs reCreatePageArgs;\r
+\r
+               if (pageFormat == StoredPage.FORMAT_NUMBER)\r
+               {\r
+            reCreatePageArgs = new PageCreationArgs(\r
+                    pageFormat,\r
+                    CachedPage.WRITE_SYNC,\r
+                    pageSize,\r
+                    spareSpace,\r
+                    minimumRecordSize,\r
+                    0 /* containerInfoSize - unused for StoredPage */);\r
+               }\r
+               else if (pageFormat == AllocPage.FORMAT_NUMBER)\r
+               {\r
+\r
+                       // only the first allocation page have borrowed space for the\r
+                       // container info\r
+\r
+                       int containerInfoSize = 0;\r
+                       if (pageNumber == FIRST_ALLOC_PAGE_NUMBER)\r
+                       {\r
+                               containerInfoSize = CONTAINER_INFO_SIZE;\r
+                               firstAllocPageNumber = pageNumber;\r
+                               firstAllocPageOffset = pageOffset;\r
+                       }\r
+\r
+            reCreatePageArgs = new PageCreationArgs(\r
+                    pageFormat,\r
+                    CachedPage.WRITE_SYNC,\r
+                    pageSize,\r
+                    0, // allocation page has no need for spare\r
+                    minimumRecordSize,\r
+                    containerInfoSize);\r
+\r
+               }\r
+               else\r
+               {\r
+                       throw StandardException.newException(\r
+                    SQLState.DATA_UNKNOWN_PAGE_FORMAT, pkey);\r
+               }\r
+\r
+        if (SanityManager.DEBUG) \r
+        {\r
+                       if (SanityManager.DEBUG_ON("LoadTran"))\r
+                               SanityManager.DEBUG_PRINT(\r
+                    "Trace", "recreating page " + pkey + " for load tran");\r
+        }\r
+\r
+               // Can't just call initPage because that wants to log an initPage\r
+               // operation, whereas we are here because of an initPage operation in\r
+               // the log already.\r
+               BasePage page = null;\r
+               boolean releasePage = true;\r
+\r
+               try\r
+               {\r
+            try\r
+            {\r
+                // a brand new page, initialize a new page in cache\r
+                page = (BasePage) pageCache.create(pkey, reCreatePageArgs);\r
+            }\r
+            catch (StandardException se)\r
+            {\r
+                throw StandardException.newException(\r
+                    SQLState.FILE_NEW_PAGE_DURING_RECOVERY, se, pkey);\r
+            }\r
+\r
+            if (page != null)\r
+            {\r
+                releasePage = false;\r
+                page = latchPage(handle, page, false /* never need to wait */);\r
+\r
+                if (page == null)\r
+                {\r
+                    throw StandardException.newException(\r
+                            SQLState.FILE_NEW_PAGE_NOT_LATCHED, pkey);\r
+                }\r
+            }\r
+            else\r
+            {\r
+                throw StandardException.newException(\r
+                    SQLState.FILE_NEW_PAGE_DURING_RECOVERY, pkey);\r
+            }\r
+\r
+               }\r
+               finally\r
+               {\r
+                       if (releasePage && page != null)\r
+                       {\r
+                               // release the new page from cache if it errors out before \r
+                // the exclusive lock is set error in roll forward recovery.\r
+                // , we are doomed anyway\r
+                               pageCache.release((Cacheable)page);\r
+                               page = null;\r
+                       }\r
+               }\r
+\r
+               return page;\r
+\r
+       }\r
+\r
+\r
+       /** \r
+               Get an alloc page - only accessible to the raw store \r
+               (container and recovery)\r
+\r
+               @exception StandardException Derby Standard error policy\r
+        */\r
+       protected BasePage getAllocPage(long pageNumber) throws StandardException \r
+       {\r
+               if (getCommittedDropState()) // committed and dropped, cannot get a page\r
+                       return null;\r
+\r
+               PageKey pageSearch = new PageKey(identity, pageNumber);\r
+               BasePage page = (BasePage) pageCache.find(pageSearch);\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       if (page == null)\r
+                               SanityManager.THROWASSERT(\r
+                                       "getting a null alloc page page " + \r
+                                       getIdentity() + pageNumber);\r
+\r
+                       if ( ! (page instanceof AllocPage))\r
+                               SanityManager.THROWASSERT(\r
+                                       "trying to get a user page as an alloc page " + \r
+                                       getIdentity() + pageNumber); \r
+               }\r
+\r
+               // assuming that allocation page lives in the page cache...\r
+               return page;\r
+       }\r
+\r
+       /**\r
+               Get only a valid, non-overflow page.  If page number is either invalid\r
+               or overflow, returns null\r
+\r
+               @exception StandardException Derby Standard error policy\r
+        */\r
+       protected BasePage getHeadPage(BaseContainerHandle handle, long pageNumber,\r
+        boolean wait)\r
+                throws StandardException\r
+       {\r
+               return getUserPage(handle, pageNumber, false /* overflow not ok */,\r
+            wait);\r
+       }\r
+\r
+       /**\r
+               Get the first valid page in the container\r
+\r
+               @exception StandardException Derby Standard error policy\r
+        */\r
+       protected BasePage getFirstHeadPage(BaseContainerHandle handle, boolean wait)\r
+                throws StandardException\r
+       {\r
+               return getNextHeadPage(handle, ContainerHandle.FIRST_PAGE_NUMBER-1, wait);\r
+       }\r
+\r
+       /**\r
+               Get the next page in the container.\r
+               @exception StandardException Standard Derby error policy\r
+       */\r
+       protected BasePage getNextHeadPage(BaseContainerHandle handle,\r
+        long pageNumber, boolean wait)\r
+                throws StandardException\r
+       {\r
+               long nextNumber;\r
+\r
+               while(true)\r
+               {\r
+                       synchronized(allocCache)\r
+                       {\r
+                               // ask the cache for the next pagenumber\r
+                               nextNumber = allocCache.getNextValidPage(handle, pageNumber, firstAllocPageNumber);\r
+                       }\r
+\r
+                       if (nextNumber == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                               return null;\r
+\r
+                       // optimistically go for the next page\r
+                       BasePage p = getUserPage(handle, nextNumber,\r
+                false /* no overflow page*/, wait);\r
+                       if (p != null)\r
+                               return p;\r
+\r
+                       pageNumber = nextNumber;\r
+               }\r
+       }\r
+\r
+\r
+       private BasePage getInsertablePage(BaseContainerHandle handle,\r
+                                                                          long pageNumber,\r
+                                                                          boolean wait,\r
+                                                                          boolean overflowOK)\r
+                throws StandardException\r
+       {\r
+               if (pageNumber == ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       return null;\r
+\r
+               BasePage p = getUserPage(handle, pageNumber, overflowOK, wait);\r
+               if (p != null)\r
+               {\r
+            // make sure the page is not too full\r
+            if (!p.allowInsert())\r
+            {\r
+                p.unlatch();\r
+                p = null;\r
+\r
+                // it is too full, make sure we are tracking it so we won't\r
+                // see it again.\r
+                allocCache.trackUnfilledPage(pageNumber, false);\r
+            }\r
+               }\r
+        /*\r
+        RESOLVE track 3757\r
+        Need to check if this fix resolves the bug.\r
+        This is commented out because we can't conclude here that this is not\r
+        a user page, it may just be that we failed to get a latch on the page.\r
+        In a high contention scenario this could cause alot of relatively empty\r
+        pages to not be considered for insert.\r
+        TODO\r
+        May be a good idea to move the trackUnfilledPage call below to some of\r
+        the lines in the getUserPage method.\r
+\r
+               else\r
+               {\r
+                       // it is not a user page, make sure we are tracking its fillness so\r
+                       // we won't consider it as a 1/2 filled page ever\r
+                       allocCache.trackUnfilledPage(pageNumber, false);\r
+               }\r
+        */\r
+               return p;\r
+       }\r
+\r
+    /**\r
+     * Get candidate page to move a row for compressing the table.\r
+     * <p>\r
+     * The caller is moving rows from the end of the table toward the beginning,\r
+     * with the goal of freeing up a block of empty pages at the end of the\r
+     * container which can be returned to the OS.\r
+     * <p>\r
+     * On entry pageno will be latched by the caller.  Only return pages with\r
+     * numbers below pageno.  Attempting to return pageno will result in a\r
+     * latch/latch deadlock on the same thread.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+       protected BasePage getPageForCompress(\r
+    BaseContainerHandle handle,\r
+    int                 flag,\r
+    long                pageno)\r
+                throws StandardException\r
+       {\r
+               BasePage p = null;\r
+               boolean getLastInserted = \r
+            (flag & ContainerHandle.GET_PAGE_UNFILLED) == 0;\r
+\r
+               if (getLastInserted)\r
+               {\r
+                       // There is nothing protecting lastInsertePage from being changed\r
+                       // by another thread.  Make a local copy.\r
+                       long localLastInsertedPage = getLastInsertedPage();\r
+\r
+            if ((localLastInsertedPage < pageno) &&\r
+                (localLastInsertedPage != ContainerHandle.INVALID_PAGE_NUMBER))\r
+            {\r
+                // First try getting last inserted page.\r
+\r
+                p = getInsertablePage(\r
+                        handle, \r
+                        localLastInsertedPage,\r
+                        true, /* wait */\r
+                        false /* no overflow page */);\r
+\r
+                // if localLastInsertedPage is not an insertable page, \r
+                // don't waste time getting it again.\r
+                if (p == null)\r
+                {\r
+                    // There is a slight possibility that lastUnfilledPage and\r
+                    // lastInsertedPage will change between the if and the\r
+                    // assignment.  The worse that will happen is we lose the\r
+                    // optimization.  Don't want to slow down allocation by \r
+                    // adding more synchronization.\r
+\r
+                    if (localLastInsertedPage == getLastUnfilledPage())\r
+                        setLastUnfilledPage(\r
+                            ContainerHandle.INVALID_PAGE_NUMBER);\r
+\r
+                    if (localLastInsertedPage == getLastInsertedPage())\r
+                        setLastInsertedPage(\r
+                            ContainerHandle.INVALID_PAGE_NUMBER);\r
+                }\r
+            }\r
+               }\r
+               else                                    \r
+               {\r
+            // get a relatively unfilled page that is not the last Inserted page\r
+\r
+                       long localLastUnfilledPage = getLastUnfilledPage();\r
+\r
+                       if (localLastUnfilledPage == ContainerHandle.INVALID_PAGE_NUMBER ||\r
+                localLastUnfilledPage >= pageno ||\r
+                               localLastUnfilledPage == getLastInsertedPage())\r
+            {\r
+                // get an unfilled page, searching from beginning of container.\r
+                               localLastUnfilledPage = \r
+                    getUnfilledPageNumber(handle, 0);\r
+            }\r
+\r
+                       if ((localLastUnfilledPage != \r
+                    ContainerHandle.INVALID_PAGE_NUMBER) &&\r
+                (localLastUnfilledPage < pageno))\r
+                       {\r
+                               p = getInsertablePage(\r
+                        handle, localLastUnfilledPage, true, false);\r
+                       }\r
+\r
+                       // return this page for insert\r
+                       if (p != null)\r
+                       {\r
+                               setLastUnfilledPage(localLastUnfilledPage);\r
+                               setLastInsertedPage(localLastUnfilledPage);\r
+                       }\r
+               }\r
+\r
+               return p;\r
+    }\r
+\r
+       /**\r
+               Get a potentially suitable page for insert and latch it.\r
+               @exception StandardException Standard Derby error policy\r
+        */\r
+       protected BasePage getPageForInsert(BaseContainerHandle handle,\r
+                                                                               int flag)\r
+                throws StandardException\r
+       {\r
+               BasePage p = null;\r
+               boolean getLastInserted = (flag & ContainerHandle.GET_PAGE_UNFILLED) == 0;\r
+\r
+               if (getLastInserted)\r
+               {\r
+                       // There is nothing protecting lastInsertePage from being changed\r
+                       // by another thread.  Make a local copy.\r
+                       long localLastInsertedPage = getLastInsertedPage();\r
+\r
+                       if (localLastInsertedPage != ContainerHandle.INVALID_PAGE_NUMBER)\r
+            {\r
+                // First try getting last allocated page, NOWAIT\r
+\r
+                               p = getInsertablePage(handle, localLastInsertedPage,\r
+                                                                         false, /* wait */\r
+                                                                         false /* no overflow page */);\r
+\r
+                if (p == null)\r
+                {\r
+                    // most likely we could not get the latch NOWAIT, try again\r
+                    // with a new page, and tell the system to switch to \r
+                    // multi-page mode.\r
+                    /* switchToMultiInsertPageMode(handle); */\r
+\r
+                    localLastInsertedPage = getLastInsertedPage();\r
+\r
+                    p = getInsertablePage(handle, localLastInsertedPage,\r
+                                          true, /* wait */\r
+                                          false /* no overflow page */);\r
+                }\r
+            }\r
+\r
+                       // if lastUnfilledPage is not an insertable page, don't waste time\r
+                       // getting it again.\r
+                       if (p == null)\r
+                       {\r
+                               // There is a slight possibility that lastUnfilledPage and\r
+                               // lastInsertedPage will change between the if and the\r
+                               // assignment.  The worse that will happen is we lose the\r
+                               // optimization.  Don't want to slow down allocation by adding\r
+                               // more synchronization.\r
+\r
+                               if (localLastInsertedPage == getLastUnfilledPage())\r
+                                       setLastUnfilledPage(ContainerHandle.INVALID_PAGE_NUMBER);\r
+\r
+                               if (localLastInsertedPage == getLastInsertedPage())\r
+                                       setLastInsertedPage(ContainerHandle.INVALID_PAGE_NUMBER);\r
+                       }\r
+               }\r
+               else                                    // get a relatively unfilled page that is not\r
+               {                                               // the last Inserted page\r
+                       long localLastUnfilledPage = getLastUnfilledPage();\r
+\r
+                       if (localLastUnfilledPage == ContainerHandle.INVALID_PAGE_NUMBER ||\r
+                               localLastUnfilledPage == getLastInsertedPage())\r
+                               localLastUnfilledPage = getUnfilledPageNumber(handle, localLastUnfilledPage);\r
+\r
+                       if (localLastUnfilledPage != ContainerHandle.INVALID_PAGE_NUMBER)\r
+                       {\r
+                               // try the last unfilled page we found - this could be\r
+                               // different from lastInserted if the last unfilled one we\r
+                               // found does not have enough space for the insert and the\r
+                               // client wants to get a brand new page.\r
+                               p = getInsertablePage(handle, localLastUnfilledPage, true, false);\r
+\r
+                               // try again\r
+                               if (p == null)\r
+                               {\r
+                                       localLastUnfilledPage = getUnfilledPageNumber(handle, localLastUnfilledPage);\r
+                                       if (localLastUnfilledPage != ContainerHandle.INVALID_PAGE_NUMBER)\r
+                                       {\r
+                                               p = getInsertablePage(handle, localLastUnfilledPage, true,\r
+                                                                                         false);\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                       // return this page for insert\r
+                       if (p != null)\r
+                       {\r
+                               setLastUnfilledPage(localLastUnfilledPage);\r
+                               setLastInsertedPage(localLastUnfilledPage);\r
+                       }\r
+               }\r
+\r
+               return p;\r
+\r
+       }\r
+\r
+\r
+       /** \r
+        *  Get a latched page. Incase of backup page Latch is necessary to \r
+        *  prevent modification to the page when it is being written to the backup.\r
+        *  Backup process relies on latches to get consistent snap\r
+        *  shot of the page , user level table/page/row locks are NOT \r
+        *  acquired  by the online backup mechanism.\r
+     *\r
+     *  @param handle the container handle used to latch the page\r
+     *  @param pageNumber the page number of the page to get\r
+     *  @return the latched page\r
+        *      @exception StandardException Standard Derby error policy\r
+        */\r
+       protected BasePage getLatchedPage(BaseContainerHandle handle, \r
+                                        long pageNumber) \r
+               throws StandardException \r
+       {\r
+               PageKey pageKey = new PageKey(identity, pageNumber);\r
+               BasePage page = (BasePage) pageCache.find(pageKey);\r
+                               \r
+               if (SanityManager.DEBUG){\r
+                       SanityManager.ASSERT(page != null, "page is not found :" + pageKey);\r
+               }\r
+               \r
+        // latch the page\r
+        page = latchPage(handle, page, true);\r
+               \r
+               if (SanityManager.DEBUG){\r
+                       SanityManager.ASSERT(page.isLatched(), "page is not latched:" + pageKey);\r
+               }\r
+\r
+               return page;\r
+       }\r
+\r
+       \r
+\r
+       private long getUnfilledPageNumber(BaseContainerHandle handle, long pagenum)\r
+                throws StandardException\r
+       {\r
+               synchronized(allocCache)\r
+               {\r
+                       return allocCache.\r
+                               getUnfilledPageNumber(handle, firstAllocPageNumber, pagenum);\r
+               }\r
+       }               \r
+\r
+       /*\r
+               Cost estimates\r
+       */\r
+       /**\r
+               <BR>MT - this routine is NOT MT-safe and clients don't need to provide\r
+               synchronization.\r
+\r
+               @see ContainerHandle#getEstimatedRowCount\r
+        */\r
+       public long getEstimatedRowCount(int flag)\r
+       {\r
+               return estimatedRowCount;\r
+       }\r
+\r
+       /**\r
+               @see ContainerHandle#setEstimatedRowCount\r
+        */\r
+       public void setEstimatedRowCount(long count, int flag)\r
+       {\r
+               boolean readOnly = dataFactory.isReadOnly();\r
+\r
+               synchronized(this)\r
+               {\r
+                       estimatedRowCount = count;\r
+\r
+                       if (!readOnly)\r
+                               isDirty = true;\r
+               }\r
+       }\r
+\r
+       /**\r
+               Update estimated row count by page as it leaves the cache.\r
+               The estimated row count is updated without logging!\r
+        */\r
+       protected void updateEstimatedRowCount(int delta)\r
+       {\r
+               boolean readOnly = dataFactory.isReadOnly();\r
+\r
+               synchronized(this)\r
+               {\r
+                       estimatedRowCount += delta;\r
+                       if (estimatedRowCount < 0)\r
+                               estimatedRowCount = 0;\r
+\r
+                       // mark the container as dirty without bumping the container\r
+                       // version because row count changes are not logged.\r
+                       if (!readOnly)\r
+                               isDirty = true;\r
+               }\r
+       }\r
+\r
+\r
+       /**\r
+               @see ContainerHandle#getEstimatedPageCount\r
+               @exception StandardException Standard Derby error policy\r
+        */\r
+       public long getEstimatedPageCount(BaseContainerHandle handle, int flag)\r
+                throws StandardException \r
+       {\r
+               // page count is set once per container materialization in cache\r
+\r
+               if (estimatedPageCount < 0)\r
+               {\r
+                       synchronized(allocCache)\r
+                       {\r
+                               estimatedPageCount = \r
+                                       allocCache.getEstimatedPageCount(handle, firstAllocPageNumber);\r
+                       }\r
+               }\r
+\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(estimatedPageCount >= 0,\r
+                                                                "AllocCache returns negatie estimatedPageCount");\r
+\r
+               return estimatedPageCount;\r
+       }\r
+\r
+       /*\r
+       ** Methods used solely by StoredPage\r
+       */\r
+\r
+       /**\r
+               Read a page into the supplied array.\r
+\r
+               <BR> MT - thread safe\r
+               @exception IOException error reading page\r
+               @exception StandardException standard Derby error message\r
+       */\r
+       protected abstract void readPage(long pageNumber, byte[] pageData)\r
+                throws IOException, StandardException;\r
+       \r
+\r
+       /**\r
+               Write a page from the supplied array.\r
+\r
+               <BR> MT - thread safe\r
+               @exception IOException error writing page\r
+               @exception StandardException Standard Derby error policy\r
+       */\r
+       protected abstract void writePage(long pageNumber, byte[] pageData, boolean syncPage) \r
+               throws IOException, StandardException;\r
+\r
+       /*\r
+        * Encryption/decryption\r
+        */\r
+       /**\r
+               Decrypts a page\r
+\r
+               <BR>MT - MT safe.\r
+\r
+               @exception StandardException Standard Derby error policy\r
+        */\r
+       protected void decryptPage(byte[] pageData, int pageSize)\r
+                throws StandardException\r
+       {\r
+               // because all our page header looks identical, the \r
+               // checksum is moved to the front so that it will hopefully\r
+               // encrypt differently from page to page\r
+               synchronized(this)\r
+               {\r
+                       if (encryptionBuffer == null || encryptionBuffer.length < pageSize)\r
+                               encryptionBuffer = new byte[pageSize];\r
+\r
+                       int len = dataFactory.decrypt(pageData, 0, pageSize,\r
+                                                                                 encryptionBuffer, 0);\r
+\r
+            if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(len == pageSize,\r
+                                                                "Encrypted page length != page length");\r
+\r
+                       // put the checksum where it belongs\r
+                       System.arraycopy(encryptionBuffer, 8, pageData, 0, pageSize-8);\r
+                       System.arraycopy(encryptionBuffer, 0, pageData, pageSize-8, 8);\r
+               }\r
+       }\r
+\r
+       /**\r
+               Encrypts a page.\r
+\r
+               <BR> MT - not safe, call within synchronized block and only use the\r
+               returned byte array withing synchronized block. \r
+\r
+               @exception StandardException Standard Derby error policy\r
+        */\r
+       protected byte[] encryptPage(byte[] pageData, \r
+                                 int pageSize, \r
+                                 byte[] encryptionBuffer,\r
+                                 boolean newEngine)\r
+        throws StandardException\r
+       {\r
+               // because all our page header looks identical, move the\r
+               // checksum to the front so that it will hopefully encrypt\r
+               // differently from page to page\r
+\r
+               System.arraycopy(pageData, pageSize-8, encryptionBuffer, 0, 8);\r
+               System.arraycopy(pageData, 0, encryptionBuffer, 8, pageSize-8);\r
+\r
+               int len = dataFactory.encrypt(encryptionBuffer, 0, pageSize,\r
+                                                                         encryptionBuffer, 0, newEngine);\r
+\r
+        if (SanityManager.DEBUG)\r
+               SanityManager.ASSERT(len == pageSize,\r
+                                                        "Encrypted page length != page length");\r
+\r
+               return encryptionBuffer;\r
+       }\r
+\r
+\r
+    /** \r
+     * Get encryption buffer.\r
+     *  MT - not safe, call within synchronized block and only use the\r
+     *  returned byte array withing synchronized block. \r
+     * @return byte array to be used for encryping a page.\r
+     */\r
+    protected byte[] getEncryptionBuffer() {\r
+\r
+        if (encryptionBuffer == null || encryptionBuffer.length < pageSize)\r
+                       encryptionBuffer = new byte[pageSize];\r
+        return encryptionBuffer;\r
+    }\r
+    \r
+    \r
+\r
+       /*\r
+        * page preallocation\r
+        */\r
+\r
+       /**\r
+               preAllocate writes out the preallocated pages to disk if necessary.\r
+\r
+               <BR>Make sure the container is large enough and the\r
+               pages are well formatted.  The only reason to do this is to save some\r
+               I/O during page initialization.  Once the initPage log record is\r
+               written, it is expected that the page really do exist and is well\r
+               formed or recovery will fail.  However, we can gain some performance by\r
+               writing a bunch of pages at a time rather than one at a time.\r
+\r
+               <BR>If it doesn't make sense for the the implementation to have \r
+               pre-allocation, just return 0. \r
+\r
+               <BR>If the container is not being logged, don't actually do anything,\r
+               just return 0.  \r
+\r
+               @return number of successfully preallocated page, or 0 if\r
+                               no page has been preallocated\r
+\r
+               @param lastPreallocPagenum the last preallocated page number as known\r
+                               by the allocation page\r
+               @param preAllocSize try to preallocate this page number of pages.\r
+                               Since only the container knows how many pages are actually on\r
+                               disk, it may determine that certain number of pages that the\r
+                               allocation page thinks need to be preallocated is already\r
+                               allocated, in those case, act as if the preallocation is\r
+                               successful.\r
+       */\r
+       protected abstract int preAllocate(long lastPreallocPagenum, int preAllocSize);\r
+\r
+       /**\r
+               Preallocate the pages - actually doing it, called by subclass only\r
+       */\r
+       protected int doPreAllocatePages(long lastPreallocPagenum,\r
+                                                                        int preAllocSize)\r
+       {\r
+               if (SanityManager.DEBUG)\r
+                       SanityManager.ASSERT(!dataFactory.isReadOnly(), \r
+                                                                "how can we be Preallocating pages in a read only database?");\r
+\r
+               // initialize and a new page in cache\r
+        PageCreationArgs createArgs = new PageCreationArgs(\r
+                StoredPage.FORMAT_NUMBER, // default is a stored page\r
+                CachedPage.WRITE_NO_SYNC, // write it but no sync\r
+                pageSize,\r
+                spareSpace,\r
+                minimumRecordSize,\r
+                0 /* containerInfoSize - unused for StoredPage */);\r
+\r
+               StoredPage page = new StoredPage();\r
+               page.setFactory(dataFactory);\r
+\r
+               boolean error = false;\r
+               int count = 0;\r
+\r
+               while(count < preAllocSize)\r
+               {\r
+                       PageKey pkey = new PageKey(identity, \r
+                                                                          lastPreallocPagenum+count+1);\r
+                       try\r
+                       {\r
+                               // create Identity will do a writePage\r
+                               page.createIdentity(pkey, createArgs);\r
+\r
+                               // if create identity somehow failed to do a write page\r
+                               if (SanityManager.DEBUG)\r
+                                       SanityManager.ASSERT(!page.isDirty(),\r
+                                                                                "create identity failed to do a write page");\r
+\r
+                               page.clearIdentity(); // ready the page for the next loop \r
+\r
+                       }\r
+                       catch (StandardException se)\r
+                       {\r
+                               // if something went wrong, stop and return how many we did\r
+                               // successfully \r
+                               error = true;\r
+                       }\r
+\r
+                       if (error)\r
+                               break;\r
+\r
+                       count++;\r
+               }\r
+\r
+               return count;\r
+       }\r
+\r
+       protected int getPageSize() {\r
+               return pageSize;\r
+       }\r
+       protected int getSpareSpace() {\r
+               return spareSpace;\r
+       }\r
+       protected int getMinimumRecordSize() {\r
+               return minimumRecordSize;\r
+       }\r
+\r
+       private synchronized void switchToMultiInsertPageMode(\r
+    BaseContainerHandle handle)\r
+        throws StandardException\r
+    {\r
+        if (lastInsertedPage.length == 1)\r
+        {\r
+            long last = lastInsertedPage[0];\r
+\r
+            lastInsertedPage = new long[4];\r
+            lastInsertedPage[0] = last;\r
+\r
+            for (int i = 3; i > 0; i--)\r
+            {\r
+                Page page = addPage(handle, false);\r
+                lastInsertedPage[i] = page.getPageNumber();\r
+                page.unlatch();\r
+            }\r
+        }\r
+    }\r
+\r
+       /*\r
+        * Setting and getting lastInserted Page and lastUnfilledPage in a thead\r
+        * safe manner. \r
+        */\r
+       private synchronized long getLastInsertedPage()\r
+       {\r
+        if (lastInsertedPage.length == 1)\r
+        {\r
+            if (SanityManager.DEBUG)\r
+                SanityManager.ASSERT(lastInsertedPage_index == 0);\r
+\r
+            // optimize the usual case where no concurrent insert has kicked us\r
+            // into multi-page mode - ie. only ONE last page.  \r
+            return(lastInsertedPage[0]);\r
+        }\r
+        else\r
+        {\r
+            long ret = lastInsertedPage[lastInsertedPage_index++];\r
+\r
+            if (lastInsertedPage_index > (lastInsertedPage.length - 1))\r
+            {\r
+                lastInsertedPage_index = 0;\r
+            }\r
+\r
+            return(ret);\r
+        }\r
+       }\r
+\r
+       private synchronized long getLastUnfilledPage()\r
+       {\r
+               return lastUnfilledPage;\r
+       }\r
+\r
+       private synchronized void initializeLastInsertedPage(int size)\r
+       {\r
+        lastInsertedPage = new long[size];\r
+\r
+        for (int i = lastInsertedPage.length - 1; i >= 0; i--)\r
+            lastInsertedPage[i] = ContainerHandle.INVALID_PAGE_NUMBER;\r
+\r
+        lastInsertedPage_index = 0;\r
+       }\r
+\r
+       private synchronized void setLastInsertedPage(long val)\r
+       {\r
+               lastInsertedPage[lastInsertedPage_index] = val;\r
+       }\r
+\r
+       private synchronized void setLastUnfilledPage(long val)\r
+       {\r
+               lastUnfilledPage = val;\r
+       }\r
+\r
+\r
+\r
+       /*\r
+       ** Hide our super-classes methods to ensure that cache management\r
+       ** is correct when the container is obtained and release.\r
+       */\r
+\r
+       /**\r
+               The container is kept by the find() in File.openContainer. \r
+       */\r
+       protected void letGo(BaseContainerHandle handle) {\r
+               super.letGo(handle);\r
+\r
+               containerCache.release(this);\r
+       }\r
+\r
+       protected BasePage latchPage(BaseContainerHandle handle, BasePage foundPage, boolean wait)\r
+               throws StandardException {\r
+\r
+               if (foundPage == null)\r
+                       return null;\r
+\r
+               BasePage ret = super.latchPage(handle, foundPage, wait);\r
+               if (ret == null) {\r
+                       // page is still cached\r
+                       pageCache.release((Cacheable) foundPage);\r
+               }\r
+               return ret;\r
+       }\r
+       \r
+\r
+\r
+       /**\r
+     * backup the container.\r
+     * \r
+     * @param handle the container handle.\r
+     * @param backupLocation location of the backup container. \r
+     * @exception StandardException Standard Derby error policy \r
+     */\r
+       protected abstract void backupContainer(BaseContainerHandle handle,     \r
+                                            String backupLocation)\r
+           throws StandardException;\r
+}\r