1 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 ; 32 import java.io.OutputStream ; 33 import java.io.SyncFailedException ; 34 import java.io.InterruptedIOException ; 35 import java.util.LinkedList ; 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 84 public class LogAccessFile 85 { 86 87 93 private static final int LOG_RECORD_FIXED_OVERHEAD_SIZE = 16; 94 private static final int LOG_RECORD_HEADER_SIZE = 12; private static final int LOG_RECORD_TRAILER_SIZE = 4; private static final int LOG_NUMBER_LOG_BUFFERS = 3; 97 98 99 private LinkedList freeBuffers; private LinkedList dirtyBuffers; private LogAccessFileBuffer currentBuffer; private boolean flushInProgress = false; 103 104 private final StorageRandomAccessFile log; 105 106 private final Object logFileSemaphore; 109 110 static int mon_numWritesToLog; 111 static int mon_numBytesToLog; 112 113 114 private ArrayOutputStream logOutputBuffer; 116 private FormatIdOutputStream logicalOut; 117 private boolean directWrite = false; private long checksumInstant = -1; 119 private int checksumLength; 120 private int checksumLogRecordSize; 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; } 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 freeBuffers = new LinkedList (); 146 dirtyBuffers = new LinkedList (); 147 148 149 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 writeChecksum = logFactory.checkVersion(RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10, 164 RawStoreFactory.DERBY_STORE_MINOR_VERSION_1); 165 if(writeChecksum) 166 { 167 171 checksumLogOperation = new ChecksumOperation(); 172 checksumLogOperation.init(); 173 checksumLogRecord = new LogRecord(); 174 175 checksumLogRecord.setValue(null, checksumLogOperation); 181 182 checksumLength = 183 checksumLogRecord.getStoredSize(checksumLogOperation.group(), null) + 184 checksumLogOperation.getStoredSize(); 185 186 if (logFactory.databaseEncrypted()) 188 { 189 checksumLength = logFactory.getEncryptedDataLength(checksumLength); 190 databaseEncrypted = true; 191 } 192 checksumLogRecordSize = checksumLength + LOG_RECORD_FIXED_OVERHEAD_SIZE; 193 194 logOutputBuffer = new ArrayOutputStream(); 196 logicalOut = new FormatIdOutputStream(logOutputBuffer); 197 198 202 }else 203 { 204 checksumLogRecordSize = 0; 206 } 207 208 currentBuffer.init(checksumLogRecordSize); 209 } 210 211 212 private byte[] db = new byte[LOG_RECORD_TRAILER_SIZE]; 213 214 215 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 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 p = writeInt(length, b, p); 268 269 p = writeLong(instant, b , p); 271 272 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 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 p = writeInt(length, b, p); 293 294 currentBuffer.position = p; 295 currentBuffer.bytes_free -= total_log_record_length; 296 } 297 else 298 { 299 300 304 directWrite = true; 305 306 byte[] b = currentBuffer.buffer; 307 int p = currentBuffer.position; 308 309 p = writeInt(length , b, p); 311 312 p = writeLong(instant, b, p); 314 315 currentBuffer.position = p; 316 currentBuffer.bytes_free -= LOG_RECORD_HEADER_SIZE; 317 318 323 324 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 checksumLogOperation.update(db, 0, LOG_RECORD_TRAILER_SIZE); 339 340 writeChecksumLogRecord(); 342 } 343 344 345 347 flushLogAccessFile(); 349 350 356 357 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 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 474 protected void flushDirtyBuffers() throws IOException 475 { 476 LogAccessFileBuffer buf = null; 477 int noOfBuffers; 478 int nFlushed= 0; 479 try{ 480 synchronized(this) 481 { 482 487 while(flushInProgress) 488 { 489 try{ 490 wait(); 491 }catch (InterruptedException ie) 492 { 493 } 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 freeBuffers.addLast(buf); 518 if(nFlushed < noOfBuffers) 519 buf = (LogAccessFileBuffer) dirtyBuffers.removeFirst(); 520 else 521 { 522 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 public void flushLogAccessFile() throws IOException , StandardException 548 { 549 switchLogBuffer(); 550 flushDirtyBuffers(); 551 } 552 553 554 562 public void switchLogBuffer() throws IOException , StandardException 563 { 564 565 synchronized(this) 566 { 567 if(currentBuffer.position == checksumLogRecordSize) 569 return; 570 571 if(writeChecksum && !directWrite) 575 { 576 checksumLogOperation.reset(); 577 checksumLogOperation.update(currentBuffer.buffer, checksumLogRecordSize, currentBuffer.position - checksumLogRecordSize); 578 writeChecksumLogRecord(); 579 } 580 581 dirtyBuffers.addLast(currentBuffer); 583 584 if(freeBuffers.size() == 0) 586 { 587 flushDirtyBuffers(); 588 } 592 593 594 if (SanityManager.DEBUG) 596 SanityManager.ASSERT(freeBuffers.size() > 0); 597 598 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 628 public void syncLogAccessFile() 629 throws IOException , StandardException 630 { 631 for( int i=0; ; ) 632 { 633 try 636 { 637 synchronized( this) 638 { 639 log.sync( false); 640 } 641 642 break; 644 } 645 catch( SyncFailedException sfe ) 646 { 647 i++; 648 try 649 { 650 Thread.sleep( 200 ); 653 } 654 catch( InterruptedException ie ) 655 { } 657 658 if( i > 20 ) 659 throw StandardException.newException( 660 SQLState.LOG_FULL, sfe); 661 } 662 } 663 } 664 665 669 public void corrupt() throws IOException 670 { 671 synchronized(logFileSemaphore) 672 { 673 if (log != null) 674 log.close(); 675 } 676 } 677 678 public void close() throws IOException , 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 699 private void writeToLog(byte b[], int off, int len) throws IOException 700 { 701 synchronized(logFileSemaphore) 702 { 703 if (log != null) 704 { 705 706 for (int i = 0; ;i++) 713 { 714 try 715 { 716 log.write(b, off, len); 717 break; 718 } 719 catch (IOException ioe) 720 { 721 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 746 protected long reserveSpaceForChecksum(int length, long logFileNumber, long currentPosition ) 747 throws StandardException, IOException 748 { 749 750 int total_log_record_length = length + LOG_RECORD_FIXED_OVERHEAD_SIZE; 751 boolean reserveChecksumSpace = false; 752 753 765 766 767 771 if(currentBuffer.position == checksumLogRecordSize) 772 { 773 reserveChecksumSpace = writeChecksum; 775 } 776 else{ 777 if (total_log_record_length > currentBuffer.bytes_free) 778 { 779 switchLogBuffer(); 783 reserveChecksumSpace = writeChecksum; 785 } 786 } 787 788 if(reserveChecksumSpace) 789 { 790 if (SanityManager.DEBUG) 791 { 792 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 809 private void writeChecksumLogRecord() throws IOException , StandardException 810 { 811 812 byte[] b = currentBuffer.buffer; 813 int p = 0; 815 p = writeInt(checksumLength, b , p); 817 818 p = writeLong(checksumInstant, b , p); 820 821 logOutputBuffer.setData(b); 823 logOutputBuffer.setPosition(p); 824 logicalOut.writeObject(checksumLogRecord); 825 826 if(databaseEncrypted) 827 { 828 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 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 , StandardException 862 { 863 flushLogAccessFile(); 865 866 byte[] b = currentBuffer.buffer; 867 int p = 0; 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 |