KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > log > LogAccessFile


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.log.LogAccessFile
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.raw.log;
23
24 import org.apache.derby.iapi.reference.SQLState;
25
26 import org.apache.derby.iapi.services.sanity.SanityManager;
27 import org.apache.derby.iapi.error.StandardException;
28
29 import org.apache.derby.io.StorageRandomAccessFile;
30
31 import java.io.IOException JavaDoc;
32 import java.io.OutputStream JavaDoc;
33 import java.io.SyncFailedException JavaDoc;
34 import java.io.InterruptedIOException JavaDoc;
35 import java.util.LinkedList JavaDoc;
36
37 import org.apache.derby.iapi.services.io.FormatIdOutputStream;
38 import org.apache.derby.iapi.services.io.ArrayOutputStream;
39 import org.apache.derby.iapi.store.raw.RawStoreFactory;
40
41
42 /**
43     Wraps a RandomAccessFile file to provide buffering
44     on log writes. Only supports the write calls
45     required for the log!
46
47     MT - unsafe. Caller of this class must provide synchronization. The one
48     exception is with the log file access, LogAccessFile will touch the log
49     only inside synchronized block protected by the semaphore, which is
50     defined by the creator of this object.
51     
52     Write to the log buffers are allowed when there are free buffers even
53     when dirty buffers are being written(flushed) to the disk by a different
54     thread. Only one flush writes to log file at a time, other wait for it to finish.
55
56     Except for flushLogAccessFile , SyncAccessLogFile other function callers
57     must provide syncronization that will allow only one of them to write to
58     the buffers.
59
60     Log Buffers are used in circular fashion, each buffer moves through following stages:
61     freeBuffers --> dirtyBuffers --> freeBuffers. Movement of buffers from one
62     stage to another stage is synchronized using the object(this) of this class.
63
64     A Checksum log record that has the checksum value for the data that is
65     being written to the disk is generated and written before the actual data.
66     Except for the large log records that does not fit into a single buffer,
67     checksum is calcualted for a group of log records that are in the buffer
68     when buffers is switched. Checksum log record is written into the reserved
69     space in the beginning buffer.
70
71     In case of a large log record that does not fit into a bufffer, it needs to
72     be written directly to the disk instead of going through the log buffers.
73     In this case the log record write gets broken into three parts:
74         1) Write checksum log record and LOG RECORD HEADER (length + instant)
75         2) Write the log record.
76         3) Write the trailing length of the log record.
77
78     Checksum log records helps in identifying the incomplete log disk writes during
79     recovery. This is done by recalculating the checksum value for the data on
80     the disk and comparing it to the the value stored in the checksum log
81     record.
82
83 */

84 public class LogAccessFile
85 {
86
87     /**
88      * The fixed size of a log record is 16 bytes:
89      * int length : 4 bytes
90      * long instant : 8 bytes
91      * int trailing length : 4 bytes
92      **/

93     private static final int LOG_RECORD_FIXED_OVERHEAD_SIZE = 16;
94     private static final int LOG_RECORD_HEADER_SIZE = 12; //(length + instant)
95
private static final int LOG_RECORD_TRAILER_SIZE = 4; //trailing length
96
private static final int LOG_NUMBER_LOG_BUFFERS = 3;
97
98
99     private LinkedList JavaDoc freeBuffers; //list of free buffers
100
private LinkedList JavaDoc dirtyBuffers; //list of dirty buffers to flush
101
private LogAccessFileBuffer currentBuffer; //current active buffer
102
private boolean flushInProgress = false;
103     
104     private final StorageRandomAccessFile log;
105
106     // log can be touched only inside synchronized block protected by
107
// logFileSemaphore.
108
private final Object JavaDoc logFileSemaphore;
109
110     static int mon_numWritesToLog;
111     static int mon_numBytesToLog;
112
113
114     //streams used to generated check sume log record ; see if there is any simpler way
115
private ArrayOutputStream logOutputBuffer;
116     private FormatIdOutputStream logicalOut;
117     private boolean directWrite = false; //true when log is written directly to file.
118
private long checksumInstant = -1;
119     private int checksumLength;
120     private int checksumLogRecordSize; //checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE
121
private boolean writeChecksum;
122     private ChecksumOperation checksumLogOperation;
123     private LogRecord checksumLogRecord;
124     private LogToFile logFactory;
125     private boolean databaseEncrypted=false;
126         
127     public LogAccessFile(LogToFile logFactory,
128                          StorageRandomAccessFile log,
129                          int bufferSize)
130     {
131         if (SanityManager.DEBUG)
132         {
133             if(SanityManager.DEBUG_ON("LogBufferOff"))
134                 bufferSize = 10; // make it very tiny
135
}
136         
137         this.log = log;
138         logFileSemaphore = log;
139         this.logFactory = logFactory;
140
141         if (SanityManager.DEBUG)
142             SanityManager.ASSERT(LOG_NUMBER_LOG_BUFFERS >= 1);
143                 
144         //initialize buffers lists
145
freeBuffers = new LinkedList JavaDoc();
146         dirtyBuffers = new LinkedList JavaDoc();
147
148
149         //add all buffers to free list
150
for (int i = 0; i < LOG_NUMBER_LOG_BUFFERS; i++)
151         {
152             LogAccessFileBuffer b = new LogAccessFileBuffer(bufferSize);
153             freeBuffers.addLast(b);
154         }
155
156         currentBuffer = (LogAccessFileBuffer) freeBuffers.removeFirst();
157         
158         // Support for Transaction Log Checksum in Derby was added in 10.1
159
// Check to see if the Store have been upgraded to 10.1 or later before
160
// writing the checksum log records. Otherwise recovery will fail
161
// incase user tries to revert back to versions before 10.1 in
162
// soft upgrade mode.
163
writeChecksum = logFactory.checkVersion(RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10,
164                                                 RawStoreFactory.DERBY_STORE_MINOR_VERSION_1);
165         if(writeChecksum)
166         {
167             /**
168              * setup structures that are required to write the checksum log records
169              * for a group of log records are being written to the disk.
170              */

171             checksumLogOperation = new ChecksumOperation();
172             checksumLogOperation.init();
173             checksumLogRecord = new LogRecord();
174
175             // Note: Checksum log records are not related any particular transaction,
176
// they are written to store a checksum information identify
177
// incomplete log record writes. No transacton id is set for this
178
// log record. That is why a null argument is passed below
179
// setValue(..) call.
180
checksumLogRecord.setValue(null, checksumLogOperation);
181
182             checksumLength =
183                 checksumLogRecord.getStoredSize(checksumLogOperation.group(), null) +
184                 checksumLogOperation.getStoredSize();
185
186             // calculate checksum log operation length when the database is encrypted
187
if (logFactory.databaseEncrypted())
188             {
189                 checksumLength = logFactory.getEncryptedDataLength(checksumLength);
190                 databaseEncrypted = true;
191             }
192             checksumLogRecordSize = checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE;
193
194             //streams required to convert a log record to raw byte array.
195
logOutputBuffer = new ArrayOutputStream();
196             logicalOut = new FormatIdOutputStream(logOutputBuffer);
197
198             /** initialize the buffer with space reserved for checksum log record in
199              * the beginning of the log buffer; checksum record is written into
200              * this space when buffer is switched or while doing direct write to the log file.
201              */

202         }else
203         {
204             //checksumming of transaction log feature is not in use.
205
checksumLogRecordSize = 0;
206         }
207         
208         currentBuffer.init(checksumLogRecordSize);
209     }
210
211
212     private byte[] db = new byte[LOG_RECORD_TRAILER_SIZE];
213
214
215     /**
216      * Write a single log record to the stream.
217      * <p>
218      * For performance pass all parameters rather into a specialized routine
219      * rather than maintaining the writeInt, writeLong, and write interfaces
220      * that this class provides as a standard OutputStream. It will make it
221      * harder to use other OutputStream implementations, but makes for less
222      * function calls and allows optimizations knowing when to switch buffers.
223      * <p>
224      * This routine handles all log records which are smaller than one log
225      * buffer. If a log record is bigger than a log buffer it calls
226      * writeUnbufferedLogRecord().
227      * <p>
228      * The log record written will always look the same as if the following
229      * code had been executed:
230      * writeInt(length)
231      * writeLong(instant)
232      * write(data, data_offset, (length - optional_data_length) )
233      *
234      * if (optional_data_length != 0)
235      * write(optional_data, optional_data_offset, optional_data_length)
236      *
237      * writeInt(length)
238      *
239      * @param length (data + optional_data) length bytes to write
240      * @param instant the log address of this log record.
241      * @param data "from" array to copy "data" portion of rec
242      * @param data_offset offset in "data" to start copying from.
243      * @param optional_data "from" array to copy "optional data" from
244      * @param optional_data_offset offset in "optional_data" to start copy from
245      * @param optional_data_length length of optional data to copy.
246      *
247      * @exception StandardException Standard exception policy.
248      **/

249     public void writeLogRecord(
250     int length,
251     long instant,
252     byte[] data,
253     int data_offset,
254     byte[] optional_data,
255     int optional_data_offset,
256     int optional_data_length)
257         throws StandardException, IOException JavaDoc
258     {
259         int total_log_record_length = length + LOG_RECORD_FIXED_OVERHEAD_SIZE;
260
261         if (total_log_record_length <= currentBuffer.bytes_free)
262         {
263             byte[] b = currentBuffer.buffer;
264             int p = currentBuffer.position;
265
266             // writeInt(length)
267
p = writeInt(length, b, p);
268             
269             // writeLong(instant)
270
p = writeLong(instant, b , p);
271
272             // write(data, data_offset, length - optional_data_length)
273
int transfer_length = (length - optional_data_length);
274             System.arraycopy(data, data_offset, b, p, transfer_length);
275
276             p += transfer_length;
277
278             if (optional_data_length != 0)
279             {
280                 // write(
281
// optional_data, optional_data_offset, optional_data_length);
282

283                 System.arraycopy(
284                     optional_data, optional_data_offset,
285                     b, p,
286                     optional_data_length);
287
288                 p += optional_data_length;
289             }
290
291             // writeInt(length)
292
p = writeInt(length, b, p);
293             
294             currentBuffer.position = p;
295             currentBuffer.bytes_free -= total_log_record_length;
296         }
297         else
298         {
299             
300             /** Because current log record will never fit in a single buffer
301              * a direct write to the log file is required instead of
302              * writing the log record through the log bufffers.
303              */

304             directWrite = true;
305
306             byte[] b = currentBuffer.buffer;
307             int p = currentBuffer.position;
308
309             // writeInt(length)
310
p = writeInt(length , b, p);
311             
312             // writeLong(instant)
313
p = writeLong(instant, b, p);
314
315             currentBuffer.position = p;
316             currentBuffer.bytes_free -= LOG_RECORD_HEADER_SIZE;
317
318             /** using a seperate small buffer to write the traling length
319              * instead of the log buffer because data portion will be
320              * written directly to log file after the log buffer is
321              * flushed and the trailing length should be written after that.
322              */

323
324             // writeInt(length)
325
writeInt(length , db, 0);
326
327             if(writeChecksum)
328             {
329                 checksumLogOperation.reset();
330                 checksumLogOperation.update(b, checksumLogRecordSize, p - checksumLogRecordSize);
331                 checksumLogOperation.update(data, data_offset, length - optional_data_length);
332                 if (optional_data_length != 0)
333                 {
334                     checksumLogOperation.update(optional_data, optional_data_offset, optional_data_length);
335                 }
336
337                 // update the checksum to include the trailing length.
338
checksumLogOperation.update(db, 0, LOG_RECORD_TRAILER_SIZE);
339             
340                 // write checksum log record to the log buffer
341
writeChecksumLogRecord();
342             }
343             
344             
345             // now do the writes directly to the log file.
346

347             // flush all buffers before wrting directly to the log file.
348
flushLogAccessFile();
349
350             // Note:No Special Synchronization required here ,
351
// There will be nothing to write by flushDirtyBuffers that can run
352
// in parallel to the threads that is executing this code. Above
353
// flush call should have written all the buffers and NO new log will
354
// get added until the following direct log to file call finishes.
355

356
357             // write the rest of the log directltly to the log file.
358
writeToLog(data, data_offset, length - optional_data_length);
359             if (optional_data_length != 0)
360             {
361                 writeToLog(
362                     optional_data, optional_data_offset, optional_data_length);
363             }
364
365             // write the trailing length
366
writeToLog(db,0, 4);
367             directWrite = false;
368         }
369     }
370
371
372
373     private final int writeInt(int i , byte b[], int p)
374     {
375     
376         b[p++] = (byte) ((i >>> 24) & 0xff);
377         b[p++] = (byte) ((i >>> 16) & 0xff);
378         b[p++] = (byte) ((i >>> 8) & 0xff);
379         b[p++] = (byte) (i & 0xff);
380         return p;
381     }
382
383
384     private final int writeLong(long l , byte b[], int p)
385     {
386         b[p++] = (byte) (((int)(l >>> 56)) & 0xff);
387         b[p++] = (byte) (((int)(l >>> 48)) & 0xff);
388         b[p++] = (byte) (((int)(l >>> 40)) & 0xff);
389         b[p++] = (byte) (((int)(l >>> 32)) & 0xff);
390         b[p++] = (byte) (((int)(l >>> 24)) & 0xff);
391         b[p++] = (byte) (((int)(l >>> 16)) & 0xff);
392         b[p++] = (byte) (((int)(l >>> 8)) & 0xff);
393         b[p++] = (byte) (((int)l) & 0xff);
394         return p;
395     }
396
397     public void writeInt(int i)
398     {
399
400         if (SanityManager.DEBUG)
401         {
402             SanityManager.ASSERT(currentBuffer.bytes_free >= 4);
403         }
404         
405         currentBuffer.position =
406             writeInt(i , currentBuffer.buffer, currentBuffer.position);
407         currentBuffer.bytes_free -= 4;
408     }
409
410     public void writeLong(long l)
411     {
412         
413         if (SanityManager.DEBUG)
414         {
415             SanityManager.ASSERT(currentBuffer.bytes_free >= 8);
416         }
417         
418         currentBuffer.position =
419             writeLong(l , currentBuffer.buffer, currentBuffer.position);
420         currentBuffer.bytes_free -= 8;
421     }
422
423     public void write(int b)
424     {
425         if (SanityManager.DEBUG)
426         {
427             SanityManager.ASSERT(currentBuffer.bytes_free > 0);
428         }
429         
430         currentBuffer.buffer[currentBuffer.position++] = (byte) b;
431         currentBuffer.bytes_free--;
432     }
433
434
435     public void write(byte b[], int off, int len)
436     {
437         if (SanityManager.DEBUG)
438         {
439             SanityManager.ASSERT(len <= currentBuffer.bytes_free);
440         }
441         
442         System.arraycopy(b, off, currentBuffer.buffer, currentBuffer.position, len);
443         currentBuffer.bytes_free -= len;
444         currentBuffer.position += len;
445     }
446
447
448     /**
449      * Write data from all dirty buffers into the log file.
450      * <p>
451      * A call for clients of LogAccessFile to insure that all privately buffered
452      * data has been writen to the file - so that reads on the file using one
453      * of the various scan classes will see
454      * all the data which has been writen to this point.
455      * <p>
456      * Note that this routine only "writes" the data to the file, this does not
457      * mean that the data has been synced to disk unless file was opened in
458      * WRITE SYNC mode(rws/rwd). The only way to insure that is by calling
459      * is to call syncLogAccessFile() after this call in Non-WRITE sync mode(rw)
460      *
461      * <p>
462      * MT-Safe : parallel thereads can call this function, only one threads does
463      * the flush and the other threads waits for the one that is doing the flush to finish.
464      * Currently there are two possible threads that can call this function in parallel
465      * 1) A Thread that is doing the commit
466      * 2) A Thread that is writing to the log and log buffers are full or
467      * a log records does not fit in a buffer. (Log Buffers
468      * full(switchLogBuffer() or a log record size that is greater than
469      * logbuffer size has to be writtern through writeToLog call directlty)
470      * Note: writeToLog() is not synchronized on the semaphore
471      * that is used to do buffer management to allow writes
472      * to the free buffers when flush is in progress.
473      **/

474     protected void flushDirtyBuffers() throws IOException JavaDoc
475     {
476         LogAccessFileBuffer buf = null;
477         int noOfBuffers;
478         int nFlushed= 0;
479         try{
480             synchronized(this)
481             {
482                 /**if some one else flushing wait, otherwise it is possible
483                  * different threads will get different buffers and order can
484                  * not be determined.
485                  *
486                  **/

487                 while(flushInProgress)
488                 {
489                     try{
490                         wait();
491                     }catch (InterruptedException JavaDoc ie)
492                     {
493                         //do nothing, let the flush request to complete.
494
//because it possible that other thread which is
495
//currently might have completed this request also ,
496
//if exited on interrupt and throw exception, can not
497
//be sure whether this transaction is COMMITTED ot not.
498
}
499                 }
500         
501                 noOfBuffers = dirtyBuffers.size();
502                 if(noOfBuffers > 0)
503                     buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();
504                 
505                 flushInProgress = true;
506             }
507             
508             while(nFlushed < noOfBuffers)
509             {
510                 if (buf.position != 0)
511                     writeToLog(buf.buffer, 0, buf.position);
512
513                 nFlushed++;
514                 synchronized(this)
515                 {
516                     //add the buffer that was written previosly to the free list
517
freeBuffers.addLast(buf);
518                     if(nFlushed < noOfBuffers)
519                         buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();
520                     else
521                     {
522                         //see if we can flush more, that came when we are at it.
523
//don't flush more than the total number of buffers,
524
//that might lead to starvation of the current thread.
525
int size = dirtyBuffers.size();
526                         if(size > 0 && nFlushed <= LOG_NUMBER_LOG_BUFFERS)
527                         {
528                             noOfBuffers += size;
529                             buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst();
530                         }
531                     }
532                 }
533             }
534
535                 
536         }finally{
537             synchronized(this)
538             {
539                 flushInProgress = false;
540                 notifyAll();
541             }
542         }
543     }
544
545
546     //flush all the the dirty buffers to disk
547
public void flushLogAccessFile() throws IOException JavaDoc, StandardException
548     {
549         switchLogBuffer();
550         flushDirtyBuffers();
551     }
552
553         
554     /**
555      * Appends the current Buffer to the dirty Buffer list and assigns a free
556      * buffer to be the currrent active buffer . Flushing of the buffer
557      * to disk is delayed if there is a free buffer available.
558      * dirty buffers will be flushed to the disk
559      * when flushDirtyBuffers() is invoked by a commit call
560      * or when no more free buffers are available.
561      */

562     public void switchLogBuffer() throws IOException JavaDoc, StandardException
563     {
564
565         synchronized(this)
566         {
567             // ignore empty buffer switch requests
568
if(currentBuffer.position == checksumLogRecordSize)
569                 return;
570
571             // calculate the checksum for the current log buffer
572
// and write the record to the space reserverd in
573
// the beginning of the buffer.
574
if(writeChecksum && !directWrite)
575             {
576                 checksumLogOperation.reset();
577                 checksumLogOperation.update(currentBuffer.buffer, checksumLogRecordSize, currentBuffer.position - checksumLogRecordSize);
578                 writeChecksumLogRecord();
579             }
580
581             //add the current buffer to the flush buffer list
582
dirtyBuffers.addLast(currentBuffer);
583
584             //if there is No free buffer, flush the buffers to get a free one
585
if(freeBuffers.size() == 0)
586             {
587                 flushDirtyBuffers();
588                 //after the flush call there should be a free buffer
589
//because this is only methods removes items from
590
//free buffers and removal is in synchronized block.
591
}
592
593
594             // there should be free buffer available at this point.
595
if (SanityManager.DEBUG)
596                 SanityManager.ASSERT(freeBuffers.size() > 0);
597
598             //switch over to the next log buffer, let someone else write it.
599
currentBuffer = (LogAccessFileBuffer) freeBuffers.removeFirst();
600             currentBuffer.init(checksumLogRecordSize);
601
602             if (SanityManager.DEBUG)
603             {
604                 SanityManager.ASSERT(currentBuffer.position == checksumLogRecordSize);
605                 SanityManager.ASSERT(
606                                      currentBuffer.bytes_free == currentBuffer.length);
607                 SanityManager.ASSERT(currentBuffer.bytes_free > 0);
608             }
609         }
610     }
611
612
613     /**
614      * Guarantee all writes up to the last call to flushLogAccessFile on disk.
615      * <p>
616      * A call for clients of LogAccessFile to insure that all data written
617      * up to the last call to flushLogAccessFile() are written to disk.
618      * This call will not return until those writes have hit disk.
619      * <p>
620      * Note that this routine may block waiting for I/O to complete so
621      * callers should limit the number of resource held locked while this
622      * operation is called. It is expected that the caller
623      * Note that this routine only "writes" the data to the file, this does not
624      * mean that the data has been synced to disk. The only way to insure that
625      * is to first call switchLogBuffer() and then follow by a call of sync().
626      *
627      **/

628     public void syncLogAccessFile()
629         throws IOException JavaDoc, StandardException
630     {
631         for( int i=0; ; )
632         {
633             // 3311: JVM sync call sometimes fails under high load against NFS
634
// mounted disk. We re-try to do this 20 times.
635
try
636             {
637                 synchronized( this)
638                 {
639                     log.sync( false);
640                 }
641
642                 // the sync succeed, so return
643
break;
644             }
645             catch( SyncFailedException JavaDoc sfe )
646             {
647                 i++;
648                 try
649                 {
650                     // wait for .2 of a second, hopefully I/O is done by now
651
// we wait a max of 4 seconds before we give up
652
Thread.sleep( 200 );
653                 }
654                 catch( InterruptedException JavaDoc ie )
655                 { //does not matter weather I get interrupted or not
656
}
657
658                 if( i > 20 )
659                     throw StandardException.newException(
660                         SQLState.LOG_FULL, sfe);
661             }
662         }
663     }
664
665     /**
666         The database is being marked corrupted, get rid of file pointer without
667         writing out anything more.
668      */

669     public void corrupt() throws IOException JavaDoc
670     {
671         synchronized(logFileSemaphore)
672         {
673             if (log != null)
674                 log.close();
675         }
676     }
677
678     public void close() throws IOException JavaDoc, StandardException
679     {
680         if (SanityManager.DEBUG)
681         {
682             if (currentBuffer.position != checksumLogRecordSize)
683                 SanityManager.THROWASSERT(
684                 "Log file being closed with data still buffered " +
685                 currentBuffer.position + " " + currentBuffer.bytes_free);
686         }
687
688         flushLogAccessFile();
689
690         synchronized(logFileSemaphore)
691         {
692             if (log != null)
693                 log.close();
694         }
695     }
696
697
698     /* write to the log file */
699     private void writeToLog(byte b[], int off, int len) throws IOException JavaDoc
700     {
701         synchronized(logFileSemaphore)
702         {
703             if (log != null)
704             {
705
706                 // Try to handle case where user application is throwing
707
// random interrupts at cloudscape threads, retry in the case
708
// of IO exceptions 5 times. After that hope that it is
709
// a real disk problem - an IO error in a write to the log file
710
// is going to take down the whole system, so seems worthwhile
711
// to retry.
712
for (int i = 0; ;i++)
713                 {
714                     try
715                     {
716                         log.write(b, off, len);
717                         break;
718                     }
719                     catch (IOException JavaDoc ioe)
720                     {
721                         // just fall through and rety the log write 1st 5 times.
722

723                         if (i >= 5)
724                             throw ioe;
725                     }
726                 }
727             }
728         }
729
730         if (SanityManager.DEBUG)
731         {
732             mon_numWritesToLog++;
733             mon_numBytesToLog += len;
734         }
735     }
736
737     /**
738      * reserve the space for the checksum log record in the log file.
739      *
740      * @param length the length of the log record to be written
741      * @param logFileNumber current log file number
742      * @param currentPosition current position in the log file.
743      *
744      * @return the space that is needed to write a checksum log record.
745      */

746     protected long reserveSpaceForChecksum(int length, long logFileNumber, long currentPosition )
747         throws StandardException, IOException JavaDoc
748     {
749
750         int total_log_record_length = length + LOG_RECORD_FIXED_OVERHEAD_SIZE;
751         boolean reserveChecksumSpace = false;
752         
753         /* checksum log record is calculated for a group of log
754          * records that can fit in to a single buffer or for
755          * a single record when it does not fit into
756          * a fit into a buffer at all. When a new buffer
757          * is required to write a log record, log space
758          * has to be reserved before writing the log record
759          * becuase checksum is written in the before the
760          * log records that are being checksummed.
761          * What it also means is a real log instant has to be
762          * reserved for writing the checksum log record in addition
763          * to the log buffer space.
764          */

765         
766
767         /* reserve checkum space for new log records if a log buffer switch had
768          * happened before because of a explicit log flush requests(like commit)
769          * or a long record write
770          */

771         if(currentBuffer.position == checksumLogRecordSize)
772         {
773             // reserver space if log checksum feature is enabled.
774
reserveChecksumSpace = writeChecksum;
775         }
776         else{
777             if (total_log_record_length > currentBuffer.bytes_free)
778             {
779                 // the log record that is going to be written is not
780
// going to fit in the current buffer, switch the
781
// log buffer to create buffer space for it.
782
switchLogBuffer();
783                 // reserve space if log checksum feature is enabled.
784
reserveChecksumSpace = writeChecksum;
785             }
786         }
787         
788         if(reserveChecksumSpace)
789         {
790             if (SanityManager.DEBUG)
791             {
792                 // Prevoiusly reserved real checksum instant should have been
793
// used, before an another one is generated.
794
SanityManager.ASSERT(checksumInstant == -1, "CHECKSUM INSTANT IS GETTING OVER WRITTEN");
795             }
796             
797             checksumInstant = LogCounter.makeLogInstantAsLong(logFileNumber, currentPosition);
798             return checksumLogRecordSize;
799         }else
800         {
801             return 0 ;
802         }
803     }
804
805
806     /*
807      * generate the checkum log record and write it into the log buffer.
808      */

809     private void writeChecksumLogRecord() throws IOException JavaDoc, StandardException
810     {
811         
812         byte[] b = currentBuffer.buffer;
813         int p = 0; //checksum is written in the beginning of the buffer
814

815         // writeInt(length)
816
p = writeInt(checksumLength, b , p);
817             
818         // writeLong(instant)
819
p = writeLong(checksumInstant, b , p);
820
821         //write the checksum log operation
822
logOutputBuffer.setData(b);
823         logOutputBuffer.setPosition(p);
824         logicalOut.writeObject(checksumLogRecord);
825
826         if(databaseEncrypted)
827         {
828             //encrypt the checksum log operation part.
829
int len =
830                 logFactory.encrypt(b, LOG_RECORD_HEADER_SIZE, checksumLength,
831                                    b, LOG_RECORD_HEADER_SIZE);
832             
833            
834             if (SanityManager.DEBUG)
835                 SanityManager.ASSERT(len == checksumLength,
836                                      "encrypted log buffer length != log buffer len");
837         }
838
839         p = LOG_RECORD_HEADER_SIZE + checksumLength ;
840
841         // writeInt(length) trailing
842
p = writeInt(checksumLength, b, p );
843         
844         if (SanityManager.DEBUG)
845         {
846             SanityManager.ASSERT(p == checksumLogRecordSize, "position=" + p + "ckrecordsize=" + checksumLogRecordSize);
847             if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG))
848             {
849                 SanityManager.DEBUG(
850                                     LogToFile.DBG_FLAG,
851                                     "Write log record: tranId=Null" +
852                                     " instant: " + LogCounter.toDebugString(checksumInstant) + " length: " +
853                                     checksumLength + "\n" + checksumLogOperation + "\n");
854             }
855             checksumInstant = -1;
856         }
857
858     }
859
860
861     protected void writeEndMarker(int marker) throws IOException JavaDoc, StandardException
862     {
863         //flush all the buffers and then write the end marker.
864
flushLogAccessFile();
865         
866         byte[] b = currentBuffer.buffer;
867         int p = 0; //end is written in the beginning of the buffer, no
868
//need to checksum a int write.
869
p = writeInt(marker , b , p);
870         writeToLog(b, 0, p);
871     }
872
873     
874 }
875
876
877
878
879
880
881
882
883
Popular Tags