1 21 22 package org.apache.derby.impl.store.raw.log; 23 24 import org.apache.derby.iapi.services.diag.Performance; 25 26 import org.apache.derby.impl.store.raw.log.CheckpointOperation; 27 import org.apache.derby.impl.store.raw.log.LogCounter; 28 import org.apache.derby.impl.store.raw.log.LogRecord; 29 import org.apache.derby.impl.store.raw.log.StreamLogScan; 30 31 import org.apache.derby.iapi.services.context.ErrorStringBuilder; 33 34 import org.apache.derby.iapi.services.info.ProductGenusNames; 35 import org.apache.derby.iapi.services.info.ProductVersionHolder; 36 37 import org.apache.derby.iapi.reference.MessageId; 38 import org.apache.derby.iapi.reference.Property; 39 import org.apache.derby.iapi.reference.SQLState; 40 41 import org.apache.derby.iapi.services.daemon.DaemonService; 42 import org.apache.derby.iapi.services.daemon.Serviceable; 43 import org.apache.derby.iapi.services.context.ContextManager; 44 import org.apache.derby.iapi.services.context.ContextService; 45 import org.apache.derby.iapi.services.context.ShutdownException; 46 import org.apache.derby.iapi.services.monitor.Monitor; 47 import org.apache.derby.iapi.services.monitor.ModuleControl; 48 import org.apache.derby.iapi.services.monitor.ModuleSupportable; 49 import org.apache.derby.iapi.services.monitor.PersistentService; 50 import org.apache.derby.iapi.services.sanity.SanityManager; 51 import org.apache.derby.iapi.services.io.Formatable; 52 import org.apache.derby.iapi.services.io.TypedFormat; 53 import org.apache.derby.iapi.services.io.FormatIdUtil; 54 import org.apache.derby.iapi.services.io.StoredFormatIds; 55 import org.apache.derby.iapi.services.stream.HeaderPrintWriter; 56 import org.apache.derby.iapi.services.stream.PrintWriterGetHeader; 57 import org.apache.derby.iapi.services.stream.InfoStreams; 58 import org.apache.derby.iapi.error.StandardException; 59 import org.apache.derby.iapi.services.i18n.MessageService; 60 import org.apache.derby.iapi.store.access.AccessFactory; 61 import org.apache.derby.iapi.store.access.AccessFactoryGlobals; 62 import org.apache.derby.iapi.store.access.TransactionController; 63 import org.apache.derby.iapi.store.raw.Loggable; 64 import org.apache.derby.iapi.store.raw.RawStoreFactory; 65 import org.apache.derby.iapi.store.raw.ScanHandle; 66 import org.apache.derby.iapi.store.raw.log.LogFactory; 67 import org.apache.derby.iapi.store.raw.log.Logger; 68 import org.apache.derby.iapi.store.raw.log.LogInstant; 69 import org.apache.derby.iapi.store.raw.log.LogScan; 70 import org.apache.derby.iapi.store.raw.Transaction; 71 import org.apache.derby.iapi.store.raw.xact.RawTransaction; 72 import org.apache.derby.iapi.store.raw.xact.TransactionFactory; 73 import org.apache.derby.iapi.store.raw.data.DataFactory; 74 import org.apache.derby.iapi.services.property.PersistentSet; 75 76 import org.apache.derby.iapi.store.access.DatabaseInstant; 77 import org.apache.derby.catalog.UUID; 78 import org.apache.derby.iapi.services.uuid.UUIDFactory; 79 import org.apache.derby.iapi.services.property.PropertyUtil; 80 import org.apache.derby.iapi.reference.Attribute; 81 import org.apache.derby.iapi.services.io.FileUtil; 82 import org.apache.derby.iapi.util.ReuseFactory; 83 84 import org.apache.derby.io.StorageFactory; 85 import org.apache.derby.io.WritableStorageFactory; 86 import org.apache.derby.io.StorageFile; 87 import org.apache.derby.io.StorageRandomAccessFile; 88 89 import java.io.File ; import java.io.IOException ; 91 import java.io.SyncFailedException ; 92 import java.io.ByteArrayOutputStream ; 93 import java.io.DataOutputStream ; 94 import java.io.ByteArrayInputStream ; 95 import java.io.DataInputStream ; 96 import java.io.FileNotFoundException ; 97 98 import java.net.MalformedURLException ; 99 import java.net.URL ; 100 101 import java.util.Properties ; 102 import java.util.Vector ; 103 import java.util.zip.CRC32 ; 104 105 214 215 public final class LogToFile implements LogFactory, ModuleControl, ModuleSupportable, 216 Serviceable, java.security.PrivilegedExceptionAction 217 { 218 219 private static int fid = StoredFormatIds.FILE_STREAM_LOG_FILE; 220 221 223 226 public int getTypeFormatId() { 227 return StoredFormatIds.FILE_STREAM_LOG_FILE; 228 } 229 230 public static final int LOG_FILE_HEADER_SIZE = 24; 236 237 protected static final int LOG_FILE_HEADER_PREVIOUS_LOG_INSTANT_OFFSET = LOG_FILE_HEADER_SIZE-8; 238 239 public static final int LOG_RECORD_OVERHEAD = 4+8+4; 243 244 public static final String DBG_FLAG = SanityManager.DEBUG ? "LogTrace" : null; 245 public static final String DUMP_LOG_ONLY = SanityManager.DEBUG ? "DumpLogOnly" : null; 246 public static final String DUMP_LOG_FROM_LOG_FILE = 247 SanityManager.DEBUG ? "derby.storage.logDumpStart" : null; 248 protected static final String LOG_SYNC_STATISTICS = "LogSyncStatistics"; 249 250 private static final int OBSOLETE_LOG_VERSION_NUMBER = 9; 256 257 258 private static final int DEFAULT_LOG_SWITCH_INTERVAL = 1024*1024; 259 private static final int LOG_SWITCH_INTERVAL_MIN = 100000; 260 private static final int LOG_SWITCH_INTERVAL_MAX = 128*1024*1024; 261 private static final int CHECKPOINT_INTERVAL_MIN = 100000; 262 private static final int CHECKPOINT_INTERVAL_MAX = 128*1024*1024; 263 private static final int DEFAULT_CHECKPOINT_INTERVAL = 10*1024*1024; 264 265 private static final int DEFAULT_LOG_BUFFER_SIZE = 32768; private static final int LOG_BUFFER_SIZE_MIN = 8192; private static final int LOG_BUFFER_SIZE_MAX = LOG_SWITCH_INTERVAL_MAX; 269 private int logBufferSize = DEFAULT_LOG_BUFFER_SIZE; 270 271 272 private static final byte IS_BETA_FLAG = 0x1; 273 274 291 private static final byte IS_DURABILITY_TESTMODE_NO_SYNC_FLAG = 0x2; 292 293 297 private static boolean wasDBInDurabilityTestModeNoSync = false; 298 299 302 private static final String DEFAULT_LOG_ARCHIVE_DIRECTORY = "DEFAULT"; 303 304 private int logSwitchInterval = DEFAULT_LOG_SWITCH_INTERVAL; 305 private int checkpointInterval = DEFAULT_CHECKPOINT_INTERVAL; 306 307 String dataDirectory; private WritableStorageFactory logStorageFactory; 309 310 private boolean logBeingFlushed; 313 protected LogAccessFile logOut; private StorageRandomAccessFile firstLog = null; 316 protected long endPosition = -1; long lastFlush = 0; 320 long logFileNumber = -1; 330 long firstLogFileNumber = -1; 331 341 private long maxLogFileNumber = LogCounter.MAX_LOGFILE_NUMBER; 342 private CheckpointOperation currentCheckpoint; 343 348 long checkpointInstant; 349 351 private DaemonService checkpointDaemon; 354 private int myClientNumber; 355 357 private volatile boolean checkpointDaemonCalled; 358 363 private long logWrittenFromLastCheckPoint = 0; 364 private RawStoreFactory rawStoreFactory; 366 368 protected DataFactory dataFactory; 369 371 protected boolean ReadOnlyDB; 374 375 private boolean keepAllLogs; 377 378 private boolean databaseEncrypted; 380 381 private boolean recoveryNeeded = true; private boolean inCheckpoint = false; private boolean inRedo = false; private boolean inLogSwitch = false; 387 388 private boolean stopped = false; 390 391 String logDevice; 394 395 private boolean logNotSynced = false; 397 398 private volatile boolean logArchived = false; 399 private boolean logSwitchRequired = false; 400 401 402 int test_logWritten = 0; 403 int test_numRecordToFillLog = -1; 404 private int mon_flushCalls; 405 private int mon_syncCalls; 406 private int mon_numLogFlushWaits; 407 private boolean mon_LogSyncStatistics; 408 private int mon_numBytesToLog; 409 410 411 414 protected volatile StandardException corrupt; 415 416 419 private boolean isFrozen; 420 421 424 ProductVersionHolder jbmsVersion; 425 426 430 private int onDiskMajorVersion; 431 private int onDiskMinorVersion; 432 private boolean onDiskBeta; 433 434 private CRC32 checksum = new CRC32 (); 436 437 457 458 461 private boolean isWriteSynced = false; 462 463 464 private volatile long logFileToBackup ; 467 private volatile boolean backupInProgress = false; 470 471 472 475 public LogToFile() { 476 keepAllLogs = PropertyUtil.getSystemBoolean(RawStoreFactory.KEEP_TRANSACTION_LOG); 477 478 479 if (Performance.MEASURE) 480 mon_LogSyncStatistics = PropertyUtil.getSystemBoolean(LOG_SYNC_STATISTICS); 481 } 482 483 486 487 490 public StandardException markCorrupt(StandardException originalError) { 491 492 boolean firsttime = false; 493 494 synchronized (this) 495 { 496 if (corrupt == null && originalError != null) 497 { 498 corrupt = originalError; 499 firsttime = true; 500 } 501 } 502 503 if (corrupt == originalError) 505 logErrMsg(corrupt); 506 507 508 if (firsttime) 511 { 512 synchronized(this) 513 { 514 stopped = true; 515 516 if (logOut != null) 517 { 518 try 519 { 520 logOut.corrupt(); } 522 catch (IOException ioe) 523 { 524 } 526 } 527 528 logOut = null; 530 } 531 532 if (dataFactory != null) 533 dataFactory.markCorrupt(null); 534 535 } 536 537 return originalError; 538 } 539 540 private void checkCorrupt() throws StandardException 541 { 542 synchronized (this) 543 { 544 if (corrupt != null) 545 { 546 throw StandardException.newException( 547 SQLState.LOG_STORE_CORRUPT, corrupt); 548 } 549 } 550 } 551 552 555 556 559 public Logger getLogger() { 560 561 if (ReadOnlyDB) 562 return null; 563 else 564 return new FileLogger(this); 565 } 566 567 589 public void recover( 590 RawStoreFactory rsf, 591 DataFactory df, 592 TransactionFactory tf) 593 throws StandardException 594 { 595 if (SanityManager.DEBUG) 596 { 597 SanityManager.ASSERT(rsf != null, "raw store factory == null"); 598 SanityManager.ASSERT(df != null, "data factory == null"); 599 } 600 601 checkCorrupt(); 602 603 rawStoreFactory = rsf; 604 dataFactory = df; 605 606 if (firstLog != null) 610 logOut = new LogAccessFile(this, firstLog, logBufferSize); 611 612 618 if (recoveryNeeded) 619 { 620 try 621 { 622 634 FileLogger logger = (FileLogger)getLogger(); 635 636 if (checkpointInstant != LogCounter.INVALID_LOG_INSTANT) 642 { 643 currentCheckpoint = 644 findCheckpoint(checkpointInstant, logger); 645 } 646 647 if (SanityManager.DEBUG) 650 { 651 if (SanityManager.DEBUG_ON(DUMP_LOG_ONLY)) 652 { 653 currentCheckpoint = null; 654 655 System.out.println("Dump log only"); 656 657 String beginLogFileNumber = 659 PropertyUtil.getSystemProperty( 660 DUMP_LOG_FROM_LOG_FILE); 661 662 if (beginLogFileNumber != null) 663 { 664 logFileNumber = 665 Long.valueOf(beginLogFileNumber).longValue(); 666 } 667 else 668 { 669 logFileNumber = 1; 670 } 671 } 672 } 673 674 if (SanityManager.DEBUG) 675 { 676 if (SanityManager.DEBUG_ON("setCheckpoint")) 677 { 678 currentCheckpoint = null; 679 680 System.out.println("Set Checkpoint."); 681 682 String checkpointStartLogStr = 684 PropertyUtil.getSystemProperty( 685 "derby.storage.checkpointStartLog"); 686 687 String checkpointStartOffsetStr = 688 PropertyUtil.getSystemProperty( 689 "derby.storage.checkpointStartOffset"); 690 691 692 if ((checkpointStartLogStr != null) && 693 (checkpointStartOffsetStr != null)) 694 { 695 checkpointInstant = 696 LogCounter.makeLogInstantAsLong( 697 Long.valueOf(checkpointStartLogStr).longValue(), 698 Long.valueOf(checkpointStartOffsetStr).longValue()); 699 } 700 else 701 { 702 SanityManager.THROWASSERT( 703 "must set derby.storage.checkpointStartLog and derby.storage.checkpointStartOffset, if setting setCheckpoint."); 704 } 705 706 currentCheckpoint = 707 findCheckpoint(checkpointInstant, logger); 708 } 709 } 710 711 long redoLWM = LogCounter.INVALID_LOG_INSTANT; 712 long undoLWM = LogCounter.INVALID_LOG_INSTANT; 713 long ttabInstant = LogCounter.INVALID_LOG_INSTANT; 714 715 StreamLogScan redoScan = null; 716 if (currentCheckpoint != null) 717 { 718 Formatable transactionTable = null; 719 720 723 tf.useTransactionTable(transactionTable); 725 726 redoLWM = currentCheckpoint.redoLWM(); 727 undoLWM = currentCheckpoint.undoLWM(); 728 729 if (transactionTable != null) 730 ttabInstant = checkpointInstant; 731 732 if (SanityManager.DEBUG) 733 { 734 if (SanityManager.DEBUG_ON(DBG_FLAG)) 735 { 736 SanityManager.DEBUG(DBG_FLAG, 737 "Found checkpoint at " + 738 LogCounter.toDebugString(checkpointInstant) + 739 " " + currentCheckpoint.toString()); 740 } 741 } 742 743 firstLogFileNumber = LogCounter.getLogFileNumber(redoLWM); 744 745 if (LogCounter.getLogFileNumber(undoLWM) < 747 firstLogFileNumber) 748 { 749 firstLogFileNumber = 750 LogCounter.getLogFileNumber(undoLWM); 751 } 752 753 754 759 redoScan = (StreamLogScan) 760 openForwardsScan(undoLWM, (LogInstant)null); 761 762 } 763 else 764 { 765 tf.useTransactionTable((Formatable)null); 767 768 long start = 769 LogCounter.makeLogInstantAsLong( 770 logFileNumber, LOG_FILE_HEADER_SIZE); 771 772 firstLogFileNumber = logFileNumber; 775 776 redoScan = (StreamLogScan) 777 openForwardsScan(start, (LogInstant)null); 778 } 779 780 RawTransaction recoveryTransaction = 782 tf.startTransaction( 783 rsf, 784 ContextService.getFactory().getCurrentContextManager(), 785 AccessFactoryGlobals.USER_TRANS_NAME); 786 787 recoveryTransaction.recoveryTransaction(); 790 791 797 inRedo = true; 810 811 long logEnd = 812 logger.redo( 813 recoveryTransaction, tf, redoScan, redoLWM, 814 ttabInstant); 815 816 inRedo = false; 817 818 819 820 if (SanityManager.DEBUG) 823 { 824 if (SanityManager.DEBUG_ON(LogToFile.DUMP_LOG_ONLY)) 825 { 826 Monitor.logMessage("_____________________________________________________"); 827 Monitor.logMessage("\n\t\t Log dump finished"); 828 Monitor.logMessage("_____________________________________________________"); 829 logOut = null; 831 832 return; 833 } 834 } 835 836 837 StorageRandomAccessFile theLog = null; 843 844 845 if (logEnd == LogCounter.INVALID_LOG_INSTANT) 849 { 850 Monitor.logTextMessage(MessageId.LOG_LOG_NOT_FOUND); 851 852 StorageFile logFile = getLogFileName(logFileNumber); 853 854 if (privExists(logFile)) 855 { 856 if (!privDelete(logFile)) 859 { 860 logFile = getLogFileName(++logFileNumber); 861 } 862 } 863 864 try 865 { 866 theLog = privRandomAccessFile(logFile, "rw"); 867 } 868 catch (IOException ioe) 869 { 870 theLog = null; 871 } 872 873 if (theLog == null || !privCanWrite(logFile)) 874 { 875 if (theLog != null) 876 theLog.close(); 877 878 theLog = null; 879 880 ReadOnlyDB = true; 881 } 882 else 883 { 884 try 885 { 886 if (!initLogFile( 888 theLog, logFileNumber, 889 LogCounter.INVALID_LOG_INSTANT)) 890 { 891 throw markCorrupt( 892 StandardException.newException( 893 SQLState.LOG_SEGMENT_NOT_EXIST, 894 logFile.getPath())); 895 } 896 } 897 catch (IOException ioe) 898 { 899 throw markCorrupt( 900 StandardException.newException( 901 SQLState.LOG_IO_ERROR, ioe)); 902 } 903 904 endPosition = theLog.getFilePointer(); 907 lastFlush = endPosition; 908 909 if(isWriteSynced) 912 { 913 preAllocateNewLogFile(theLog); 915 theLog.close(); 916 theLog = openLogFileInWriteMode(logFile); 917 theLog.seek(endPosition); 919 } 920 921 if (SanityManager.DEBUG) 922 { 923 SanityManager.ASSERT( 924 endPosition == LOG_FILE_HEADER_SIZE, 925 "empty log file has wrong size"); 926 } 927 928 logSwitchRequired = false; 932 } 933 } 934 else 935 { 936 logFileNumber = LogCounter.getLogFileNumber(logEnd); 940 941 ReadOnlyDB = df.isReadOnly(); 942 943 StorageFile logFile = getLogFileName(logFileNumber); 944 945 if (!ReadOnlyDB) 946 { 947 try 950 { 951 if(isWriteSynced) 952 theLog = openLogFileInWriteMode(logFile); 953 else 954 theLog = privRandomAccessFile(logFile, "rw"); 955 } 956 catch (IOException ioe) 957 { 958 theLog = null; 959 } 960 if (theLog == null || !privCanWrite(logFile)) 961 { 962 if (theLog != null) 963 theLog.close(); 964 theLog = null; 965 966 ReadOnlyDB = true; 967 } 968 } 969 970 if (!ReadOnlyDB) 971 { 972 endPosition = LogCounter.getLogFilePosition(logEnd); 973 974 1006 if (redoScan.isLogEndFuzzy()) 1008 { 1009 theLog.seek(endPosition); 1010 long eof = theLog.length(); 1011 1012 Monitor.logTextMessage(MessageId.LOG_INCOMPLETE_LOG_RECORD, 1013 logFile, new Long (endPosition), new Long (eof)); 1014 1015 1016 long nWrites = (eof - endPosition)/logBufferSize; 1017 int rBytes = (int)((eof - endPosition) % logBufferSize); 1018 byte zeroBuf[]= new byte[logBufferSize]; 1019 1020 while(nWrites-- > 0) 1022 theLog.write(zeroBuf); 1023 if(rBytes !=0) 1024 theLog.write(zeroBuf, 0, rBytes); 1025 1026 if(!isWriteSynced) 1027 syncFile(theLog); 1028 } 1029 1030 if (SanityManager.DEBUG) 1031 { 1032 if (theLog.length() != endPosition) 1033 { 1034 SanityManager.ASSERT( 1035 theLog.length() > endPosition, 1036 "log end > log file length, bad scan"); 1037 } 1038 } 1039 1040 1043 lastFlush = endPosition; 1044 theLog.seek(endPosition); 1045 } 1046 } 1047 1048 if (theLog != null) 1049 logOut = new LogAccessFile(this, theLog, logBufferSize); 1050 1051 if(logSwitchRequired) 1052 switchLogFile(); 1053 1054 1055 boolean noInFlightTransactions = tf.noActiveUpdateTransaction(); 1056 1057 if (ReadOnlyDB) 1058 { 1059 if (!noInFlightTransactions) 1064 { 1065 throw StandardException.newException( 1066 SQLState.LOG_READ_ONLY_DB_NEEDS_UNDO); 1067 } 1068 } 1069 1070 1078 if (SanityManager.DEBUG) 1079 { 1080 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1081 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1082 "About to call undo(), transaction table =" + 1083 tf.getTransactionTable()); 1084 } 1085 1086 if (!noInFlightTransactions) 1087 { 1088 if (SanityManager.DEBUG) 1089 { 1090 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1091 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1092 "In recovery undo, rollback inflight transactions"); 1093 } 1094 1095 tf.rollbackAllTransactions(recoveryTransaction, rsf); 1096 1097 if (SanityManager.DEBUG) 1098 { 1099 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1100 SanityManager.DEBUG( 1101 LogToFile.DBG_FLAG, "finish recovery undo,"); 1102 } 1103 } 1104 else 1105 { 1106 if (SanityManager.DEBUG) 1107 { 1108 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1109 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1110 "No in flight transaction, no recovery undo work"); 1111 } 1112 } 1113 1114 1126 if (SanityManager.DEBUG) 1127 { 1128 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1129 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1130 "About to call rePrepare(), transaction table =" + 1131 tf.getTransactionTable()); 1132 } 1133 1134 tf.handlePreparedXacts(rsf); 1135 1136 if (SanityManager.DEBUG) 1137 { 1138 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 1139 SanityManager.DEBUG(LogToFile.DBG_FLAG, 1140 "Finished rePrepare(), transaction table =" + 1141 tf.getTransactionTable()); 1142 } 1143 1144 1150 recoveryTransaction.close(); 1152 1153 1154 dataFactory.postRecovery(); 1157 1158 1159 tf.resetTranId(); 1166 1167 if (!ReadOnlyDB) 1170 { 1171 boolean needCheckpoint = true; 1172 1173 if (currentCheckpoint != null && noInFlightTransactions && 1177 redoLWM != LogCounter.INVALID_LOG_INSTANT && 1178 undoLWM != LogCounter.INVALID_LOG_INSTANT) 1179 { 1180 if ((logFileNumber == LogCounter.getLogFileNumber(redoLWM)) 1181 && (logFileNumber == LogCounter.getLogFileNumber(undoLWM)) 1182 && (endPosition < (LogCounter.getLogFilePosition(redoLWM) + 1000))) 1183 needCheckpoint = false; 1184 } 1185 1186 if (needCheckpoint && !checkpoint(rsf, df, tf, false)) 1187 flush(logFileNumber, endPosition); 1188 } 1189 1190 logger.close(); 1191 1192 recoveryNeeded = false; 1193 } 1194 catch (IOException ioe) 1195 { 1196 if (SanityManager.DEBUG) 1197 ioe.printStackTrace(); 1198 1199 throw markCorrupt( 1200 StandardException.newException(SQLState.LOG_IO_ERROR, ioe)); 1201 } 1202 catch (ClassNotFoundException cnfe) 1203 { 1204 throw markCorrupt( 1205 StandardException.newException( 1206 SQLState.LOG_CORRUPTED, cnfe)); 1207 } 1208 catch (StandardException se) 1209 { 1210 throw markCorrupt(se); 1211 } 1212 catch (Throwable th) 1213 { 1214 if (SanityManager.DEBUG) 1215 { 1216 SanityManager.showTrace(th); 1217 th.printStackTrace(); 1218 } 1219 1220 throw markCorrupt( 1221 StandardException.newException( 1222 SQLState.LOG_RECOVERY_FAILED, th)); 1223 } 1224 } 1225 else 1226 { 1227 1228 tf.useTransactionTable((Formatable)null); 1229 1230 tf.resetTranId(); 1232 } 1233 1234 1236 checkpointDaemon = rawStoreFactory.getDaemon(); 1240 if (checkpointDaemon != null) 1241 { 1242 myClientNumber = 1243 checkpointDaemon.subscribe(this, true ); 1244 } 1245 } 1246 1247 1248 1347 public boolean checkpoint(RawStoreFactory rsf, 1348 DataFactory df, 1349 TransactionFactory tf, 1350 boolean wait) 1351 throws StandardException 1352 { 1353 1354 boolean done = checkpointWithTran(null, rsf, df, tf); 1356 1357 1365 if(!done && wait) 1366 { 1367 synchronized(this) 1368 { 1369 while(inCheckpoint) 1371 { 1372 try 1373 { 1374 wait(); 1375 } 1376 catch (InterruptedException ie) 1377 { 1378 throw StandardException.interrupt(ie); 1379 } 1380 } 1381 done = true; 1382 } 1383 } 1384 1385 return done; 1386 } 1387 1388 1389 1394 protected boolean checkpointWithTran(RawTransaction cptran, 1395 RawStoreFactory rsf, 1396 DataFactory df, 1397 TransactionFactory tf) 1398 throws StandardException 1399 { 1400 boolean proceed = true; 1401 LogInstant redoLWM; 1402 1403 if (logOut == null) 1406 { 1407 return false; 1408 } 1409 1410 long approxLogLength; 1411 1412 synchronized (this) 1413 { 1414 if (corrupt != null) 1416 { 1417 throw StandardException.newException(SQLState.LOG_STORE_CORRUPT, corrupt); 1418 } 1419 1420 if (inCheckpoint == true) 1422 proceed = false; 1423 else 1424 inCheckpoint = true; 1425 1426 approxLogLength = endPosition; 1428 } 1430 1431 if (!proceed) 1432 { 1433 return false; 1434 } 1435 1436 boolean needCPTran = (cptran == null); 1438 1439 if (SanityManager.DEBUG) 1440 { 1441 if (logSwitchInterval == 0) 1442 { 1443 SanityManager.THROWASSERT( 1444 "switching log file: Approx log length = " + 1445 approxLogLength + " logSwitchInterval = 0"); 1446 } 1447 } 1448 1449 1450 try 1451 { 1452 if (approxLogLength > logSwitchInterval) 1453 { 1454 switchLogFile(); 1455 logWrittenFromLastCheckPoint = 0; 1458 }else 1459 { 1460 logWrittenFromLastCheckPoint = -endPosition; 1468 } 1469 1470 if (SanityManager.DEBUG) 1471 { 1472 1474 if (SanityManager.DEBUG_ON(TEST_LOG_SWITCH_LOG)) 1475 return false; 1476 } 1477 1478 1479 if (needCPTran) 1481 cptran = tf.startInternalTransaction(rsf, 1482 ContextService.getFactory().getCurrentContextManager()); 1483 1484 long undoLWM_long; 1488 long redoLWM_long; 1489 1490 synchronized(this) { 1494 redoLWM_long = currentInstant(); 1498 redoLWM = new LogCounter(redoLWM_long); 1499 1500 1505 LogCounter undoLWM = (LogCounter)(tf.firstUpdateInstant()); 1506 if (undoLWM == null) 1507 undoLWM_long = redoLWM_long; else 1509 undoLWM_long = undoLWM.getValueAsLong(); 1510 1511 } 1512 1513 df.checkpoint(); 1517 1518 1519 1523 Formatable transactionTable = tf.getTransactionTable(); 1525 1526 CheckpointOperation nextCheckpoint = 1527 new CheckpointOperation( 1528 redoLWM_long, undoLWM_long, transactionTable); 1529 1530 cptran.logAndDo(nextCheckpoint); 1531 1532 LogCounter checkpointInstant = 1533 (LogCounter)(cptran.getLastLogInstant()); 1534 1535 if (checkpointInstant != null) 1536 { 1537 flush(checkpointInstant); 1540 } 1541 else 1542 { 1543 throw StandardException.newException( 1544 SQLState.LOG_CANNOT_LOG_CHECKPOINT); 1545 } 1546 1547 cptran.commit(); 1548 1549 if (needCPTran) 1550 { 1551 cptran.close(); cptran = null; 1553 } 1554 1555 1560 if (!writeControlFile(getControlFileName(), 1561 checkpointInstant.getValueAsLong())) 1562 { 1563 throw StandardException.newException( 1564 SQLState.LOG_CONTROL_FILE, getControlFileName()); 1565 } 1566 1567 currentCheckpoint = nextCheckpoint; 1569 1570 1571 1575 if (!logArchived()) 1576 { 1577 truncateLog(currentCheckpoint); 1578 } 1579 1580 if(!backupInProgress) 1586 df.removeDroppedContainerFileStubs(redoLWM); 1587 1588 } 1589 catch (IOException ioe) 1590 { 1591 throw markCorrupt( 1592 StandardException.newException(SQLState.LOG_IO_ERROR, ioe)); 1593 } 1594 finally 1595 { 1596 synchronized(this) 1597 { 1598 1599 1600 inCheckpoint = false; 1601 notifyAll(); 1602 } 1603 1604 if (cptran != null && needCPTran) 1605 { 1606 try 1607 { 1608 cptran.commit(); 1609 cptran.close(); 1610 } 1611 catch (StandardException se) 1612 { 1613 throw markCorrupt(StandardException.newException( 1614 SQLState.LOG_CORRUPTED, se)); 1615 } 1616 } 1617 } 1618 1619 return true; 1620 } 1621 1622 1633 public void flush(LogInstant where) throws StandardException 1634 { 1635 long fileNumber; 1636 long wherePosition; 1637 1638 if (where == null) { 1639 fileNumber = 0; 1642 wherePosition = LogCounter.INVALID_LOG_INSTANT; 1643 } else { 1644 LogCounter whereC = (LogCounter) where; 1645 fileNumber = whereC.getLogFileNumber(); 1646 wherePosition = whereC.getLogFilePosition(); 1647 } 1648 flush(fileNumber, wherePosition); 1649 } 1650 1651 1659 public void flushAll() throws StandardException 1660 { 1661 long fnum; 1662 long whereTo; 1663 1664 synchronized(this) 1665 { 1666 fnum = logFileNumber; 1667 whereTo = endPosition; 1668 } 1669 1670 flush(fnum, whereTo); 1671 } 1672 1673 1676 1677 1690 private boolean verifyLogFormat(StorageFile logFileName, long number) 1691 throws StandardException 1692 { 1693 boolean ret = false; 1694 try 1695 { 1696 StorageRandomAccessFile log = privRandomAccessFile(logFileName, "r"); 1697 ret = verifyLogFormat(log, number); 1698 log.close(); 1699 } 1700 catch (IOException ioe) 1701 { 1702 1703 } 1704 1705 return ret; 1706 } 1707 1708 1722 private boolean verifyLogFormat(StorageRandomAccessFile log, long number) 1723 throws StandardException 1724 { 1725 try 1726 { 1727 log.seek(0); 1728 int logfid = log.readInt(); 1729 int obsoleteLogVersion = log.readInt(); long logNumber = log.readLong(); 1732 1733 if (logfid != fid || logNumber != number) 1734 { 1735 throw StandardException.newException( 1736 SQLState.LOG_INCOMPATIBLE_FORMAT, dataDirectory); 1737 } 1738 } 1739 catch (IOException ioe) 1740 { 1741 throw StandardException.newException( 1742 SQLState.LOG_CANNOT_VERIFY_LOG_FORMAT, ioe, dataDirectory); 1743 } 1744 1745 return true; 1746 } 1747 1748 1763 1764 private boolean initLogFile(StorageRandomAccessFile newlog, long number, 1765 long prevLogRecordEndInstant) 1766 throws IOException , StandardException 1767 { 1768 if (newlog.length() != 0) 1769 return false; 1770 1771 if (SanityManager.DEBUG) 1772 { 1773 if ( SanityManager.DEBUG_ON(TEST_LOG_FULL)) 1774 testLogFull(); 1775 } 1776 if (SanityManager.DEBUG) 1777 { 1778 if (SanityManager.DEBUG_ON(TEST_SWITCH_LOG_FAIL1)) 1779 throw new IOException ("TestLogSwitchFail1"); 1780 } 1781 1782 1783 newlog.seek(0); 1784 1785 newlog.writeInt(fid); 1786 newlog.writeInt(OBSOLETE_LOG_VERSION_NUMBER); newlog.writeLong(number); 1788 newlog.writeLong(prevLogRecordEndInstant); 1789 1790 syncFile(newlog); 1791 1792 return true; 1793 } 1794 1795 1801 private void switchLogFile() throws StandardException 1802 { 1803 boolean switchedOver = false; 1804 1805 synchronized (this) 1817 { 1818 1819 while(logBeingFlushed | isFrozen) 1825 { 1826 try 1827 { 1828 wait(); 1829 } 1830 catch (InterruptedException ie) 1831 { 1832 throw StandardException.interrupt(ie); 1833 } 1834 } 1835 1836 if (endPosition == LOG_FILE_HEADER_SIZE) 1838 { 1839 if (SanityManager.DEBUG) 1840 { 1841 Monitor.logMessage("not switching from an empty log file (" + 1842 logFileNumber + ")"); 1843 } 1844 return; 1845 } 1846 1847 StorageFile newLogFile = getLogFileName(logFileNumber+1); 1850 1851 if (logFileNumber+1 >= maxLogFileNumber) 1852 { 1853 throw StandardException.newException( 1854 SQLState.LOG_EXCEED_MAX_LOG_FILE_NUMBER, 1855 new Long (maxLogFileNumber)); 1856 } 1857 1858 StorageRandomAccessFile newLog = null; try 1860 { 1861 if (privExists(newLogFile) && !privDelete(newLogFile)) 1864 { 1865 logErrMsg(MessageService.getTextMessage( 1866 MessageId.LOG_NEW_LOGFILE_EXIST, 1867 newLogFile.getPath())); 1868 return; 1869 } 1870 1871 try 1872 { 1873 newLog = privRandomAccessFile(newLogFile, "rw"); 1874 } 1875 catch (IOException ioe) 1876 { 1877 newLog = null; 1878 } 1879 1880 if (newLog == null || !privCanWrite(newLogFile)) 1881 { 1882 if (newLog != null) 1883 newLog.close(); 1884 newLog = null; 1885 1886 return; 1887 } 1888 1889 if (initLogFile(newLog, logFileNumber+1, 1890 LogCounter.makeLogInstantAsLong(logFileNumber, endPosition))) 1891 { 1892 1893 switchedOver = true; 1897 1898 1901 logOut.writeEndMarker(0); 1902 1903 endPosition += 4; 1904 inLogSwitch = true; 1907 flush(logFileNumber, endPosition); 1909 1910 1911 if (SanityManager.DEBUG) 1913 { 1914 if (SanityManager.DEBUG_ON(TEST_SWITCH_LOG_FAIL2)) 1915 throw new IOException ("TestLogSwitchFail2"); 1916 } 1917 1918 1919 logOut.close(); 1921 logWrittenFromLastCheckPoint += endPosition; 1922 1923 endPosition = newLog.getFilePointer(); 1924 lastFlush = endPosition; 1925 1926 if(isWriteSynced) 1927 { 1928 preAllocateNewLogFile(newLog); 1930 newLog.close(); 1931 newLog = openLogFileInWriteMode(newLogFile); 1932 newLog.seek(endPosition); 1933 } 1934 1935 logOut = new LogAccessFile(this, newLog, logBufferSize); 1936 newLog = null; 1937 1938 1939 if (SanityManager.DEBUG) 1940 { 1941 if (endPosition != LOG_FILE_HEADER_SIZE) 1942 SanityManager.THROWASSERT( 1943 "new log file has unexpected size" + 1944 + endPosition); 1945 } 1946 logFileNumber++; 1947 1948 if (SanityManager.DEBUG) 1949 { 1950 SanityManager.ASSERT(endPosition == LOG_FILE_HEADER_SIZE, 1951 "empty log file has wrong size"); 1952 } 1953 1954 } 1955 else { 1957 newLog.close(); 1958 newLog = null; 1959 1960 if (privExists(newLogFile)) 1961 privDelete(newLogFile); 1962 newLogFile = null; 1963 1964 logErrMsg(MessageService.getTextMessage( 1965 MessageId.LOG_CANNOT_CREATE_NEW, 1966 newLogFile.getPath())); 1967 } 1968 1969 } 1970 catch (IOException ioe) 1971 { 1972 1973 inLogSwitch = false; 1974 1978 logErrMsg(MessageService.getTextMessage( 1979 MessageId.LOG_CANNOT_CREATE_NEW_DUETO, 1980 newLogFile.getPath(), 1981 ioe.toString())); 1982 1983 try 1984 { 1985 if (newLog != null) 1986 { 1987 newLog.close(); 1988 newLog = null; 1989 } 1990 } 1991 catch (IOException ioe2) {} 1992 1993 if (newLogFile != null && privExists(newLogFile)) 1994 { 1995 privDelete(newLogFile); 1996 newLogFile = null; 1997 } 1998 1999 if (switchedOver) { 2001 logOut = null; throw markCorrupt( 2003 StandardException.newException( 2004 SQLState.LOG_IO_ERROR, ioe)); 2005 } 2006 } 2007 2008 inLogSwitch = false; 2009 } 2010 } 2012 2013 2023 private void flushBuffer(long fileNumber, long wherePosition) 2024 throws IOException , StandardException 2025 { 2026 synchronized (this) { 2027 if (fileNumber < logFileNumber) return; 2029 2030 2037 if (wherePosition < lastFlush) return; 2039 2040 2049 logOut.flushLogAccessFile(); 2050 } 2051 } 2052 2058 private void truncateLog(CheckpointOperation checkpoint) 2059 { 2060 long oldFirstLog; 2061 long firstLogNeeded; 2062 2063 if (keepAllLogs) 2064 return; 2065 if ((firstLogNeeded = getFirstLogNeeded(checkpoint))==-1) 2066 return; 2067 2068 if(backupInProgress) { 2072 long logFileNeededForBackup = logFileToBackup; 2073 if (logFileNeededForBackup < firstLogNeeded) 2079 firstLogNeeded = logFileNeededForBackup; 2080 } 2081 2082 oldFirstLog = firstLogFileNumber; 2083 firstLogFileNumber = firstLogNeeded; 2084 2085 while(oldFirstLog < firstLogNeeded) 2086 { 2087 StorageFile uselessLogFile = null; 2088 try 2089 { 2090 uselessLogFile = getLogFileName(oldFirstLog); 2091 if (privDelete(uselessLogFile)) 2092 { 2093 if (SanityManager.DEBUG) 2094 { 2095 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2096 SanityManager.DEBUG(DBG_FLAG, "truncating useless log file " + uselessLogFile.getPath()); 2097 } 2098 } 2099 else 2100 { 2101 if (SanityManager.DEBUG) 2102 { 2103 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2104 SanityManager.DEBUG(DBG_FLAG, "Fail to truncate useless log file " + uselessLogFile.getPath()); 2105 } 2106 } 2107 } 2108 catch (StandardException se) 2109 { 2110 if (SanityManager.DEBUG) 2111 SanityManager.THROWASSERT("error opening log segment while deleting " 2112 + uselessLogFile.getPath(), se); 2113 2114 } 2116 2117 oldFirstLog++; 2118 } 2119 } 2120 2121 2122 2123 2133 private long getFirstLogNeeded(CheckpointOperation checkpoint) 2134 { 2135 long firstLogNeeded; 2136 2137 synchronized (this) 2139 { 2140 firstLogNeeded = 2141 (checkpoint != null ? 2142 LogCounter.getLogFileNumber(checkpoint.undoLWM()) : -1); 2143 2144 if (SanityManager.DEBUG) 2145 { 2146 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2147 SanityManager.DEBUG(DBG_FLAG, 2148 "truncatLog: undoLWM firstlog needed " + firstLogNeeded); 2149 } 2150 2151 if (SanityManager.DEBUG) 2152 { 2153 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2154 { 2155 SanityManager.DEBUG(DBG_FLAG, 2156 "truncatLog: checkpoint truncationLWM firstlog needed " + 2157 firstLogNeeded); 2158 SanityManager.DEBUG(DBG_FLAG, 2159 "truncatLog: firstLogFileNumber = " + firstLogFileNumber); 2160 } 2161 } 2162 } 2163 return firstLogNeeded; 2164 } 2165 2166 2167 2181 boolean writeControlFile(StorageFile logControlFileName, long value) 2182 throws IOException , StandardException 2183 { 2184 StorageRandomAccessFile logControlFile = null; 2185 2186 ByteArrayOutputStream baos = new ByteArrayOutputStream (64); 2187 DataOutputStream daos = new DataOutputStream (baos); 2188 2189 daos.writeInt(fid); 2190 2191 daos.writeInt(OBSOLETE_LOG_VERSION_NUMBER); 2195 daos.writeLong(value); 2196 2197 if (onDiskMajorVersion == 0) { 2198 onDiskMajorVersion = jbmsVersion.getMajorVersion(); 2199 onDiskMinorVersion = jbmsVersion.getMinorVersion(); 2200 onDiskBeta = jbmsVersion.isBeta(); 2201 } 2202 2203 daos.writeInt(onDiskMajorVersion); 2206 daos.writeInt(onDiskMinorVersion); 2207 2208 daos.writeInt(jbmsVersion.getBuildNumberAsInt()); 2211 2212 byte flags = 0; 2213 if (onDiskBeta) 2214 flags |= IS_BETA_FLAG; 2215 2216 if (logNotSynced || wasDBInDurabilityTestModeNoSync) 2226 flags |= IS_DURABILITY_TESTMODE_NO_SYNC_FLAG; 2227 daos.writeByte(flags); 2228 2229 long spare = 0; 2232 2233 daos.writeByte(0); 2234 daos.writeByte(0); 2235 daos.writeByte(0); 2236 daos.writeLong(spare); 2237 daos.flush(); 2238 checksum.reset(); 2240 checksum.update(baos.toByteArray(), 0, baos.size()); 2241 daos.writeLong(checksum.getValue()); 2242 daos.flush(); 2243 2244 try 2245 { 2246 checkCorrupt(); 2247 2248 try 2249 { 2250 logControlFile = privRandomAccessFile(logControlFileName, "rw"); 2251 } 2252 catch (IOException ioe) 2253 { 2254 logControlFile = null; 2255 return false; 2256 } 2257 2258 if (!privCanWrite(logControlFileName)) 2259 return false; 2260 2261 if (SanityManager.DEBUG) 2262 { 2263 if (SanityManager.DEBUG_ON(TEST_LOG_FULL)) 2264 testLogFull(); 2265 } 2266 2267 logControlFile.seek(0); 2268 logControlFile.write(baos.toByteArray()); 2269 syncFile(logControlFile); 2270 logControlFile.close(); 2271 2272 try 2274 { 2275 logControlFile = 2276 privRandomAccessFile(getMirrorControlFileName(), "rw"); 2277 } 2278 catch (IOException ioe) 2279 { 2280 logControlFile = null; 2281 return false; 2282 } 2283 2284 logControlFile.seek(0); 2285 logControlFile.write(baos.toByteArray()); 2286 syncFile(logControlFile); 2287 2288 } 2289 finally 2290 { 2291 if (logControlFile != null) 2292 logControlFile.close(); 2293 } 2294 2295 return true; 2296 2297 } 2298 2299 2304 private long readControlFile(StorageFile logControlFileName, Properties startParams) 2305 throws IOException , StandardException 2306 { 2307 StorageRandomAccessFile logControlFile = null; 2308 ByteArrayInputStream bais = null; 2309 DataInputStream dais = null; 2310 logControlFile = privRandomAccessFile(logControlFileName, "r"); 2311 boolean upgradeNeeded = false; 2312 long value = LogCounter.INVALID_LOG_INSTANT; 2313 long onDiskChecksum = 0; 2314 long controlFilelength = logControlFile.length(); 2315 byte barray[] = null; 2316 2317 try 2318 { 2319 if (controlFilelength < 16) 2323 onDiskChecksum = -1; 2324 else if (controlFilelength == 16) 2325 { 2326 barray = new byte[16]; 2327 logControlFile.readFully(barray); 2328 }else if (controlFilelength > 16) 2329 { 2330 barray = new byte[(int) logControlFile.length() - 8]; 2331 logControlFile.readFully(barray); 2332 onDiskChecksum = logControlFile.readLong(); 2333 if (onDiskChecksum !=0 ) 2334 { 2335 checksum.reset(); 2336 checksum.update(barray, 0, barray.length); 2337 } 2338 } 2339 2340 if ( onDiskChecksum == checksum.getValue() || onDiskChecksum ==0) 2341 { 2342 2343 bais = new ByteArrayInputStream (barray); 2344 dais = new DataInputStream (bais); 2345 2346 if (dais.readInt() != fid) 2347 { 2348 throw StandardException.newException( 2349 SQLState.LOG_INCOMPATIBLE_FORMAT, dataDirectory); 2350 } 2351 2352 int obsoleteVersion = dais.readInt(); 2353 value = dais.readLong(); 2354 2355 if (SanityManager.DEBUG) 2356 { 2357 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2358 SanityManager.DEBUG(LogToFile.DBG_FLAG, 2359 "log control file ckp instance = " + 2360 LogCounter.toDebugString(value)); 2361 } 2362 2363 2364 onDiskMajorVersion = dais.readInt(); 2368 onDiskMinorVersion = dais.readInt(); 2369 int dbBuildNumber = dais.readInt(); 2370 int flags = dais.readByte(); 2371 2372 wasDBInDurabilityTestModeNoSync = 2378 (flags & IS_DURABILITY_TESTMODE_NO_SYNC_FLAG) != 0; 2379 2380 if (SanityManager.DEBUG) { 2381 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2382 SanityManager.DEBUG(LogToFile.DBG_FLAG, 2383 "log control file, was derby.system.durability set to test = " + 2384 wasDBInDurabilityTestModeNoSync); 2385 } 2386 2387 2388 onDiskBeta = (flags & IS_BETA_FLAG) != 0; 2389 if (onDiskBeta) 2390 { 2391 if (!jbmsVersion.isBeta() || 2394 onDiskMajorVersion != jbmsVersion.getMajorVersion() || 2395 onDiskMinorVersion != jbmsVersion.getMinorVersion()) 2396 { 2397 boolean forceBetaUpgrade = false; 2398 if (SanityManager.DEBUG) 2399 { 2400 if (SanityManager.DEBUG_ON("forceBetaUpgrade")) 2402 { 2403 Monitor.logMessage("WARNING !! : forcing beta upgrade."); 2404 forceBetaUpgrade =true; 2405 } 2406 } 2407 2408 if (!forceBetaUpgrade) 2409 { 2410 throw StandardException.newException( 2411 SQLState.LOG_CANNOT_UPGRADE_BETA, 2412 dataDirectory, 2413 ProductVersionHolder.simpleVersionString(onDiskMajorVersion, onDiskMinorVersion, onDiskBeta)); 2414 } 2415 } 2416 } 2417 2418 2419 if (onDiskMajorVersion > jbmsVersion.getMajorVersion() || 2424 (onDiskMajorVersion == jbmsVersion.getMajorVersion() && 2425 onDiskMinorVersion > jbmsVersion.getMinorVersion())) 2426 { 2427 throw StandardException.newException( 2430 SQLState.LOG_INCOMPATIBLE_VERSION, 2431 dataDirectory, 2432 ProductVersionHolder.simpleVersionString(onDiskMajorVersion, onDiskMinorVersion, onDiskBeta)); 2433 } 2434 2435 if ((onDiskMajorVersion != jbmsVersion.getMajorVersion()) || 2438 (onDiskMinorVersion != jbmsVersion.getMinorVersion())) 2439 { 2440 upgradeNeeded = true; 2441 } 2442 if (onDiskChecksum == 0 && 2445 (!(onDiskMajorVersion <= 3 && onDiskMinorVersion <=5) || 2446 onDiskMajorVersion == 0)) 2447 value = LogCounter.INVALID_LOG_INSTANT; 2448 } 2449 } 2450 finally 2451 { 2452 if (logControlFile != null) 2453 logControlFile.close(); 2454 if (bais != null) 2455 bais.close(); 2456 if (dais != null) 2457 dais.close(); 2458 } 2459 2460 if (upgradeNeeded) 2461 { 2462 if (Monitor.isFullUpgrade(startParams, 2463 ProductVersionHolder.simpleVersionString(onDiskMajorVersion, onDiskMinorVersion, onDiskBeta))) { 2464 2465 onDiskMajorVersion = jbmsVersion.getMajorVersion(); 2466 onDiskMinorVersion = jbmsVersion.getMinorVersion(); 2467 onDiskBeta = jbmsVersion.isBeta(); 2468 2469 2472 if (!writeControlFile(logControlFileName, value)) 2473 { 2474 throw StandardException.newException( 2475 SQLState.LOG_CONTROL_FILE, logControlFileName); 2476 } 2477 } 2478 } 2479 2480 return value; 2481 2482 } 2483 2484 2485 2486 2490 private void createLogDirectory() throws StandardException 2491 { 2492 StorageFile logDir = 2493 logStorageFactory.newStorageFile(LogFactory.LOG_DIRECTORY_NAME); 2494 2495 if (privExists(logDir)) { 2496 String [] logfiles = privList(logDir); 2498 if (logfiles != null) { 2499 if(logfiles.length != 0) { 2500 throw StandardException.newException( 2501 SQLState.LOG_SEGMENT_EXIST, logDir.getPath()); 2502 } 2503 } 2504 2505 }else { 2506 if (!privMkdirs(logDir)) { 2508 throw StandardException.newException( 2509 SQLState.LOG_SEGMENT_NOT_EXIST, logDir.getPath()); 2510 } 2511 } 2512 } 2513 2514 2520 public StorageFile getLogDirectory() throws StandardException 2521 { 2522 StorageFile logDir = null; 2523 2524 logDir = logStorageFactory.newStorageFile( LogFactory.LOG_DIRECTORY_NAME); 2525 2526 if (!privExists(logDir)) 2527 { 2528 throw StandardException.newException( 2529 SQLState.LOG_SEGMENT_NOT_EXIST, logDir.getPath()); 2530 } 2531 2532 return logDir; 2533 } 2534 2535 public String getCanonicalLogPath() 2536 { 2537 if (logDevice == null) 2538 return null; 2539 else 2540 { 2541 try 2542 { 2543 return logStorageFactory.getCanonicalName(); 2544 } 2545 catch (IOException ioe) 2546 { 2547 return null; 2548 } 2550 } 2551 } 2552 2553 2554 2559 private StorageFile getControlFileName() throws StandardException 2560 { 2561 return logStorageFactory.newStorageFile( getLogDirectory(), "log.ctrl"); 2562 } 2563 2564 2569 private StorageFile getMirrorControlFileName() throws StandardException 2570 { 2571 return logStorageFactory.newStorageFile( getLogDirectory(), "logmirror.ctrl"); 2572 } 2573 2574 2579 private StorageFile getLogFileName(long filenumber) throws StandardException 2580 { 2581 return logStorageFactory.newStorageFile( getLogDirectory(), "log" + filenumber + ".dat"); 2582 } 2583 2584 2589 private CheckpointOperation findCheckpoint(long checkpointInstant, FileLogger logger) 2590 throws IOException , StandardException, ClassNotFoundException 2591 { 2592 StreamLogScan scan = (StreamLogScan) 2593 openForwardsScan(checkpointInstant, (LogInstant)null); 2594 2595 Loggable lop = logger.readLogRecord(scan, 100); 2598 2599 scan.close(); 2600 2601 if (lop instanceof CheckpointOperation) 2602 return (CheckpointOperation)lop; 2603 else 2604 return null; 2605 } 2606 2607 2608 2611 2612 2620 protected LogScan openBackwardsScan(long startAt, LogInstant stopAt) 2621 throws IOException , StandardException 2622 { 2623 checkCorrupt(); 2624 2625 if (startAt == LogCounter.INVALID_LOG_INSTANT) 2627 return openBackwardsScan(stopAt); 2628 2629 2630 flushBuffer(LogCounter.getLogFileNumber(startAt), 2632 LogCounter.getLogFilePosition(startAt)); 2633 2634 return new Scan(this, startAt, stopAt, Scan.BACKWARD); 2635 } 2636 2637 2644 protected LogScan openBackwardsScan(LogInstant stopAt) 2645 throws IOException , StandardException 2646 { 2647 checkCorrupt(); 2648 2649 long startAt; 2653 synchronized (this) 2654 { 2655 logOut.flushLogAccessFile(); 2658 startAt = currentInstant(); 2659 } 2660 2661 return new Scan(this, startAt, stopAt, Scan.BACKWARD_FROM_LOG_END); 2662 } 2663 2664 2668 public ScanHandle openFlushedScan(DatabaseInstant start,int groupsIWant) 2669 throws StandardException 2670 { 2671 return new FlushedScanHandle(this,start,groupsIWant); 2672 } 2673 2674 2675 2676 2689 protected LogScan openForwardsScan(long startAt, LogInstant stopAt) 2690 throws IOException , StandardException 2691 { 2692 checkCorrupt(); 2693 2694 if (startAt == LogCounter.INVALID_LOG_INSTANT) 2695 { 2696 startAt = firstLogInstant(); 2697 } 2698 2699 if (stopAt != null) { 2701 LogCounter stopCounter = (LogCounter) stopAt; 2702 flushBuffer(stopCounter.getLogFileNumber(), 2703 stopCounter.getLogFilePosition()); 2704 } else { 2705 synchronized (this) { 2706 if (logOut != null) 2707 logOut.flushLogAccessFile(); 2709 } 2710 } 2711 2712 return new Scan(this, startAt, stopAt, Scan.FORWARD); 2713 } 2714 2715 2718 2719 2728 protected StorageRandomAccessFile getLogFileAtBeginning(long filenumber) 2729 throws IOException , StandardException 2730 { 2731 long instant = LogCounter.makeLogInstantAsLong(filenumber, 2732 LOG_FILE_HEADER_SIZE); 2733 return getLogFileAtPosition(instant); 2734 } 2735 2736 2737 2746 protected StorageRandomAccessFile getLogFileAtPosition(long logInstant) 2747 throws IOException , StandardException 2748 { 2749 checkCorrupt(); 2750 2751 long filenum = LogCounter.getLogFileNumber(logInstant); 2752 long filepos = LogCounter.getLogFilePosition(logInstant); 2753 2754 StorageFile fileName = getLogFileName(filenum); 2755 if (!privExists(fileName)) 2756 { 2757 if (SanityManager.DEBUG) 2758 { 2759 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2760 SanityManager.DEBUG(LogToFile.DBG_FLAG, fileName.getPath() + " does not exist"); 2761 } 2762 2763 return null; 2764 } 2765 2766 2767 StorageRandomAccessFile log = null; 2768 2769 try 2770 { 2771 log = privRandomAccessFile(fileName, "r"); 2772 2773 if (!verifyLogFormat(log, filenum)) 2775 { 2776 if (SanityManager.DEBUG) 2777 { 2778 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 2779 SanityManager.DEBUG(LogToFile.DBG_FLAG, fileName.getPath() + " format mismatch"); 2780 } 2781 2782 log.close(); 2783 log = null; 2784 } 2785 else 2786 { 2787 log.seek(filepos); 2788 } 2789 } 2790 catch (IOException ioe) 2791 { 2792 try 2793 { 2794 if (log != null) 2795 { 2796 log.close(); 2797 log = null; 2798 } 2799 2800 if (SanityManager.DEBUG) 2801 { 2802 SanityManager.THROWASSERT("cannot get to position " + filepos + 2803 " for log file " + fileName.getPath(), ioe); 2804 } 2805 } 2806 catch (IOException ioe2) 2807 {} 2808 throw ioe; 2809 } 2810 2811 return log; 2812 2813 } 2814 2815 2818 2819 public boolean canSupport(Properties startParams) 2820 { 2821 String runtimeLogAttributes = startParams.getProperty(LogFactory.RUNTIME_ATTRIBUTES); 2822 if (runtimeLogAttributes != null) { 2823 if (runtimeLogAttributes.equals(LogFactory.RT_READONLY)) 2824 return false; 2825 } 2826 2827 return true; 2828 } 2829 2830 2831 2832 2833 2839 public void boot(boolean create, Properties startParams) throws StandardException 2840 { 2841 dataDirectory = startParams.getProperty(PersistentService.ROOT); 2842 2843 logDevice = startParams.getProperty(Attribute.LOG_DEVICE); 2844 if( logDevice != null) 2845 { 2846 String logDeviceURL = null; 2848 try { 2849 URL url = new URL (logDevice); 2850 logDeviceURL = url.getFile(); 2851 } catch (MalformedURLException ex) {} 2852 if (logDeviceURL != null) 2853 logDevice = logDeviceURL; 2854 } 2855 2856 2857 if(create) { 2858 getLogStorageFactory(); 2859 createLogDirectory(); 2860 2861 } else { 2862 if (!restoreLogs(startParams)) { 2865 getLogStorageFactory(); 2867 if (logDevice != null) 2868 { 2869 StorageFile checklogDir = 2875 logStorageFactory.newStorageFile( 2876 LogFactory.LOG_DIRECTORY_NAME); 2877 if (!privExists(checklogDir)) 2878 { 2879 throw 2880 StandardException.newException( 2881 SQLState.LOG_FILE_NOT_FOUND, checklogDir.getPath()); 2882 2883 } 2884 } 2885 } 2886 } 2887 2888 logBufferSize = PropertyUtil.getSystemInt(org.apache.derby.iapi.reference.Property.LOG_BUFFER_SIZE, 2891 LOG_BUFFER_SIZE_MIN, 2892 LOG_BUFFER_SIZE_MAX, 2893 DEFAULT_LOG_BUFFER_SIZE); 2894 jbmsVersion = Monitor.getMonitor().getEngineVersion(); 2895 2896 2897 String logArchiveMode = 2898 startParams.getProperty(Property.LOG_ARCHIVE_MODE); 2899 logArchived = Boolean.valueOf(logArchiveMode).booleanValue(); 2900 2901 getLogFactoryProperties(null); 2903 2904 2907 2908 if (logStorageFactory.supportsRws()) 2909 { 2910 isWriteSynced = 2913 !(PropertyUtil.getSystemBoolean(Property.FILESYNC_TRANSACTION_LOG)); 2914 } 2915 else 2916 { 2917 isWriteSynced = false; 2918 } 2919 2920 2921 if (Property.DURABILITY_TESTMODE_NO_SYNC.equalsIgnoreCase( 2925 PropertyUtil.getSystemProperty(Property.DURABILITY_PROPERTY))) 2926 { 2927 logNotSynced = true; 2929 isWriteSynced = false; 2931 } 2932 else if (Performance.MEASURE) 2933 { 2934 2940 logNotSynced = 2941 PropertyUtil.getSystemBoolean( 2942 Property.STORAGE_LOG_NOT_SYNCED); 2943 2944 if (logNotSynced) 2945 { 2946 isWriteSynced = false; 2947 Monitor.logMessage("Performance.logNotSynced = true"); 2948 } 2949 } 2950 2951 2955 boolean createNewLog = create; 2956 2957 if (SanityManager.DEBUG) 2958 SanityManager.ASSERT(fid != -1, "invalid log format Id"); 2959 2960 checkpointInstant = LogCounter.INVALID_LOG_INSTANT; 2961 try 2962 { 2963 StorageFile logControlFileName = getControlFileName(); 2964 2965 StorageFile logFile; 2966 2967 if (!createNewLog) 2968 { 2969 if (privExists(logControlFileName)) 2970 { 2971 checkpointInstant = 2972 readControlFile(logControlFileName, startParams); 2973 2974 if (wasDBInDurabilityTestModeNoSync) 2978 { 2979 Monitor.logMessage(MessageService.getTextMessage( 2983 MessageId.LOG_WAS_IN_DURABILITY_TESTMODE_NO_SYNC, 2984 Property.DURABILITY_PROPERTY, 2985 Property.DURABILITY_TESTMODE_NO_SYNC)); 2986 } 2987 2988 if (checkpointInstant == LogCounter.INVALID_LOG_INSTANT && 2989 privExists(getMirrorControlFileName())) 2990 { 2991 checkpointInstant = 2992 readControlFile( 2993 getMirrorControlFileName(), startParams); 2994 } 2995 2996 } 2997 else if (logDevice != null) 2998 { 2999 throw StandardException.newException( 3004 SQLState.LOG_FILE_NOT_FOUND, 3005 logControlFileName.getPath()); 3006 } 3007 3008 if (checkpointInstant != LogCounter.INVALID_LOG_INSTANT) 3009 logFileNumber = LogCounter.getLogFileNumber(checkpointInstant); 3010 else 3011 logFileNumber = 1; 3012 3013 logFile = getLogFileName(logFileNumber); 3014 3015 3018 if (!privExists(logFile)) 3019 { 3020 if (logDevice != null) 3021 { 3022 throw StandardException.newException( 3023 SQLState.LOG_FILE_NOT_FOUND, 3024 logControlFileName.getPath()); 3025 } 3026 3027 logErrMsg(MessageService.getTextMessage( 3028 MessageId.LOG_MAYBE_INCONSISTENT, 3029 logFile.getPath())); 3030 3031 createNewLog = true; 3032 } 3033 else if (!verifyLogFormat(logFile, logFileNumber)) 3034 { 3035 Monitor.logTextMessage(MessageId.LOG_DELETE_INCOMPATIBLE_FILE, logFile); 3036 3037 if (!privDelete(logFile) && logFileNumber == 1) 3039 { 3040 logErrMsgForDurabilityTestModeNoSync(); 3041 throw StandardException.newException( 3042 SQLState.LOG_INCOMPATIBLE_FORMAT, dataDirectory); 3043 } 3044 3045 3049 createNewLog = true; 3050 } 3051 } 3052 3053 if (createNewLog) 3054 { 3055 3057 if (writeControlFile(logControlFileName, 3060 LogCounter.INVALID_LOG_INSTANT)) 3061 { 3062 firstLogFileNumber = 1; 3063 logFileNumber = 1; 3064 if (SanityManager.DEBUG) 3065 { 3066 if (SanityManager.DEBUG_ON(TEST_MAX_LOGFILE_NUMBER)) 3067 { 3068 firstLogFileNumber = 3072 LogCounter.MAX_LOGFILE_NUMBER -2; 3073 3074 logFileNumber = LogCounter.MAX_LOGFILE_NUMBER -2; 3075 } 3076 } 3077 logFile = getLogFileName(logFileNumber); 3078 3079 if (privExists(logFile)) 3080 { 3081 Monitor.logTextMessage( 3085 MessageId.LOG_DELETE_OLD_FILE, logFile); 3086 3087 if (!privDelete(logFile)) 3088 { 3089 logErrMsgForDurabilityTestModeNoSync(); 3090 throw StandardException.newException( 3091 SQLState.LOG_INCOMPATIBLE_FORMAT, 3092 dataDirectory); 3093 } 3094 } 3095 3096 firstLog = privRandomAccessFile(logFile, "rw"); 3098 3099 if (!initLogFile(firstLog, logFileNumber, LogCounter.INVALID_LOG_INSTANT)) 3100 { 3101 throw StandardException.newException( 3102 SQLState.LOG_SEGMENT_NOT_EXIST, logFile.getPath()); 3103 } 3104 3105 endPosition = firstLog.getFilePointer(); 3106 lastFlush = firstLog.getFilePointer(); 3107 3108 if(isWriteSynced) 3111 { 3112 preAllocateNewLogFile(firstLog); 3114 firstLog.close(); 3115 firstLog = openLogFileInWriteMode(logFile); 3116 firstLog.seek(endPosition); 3118 } 3119 3120 if (SanityManager.DEBUG) 3121 { 3122 SanityManager.ASSERT( 3123 endPosition == LOG_FILE_HEADER_SIZE, 3124 "empty log file has wrong size"); 3125 } 3126 } 3127 else 3128 { 3129 ReadOnlyDB = true; 3131 logOut = null; 3132 firstLog = null; 3133 } 3134 3135 recoveryNeeded = false; 3136 } 3137 else 3138 { 3139 recoveryNeeded = true; 3141 } 3142 3143 } 3144 catch (IOException ioe) 3145 { 3146 throw Monitor.exceptionStartingModule(ioe); 3147 } 3148 3149 3157 if (!checkVersion(RawStoreFactory.DERBY_STORE_MAJOR_VERSION_10, 3160 RawStoreFactory.DERBY_STORE_MINOR_VERSION_1)) 3161 maxLogFileNumber = LogCounter.DERBY_10_0_MAX_LOGFILE_NUMBER; 3162 3163 } 3165 private void getLogStorageFactory() throws StandardException 3166 { 3167 if( logDevice == null) 3168 { 3169 DataFactory df = (DataFactory) Monitor.findServiceModule( this, DataFactory.MODULE); 3170 logStorageFactory = (WritableStorageFactory) df.getStorageFactory(); 3171 } 3172 else 3173 { 3174 try 3175 { 3176 PersistentService ps = Monitor.getMonitor().getServiceType(this); 3177 logStorageFactory = (WritableStorageFactory) ps.getStorageFactoryInstance( false, logDevice, null, null); 3178 } 3179 catch( IOException ioe) 3180 { 3181 if( SanityManager.DEBUG) 3182 SanityManager.NOTREACHED(); 3183 throw StandardException.newException( SQLState.LOG_FILE_NOT_FOUND, ioe, logDevice); 3184 } 3185 } 3186 } 3188 3194 public void stop() { 3195 3196 3197 if (checkpointDaemon != null) { 3199 checkpointDaemon.unsubscribe(myClientNumber); 3200 checkpointDaemon.stop(); 3201 } 3202 3203 synchronized(this) 3204 { 3205 stopped = true; 3206 3207 if (logOut != null) { 3208 try { 3209 logOut.flushLogAccessFile(); 3210 logOut.close(); 3211 } 3212 catch (IOException ioe) {} 3213 catch(StandardException se){} 3214 logOut = null; 3215 } 3216 } 3217 3218 3219 if (SanityManager.DEBUG && 3220 Performance.MEASURE && 3221 mon_LogSyncStatistics) 3222 { 3223 Monitor.logMessage("number of times someone waited = " + 3224 mon_numLogFlushWaits + 3225 "\nnumber of times flush is called = " + 3226 mon_flushCalls + 3227 "\nnumber of sync is called = " + 3228 mon_syncCalls + 3229 "\ntotal number of bytes written to log = " + 3230 LogAccessFile.mon_numBytesToLog + 3231 "\ntotal number of writes to log file = " + 3232 LogAccessFile.mon_numWritesToLog); 3233 } 3234 3235 3236 if(corrupt == null && ! logArchived() && !keepAllLogs && !ReadOnlyDB) 3238 deleteObsoleteLogfiles(); 3239 3240 if( logDevice != null) 3241 logStorageFactory.shutdown(); 3242 logStorageFactory = null; 3243 } 3244 3245 3246 3247 3251 3252 private void deleteObsoleteLogfiles(){ 3253 StorageFile logDir; 3254 long firstLogNeeded = getFirstLogNeeded(currentCheckpoint); 3256 if (firstLogNeeded == -1) 3257 return; 3258 3259 if(backupInProgress) { 3263 long logFileNeededForBackup = logFileToBackup; 3264 if (logFileNeededForBackup < firstLogNeeded) 3270 firstLogNeeded = logFileNeededForBackup; 3271 } 3272 3273 try{ 3274 logDir = getLogDirectory(); 3275 }catch (StandardException se) 3276 { 3277 if (SanityManager.DEBUG) 3278 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3279 SanityManager.DEBUG(DBG_FLAG, "error opening log segment dir"); 3280 return; 3281 } 3282 3283 String [] logfiles = privList(logDir); 3284 if (logfiles != null) 3285 { 3286 StorageFile uselessLogFile = null; 3287 long fileNumber; 3288 for(int i=0 ; i < logfiles.length; i++) 3289 { 3290 if(logfiles[i].startsWith("log") && logfiles[i].endsWith(".dat")) 3292 { 3293 fileNumber = Long.parseLong(logfiles[i].substring(3, (logfiles[i].length() -4))); 3294 if(fileNumber < firstLogNeeded ) 3295 { 3296 uselessLogFile = logStorageFactory.newStorageFile(logDir, logfiles[i]); 3297 if (privDelete(uselessLogFile)) 3298 { 3299 if (SanityManager.DEBUG) 3300 { 3301 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3302 SanityManager.DEBUG(DBG_FLAG, "truncating obsolete log file " + uselessLogFile.getPath()); 3303 } 3304 } 3305 else 3306 { 3307 if (SanityManager.DEBUG) 3308 { 3309 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3310 SanityManager.DEBUG(DBG_FLAG, "Fail to truncate obsolete log file " + uselessLogFile.getPath()); 3311 } 3312 } 3313 } 3314 } 3315 } 3316 } 3317 } 3318 3319 3322 3323 public boolean serviceASAP() 3324 { 3325 return false; 3326 } 3327 3328 public boolean serviceImmediately() 3330 { 3331 return false; 3332 } 3333 3334 3335 public void getLogFactoryProperties(PersistentSet set) 3336 throws StandardException 3337 { 3338 String lsInterval; 3339 String cpInterval; 3340 if(set == null) 3341 { 3342 lsInterval=PropertyUtil.getSystemProperty(org.apache.derby.iapi.reference.Property.LOG_SWITCH_INTERVAL); 3343 cpInterval=PropertyUtil.getSystemProperty(org.apache.derby.iapi.reference.Property.CHECKPOINT_INTERVAL); 3344 }else 3345 { 3346 lsInterval = PropertyUtil.getServiceProperty(set, org.apache.derby.iapi.reference.Property.LOG_SWITCH_INTERVAL); 3347 cpInterval = PropertyUtil.getServiceProperty(set, org.apache.derby.iapi.reference.Property.CHECKPOINT_INTERVAL); 3348 } 3349 3350 3351 if (lsInterval != null) 3352 { 3353 logSwitchInterval = Integer.parseInt(lsInterval); 3354 if (logSwitchInterval < LOG_SWITCH_INTERVAL_MIN) 3356 logSwitchInterval = LOG_SWITCH_INTERVAL_MIN; 3357 else if (logSwitchInterval > LOG_SWITCH_INTERVAL_MAX) 3358 logSwitchInterval = LOG_SWITCH_INTERVAL_MAX; 3359 } 3360 3361 3362 if (cpInterval != null) 3363 { 3364 checkpointInterval = Integer.parseInt(cpInterval); 3365 if (checkpointInterval < CHECKPOINT_INTERVAL_MIN) 3366 checkpointInterval = CHECKPOINT_INTERVAL_MIN; 3367 else if(checkpointInterval > CHECKPOINT_INTERVAL_MAX) 3368 checkpointInterval = CHECKPOINT_INTERVAL_MAX; 3369 } 3370 } 3371 3372 public int performWork(ContextManager context) 3373 { 3374 synchronized(this) 3375 { 3376 if (corrupt != null) 3377 return Serviceable.DONE; } 3379 3380 AccessFactory af = 3382 (AccessFactory)Monitor.getServiceModule(this, AccessFactory.MODULE); 3383 3384 try 3385 { 3386 if (af != null) 3387 { 3388 TransactionController tc = null; 3389 try 3390 { 3391 tc = af.getAndNameTransaction( 3392 context, AccessFactoryGlobals.SYS_TRANS_NAME); 3393 3394 getLogFactoryProperties(tc); 3395 } 3396 finally 3397 { 3398 if (tc != null) 3399 tc.commit(); 3400 } 3401 } 3402 3403 rawStoreFactory.checkpoint(); 3406 } 3407 catch (StandardException se) 3408 { 3409 Monitor.logTextMessage(MessageId.LOG_CHECKPOINT_EXCEPTION); 3410 logErrMsg(se); 3411 } 3412 catch (ShutdownException shutdown) 3413 { 3414 } 3417 3418 checkpointDaemonCalled = false; 3419 3420 return Serviceable.DONE; 3421 } 3422 3423 3424 3427 3428 3442 protected long appendLogRecord(byte[] data, int offset, int length, 3443 byte[] optionalData, int optionalDataOffset, int optionalDataLength) 3444 throws StandardException 3445 { 3446 long instant; 3447 boolean testIncompleteLogWrite = false; 3448 3449 if (ReadOnlyDB) 3450 { 3451 throw StandardException.newException( 3452 SQLState.LOG_READ_ONLY_DB_UPDATE); 3453 } 3454 3455 if (length <= 0) 3456 { 3457 throw StandardException.newException( 3458 SQLState.LOG_ZERO_LENGTH_LOG_RECORD); 3459 } 3460 3461 if (SanityManager.DEBUG) 3463 { 3464 if (SanityManager.DEBUG_ON(TEST_LOG_INCOMPLETE_LOG_WRITE)) 3465 { 3466 return logtest_appendPartialLogRecord(data, offset, length, 3472 optionalData, 3473 optionalDataOffset, 3474 optionalDataLength); 3475 3476 } 3477 3478 } 3479 3480 try 3481 { 3482 if (SanityManager.DEBUG) 3483 { 3484 if (SanityManager.DEBUG_ON(TEST_LOG_FULL)) 3485 testLogFull(); } 3488 3489 synchronized (this) 3490 { 3491 if (corrupt != null) 3493 { 3494 throw StandardException.newException( 3495 SQLState.LOG_STORE_CORRUPT, corrupt); 3496 } 3497 3498 if (logOut == null) 3499 { 3500 throw StandardException.newException(SQLState.LOG_NULL); 3501 } 3502 3503 3513 3514 if ((endPosition + LOG_RECORD_OVERHEAD + length) >= 3517 LogCounter.MAX_LOGFILE_SIZE) 3518 { 3519 switchLogFile(); 3520 3521 if ((endPosition + LOG_RECORD_OVERHEAD + length) >= 3523 LogCounter.MAX_LOGFILE_SIZE) 3524 { 3525 throw StandardException.newException( 3526 SQLState.LOG_EXCEED_MAX_LOG_FILE_SIZE, 3527 new Long (logFileNumber), 3528 new Long (endPosition), 3529 new Long (length), 3530 new Long (LogCounter.MAX_LOGFILE_SIZE)); 3531 } 3532 } 3533 3534 endPosition += logOut.reserveSpaceForChecksum(length, logFileNumber,endPosition); 3536 3537 instant = 3540 LogCounter.makeLogInstantAsLong(logFileNumber, endPosition); 3541 3542 logOut.writeLogRecord( 3543 length, instant, data, offset, 3544 optionalData, optionalDataOffset, optionalDataLength); 3545 3546 if (optionalDataLength != 0) 3547 { 3548 if (SanityManager.DEBUG) 3549 { 3550 if (optionalData == null) 3551 SanityManager.THROWASSERT( 3552 "optionalDataLength = " + optionalDataLength + 3553 " with null Optional data"); 3554 3555 if (optionalData.length < 3556 (optionalDataOffset+optionalDataLength)) 3557 SanityManager.THROWASSERT( 3558 "optionalDataLength = " + optionalDataLength + 3559 " optionalDataOffset = " + optionalDataOffset + 3560 " optionalData.length = " + optionalData.length); 3561 } 3562 } 3563 3564 endPosition += (length + LOG_RECORD_OVERHEAD); 3565 } 3566 } 3567 catch (IOException ioe) 3568 { 3569 throw markCorrupt(StandardException.newException( 3570 SQLState.LOG_FULL, ioe)); 3571 } 3572 3573 return instant; 3574 } 3575 3576 3579 3580 3586 protected synchronized long currentInstant() 3587 { 3588 return LogCounter.makeLogInstantAsLong(logFileNumber, endPosition); 3589 } 3590 3591 protected synchronized long endPosition() 3592 { 3593 return endPosition; 3594 } 3595 3596 3602 private synchronized long getLogFileNumber() 3603 { 3604 return logFileNumber; 3605 } 3606 3607 3613 private synchronized long firstLogInstant() 3614 { 3615 return LogCounter.makeLogInstantAsLong(firstLogFileNumber, LOG_FILE_HEADER_SIZE); 3616 } 3617 3618 3629 protected void flush(long fileNumber, long wherePosition) throws StandardException 3630 { 3631 3632 long potentialLastFlush = 0; 3633 3634 synchronized (this) 3635 { 3636 if (Performance.MEASURE) 3637 mon_flushCalls++; 3638 try 3639 { 3640 boolean waited; 3641 do 3642 { 3643 3650 if (corrupt != null) 3651 { 3652 throw StandardException.newException( 3653 SQLState.LOG_STORE_CORRUPT, corrupt); 3654 } 3655 3656 while (isFrozen) 3658 { 3659 try 3660 { 3661 wait(); 3662 } 3663 catch (InterruptedException ie) 3664 { 3665 throw StandardException.interrupt(ie); 3666 } 3667 } 3668 3669 if (wherePosition == LogCounter.INVALID_LOG_INSTANT || 3675 fileNumber < logFileNumber || 3676 wherePosition < lastFlush) 3677 { 3678 return; 3679 } 3680 3681 if (recoveryNeeded && inRedo) 3685 { 3686 return; 3687 } 3688 3689 3690 if (SanityManager.DEBUG) 3691 { 3692 if (fileNumber > getLogFileNumber()) 3693 SanityManager.THROWASSERT( 3694 "trying to flush a file that is not there yet " + 3695 fileNumber + " " + logFileNumber); 3696 3697 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3698 { 3699 SanityManager.DEBUG( 3700 DBG_FLAG, "Flush log to " + wherePosition); 3701 } 3702 } 3703 3704 if (logBeingFlushed) 3707 { 3708 waited = true; 3709 try 3710 { 3711 if (Performance.MEASURE) 3712 mon_numLogFlushWaits++; 3713 wait(); 3717 } 3721 catch (InterruptedException ie) 3722 { 3723 throw StandardException.interrupt(ie); 3724 } 3725 } 3726 else 3727 { 3728 waited = false; 3729 3730 if(!isWriteSynced) 3732 { 3733 logOut.flushLogAccessFile(); 3735 }else 3736 { 3737 logOut.switchLogBuffer(); 3740 } 3741 3742 potentialLastFlush = endPosition; 3744 logBeingFlushed = true; 3747 } 3748 3749 } while (waited) ; 3750 } 3753 catch (IOException ioe) 3754 { 3755 throw markCorrupt(StandardException.newException( 3756 SQLState.LOG_CANNOT_FLUSH, 3757 ioe, 3758 getLogFileName(logFileNumber).getPath())); 3759 } 3760 } 3762 boolean syncSuceed = false; 3763 try 3764 { 3765 if (SanityManager.DEBUG) 3766 { 3767 SanityManager.ASSERT(logBeingFlushed, 3768 "flushing log without logBeingFlushed set"); 3769 SanityManager.ASSERT(potentialLastFlush > 0, 3770 "potentialLastFlush not set"); 3771 3772 if (SanityManager.DEBUG_ON(TEST_LOG_FULL)) 3773 testLogFull(); 3774 3775 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3776 SanityManager.DEBUG(DBG_FLAG, "Begin log sync..."); 3777 } 3778 3779 3780 if (Performance.MEASURE) 3781 mon_syncCalls++; 3782 3783 if (isWriteSynced) 3784 { 3785 logOut.flushDirtyBuffers(); 3788 } 3789 else 3790 { 3791 if (!logNotSynced) 3792 logOut.syncLogAccessFile(); 3793 } 3794 3795 syncSuceed = true; 3796 3797 if (SanityManager.DEBUG) 3798 { 3799 if (SanityManager.DEBUG_ON(LogToFile.DBG_FLAG)) 3800 SanityManager.DEBUG(DBG_FLAG, "end log sync."); 3801 } 3802 } 3803 catch (SyncFailedException sfe) 3804 { 3805 throw markCorrupt(StandardException.newException( 3806 SQLState.LOG_CANNOT_FLUSH, 3807 sfe, 3808 getLogFileName(logFileNumber).getPath())); 3809 } 3810 catch (IOException ioe) 3811 { 3812 throw markCorrupt(StandardException.newException( 3813 SQLState.LOG_CANNOT_FLUSH, 3814 ioe, 3815 getLogFileName(logFileNumber).getPath())); 3816 } 3817 finally 3818 { 3819 synchronized(this) 3820 { 3821 logBeingFlushed = false; 3823 if (syncSuceed) 3825 { 3826 lastFlush = potentialLastFlush; 3827 } 3828 3829 3830 notifyAll(); 3834 } 3835 } 3836 3837 3838 if ((logWrittenFromLastCheckPoint + potentialLastFlush) > checkpointInterval && 3840 checkpointDaemon != null && !checkpointDaemonCalled && !inLogSwitch) 3841 { 3842 synchronized(this) 3845 { 3846 if ((logWrittenFromLastCheckPoint + potentialLastFlush) > checkpointInterval && 3849 checkpointDaemon != null && !checkpointDaemonCalled && !inLogSwitch) 3850 { 3851 checkpointDaemonCalled = true; 3852 checkpointDaemon.serviceNow(myClientNumber); 3853 } 3854 } 3855 3856 }else 3857 { 3858 if (potentialLastFlush > logSwitchInterval && 3863 !checkpointDaemonCalled && !inLogSwitch) 3864 { 3865 synchronized(this) 3868 { 3869 if (potentialLastFlush > logSwitchInterval && 3872 !checkpointDaemonCalled && !inLogSwitch) 3873 { 3874 inLogSwitch = true; 3875 switchLogFile(); 3876 } 3877 } 3878 } 3879 } 3880 } 3881 3882 3886 private void syncFile( StorageRandomAccessFile raf) 3887 throws StandardException 3888 { 3889 for( int i=0; ; ) 3890 { 3891 try 3894 { 3895 raf.sync( false); 3896 3897 break; 3899 } 3900 catch (IOException ioe) 3901 { 3902 i++; 3903 try 3904 { 3905 Thread.sleep(200); 3908 } 3909 catch( InterruptedException ie ) 3910 { 3911 } 3913 3914 if( i > 20 ) 3915 { 3916 throw StandardException.newException( 3917 SQLState.LOG_FULL, ioe); 3918 } 3919 } 3920 } 3921 } 3922 3923 3924 3930 public LogScan openForwardsFlushedScan(LogInstant startAt) 3931 throws StandardException 3932 { 3933 checkCorrupt(); 3934 3935 3937 return new FlushedScan(this,((LogCounter)startAt).getValueAsLong()); 3938 } 3939 3940 3941 3946 public LogScan openForwardsScan(LogInstant startAt,LogInstant stopAt) 3947 throws StandardException 3948 { 3949 try 3950 { 3951 long startLong; 3952 3953 if (startAt == null) 3954 startLong = LogCounter.INVALID_LOG_INSTANT; 3955 else 3956 startLong = ((LogCounter)startAt).getValueAsLong(); 3957 3958 return openForwardsScan(startLong, stopAt); 3959 } 3960 3961 catch (IOException ioe) 3962 { 3963 throw markCorrupt(StandardException.newException( 3964 SQLState.LOG_IO_ERROR, ioe)); 3965 } 3966 3967 } 3968 3969 public final boolean databaseEncrypted() 3970 { 3971 return databaseEncrypted; 3972 } 3973 3974 3975 3984 public void setDatabaseEncrypted(boolean flushLog) 3985 throws StandardException 3986 { 3987 if (flushLog) 3988 flushAll(); 3989 databaseEncrypted = true; 3990 } 3991 3992 3993 4002 public void startNewLogFile() throws StandardException 4003 { 4004 switchLogFile(); 4006 } 4007 4008 4009 4019 public boolean isCheckpointInLastLogFile() 4020 throws StandardException 4021 { 4022 long logFileNumberAfterCheckpoint = 4024 LogCounter.getLogFileNumber(checkpointInstant) + 1; 4025 4026 StorageFile logFileAfterCheckpoint = 4030 getLogFileName(logFileNumberAfterCheckpoint); 4031 if (privExists(logFileAfterCheckpoint)) 4033 return false; 4034 else 4035 return true; 4036 } 4037 4038 4045 public void deleteLogFileAfterCheckpointLogFile() 4046 throws StandardException 4047 { 4048 long logFileNumberAfterCheckpoint = 4049 LogCounter.getLogFileNumber(checkpointInstant) + 1; 4050 4051 StorageFile logFileAfterCheckpoint = 4052 getLogFileName(logFileNumberAfterCheckpoint); 4053 4054 4056 if (privExists(logFileAfterCheckpoint)) 4057 { 4058 if (!privDelete(logFileAfterCheckpoint)) 4061 { 4062 throw StandardException.newException( 4065 SQLState.UNABLE_TO_DELETE_FILE, 4066 logFileAfterCheckpoint); 4067 } 4068 } 4069 } 4070 4071 4072 4076 public int encrypt(byte[] cleartext, int offset, int length, 4077 byte[] ciphertext, int outputOffset) 4078 throws StandardException 4079 { 4080 return rawStoreFactory.encrypt(cleartext, offset, length, 4081 ciphertext, outputOffset, false); 4082 } 4083 4084 4088 public int decrypt(byte[] ciphertext, int offset, int length, 4089 byte[] cleartext, int outputOffset) 4090 throws StandardException 4091 { 4092 return rawStoreFactory.decrypt(ciphertext, offset, length, cleartext, outputOffset); 4093 } 4094 4095 4098 public int getEncryptionBlockSize() 4099 { 4100 return rawStoreFactory.getEncryptionBlockSize(); 4101 } 4102 4103 4108 public int getEncryptedDataLength(int length) 4109 { 4110 if ((length % getEncryptionBlockSize()) != 0) 4111 { 4112 return length + getEncryptionBlockSize() - (length % getEncryptionBlockSize()); 4113 } 4114 4115 return length; 4116 } 4117 4118 4119 4120 4127 public synchronized LogInstant getFirstUnflushedInstant() 4128 { 4129 if (SanityManager.DEBUG) 4130 SanityManager.ASSERT(logFileNumber > 0 && lastFlush > 0); 4131 4132 return new LogCounter(logFileNumber,lastFlush); 4133 } 4134 4135 4136 4140 public void freezePersistentStore() throws StandardException 4141 { 4142 synchronized(this) 4145 { 4146 isFrozen = true; 4147 } 4148 } 4149 4150 4154 public void unfreezePersistentStore() throws StandardException 4155 { 4156 synchronized(this) 4157 { 4158 isFrozen = false; 4159 notifyAll(); 4160 } 4161 } 4162 4163 4167 public boolean logArchived() 4168 { 4169 return logArchived; 4170 } 4171 4172 4179 boolean checkVersion(int requiredMajorVersion, int requiredMinorVersion) 4180 { 4181 if(onDiskMajorVersion > requiredMajorVersion ) 4182 { 4183 return true; 4184 } 4185 else 4186 { 4187 if(onDiskMajorVersion == requiredMajorVersion && 4188 onDiskMinorVersion >= requiredMinorVersion) 4189 return true; 4190 } 4191 4192 return false; 4193 } 4194 4195 4196 4211 public boolean checkVersion(int requiredMajorVersion, 4212 int requiredMinorVersion, 4213 String feature) throws StandardException 4214 { 4215 4216 boolean isRequiredVersion = 4217 checkVersion(requiredMajorVersion, requiredMinorVersion); 4218 4219 if (!isRequiredVersion && feature != null) 4222 { 4223 throw StandardException.newException( 4224 SQLState.LANG_STATEMENT_UPGRADE_REQUIRED, feature, 4225 ProductVersionHolder.simpleVersionString(onDiskMajorVersion, 4226 onDiskMinorVersion, 4227 onDiskBeta), 4228 ProductVersionHolder.simpleVersionString(requiredMajorVersion, 4229 requiredMinorVersion, 4230 false)); 4231 } 4232 4233 return isRequiredVersion; 4234 } 4235 4236 4237 4247 4248 4249 4253 protected void logErrMsg(String msg) 4254 { 4255 logErrMsgForDurabilityTestModeNoSync(); 4256 Monitor.logTextMessage(MessageId.LOG_BEGIN_ERROR); 4257 Monitor.logMessage(msg); 4258 Monitor.logTextMessage(MessageId.LOG_END_ERROR); 4259 } 4260 4261 4265 protected void logErrMsg(Throwable t) 4266 { 4267 logErrMsgForDurabilityTestModeNoSync(); 4268 if (corrupt != null) 4269 { 4270 Monitor.logTextMessage(MessageId.LOG_BEGIN_CORRUPT_STACK); 4271 printErrorStack(corrupt); 4272 Monitor.logTextMessage(MessageId.LOG_END_CORRUPT_STACK); 4273 } 4274 4275 if (t != corrupt) 4276 { 4277 Monitor.logTextMessage(MessageId.LOG_BEGIN_ERROR_STACK); 4278 printErrorStack(t); 4279 Monitor.logTextMessage(MessageId.LOG_END_ERROR_STACK); 4280 } 4281 } 4282 4283 4284 4294 private void logErrMsgForDurabilityTestModeNoSync() 4295 { 4296 if (logNotSynced || wasDBInDurabilityTestModeNoSync) 4297 { 4298 Monitor.logTextMessage( 4299 MessageId.LOG_DURABILITY_TESTMODE_NO_SYNC_ERR, 4300 Property.DURABILITY_PROPERTY, 4301 Property.DURABILITY_TESTMODE_NO_SYNC); 4302 } 4303 } 4304 4305 4310 private void printErrorStack(Throwable t) 4311 { 4312 ErrorStringBuilder esb = 4313 new ErrorStringBuilder(Monitor.getStream().getHeader()); 4314 esb.stackTrace(t); 4315 Monitor.logMessage(esb.get().toString()); 4316 esb.reset(); 4317 } 4318 4319 4320 4323 4328 private long logtest_appendPartialLogRecord(byte[] data, int offset, 4329 int length, 4330 byte[] optionalData, 4331 int optionalDataOffset, 4332 int optionalDataLength) 4333 throws StandardException 4334 { 4335 if (SanityManager.DEBUG) 4336 { 4337 int bytesToWrite = 1; 4338 4339 String TestPartialLogWrite = PropertyUtil.getSystemProperty(TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES); 4340 if (TestPartialLogWrite != null) 4341 { 4342 bytesToWrite = Integer.valueOf(TestPartialLogWrite).intValue(); 4343 } 4344 4345 Monitor.logMessage("TEST_LOG_INCOMPLETE_LOG_WRITE: writing " + bytesToWrite + 4346 " bytes out of " + length + " + " + LOG_RECORD_OVERHEAD + " log record"); 4347 4348 long instant; 4349 try 4350 { 4351 4352 synchronized (this) 4353 { 4354 endPosition += 4357 logOut.reserveSpaceForChecksum(((length + LOG_RECORD_OVERHEAD) 4358 < bytesToWrite ? length : 4359 (bytesToWrite - LOG_RECORD_OVERHEAD)), 4360 logFileNumber,endPosition); 4361 instant = currentInstant(); 4362 4363 if(length + LOG_RECORD_OVERHEAD < bytesToWrite) 4366 endPosition += (length + LOG_RECORD_OVERHEAD); 4367 else 4368 endPosition += bytesToWrite; 4369 4370 while(true) { 4373 if (bytesToWrite < 4) 4374 { 4375 int shift = 3; 4376 while(bytesToWrite-- > 0) 4377 { 4378 logOut.write((byte)((length >>> 8*shift) & 0xFF)); 4379 shift--; 4380 } 4381 break; 4382 } 4383 4384 logOut.writeInt(length); 4386 bytesToWrite -= 4; 4387 4388 if (bytesToWrite < 8) 4389 { 4390 int shift = 7; 4391 while(bytesToWrite-- > 0) 4392 { 4393 logOut.write((byte)((instant >>> 8*shift) & 0xFF)); 4394 shift--; 4395 } 4396 break; 4397 } 4398 4399 logOut.writeLong(instant); 4401 bytesToWrite -= 8; 4402 4403 if (bytesToWrite < length) 4404 { 4405 int dataLength = length - optionalDataLength; 4406 if(bytesToWrite < dataLength) 4407 logOut.write(data, offset,bytesToWrite); 4408 else 4409 { 4410 logOut.write(data, offset, dataLength); 4411 bytesToWrite -= dataLength ; 4412 if(optionalDataLength != 0 && bytesToWrite > 0) 4413 logOut.write(optionalData, optionalDataOffset, bytesToWrite); 4414 } 4415 break; 4416 } 4417 4418 logOut.write(data, offset, length - optionalDataLength); 4420 if(optionalDataLength != 0) 4422 logOut.write(optionalData, optionalDataOffset, optionalDataLength); 4423 4424 bytesToWrite -= length; 4425 4426 if (bytesToWrite < 4) 4427 { 4428 int shift = 3; 4429 while(bytesToWrite-- > 0) 4430 { 4431 logOut.write((byte)((length >>> 8*shift) & 0xFF)); 4432 shift--; 4433 } 4434 break; 4435 } 4436 4437 logOut.writeInt(length); 4439 break; 4440 4441 } 4442 4443 flush(logFileNumber, endPosition); 4445 4446 } 4447 4448 4449 } 4450 catch (IOException ioe) 4451 { 4452 throw StandardException.newException(SQLState.LOG_FULL, ioe); 4453 } 4454 4455 return instant; 4456 } 4457 return 0; 4458 } 4459 4460 4469 protected void testLogFull() throws IOException 4470 { 4471 if (SanityManager.DEBUG) 4472 { 4473 if (test_numRecordToFillLog < 0) 4474 { 4475 String RecordToFillLog = PropertyUtil.getSystemProperty(TEST_RECORD_TO_FILL_LOG); 4476 if (RecordToFillLog != null) 4477 test_numRecordToFillLog = Integer.valueOf(RecordToFillLog).intValue(); 4478 else 4479 test_numRecordToFillLog = 100; 4480 } 4481 4482 if (++test_logWritten > test_numRecordToFillLog) 4483 throw new IOException ("TestLogFull " + test_numRecordToFillLog + 4484 " written " + test_logWritten); 4485 4486 } 4487 } 4488 4489 4493 public StorageRandomAccessFile getLogFileToSimulateCorruption(long filenum) throws IOException , StandardException 4494 { 4495 if (SanityManager.DEBUG) 4496 { 4497 StorageFile fileName = getLogFileName(filenum); 4500 StorageRandomAccessFile log = null; 4501 return privRandomAccessFile(fileName, "rw"); 4502 } 4503 4504 return null; 4505 4506 } 4507 4508 4509 4516 4517 4521 public static final String TEST_LOG_SWITCH_LOG = SanityManager.DEBUG ? "TEST_LOG_SWITCH_LOG" : null ; 4522 4523 4529 public static final String TEST_LOG_INCOMPLETE_LOG_WRITE = SanityManager.DEBUG ? "TEST_LOG_INCOMPLETE_LOG_WRITE" : null; 4530 4531 4536 public static final String TEST_LOG_PARTIAL_LOG_WRITE_NUM_BYTES = SanityManager.DEBUG ? "derbyTesting.unittest.partialLogWrite" : null; 4537 4538 4541 public static final String TEST_LOG_FULL = 4542 SanityManager.DEBUG ? "TEST_LOG_FULL" : null; 4543 4544 4547 public static final String TEST_SWITCH_LOG_FAIL1 = 4548 SanityManager.DEBUG ? "TEST_SWITCH_LOG_FAIL1" : null; 4549 public static final String TEST_SWITCH_LOG_FAIL2 = 4550 SanityManager.DEBUG ? "TEST_SWITCH_LOG_FAIL2" : null; 4551 4552 4553 4557 public static final String TEST_RECORD_TO_FILL_LOG = 4558 SanityManager.DEBUG ? "derbyTesting.unittest.recordToFillLog" : null; 4559 4560 4564 public static final String TEST_MAX_LOGFILE_NUMBER = 4565 SanityManager.DEBUG ? "testMaxLogFileNumber" : null; 4566 4567 4568 public void enableLogArchiveMode() throws StandardException 4570 { 4571 4572 if(!logArchived) 4574 { 4575 logArchived = true; 4576 AccessFactory af = 4577 (AccessFactory)Monitor.getServiceModule(this, AccessFactory.MODULE); 4578 4579 if (af != null) 4580 { 4581 TransactionController tc = null; 4582 tc = af.getTransaction( 4583 ContextService.getFactory().getCurrentContextManager()); 4584 tc.setProperty(Property.LOG_ARCHIVE_MODE , "true", true); 4585 } 4586 } 4587 } 4588 4589 public void disableLogArchiveMode() throws StandardException 4591 { 4592 AccessFactory af = 4593 (AccessFactory)Monitor.getServiceModule(this, AccessFactory.MODULE); 4594 if (af != null) 4595 { 4596 TransactionController tc = null; 4597 tc = af.getTransaction(ContextService.getFactory().getCurrentContextManager()); 4598 tc.setProperty(Property.LOG_ARCHIVE_MODE , "false", true); 4599 } 4600 logArchived = false; 4601 } 4602 4603 public void deleteOnlineArchivedLogFiles() 4605 { 4606 deleteObsoleteLogfiles(); 4607 } 4608 4609 4610 4638 public void startLogBackup(File toDir) throws StandardException 4639 { 4640 4641 4645 synchronized(this) 4646 { 4647 while(inCheckpoint) 4649 { 4650 try 4651 { 4652 wait(); 4653 } 4654 catch (InterruptedException ie) 4655 { 4656 throw StandardException.interrupt(ie); 4657 } 4658 } 4659 4660 backupInProgress = true; 4661 4662 StorageFile fromFile; 4664 File toFile; 4665 fromFile = getControlFileName(); 4667 toFile = new File(toDir,fromFile.getName()); 4668 if(!privCopyFile(fromFile, toFile)) 4669 { 4670 throw StandardException.newException( 4671 SQLState.RAWSTORE_ERROR_COPYING_FILE, fromFile, toFile); 4672 } 4673 4674 fromFile = getMirrorControlFileName(); 4676 toFile = new File(toDir,fromFile.getName()); 4677 if(!privCopyFile(fromFile, toFile)) 4678 { 4679 throw StandardException.newException( 4680 SQLState.RAWSTORE_ERROR_COPYING_FILE, fromFile, toFile); 4681 } 4682 4683 logFileToBackup = getFirstLogNeeded(currentCheckpoint); 4685 } 4686 4687 backupLogFiles(toDir, getLogFileNumber() - 1); 4689 } 4690 4691 4697 private void backupLogFiles(File toDir, long lastLogFileToBackup) 4698 throws StandardException 4699 { 4700 4701 while(logFileToBackup <= lastLogFileToBackup) 4702 { 4703 StorageFile fromFile = getLogFileName(logFileToBackup); 4704 File toFile = new File(toDir, fromFile.getName()); 4705 if(!privCopyFile(fromFile, toFile)) 4706 { 4707 throw StandardException.newException( 4708 SQLState.RAWSTORE_ERROR_COPYING_FILE, fromFile, toFile); 4709 } 4710 logFileToBackup++; 4711 } 4712 } 4713 4714 4721 public void endLogBackup(File toDir) throws StandardException 4722 { 4723 long lastLogFileToBackup; 4724 4725 4726 flush(logFileNumber, endPosition); 4732 4733 if (logArchived) 4734 { 4735 switchLogFile(); 4744 lastLogFileToBackup = getLogFileNumber() - 1; 4745 } 4746 else 4747 { 4748 lastLogFileToBackup = getLogFileNumber(); 4751 } 4752 4753 backupLogFiles(toDir, lastLogFileToBackup); 4755 4756 backupInProgress = false; 4758 } 4759 4760 4761 4764 public void abortLogBackup() 4765 { 4766 backupInProgress = false; 4767 } 4768 4769 4770 public boolean inRFR() 4772 { 4773 4780 4781 if(recoveryNeeded) 4782 { 4783 boolean readOnly = false; 4784 try{ 4785 readOnly = !privCanWrite(getControlFileName()); 4786 }catch(StandardException se) 4787 { 4788 } 4795 4796 readOnly = readOnly || (dataFactory == null ? false :dataFactory.isReadOnly()); 4797 return !readOnly; 4798 }else{ 4799 return false; 4800 } 4801 } 4802 4803 4806 public void checkpointInRFR(LogInstant cinstant, long redoLWM, DataFactory df) throws StandardException 4807 { 4808 df.checkpoint(); 4810 4811 try{ 4815 if (!writeControlFile(getControlFileName(), ((LogCounter)cinstant).getValueAsLong())) 4816 { 4817 throw StandardException.newException( 4818 SQLState.LOG_CONTROL_FILE, getControlFileName()); 4819 } 4820 } 4821 catch (IOException ioe) 4822 { 4823 throw markCorrupt( 4824 StandardException.newException(SQLState.LOG_IO_ERROR, ioe)); 4825 } 4826 df.removeDroppedContainerFileStubs(new LogCounter(redoLWM)); 4828 4829 } 4830 4831 4832 4855 private boolean restoreLogs(Properties properties) throws StandardException 4856 { 4857 4858 String backupPath =null; 4859 boolean isCreateFrom = false; 4860 boolean isRestoreFrom = false; 4861 4862 backupPath = properties.getProperty(Attribute.CREATE_FROM); 4864 if (backupPath != null) { 4865 isCreateFrom = true; 4866 } else { 4867 backupPath = properties.getProperty(Attribute.RESTORE_FROM); 4868 if (backupPath != null) { 4869 isRestoreFrom = true; 4870 } else { 4871 backupPath = properties.getProperty( 4872 Attribute.ROLL_FORWARD_RECOVERY_FROM); 4873 } 4875 } 4876 4877 if(backupPath !=null) 4878 { 4879 if(!isCreateFrom){ 4880 if(logDevice == null){ 4881 4891 logDevice = 4892 properties.getProperty(Property.LOG_DEVICE_AT_BACKUP); 4893 } 4894 } 4895 4896 getLogStorageFactory(); 4897 StorageFile logDir; 4898 logDir = logStorageFactory.newStorageFile( 4899 LogFactory.LOG_DIRECTORY_NAME); 4900 4901 if (isRestoreFrom && logDevice != null) 4905 { 4906 if(!privRemoveDirectory(logDir)) 4907 { 4908 if(!privDelete(logDir)) 4910 { 4911 throw StandardException.newException( 4912 SQLState.UNABLE_TO_REMOVE_DATA_DIRECTORY, 4913 getLogDirPath( logDir)); 4914 } 4915 } 4916 } 4917 4918 if (isCreateFrom || isRestoreFrom) { 4921 createLogDirectory(); 4922 } 4923 4924 File backupLogDir = new File(backupPath, LogFactory.LOG_DIRECTORY_NAME); 4925 String [] logfilelist = privList(backupLogDir); 4926 if(logfilelist !=null) 4927 { 4928 for (int i = 0; i < logfilelist.length; i++) 4929 { 4930 File blogFile = new File(backupLogDir, logfilelist[i]); 4931 StorageFile clogFile = logStorageFactory.newStorageFile(logDir, logfilelist[i]); 4932 if(!privCopyFile(blogFile , clogFile)) 4933 { 4934 throw 4935 StandardException.newException(SQLState.UNABLE_TO_COPY_LOG_FILE, blogFile, clogFile); 4936 } 4937 } 4938 }else 4939 { 4940 throw StandardException.newException(SQLState.LOG_DIRECTORY_NOT_FOUND_IN_BACKUP,backupLogDir); 4941 } 4942 logSwitchRequired = true; 4947 4948 return true; 4950 } else { 4951 return false; 4953 } 4954 } 4955 4956 4960 private void preAllocateNewLogFile(StorageRandomAccessFile log) throws IOException , StandardException 4961 { 4962 4964 if (SanityManager.DEBUG) 4965 { 4966 int currentPostion = (int)log.getFilePointer(); 4967 SanityManager.ASSERT(currentPostion == LOG_FILE_HEADER_SIZE, 4968 "New Log File Is not Correctly Initialized"); 4969 } 4970 4971 int amountToWrite = logSwitchInterval - LOG_FILE_HEADER_SIZE ; 4972 int bufferSize = logBufferSize * 2; 4973 byte[] emptyBuffer = new byte[bufferSize]; 4974 int nWrites = amountToWrite/bufferSize; 4975 int remainingBytes = amountToWrite % bufferSize; 4976 4977 try{ 4978 while(nWrites-- > 0) 4979 log.write(emptyBuffer); 4980 4981 if(remainingBytes !=0) 4982 log.write(emptyBuffer , 0 ,remainingBytes); 4983 4984 syncFile(log); 4986 }catch(IOException ie) 4987 { 4988 4992 4995 if (SanityManager.DEBUG) 4997 { 4998 throw ie; 4999 } 5000 } 5001 } 5003 5004 5009 private StorageRandomAccessFile openLogFileInWriteMode(StorageFile logFile) throws IOException 5010 { 5011 StorageRandomAccessFile log; 5012 try{ 5013 log = privRandomAccessFile(logFile, "rws"); 5014 }catch(FileNotFoundException ex) 5015 { 5016 5023 isWriteSynced = false; 5025 log = privRandomAccessFile(logFile, "rw"); 5026 } 5027 5028 return log ; 5029 } 5030 5031 5032 private String getLogDirPath( StorageFile logDir) 5033 { 5034 if( logDevice == null) 5035 return logDir.toString(); 5036 return logDevice + logStorageFactory.getSeparator() + logDir.toString(); 5037 } 5039 5042 private int action; 5043 private StorageFile activeFile; 5044 private File toFile; 5045 private String activePerms; 5046 5047 protected boolean privExists(StorageFile file) 5048 { 5049 return runBooleanAction(0, file); 5050 } 5051 5052 protected boolean privDelete(StorageFile file) 5053 { 5054 return runBooleanAction(1, file); 5055 } 5056 5057 private synchronized StorageRandomAccessFile privRandomAccessFile(StorageFile file, String perms) 5058 throws IOException 5059 { 5060 action = 2; 5061 activeFile = file; 5062 activePerms = perms; 5063 try 5064 { 5065 return (StorageRandomAccessFile) java.security.AccessController.doPrivileged(this); 5066 } 5067 catch (java.security.PrivilegedActionException pae) 5068 { 5069 throw (IOException ) pae.getException(); 5070 } 5071 } 5072 5073 protected boolean privCanWrite(StorageFile file) 5074 { 5075 return runBooleanAction(3, file); 5076 } 5077 5078 protected boolean privMkdirs(StorageFile file) 5079 { 5080 return runBooleanAction(4, file); 5081 } 5082 5083 private synchronized String [] privList(File file) 5084 { 5085 action = 8; 5086 toFile = file; 5087 5088 try 5089 { 5090 return (String []) java.security.AccessController.doPrivileged(this); 5091 } 5092 catch (java.security.PrivilegedActionException pae) 5093 { 5094 return null; 5095 } 5096 } 5097 5098 private synchronized String [] privList(StorageFile file) 5099 { 5100 action = 5; 5101 activeFile = file; 5102 5103 try 5104 { 5105 return (String []) java.security.AccessController.doPrivileged(this); 5106 } 5107 catch (java.security.PrivilegedActionException pae) 5108 { 5109 return null; 5110 } 5111 } 5112 5113 5114 private synchronized boolean privCopyFile(StorageFile from, File to) 5115 { 5116 action = 6; 5117 activeFile = from; 5118 toFile = to; 5119 try 5120 { 5121 return ((Boolean ) java.security.AccessController.doPrivileged(this)).booleanValue(); 5122 } 5123 catch (java.security.PrivilegedActionException pae) 5124 { 5125 return false; 5126 } 5127 } 5128 5129 private synchronized boolean privCopyFile(File from, StorageFile to) 5130 { 5131 action = 9; 5132 activeFile = to; 5133 toFile = from; 5134 try 5135 { 5136 return ((Boolean ) java.security.AccessController.doPrivileged(this)).booleanValue(); 5137 } 5138 catch (java.security.PrivilegedActionException pae) 5139 { 5140 return false; 5141 } 5142 } 5143 5144 private boolean privRemoveDirectory(StorageFile file) 5145 { 5146 return runBooleanAction(7, file); 5147 } 5148 5149 5150 private synchronized boolean runBooleanAction(int action, StorageFile file) { 5151 this.action = action; 5152 this.activeFile = file; 5153 5154 try { 5155 return ((Boolean ) java.security.AccessController.doPrivileged(this)).booleanValue(); 5156 } catch (java.security.PrivilegedActionException pae) { 5157 return false; 5158 } 5159 } 5160 5161 5162 5163 5164 public final Object run() throws IOException { 5165 switch (action) { 5166 case 0: 5167 return ReuseFactory.getBoolean(activeFile.exists()); 5169 case 1: 5170 return ReuseFactory.getBoolean(activeFile.delete()); 5172 case 2: 5173 return activeFile.getRandomAccessFile(activePerms); 5176 case 3: 5177 return ReuseFactory.getBoolean(activeFile.canWrite()); 5179 case 4: 5180 return ReuseFactory.getBoolean(activeFile.mkdirs()); 5182 case 5: 5183 return activeFile.list(); 5185 case 6: 5186 return ReuseFactory.getBoolean(FileUtil.copyFile(logStorageFactory, activeFile, toFile)); 5188 case 7: 5189 if( ! activeFile.exists()) 5191 return ReuseFactory.getBoolean( true); 5192 return ReuseFactory.getBoolean(activeFile.deleteAll()); 5193 case 8: 5194 return toFile.list(); 5195 case 9: 5196 return ReuseFactory.getBoolean(FileUtil.copyFile( logStorageFactory, toFile, activeFile)); 5197 5198 default: 5199 return null; 5200 } 5201 } 5202} 5203 | Popular Tags |