Source Code Cross Referenced for LogAccessFile.java in  » Database-DBMS » db-derby-10.2 » org » apache » derby » impl » store » raw » log » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database DBMS » db derby 10.2 » org.apache.derby.impl.store.raw.log 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:
003:           Derby - Class org.apache.derby.impl.store.raw.log.LogAccessFile
004:
005:           Licensed to the Apache Software Foundation (ASF) under one or more
006:           contributor license agreements.  See the NOTICE file distributed with
007:           this work for additional information regarding copyright ownership.
008:           The ASF licenses this file to you under the Apache License, Version 2.0
009:           (the "License"); you may not use this file except in compliance with
010:           the License.  You may obtain a copy of the License at
011:
012:              http://www.apache.org/licenses/LICENSE-2.0
013:
014:           Unless required by applicable law or agreed to in writing, software
015:           distributed under the License is distributed on an "AS IS" BASIS,
016:           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017:           See the License for the specific language governing permissions and
018:           limitations under the License.
019:
020:         */
021:
022:        package org.apache.derby.impl.store.raw.log;
023:
024:        import org.apache.derby.iapi.reference.SQLState;
025:
026:        import org.apache.derby.iapi.services.sanity.SanityManager;
027:        import org.apache.derby.iapi.error.StandardException;
028:
029:        import org.apache.derby.io.StorageRandomAccessFile;
030:
031:        import java.io.IOException;
032:        import java.io.OutputStream;
033:        import java.io.SyncFailedException;
034:        import java.io.InterruptedIOException;
035:        import java.util.LinkedList;
036:
037:        import org.apache.derby.iapi.services.io.FormatIdOutputStream;
038:        import org.apache.derby.iapi.services.io.ArrayOutputStream;
039:        import org.apache.derby.iapi.store.raw.RawStoreFactory;
040:
041:        /**
042:         Wraps a RandomAccessFile file to provide buffering
043:         on log writes. Only supports the write calls
044:         required for the log!
045:
046:         MT - unsafe.  Caller of this class must provide synchronization.  The one
047:         exception is with the log file access, LogAccessFile will touch the log
048:         only inside synchronized block protected by the semaphore, which is
049:         defined by the creator of this object.
050:        
051:         Write to the log buffers are allowed when there are free buffers even
052:         when dirty buffers are being written(flushed) to the disk by a different
053:         thread. Only one flush writes to log file at a time, other wait for it to finish.
054:
055:         Except for flushLogAccessFile , SyncAccessLogFile other function callers
056:         must provide syncronization that will allow only one of them to write to 
057:         the buffers. 
058:
059:         Log Buffers are used in circular fashion, each buffer moves through following stages: 
060:         freeBuffers --> dirtyBuffers --> freeBuffers. Movement of buffers from one
061:         stage to 	another stage is synchronized using	the object(this) of this class. 
062:
063:         A Checksum log record that has the checksum value for the data that is
064:         being written to the disk is generated and written 	before the actual data. 
065:         Except for the large log records that does not fit into a single buffer, 
066:         checksum is calcualted for a group of log records that are in the buffer 
067:         when buffers is switched. Checksum log record is written into the reserved
068:         space in the beginning buffer. 
069:
070:         In case of a large log record that does not fit into a bufffer, it needs to 
071:         be written directly to the disk instead of going through the log buffers. 
072:         In this case the log record write gets broken into three parts:
073:         1) Write checksum log record and LOG RECORD HEADER (length + instant) 
074:         2) Write the log record. 
075:         3) Write the trailing length of the log record. 
076:
077:         Checksum log records helps in identifying the incomplete log disk writes during 
078:         recovery. This is done by recalculating the checksum value for the data on
079:         the disk and comparing it to the the value stored in the checksum log
080:         record. 
081:
082:         */
083:        public class LogAccessFile {
084:
085:            /**
086:             * The fixed size of a log record is 16 bytes:
087:             *     int   length             : 4 bytes
088:             *     long  instant            : 8 bytes
089:             *     int   trailing length    : 4 bytes
090:             **/
091:            private static final int LOG_RECORD_FIXED_OVERHEAD_SIZE = 16;
092:            private static final int LOG_RECORD_HEADER_SIZE = 12; //(length + instant)
093:            private static final int LOG_RECORD_TRAILER_SIZE = 4; //trailing length 
094:            private static final int LOG_NUMBER_LOG_BUFFERS = 3;
095:
096:            private LinkedList freeBuffers; //list of free buffers
097:            private LinkedList dirtyBuffers; //list of dirty buffers to flush
098:            private LogAccessFileBuffer currentBuffer; //current active buffer
099:            private boolean flushInProgress = false;
100:
101:            private final StorageRandomAccessFile log;
102:
103:            // log can be touched only inside synchronized block protected by
104:            // logFileSemaphore.
105:            private final Object logFileSemaphore;
106:
107:            static int mon_numWritesToLog;
108:            static int mon_numBytesToLog;
109:
110:            //streams used to generated check sume log record ; see if there is any simpler way
111:            private ArrayOutputStream logOutputBuffer;
112:            private FormatIdOutputStream logicalOut;
113:            private boolean directWrite = false; //true when log is written directly to file.
114:            private long checksumInstant = -1;
115:            private int checksumLength;
116:            private int checksumLogRecordSize; //checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE
117:            private boolean writeChecksum;
118:            private ChecksumOperation checksumLogOperation;
119:            private LogRecord checksumLogRecord;
120:            private LogToFile logFactory;
121:            private boolean databaseEncrypted = false;
122:
123:            public LogAccessFile(LogToFile logFactory,
124:                    StorageRandomAccessFile log, int bufferSize) {
125:                if (SanityManager.DEBUG) {
126:                    if (SanityManager.DEBUG_ON("LogBufferOff"))
127:                        bufferSize = 10; // make it very tiny
128:                }
129:
130:                this .log = log;
131:                logFileSemaphore = log;
132:                this .logFactory = logFactory;
133:
134:                if (SanityManager.DEBUG)
135:                    SanityManager.ASSERT(LOG_NUMBER_LOG_BUFFERS >= 1);
136:
137:                //initialize buffers lists
138:                freeBuffers = new LinkedList();
139:                dirtyBuffers = new LinkedList();
140:
141:                //add all buffers to free list
142:                for (int i = 0; i < LOG_NUMBER_LOG_BUFFERS; i++) {
143:                    LogAccessFileBuffer b = new LogAccessFileBuffer(bufferSize);
144:                    freeBuffers.addLast(b);
145:                }
146:
147:                currentBuffer = (LogAccessFileBuffer) freeBuffers.removeFirst();
148:
149:                // Support for Transaction Log Checksum in Derby was added in 10.1
150:                // Check to see if the Store have been upgraded to 10.1 or later before
151:                // writing the checksum log records.  Otherwise recovery will fail
152:                // incase user tries to revert back to versions before 10.1 in 
153:                // soft upgrade mode. 
154:                writeChecksum = logFactory.checkVersion(
155:                        RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10,
156:                        RawStoreFactory.DERBY_STORE_MINOR_VERSION_1);
157:                if (writeChecksum) {
158:                    /**
159:                     * setup structures that are required to write the checksum log records
160:                     * for a group of log records are being written to the disk. 
161:                     */
162:                    checksumLogOperation = new ChecksumOperation();
163:                    checksumLogOperation.init();
164:                    checksumLogRecord = new LogRecord();
165:
166:                    // Note: Checksum log records are not related any particular transaction, 
167:                    // they are written to store a checksum information identify
168:                    // incomplete log record writes. No transacton id is set for this
169:                    // log record. That is why a null argument is passed below 
170:                    // setValue(..) call. 
171:                    checksumLogRecord.setValue(null, checksumLogOperation);
172:
173:                    checksumLength = checksumLogRecord.getStoredSize(
174:                            checksumLogOperation.group(), null)
175:                            + checksumLogOperation.getStoredSize();
176:
177:                    // calculate checksum log operation length when the database is encrypted
178:                    if (logFactory.databaseEncrypted()) {
179:                        checksumLength = logFactory
180:                                .getEncryptedDataLength(checksumLength);
181:                        databaseEncrypted = true;
182:                    }
183:                    checksumLogRecordSize = checksumLength
184:                            + LOG_RECORD_FIXED_OVERHEAD_SIZE;
185:
186:                    //streams required to convert a log record to raw byte array. 
187:                    logOutputBuffer = new ArrayOutputStream();
188:                    logicalOut = new FormatIdOutputStream(logOutputBuffer);
189:
190:                    /** initialize the buffer with space reserved for checksum log record in
191:                     * the beginning of the log buffer; checksum record is written into
192:                     * this space when buffer is switched or while doing direct write to the log file.
193:                     */
194:                } else {
195:                    //checksumming of transaction log feature is not in use. 
196:                    checksumLogRecordSize = 0;
197:                }
198:
199:                currentBuffer.init(checksumLogRecordSize);
200:            }
201:
202:            private byte[] db = new byte[LOG_RECORD_TRAILER_SIZE];
203:
204:            /**
205:             * Write a single log record to the stream.
206:             * <p>
207:             * For performance pass all parameters rather into a specialized routine
208:             * rather than maintaining the writeInt, writeLong, and write interfaces
209:             * that this class provides as a standard OutputStream.  It will make it
210:             * harder to use other OutputStream implementations, but makes for less
211:             * function calls and allows optimizations knowing when to switch buffers.
212:             * <p>
213:             * This routine handles all log records which are smaller than one log
214:             * buffer.  If a log record is bigger than a log buffer it calls
215:             * writeUnbufferedLogRecord().
216:             * <p>
217:             * The log record written will always look the same as if the following
218:             * code had been executed:
219:             *     writeInt(length)
220:             *     writeLong(instant)
221:             *     write(data, data_offset, (length - optional_data_length) )
222:             *
223:             *     if (optional_data_length != 0)
224:             *         write(optional_data, optional_data_offset, optional_data_length)
225:             *
226:             *     writeInt(length)
227:             *
228:             * @param length                (data + optional_data) length bytes to write
229:             * @param instant               the log address of this log record.
230:             * @param data                  "from" array to copy "data" portion of rec
231:             * @param data_offset           offset in "data" to start copying from.
232:             * @param optional_data         "from" array to copy "optional data" from
233:             * @param optional_data_offset  offset in "optional_data" to start copy from
234:             * @param optional_data_length  length of optional data to copy.
235:             *
236:             * @exception  StandardException  Standard exception policy.
237:             **/
238:            public void writeLogRecord(int length, long instant, byte[] data,
239:                    int data_offset, byte[] optional_data,
240:                    int optional_data_offset, int optional_data_length)
241:                    throws StandardException, IOException {
242:                int total_log_record_length = length
243:                        + LOG_RECORD_FIXED_OVERHEAD_SIZE;
244:
245:                if (total_log_record_length <= currentBuffer.bytes_free) {
246:                    byte[] b = currentBuffer.buffer;
247:                    int p = currentBuffer.position;
248:
249:                    // writeInt(length)
250:                    p = writeInt(length, b, p);
251:
252:                    // writeLong(instant)
253:                    p = writeLong(instant, b, p);
254:
255:                    // write(data, data_offset, length - optional_data_length)
256:                    int transfer_length = (length - optional_data_length);
257:                    System.arraycopy(data, data_offset, b, p, transfer_length);
258:
259:                    p += transfer_length;
260:
261:                    if (optional_data_length != 0) {
262:                        // write(
263:                        //   optional_data, optional_data_offset, optional_data_length);
264:
265:                        System.arraycopy(optional_data, optional_data_offset,
266:                                b, p, optional_data_length);
267:
268:                        p += optional_data_length;
269:                    }
270:
271:                    // writeInt(length)
272:                    p = writeInt(length, b, p);
273:
274:                    currentBuffer.position = p;
275:                    currentBuffer.bytes_free -= total_log_record_length;
276:                } else {
277:
278:                    /** Because current log record will never fit in a single buffer
279:                     * a direct write to the log file is required instead of 
280:                     * writing the log record through  the log bufffers. 
281:                     */
282:                    directWrite = true;
283:
284:                    byte[] b = currentBuffer.buffer;
285:                    int p = currentBuffer.position;
286:
287:                    // writeInt(length)
288:                    p = writeInt(length, b, p);
289:
290:                    // writeLong(instant)
291:                    p = writeLong(instant, b, p);
292:
293:                    currentBuffer.position = p;
294:                    currentBuffer.bytes_free -= LOG_RECORD_HEADER_SIZE;
295:
296:                    /** using a seperate small buffer to write the traling length
297:                     * instead of the log buffer because data portion will be 
298:                     * written directly to log file after the log buffer is 
299:                     * flushed and the trailing length should be written after that. 
300:                     */
301:
302:                    // writeInt(length)
303:                    writeInt(length, db, 0);
304:
305:                    if (writeChecksum) {
306:                        checksumLogOperation.reset();
307:                        checksumLogOperation.update(b, checksumLogRecordSize, p
308:                                - checksumLogRecordSize);
309:                        checksumLogOperation.update(data, data_offset, length
310:                                - optional_data_length);
311:                        if (optional_data_length != 0) {
312:                            checksumLogOperation.update(optional_data,
313:                                    optional_data_offset, optional_data_length);
314:                        }
315:
316:                        // update the checksum to include the trailing length.
317:                        checksumLogOperation.update(db, 0,
318:                                LOG_RECORD_TRAILER_SIZE);
319:
320:                        // write checksum log record to the log buffer 
321:                        writeChecksumLogRecord();
322:                    }
323:
324:                    // now do the  writes directly to the log file. 
325:
326:                    // flush all buffers before wrting directly to the log file. 
327:                    flushLogAccessFile();
328:
329:                    // Note:No Special Synchronization required here , 
330:                    // There will be nothing to write by flushDirtyBuffers that can run
331:                    // in parallel to the threads that is executing this code. Above
332:                    // flush call should have written all the buffers and NO new log will 
333:                    // get added until the following direct log to file call finishes. 
334:
335:                    // write the rest of the log directltly to the log file. 
336:                    writeToLog(data, data_offset, length - optional_data_length);
337:                    if (optional_data_length != 0) {
338:                        writeToLog(optional_data, optional_data_offset,
339:                                optional_data_length);
340:                    }
341:
342:                    // write the trailing length 
343:                    writeToLog(db, 0, 4);
344:                    directWrite = false;
345:                }
346:            }
347:
348:            private final int writeInt(int i, byte b[], int p) {
349:
350:                b[p++] = (byte) ((i >>> 24) & 0xff);
351:                b[p++] = (byte) ((i >>> 16) & 0xff);
352:                b[p++] = (byte) ((i >>> 8) & 0xff);
353:                b[p++] = (byte) (i & 0xff);
354:                return p;
355:            }
356:
357:            private final int writeLong(long l, byte b[], int p) {
358:                b[p++] = (byte) (((int) (l >>> 56)) & 0xff);
359:                b[p++] = (byte) (((int) (l >>> 48)) & 0xff);
360:                b[p++] = (byte) (((int) (l >>> 40)) & 0xff);
361:                b[p++] = (byte) (((int) (l >>> 32)) & 0xff);
362:                b[p++] = (byte) (((int) (l >>> 24)) & 0xff);
363:                b[p++] = (byte) (((int) (l >>> 16)) & 0xff);
364:                b[p++] = (byte) (((int) (l >>> 8)) & 0xff);
365:                b[p++] = (byte) (((int) l) & 0xff);
366:                return p;
367:            }
368:
369:            public void writeInt(int i) {
370:
371:                if (SanityManager.DEBUG) {
372:                    SanityManager.ASSERT(currentBuffer.bytes_free >= 4);
373:                }
374:
375:                currentBuffer.position = writeInt(i, currentBuffer.buffer,
376:                        currentBuffer.position);
377:                currentBuffer.bytes_free -= 4;
378:            }
379:
380:            public void writeLong(long l) {
381:
382:                if (SanityManager.DEBUG) {
383:                    SanityManager.ASSERT(currentBuffer.bytes_free >= 8);
384:                }
385:
386:                currentBuffer.position = writeLong(l, currentBuffer.buffer,
387:                        currentBuffer.position);
388:                currentBuffer.bytes_free -= 8;
389:            }
390:
391:            public void write(int b) {
392:                if (SanityManager.DEBUG) {
393:                    SanityManager.ASSERT(currentBuffer.bytes_free > 0);
394:                }
395:
396:                currentBuffer.buffer[currentBuffer.position++] = (byte) b;
397:                currentBuffer.bytes_free--;
398:            }
399:
400:            public void write(byte b[], int off, int len) {
401:                if (SanityManager.DEBUG) {
402:                    SanityManager.ASSERT(len <= currentBuffer.bytes_free);
403:                }
404:
405:                System.arraycopy(b, off, currentBuffer.buffer,
406:                        currentBuffer.position, len);
407:                currentBuffer.bytes_free -= len;
408:                currentBuffer.position += len;
409:            }
410:
411:            /**
412:             * Write data from all dirty buffers into the log file.
413:             * <p>
414:             * A call for clients of LogAccessFile to insure that all privately buffered
415:             * data has been writen to the file - so that reads on the file using one
416:             * of the various scan classes will see
417:             * all the data which has been writen to this point.
418:             * <p>
419:             * Note that this routine only "writes" the data to the file, this does not
420:             * mean that the data has been synced to disk unless file was opened in
421:             * WRITE SYNC mode(rws/rwd).  The only way to insure that is by calling
422:             * is to call syncLogAccessFile() after this call in Non-WRITE sync mode(rw)
423:             * 
424:             * <p>
425:             * MT-Safe : parallel thereads can call this function, only one threads does
426:             * the flush and the other threads waits for the one that is doing the flush to finish.
427:             * Currently there are two possible threads that can call this function in parallel 
428:             * 1) A Thread that is doing the commit
429:             * 2) A Thread that is writing to the log and log buffers are full or
430:             * a log records does not fit in a buffer. (Log Buffers
431:             * full(switchLogBuffer() or a log record size that is greater than
432:             * logbuffer size has to be writtern through writeToLog call directlty)
433:             * Note: writeToLog() is not synchronized on the semaphore
434:             * that is used to do  buffer management to allow writes 
435:             * to the free buffers when flush is in progress.  
436:             **/
437:            protected void flushDirtyBuffers() throws IOException {
438:                LogAccessFileBuffer buf = null;
439:                int noOfBuffers;
440:                int nFlushed = 0;
441:                try {
442:                    synchronized (this ) {
443:                        /**if some one else flushing wait, otherwise it is possible 
444:                         * different threads will get different buffers and order can 
445:                         * not be determined.
446:                         * 
447:                         **/
448:                        while (flushInProgress) {
449:                            try {
450:                                wait();
451:                            } catch (InterruptedException ie) {
452:                                //do nothing, let the flush request to complete.
453:                                //because it possible that other thread which is
454:                                //currently might have completed this request also ,
455:                                //if exited  on interrupt and throw exception, can not
456:                                //be sure whether this transaction is COMMITTED ot not.
457:                            }
458:                        }
459:
460:                        noOfBuffers = dirtyBuffers.size();
461:                        if (noOfBuffers > 0)
462:                            buf = (LogAccessFileBuffer) dirtyBuffers
463:                                    .removeFirst();
464:
465:                        flushInProgress = true;
466:                    }
467:
468:                    while (nFlushed < noOfBuffers) {
469:                        if (buf.position != 0)
470:                            writeToLog(buf.buffer, 0, buf.position);
471:
472:                        nFlushed++;
473:                        synchronized (this ) {
474:                            //add the buffer that was written previosly to the free list
475:                            freeBuffers.addLast(buf);
476:                            if (nFlushed < noOfBuffers)
477:                                buf = (LogAccessFileBuffer) dirtyBuffers
478:                                        .removeFirst();
479:                            else {
480:                                //see if we can flush more, that came when we are at it.
481:                                //don't flush more than the total number of buffers,
482:                                //that might lead to starvation of the current thread.
483:                                int size = dirtyBuffers.size();
484:                                if (size > 0
485:                                        && nFlushed <= LOG_NUMBER_LOG_BUFFERS) {
486:                                    noOfBuffers += size;
487:                                    buf = (LogAccessFileBuffer) dirtyBuffers
488:                                            .removeFirst();
489:                                }
490:                            }
491:                        }
492:                    }
493:
494:                } finally {
495:                    synchronized (this ) {
496:                        flushInProgress = false;
497:                        notifyAll();
498:                    }
499:                }
500:            }
501:
502:            //flush all the the dirty buffers to disk
503:            public void flushLogAccessFile() throws IOException,
504:                    StandardException {
505:                switchLogBuffer();
506:                flushDirtyBuffers();
507:            }
508:
509:            /**
510:             * Appends the current Buffer to the dirty Buffer list and assigns a free
511:             * buffer to be the currrent active buffer . Flushing of the buffer
512:             * to disk is delayed if there is a free buffer available. 
513:             * dirty buffers will be  flushed to the disk   
514:             * when  flushDirtyBuffers() is invoked by  a commit call 
515:             * or when no more free buffers are available. 
516:             */
517:            public void switchLogBuffer() throws IOException, StandardException {
518:
519:                synchronized (this ) {
520:                    // ignore empty buffer switch requests
521:                    if (currentBuffer.position == checksumLogRecordSize)
522:                        return;
523:
524:                    // calculate the checksum for the current log buffer 
525:                    // and write the record to the space reserverd in 
526:                    // the beginning of the buffer. 
527:                    if (writeChecksum && !directWrite) {
528:                        checksumLogOperation.reset();
529:                        checksumLogOperation.update(currentBuffer.buffer,
530:                                checksumLogRecordSize, currentBuffer.position
531:                                        - checksumLogRecordSize);
532:                        writeChecksumLogRecord();
533:                    }
534:
535:                    //add the current buffer to the flush buffer list
536:                    dirtyBuffers.addLast(currentBuffer);
537:
538:                    //if there is No free buffer, flush the buffers to get a free one 
539:                    if (freeBuffers.size() == 0) {
540:                        flushDirtyBuffers();
541:                        //after the flush call there should be a free buffer
542:                        //because this is only methods removes items from 
543:                        //free buffers and removal is in synchronized block. 
544:                    }
545:
546:                    // there should be free buffer available at this point.
547:                    if (SanityManager.DEBUG)
548:                        SanityManager.ASSERT(freeBuffers.size() > 0);
549:
550:                    //switch over to the next log buffer, let someone else write it.
551:                    currentBuffer = (LogAccessFileBuffer) freeBuffers
552:                            .removeFirst();
553:                    currentBuffer.init(checksumLogRecordSize);
554:
555:                    if (SanityManager.DEBUG) {
556:                        SanityManager
557:                                .ASSERT(currentBuffer.position == checksumLogRecordSize);
558:                        SanityManager
559:                                .ASSERT(currentBuffer.bytes_free == currentBuffer.length);
560:                        SanityManager.ASSERT(currentBuffer.bytes_free > 0);
561:                    }
562:                }
563:            }
564:
565:            /**
566:             * Guarantee all writes up to the last call to flushLogAccessFile on disk.
567:             * <p>
568:             * A call for clients of LogAccessFile to insure that all data written
569:             * up to the last call to flushLogAccessFile() are written to disk.
570:             * This call will not return until those writes have hit disk.
571:             * <p>
572:             * Note that this routine may block waiting for I/O to complete so 
573:             * callers should limit the number of resource held locked while this
574:             * operation is called.  It is expected that the caller
575:             * Note that this routine only "writes" the data to the file, this does not
576:             * mean that the data has been synced to disk.  The only way to insure that
577:             * is to first call switchLogBuffer() and then follow by a call of sync().
578:             *
579:             **/
580:            public void syncLogAccessFile() throws IOException,
581:                    StandardException {
582:                for (int i = 0;;) {
583:                    // 3311: JVM sync call sometimes fails under high load against NFS 
584:                    // mounted disk.  We re-try to do this 20 times.
585:                    try {
586:                        synchronized (this ) {
587:                            log.sync(false);
588:                        }
589:
590:                        // the sync succeed, so return
591:                        break;
592:                    } catch (SyncFailedException sfe) {
593:                        i++;
594:                        try {
595:                            // wait for .2 of a second, hopefully I/O is done by now
596:                            // we wait a max of 4 seconds before we give up
597:                            Thread.sleep(200);
598:                        } catch (InterruptedException ie) { //does not matter weather I get interrupted or not
599:                        }
600:
601:                        if (i > 20)
602:                            throw StandardException.newException(
603:                                    SQLState.LOG_FULL, sfe);
604:                    }
605:                }
606:            }
607:
608:            /**
609:            	The database is being marked corrupted, get rid of file pointer without
610:            	writing out anything more.
611:             */
612:            public void corrupt() throws IOException {
613:                synchronized (logFileSemaphore) {
614:                    if (log != null)
615:                        log.close();
616:                }
617:            }
618:
619:            public void close() throws IOException, StandardException {
620:                if (SanityManager.DEBUG) {
621:                    if (currentBuffer.position != checksumLogRecordSize)
622:                        SanityManager
623:                                .THROWASSERT("Log file being closed with data still buffered "
624:                                        + currentBuffer.position
625:                                        + " "
626:                                        + currentBuffer.bytes_free);
627:                }
628:
629:                flushLogAccessFile();
630:
631:                synchronized (logFileSemaphore) {
632:                    if (log != null)
633:                        log.close();
634:                }
635:            }
636:
637:            /* write to the log file */
638:            private void writeToLog(byte b[], int off, int len)
639:                    throws IOException {
640:                synchronized (logFileSemaphore) {
641:                    if (log != null) {
642:
643:                        // Try to handle case where user application is throwing
644:                        // random interrupts at cloudscape threads, retry in the case
645:                        // of IO exceptions 5 times.  After that hope that it is 
646:                        // a real disk problem - an IO error in a write to the log file
647:                        // is going to take down the whole system, so seems worthwhile
648:                        // to retry.
649:                        for (int i = 0;; i++) {
650:                            try {
651:                                log.write(b, off, len);
652:                                break;
653:                            } catch (IOException ioe) {
654:                                // just fall through and rety the log write 1st 5 times.
655:
656:                                if (i >= 5)
657:                                    throw ioe;
658:                            }
659:                        }
660:                    }
661:                }
662:
663:                if (SanityManager.DEBUG) {
664:                    mon_numWritesToLog++;
665:                    mon_numBytesToLog += len;
666:                }
667:            }
668:
669:            /**
670:             * reserve the space for the checksum log record in the log file. 
671:             *
672:             * @param  length           the length of the log record to be written
673:             * @param  logFileNumber    current log file number 
674:             * @param  currentPosition  current position in the log file. 
675:             *
676:             * @return the space that is needed to write a checksum log record.
677:             */
678:            protected long reserveSpaceForChecksum(int length,
679:                    long logFileNumber, long currentPosition)
680:                    throws StandardException, IOException {
681:
682:                int total_log_record_length = length
683:                        + LOG_RECORD_FIXED_OVERHEAD_SIZE;
684:                boolean reserveChecksumSpace = false;
685:
686:                /* checksum log record is calculated for a group of log 
687:                 * records that can fit in to a single buffer or for 
688:                 * a single record when it does not fit into 
689:                 * a fit into a buffer at all. When a new buffer 
690:                 * is required to write a log record, log space 
691:                 * has to be reserved before writing the log record
692:                 * becuase checksum is written in the before the 
693:                 * log records that are being checksummed. 
694:                 * What it also means is a real log instant has to be 
695:                 * reserved for writing the checksum log record in addition 
696:                 * to the log buffer space.
697:                 */
698:
699:                /* reserve checkum space for new log records if a log buffer switch had
700:                 * happened before because of a explicit log flush requests(like commit)
701:                 * or a long record write 
702:                 */
703:                if (currentBuffer.position == checksumLogRecordSize) {
704:                    // reserver space if log checksum feature is enabled.
705:                    reserveChecksumSpace = writeChecksum;
706:                } else {
707:                    if (total_log_record_length > currentBuffer.bytes_free) {
708:                        // the log record that is going to be written is not 
709:                        // going to fit in the current buffer, switch the 
710:                        // log buffer to create buffer space for it. 
711:                        switchLogBuffer();
712:                        // reserve space if log checksum feature is enabled. 
713:                        reserveChecksumSpace = writeChecksum;
714:                    }
715:                }
716:
717:                if (reserveChecksumSpace) {
718:                    if (SanityManager.DEBUG) {
719:                        // Prevoiusly reserved real checksum instant should have been
720:                        // used, before an another one is generated. 
721:                        SanityManager.ASSERT(checksumInstant == -1,
722:                                "CHECKSUM INSTANT IS GETTING OVER WRITTEN");
723:                    }
724:
725:                    checksumInstant = LogCounter.makeLogInstantAsLong(
726:                            logFileNumber, currentPosition);
727:                    return checksumLogRecordSize;
728:                } else {
729:                    return 0;
730:                }
731:            }
732:
733:            /*
734:             * generate the checkum log record and write it into the log buffer.
735:             */
736:            private void writeChecksumLogRecord() throws IOException,
737:                    StandardException {
738:
739:                byte[] b = currentBuffer.buffer;
740:                int p = 0; //checksum is written in the beginning of the buffer
741:
742:                // writeInt(length)
743:                p = writeInt(checksumLength, b, p);
744:
745:                // writeLong(instant)
746:                p = writeLong(checksumInstant, b, p);
747:
748:                //write the checksum log operation  
749:                logOutputBuffer.setData(b);
750:                logOutputBuffer.setPosition(p);
751:                logicalOut.writeObject(checksumLogRecord);
752:
753:                if (databaseEncrypted) {
754:                    //encrypt the checksum log operation part.
755:                    int len = logFactory.encrypt(b, LOG_RECORD_HEADER_SIZE,
756:                            checksumLength, b, LOG_RECORD_HEADER_SIZE);
757:
758:                    if (SanityManager.DEBUG)
759:                        SanityManager
760:                                .ASSERT(len == checksumLength,
761:                                        "encrypted log buffer length != log buffer len");
762:                }
763:
764:                p = LOG_RECORD_HEADER_SIZE + checksumLength;
765:
766:                // writeInt(length) trailing
767:                p = writeInt(checksumLength, b, p);
768:
769:                if (SanityManager.DEBUG) {
770:                    SanityManager.ASSERT(p == checksumLogRecordSize,
771:                            "position=" + p + "ckrecordsize="
772:                                    + checksumLogRecordSize);
773:                    if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) {
774:                        SanityManager.DEBUG(LogToFile.DBG_FLAG,
775:                                "Write log record: tranId=Null"
776:                                        + " instant: "
777:                                        + LogCounter
778:                                                .toDebugString(checksumInstant)
779:                                        + " length: " + checksumLength + "\n"
780:                                        + checksumLogOperation + "\n");
781:                    }
782:                    checksumInstant = -1;
783:                }
784:
785:            }
786:
787:            protected void writeEndMarker(int marker) throws IOException,
788:                    StandardException {
789:                //flush all the buffers and then write the end marker.
790:                flushLogAccessFile();
791:
792:                byte[] b = currentBuffer.buffer;
793:                int p = 0; //end is written in the beginning of the buffer, no
794:                //need to checksum a int write.
795:                p = writeInt(marker, b, p);
796:                writeToLog(b, 0, p);
797:            }
798:
799:        }
ww__w___.__j___a__v__a_2_s___.__c_o_m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.