1 65 66 67 package org.hsqldb.persist; 68 69 import java.io.File ; 70 import java.io.IOException ; 71 72 import org.hsqldb.Database; 73 import org.hsqldb.HsqlException; 74 import org.hsqldb.NumberSequence; 75 import org.hsqldb.Session; 76 import org.hsqldb.Table; 77 import org.hsqldb.Trace; 78 import org.hsqldb.lib.FileAccess; 79 import org.hsqldb.lib.HashMap; 80 import org.hsqldb.lib.Iterator; 81 import org.hsqldb.lib.SimpleLog; 82 import org.hsqldb.lib.ZipUnzipFile; 83 import org.hsqldb.scriptio.ScriptReaderBase; 84 import org.hsqldb.scriptio.ScriptWriterBase; 85 86 106 127 public class Log { 128 129 private HsqlDatabaseProperties properties; 130 private String fileName; 131 private Database database; 132 private FileAccess fa; 133 private ScriptWriterBase dbLogWriter; 134 private String scriptFileName; 135 private String logFileName; 136 private boolean filesReadOnly; 137 private long maxLogSize; 138 private int writeDelay; 139 private int scriptFormat; 140 private DataFileCache cache; 141 142 Log(Database db) throws HsqlException { 143 144 database = db; 145 fa = db.getFileAccess(); 146 fileName = db.getPath(); 147 properties = db.getProperties(); 148 } 149 150 void initParams() { 151 152 int logMegas = properties.getIntegerProperty( 154 HsqlDatabaseProperties.hsqldb_log_size, 0); 155 156 maxLogSize = logMegas * 1024 * 1024; 157 scriptFormat = properties.getIntegerProperty( 158 HsqlDatabaseProperties.hsqldb_script_format, 159 ScriptWriterBase.SCRIPT_TEXT_170); 160 writeDelay = properties.getDefaultWriteDelay(); 161 filesReadOnly = database.isFilesReadOnly(); 162 scriptFileName = fileName + ".script"; 163 logFileName = fileName + ".log"; 164 } 165 166 174 void open() throws HsqlException { 175 176 initParams(); 177 178 int state = properties.getDBModified(); 179 180 switch (state) { 181 182 case HsqlDatabaseProperties.FILES_MODIFIED : 183 deleteNewAndOldFiles(); 184 restoreBackup(); 185 processScript(); 186 processDataFile(); 187 processLog(); 188 close(false); 189 190 if (cache != null) { 191 cache.open(filesReadOnly); 192 } 193 194 reopenAllTextCaches(); 195 break; 196 197 case HsqlDatabaseProperties.FILES_NEW : 198 try { 199 deleteBackup(); 200 backupData(); 201 renameNewBackup(); 202 renameNewScript(); 203 deleteLog(); 204 properties.setDBModified( 205 HsqlDatabaseProperties.FILES_NOT_MODIFIED); 206 } catch (IOException e) { 207 database.logger.appLog.logContext(e, null); 208 } 209 210 case HsqlDatabaseProperties.FILES_NOT_MODIFIED : 212 213 218 processScript(); 219 220 if (isAnyCacheModified()) { 221 properties.setDBModified( 222 HsqlDatabaseProperties.FILES_MODIFIED); 223 close(false); 224 225 if (cache != null) { 226 cache.open(filesReadOnly); 227 } 228 229 reopenAllTextCaches(); 230 } 231 break; 232 } 233 234 openLog(); 235 236 if (!filesReadOnly) { 237 properties.setDBModified(HsqlDatabaseProperties.FILES_MODIFIED); 238 } 239 } 240 241 248 void close(boolean script) throws HsqlException { 249 250 closeLog(); 251 deleteNewAndOldFiles(); 252 writeScript(script); 253 closeAllTextCaches(script); 254 255 if (cache != null) { 256 cache.close(true); 257 } 258 259 properties.setProperty(HsqlDatabaseProperties.db_version, 260 HsqlDatabaseProperties.THIS_VERSION); 261 properties.setProperty( 262 HsqlDatabaseProperties.hsqldb_compatible_version, 263 HsqlDatabaseProperties.FIRST_COMPATIBLE_VERSION); 264 265 properties.setDBModified(HsqlDatabaseProperties.FILES_NEW); 267 deleteLog(); 268 269 if (script) { 270 deleteBackup(); 271 deleteData(); 272 } else { 273 try { 274 backupData(); 275 renameNewBackup(); 276 } catch (IOException e) {} 277 } 278 279 renameNewScript(); 280 properties.setDBModified(HsqlDatabaseProperties.FILES_NOT_MODIFIED); 281 } 282 283 287 void shutdown() throws HsqlException { 288 289 synchLog(); 290 291 if (cache != null) { 292 cache.close(false); 293 } 294 295 closeAllTextCaches(false); 296 closeLog(); 297 } 298 299 302 void deleteNewAndOldFiles() { 303 304 fa.removeElement(fileName + ".data" + ".old"); 305 fa.removeElement(fileName + ".data" + ".new"); 306 fa.removeElement(fileName + ".backup" + ".new"); 307 fa.removeElement(scriptFileName + ".new"); 308 } 309 310 void deleteBackup() { 311 fa.removeElement(fileName + ".backup"); 312 } 313 314 void deleteData() { 315 fa.removeElement(fileName + ".data"); 316 } 317 318 void backupData() throws IOException { 319 320 if (fa.isStreamElement(fileName + ".data")) { 321 ZipUnzipFile.compressFile(fileName + ".data", 322 fileName + ".backup.new", 323 database.getFileAccess()); 324 } 325 } 326 327 void renameNewBackup() { 328 329 if (fa.isStreamElement(fileName + ".backup.new")) { 330 fa.renameElement(fileName + ".backup.new", fileName + ".backup"); 331 } 332 } 333 334 void renameNewScript() { 335 336 if (fa.isStreamElement(scriptFileName + ".new")) { 337 fa.renameElement(scriptFileName + ".new", scriptFileName); 338 } 339 } 340 341 void deleteNewScript() { 342 fa.removeElement(scriptFileName + ".new"); 343 } 344 345 void deleteNewBackup() { 346 fa.removeElement(scriptFileName + ".backup.new"); 347 } 348 349 void deleteLog() { 350 fa.removeElement(logFileName); 351 } 352 353 356 boolean isAnyCacheModified() { 357 358 if (cache != null && cache.isFileModified()) { 359 return true; 360 } 361 362 return isAnyTextCacheModified(); 363 } 364 365 369 void checkpoint(boolean defrag) throws HsqlException { 370 371 if (filesReadOnly) { 372 return; 373 } 374 375 database.logger.appLog.logContext(SimpleLog.LOG_NORMAL, "start"); 376 deleteNewAndOldFiles(); 377 378 if (cache != null) { 379 if (forceDefrag()) { 380 defrag = true; 381 } 382 383 if (defrag) { 384 try { 385 cache.defrag(); 386 } catch (Exception e) {} 387 } else { 388 cache.close(true); 389 390 try { 391 cache.backupFile(); 392 } catch (IOException e1) { 393 deleteNewBackup(); 394 cache.open(false); 395 396 return; 397 } 398 399 cache.open(false); 400 } 401 } 402 403 writeScript(false); 404 properties.setDBModified(HsqlDatabaseProperties.FILES_NEW); 405 closeLog(); 406 deleteLog(); 407 renameNewScript(); 408 renameNewBackup(); 409 properties.setDBModified(HsqlDatabaseProperties.FILES_MODIFIED); 410 411 if (dbLogWriter == null) { 412 return; 413 } 414 415 openLog(); 416 417 Session[] sessions = database.sessionManager.getAllSessions(); 418 419 try { 420 for (int i = 0; i < sessions.length; i++) { 421 Session session = sessions[i]; 422 423 if (session.isAutoCommit() == false) { 424 dbLogWriter.writeLogStatement( 425 session, session.getAutoCommitStatement()); 426 } 427 } 428 } catch (IOException e) { 429 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 430 } 431 432 database.logger.appLog.logContext(SimpleLog.LOG_NORMAL, "end"); 433 } 434 435 438 boolean forceDefrag() { 439 440 long megas = properties.getIntegerProperty( 441 HsqlDatabaseProperties.hsqldb_defrag_limit, 200); 442 long defraglimit = megas * 1024 * 1024; 443 long lostSize = cache.freeBlocks.getLostBlocksSize(); 444 445 return lostSize > defraglimit; 446 } 447 448 451 boolean hasCache() { 452 return cache != null; 453 } 454 455 458 DataFileCache getCache() throws HsqlException { 459 460 465 if (cache == null) { 466 cache = new DataFileCache(database, fileName); 467 468 cache.open(filesReadOnly); 469 } 470 471 return cache; 472 } 473 474 int getLogSize() { 475 return (int) (maxLogSize / (1024 * 11024)); 476 } 477 478 void setLogSize(int megas) { 479 480 properties.setProperty(HsqlDatabaseProperties.hsqldb_log_size, 481 String.valueOf(megas)); 482 483 maxLogSize = megas * 1024 * 1024; 484 } 485 486 int getScriptType() { 487 return scriptFormat; 488 } 489 490 494 void setScriptType(int type) throws HsqlException { 495 496 if (database.isStoredFileAccess()) { 497 return; 498 } 499 500 boolean needsCheckpoint = scriptFormat != type; 501 502 scriptFormat = type; 503 504 properties.setProperty(HsqlDatabaseProperties.hsqldb_script_format, 505 String.valueOf(scriptFormat)); 506 507 if (needsCheckpoint) { 508 database.logger.needsCheckpoint = true; 509 } 510 } 511 512 515 int getWriteDelay() { 516 return writeDelay; 517 } 518 519 void setWriteDelay(int delay) { 520 521 writeDelay = delay; 522 523 if (dbLogWriter != null) { 524 synchLog(); 525 dbLogWriter.setWriteDelay(delay); 526 } 527 } 528 529 532 void writeStatement(Session session, String s) throws HsqlException { 533 534 if (s == null || s.length() == 0) { 535 return; 536 } 537 538 try { 539 dbLogWriter.writeLogStatement(session, s); 540 } catch (IOException e) { 541 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 542 } 543 544 if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) { 545 database.logger.needsCheckpoint = true; 546 } 547 } 548 549 void writeInsertStatement(Session session, Table t, 550 Object [] row) throws HsqlException { 551 552 try { 553 dbLogWriter.writeInsertStatement(session, t, row); 554 } catch (IOException e) { 555 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 556 } 557 558 if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) { 559 database.logger.needsCheckpoint = true; 560 } 561 } 562 563 void writeDeleteStatement(Session session, Table t, 564 Object [] row) throws HsqlException { 565 566 try { 567 dbLogWriter.writeDeleteStatement(session, t, row); 568 } catch (IOException e) { 569 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 570 } 571 572 if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) { 573 database.logger.needsCheckpoint = true; 574 } 575 } 576 577 void writeSequenceStatement(Session session, 578 NumberSequence s) throws HsqlException { 579 580 try { 581 dbLogWriter.writeSequenceStatement(session, s); 582 } catch (IOException e) { 583 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 584 } 585 586 if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) { 587 database.logger.needsCheckpoint = true; 588 } 589 } 590 591 void writeCommitStatement(Session session) throws HsqlException { 592 593 try { 594 dbLogWriter.writeCommitStatement(session); 595 } catch (IOException e) { 596 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 597 } 598 599 if (maxLogSize > 0 && dbLogWriter.size() > maxLogSize) { 600 database.logger.needsCheckpoint = true; 601 } 602 } 603 604 void synchLog() { 605 606 if (dbLogWriter != null) { 607 dbLogWriter.sync(); 608 } 609 } 610 611 615 private void openLog() throws HsqlException { 616 617 if (filesReadOnly) { 618 return; 619 } 620 621 try { 622 dbLogWriter = ScriptWriterBase.newScriptWriter(database, 623 logFileName, false, false, 624 ScriptWriterBase.SCRIPT_TEXT_170); 625 626 dbLogWriter.setWriteDelay(writeDelay); 627 dbLogWriter.start(); 628 } catch (Exception e) { 629 throw Trace.error(Trace.FILE_IO_ERROR, logFileName); 630 } 631 } 632 633 private synchronized void closeLog() throws HsqlException { 634 635 if (dbLogWriter != null) { 636 dbLogWriter.close(); 637 } 638 } 639 640 643 private void writeScript(boolean full) throws HsqlException { 644 645 deleteNewScript(); 646 647 ScriptWriterBase scw = ScriptWriterBase.newScriptWriter(database, 649 scriptFileName + ".new", full, true, scriptFormat); 650 651 scw.writeAll(); 652 scw.close(); 653 } 654 655 658 private void processScript() throws HsqlException { 659 660 ScriptReaderBase scr = null; 661 662 try { 663 if (database.isFilesInJar() 664 || fa.isStreamElement(scriptFileName)) { 665 scr = ScriptReaderBase.newScriptReader(database, 666 scriptFileName, 667 scriptFormat); 668 669 scr.readAll(database.sessionManager.getSysSession(null, 670 true)); 671 scr.close(); 672 } 673 } catch (Throwable e) { 674 if (scr != null) { 675 scr.close(); 676 677 if (cache != null) { 678 cache.close(false); 679 } 680 681 closeAllTextCaches(false); 682 } 683 684 database.logger.appLog.logContext(e, null); 685 686 if (e instanceof HsqlException) { 687 throw (HsqlException) e; 688 } else if (e instanceof IOException ) { 689 throw Trace.error(Trace.FILE_IO_ERROR, e.toString()); 690 } else if (e instanceof OutOfMemoryError ) { 691 throw Trace.error(Trace.OUT_OF_MEMORY); 692 } else { 693 throw Trace.error(Trace.GENERAL_ERROR, e.toString()); 694 } 695 } 696 } 697 698 701 private void processDataFile() throws HsqlException { 702 703 if (cache == null || filesReadOnly || database.isStoredFileAccess() 704 ||!fa.isStreamElement(logFileName)) { 705 return; 706 } 707 708 File file = new File (logFileName); 709 long logLength = file.length(); 710 long dataLength = cache.getFileFreePos(); 711 712 if (logLength + dataLength > cache.maxDataFileSize) { 713 database.logger.needsCheckpoint = true; 714 } 715 } 716 717 720 private void processLog() throws HsqlException { 721 722 if (!database.isFilesInJar() && fa.isStreamElement(logFileName)) { 723 ScriptRunner.runScript(database, logFileName, 724 ScriptWriterBase.SCRIPT_TEXT_170); 725 } 726 } 727 728 731 private void restoreBackup() throws HsqlException { 732 733 DataFileCache.deleteOrResetFreePos(database, fileName + ".data"); 735 736 try { 737 ZipUnzipFile.decompressFile(fileName + ".backup", 738 fileName + ".data", 739 database.getFileAccess()); 740 } catch (Exception e) { 741 throw Trace.error(Trace.FILE_IO_ERROR, Trace.Message_Pair, 742 new Object [] { 743 fileName + ".backup", e.toString() 744 }); 745 } 746 } 747 748 private HashMap textCacheList = new HashMap(); 750 751 DataFileCache openTextCache(Table table, String source, 752 boolean readOnlyData, 753 boolean reversed) throws HsqlException { 754 755 closeTextCache(table); 756 757 if (!properties.isPropertyTrue("textdb.allow_full_path")) { 758 if (source.indexOf("..") != -1) { 759 throw (Trace.error(Trace.ACCESS_IS_DENIED, source)); 760 } 761 762 String path = new File ( 763 new File ( 764 database.getPath() 765 + ".properties").getAbsolutePath()).getParent(); 766 767 if (path != null) { 768 source = path + File.separator + source; 769 } 770 } 771 772 TextCache c; 773 int type; 774 775 if (reversed) { 776 c = new TextCache(table, source); 777 } else { 778 c = new TextCache(table, source); 779 } 780 781 c.open(readOnlyData || filesReadOnly); 782 textCacheList.put(table.getName(), c); 783 784 return c; 785 } 786 787 void closeTextCache(Table table) throws HsqlException { 788 789 TextCache c = (TextCache) textCacheList.remove(table.getName()); 790 791 if (c != null) { 792 c.close(true); 793 } 794 } 795 796 private void closeAllTextCaches(boolean compact) throws HsqlException { 797 798 Iterator it = textCacheList.values().iterator(); 799 800 while (it.hasNext()) { 801 if (compact) { 802 ((TextCache) it.next()).purge(); 803 } else { 804 ((TextCache) it.next()).close(true); 805 } 806 } 807 } 808 809 private void reopenAllTextCaches() throws HsqlException { 810 811 Iterator it = textCacheList.values().iterator(); 812 813 while (it.hasNext()) { 814 ((TextCache) it.next()).reopen(); 815 } 816 } 817 818 private boolean isAnyTextCacheModified() { 819 820 Iterator it = textCacheList.values().iterator(); 821 822 while (it.hasNext()) { 823 if (((TextCache) it.next()).isFileModified()) { 824 return true; 825 } 826 } 827 828 return false; 829 } 830 } 831 | Popular Tags |