| 1 8 9 package com.sleepycat.je.dbi; 10 11 import java.io.File ; 12 import java.io.IOException ; 13 import java.io.PrintStream ; 14 import java.util.ArrayList ; 15 import java.util.Collection ; 16 import java.util.List ; 17 import java.util.logging.ConsoleHandler ; 18 import java.util.logging.FileHandler ; 19 import java.util.logging.Handler ; 20 import java.util.logging.Level ; 21 import java.util.logging.Logger ; 22 import java.util.logging.SimpleFormatter ; 23 24 import com.sleepycat.je.CheckpointConfig; 25 import com.sleepycat.je.Database; 26 import com.sleepycat.je.DatabaseConfig; 27 import com.sleepycat.je.DatabaseException; 28 import com.sleepycat.je.DbInternal; 29 import com.sleepycat.je.Environment; 30 import com.sleepycat.je.EnvironmentConfig; 31 import com.sleepycat.je.EnvironmentMutableConfig; 32 import com.sleepycat.je.EnvironmentStats; 33 import com.sleepycat.je.ExceptionListener; 34 import com.sleepycat.je.LockStats; 35 import com.sleepycat.je.RunRecoveryException; 36 import com.sleepycat.je.StatsConfig; 37 import com.sleepycat.je.Transaction; 38 import com.sleepycat.je.TransactionConfig; 39 import com.sleepycat.je.TransactionStats; 40 import com.sleepycat.je.VerifyConfig; 41 import com.sleepycat.je.cleaner.Cleaner; 42 import com.sleepycat.je.cleaner.UtilizationProfile; 43 import com.sleepycat.je.cleaner.UtilizationTracker; 44 import com.sleepycat.je.config.EnvironmentParams; 45 import com.sleepycat.je.evictor.Evictor; 46 import com.sleepycat.je.incomp.INCompressor; 47 import com.sleepycat.je.latch.Latch; 48 import com.sleepycat.je.latch.LatchSupport; 49 import com.sleepycat.je.latch.SharedLatch; 50 import com.sleepycat.je.log.FileManager; 51 import com.sleepycat.je.log.LatchedLogManager; 52 import com.sleepycat.je.log.LogManager; 53 import com.sleepycat.je.log.SyncedLogManager; 54 import com.sleepycat.je.log.TraceLogHandler; 55 import com.sleepycat.je.recovery.Checkpointer; 56 import com.sleepycat.je.recovery.RecoveryInfo; 57 import com.sleepycat.je.recovery.RecoveryManager; 58 import com.sleepycat.je.tree.BIN; 59 import com.sleepycat.je.tree.BINReference; 60 import com.sleepycat.je.tree.IN; 61 import com.sleepycat.je.tree.Key; 62 import com.sleepycat.je.txn.Locker; 63 import com.sleepycat.je.txn.Txn; 64 import com.sleepycat.je.txn.TxnManager; 65 import com.sleepycat.je.utilint.DbLsn; 66 import com.sleepycat.je.utilint.NotImplementedYetException; 67 import com.sleepycat.je.utilint.PropUtil; 68 import com.sleepycat.je.utilint.TestHook; 69 import com.sleepycat.je.utilint.TestHookExecute; 70 import com.sleepycat.je.utilint.Tracer; 71 72 76 public class EnvironmentImpl implements EnvConfigObserver { 77 78 82 private static final boolean TEST_NO_LOCKING_MODE = false; 83 84 85 private DbEnvState envState; 86 private boolean closing; private File envHome; 88 private int referenceCount; private boolean isTransactional; private boolean isNoLocking; private boolean isReadOnly; private boolean isMemOnly; private boolean directNIO; private static boolean fairLatches; private static boolean useSharedLatchesForINs; 96 97 private boolean deferredWriteTemp; 98 99 private MemoryBudget memoryBudget; 100 private static int adler32ChunkSize; 101 102 103 private long lockTimeout; 104 private long txnTimeout; 105 106 107 private DbTree dbMapTree; 108 private long mapTreeRootLsn = DbLsn.NULL_LSN; 109 private Latch mapTreeRootLatch; 110 private INList inMemoryINs; 111 112 113 private DbConfigManager configManager; 114 private List configObservers; 115 private Logger envLogger; 116 protected LogManager logManager; 117 private FileManager fileManager; 118 private TxnManager txnManager; 119 120 121 private Evictor evictor; 122 private INCompressor inCompressor; 123 private Checkpointer checkpointer; 124 private Cleaner cleaner; 125 126 127 private boolean isReplicated; 128 private ReplicatorInstance repInstance; 129 130 131 private RecoveryInfo lastRecoveryInfo; 132 private RunRecoveryException savedInvalidatingException; 133 134 135 private static boolean forcedYield = false; 136 137 141 private SharedLatch triggerLatch; 142 143 146 private ExceptionListener exceptionListener = null; 147 148 156 private volatile int backgroundSleepBacklog; 157 private volatile int backgroundReadLimit; 158 private volatile int backgroundWriteLimit; 159 private long backgroundSleepInterval; 160 private int backgroundReadCount; 161 private long backgroundWriteBytes; 162 private TestHook backgroundSleepHook; 163 private Object backgroundTrackingMutex = new Object (); 164 private Object backgroundSleepMutex = new Object (); 165 166 174 private static int threadLocalReferenceCount = 0; 175 176 181 private static boolean noComparators = false; 182 183 188 public final RunRecoveryException SAVED_RRE = DbInternal.makeNoArgsRRE(); 189 190 public static final boolean JAVA5_AVAILABLE; 191 192 private static final String DISABLE_JAVA_ADLER32 = 193 "je.disable.java.adler32"; 194 195 static { 196 boolean ret = false; 197 if (System.getProperty(DISABLE_JAVA_ADLER32) == null) { 198 199 202 String javaVersion = System.getProperty("java.version"); 203 if (javaVersion != null && 204 !javaVersion.startsWith("1.4.")) { 205 ret = true; 206 } 207 } 208 JAVA5_AVAILABLE = ret; 209 } 210 211 224 public EnvironmentImpl(File envHome, EnvironmentConfig envConfig) 225 throws DatabaseException { 226 227 try { 228 this.envHome = envHome; 229 envState = DbEnvState.INIT; 230 mapTreeRootLatch = LatchSupport.makeLatch("MapTreeRoot", this); 231 232 233 configManager = new DbConfigManager(envConfig); 234 configObservers = new ArrayList (); 235 addConfigObserver(this); 236 237 241 memoryBudget = new MemoryBudget(this, configManager); 242 243 247 envLogger = initLogger(envHome); 248 249 252 forcedYield = 253 configManager.getBoolean(EnvironmentParams.ENV_FORCED_YIELD); 254 isTransactional = 255 configManager.getBoolean(EnvironmentParams.ENV_INIT_TXN); 256 isNoLocking = !(configManager.getBoolean 257 (EnvironmentParams.ENV_INIT_LOCKING)); 258 if (isTransactional && isNoLocking) { 259 if (TEST_NO_LOCKING_MODE) { 260 isNoLocking = !isTransactional; 261 } else { 262 throw new IllegalArgumentException  263 ("Can't set 'je.env.isNoLocking' and " + 264 "'je.env.isTransactional';"); 265 } 266 } 267 268 directNIO = 269 configManager.getBoolean(EnvironmentParams.LOG_DIRECT_NIO); 270 fairLatches = 271 configManager.getBoolean(EnvironmentParams.ENV_FAIR_LATCHES); 272 isReadOnly = 273 configManager.getBoolean(EnvironmentParams.ENV_RDONLY); 274 isMemOnly = 275 configManager.getBoolean(EnvironmentParams.LOG_MEMORY_ONLY); 276 useSharedLatchesForINs = 277 configManager.getBoolean(EnvironmentParams.ENV_SHARED_LATCHES); 278 adler32ChunkSize = 279 configManager.getInt(EnvironmentParams.ADLER32_CHUNK_SIZE); 280 281 exceptionListener = envConfig.getExceptionListener(); 282 283 288 deferredWriteTemp = 289 configManager.getBoolean( 290 EnvironmentParams.LOG_DEFERREDWRITE_TEMP); 291 292 fileManager = new FileManager(this, envHome, isReadOnly); 293 if (!envConfig.getAllowCreate() && !fileManager.filesExist()) { 294 throw new DatabaseException 295 ("Environment.setAllowCreate is false so environment " + 296 " creation is not permitted, but there is no " + 297 " pre-existing environment in " + envHome); 298 } 299 300 if (fairLatches) { 301 logManager = new LatchedLogManager(this, isReadOnly); 302 } else { 303 logManager = new SyncedLogManager(this, isReadOnly); 304 } 305 306 inMemoryINs = new INList(this); 307 txnManager = new TxnManager(this); 308 309 314 createDaemons(); 315 316 319 dbMapTree = new DbTree(this); 320 321 referenceCount = 0; 322 323 triggerLatch = LatchSupport.makeSharedLatch("TriggerLatch", this); 324 325 329 if (configManager.getBoolean(EnvironmentParams.ENV_RECOVERY)) { 330 331 335 try { 336 RecoveryManager recoveryManager = 337 new RecoveryManager(this); 338 lastRecoveryInfo = recoveryManager.recover(isReadOnly); 339 } finally { 340 try { 341 342 logManager.flush(); 343 fileManager.clear(); 344 } catch (IOException e) { 345 throw new DatabaseException(e.getMessage()); 346 } 347 } 348 } else { 349 isReadOnly = true; 350 noComparators = true; 351 } 352 353 354 envConfigUpdate(configManager); 355 356 360 lockTimeout = 361 PropUtil.microsToMillis(configManager.getLong 362 (EnvironmentParams.LOCK_TIMEOUT)); 363 txnTimeout = 364 PropUtil.microsToMillis(configManager.getLong 365 (EnvironmentParams.TXN_TIMEOUT)); 366 367 368 memoryBudget.initCacheMemoryUsage(); 369 370 371 open(); 372 } catch (DatabaseException e) { 373 374 375 if (fileManager != null) { 376 try { 377 381 fileManager.clear(); 382 fileManager.close(); 383 } catch (IOException IOE) { 384 385 389 } 390 } 391 throw e; 392 } 393 } 394 395 398 public void envConfigUpdate(DbConfigManager mgr) 399 throws DatabaseException { 400 401 runOrPauseDaemons(mgr); 402 403 backgroundReadLimit = mgr.getInt 404 (EnvironmentParams.ENV_BACKGROUND_READ_LIMIT); 405 backgroundWriteLimit = mgr.getInt 406 (EnvironmentParams.ENV_BACKGROUND_WRITE_LIMIT); 407 backgroundSleepInterval = PropUtil.microsToMillis(mgr.getLong 408 (EnvironmentParams.ENV_BACKGROUND_SLEEP_INTERVAL)); 409 } 410 411 414 private void createDaemons() 415 throws DatabaseException { 416 417 418 evictor = new Evictor(this, "Evictor"); 419 420 421 422 426 long checkpointerWakeupTime = 427 Checkpointer.getWakeupPeriod(configManager); 428 checkpointer = new Checkpointer(this, 429 checkpointerWakeupTime, 430 Environment.CHECKPOINTER_NAME); 431 432 433 long compressorWakeupInterval = 434 PropUtil.microsToMillis 435 (configManager.getLong 436 (EnvironmentParams.COMPRESSOR_WAKEUP_INTERVAL)); 437 inCompressor = new INCompressor(this, compressorWakeupInterval, 438 Environment.INCOMP_NAME); 439 440 441 cleaner = new Cleaner(this, Environment.CLEANER_NAME); 442 } 443 444 447 private void runOrPauseDaemons(DbConfigManager mgr) 448 throws DatabaseException { 449 450 if (!isReadOnly) { 451 452 inCompressor.runOrPause 453 (mgr.getBoolean(EnvironmentParams.ENV_RUN_INCOMPRESSOR)); 454 455 456 cleaner.runOrPause 457 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CLEANER) && 458 !isMemOnly); 459 460 464 checkpointer.runOrPause 465 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CHECKPOINTER)); 466 } 467 468 469 evictor.runOrPause 470 (mgr.getBoolean(EnvironmentParams.ENV_RUN_EVICTOR)); 471 } 472 473 479 public INCompressor getINCompressor() { 480 return inCompressor; 481 } 482 483 486 public UtilizationTracker getUtilizationTracker() { 487 return cleaner.getUtilizationTracker(); 488 } 489 490 493 public UtilizationProfile getUtilizationProfile() { 494 return cleaner.getUtilizationProfile(); 495 } 496 497 506 public void updateBackgroundReads(int nReads) { 507 508 512 int limit = backgroundReadLimit; 513 if (limit > 0) { 514 synchronized (backgroundTrackingMutex) { 515 backgroundReadCount += nReads; 516 if (backgroundReadCount >= limit) { 517 backgroundSleepBacklog += 1; 518 519 backgroundReadCount -= limit; 520 assert backgroundReadCount >= 0; 521 } 522 } 523 } 524 } 525 526 539 public void updateBackgroundWrites(int writeSize, int logBufferSize) { 540 541 545 int limit = backgroundWriteLimit; 546 if (limit > 0) { 547 synchronized (backgroundTrackingMutex) { 548 backgroundWriteBytes += writeSize; 549 int writeCount = (int) (backgroundWriteBytes / logBufferSize); 550 if (writeCount >= limit) { 551 backgroundSleepBacklog += 1; 552 553 backgroundWriteBytes -= (limit * logBufferSize); 554 assert backgroundWriteBytes >= 0; 555 } 556 } 557 } 558 } 559 560 573 public void sleepAfterBackgroundIO() { 574 if (backgroundSleepBacklog > 0) { 575 synchronized (backgroundSleepMutex) { 576 577 try { 578 579 Thread.sleep(backgroundSleepInterval); 580 } catch (InterruptedException e) { 581 Thread.currentThread().interrupt(); 582 } 583 584 assert TestHookExecute.doHookIfSet(backgroundSleepHook); 585 } 586 synchronized (backgroundTrackingMutex) { 587 588 if (backgroundSleepBacklog > 0) { 589 backgroundSleepBacklog -= 1; 590 } 591 } 592 } 593 } 594 595 596 public void setBackgroundSleepHook(TestHook hook) { 597 backgroundSleepHook = hook; 598 } 599 600 603 public void logMapTreeRoot() 604 throws DatabaseException { 605 606 mapTreeRootLatch.acquire(); 607 try { 608 mapTreeRootLsn = logManager.log(dbMapTree); 609 } finally { 610 mapTreeRootLatch.release(); 611 } 612 } 613 614 617 public void rewriteMapTreeRoot(long cleanerTargetLsn) 618 throws DatabaseException { 619 620 mapTreeRootLatch.acquire(); 621 try { 622 if (DbLsn.compareTo(cleanerTargetLsn, mapTreeRootLsn) == 0) { 623 624 628 mapTreeRootLsn = logManager.log(dbMapTree); 629 } 630 } finally { 631 mapTreeRootLatch.release(); 632 } 633 } 634 635 638 public long getRootLsn() { 639 return mapTreeRootLsn; 640 } 641 642 645 public void readMapTreeFromLog(long rootLsn) 646 throws DatabaseException { 647 648 dbMapTree = (DbTree) logManager.get(rootLsn); 649 dbMapTree.setEnvironmentImpl(this); 650 651 652 mapTreeRootLatch.acquire(); 653 try { 654 mapTreeRootLsn = rootLsn; 655 } finally { 656 mapTreeRootLatch.release(); 657 } 658 } 659 660 664 public void addToCompressorQueue(BIN bin, 665 Key deletedKey, 666 boolean doWakeup) 667 throws DatabaseException { 668 669 673 if (inCompressor != null) { 674 inCompressor.addBinKeyToQueue(bin, deletedKey, doWakeup); 675 } 676 } 677 678 682 public void addToCompressorQueue(BINReference binRef, 683 boolean doWakeup) 684 throws DatabaseException { 685 686 690 if (inCompressor != null) { 691 inCompressor.addBinRefToQueue(binRef, doWakeup); 692 } 693 } 694 695 699 public void addToCompressorQueue(Collection binRefs, 700 boolean doWakeup) 701 throws DatabaseException { 702 703 707 if (inCompressor != null) { 708 inCompressor.addMultipleBinRefsToQueue(binRefs, doWakeup); 709 } 710 } 711 712 715 public void lazyCompress(IN in) 716 throws DatabaseException { 717 718 722 if (inCompressor != null) { 723 inCompressor.lazyCompress(in); 724 } 725 } 726 727 732 private Logger initLogger(File envHome) 733 throws DatabaseException { 734 735 738 Logger logger = Logger.getAnonymousLogger(); 739 740 744 logger.setUseParentHandlers(false); 745 746 747 Level level = 748 Tracer.parseLevel(this, EnvironmentParams.JE_LOGGING_LEVEL); 749 logger.setLevel(level); 750 751 752 if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_CONSOLE)) { 753 Handler consoleHandler = new ConsoleHandler (); 754 consoleHandler.setLevel(level); 755 logger.addHandler(consoleHandler); 756 } 757 758 759 Handler fileHandler = null; 760 try { 761 if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_FILE)) { 762 763 764 int limit = 765 configManager.getInt(EnvironmentParams. 766 JE_LOGGING_FILE_LIMIT); 767 int count = 768 configManager.getInt(EnvironmentParams. 769 JE_LOGGING_FILE_COUNT); 770 String logFilePattern = envHome + "/" + Tracer.INFO_FILES; 771 772 fileHandler = new FileHandler (logFilePattern, 773 limit, count, true); 774 fileHandler.setFormatter(new SimpleFormatter ()); 775 fileHandler.setLevel(level); 776 logger.addHandler(fileHandler); 777 } 778 } catch (IOException e) { 779 throw new DatabaseException(e.getMessage()); 780 } 781 782 return logger; 783 } 784 785 789 public void enableDebugLoggingToDbLog() 790 throws DatabaseException { 791 792 if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_DBLOG)) { 793 Handler dbLogHandler = new TraceLogHandler(this); 794 Level level = 795 Level.parse(configManager.get(EnvironmentParams. 796 JE_LOGGING_LEVEL)); 797 dbLogHandler.setLevel(level); 798 envLogger.addHandler(dbLogHandler); 799 } 800 } 801 802 805 public void closeLogger() { 806 Handler [] handlers = envLogger.getHandlers(); 807 for (int i = 0; i < handlers.length; i++) { 808 handlers[i].close(); 809 } 810 } 811 812 815 public void open() { 816 envState = DbEnvState.OPEN; 817 } 818 819 823 public void invalidate(RunRecoveryException e) { 824 825 831 savedInvalidatingException = e; 832 envState = DbEnvState.INVALID; 833 requestShutdownDaemons(); 834 } 835 836 public void invalidate(Error e) { 837 savedInvalidatingException = (RunRecoveryException) 838 SAVED_RRE.initCause(e); 839 envState = DbEnvState.INVALID; 840 requestShutdownDaemons(); 841 } 842 843 846 public boolean isOpen() { 847 return (envState == DbEnvState.OPEN); 848 } 849
|