Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / store / raw / log / LogAccessFile.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/store/raw/log/LogAccessFile.java
new file mode 100644 (file)
index 0000000..ef2cb90
--- /dev/null
@@ -0,0 +1,882 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.store.raw.log.LogAccessFile\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.log;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.io.StorageRandomAccessFile;\r
+\r
+import java.io.IOException;\r
+import java.io.OutputStream;\r
+import java.io.SyncFailedException;\r
+import java.io.InterruptedIOException;\r
+import java.util.LinkedList;\r
+\r
+import org.apache.derby.iapi.services.io.FormatIdOutputStream;\r
+import org.apache.derby.iapi.services.io.ArrayOutputStream;\r
+import org.apache.derby.iapi.store.raw.RawStoreFactory;\r
+\r
+\r
+/**\r
+       Wraps a RandomAccessFile file to provide buffering\r
+       on log writes. Only supports the write calls\r
+       required for the log!\r
+\r
+       MT - unsafe.  Caller of this class must provide synchronization.  The one\r
+       exception is with the log file access, LogAccessFile will touch the log\r
+       only inside synchronized block protected by the semaphore, which is\r
+       defined by the creator of this object.\r
+       \r
+    Write to the log buffers are allowed when there are free buffers even\r
+    when dirty buffers are being written(flushed) to the disk by a different\r
+       thread. Only one flush writes to log file at a time, other wait for it to finish.\r
+\r
+       Except for flushLogAccessFile , SyncAccessLogFile other function callers\r
+       must provide syncronization that will allow only one of them to write to \r
+    the buffers. \r
+\r
+    Log Buffers are used in circular fashion, each buffer moves through following stages: \r
+       freeBuffers --> dirtyBuffers --> freeBuffers. Movement of buffers from one\r
+    stage to   another stage is synchronized using     the object(this) of this class. \r
+\r
+       A Checksum log record that has the checksum value for the data that is\r
+    being written to the disk is generated and written         before the actual data. \r
+       Except for the large log records that does not fit into a single buffer, \r
+    checksum is calcualted for a group of log records that are in the buffer \r
+       when buffers is switched. Checksum log record is written into the reserved\r
+       space in the beginning buffer. \r
+\r
+    In case of a large log record that does not fit into a bufffer, it needs to \r
+    be written directly to the disk instead of going through the log buffers. \r
+    In this case the log record write gets broken into three parts:\r
+        1) Write checksum log record and LOG RECORD HEADER (length + instant) \r
+        2) Write the log record. \r
+        3) Write the trailing length of the log record. \r
+\r
+       Checksum log records helps in identifying the incomplete log disk writes during \r
+    recovery. This is done by recalculating the checksum value for the data on\r
+    the disk and comparing it to the the value stored in the checksum log\r
+    record. \r
+\r
+*/\r
+public class LogAccessFile \r
+{\r
+\r
+    /**\r
+     * The fixed size of a log record is 16 bytes:\r
+     *     int   length             : 4 bytes\r
+     *     long  instant            : 8 bytes\r
+     *     int   trailing length    : 4 bytes\r
+     **/\r
+    private static final int            LOG_RECORD_FIXED_OVERHEAD_SIZE = 16;\r
+       private static final int            LOG_RECORD_HEADER_SIZE = 12; //(length + instant)\r
+       private static final int            LOG_RECORD_TRAILER_SIZE = 4; //trailing length \r
+    private static final int            LOG_NUMBER_LOG_BUFFERS = 3;\r
+\r
+\r
+       private LinkedList    freeBuffers;  //list of free buffers\r
+       private LinkedList    dirtyBuffers; //list of dirty buffers to flush\r
+       private  LogAccessFileBuffer currentBuffer; //current active buffer\r
+       private boolean flushInProgress = false;\r
+       \r
+       private final StorageRandomAccessFile  log;\r
+\r
+       // log can be touched only inside synchronized block protected by\r
+       // logFileSemaphore.\r
+       private final Object            logFileSemaphore;\r
+\r
+       static int                      mon_numWritesToLog;\r
+       static int                      mon_numBytesToLog;\r
+\r
+\r
+       //streams used to generated check sume log record ; see if there is any simpler way\r
+       private ArrayOutputStream logOutputBuffer;\r
+       private FormatIdOutputStream logicalOut;\r
+       private boolean directWrite = false; //true when log is written directly to file.\r
+       private long checksumInstant = -1;\r
+       private int checksumLength;\r
+       private int checksumLogRecordSize;      //checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE\r
+       private boolean writeChecksum; \r
+       private ChecksumOperation checksumLogOperation;\r
+       private LogRecord checksumLogRecord;\r
+       private LogToFile logFactory;\r
+       private boolean databaseEncrypted=false;\r
+               \r
+       public LogAccessFile(LogToFile logFactory,\r
+                                                StorageRandomAccessFile    log, \r
+                                                int                 bufferSize) \r
+    {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       if(SanityManager.DEBUG_ON("LogBufferOff"))\r
+                               bufferSize = 10;        // make it very tiny\r
+               }\r
+               \r
+               this.log            = log;\r
+               logFileSemaphore    = log;\r
+               this.logFactory     = logFactory;\r
+\r
+               if (SanityManager.DEBUG)\r
+            SanityManager.ASSERT(LOG_NUMBER_LOG_BUFFERS >= 1);\r
+                               \r
+               //initialize buffers lists\r
+               freeBuffers = new LinkedList();\r
+               dirtyBuffers = new LinkedList();\r
+\r
+\r
+               //add all buffers to free list\r
+        for (int i = 0; i < LOG_NUMBER_LOG_BUFFERS; i++)\r
+        {\r
+            LogAccessFileBuffer b = new LogAccessFileBuffer(bufferSize);\r
+            freeBuffers.addLast(b);\r
+        }\r
+\r
+               currentBuffer = (LogAccessFileBuffer) freeBuffers.removeFirst();\r
+               \r
+               // Support for Transaction Log Checksum in Derby was added in 10.1\r
+               // Check to see if the Store have been upgraded to 10.1 or later before\r
+               // writing the checksum log records.  Otherwise recovery will fail\r
+               // incase user tries to revert back to versions before 10.1 in \r
+               // soft upgrade mode. \r
+               writeChecksum = logFactory.checkVersion(RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10, \r
+                                                                                               RawStoreFactory.DERBY_STORE_MINOR_VERSION_1);\r
+               if(writeChecksum)\r
+               {\r
+                       /**\r
+                        * setup structures that are required to write the checksum log records\r
+                        * for a group of log records are being written to the disk. \r
+                        */\r
+                       checksumLogOperation = new ChecksumOperation();\r
+                       checksumLogOperation.init();\r
+                       checksumLogRecord = new LogRecord();\r
+\r
+                       // Note: Checksum log records are not related any particular transaction, \r
+                       // they are written to store a checksum information identify\r
+                       // incomplete log record writes. No transacton id is set for this\r
+                       // log record. That is why a null argument is passed below \r
+                       // setValue(..) call. \r
+                       checksumLogRecord.setValue(null, checksumLogOperation);\r
+\r
+                       checksumLength = \r
+                               checksumLogRecord.getStoredSize(checksumLogOperation.group(), null) + \r
+                               checksumLogOperation.getStoredSize();\r
+\r
+                       // calculate checksum log operation length when the database is encrypted\r
+                       if (logFactory.databaseEncrypted())\r
+                       {\r
+                               checksumLength =  logFactory.getEncryptedDataLength(checksumLength);\r
+                               databaseEncrypted = true;\r
+                       }\r
+                       checksumLogRecordSize = checksumLength  + LOG_RECORD_FIXED_OVERHEAD_SIZE;\r
+\r
+                       //streams required to convert a log record to raw byte array. \r
+                       logOutputBuffer = new ArrayOutputStream(); \r
+                       logicalOut = new FormatIdOutputStream(logOutputBuffer);\r
+\r
+                       /** initialize the buffer with space reserved for checksum log record in\r
+                        * the beginning of the log buffer; checksum record is written into\r
+                        * this space when buffer is switched or while doing direct write to the log file.\r
+                        */\r
+               }else\r
+               {\r
+                       //checksumming of transaction log feature is not in use. \r
+                       checksumLogRecordSize = 0;\r
+               }\r
+               \r
+               currentBuffer.init(checksumLogRecordSize);\r
+       }\r
+\r
+\r
+       private byte[] db = new byte[LOG_RECORD_TRAILER_SIZE]; \r
+\r
+\r
+    /**\r
+     * Write a single log record to the stream.\r
+     * <p>\r
+     * For performance pass all parameters rather into a specialized routine\r
+     * rather than maintaining the writeInt, writeLong, and write interfaces\r
+     * that this class provides as a standard OutputStream.  It will make it\r
+     * harder to use other OutputStream implementations, but makes for less\r
+     * function calls and allows optimizations knowing when to switch buffers.\r
+     * <p>\r
+     * This routine handles all log records which are smaller than one log\r
+     * buffer.  If a log record is bigger than a log buffer it calls\r
+     * writeUnbufferedLogRecord().\r
+     * <p>\r
+     * The log record written will always look the same as if the following\r
+     * code had been executed:\r
+     *     writeInt(length)\r
+     *     writeLong(instant)\r
+     *     write(data, data_offset, (length - optional_data_length) )\r
+     *\r
+     *     if (optional_data_length != 0)\r
+     *         write(optional_data, optional_data_offset, optional_data_length)\r
+     *\r
+     *     writeInt(length)\r
+     *\r
+     * @param length                (data + optional_data) length bytes to write\r
+     * @param instant               the log address of this log record.\r
+     * @param data                  "from" array to copy "data" portion of rec\r
+     * @param data_offset           offset in "data" to start copying from.\r
+     * @param optional_data         "from" array to copy "optional data" from\r
+     * @param optional_data_offset  offset in "optional_data" to start copy from\r
+     * @param optional_data_length  length of optional data to copy.\r
+     *\r
+        * @exception  StandardException  Standard exception policy.\r
+     **/\r
+    public void writeLogRecord(\r
+    int     length,\r
+    long    instant,\r
+    byte[]  data,\r
+    int     data_offset,\r
+    byte[]  optional_data,\r
+    int     optional_data_offset,\r
+    int     optional_data_length)\r
+        throws StandardException, IOException \r
+    {\r
+        int total_log_record_length = length + LOG_RECORD_FIXED_OVERHEAD_SIZE;\r
+\r
+               if (total_log_record_length <= currentBuffer.bytes_free)\r
+        {\r
+            byte[] b    = currentBuffer.buffer;\r
+            int    p    = currentBuffer.position;\r
+\r
+            // writeInt(length)\r
+                       p = writeInt(length, b, p);\r
+            \r
+            // writeLong(instant)\r
+                       p = writeLong(instant, b , p);\r
+\r
+            // write(data, data_offset, length - optional_data_length)\r
+            int transfer_length = (length - optional_data_length);\r
+                       System.arraycopy(data, data_offset, b, p, transfer_length);\r
+\r
+            p += transfer_length;\r
+\r
+            if (optional_data_length != 0)\r
+            {\r
+                // write(\r
+                //   optional_data, optional_data_offset, optional_data_length);\r
+\r
+                System.arraycopy(\r
+                    optional_data, optional_data_offset, \r
+                    b,             p, \r
+                    optional_data_length);\r
+\r
+                p += optional_data_length;\r
+            }\r
+\r
+            // writeInt(length)\r
+                       p = writeInt(length, b, p);\r
+            \r
+                       currentBuffer.position   = p;\r
+            currentBuffer.bytes_free -= total_log_record_length;\r
+               }\r
+        else\r
+        {\r
+                       \r
+                       /** Because current log record will never fit in a single buffer\r
+                        * a direct write to the log file is required instead of \r
+                        * writing the log record through  the log bufffers. \r
+                        */\r
+                       directWrite = true;\r
+\r
+                       byte[] b    = currentBuffer.buffer;\r
+            int    p    = currentBuffer.position;\r
+\r
+            // writeInt(length)\r
+                       p = writeInt(length , b, p);\r
+            \r
+            // writeLong(instant)\r
+                       p = writeLong(instant, b, p);\r
+\r
+                       currentBuffer.position   = p;\r
+                       currentBuffer.bytes_free -= LOG_RECORD_HEADER_SIZE;\r
+\r
+                       /** using a seperate small buffer to write the traling length\r
+                        * instead of the log buffer because data portion will be \r
+                        * written directly to log file after the log buffer is \r
+                        * flushed and the trailing length should be written after that. \r
+                        */\r
+\r
+                       // writeInt(length)\r
+                       writeInt(length , db, 0);\r
+\r
+                       if(writeChecksum)\r
+                       {\r
+                               checksumLogOperation.reset();\r
+                               checksumLogOperation.update(b, checksumLogRecordSize, p - checksumLogRecordSize);\r
+                               checksumLogOperation.update(data, data_offset, length - optional_data_length);\r
+                               if (optional_data_length != 0)\r
+                               {\r
+                                       checksumLogOperation.update(optional_data, optional_data_offset, optional_data_length); \r
+                               }\r
+\r
+                               // update the checksum to include the trailing length.\r
+                               checksumLogOperation.update(db, 0, LOG_RECORD_TRAILER_SIZE);\r
+                       \r
+                               // write checksum log record to the log buffer \r
+                               writeChecksumLogRecord();\r
+                       }\r
+                       \r
+                       \r
+                       // now do the  writes directly to the log file. \r
+\r
+                       // flush all buffers before wrting directly to the log file. \r
+                       flushLogAccessFile();\r
+\r
+                       // Note:No Special Synchronization required here , \r
+                       // There will be nothing to write by flushDirtyBuffers that can run\r
+                       // in parallel to the threads that is executing this code. Above\r
+                       // flush call should have written all the buffers and NO new log will \r
+                       // get added until the following direct log to file call finishes. \r
+\r
+\r
+                       // write the rest of the log directltly to the log file. \r
+            writeToLog(data, data_offset, length - optional_data_length);\r
+            if (optional_data_length != 0)\r
+            {\r
+                writeToLog(\r
+                    optional_data, optional_data_offset, optional_data_length);\r
+            }\r
+\r
+                       // write the trailing length \r
+                       writeToLog(db,0, 4);\r
+                       directWrite = false;\r
+               }\r
+    }\r
+\r
+\r
+\r
+       private final int writeInt(int i , byte b[], int p)\r
+       {\r
+       \r
+        b[p++] = (byte) ((i >>> 24) & 0xff); \r
+        b[p++] = (byte) ((i >>> 16) & 0xff); \r
+        b[p++] = (byte) ((i >>> 8) & 0xff); \r
+        b[p++] = (byte) (i & 0xff);    \r
+               return p;\r
+       }\r
+\r
+\r
+       private final int writeLong(long l , byte b[], int p)\r
+       {\r
+               b[p++] = (byte) (((int)(l >>> 56)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 48)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 40)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 32)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 24)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 16)) & 0xff); \r
+        b[p++] = (byte) (((int)(l >>> 8)) & 0xff); \r
+        b[p++] = (byte) (((int)l) & 0xff); \r
+               return p;\r
+       }\r
+\r
+       public void writeInt(int i) \r
+    {\r
+\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(currentBuffer.bytes_free >= 4);\r
+               }\r
+               \r
+               currentBuffer.position = \r
+                       writeInt(i , currentBuffer.buffer, currentBuffer.position);\r
+               currentBuffer.bytes_free -= 4;\r
+       }\r
+\r
+       public void writeLong(long l) \r
+    {\r
+               \r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(currentBuffer.bytes_free >= 8);\r
+               }\r
+               \r
+               currentBuffer.position = \r
+                       writeLong(l , currentBuffer.buffer, currentBuffer.position);\r
+               currentBuffer.bytes_free -= 8;\r
+    }\r
+\r
+       public void write(int b) \r
+    {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(currentBuffer.bytes_free > 0);\r
+               }\r
+               \r
+               currentBuffer.buffer[currentBuffer.position++] = (byte) b;\r
+               currentBuffer.bytes_free--;\r
+       }\r
+\r
+\r
+       public void write(byte b[], int off, int len) \r
+    {\r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(len <= currentBuffer.bytes_free);\r
+               }\r
+               \r
+               System.arraycopy(b, off, currentBuffer.buffer, currentBuffer.position, len);\r
+               currentBuffer.bytes_free -= len;\r
+               currentBuffer.position += len;\r
+       }\r
+\r
+\r
+    /**\r
+     * Write data from all dirty buffers into the log file.\r
+     * <p>\r
+     * A call for clients of LogAccessFile to insure that all privately buffered\r
+     * data has been writen to the file - so that reads on the file using one\r
+     * of the various scan classes will see\r
+     * all the data which has been writen to this point.\r
+     * <p>\r
+     * Note that this routine only "writes" the data to the file, this does not\r
+     * mean that the data has been synced to disk unless file was opened in\r
+        * WRITE SYNC mode(rws/rwd).  The only way to insure that is by calling\r
+     * is to call syncLogAccessFile() after this call in Non-WRITE sync mode(rw)\r
+        * \r
+        * <p>\r
+        * MT-Safe : parallel thereads can call this function, only one threads does\r
+        * the flush and the other threads waits for the one that is doing the flush to finish.\r
+        * Currently there are two possible threads that can call this function in parallel \r
+        * 1) A Thread that is doing the commit\r
+        * 2) A Thread that is writing to the log and log buffers are full or\r
+        * a log records does not fit in a buffer. (Log Buffers\r
+        * full(switchLogBuffer() or a log record size that is greater than\r
+        * logbuffer size has to be writtern through writeToLog call directlty)\r
+        * Note: writeToLog() is not synchronized on the semaphore\r
+        * that is used to do  buffer management to allow writes \r
+        * to the free buffers when flush is in progress.  \r
+     **/\r
+       protected void flushDirtyBuffers() throws IOException \r
+    {\r
+        LogAccessFileBuffer buf = null;\r
+               int noOfBuffers;\r
+               int nFlushed= 0;\r
+               try{\r
+                       synchronized(this)\r
+                       {\r
+                               /**if some one else flushing wait, otherwise it is possible \r
+                                * different threads will get different buffers and order can \r
+                                * not be determined.\r
+                                * \r
+                                **/\r
+                               while(flushInProgress)\r
+                               {\r
+                                       try{\r
+                                               wait();\r
+                                       }catch (InterruptedException ie) \r
+                                       {\r
+                                               //do nothing, let the flush request to complete.\r
+                                               //because it possible that other thread which is\r
+                                               //currently might have completed this request also ,\r
+                                               //if exited  on interrupt and throw exception, can not\r
+                                               //be sure whether this transaction is COMMITTED ot not.\r
+                                       }\r
+                               }\r
+               \r
+                               noOfBuffers = dirtyBuffers.size();\r
+                               if(noOfBuffers > 0)\r
+                                       buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();\r
+                               \r
+                               flushInProgress = true;\r
+                       }\r
+                       \r
+                       while(nFlushed < noOfBuffers)\r
+                       {\r
+                               if (buf.position != 0)\r
+                                       writeToLog(buf.buffer, 0, buf.position);\r
+\r
+                               nFlushed++;\r
+                               synchronized(this)\r
+                               {\r
+                                       //add the buffer that was written previosly to the free list\r
+                                       freeBuffers.addLast(buf);\r
+                                       if(nFlushed < noOfBuffers)\r
+                                               buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();\r
+                                       else\r
+                                       {\r
+                                               //see if we can flush more, that came when we are at it.\r
+                                               //don't flush more than the total number of buffers,\r
+                                               //that might lead to starvation of the current thread.\r
+                                               int size = dirtyBuffers.size();\r
+                                               if(size > 0 && nFlushed <= LOG_NUMBER_LOG_BUFFERS)\r
+                                               {\r
+                                                       noOfBuffers += size;\r
+                                                       buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();\r
+                                               }\r
+                                       }\r
+                               }\r
+                       }\r
+\r
+                               \r
+               }finally{\r
+                       synchronized(this)\r
+                       {\r
+                               flushInProgress = false;\r
+                               notifyAll();\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+       //flush all the the dirty buffers to disk\r
+       public void flushLogAccessFile() throws IOException,  StandardException \r
+       {\r
+               switchLogBuffer();\r
+               flushDirtyBuffers();\r
+       }\r
+\r
+               \r
+       /**\r
+        * Appends the current Buffer to the dirty Buffer list and assigns a free\r
+        * buffer to be the currrent active buffer . Flushing of the buffer\r
+        * to disk is delayed if there is a free buffer available. \r
+        * dirty buffers will be  flushed to the disk   \r
+        * when  flushDirtyBuffers() is invoked by  a commit call \r
+        * or when no more free buffers are available. \r
+        */\r
+       public void switchLogBuffer() throws IOException, StandardException  \r
+    {\r
+\r
+               synchronized(this)\r
+               {\r
+                       // ignore empty buffer switch requests\r
+                       if(currentBuffer.position == checksumLogRecordSize)\r
+                               return;\r
+\r
+                       // calculate the checksum for the current log buffer \r
+                       // and write the record to the space reserverd in \r
+                       // the beginning of the buffer. \r
+                       if(writeChecksum && !directWrite)\r
+                       {\r
+                               checksumLogOperation.reset();\r
+                               checksumLogOperation.update(currentBuffer.buffer, checksumLogRecordSize, currentBuffer.position - checksumLogRecordSize);\r
+                               writeChecksumLogRecord();\r
+                       }\r
+\r
+                       //add the current buffer to the flush buffer list\r
+                       dirtyBuffers.addLast(currentBuffer);\r
+\r
+                       //if there is No free buffer, flush the buffers to get a free one \r
+                       if(freeBuffers.size() == 0) \r
+                       {\r
+                               flushDirtyBuffers();\r
+                               //after the flush call there should be a free buffer\r
+                               //because this is only methods removes items from \r
+                               //free buffers and removal is in synchronized block. \r
+                       }\r
+\r
+\r
+                       // there should be free buffer available at this point.\r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.ASSERT(freeBuffers.size() > 0);\r
+\r
+                       //switch over to the next log buffer, let someone else write it.\r
+                       currentBuffer = (LogAccessFileBuffer) freeBuffers.removeFirst();\r
+                       currentBuffer.init(checksumLogRecordSize);\r
+\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               SanityManager.ASSERT(currentBuffer.position == checksumLogRecordSize);\r
+                               SanityManager.ASSERT(\r
+                                                                        currentBuffer.bytes_free == currentBuffer.length);\r
+                SanityManager.ASSERT(currentBuffer.bytes_free > 0);\r
+                       }\r
+               }\r
+       }\r
+\r
+\r
+    /**\r
+     * Guarantee all writes up to the last call to flushLogAccessFile on disk.\r
+     * <p>\r
+     * A call for clients of LogAccessFile to insure that all data written\r
+     * up to the last call to flushLogAccessFile() are written to disk.\r
+     * This call will not return until those writes have hit disk.\r
+     * <p>\r
+     * Note that this routine may block waiting for I/O to complete so \r
+     * callers should limit the number of resource held locked while this\r
+     * operation is called.  It is expected that the caller\r
+     * Note that this routine only "writes" the data to the file, this does not\r
+     * mean that the data has been synced to disk.  The only way to insure that\r
+     * is to first call switchLogBuffer() and then follow by a call of sync().\r
+     *\r
+     **/\r
+    public void syncLogAccessFile() \r
+        throws IOException, StandardException\r
+    {\r
+        for( int i=0; ; )\r
+        {\r
+            // 3311: JVM sync call sometimes fails under high load against NFS \r
+            // mounted disk.  We re-try to do this 20 times.\r
+            try\r
+            {\r
+                synchronized( this)\r
+                {\r
+                    log.sync( false);\r
+                }\r
+\r
+                // the sync succeed, so return\r
+                break;\r
+            }\r
+            catch( SyncFailedException sfe )\r
+            {\r
+                i++;\r
+                try\r
+                {\r
+                    // wait for .2 of a second, hopefully I/O is done by now\r
+                    // we wait a max of 4 seconds before we give up\r
+                    Thread.sleep( 200 ); \r
+                }\r
+                catch( InterruptedException ie )\r
+                {   //does not matter weather I get interrupted or not\r
+                }\r
+\r
+                if( i > 20 )\r
+                    throw StandardException.newException(\r
+                        SQLState.LOG_FULL, sfe);\r
+            }\r
+        }\r
+    }\r
+\r
+       /**\r
+               The database is being marked corrupted, get rid of file pointer without\r
+               writing out anything more.\r
+        */\r
+       public void corrupt() throws IOException\r
+       {\r
+               synchronized(logFileSemaphore)\r
+               {\r
+                       if (log != null)\r
+                               log.close();\r
+               }\r
+       }\r
+\r
+       public void close() throws IOException, StandardException\r
+    {\r
+               if (SanityManager.DEBUG) \r
+        {\r
+                       if (currentBuffer.position !=  checksumLogRecordSize)\r
+                               SanityManager.THROWASSERT(\r
+                               "Log file being closed with data still buffered " + \r
+                currentBuffer.position +  " " + currentBuffer.bytes_free);\r
+               }\r
+\r
+               flushLogAccessFile();\r
+\r
+               synchronized(logFileSemaphore)\r
+               {\r
+                       if (log != null)\r
+                               log.close();\r
+               }\r
+       }\r
+\r
+\r
+       /* write to the log file */\r
+       private void writeToLog(byte b[], int off, int len) throws IOException\r
+       {\r
+               synchronized(logFileSemaphore)\r
+               {\r
+            if (log != null)\r
+            {\r
+\r
+                // Try to handle case where user application is throwing\r
+                // random interrupts at Derby threads, retry in the case\r
+                // of IO exceptions 5 times.  After that hope that it is \r
+                // a real disk problem - an IO error in a write to the log file\r
+                // is going to take down the whole system, so seems worthwhile\r
+                // to retry.\r
+                for (int i = 0; ;i++)\r
+                {\r
+                    try \r
+                    {\r
+                        log.write(b, off, len);\r
+                        break;\r
+                    }\r
+                    catch (IOException ioe)\r
+                    {\r
+                        // just fall through and rety the log write 1st 5 times.\r
+\r
+                        if (i >= 5)\r
+                            throw ioe;\r
+                    }\r
+                }\r
+            }\r
+               }\r
+\r
+               if (SanityManager.DEBUG) \r
+        {\r
+                       mon_numWritesToLog++;\r
+                       mon_numBytesToLog += len;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * reserve the space for the checksum log record in the log file. \r
+     *\r
+        * @param  length           the length of the log record to be written\r
+        * @param  logFileNumber    current log file number \r
+        * @param  currentPosition  current position in the log file. \r
+     *\r
+        * @return the space that is needed to write a checksum log record.\r
+        */\r
+       protected long reserveSpaceForChecksum(int length, long logFileNumber, long currentPosition )\r
+               throws StandardException, IOException \r
+       {\r
+\r
+               int total_log_record_length = length + LOG_RECORD_FIXED_OVERHEAD_SIZE;\r
+               boolean reserveChecksumSpace = false;\r
+               \r
+               /* checksum log record is calculated for a group of log \r
+                * records that can fit in to a single buffer or for \r
+                * a single record when it does not fit into \r
+                * a fit into a buffer at all. When a new buffer \r
+                * is required to write a log record, log space \r
+                * has to be reserved before writing the log record\r
+                * becuase checksum is written in the before the \r
+                * log records that are being checksummed. \r
+                * What it also means is a real log instant has to be \r
+                * reserved for writing the checksum log record in addition \r
+                * to the log buffer space.\r
+                */\r
+               \r
+\r
+               /* reserve checkum space for new log records if a log buffer switch had\r
+                * happened before because of a explicit log flush requests(like commit)\r
+                * or a long record write \r
+                */\r
+               if(currentBuffer.position == checksumLogRecordSize)\r
+               {\r
+                       // reserver space if log checksum feature is enabled.\r
+                       reserveChecksumSpace = writeChecksum;\r
+               }\r
+               else{\r
+                       if (total_log_record_length > currentBuffer.bytes_free)\r
+                       {\r
+                               // the log record that is going to be written is not \r
+                               // going to fit in the current buffer, switch the \r
+                               // log buffer to create buffer space for it. \r
+                               switchLogBuffer();\r
+                               // reserve space if log checksum feature is enabled. \r
+                               reserveChecksumSpace = writeChecksum;\r
+                       }\r
+               }\r
+               \r
+               if(reserveChecksumSpace)\r
+               {\r
+                       if (SanityManager.DEBUG)\r
+                       {\r
+                               // Prevoiusly reserved real checksum instant should have been\r
+                               // used, before an another one is generated. \r
+                               SanityManager.ASSERT(checksumInstant == -1,  "CHECKSUM INSTANT IS GETTING OVER WRITTEN");\r
+                       }\r
+                       \r
+                       checksumInstant = LogCounter.makeLogInstantAsLong(logFileNumber, currentPosition);\r
+                       return  checksumLogRecordSize;\r
+               }else\r
+               {\r
+                       return 0 ;\r
+               }\r
+       }\r
+\r
+\r
+       /*\r
+        * generate the checkum log record and write it into the log buffer.\r
+        */\r
+       private void writeChecksumLogRecord() throws IOException, StandardException\r
+       {\r
+               \r
+               byte[] b    = currentBuffer.buffer;\r
+               int    p    = 0; //checksum is written in the beginning of the buffer\r
+\r
+               // writeInt(length)\r
+               p = writeInt(checksumLength, b , p);\r
+            \r
+               // writeLong(instant)\r
+               p = writeLong(checksumInstant, b , p);\r
+\r
+               //write the checksum log operation  \r
+               logOutputBuffer.setData(b);\r
+               logOutputBuffer.setPosition(p);\r
+               logicalOut.writeObject(checksumLogRecord);\r
+\r
+               if(databaseEncrypted)\r
+               {\r
+                       //encrypt the checksum log operation part.\r
+                       int len = \r
+                               logFactory.encrypt(b, LOG_RECORD_HEADER_SIZE, checksumLength, \r
+                                                                  b, LOG_RECORD_HEADER_SIZE);\r
+                       \r
+                  \r
+                       if (SanityManager.DEBUG)\r
+                               SanityManager.ASSERT(len == checksumLength, \r
+                                                                        "encrypted log buffer length != log buffer len");\r
+               }\r
+\r
+               p = LOG_RECORD_HEADER_SIZE + checksumLength ;\r
+\r
+               // writeInt(length) trailing\r
+               p = writeInt(checksumLength, b, p );\r
+               \r
+               if (SanityManager.DEBUG)\r
+               {\r
+                       SanityManager.ASSERT(p == checksumLogRecordSize, "position=" + p  + "ckrecordsize=" + checksumLogRecordSize);\r
+                       if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))\r
+                       {\r
+                               SanityManager.DEBUG(\r
+                                                                       LogToFile.DBG_FLAG, \r
+                                                                       "Write log record: tranId=Null"  +\r
+                                                                       " instant: " + LogCounter.toDebugString(checksumInstant) + " length: " +\r
+                                                                       checksumLength + "\n" + checksumLogOperation + "\n");\r
+                       }\r
+                       checksumInstant = -1; \r
+               }\r
+\r
+       }\r
+\r
+\r
+       protected void writeEndMarker(int marker) throws IOException, StandardException \r
+       {\r
+               //flush all the buffers and then write the end marker.\r
+               flushLogAccessFile();\r
+               \r
+               byte[] b    = currentBuffer.buffer;\r
+               int    p    = 0; //end is written in the beginning of the buffer, no\r
+                                                //need to checksum a int write.\r
+               p = writeInt(marker , b , p);\r
+               writeToLog(b, 0, p);\r
+       }\r
+\r
+       \r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r