1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002, 2014 Oracle and/or its affiliates. All rights reserved. 5 * 6 */ 7 package com.sleepycat.je.dbi; 8 9 import static com.sleepycat.je.dbi.DbiStatDefinition.ENVIMPL_CREATION_TIME; 10 import static com.sleepycat.je.dbi.DbiStatDefinition.ENVIMPL_RELATCHES_REQUIRED; 11 import static com.sleepycat.je.dbi.DbiStatDefinition.ENV_GROUP_DESC; 12 import static com.sleepycat.je.dbi.DbiStatDefinition.ENV_GROUP_NAME; 13 import static com.sleepycat.je.dbi.DbiStatDefinition.THROUGHPUT_GROUP_DESC; 14 import static com.sleepycat.je.dbi.DbiStatDefinition.THROUGHPUT_GROUP_NAME; 15 16 import java.io.File; 17 import java.io.IOException; 18 import java.io.PrintStream; 19 import java.io.PrintWriter; 20 import java.io.StringWriter; 21 import java.util.ArrayList; 22 import java.util.Arrays; 23 import java.util.Collection; 24 import java.util.Comparator; 25 import java.util.Enumeration; 26 import java.util.List; 27 import java.util.NavigableSet; 28 import java.util.Properties; 29 import java.util.SortedSet; 30 import java.util.concurrent.atomic.AtomicInteger; 31 import java.util.concurrent.locks.ReentrantReadWriteLock; 32 import java.util.logging.ConsoleHandler; 33 import java.util.logging.FileHandler; 34 import java.util.logging.Formatter; 35 import java.util.logging.Handler; 36 import java.util.logging.Level; 37 import java.util.logging.Logger; 38 39 import com.sleepycat.je.CacheMode; 40 import com.sleepycat.je.CacheModeStrategy; 41 import com.sleepycat.je.CheckpointConfig; 42 import com.sleepycat.je.CustomStats; 43 import com.sleepycat.je.Database; 44 import com.sleepycat.je.DatabaseException; 45 import com.sleepycat.je.DbInternal; 46 import com.sleepycat.je.Environment; 47 import com.sleepycat.je.EnvironmentConfig; 48 import com.sleepycat.je.EnvironmentFailureException; 49 import com.sleepycat.je.EnvironmentLockedException; 50 import com.sleepycat.je.EnvironmentMutableConfig; 51 import com.sleepycat.je.EnvironmentNotFoundException; 52 import com.sleepycat.je.EnvironmentStats; 53 import com.sleepycat.je.ExceptionListener; 54 import com.sleepycat.je.LockStats; 55 import com.sleepycat.je.OperationFailureException; 56 import com.sleepycat.je.PreloadConfig; 57 import com.sleepycat.je.PreloadStats; 58 import com.sleepycat.je.PreloadStatus; 59 import com.sleepycat.je.ProgressListener; 60 import com.sleepycat.je.RecoveryProgress; 61 import com.sleepycat.je.ReplicaConsistencyPolicy; 62 import com.sleepycat.je.StatsConfig; 63 import com.sleepycat.je.Transaction; 64 import com.sleepycat.je.TransactionConfig; 65 import com.sleepycat.je.TransactionStats; 66 import com.sleepycat.je.TransactionStats.Active; 67 import com.sleepycat.je.VerifyConfig; 68 import com.sleepycat.je.VersionMismatchException; 69 import com.sleepycat.je.cleaner.Cleaner; 70 import com.sleepycat.je.cleaner.UtilizationProfile; 71 import com.sleepycat.je.cleaner.UtilizationTracker; 72 import com.sleepycat.je.config.EnvironmentParams; 73 import com.sleepycat.je.dbi.SortedLSNTreeWalker.TreeNodeProcessor; 74 import com.sleepycat.je.dbi.StartupTracker.Phase; 75 import com.sleepycat.je.evictor.Evictor; 76 import com.sleepycat.je.incomp.INCompressor; 77 import com.sleepycat.je.latch.Latch; 78 import com.sleepycat.je.latch.LatchFactory; 79 import com.sleepycat.je.latch.LatchSupport; 80 import com.sleepycat.je.log.FileManager; 81 import com.sleepycat.je.log.LogEntryHeader; 82 import com.sleepycat.je.log.LogEntryType; 83 import com.sleepycat.je.log.LogItem; 84 import com.sleepycat.je.log.LogManager; 85 import com.sleepycat.je.log.ReplicationContext; 86 import com.sleepycat.je.log.Trace; 87 import com.sleepycat.je.log.entry.LogEntry; 88 import com.sleepycat.je.log.entry.SingleItemEntry; 89 import com.sleepycat.je.log.entry.TraceLogEntry; 90 import com.sleepycat.je.recovery.Checkpointer; 91 import com.sleepycat.je.recovery.RecoveryInfo; 92 import com.sleepycat.je.recovery.RecoveryManager; 93 import com.sleepycat.je.recovery.VLSNRecoveryProxy; 94 import com.sleepycat.je.statcap.EnvStatsLogger; 95 import com.sleepycat.je.statcap.StatCapture; 96 import com.sleepycat.je.statcap.StatCaptureDefinitions; 97 import com.sleepycat.je.statcap.StatManager; 98 import com.sleepycat.je.tree.BIN; 99 import com.sleepycat.je.tree.BINReference; 100 import com.sleepycat.je.tree.IN; 101 import com.sleepycat.je.tree.LN; 102 import com.sleepycat.je.tree.Node; 103 import com.sleepycat.je.tree.dupConvert.DupConvert; 104 import com.sleepycat.je.txn.LockType; 105 import com.sleepycat.je.txn.LockUpgrade; 106 import com.sleepycat.je.txn.Locker; 107 import com.sleepycat.je.txn.ThreadLocker; 108 import com.sleepycat.je.txn.Txn; 109 import com.sleepycat.je.txn.TxnManager; 110 import com.sleepycat.je.util.DbBackup; 111 import com.sleepycat.je.utilint.AtomicLongStat; 112 import com.sleepycat.je.utilint.DbLsn; 113 import com.sleepycat.je.utilint.LoggerUtils; 114 import com.sleepycat.je.utilint.LongStat; 115 import com.sleepycat.je.utilint.StatDefinition; 116 import com.sleepycat.je.utilint.StatGroup; 117 import com.sleepycat.je.utilint.TestHook; 118 import com.sleepycat.je.utilint.TestHookExecute; 119 import com.sleepycat.je.utilint.ThroughputStatGroup; 120 import com.sleepycat.je.utilint.TracerFormatter; 121 import com.sleepycat.je.utilint.VLSN; 122 123 /** 124 * Underlying Environment implementation. There is a single instance for any 125 * database environment opened by the application. 126 */ 127 public class EnvironmentImpl implements EnvConfigObserver { 128 129 /* 130 * Set true and run unit tests for NO_LOCKING_MODE test. 131 * EnvironmentConfigTest.testInconsistentParams will fail. [#13788] 132 */ 133 private static final boolean TEST_NO_LOCKING_MODE = false; 134 135 /* Attributes of the entire environment */ 136 private volatile DbEnvState envState; 137 private volatile boolean closing;// true if close has begun 138 private final File envHome; 139 private final AtomicInteger openCount = new AtomicInteger(0); 140 // count of open environment handles 141 private final AtomicInteger backupCount = new AtomicInteger(0); 142 // count of in-progress dbBackup 143 private boolean isTransactional; // true if env opened with DB_INIT_TRANS 144 private boolean isNoLocking; // true if env has no locking 145 private boolean isReadOnly; // true if env opened with the read only flag. 146 private boolean isMemOnly; // true if je.log.memOnly=true 147 private boolean sharedCache; // true if je.sharedCache=true 148 /* true if offset tracking should be used for deferred write dbs. */ 149 private boolean dbEviction; 150 151 private boolean allowBlindOps = false; 152 private boolean allowBlindPuts = false; 153 154 private CacheMode cacheMode; 155 private CacheModeStrategy cacheModeStrategy; 156 157 /* Whether or not initialization succeeded. */ 158 private boolean initializedSuccessfully = false; 159 160 /* 161 * Represents whether this environment needs to be converted from 162 * standalone to replicated. 163 */ 164 protected boolean needRepConvert = false; 165 166 private MemoryBudget memoryBudget; 167 private static int adler32ChunkSize; 168 169 /* Save so we don't have to look it up in the config manager frequently. */ 170 private long lockTimeout; 171 private long txnTimeout; 172 173 /* Directory of databases */ 174 protected DbTree dbMapTree; 175 private long mapTreeRootLsn = DbLsn.NULL_LSN; 176 private Latch mapTreeRootLatch; 177 178 private INList inMemoryINs; 179 180 /* Services */ 181 protected DbConfigManager configManager; 182 private List<EnvConfigObserver> configObservers; 183 protected Logger envLogger; 184 private LogManager logManager; 185 private FileManager fileManager; 186 private TxnManager txnManager; 187 protected StatManager statManager; 188 189 /* Daemons */ 190 private Evictor evictor; 191 private INCompressor inCompressor; 192 private Checkpointer checkpointer; 193 private Cleaner cleaner; 194 private StatCapture statCapture; 195 196 /* Stats, debug information */ 197 protected final StartupTracker startupTracker; 198 private volatile EnvironmentFailureException savedInvalidatingException; 199 private TestHook<Long> cleanerBarrierHoook; 200 201 /* If true, call Thread.yield() at strategic points (stress test aid) */ 202 private static boolean forcedYield = false; 203 204 /* 205 * Used by Database, SecondaryDatabase and Cursor to protect changes to 206 * secondary associations during operations that use the associations. A 207 * single latch for all databases is used to prevent deadlocks and to 208 * support associations involving multiple primary databases. 209 * 210 * A ReentrantReadWriteLock is used directly rather than via a SharedLatch. 211 * This is because reentrancy is required but not supported by SharedLatch. 212 */ 213 private ReentrantReadWriteLock secondaryAssociationLock; 214 215 /** 216 * The exception listener for this environment, if any has been specified. 217 */ 218 private ExceptionListener exceptionListener = null; 219 220 /** 221 * The recovery progress listener for this environment, if any has been 222 * specified. 223 */ 224 private ProgressListener<RecoveryProgress> recoveryProgressListener = null; 225 226 /** 227 * ClassLoader used to load user-supplied classes by name. 228 */ 229 private ClassLoader classLoader = null; 230 231 /** 232 * Used for duplicate database conversion. 233 */ 234 private PreloadConfig dupConvertPreloadConfig = null; 235 236 /* 237 * Configuration and tracking of background IO limits. Managed by the 238 * updateBackgroundReads, updateBackgroundWrites and sleepAfterBackgroundIO 239 * methods. The limits and the backlog are volatile because we check them 240 * outside the synchronized block. Other fields are updated and checked 241 * while synchronized on the tracking mutex object. The sleep mutex is 242 * used to block multiple background threads while sleeping. 243 */ 244 private volatile int backgroundSleepBacklog; 245 private volatile int backgroundReadLimit; 246 private volatile int backgroundWriteLimit; 247 private long backgroundSleepInterval; 248 private int backgroundReadCount; 249 private long backgroundWriteBytes; 250 private TestHook<?> backgroundSleepHook; 251 private final Object backgroundTrackingMutex = new Object(); 252 private final Object backgroundSleepMutex = new Object(); 253 254 /* 255 * ThreadLocal.get() is not cheap so we want to minimize calls to it. We 256 * only use ThreadLocals for the TreeStatsAccumulator which are only called 257 * in limited circumstances. Use this reference count to indicate that a 258 * thread has set a TreeStatsAccumulator. When it's done, it decrements 259 * the counter. It's static so that we don't have to pass around the 260 * EnvironmentImpl. 261 */ 262 private static int threadLocalReferenceCount = 0; 263 264 /* Used to prevent multiple full thread dumps. */ 265 private boolean didFullThreadDump = false; 266 267 /** 268 * DbPrintLog doesn't need btree and dup comparators to function properly 269 * don't require any instantiations. This flag, if true, indicates that 270 * we've been called from DbPrintLog or a similar utility. 271 */ 272 private boolean noComparators = false; 273 274 /* 275 * A preallocated EnvironmentFailureException that is used in OOME and 276 * other java.lang.Error situations so that allocation does not need to be 277 * done in the OOME context. 278 */ 279 public final EnvironmentFailureException SAVED_EFE = 280 EnvironmentFailureException.makeJavaErrorWrapper(); 281 282 public static final boolean USE_JAVA5_ADLER32; 283 284 private static final String DISABLE_JAVA_ADLER32_NAME = 285 "je.disable.java.adler32"; 286 287 static { 288 USE_JAVA5_ADLER32 = 289 System.getProperty(DISABLE_JAVA_ADLER32_NAME) == null; 290 } 291 292 /* 293 * JE MBeans. 294 * 295 * Note that MBeans are loaded dynamically in order to support platforms 296 * that do not include javax.management. TODO: Since Dalvik is no longer 297 * supported, we may want to remove this abstraction. 298 */ 299 300 /* The property name of setting these two MBeans. */ 301 private static final String REGISTER_MONITOR = "JEMonitor"; 302 303 /* The two MBeans registered or not. */ 304 private volatile boolean isMBeanRegistered = false; 305 306 /* 307 * Log handlers used in java.util.logging. Handlers are per-environment, 308 * and must not be static, because the output is tagged with an identifier 309 * that associates the information with that environment. Handlers should 310 * be closed to release resources when the environment is closed. 311 * 312 * Note that handlers are not statically attached to loggers. See 313 * LoggerUtils.java for information on how redirect loggers are used. 314 */ 315 private static final String INFO_FILES = "je.info"; 316 private static final int FILEHANDLER_LIMIT = 10000000; 317 private static final int FILEHANDLER_COUNT = 10; 318 private final ConsoleHandler consoleHandler; 319 private final FileHandler fileHandler; 320 321 /* 322 * A Handler that was specified by the application through 323 * EnvironmentConfig 324 */ 325 private final Handler configuredHandler; 326 /* cache this value as a performance optimization. */ 327 private boolean dbLoggingDisabled; 328 329 /* Formatter for java.util.logging. */ 330 protected final Formatter formatter; 331 332 /* 333 * The internal environment handle that is passed to triggers invoked as a 334 * result of AutoTransactions where no environment handle is available, and 335 * in all cases of triggers involving replicated environments. 336 */ 337 protected Environment envInternal; 338 339 /* 340 * Used to coordinate getting stats and shutting down the threads 341 * that provide the stats. The shutdown of the statistics capture 342 * thread will get statistics right before shutting down. The 343 * acquisition of stats must be done without synchronizing on the 344 * EnvironmentImpl to avoid a deadlock between the shutdown thread 345 * (has the EnvironmentImpl lock) and the stat capture thread calling 346 * getStats(). 347 */ 348 private final Object statSynchronizer = new Object(); 349 350 /* Stat base key used for loadStats api */ 351 protected Integer statKey; 352 353 private long creationTime; 354 355 /** 356 * To support platforms that do not have any javax.management classes, we 357 * load JEMonitor dynamically to ensure that there are no explicit 358 * references to com.sleepycat.je.jmx.*. 359 */ 360 public static interface MBeanRegistrar { doRegister(Environment env)361 public void doRegister(Environment env) 362 throws Exception; 363 doUnregister()364 public void doUnregister() 365 throws Exception; 366 } 367 368 private final ArrayList<MBeanRegistrar> mBeanRegList = 369 new ArrayList<MBeanRegistrar>(); 370 371 /* NodeId sequence counters */ 372 private final NodeSequence nodeSequence; 373 374 /* Stats */ 375 private StatGroup stats; 376 377 private ThroughputStatGroup thrputStats; 378 379 private CustomStats customStats; 380 381 /* Number of relatches required in this environment. */ 382 private LongStat relatchesRequired; 383 384 private EnvStatsLogger envStatLogger = null; 385 386 /* Refer to comment near declaration of these static LockUpgrades. */ 387 static { 388 LockUpgrade.ILLEGAL.setUpgrade(null); 389 LockUpgrade.EXISTING.setUpgrade(null); 390 LockUpgrade.WRITE_PROMOTE.setUpgrade(LockType.WRITE); 391 LockUpgrade.RANGE_READ_IMMED.setUpgrade(LockType.RANGE_READ); 392 LockUpgrade.RANGE_WRITE_IMMED.setUpgrade(LockType.RANGE_WRITE); 393 LockUpgrade.RANGE_WRITE_PROMOTE.setUpgrade(LockType.RANGE_WRITE); 394 } 395 396 /* May be null, see getOptionalNodeName. */ 397 private final String optionalNodeName; 398 399 /* EnvironmentConfig.TREE_COMPACT_MAX_KEY_LENGTH. */ 400 private int compactMaxKeyLength; 401 402 /* EnvironmentParams.ENV_LATCH_TIMEOUT. */ 403 private int latchTimeoutMs; 404 EnvironmentImpl(File envHome, EnvironmentConfig envConfig, EnvironmentImpl sharedCacheEnv)405 public EnvironmentImpl(File envHome, 406 EnvironmentConfig envConfig, 407 EnvironmentImpl sharedCacheEnv) 408 throws EnvironmentNotFoundException, EnvironmentLockedException { 409 410 this(envHome, envConfig, sharedCacheEnv, null); 411 } 412 413 /** 414 * Create a database environment to represent the data in envHome. 415 * dbHome. Properties from the je.properties file in that directory are 416 * used to initialize the system wide property bag. Properties passed to 417 * this method are used to influence the open itself. 418 * 419 * @param envHome absolute path of the database environment home directory 420 * @param envConfig is the configuration to be used. It's already had 421 * the je.properties file applied, and has been validated. 422 * @param sharedCacheEnv if non-null, is another environment that is 423 * sharing the cache with this environment; if null, this environment is 424 * not sharing the cache or is the first environment to share the cache. 425 * 426 * @throws DatabaseException on all other failures 427 * 428 * @throws IllegalArgumentException via Environment ctor. 429 */ EnvironmentImpl(File envHome, EnvironmentConfig envConfig, EnvironmentImpl sharedCacheEnv, RepConfigProxy repConfigProxy)430 protected EnvironmentImpl(File envHome, 431 EnvironmentConfig envConfig, 432 EnvironmentImpl sharedCacheEnv, 433 RepConfigProxy repConfigProxy) 434 throws EnvironmentNotFoundException, EnvironmentLockedException { 435 436 boolean success = false; 437 startupTracker = new StartupTracker(this); 438 startupTracker.start(Phase.TOTAL_ENV_OPEN); 439 440 try { 441 this.envHome = envHome; 442 envState = DbEnvState.INIT; 443 mapTreeRootLatch = LatchFactory.createExclusiveLatch( 444 this, "MapTreeRoot", false /*collectStats*/); 445 446 /* Do the stats definition. */ 447 stats = new StatGroup(ENV_GROUP_NAME, ENV_GROUP_DESC); 448 thrputStats = 449 new ThroughputStatGroup 450 (THROUGHPUT_GROUP_NAME, THROUGHPUT_GROUP_DESC); 451 452 relatchesRequired = 453 new LongStat(stats, ENVIMPL_RELATCHES_REQUIRED); 454 creationTime = System.currentTimeMillis(); 455 456 /* Set up configuration parameters */ 457 configManager = initConfigManager(envConfig, repConfigProxy); 458 configObservers = new ArrayList<EnvConfigObserver>(); 459 addConfigObserver(this); 460 initConfigParams(envConfig, repConfigProxy); 461 462 /* 463 * Create essential services that must exist before recovery. 464 */ 465 466 /* 467 * Set up java.util.logging handlers and their environment specific 468 * formatters. These are used by the redirect handlers, rather 469 * than specific loggers. 470 */ 471 formatter = initFormatter(); 472 consoleHandler = 473 new com.sleepycat.je.util.ConsoleHandler(formatter, this); 474 fileHandler = initFileHandler(); 475 configuredHandler = envConfig.getLoggingHandler(); 476 envLogger = LoggerUtils.getLogger(getClass()); 477 478 /* 479 * Decide on memory budgets based on environment config params and 480 * memory available to this process. 481 */ 482 memoryBudget = 483 new MemoryBudget(this, sharedCacheEnv, configManager); 484 485 fileManager = new FileManager(this, envHome, isReadOnly); 486 if (!envConfig.getAllowCreate() && !fileManager.filesExist()) { 487 throw new EnvironmentNotFoundException 488 (this, "Home directory: " + envHome); 489 } 490 491 optionalNodeName = envConfig.getNodeName(); 492 493 logManager = new LogManager(this, isReadOnly); 494 495 inMemoryINs = new INList(this); 496 txnManager = new TxnManager(this); 497 statManager = createStatManager(); 498 499 /* 500 * Daemons are always made here, but only started after recovery. 501 * We want them to exist so we can call them programatically even 502 * if the daemon thread is not started. 503 */ 504 createDaemons(sharedCacheEnv); 505 506 /* 507 * The node sequences are not initialized until after the DbTree is 508 * created below. 509 */ 510 nodeSequence = new NodeSequence(this); 511 512 /* 513 * Instantiate a new, blank dbtree. If the environment already 514 * exists, recovery will recreate the dbMapTree from the log and 515 * overwrite this instance. 516 */ 517 dbMapTree = new DbTree(this, isReplicated(), getPreserveVLSN()); 518 519 secondaryAssociationLock = 520 new ReentrantReadWriteLock(false /*fair*/); 521 522 /* 523 * Allocate node sequences before recovery. We expressly wait to 524 * allocate it after the DbTree is created, because these sequences 525 * should not be used by the DbTree before recovery has 526 * run. Waiting until now to allocate them will make errors more 527 * evident, since there will be a NullPointerException. 528 */ 529 nodeSequence.initRealNodeId(); 530 531 statKey = statManager.registerStatContext(); 532 if (!isReadOnly() && 533 !isMemOnly() && 534 configManager.getBoolean(EnvironmentParams.STATS_COLLECT)) { 535 envStatLogger = new EnvStatsLogger(this); 536 addConfigObserver(envStatLogger); 537 envStatLogger.log(); 538 } 539 success = true; 540 } finally { 541 if (!success) { 542 /* Release any environment locks if there was a problem. */ 543 clearFileManager(); 544 closeHandlers(); 545 } 546 } 547 } 548 549 /** 550 * Create a config manager that holds the configuration properties that 551 * have been passed in. These properties are already validated, and have 552 * had the proper order of precedence applied; that is, the je.properties 553 * file has been applied. The configuration properties need to be available 554 * before the rest of environment creation proceeds. 555 * 556 * This method is overridden by replication environments. 557 * 558 * @param envConfig is the environment configuration to use 559 * @param repParams are the replication configurations to use. In this 560 * case, the Properties bag has been extracted from the configuration 561 * instance, to avoid crossing the compilation firewall. 562 */ initConfigManager(EnvironmentConfig envConfig, RepConfigProxy repParams)563 protected DbConfigManager initConfigManager(EnvironmentConfig envConfig, 564 RepConfigProxy repParams) { 565 return new DbConfigManager(envConfig); 566 } 567 568 /** 569 * Init configuration params during environment creation. 570 * 571 * This method is overridden by RepImpl to get init params also. This 572 * allows certain rep params to be accessed from the EnvironmentImpl 573 * constructor using methods such as getPreserveVLSN. The overridden method 574 * calls this method first. 575 * @param repConfigProxy unused 576 */ initConfigParams(EnvironmentConfig envConfig, RepConfigProxy repConfigProxy)577 protected void initConfigParams(EnvironmentConfig envConfig, 578 RepConfigProxy repConfigProxy) { 579 580 forcedYield = 581 configManager.getBoolean(EnvironmentParams.ENV_FORCED_YIELD); 582 isTransactional = 583 configManager.getBoolean(EnvironmentParams.ENV_INIT_TXN); 584 isNoLocking = !(configManager.getBoolean 585 (EnvironmentParams.ENV_INIT_LOCKING)); 586 if (isTransactional && isNoLocking) { 587 if (TEST_NO_LOCKING_MODE) { 588 isNoLocking = !isTransactional; 589 } else { 590 throw new IllegalArgumentException 591 ("Can't set 'je.env.isNoLocking' and " + 592 "'je.env.isTransactional';"); 593 } 594 } 595 596 isReadOnly = configManager.getBoolean( 597 EnvironmentParams.ENV_RDONLY); 598 599 isMemOnly = configManager.getBoolean( 600 EnvironmentParams.LOG_MEMORY_ONLY); 601 602 dbEviction = configManager.getBoolean( 603 EnvironmentParams.ENV_DB_EVICTION); 604 605 adler32ChunkSize = configManager.getInt( 606 EnvironmentParams.ADLER32_CHUNK_SIZE); 607 608 sharedCache = configManager.getBoolean( 609 EnvironmentParams.ENV_SHARED_CACHE); 610 611 dbLoggingDisabled = !configManager.getBoolean( 612 EnvironmentParams.JE_LOGGING_DBLOG); 613 614 compactMaxKeyLength = configManager.getInt( 615 EnvironmentParams.TREE_COMPACT_MAX_KEY_LENGTH); 616 617 latchTimeoutMs = configManager.getDuration( 618 EnvironmentParams.ENV_LATCH_TIMEOUT); 619 620 allowBlindOps = configManager.getBoolean( 621 EnvironmentParams.BIN_DELTA_BLIND_OPS); 622 623 allowBlindPuts = configManager.getBoolean( 624 EnvironmentParams.BIN_DELTA_BLIND_PUTS); 625 626 recoveryProgressListener = envConfig.getRecoveryProgressListener(); 627 classLoader = envConfig.getClassLoader(); 628 dupConvertPreloadConfig = envConfig.getDupConvertPreloadConfig(); 629 customStats = envConfig.getCustomStats(); 630 } 631 632 /** 633 * Initialize the environment, including running recovery, if it is not 634 * already initialized. 635 * 636 * Note that this method should be called even when opening additional 637 * handles for an already initialized environment. If initialization is 638 * still in progress then this method will block until it is finished. 639 * 640 * @return true if we are opening the first handle for this environment and 641 * recovery is run (when ENV_RECOVERY is configured to true); false if we 642 * are opening an additional handle and recovery is not run. 643 */ finishInit(EnvironmentConfig envConfig)644 public synchronized boolean finishInit(EnvironmentConfig envConfig) 645 throws DatabaseException { 646 647 if (initializedSuccessfully) { 648 return false; 649 } 650 651 boolean success = false; 652 try { 653 654 /* 655 * Do not do recovery if this environment is for a utility that 656 * reads the log directly. 657 */ 658 final boolean doRecovery = 659 configManager.getBoolean(EnvironmentParams.ENV_RECOVERY); 660 if (doRecovery) { 661 662 /* 663 * Run recovery. Note that debug logging to the database log 664 * is disabled until recovery is finished. 665 */ 666 boolean recoverySuccess = false; 667 try { 668 RecoveryManager recoveryManager = 669 new RecoveryManager(this); 670 recoveryManager.recover(isReadOnly); 671 672 postRecoveryConversion(); 673 recoverySuccess = true; 674 } finally { 675 try { 676 677 /* 678 * Flush to get all exception tracing out to the log. 679 */ 680 logManager.flush(); 681 fileManager.clear(); 682 } catch (IOException e) { 683 /* Ignore second order exceptions. */ 684 if (recoverySuccess) { 685 throw new EnvironmentFailureException 686 (this, EnvironmentFailureReason.LOG_INTEGRITY, 687 e); 688 } 689 } catch (Exception e) { 690 if (recoverySuccess) { 691 throw EnvironmentFailureException. 692 unexpectedException(this, e); 693 } 694 } 695 } 696 } else { 697 isReadOnly = true; 698 699 /* 700 * Normally when recovery is skipped, we don't need to 701 * instantiate comparators. But even without recovery, some 702 * utilities such as DbScavenger need comparators. 703 */ 704 if (!configManager.getBoolean 705 (EnvironmentParams.ENV_COMPARATORS_REQUIRED)) { 706 noComparators = true; 707 } 708 } 709 710 /* 711 * Cache a few critical values. We keep our timeout in millis 712 * because Object.wait takes millis. 713 */ 714 lockTimeout = 715 configManager.getDuration(EnvironmentParams.LOCK_TIMEOUT); 716 txnTimeout = 717 configManager.getDuration(EnvironmentParams.TXN_TIMEOUT); 718 719 /* 720 * Initialize the environment memory usage number. Must be called 721 * after recovery, because recovery determines the starting size of 722 * the in-memory tree. 723 */ 724 memoryBudget.initCacheMemoryUsage 725 (dbMapTree.getTreeAdminMemory()); 726 727 /* 728 * Call config observer and start daemons last after everything 729 * else is initialized. Note that all config parameters, both 730 * mutable and non-mutable, needed by the memoryBudget have already 731 * been initialized when the configManager was instantiated. 732 */ 733 envConfigUpdate(configManager, envConfig); 734 735 /* Mark as open before starting daemons. */ 736 open(); 737 738 /* 739 * Mark initialized before creating the internal env, since 740 * otherwise a we'll recurse and attempt to create another 741 * EnvironmentImpl. 742 */ 743 initializedSuccessfully = true; 744 745 if (doRecovery) { 746 747 /* 748 * Perform dup database conversion after recovery and other 749 * initialization is complete, but before running daemons. 750 */ 751 convertDupDatabases(); 752 753 /* Create internal env before SyncCleanerBarrier. */ 754 envInternal = createInternalEnvironment(); 755 } 756 757 runOrPauseDaemons(configManager); 758 success = true; 759 return true; 760 } finally { 761 if (!success) { 762 /* Release any environment locks if there was a problem. */ 763 clearFileManager(); 764 closeHandlers(); 765 } 766 767 /* 768 * DbEnvPool.addEnvironment is called by RecoveryManager.buildTree 769 * during recovery above, to enable eviction during recovery. If 770 * we fail to create the environment, we must remove it. 771 */ 772 if (!success && sharedCache && evictor != null) { 773 evictor.removeEnvironment(this); 774 } 775 776 startupTracker.stop(Phase.TOTAL_ENV_OPEN); 777 startupTracker.setProgress(RecoveryProgress.RECOVERY_FINISHED); 778 } 779 } 780 781 /** 782 * Is overridden in RepImpl to create a ReplicatedEnvironment. 783 */ createInternalEnvironment()784 protected Environment createInternalEnvironment() { 785 return new InternalEnvironment(getEnvironmentHome(), cloneConfig(), 786 this); 787 } 788 789 /* 790 * JE MBean registration is performed during Environment creation so that 791 * the MBean has access to the Environment API which is not available from 792 * EnvironmentImpl. This precludes registering MBeans in 793 * EnvironmentImpl.finishInit. 794 */ registerMBean(Environment env)795 public synchronized void registerMBean(Environment env) 796 throws DatabaseException { 797 798 if (!isMBeanRegistered) { 799 if (System.getProperty(REGISTER_MONITOR) != null) { 800 doRegisterMBean(getMonitorClassName(), env); 801 doRegisterMBean(getDiagnosticsClassName(), env); 802 } 803 isMBeanRegistered = true; 804 } 805 } 806 getMonitorClassName()807 protected String getMonitorClassName() { 808 return "com.sleepycat.je.jmx.JEMonitor"; 809 } 810 getDiagnosticsClassName()811 protected String getDiagnosticsClassName() { 812 return "com.sleepycat.je.jmx.JEDiagnostics"; 813 } 814 815 /* 816 * Returns the default consistency policy for this EnvironmentImpl. 817 * 818 * When a Txn is created directly for internal use, the default consistency 819 * is needed. For example, SyncDB uses this method. 820 * 821 * This method returns null for a standalone Environment, and returns the 822 * default consistency policy for a ReplicatedEnvironment. 823 */ getDefaultConsistencyPolicy()824 public ReplicaConsistencyPolicy getDefaultConsistencyPolicy() { 825 return null; 826 } 827 828 /* Return the durable VLSN for the replication group. */ getGroupDurableVLSN()829 public VLSN getGroupDurableVLSN() { 830 throw new UnsupportedOperationException 831 ("Standalone Environment doesn't support returning " + 832 "GlobalDurableVLSN."); 833 } 834 835 /* Returns the on disk LSN for a VLSN. */ getLsnForVLSN(@uppressWarningsR) VLSN vlsn, @SuppressWarnings(R) int readBufferSize)836 public long getLsnForVLSN(@SuppressWarnings("unused") VLSN vlsn, 837 @SuppressWarnings("unused") int readBufferSize) { 838 throw new UnsupportedOperationException 839 ("Standalone Environment doesn't support finding LSN for VLSN."); 840 } 841 842 /* Disable the LocalCBVLSN changes on a replicator. */ freezeLocalCBVLSN()843 public void freezeLocalCBVLSN() { 844 throw new UnsupportedOperationException 845 ("Standalone Environment doesn't support LocalCBVLSN."); 846 } 847 848 /* Enable the LocalCBVLSN changes on a replicator. */ unfreezeLocalCBVLSN()849 public void unfreezeLocalCBVLSN() { 850 throw new UnsupportedOperationException 851 ("Standalone Environment doesn't support LocalCBVLSN."); 852 } 853 854 /* 855 * Returns the end of the log. 856 * 857 * Returned value is a Lsn if it's a standalone Environment, otherwise it's 858 * a VLSN. 859 */ getEndOfLog()860 public long getEndOfLog() { 861 return fileManager.getLastUsedLsn(); 862 } 863 864 /* Get replication statistics. */ getRepStatGroups(StatsConfig config, Integer statkey)865 public Collection<StatGroup> getRepStatGroups(StatsConfig config, 866 Integer statkey) { 867 throw new UnsupportedOperationException 868 ("Standalone Environment doesn't support replication statistics."); 869 } 870 getStatCaptureProjections()871 public SortedSet<String> getStatCaptureProjections() { 872 return new StatCaptureDefinitions().getStatisticProjections(); 873 } 874 createStatManager()875 public StatManager createStatManager() { 876 return new StatManager(this); 877 } 878 doRegisterMBean(String className, Environment env)879 private void doRegisterMBean(String className, Environment env) 880 throws DatabaseException { 881 882 try { 883 Class<?> newClass = Class.forName(className); 884 MBeanRegistrar mBeanReg = (MBeanRegistrar) newClass.newInstance(); 885 mBeanReg.doRegister(env); 886 mBeanRegList.add(mBeanReg); 887 } catch (Exception e) { 888 throw new EnvironmentFailureException 889 (DbInternal.getEnvironmentImpl(env), 890 EnvironmentFailureReason.MONITOR_REGISTRATION, e); 891 } 892 } 893 unregisterMBean()894 private synchronized void unregisterMBean() 895 throws Exception { 896 897 for (MBeanRegistrar mBeanReg : mBeanRegList) { 898 mBeanReg.doUnregister(); 899 } 900 } 901 902 /* 903 * Release and close the FileManager when there are problems during the 904 * initialization of this EnvironmentImpl. An exception is already in 905 * flight when this method is called. 906 */ clearFileManager()907 private void clearFileManager() 908 throws DatabaseException { 909 910 if (fileManager != null) { 911 try { 912 913 /* 914 * Clear again, in case an exception in logManager.flush() 915 * caused us to skip the earlier call to clear(). 916 */ 917 fileManager.clear(); 918 } catch (Throwable e) { 919 920 /* 921 * Klockwork - ok 922 * Eat it, we want to throw the original exception. 923 */ 924 } 925 try { 926 fileManager.close(); 927 } catch (Throwable e) { 928 929 /* 930 * Klockwork - ok 931 * Eat it, we want to throw the original exception. 932 */ 933 } 934 } 935 } 936 937 /** 938 * Respond to config updates. 939 */ 940 @Override envConfigUpdate(DbConfigManager mgr, EnvironmentMutableConfig newConfig)941 public void envConfigUpdate(DbConfigManager mgr, 942 EnvironmentMutableConfig newConfig) { 943 backgroundReadLimit = mgr.getInt 944 (EnvironmentParams.ENV_BACKGROUND_READ_LIMIT); 945 backgroundWriteLimit = mgr.getInt 946 (EnvironmentParams.ENV_BACKGROUND_WRITE_LIMIT); 947 backgroundSleepInterval = mgr.getDuration 948 (EnvironmentParams.ENV_BACKGROUND_SLEEP_INTERVAL); 949 950 /* Reset logging levels if they're set in EnvironmentMutableConfig. */ 951 if (newConfig.isConfigParamSet 952 (EnvironmentConfig.CONSOLE_LOGGING_LEVEL)) { 953 Level newConsoleHandlerLevel = 954 Level.parse(mgr.get(EnvironmentParams.JE_CONSOLE_LEVEL)); 955 consoleHandler.setLevel(newConsoleHandlerLevel); 956 } 957 958 if (newConfig.isConfigParamSet 959 (EnvironmentConfig.FILE_LOGGING_LEVEL)) { 960 Level newFileHandlerLevel = 961 Level.parse(mgr.get(EnvironmentParams.JE_FILE_LEVEL)); 962 if (fileHandler != null) { 963 fileHandler.setLevel(newFileHandlerLevel); 964 } 965 } 966 967 exceptionListener = newConfig.getExceptionListener(); 968 969 cacheMode = newConfig.getCacheMode(); 970 cacheModeStrategy = newConfig.getCacheModeStrategy(); 971 972 if (mgr.getBoolean(EnvironmentParams.STATS_COLLECT)) { 973 if (envStatLogger == null && 974 !isReadOnly() && 975 !isMemOnly() ) { 976 envStatLogger = new EnvStatsLogger(this); 977 addConfigObserver(envStatLogger); 978 979 /* 980 * Need to log env stats because stats were off and are now on. 981 * Since stats were off there was no event observer registered. 982 */ 983 envStatLogger.log(); 984 } 985 986 /* Create stat capture object if needed */ 987 createStatCapture(); 988 989 } else { 990 if (envStatLogger != null) { 991 removeConfigObserver(envStatLogger); 992 } 993 envStatLogger = null; 994 shutdownStatCapture(); 995 } 996 997 /* 998 * Start daemons last, after all other parameters are set. Do not 999 * start the daemons during the EnvironmentImpl constructor's call 1000 * (before open() has been called), because this must be done after 1001 * creating the SyncCleanerBarrier. 1002 */ 1003 if (isValid()) { 1004 runOrPauseDaemons(mgr); 1005 } 1006 } 1007 1008 /** 1009 * Read configurations for daemons, instantiate. 1010 */ createDaemons(EnvironmentImpl sharedCacheEnv)1011 private void createDaemons(EnvironmentImpl sharedCacheEnv) 1012 throws DatabaseException { 1013 1014 /* Evictor */ 1015 if (sharedCacheEnv != null) { 1016 assert sharedCache; 1017 evictor = sharedCacheEnv.evictor; 1018 } else { 1019 evictor = new Evictor(this); 1020 } 1021 1022 /* Checkpointer */ 1023 1024 /* 1025 * Make sure that either log-size-based or time-based checkpointing 1026 * is enabled. 1027 */ 1028 long checkpointerWakeupTime = 1029 Checkpointer.getWakeupPeriod(configManager); 1030 checkpointer = new Checkpointer(this, 1031 checkpointerWakeupTime, 1032 Environment.CHECKPOINTER_NAME); 1033 1034 /* INCompressor */ 1035 long compressorWakeupInterval = configManager.getDuration 1036 (EnvironmentParams.COMPRESSOR_WAKEUP_INTERVAL); 1037 inCompressor = new INCompressor(this, compressorWakeupInterval, 1038 Environment.INCOMP_NAME); 1039 1040 /* The cleaner is not time-based so no wakeup interval is used. */ 1041 cleaner = new Cleaner(this, Environment.CLEANER_NAME); 1042 1043 createStatCapture(); 1044 } 1045 1046 /** 1047 * Run or pause daemons, depending on config properties. 1048 */ runOrPauseDaemons(DbConfigManager mgr)1049 private void runOrPauseDaemons(DbConfigManager mgr) { 1050 if (!isReadOnly) { 1051 /* INCompressor */ 1052 inCompressor.runOrPause 1053 (mgr.getBoolean(EnvironmentParams.ENV_RUN_INCOMPRESSOR)); 1054 1055 /* Cleaner. Do not start it if running in-memory */ 1056 cleaner.runOrPause 1057 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CLEANER) && 1058 !isMemOnly); 1059 1060 /* 1061 * Checkpointer. Run in both transactional and non-transactional 1062 * environments to guarantee recovery time. 1063 */ 1064 checkpointer.runOrPause 1065 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CHECKPOINTER)); 1066 1067 /* Stat capture */ 1068 if (statCapture != null) { 1069 statCapture.runOrPause 1070 (mgr.getBoolean(EnvironmentParams.STATS_COLLECT)); 1071 } 1072 } 1073 } 1074 1075 /** 1076 * Return the incompressor. In general, don't use this directly because 1077 * it's easy to forget that the incompressor can be null at times (i.e 1078 * during the shutdown procedure. Instead, wrap the functionality within 1079 * this class, like lazyCompress. 1080 */ getINCompressor()1081 public INCompressor getINCompressor() { 1082 return inCompressor; 1083 } 1084 1085 /** 1086 * Returns the UtilizationTracker. 1087 */ getUtilizationTracker()1088 public UtilizationTracker getUtilizationTracker() { 1089 return cleaner.getUtilizationTracker(); 1090 } 1091 1092 /** 1093 * Returns the UtilizationProfile. 1094 */ getUtilizationProfile()1095 public UtilizationProfile getUtilizationProfile() { 1096 return cleaner.getUtilizationProfile(); 1097 } 1098 1099 /** 1100 * Returns the default cache mode for this environment. If the environment 1101 * has a null cache mode, CacheMode.DEFAULT is returned. Null is never 1102 * returned. 1103 */ getDefaultCacheMode()1104 public CacheMode getDefaultCacheMode() { 1105 if (cacheMode != null) { 1106 return cacheMode; 1107 } 1108 return CacheMode.DEFAULT; 1109 } 1110 1111 /** 1112 * Returns the environment cache mode strategy. Null may be returned. 1113 */ getDefaultCacheModeStrategy()1114 public CacheModeStrategy getDefaultCacheModeStrategy() { 1115 return cacheModeStrategy; 1116 } 1117 1118 /** 1119 * Returns EnvironmentConfig.TREE_COMPACT_MAX_KEY_LENGTH. 1120 */ getCompactMaxKeyLength()1121 public int getCompactMaxKeyLength() { 1122 return compactMaxKeyLength; 1123 } 1124 1125 /** 1126 * Returns EnvironmentParams.ENV_LATCH_TIMEOUT. 1127 */ getLatchTimeoutMs()1128 public int getLatchTimeoutMs() { 1129 return latchTimeoutMs; 1130 } 1131 1132 /** 1133 * If a background read limit has been configured and that limit is 1134 * exceeded when the cumulative total is incremented by the given number of 1135 * reads, increment the sleep backlog to cause a sleep to occur. Called by 1136 * background activities such as the cleaner after performing a file read 1137 * operation. 1138 * 1139 * @see #sleepAfterBackgroundIO 1140 */ updateBackgroundReads(int nReads)1141 public void updateBackgroundReads(int nReads) { 1142 1143 /* 1144 * Make a copy of the volatile limit field since it could change 1145 * between the time we check it and the time we use it below. 1146 */ 1147 int limit = backgroundReadLimit; 1148 if (limit > 0) { 1149 synchronized (backgroundTrackingMutex) { 1150 backgroundReadCount += nReads; 1151 if (backgroundReadCount >= limit) { 1152 backgroundSleepBacklog += 1; 1153 /* Remainder is rolled forward. */ 1154 backgroundReadCount -= limit; 1155 assert backgroundReadCount >= 0; 1156 } 1157 } 1158 } 1159 } 1160 1161 /** 1162 * If a background write limit has been configured and that limit is 1163 * exceeded when the given amount written is added to the cumulative total, 1164 * increment the sleep backlog to cause a sleep to occur. Called by 1165 * background activities such as the checkpointer and evictor after 1166 * performing a file write operation. 1167 * 1168 * <p>The number of writes is estimated by dividing the bytes written by 1169 * the log buffer size. Since the log write buffer is shared by all 1170 * writers, this is the best approximation possible.</p> 1171 * 1172 * @see #sleepAfterBackgroundIO 1173 */ updateBackgroundWrites(int writeSize, int logBufferSize)1174 public void updateBackgroundWrites(int writeSize, int logBufferSize) { 1175 1176 /* 1177 * Make a copy of the volatile limit field since it could change 1178 * between the time we check it and the time we use it below. 1179 */ 1180 int limit = backgroundWriteLimit; 1181 if (limit > 0) { 1182 synchronized (backgroundTrackingMutex) { 1183 backgroundWriteBytes += writeSize; 1184 int writeCount = (int) (backgroundWriteBytes / logBufferSize); 1185 if (writeCount >= limit) { 1186 backgroundSleepBacklog += 1; 1187 /* Remainder is rolled forward. */ 1188 backgroundWriteBytes -= (limit * logBufferSize); 1189 assert backgroundWriteBytes >= 0; 1190 } 1191 } 1192 } 1193 } 1194 1195 /** 1196 * If the sleep backlog is non-zero (set by updateBackgroundReads or 1197 * updateBackgroundWrites), sleep for the configured interval and decrement 1198 * the backlog. 1199 * 1200 * <p>If two threads call this method and the first call causes a sleep, 1201 * the call by the second thread will block until the first thread's sleep 1202 * interval is over. When the call by the second thread is unblocked, if 1203 * another sleep is needed then the second thread will sleep again. In 1204 * other words, when lots of sleeps are needed, background threads may 1205 * backup. This is intended to give foreground threads a chance to "catch 1206 * up" when background threads are doing a lot of IO.</p> 1207 */ sleepAfterBackgroundIO()1208 public void sleepAfterBackgroundIO() { 1209 if (backgroundSleepBacklog > 0) { 1210 synchronized (backgroundSleepMutex) { 1211 /* Sleep. Rethrow interrupts if they occur. */ 1212 try { 1213 /* FindBugs: OK that we're sleeping with a mutex held. */ 1214 Thread.sleep(backgroundSleepInterval); 1215 } catch (InterruptedException e) { 1216 Thread.currentThread().interrupt(); 1217 } 1218 /* Assert has intentional side effect for unit testing. */ 1219 assert TestHookExecute.doHookIfSet(backgroundSleepHook); 1220 } 1221 synchronized (backgroundTrackingMutex) { 1222 /* Decrement backlog last to make other threads wait. */ 1223 if (backgroundSleepBacklog > 0) { 1224 backgroundSleepBacklog -= 1; 1225 } 1226 } 1227 } 1228 } 1229 1230 /* For unit testing only. */ setBackgroundSleepHook(TestHook<?> hook)1231 public void setBackgroundSleepHook(TestHook<?> hook) { 1232 backgroundSleepHook = hook; 1233 } 1234 1235 /* For unit testing only. */ setCleanerBarrierHook(TestHook<Long> hook)1236 public void setCleanerBarrierHook(TestHook<Long> hook) { 1237 cleanerBarrierHoook = hook; 1238 } 1239 1240 /** 1241 * Logs the map tree root and saves the LSN. 1242 */ logMapTreeRoot()1243 public void logMapTreeRoot() 1244 throws DatabaseException { 1245 1246 logMapTreeRoot(DbLsn.NULL_LSN); 1247 } 1248 1249 /** 1250 * Logs the map tree root, but only if its current LSN is before the 1251 * ifBeforeLsn parameter or ifBeforeLsn is NULL_LSN. 1252 */ logMapTreeRoot(long ifBeforeLsn)1253 public void logMapTreeRoot(long ifBeforeLsn) 1254 throws DatabaseException { 1255 1256 mapTreeRootLatch.acquireExclusive(); 1257 try { 1258 if (ifBeforeLsn == DbLsn.NULL_LSN || 1259 DbLsn.compareTo(mapTreeRootLsn, ifBeforeLsn) < 0) { 1260 mapTreeRootLsn = logManager.log( 1261 SingleItemEntry.create(LogEntryType.LOG_DBTREE, 1262 dbMapTree), 1263 ReplicationContext.NO_REPLICATE); 1264 } 1265 } finally { 1266 mapTreeRootLatch.release(); 1267 } 1268 } 1269 1270 /** 1271 * Force a rewrite of the map tree root if required. 1272 */ rewriteMapTreeRoot(long cleanerTargetLsn)1273 public void rewriteMapTreeRoot(long cleanerTargetLsn) 1274 throws DatabaseException { 1275 1276 mapTreeRootLatch.acquireExclusive(); 1277 try { 1278 if (DbLsn.compareTo(cleanerTargetLsn, mapTreeRootLsn) == 0) { 1279 1280 /* 1281 * The root entry targetted for cleaning is in use. Write a 1282 * new copy. 1283 */ 1284 mapTreeRootLsn = logManager.log( 1285 SingleItemEntry.create(LogEntryType.LOG_DBTREE, 1286 dbMapTree), 1287 ReplicationContext.NO_REPLICATE); 1288 } 1289 } finally { 1290 mapTreeRootLatch.release(); 1291 } 1292 } 1293 1294 /** 1295 * @return the mapping tree root LSN. 1296 */ getRootLsn()1297 public long getRootLsn() { 1298 return mapTreeRootLsn; 1299 } 1300 1301 /** 1302 * Set the mapping tree from the log. Called during recovery. 1303 */ readMapTreeFromLog(long rootLsn)1304 public void readMapTreeFromLog(long rootLsn) 1305 throws DatabaseException { 1306 1307 if (dbMapTree != null) { 1308 dbMapTree.close(); 1309 } 1310 dbMapTree = (DbTree) logManager.getEntryHandleFileNotFound(rootLsn); 1311 1312 /* Set the dbMapTree to replicated when converted. */ 1313 if (!dbMapTree.isReplicated() && getAllowRepConvert()) { 1314 dbMapTree.setIsReplicated(); 1315 dbMapTree.setIsRepConverted(); 1316 needRepConvert = true; 1317 } 1318 1319 dbMapTree.initExistingEnvironment(this); 1320 1321 /* Set the map tree root */ 1322 mapTreeRootLatch.acquireExclusive(); 1323 try { 1324 mapTreeRootLsn = rootLsn; 1325 } finally { 1326 mapTreeRootLatch.release(); 1327 } 1328 } 1329 1330 /** 1331 * Tells the asynchronous IN compressor thread about a BIN with a deleted 1332 * entry. 1333 */ addToCompressorQueue(BIN bin, boolean doWakeup)1334 public void addToCompressorQueue(BIN bin, boolean doWakeup) { 1335 1336 /* 1337 * May be called by the cleaner on its last cycle, after the compressor 1338 * is shut down. 1339 */ 1340 if (inCompressor != null) { 1341 inCompressor.addBinToQueue(bin, doWakeup); 1342 } 1343 } 1344 1345 /** 1346 * Tells the asynchronous IN compressor thread about a BINReference with a 1347 * deleted entry. 1348 */ addToCompressorQueue(BINReference binRef, boolean doWakeup)1349 public void addToCompressorQueue(BINReference binRef, boolean doWakeup) { 1350 1351 /* 1352 * May be called by the cleaner on its last cycle, after the compressor 1353 * is shut down. 1354 */ 1355 if (inCompressor != null) { 1356 inCompressor.addBinRefToQueue(binRef, doWakeup); 1357 } 1358 } 1359 1360 /** 1361 * Tells the asynchronous IN compressor thread about a collections of 1362 * BINReferences with deleted entries. 1363 */ addToCompressorQueue(Collection<BINReference> binRefs, boolean doWakeup)1364 public void addToCompressorQueue(Collection<BINReference> binRefs, 1365 boolean doWakeup) { 1366 1367 /* 1368 * May be called by the cleaner on its last cycle, after the compressor 1369 * is shut down. 1370 */ 1371 if (inCompressor != null) { 1372 inCompressor.addMultipleBinRefsToQueue(binRefs, doWakeup); 1373 } 1374 } 1375 1376 /** 1377 * Do lazy compression at opportune moments. 1378 */ lazyCompress(IN in)1379 public void lazyCompress(IN in) 1380 throws DatabaseException { 1381 1382 /* 1383 * May be called by the cleaner on its last cycle, after the compressor 1384 * is shut down. 1385 */ 1386 if (inCompressor != null) { 1387 inCompressor.lazyCompress(in); 1388 } 1389 } 1390 1391 /** 1392 * Reset the logging level for specified loggers in a JE environment. 1393 * 1394 * @throws IllegalArgumentException via JEDiagnostics.OP_RESET_LOGGING 1395 */ resetLoggingLevel(String changedLoggerName, Level level)1396 public void resetLoggingLevel(String changedLoggerName, Level level) { 1397 1398 /* 1399 * Go through the loggers registered in the global log manager, and 1400 * set the new level. If the specified logger name is not valid, throw 1401 * an IllegalArgumentException. 1402 */ 1403 java.util.logging.LogManager loggerManager = 1404 java.util.logging.LogManager.getLogManager(); 1405 Enumeration<String> loggers = loggerManager.getLoggerNames(); 1406 boolean validName = false; 1407 1408 while (loggers.hasMoreElements()) { 1409 String loggerName = loggers.nextElement(); 1410 Logger logger = loggerManager.getLogger(loggerName); 1411 1412 if ("all".equals(changedLoggerName) || 1413 loggerName.endsWith(changedLoggerName) || 1414 loggerName.endsWith(changedLoggerName + 1415 LoggerUtils.NO_ENV) || 1416 loggerName.endsWith(changedLoggerName + 1417 LoggerUtils.FIXED_PREFIX) || 1418 loggerName.startsWith(changedLoggerName)) { 1419 1420 logger.setLevel(level); 1421 validName = true; 1422 } 1423 } 1424 1425 if (!validName) { 1426 throw new IllegalArgumentException 1427 ("The logger name parameter: " + changedLoggerName + 1428 " is invalid!"); 1429 } 1430 } 1431 1432 /* Initialize the handler's formatter. */ initFormatter()1433 protected Formatter initFormatter() { 1434 return new TracerFormatter(getName()); 1435 } 1436 initFileHandler()1437 private FileHandler initFileHandler() 1438 throws DatabaseException { 1439 1440 /* 1441 * Note that in JE 3.X and earlier, file logging encompassed both 1442 * logging to a java.util.logging.FileHandler and our own JE log files 1443 * and logging was disabled for read only and in-memory environments. 1444 * Now that these two concepts are separated, file logging is supported 1445 * for in-memory environments. File logging can be supported as long as 1446 * there is a valid environment home. 1447 */ 1448 if ((envHome == null) || (!envHome.isDirectory()) || isReadOnly) { 1449 1450 /* 1451 * Return null if no environment home directory(therefore no place 1452 * to put file handler output files), or if the Environment is read 1453 * only. 1454 */ 1455 return null; 1456 } 1457 1458 String handlerName = com.sleepycat.je.util.FileHandler.class.getName(); 1459 String logFilePattern = envHome + "/" + INFO_FILES; 1460 1461 /* Log with a rotating set of files, use append mode. */ 1462 int limit = FILEHANDLER_LIMIT; 1463 String logLimit = 1464 LoggerUtils.getLoggerProperty(handlerName + ".limit"); 1465 if (logLimit != null) { 1466 limit = Integer.parseInt(logLimit); 1467 } 1468 1469 /* Limit the number of files. */ 1470 int count = FILEHANDLER_COUNT; 1471 String logCount = 1472 LoggerUtils.getLoggerProperty(handlerName + ".count"); 1473 if (logCount != null) { 1474 count = Integer.parseInt(logCount); 1475 } 1476 1477 try { 1478 return new com.sleepycat.je.util.FileHandler(logFilePattern, 1479 limit, 1480 count, 1481 formatter, 1482 this); 1483 } catch (IOException e) { 1484 throw EnvironmentFailureException.unexpectedException 1485 ("Problem creating output files in: " + logFilePattern, e); 1486 } 1487 } 1488 getConsoleHandler()1489 public ConsoleHandler getConsoleHandler() { 1490 return consoleHandler; 1491 } 1492 getFileHandler()1493 public FileHandler getFileHandler() { 1494 return fileHandler; 1495 } 1496 getConfiguredHandler()1497 public Handler getConfiguredHandler() { 1498 return configuredHandler; 1499 } 1500 closeHandlers()1501 public void closeHandlers() { 1502 if (consoleHandler != null) { 1503 consoleHandler.close(); 1504 } 1505 1506 if (fileHandler != null) { 1507 fileHandler.close(); 1508 } 1509 } 1510 1511 /** 1512 * Not much to do, mark state. 1513 */ open()1514 public void open() { 1515 envState = DbEnvState.OPEN; 1516 } 1517 1518 /** 1519 * Invalidate the environment. Done when a fatal exception 1520 * (EnvironmentFailureException) is thrown. 1521 */ invalidate(EnvironmentFailureException e)1522 public void invalidate(EnvironmentFailureException e) { 1523 1524 /* 1525 * Remember the fatal exception so we can redisplay it if the 1526 * environment is called by the application again. 1527 */ 1528 savedInvalidatingException = e; 1529 envState = DbEnvState.INVALID; 1530 requestShutdownDaemons(); 1531 } 1532 getInvalidatingException()1533 public EnvironmentFailureException getInvalidatingException() { 1534 return savedInvalidatingException; 1535 } 1536 1537 /** 1538 * Invalidate the environment when a Java Error is thrown. 1539 */ invalidate(Error e)1540 public void invalidate(Error e) { 1541 if (SAVED_EFE.getCause() != null) { 1542 /* Cause was previously set. */ 1543 return; 1544 } 1545 try { 1546 SAVED_EFE.initCause(e); 1547 } catch (IllegalStateException ignored) { 1548 /* Cause was set by another concurrent thread. [#22837] */ 1549 return; 1550 } 1551 invalidate(SAVED_EFE); 1552 } 1553 1554 /** 1555 * Predicate used to determine whether the EnvironmentImpl is currently 1556 * invalid. Note that INVALID is not a terminal state and it could 1557 * subsequently transition to the terminal CLOSED state. 1558 * 1559 * @return true if the environment is invalid 1560 */ isInvalid()1561 public boolean isInvalid() { 1562 return (envState == DbEnvState.INVALID); 1563 } 1564 1565 /** 1566 * Returns true if the environment is currently invalid or was invalidated 1567 * and closed. 1568 */ wasInvalidated()1569 public boolean wasInvalidated() { 1570 return (envState == DbEnvState.INVALID) || 1571 ((envState == DbEnvState.CLOSED) && 1572 (savedInvalidatingException != null)); 1573 } 1574 1575 /** 1576 * @return true if environment is open. 1577 */ isValid()1578 public boolean isValid() { 1579 return (envState == DbEnvState.OPEN); 1580 } 1581 1582 /** 1583 * @return true if environment is still in init 1584 */ isInInit()1585 public boolean isInInit() { 1586 return (envState == DbEnvState.INIT); 1587 } 1588 1589 /** 1590 * @return true if close has begun, although the state may still be open. 1591 */ isClosing()1592 public boolean isClosing() { 1593 return closing; 1594 } 1595 isClosed()1596 public boolean isClosed() { 1597 return (envState == DbEnvState.CLOSED); 1598 } 1599 1600 /** 1601 * When a EnvironmentFailureException occurs or the environment is closed, 1602 * further writing can cause log corruption. 1603 */ mayNotWrite()1604 public boolean mayNotWrite() { 1605 return (envState == DbEnvState.INVALID) || 1606 (envState == DbEnvState.CLOSED); 1607 } 1608 checkIfInvalid()1609 public void checkIfInvalid() 1610 throws EnvironmentFailureException { 1611 1612 if (envState == DbEnvState.INVALID) { 1613 1614 /* 1615 * Set a flag in the exception so the exception message will be 1616 * clear that this was an earlier exception. 1617 */ 1618 savedInvalidatingException.setAlreadyThrown(true); 1619 1620 if (savedInvalidatingException == SAVED_EFE) { 1621 savedInvalidatingException.fillInStackTrace(); 1622 /* Do not wrap to avoid allocations after an OOME. */ 1623 throw savedInvalidatingException; 1624 } 1625 1626 throw savedInvalidatingException.wrapSelf 1627 ("Environment must be closed, caused by: " + 1628 savedInvalidatingException); 1629 } 1630 } 1631 checkNotClosed()1632 public void checkNotClosed() 1633 throws DatabaseException { 1634 1635 if (envState == DbEnvState.CLOSED) { 1636 throw new IllegalStateException 1637 ("Attempt to use a Environment that has been closed."); 1638 } 1639 } 1640 1641 /** 1642 * Decrements the reference count and closes the environment when it 1643 * reaches zero. A checkpoint is always performed when closing. 1644 */ close()1645 public void close() 1646 throws DatabaseException { 1647 1648 /* Calls doClose while synchronized on DbEnvPool. */ 1649 DbEnvPool.getInstance().closeEnvironment 1650 (this, true /*doCheckpoint*/, false /*isAbnormalClose*/); 1651 } 1652 1653 /** 1654 * Decrements the reference count and closes the environment when it 1655 * reaches zero. A checkpoint when closing is optional. 1656 */ close(boolean doCheckpoint)1657 public void close(boolean doCheckpoint) 1658 throws DatabaseException { 1659 1660 /* Calls doClose while synchronized on DbEnvPool. */ 1661 DbEnvPool.getInstance().closeEnvironment 1662 (this, doCheckpoint, false /*isAbnormalClose*/); 1663 } 1664 1665 /** 1666 * Used by error handling to forcibly close an environment, and by tests to 1667 * close an environment to simulate a crash. Database handles do not have 1668 * to be closed before calling this method. A checkpoint is not performed. 1669 */ abnormalClose()1670 public void abnormalClose() 1671 throws DatabaseException { 1672 1673 /* Discard the internal handle, for an abnormal close. */ 1674 closeInternalEnvHandle(true); 1675 1676 /* 1677 * We are assuming that the environment will be cleared out of the 1678 * environment pool, so it's safe to assert that the reference and open 1679 * counts are zero. 1680 */ 1681 int openCount1 = getOpenCount(); 1682 if (openCount1 > 1) { 1683 throw EnvironmentFailureException.unexpectedState 1684 (this, "Abnormal close assumes that the open count on " + 1685 "this handle is 1, not " + openCount1); 1686 } 1687 1688 int backupCount1 = getBackupCount(); 1689 if (backupCount1 > 0) { 1690 throw EnvironmentFailureException.unexpectedState 1691 (this, "Abnormal close assumes that the backup count on " + 1692 "this handle is 0, not " + backupCount1); 1693 } 1694 1695 /* Calls doClose while synchronized on DbEnvPool. */ 1696 DbEnvPool.getInstance().closeEnvironment 1697 (this, false /*doCheckpoint*/, true /*isAbnormalClose*/); 1698 } 1699 1700 /** 1701 * Closes the environment, optionally performing a checkpoint and checking 1702 * for resource leaks. This method must be called while synchronized on 1703 * DbEnvPool. 1704 * 1705 * @throws IllegalStateException if the environment is already closed. 1706 * 1707 * @throws EnvironmentFailureException if leaks or other problems are 1708 * detected while closing. 1709 */ doClose(boolean doCheckpoint, boolean isAbnormalClose)1710 synchronized void doClose(boolean doCheckpoint, boolean isAbnormalClose) { 1711 1712 /* Discard the internal handle. */ 1713 closeInternalEnvHandle(isAbnormalClose); 1714 1715 StringWriter errorStringWriter = new StringWriter(); 1716 PrintWriter errors = new PrintWriter(errorStringWriter); 1717 1718 try { 1719 Trace.traceLazily 1720 (this, "Close of environment " + envHome + " started"); 1721 LoggerUtils.fine(envLogger, 1722 this, 1723 "Close of environment " + envHome + " started"); 1724 1725 envState.checkState(DbEnvState.VALID_FOR_CLOSE, 1726 DbEnvState.CLOSED); 1727 1728 try { 1729 setupClose(errors); 1730 } catch (Exception e) { 1731 appendException(errors, e, "releasing resources"); 1732 } 1733 1734 /* 1735 * If backups are in progress, warn the caller that it was a 1736 * mistake to close the environment at this time. 1737 */ 1738 if (getBackupCount() > 0) { 1739 errors.append("\nThere are backups in progress so the "); 1740 errors.append("Environment should not have been closed."); 1741 errors.println(); 1742 } 1743 1744 /* 1745 * Begin shutdown of the deamons before checkpointing. Cleaning 1746 * during the checkpoint is wasted and slows down the checkpoint. 1747 */ 1748 requestShutdownDaemons(); 1749 1750 try { 1751 unregisterMBean(); 1752 } catch (Exception e) { 1753 appendException(errors, e, "unregistering MBean"); 1754 } 1755 1756 /* Checkpoint to bound recovery time. */ 1757 boolean checkpointHappened = false; 1758 if (doCheckpoint && 1759 !isReadOnly && 1760 (envState != DbEnvState.INVALID) && 1761 logManager.getLastLsnAtRecovery() != 1762 fileManager.getLastUsedLsn()) { 1763 1764 /* 1765 * Force a checkpoint. Don't allow deltas (minimize recovery 1766 * time) because they cause inefficiencies for two reasons: (1) 1767 * recovering BIN-deltas causes extra random I/O in order to 1768 * reconstitute BINS, which can greatly increase recovery time, 1769 * and (2) logging deltas during close causes redundant logging 1770 * by the full checkpoint after recovery. 1771 */ 1772 CheckpointConfig ckptConfig = new CheckpointConfig(); 1773 ckptConfig.setForce(true); 1774 ckptConfig.setMinimizeRecoveryTime(true); 1775 try { 1776 invokeCheckpoint(ckptConfig, "close"); 1777 } catch (DatabaseException e) { 1778 appendException(errors, e, "performing checkpoint"); 1779 } 1780 checkpointHappened = true; 1781 } 1782 1783 try { 1784 postCheckpointClose(checkpointHappened); 1785 } catch (Exception e) { 1786 appendException(errors, e, "after checkpoint"); 1787 } 1788 1789 LoggerUtils.fine(envLogger, 1790 this, 1791 "About to shutdown daemons for Env " + envHome); 1792 shutdownDaemons(); 1793 1794 /* Flush log. */ 1795 if (!isAbnormalClose) { 1796 try { 1797 logManager.flush(); 1798 } catch (Exception e) { 1799 appendException(errors, e, "flushing log manager"); 1800 } 1801 } 1802 1803 try { 1804 fileManager.clear(); 1805 } catch (Exception e) { 1806 appendException(errors, e, "clearing file manager"); 1807 } 1808 1809 try { 1810 fileManager.close(); 1811 } catch (Exception e) { 1812 appendException(errors, e, "closing file manager"); 1813 } 1814 1815 /* 1816 * Close the memory budgets on these components before the 1817 * INList is forcibly released and the treeAdmin budget is 1818 * cleared. 1819 */ 1820 dbMapTree.close(); 1821 cleaner.close(); 1822 inMemoryINs.clear(); 1823 1824 closeHandlers(); 1825 1826 if (!isAbnormalClose && 1827 (envState != DbEnvState.INVALID)) { 1828 1829 try { 1830 checkLeaks(); 1831 } catch (Exception e) { 1832 appendException(errors, e, "performing validity checks"); 1833 } 1834 } 1835 } finally { 1836 envState = DbEnvState.CLOSED; 1837 1838 /* 1839 * Last ditch effort to clean up so that tests can continue and 1840 * re-open the Environment in the face of an Exception or even an 1841 * Error. Note that this was also attempted above. [#21929] 1842 */ 1843 clearFileManager(); 1844 closeHandlers(); 1845 } 1846 1847 /* Don't whine again if we've already whined. */ 1848 if (errorStringWriter.getBuffer().length() > 0 && 1849 savedInvalidatingException == null) { 1850 throw EnvironmentFailureException.unexpectedState 1851 (errorStringWriter.toString()); 1852 } 1853 } 1854 appendException(PrintWriter pw, Exception e, String doingWhat)1855 protected void appendException(PrintWriter pw, 1856 Exception e, 1857 String doingWhat) { 1858 pw.append("\nException " + doingWhat + ": "); 1859 e.printStackTrace(pw); 1860 pw.println(); 1861 } 1862 1863 /** 1864 * Release any resources from a subclass that need to be released before 1865 * close is called on regular environment components. 1866 * @throws DatabaseException 1867 */ setupClose(@uppressWarningsR) PrintWriter errors)1868 protected synchronized void setupClose(@SuppressWarnings("unused") 1869 PrintWriter errors) 1870 throws DatabaseException { 1871 } 1872 1873 /** 1874 * Release any resources from a subclass that need to be released after 1875 * the closing checkpoint. 1876 * @param checkpointed if true, a checkpoint as issued before the close 1877 * @throws DatabaseException 1878 */ postCheckpointClose(boolean checkpointed)1879 protected synchronized void postCheckpointClose(boolean checkpointed) 1880 throws DatabaseException { 1881 } 1882 1883 /** 1884 * Called after recovery but before any other initialization. Is overridden 1885 * by ReplImpl to convert user defined databases to replicated after doing 1886 * recovery. 1887 */ postRecoveryConversion()1888 protected void postRecoveryConversion() { 1889 } 1890 1891 /** 1892 * Perform dup conversion after recovery and before running daemons. 1893 */ convertDupDatabases()1894 private void convertDupDatabases() { 1895 if (dbMapTree.getDupsConverted()) { 1896 return; 1897 } 1898 /* Convert dup dbs, set converted flag, flush mapping tree root. */ 1899 final DupConvert dupConvert = new DupConvert(this, dbMapTree); 1900 dupConvert.convertDatabases(); 1901 dbMapTree.setDupsConverted(); 1902 logMapTreeRoot(); 1903 logManager.flush(); 1904 } 1905 1906 /* 1907 * Clear as many resources as possible, even in the face of an environment 1908 * that has received a fatal error, in order to support reopening the 1909 * environment in the same JVM. 1910 */ closeAfterInvalid()1911 public void closeAfterInvalid() 1912 throws DatabaseException { 1913 1914 /* Calls doCloseAfterInvalid while synchronized on DbEnvPool. */ 1915 DbEnvPool.getInstance().closeEnvironmentAfterInvalid(this); 1916 } 1917 1918 /** 1919 * This method must be called while synchronized on DbEnvPool. 1920 */ doCloseAfterInvalid()1921 public synchronized void doCloseAfterInvalid() { 1922 1923 try { 1924 unregisterMBean(); 1925 } catch (Exception e) { 1926 /* Klockwork - ok */ 1927 } 1928 1929 shutdownDaemons(); 1930 1931 try { 1932 fileManager.clear(); 1933 } catch (Throwable e) { 1934 /* Klockwork - ok */ 1935 } 1936 1937 try { 1938 fileManager.close(); 1939 } catch (Throwable e) { 1940 /* Klockwork - ok */ 1941 } 1942 1943 /* 1944 * Release resources held by handlers, such as memory and file 1945 * descriptors 1946 */ 1947 closeHandlers(); 1948 } 1949 incOpenCount()1950 void incOpenCount() { 1951 openCount.incrementAndGet(); 1952 } 1953 1954 /** 1955 * Returns true if the environment should be closed. 1956 */ decOpenCount()1957 boolean decOpenCount() { 1958 return (openCount.decrementAndGet() <= 0); 1959 } 1960 1961 /** 1962 * Returns a count of open environment handles, not including the internal 1963 * handle. 1964 */ getOpenCount()1965 private int getOpenCount() { 1966 return openCount.get(); 1967 } 1968 1969 /** 1970 * Returns the count of environment handles that were opened explicitly by 1971 * the application. Because the internal environment handle is not included 1972 * in the openCount, this method is currently equivalent to getOpenCount. 1973 * 1974 * @return the count of open application handles 1975 */ getAppOpenCount()1976 protected int getAppOpenCount() { 1977 return openCount.get(); 1978 } 1979 incBackupCount()1980 void incBackupCount() { 1981 backupCount.incrementAndGet(); 1982 } 1983 decBackupCount()1984 void decBackupCount() { 1985 backupCount.decrementAndGet(); 1986 } 1987 1988 /** 1989 * Returns a count of the number of in-progress DbBackups. 1990 */ getBackupCount()1991 protected int getBackupCount() { 1992 return backupCount.get(); 1993 } 1994 getThreadLocalReferenceCount()1995 public static int getThreadLocalReferenceCount() { 1996 return threadLocalReferenceCount; 1997 } 1998 incThreadLocalReferenceCount()1999 static synchronized void incThreadLocalReferenceCount() { 2000 threadLocalReferenceCount++; 2001 } 2002 decThreadLocalReferenceCount()2003 static synchronized void decThreadLocalReferenceCount() { 2004 threadLocalReferenceCount--; 2005 } 2006 getDidFullThreadDump()2007 public boolean getDidFullThreadDump() { 2008 return didFullThreadDump; 2009 } 2010 setDidFullThreadDump(boolean val)2011 public void setDidFullThreadDump(boolean val) { 2012 didFullThreadDump = val; 2013 } 2014 getNoComparators()2015 public boolean getNoComparators() { 2016 return noComparators; 2017 } 2018 2019 /** 2020 * Debugging support. Check for leaked locks and transactions. 2021 */ checkLeaks()2022 private void checkLeaks() 2023 throws DatabaseException { 2024 2025 /* Only enabled if this check leak flag is true. */ 2026 if (!configManager.getBoolean(EnvironmentParams.ENV_CHECK_LEAKS)) { 2027 return; 2028 } 2029 2030 boolean clean = true; 2031 StatsConfig statsConfig = new StatsConfig(); 2032 2033 /* Fast stats will not return NTotalLocks below. */ 2034 statsConfig.setFast(false); 2035 2036 LockStats lockStat = lockStat(statsConfig); 2037 if (lockStat.getNTotalLocks() != 0) { 2038 clean = false; 2039 System.err.println("Problem: " + lockStat.getNTotalLocks() + 2040 " locks left"); 2041 txnManager.getLockManager().dump(); 2042 } 2043 2044 TransactionStats txnStat = txnStat(statsConfig); 2045 if (txnStat.getNActive() != 0) { 2046 clean = false; 2047 System.err.println("Problem: " + txnStat.getNActive() + 2048 " txns left"); 2049 TransactionStats.Active[] active = txnStat.getActiveTxns(); 2050 if (active != null) { 2051 for (Active element : active) { 2052 System.err.println(element); 2053 } 2054 } 2055 } 2056 2057 if (LatchSupport.TRACK_LATCHES) { 2058 if (LatchSupport.nBtreeLatchesHeld() > 0) { 2059 clean = false; 2060 System.err.println("Some latches held at env close."); 2061 System.err.println(LatchSupport.btreeLatchesHeldToString()); 2062 } 2063 } 2064 2065 long memoryUsage = memoryBudget.getVariableCacheUsage(); 2066 if (memoryUsage != 0) { 2067 clean = false; 2068 System.err.println("Local Cache Usage = " + memoryUsage); 2069 System.err.println(memoryBudget.loadStats()); 2070 } 2071 2072 boolean assertionsEnabled = false; 2073 assert assertionsEnabled = true; // Intentional side effect. 2074 if (!clean && assertionsEnabled) { 2075 throw EnvironmentFailureException.unexpectedState 2076 ("Lock, transaction, latch or memory " + 2077 "left behind at environment close"); 2078 } 2079 } 2080 2081 /** 2082 * Invoke a checkpoint programmatically. Note that only one checkpoint may 2083 * run at a time. 2084 */ invokeCheckpoint(CheckpointConfig config, String invokingSource)2085 public boolean invokeCheckpoint(CheckpointConfig config, 2086 String invokingSource) 2087 throws DatabaseException { 2088 2089 if (checkpointer != null) { 2090 checkpointer.doCheckpoint(config, invokingSource); 2091 return true; 2092 } 2093 return false; 2094 } 2095 2096 /** 2097 * Flush the log buffers and write to the log, and optionally fsync. 2098 * [#19111] 2099 */ flushLog(boolean fsync)2100 public void flushLog(boolean fsync) { 2101 if (fsync) { 2102 logManager.flush(); 2103 } else { 2104 logManager.flushWriteNoSync(); 2105 } 2106 } 2107 2108 /** 2109 * Flip the log to a new file, forcing an fsync. Return the LSN of the 2110 * trace record in the new file. 2111 */ forceLogFileFlip()2112 public long forceLogFileFlip() 2113 throws DatabaseException { 2114 2115 return logManager.logForceFlip( 2116 new TraceLogEntry(new Trace("File Flip"))); 2117 } 2118 2119 /** 2120 * Invoke a compress programatically. Note that only one compress may run 2121 * at a time. 2122 */ invokeCompressor()2123 public boolean invokeCompressor() 2124 throws DatabaseException { 2125 2126 if (inCompressor != null) { 2127 inCompressor.doCompress(); 2128 return true; 2129 } 2130 return false; 2131 } 2132 invokeEvictor()2133 public void invokeEvictor() 2134 throws DatabaseException { 2135 2136 if (evictor != null) { 2137 evictor.doManualEvict(); 2138 } 2139 } 2140 2141 /** 2142 * @throws UnsupportedOperationException via Environment.cleanLog. 2143 */ invokeCleaner()2144 public int invokeCleaner() 2145 throws DatabaseException { 2146 2147 if (isReadOnly || isMemOnly) { 2148 throw new UnsupportedOperationException 2149 ("Log cleaning not allowed in a read-only or memory-only " + 2150 "environment"); 2151 } 2152 if (cleaner != null) { 2153 return cleaner.doClean(true, // cleanMultipleFiles 2154 false); // forceCleaning 2155 } 2156 return 0; 2157 } 2158 requestShutdownDaemons()2159 public void requestShutdownDaemons() { 2160 2161 closing = true; 2162 2163 if (inCompressor != null) { 2164 inCompressor.requestShutdown(); 2165 } 2166 2167 /* 2168 * Don't shutdown the shared cache evictor here. It is shutdown when 2169 * the last shared cache environment is removed in DbEnvPool. 2170 */ 2171 if (evictor != null && !sharedCache) { 2172 evictor.requestShutdownPool(); 2173 } 2174 2175 if (checkpointer != null) { 2176 checkpointer.requestShutdown(); 2177 } 2178 2179 if (cleaner != null) { 2180 cleaner.requestShutdown(); 2181 } 2182 2183 if (statCapture != null) { 2184 statCapture.requestShutdown(); 2185 } 2186 } 2187 2188 /** 2189 * For unit testing -- shuts down daemons completely but leaves environment 2190 * usable since environment references are not nulled out. 2191 */ stopDaemons()2192 public void stopDaemons() { 2193 2194 if (inCompressor != null) { 2195 inCompressor.shutdown(); 2196 } 2197 if (evictor != null) { 2198 evictor.shutdown(); 2199 } 2200 if (checkpointer != null) { 2201 checkpointer.shutdown(); 2202 } 2203 if (cleaner != null) { 2204 cleaner.shutdown(); 2205 } 2206 if (statCapture != null) { 2207 statCapture.shutdown(); 2208 } 2209 } 2210 2211 /** 2212 * Ask all daemon threads to shut down. 2213 */ shutdownDaemons()2214 public void shutdownDaemons() { 2215 2216 /* Shutdown stats capture thread first so we can access stats. */ 2217 shutdownStatCapture(); 2218 synchronized (statSynchronizer) { 2219 2220 shutdownINCompressor(); 2221 2222 /* 2223 * Cleaner has to be shutdown before checkpointer because former 2224 * calls the latter. 2225 */ 2226 shutdownCleaner(); 2227 shutdownCheckpointer(); 2228 2229 /* 2230 * The evictor has to get shutdown last because the other daemons 2231 * might create changes to the memory usage which result in a 2232 * notify to eviction. 2233 */ 2234 shutdownEvictor(); 2235 } 2236 } 2237 shutdownINCompressor()2238 void shutdownINCompressor() { 2239 if (inCompressor != null) { 2240 inCompressor.shutdown(); 2241 2242 /* 2243 * If daemon thread doesn't shutdown for any reason, at least clear 2244 * the reference to the environment so it can be GC'd. 2245 */ 2246 inCompressor.clearEnv(); 2247 inCompressor = null; 2248 } 2249 return; 2250 } 2251 shutdownEvictor()2252 void shutdownEvictor() { 2253 if (evictor != null) { 2254 if (sharedCache) { 2255 2256 /* 2257 * Don't shutdown the SharedEvictor here. It is shutdown when 2258 * the last shared cache environment is removed in DbEnvPool. 2259 * Instead, remove this environment from the SharedEvictor's 2260 * list so we won't try to evict from a closing/closed 2261 * environment. Note that we do this after the final checkpoint 2262 * so that eviction is possible during the checkpoint, and just 2263 * before deconstructing the environment. Leave the evictor 2264 * field intact so DbEnvPool can get it. 2265 */ 2266 evictor.removeEnvironment(this); 2267 } else { 2268 evictor.shutdown(); 2269 evictor = null; 2270 } 2271 } 2272 return; 2273 } 2274 shutdownCheckpointer()2275 void shutdownCheckpointer() { 2276 if (checkpointer != null) { 2277 checkpointer.shutdown(); 2278 2279 /* 2280 * If daemon thread doesn't shutdown for any reason, at least clear 2281 * the reference to the environment so it can be GC'd. 2282 */ 2283 checkpointer.clearEnv(); 2284 checkpointer = null; 2285 } 2286 return; 2287 } 2288 shutdownStatCapture()2289 void shutdownStatCapture() { 2290 if (statCapture != null) { 2291 statCapture.shutdown(); 2292 2293 /* 2294 * If daemon thread doesn't shutdown for any reason, at least clear 2295 * the reference to the environment so it can be GC'd. 2296 */ 2297 statCapture.clearEnv(); 2298 statCapture = null; 2299 } 2300 return; 2301 } 2302 2303 /* 2304 * Create stat capture if configured and not created yet. 2305 */ createStatCapture()2306 private void createStatCapture() { 2307 if (statCapture == null && 2308 !isReadOnly() && 2309 !isMemOnly() && 2310 configManager.getBoolean(EnvironmentParams.STATS_COLLECT)) { 2311 statCapture = 2312 new StatCapture(this, 2313 Environment.STATCAPTURE_NAME, 2314 configManager.getDuration( 2315 EnvironmentParams.STATS_COLLECT_INTERVAL), 2316 customStats, 2317 getStatCaptureProjections(), 2318 statManager); 2319 } 2320 } 2321 2322 /** 2323 * public for unit tests. 2324 */ shutdownCleaner()2325 public void shutdownCleaner() { 2326 2327 if (cleaner != null) { 2328 cleaner.shutdown(); 2329 2330 /* 2331 * Don't call clearEnv -- Cleaner.shutdown does this for each 2332 * cleaner thread. Don't set the cleaner field to null because we 2333 * use it to get the utilization profile and tracker. 2334 */ 2335 } 2336 return; 2337 } 2338 isNoLocking()2339 public boolean isNoLocking() { 2340 return isNoLocking; 2341 } 2342 isTransactional()2343 public boolean isTransactional() { 2344 return isTransactional; 2345 } 2346 isReadOnly()2347 public boolean isReadOnly() { 2348 return isReadOnly; 2349 } 2350 isMemOnly()2351 public boolean isMemOnly() { 2352 return isMemOnly; 2353 } 2354 2355 /** 2356 * Named "optional" because the nodeName property in EnvironmentConfig is 2357 * optional may be null. {@link #getName()} should almost always be used 2358 * instead for messages, exceptions, etc. 2359 */ getOptionalNodeName()2360 public String getOptionalNodeName() { 2361 return optionalNodeName; 2362 } 2363 2364 /** 2365 * Returns whether DB/MapLN eviction is enabled. 2366 */ getDbEviction()2367 public boolean getDbEviction() { 2368 return dbEviction; 2369 } 2370 getAdler32ChunkSize()2371 public static int getAdler32ChunkSize() { 2372 return adler32ChunkSize; 2373 } 2374 getSharedCache()2375 public boolean getSharedCache() { 2376 return sharedCache; 2377 } 2378 allowBlindOps()2379 public boolean allowBlindOps() { 2380 return allowBlindOps; 2381 } 2382 allowBlindPuts()2383 public boolean allowBlindPuts() { 2384 return allowBlindPuts; 2385 } 2386 2387 /** 2388 * Transactional services. 2389 */ txnBegin(Transaction parent, TransactionConfig txnConfig)2390 public Txn txnBegin(Transaction parent, TransactionConfig txnConfig) 2391 throws DatabaseException { 2392 2393 return txnManager.txnBegin(parent, txnConfig); 2394 } 2395 2396 /* Services. */ getLogManager()2397 public LogManager getLogManager() { 2398 return logManager; 2399 } 2400 getFileManager()2401 public FileManager getFileManager() { 2402 return fileManager; 2403 } 2404 getDbTree()2405 public DbTree getDbTree() { 2406 return dbMapTree; 2407 } 2408 2409 /** 2410 * Returns the config manager for the current base configuration. 2411 * 2412 * <p>The configuration can change, but changes are made by replacing the 2413 * config manager object with a enw one. To use a consistent set of 2414 * properties, call this method once and query the returned manager 2415 * repeatedly for each property, rather than getting the config manager via 2416 * this method for each property individually.</p> 2417 */ getConfigManager()2418 public DbConfigManager getConfigManager() { 2419 return configManager; 2420 } 2421 getNodeSequence()2422 public NodeSequence getNodeSequence() { 2423 return nodeSequence; 2424 } 2425 2426 /** 2427 * Clones the current configuration. 2428 */ cloneConfig()2429 public EnvironmentConfig cloneConfig() { 2430 return configManager.getEnvironmentConfig().clone(); 2431 } 2432 2433 /** 2434 * Clones the current mutable configuration. 2435 */ cloneMutableConfig()2436 public EnvironmentMutableConfig cloneMutableConfig() { 2437 return DbInternal.cloneMutableConfig 2438 (configManager.getEnvironmentConfig()); 2439 } 2440 2441 /** 2442 * Throws an exception if an immutable property is changed. 2443 */ checkImmutablePropsForEquality(Properties handleConfigProps)2444 public void checkImmutablePropsForEquality(Properties handleConfigProps) 2445 throws IllegalArgumentException { 2446 2447 DbInternal.checkImmutablePropsForEquality 2448 (configManager.getEnvironmentConfig(), handleConfigProps); 2449 } 2450 2451 /** 2452 * Changes the mutable config properties that are present in the given 2453 * config, and notifies all config observer. 2454 */ setMutableConfig(EnvironmentMutableConfig config)2455 public void setMutableConfig(EnvironmentMutableConfig config) 2456 throws DatabaseException { 2457 2458 /* Calls doSetMutableConfig while synchronized on DbEnvPool. */ 2459 DbEnvPool.getInstance().setMutableConfig(this, config); 2460 } 2461 2462 /** 2463 * This method must be called while synchronized on DbEnvPool. 2464 */ doSetMutableConfig(EnvironmentMutableConfig config)2465 synchronized void doSetMutableConfig(EnvironmentMutableConfig config) 2466 throws DatabaseException { 2467 2468 /* Clone the current config. */ 2469 EnvironmentConfig newConfig = 2470 configManager.getEnvironmentConfig().clone(); 2471 2472 /* Copy in the mutable props. */ 2473 DbInternal.copyMutablePropsTo(config, newConfig); 2474 2475 /* 2476 * Update the current config and notify observers. The config manager 2477 * is replaced with a new instance that uses the new configuration. 2478 * This avoids synchronization issues: other threads that have a 2479 * reference to the old configuration object are not impacted. 2480 * 2481 * Notify listeners in reverse order of registration so that the 2482 * environment listener is notified last and can start daemon threads 2483 * after they are configured. 2484 */ 2485 configManager = resetConfigManager(newConfig); 2486 for (int i = configObservers.size() - 1; i >= 0; i -= 1) { 2487 EnvConfigObserver o = configObservers.get(i); 2488 o.envConfigUpdate(configManager, newConfig); 2489 } 2490 } 2491 2492 /** 2493 * Make a new config manager that has all the properties needed. More 2494 * complicated for subclasses. 2495 */ resetConfigManager(EnvironmentConfig newConfig)2496 protected DbConfigManager resetConfigManager(EnvironmentConfig newConfig) { 2497 return new DbConfigManager(newConfig); 2498 } 2499 getExceptionListener()2500 public ExceptionListener getExceptionListener() { 2501 return exceptionListener; 2502 } 2503 2504 /** 2505 * Adds an observer of mutable config changes. 2506 */ addConfigObserver(EnvConfigObserver o)2507 public synchronized void addConfigObserver(EnvConfigObserver o) { 2508 configObservers.add(o); 2509 } 2510 2511 /** 2512 * Removes an observer of mutable config changes. 2513 */ removeConfigObserver(EnvConfigObserver o)2514 public synchronized void removeConfigObserver(EnvConfigObserver o) { 2515 configObservers.remove(o); 2516 } 2517 getInMemoryINs()2518 public INList getInMemoryINs() { 2519 return inMemoryINs; 2520 } 2521 getTxnManager()2522 public TxnManager getTxnManager() { 2523 return txnManager; 2524 } 2525 getCheckpointer()2526 public Checkpointer getCheckpointer() { 2527 return checkpointer; 2528 } 2529 getCleaner()2530 public Cleaner getCleaner() { 2531 return cleaner; 2532 } 2533 getMemoryBudget()2534 public MemoryBudget getMemoryBudget() { 2535 return memoryBudget; 2536 } 2537 2538 /** 2539 * @return environment Logger, for use in debugging output. 2540 */ getLogger()2541 public Logger getLogger() { 2542 return envLogger; 2543 } 2544 isDbLoggingDisabled()2545 public boolean isDbLoggingDisabled() { 2546 return dbLoggingDisabled; 2547 } 2548 2549 /* 2550 * Verification, must be run while system is quiescent. 2551 */ verify(VerifyConfig config, PrintStream out)2552 public boolean verify(VerifyConfig config, PrintStream out) 2553 throws DatabaseException { 2554 2555 /* For now, verify all databases */ 2556 return dbMapTree.verify(config, out); 2557 } 2558 verifyCursors()2559 public void verifyCursors() 2560 throws DatabaseException { 2561 2562 inCompressor.verifyCursors(); 2563 } 2564 2565 /* 2566 * Statistics 2567 */ 2568 2569 /** 2570 * Retrieve and return stat information. 2571 */ loadStats(StatsConfig config)2572 public EnvironmentStats loadStats(StatsConfig config) 2573 throws DatabaseException { 2574 return statManager.loadStats(config, statKey); 2575 } 2576 2577 /** 2578 * Retrieve and return stat information. 2579 */ loadStatsInternal(StatsConfig config)2580 public EnvironmentStats loadStatsInternal(StatsConfig config) 2581 throws DatabaseException { 2582 2583 EnvironmentStats envStats = new EnvironmentStats(); 2584 2585 synchronized (statSynchronizer) { 2586 envStats.setINCompStats(inCompressor.loadStats(config)); 2587 envStats.setCkptStats(checkpointer.loadStats(config)); 2588 envStats.setCleanerStats(cleaner.loadStats(config)); 2589 envStats.setLogStats(logManager.loadStats(config)); 2590 envStats.setMBAndEvictorStats(memoryBudget.loadStats(), 2591 evictor.loadStats(config)); 2592 envStats.setLockStats(txnManager.loadStats(config)); 2593 envStats.setEnvImplStats(loadEnvImplStats(config)); 2594 envStats.setStatGroup(thrputStats.cloneGroup(config.getClear())); 2595 } 2596 return envStats; 2597 } 2598 loadEnvImplStats(StatsConfig config)2599 public StatGroup loadEnvImplStats(StatsConfig config) { 2600 StatGroup ret = stats.cloneGroup(config.getClear()); 2601 LongStat ct = new LongStat(ret, ENVIMPL_CREATION_TIME); 2602 ct.set(creationTime); 2603 return ret; 2604 2605 } 2606 incRelatchesRequired()2607 public void incRelatchesRequired() { 2608 relatchesRequired.increment(); 2609 } 2610 2611 /** 2612 * For replicated environments only; just return true for a standalone 2613 * environment. 2614 */ addDbBackup(@uppressWarningsR) DbBackup backup)2615 public boolean addDbBackup(@SuppressWarnings("unused") DbBackup backup) { 2616 incBackupCount(); 2617 return true; 2618 } 2619 2620 /** 2621 * For replicated environments only; do nothing for a standalone 2622 * environment. 2623 */ removeDbBackup(@uppressWarningsR) DbBackup backup)2624 public void removeDbBackup(@SuppressWarnings("unused") DbBackup backup) { 2625 decBackupCount(); 2626 } 2627 2628 /** 2629 * Retrieve lock statistics 2630 */ lockStat(StatsConfig config)2631 public synchronized LockStats lockStat(StatsConfig config) 2632 throws DatabaseException { 2633 2634 return txnManager.lockStat(config); 2635 } 2636 2637 /** 2638 * Retrieve txn statistics 2639 */ txnStat(StatsConfig config)2640 public synchronized TransactionStats txnStat(StatsConfig config) { 2641 return txnManager.txnStat(config); 2642 } 2643 getINCompressorQueueSize()2644 public int getINCompressorQueueSize() { 2645 return inCompressor.getBinRefQueueSize(); 2646 } 2647 getStartupTracker()2648 public StartupTracker getStartupTracker() { 2649 return startupTracker; 2650 } 2651 2652 /** 2653 * Get the environment home directory. 2654 */ getEnvironmentHome()2655 public File getEnvironmentHome() { 2656 return envHome; 2657 } 2658 getInternalEnvHandle()2659 public Environment getInternalEnvHandle() { 2660 return envInternal; 2661 } 2662 2663 /** 2664 * Closes the internally maintained environment handle. If the close is 2665 * an abnormal close, it just does cleanup work instead of trying to close 2666 * the internal environment handle which may result in further errors. 2667 */ closeInternalEnvHandle(boolean isAbnormalClose)2668 private synchronized void closeInternalEnvHandle(boolean isAbnormalClose) { 2669 2670 if (envInternal == null) { 2671 return; 2672 } 2673 2674 if (isAbnormalClose) { 2675 envInternal = null; 2676 } else { 2677 final Environment savedEnvInternal = envInternal; 2678 /* Blocks recursions resulting from the close operation below */ 2679 envInternal = null; 2680 DbInternal.closeInternalHandle(savedEnvInternal); 2681 } 2682 } 2683 2684 /** 2685 * Get an environment name, for tagging onto logging and debug message. 2686 * Useful for multiple environments in a JVM, or for HA. 2687 */ getName()2688 public String getName() { 2689 if (optionalNodeName == null){ 2690 return envHome.toString(); 2691 } 2692 return getOptionalNodeName(); 2693 } 2694 getTxnTimeout()2695 public long getTxnTimeout() { 2696 return txnTimeout; 2697 } 2698 getLockTimeout()2699 public long getLockTimeout() { 2700 return lockTimeout; 2701 } 2702 getReplayTxnTimeout()2703 public long getReplayTxnTimeout() { 2704 if (lockTimeout != 0) { 2705 return lockTimeout; 2706 } 2707 /* It can't be disabled, so make it the minimum. */ 2708 return 1; 2709 } 2710 2711 /** 2712 * Returns the shared secondary association latch. 2713 */ getSecondaryAssociationLock()2714 public ReentrantReadWriteLock getSecondaryAssociationLock() { 2715 return secondaryAssociationLock; 2716 } 2717 getEvictor()2718 public Evictor getEvictor() { 2719 return evictor; 2720 } 2721 alertEvictor()2722 void alertEvictor() { 2723 if (evictor != null) { 2724 evictor.alert(); 2725 } 2726 } 2727 2728 /** 2729 * Performs critical eviction if necessary. Is called before and after 2730 * each cursor operation. We prefer to have the application thread do as 2731 * little eviction as possible, to reduce the impact on latency, so 2732 * critical eviction has an explicit set of criteria for determining when 2733 * this should run. 2734 * 2735 * WARNING: The action performed here should be as inexpensive as possible, 2736 * since it will impact app operation latency. Unconditional 2737 * synchronization must not be performed, since that would introduce a new 2738 * synchronization point for all app threads. 2739 * 2740 * An overriding method must call super.criticalEviction. 2741 * 2742 * No latches are held or synchronization is in use when this method is 2743 * called. 2744 */ criticalEviction(boolean backgroundIO)2745 public void criticalEviction(boolean backgroundIO) { 2746 evictor.doCriticalEviction(backgroundIO); 2747 } 2748 2749 /** 2750 * Do eviction if the memory budget is over. Called by JE daemon 2751 * threads that do not have the same latency concerns as application 2752 * threads. 2753 */ daemonEviction(boolean backgroundIO)2754 public void daemonEviction(boolean backgroundIO) { 2755 evictor.doDaemonEviction(backgroundIO); 2756 } 2757 2758 /** 2759 * Performs special eviction (eviction other than standard IN eviction) 2760 * for this environment. This method is called once per eviction batch to 2761 * give other components an opportunity to perform eviction. For a shared 2762 * cached, it is called for only one environment (in rotation) per batch. 2763 * 2764 * An overriding method must call super.specialEviction and return the sum 2765 * of the long value it returns and any additional amount of budgeted 2766 * memory that is evicted. 2767 * 2768 * No latches are held when this method is called, but it is called while 2769 * synchronized on the evictor. 2770 * 2771 * @return the number of bytes evicted from the JE cache. 2772 */ specialEviction()2773 public long specialEviction() { 2774 return cleaner.getUtilizationTracker().evictMemory(); 2775 } 2776 2777 /** 2778 * See Evictor.isCacheFull 2779 */ isCacheFull()2780 public boolean isCacheFull() { 2781 return getEvictor().isCacheFull(); 2782 } 2783 2784 /** 2785 * See Evictor.wasCacheEverFull 2786 */ wasCacheEverFull()2787 public boolean wasCacheEverFull() { 2788 return getEvictor().wasCacheEverFull(); 2789 } 2790 2791 /** 2792 * For stress testing. Should only ever be called from an assert. 2793 */ maybeForceYield()2794 public static boolean maybeForceYield() { 2795 if (forcedYield) { 2796 Thread.yield(); 2797 } 2798 return true; // so assert doesn't fire 2799 } 2800 2801 /** 2802 * Return true if this environment is part of a replication group. 2803 */ isReplicated()2804 public boolean isReplicated() { 2805 return false; 2806 } 2807 2808 /** 2809 * Returns true if the VLSN is preserved as the record version. Always 2810 * false in a standalone environment. Overridden by RepImpl. 2811 */ getPreserveVLSN()2812 public boolean getPreserveVLSN() { 2813 return false; 2814 } 2815 2816 /** 2817 * Returns true if the VLSN is both preserved and cached. Always false in 2818 * a standalone environment. Overridden by RepImpl. 2819 */ getCacheVLSN()2820 public boolean getCacheVLSN() { 2821 return false; 2822 } 2823 2824 /** 2825 * Returns the number of initial bytes per VLSN in the vlsnCache. Returns 2826 * zero in a standalone env. Overridden by RepImpl. 2827 */ getCachedVLSNMinLength()2828 public int getCachedVLSNMinLength() { 2829 return 0; 2830 } 2831 2832 /** 2833 * True if ReplicationConfig set allowConvert as true. Standalone 2834 * environment is prohibited from doing a conversion, return false. 2835 */ getAllowRepConvert()2836 public boolean getAllowRepConvert() { 2837 return false; 2838 } 2839 2840 /** 2841 * True if this environment is converted from non-replicated to 2842 * replicated. 2843 */ isRepConverted()2844 public boolean isRepConverted() { 2845 return dbMapTree.isRepConverted(); 2846 } 2847 needRepConvert()2848 public boolean needRepConvert() { 2849 return needRepConvert; 2850 } 2851 bumpVLSN()2852 public VLSN bumpVLSN() { 2853 /* NOP for non-replicated environment. */ 2854 return null; 2855 } 2856 decrementVLSN()2857 public void decrementVLSN() { 2858 /* NOP for non-replicated environment. */ 2859 } 2860 2861 /** 2862 * @throws DatabaseException from subclasses. 2863 */ getVLSNProxy()2864 public VLSNRecoveryProxy getVLSNProxy() 2865 throws DatabaseException { 2866 2867 return new NoopVLSNProxy(); 2868 } 2869 isMaster()2870 public boolean isMaster() { 2871 /* NOP for non-replicated environment. */ 2872 return false; 2873 } 2874 2875 /** 2876 * @param recoveryInfo 2877 */ preRecoveryCheckpointInit(RecoveryInfo recoveryInfo)2878 public void preRecoveryCheckpointInit(RecoveryInfo recoveryInfo) { 2879 /* NOP for non-replicated environment. */ 2880 } 2881 2882 /** 2883 * @param logItem 2884 */ registerVLSN(LogItem logItem)2885 public void registerVLSN(LogItem logItem) { 2886 /* NOP for non-replicated environment. */ 2887 } 2888 2889 /** 2890 * Adjust the vlsn index after cleaning. 2891 * @param lastVLSN 2892 * @param deleteFileNum 2893 */ vlsnHeadTruncate(VLSN lastVLSN, long deleteFileNum)2894 public void vlsnHeadTruncate(VLSN lastVLSN, long deleteFileNum) { 2895 2896 /* NOP for non-replicated environment. */ 2897 } 2898 2899 /** 2900 * Do any work that must be done before the checkpoint end is written, as 2901 * as part of the checkpoint process. 2902 * @throws DatabaseException 2903 */ preCheckpointEndFlush()2904 public void preCheckpointEndFlush() 2905 throws DatabaseException { 2906 2907 /* NOP for non-replicated environment. */ 2908 } 2909 2910 /** 2911 * For replicated environments only; only the overridden method should 2912 * ever be called. 2913 * @param txnId 2914 * @throws DatabaseException from subclasses. 2915 */ createReplayTxn(long txnId)2916 public Txn createReplayTxn(long txnId) { 2917 throw EnvironmentFailureException.unexpectedState 2918 ("Should not be called on a non replicated environment"); 2919 } 2920 2921 /** 2922 * For replicated environments only; only the overridden method should 2923 * ever be called. 2924 * @throws DatabaseException from subclasses. 2925 */ createRepThreadLocker()2926 public ThreadLocker createRepThreadLocker() { 2927 throw EnvironmentFailureException.unexpectedState 2928 ("Should not be called on a non replicated environment"); 2929 } 2930 2931 /** 2932 * For replicated environments only; only the overridden method should 2933 * ever be called. 2934 * @param config 2935 * @throws DatabaseException from subclasses. 2936 */ createRepUserTxn(TransactionConfig config)2937 public Txn createRepUserTxn(TransactionConfig config) { 2938 throw EnvironmentFailureException.unexpectedState 2939 ("Should not be called on a non replicated environment"); 2940 } 2941 2942 /** 2943 * For replicated environments only; only the overridden method should 2944 * ever be called. 2945 * @param config 2946 * @param mandatedId 2947 * @throws DatabaseException from subclasses. 2948 */ createRepTxn(TransactionConfig config, long mandatedId)2949 public Txn createRepTxn(TransactionConfig config, 2950 long mandatedId) { 2951 throw EnvironmentFailureException.unexpectedState 2952 ("Should not be called on a non replicated environment"); 2953 } 2954 2955 /** 2956 * For replicated environments only; only the overridden method should 2957 * ever be called. 2958 * @param locker 2959 * @param cause 2960 * @throws com.sleepycat.je.rep.LockPreemptedException from subclasses. 2961 */ 2962 public OperationFailureException createLockPreemptedException(Locker locker, Throwable cause)2963 createLockPreemptedException(Locker locker, Throwable cause) { 2964 throw EnvironmentFailureException.unexpectedState 2965 ("Should not be called on a non replicated environment"); 2966 } 2967 2968 /** 2969 * For replicated environments only; only the overridden method should 2970 * ever be called. 2971 * @param msg 2972 * @param dbName 2973 * @param db 2974 * @throws com.sleepycat.je.rep.DatabasePreemptedException from subclasses. 2975 */ 2976 public OperationFailureException createDatabasePreemptedException(String msg, String dbName, Database db)2977 createDatabasePreemptedException(String msg, 2978 String dbName, 2979 Database db) { 2980 throw EnvironmentFailureException.unexpectedState 2981 ("Should not be called on a non replicated environment"); 2982 } 2983 2984 /** 2985 * For replicated environments only; only the overridden method should 2986 * ever be called. 2987 * @param msg unused 2988 * @throws com.sleepycat.je.rep.LogOverwriteException from subclasses. 2989 */ createLogOverwriteException(String msg)2990 public OperationFailureException createLogOverwriteException(String msg) { 2991 throw EnvironmentFailureException.unexpectedState 2992 ("Should not be called on a non replicated environment"); 2993 } 2994 2995 /** 2996 * Removes files that ought to be protected from deletion. 2997 * 2998 * @param files a set of log file numbers that the Cleaner is contemplating 2999 * deleting. This should of course be the set of files that the Cleaner 3000 * has decided are no longer needed for recovery and for holding database 3001 * contents. 3002 * 3003 * @return a set representing files that remain unprotected from deletion, 3004 * either a new set or a view onto the original set. (This method does not 3005 * modify the original passed-in set.) Returns null (in the RepImpl 3006 * subclass) if file deletion is prohibited. 3007 */ getUnprotectedFileSet( final NavigableSet<Long> files)3008 public NavigableSet<Long> getUnprotectedFileSet( 3009 final NavigableSet<Long> files) { 3010 3011 /* Allow test hook to return barrier value. */ 3012 if (cleanerBarrierHoook != null) { 3013 return files.headSet(cleanerBarrierHoook.getHookValue(), false); 3014 } 3015 3016 return files; 3017 } 3018 3019 /** 3020 * Check whether this environment can be opened on an existing environment 3021 * directory. 3022 * @param dbTreePreserveVLSN 3023 * 3024 * @throws UnsupportedOperationException via Environment ctor. 3025 */ checkRulesForExistingEnv(boolean dbTreeReplicatedBit, boolean dbTreePreserveVLSN)3026 public void checkRulesForExistingEnv(boolean dbTreeReplicatedBit, 3027 boolean dbTreePreserveVLSN) 3028 throws UnsupportedOperationException { 3029 3030 /* 3031 * We only permit standalone Environment construction on an existing 3032 * environment when we are in read only mode, to support command 3033 * line utilities. We prohibit read/write opening, because we don't 3034 * want to chance corruption of the environment by writing non-VLSN 3035 * tagged entries in. 3036 */ 3037 if (dbTreeReplicatedBit && (!isReadOnly())) { 3038 throw new UnsupportedOperationException 3039 ("This environment was previously opened for replication." + 3040 " It cannot be re-opened for in read/write mode for" + 3041 " non-replicated operation."); 3042 } 3043 3044 /* 3045 * Same as above but for the preserve VLSN param, which may only be 3046 * used in a replicated environment. See this overridden method in 3047 * RepImpl which checks that the param is never changed. 3048 */ 3049 if (getPreserveVLSN() && (!isReadOnly())) { 3050 /* Cannot use RepParams constant in standalone code. */ 3051 throw new IllegalArgumentException 3052 (EnvironmentParams.REP_PARAM_PREFIX + 3053 "preserveRecordVersion parameter may not be true in a" + 3054 " read-write, non-replicated environment"); 3055 } 3056 } 3057 3058 /** 3059 * Ensure that the in-memory vlsn index encompasses all logged entries 3060 * before it is flushed to disk. A No-Op for non-replicated systems. 3061 * [#19754] 3062 */ awaitVLSNConsistency()3063 public void awaitVLSNConsistency() { 3064 /* Nothing to do in a non-replicated system. */ 3065 } 3066 3067 /** 3068 * The VLSNRecoveryProxy is only needed for replicated environments. 3069 */ 3070 private class NoopVLSNProxy implements VLSNRecoveryProxy { 3071 3072 @Override trackMapping(long lsn, LogEntryHeader currentEntryHeader, LogEntry targetLogEntry)3073 public void trackMapping(long lsn, 3074 LogEntryHeader currentEntryHeader, 3075 LogEntry targetLogEntry) { 3076 /* intentional no-op */ 3077 } 3078 } 3079 getThroughputStat(StatDefinition def)3080 public AtomicLongStat getThroughputStat(StatDefinition def) { 3081 return thrputStats.getAtomicLongStat(def); 3082 } 3083 getThroughputStatGroup()3084 public ThroughputStatGroup getThroughputStatGroup() { 3085 return thrputStats; 3086 } 3087 3088 /** 3089 * Private class to prevent used of the close() method by the application 3090 * on an internal handle. 3091 */ 3092 private static class InternalEnvironment extends Environment { 3093 InternalEnvironment(File envHome, EnvironmentConfig configuration, EnvironmentImpl envImpl)3094 public InternalEnvironment(File envHome, 3095 EnvironmentConfig configuration, 3096 EnvironmentImpl envImpl) 3097 throws EnvironmentNotFoundException, 3098 EnvironmentLockedException, 3099 VersionMismatchException, 3100 DatabaseException, 3101 IllegalArgumentException { 3102 super(envHome, configuration, false /*openIfNeeded*/, 3103 null /*repConfigProxy*/, envImpl); 3104 } 3105 3106 @Override isInternalHandle()3107 protected boolean isInternalHandle() { 3108 return true; 3109 } 3110 3111 @Override close()3112 public synchronized void close() { 3113 throw EnvironmentFailureException.unexpectedState 3114 ("close() not permitted on an internal environment handle"); 3115 } 3116 } 3117 3118 /** 3119 * Preload exceptions, classes. 3120 */ 3121 3122 /** 3123 * Undeclared exception used to throw through SortedLSNTreeWalker code 3124 * when preload has either filled the user's max byte or time request. 3125 */ 3126 @SuppressWarnings("serial") 3127 private static class HaltPreloadException extends RuntimeException { 3128 3129 private final PreloadStatus status; 3130 HaltPreloadException(PreloadStatus status)3131 HaltPreloadException(PreloadStatus status) { 3132 super(status.toString()); 3133 this.status = status; 3134 } 3135 getStatus()3136 PreloadStatus getStatus() { 3137 return status; 3138 } 3139 } 3140 3141 private static final HaltPreloadException 3142 TIME_EXCEEDED_PRELOAD_EXCEPTION = 3143 new HaltPreloadException(PreloadStatus.EXCEEDED_TIME); 3144 3145 private static final HaltPreloadException 3146 MEMORY_EXCEEDED_PRELOAD_EXCEPTION = 3147 new HaltPreloadException(PreloadStatus.FILLED_CACHE); 3148 3149 private static final HaltPreloadException 3150 USER_HALT_REQUEST_PRELOAD_EXCEPTION = 3151 new HaltPreloadException(PreloadStatus.USER_HALT_REQUEST); 3152 preload(final DatabaseImpl[] dbImpls, final PreloadConfig config)3153 public PreloadStats preload(final DatabaseImpl[] dbImpls, 3154 final PreloadConfig config) 3155 throws DatabaseException { 3156 3157 try { 3158 long maxBytes = config.getMaxBytes(); 3159 long maxMillisecs = config.getMaxMillisecs(); 3160 long targetTime = Long.MAX_VALUE; 3161 if (maxMillisecs > 0) { 3162 targetTime = System.currentTimeMillis() + maxMillisecs; 3163 if (targetTime < 0) { 3164 targetTime = Long.MAX_VALUE; 3165 } 3166 } 3167 3168 long cacheBudget = getMemoryBudget().getMaxMemory(); 3169 if (maxBytes == 0) { 3170 maxBytes = cacheBudget; 3171 } else if (maxBytes > cacheBudget) { 3172 throw new IllegalArgumentException 3173 ("maxBytes parameter to preload() was " + 3174 "specified as " + 3175 maxBytes + " bytes \nbut the cache is only " + 3176 cacheBudget + " bytes."); 3177 } 3178 3179 /* 3180 * Sort DatabaseImpls so that we always latch in a well-defined 3181 * order to avoid potential deadlocks if multiple preloads happen 3182 * to (accidentally) execute concurrently. 3183 */ 3184 Arrays.sort(dbImpls, new Comparator<DatabaseImpl>() { 3185 @Override 3186 public int compare(DatabaseImpl o1, DatabaseImpl o2) { 3187 DatabaseId id1 = o1.getId(); 3188 DatabaseId id2 = o2.getId(); 3189 return id1.compareTo(id2); 3190 } 3191 }); 3192 3193 PreloadStats pstats = new PreloadStats(); 3194 PreloadProcessor callback = new PreloadProcessor 3195 (this, maxBytes, targetTime, pstats, config); 3196 int nDbs = dbImpls.length; 3197 long[] rootLsns = new long[nDbs]; 3198 for (int i = 0; i < nDbs; i += 1) { 3199 rootLsns[i] = dbImpls[i].getTree().getRootLsn(); 3200 } 3201 SortedLSNTreeWalker walker = 3202 new PreloadLSNTreeWalker(dbImpls, rootLsns, callback, config); 3203 try { 3204 walker.walk(); 3205 callback.close(); 3206 } catch (HaltPreloadException HPE) { 3207 pstats.setStatus(HPE.getStatus()); 3208 } 3209 3210 if (LatchSupport.TRACK_LATCHES) { 3211 LatchSupport.expectBtreeLatchesHeld(0); 3212 } 3213 return pstats; 3214 } catch (Error E) { 3215 invalidate(E); 3216 throw E; 3217 } 3218 } 3219 3220 /** 3221 * The processLSN() code for PreloadLSNTreeWalker. 3222 */ 3223 private static class PreloadProcessor implements TreeNodeProcessor { 3224 3225 private final EnvironmentImpl envImpl; 3226 private final long maxBytes; 3227 private final long targetTime; 3228 private final PreloadStats stats; 3229 private final boolean countLNs; 3230 private final ProgressListener<PreloadConfig.Phases> progressListener; 3231 private long progressCounter = 0; 3232 PreloadProcessor(final EnvironmentImpl envImpl, final long maxBytes, final long targetTime, final PreloadStats stats, final PreloadConfig config)3233 PreloadProcessor(final EnvironmentImpl envImpl, 3234 final long maxBytes, 3235 final long targetTime, 3236 final PreloadStats stats, 3237 final PreloadConfig config) { 3238 this.envImpl = envImpl; 3239 this.maxBytes = maxBytes; 3240 this.targetTime = targetTime; 3241 this.stats = stats; 3242 this.countLNs = config.getLoadLNs(); 3243 this.progressListener = config.getProgressListener(); 3244 } 3245 3246 /** 3247 * Called for each LSN that the SortedLSNTreeWalker encounters. 3248 */ 3249 @Override processLSN(@uppressWarningsR) long childLsn, LogEntryType childType, @SuppressWarnings(R) Node ignore, @SuppressWarnings(R) byte[] ignore2, @SuppressWarnings(R) int ignore3)3250 public void processLSN(@SuppressWarnings("unused") long childLsn, 3251 LogEntryType childType, 3252 @SuppressWarnings("unused") Node ignore, 3253 @SuppressWarnings("unused") byte[] ignore2, 3254 @SuppressWarnings("unused") int ignore3) { 3255 3256 /* 3257 * Check if we've exceeded either the max time or max bytes 3258 * allowed for this preload() call. 3259 */ 3260 if (System.currentTimeMillis() > targetTime) { 3261 throw TIME_EXCEEDED_PRELOAD_EXCEPTION; 3262 } 3263 3264 if (envImpl.getMemoryBudget().getCacheMemoryUsage() > maxBytes) { 3265 throw MEMORY_EXCEEDED_PRELOAD_EXCEPTION; 3266 } 3267 3268 if (progressListener != null) { 3269 progressCounter += 1; 3270 if (!progressListener.progress(PreloadConfig.Phases.PRELOAD, 3271 progressCounter, -1)) { 3272 throw USER_HALT_REQUEST_PRELOAD_EXCEPTION; 3273 } 3274 } 3275 3276 /* Count entry types to return in the PreloadStats. */ 3277 if (childType.equals(LogEntryType.LOG_DUPCOUNTLN_TRANSACTIONAL) || 3278 childType.equals(LogEntryType.LOG_DUPCOUNTLN)) { 3279 stats.incDupCountLNsLoaded(); 3280 } else if (childType.isLNType()) { 3281 if (countLNs) { 3282 stats.incLNsLoaded(); 3283 } 3284 } else if (childType.equals(LogEntryType.LOG_DBIN)) { 3285 stats.incDBINsLoaded(); 3286 } else if (childType.equals(LogEntryType.LOG_BIN)) { 3287 stats.incBINsLoaded(); 3288 } else if (childType.equals(LogEntryType.LOG_DIN)) { 3289 stats.incDINsLoaded(); 3290 } else if (childType.equals(LogEntryType.LOG_IN)) { 3291 stats.incINsLoaded(); 3292 } 3293 } 3294 3295 @Override processDirtyDeletedLN(@uppressWarningsR) long childLsn, @SuppressWarnings(R) LN ln, @SuppressWarnings(R) byte[] lnKey)3296 public void processDirtyDeletedLN(@SuppressWarnings("unused") 3297 long childLsn, 3298 @SuppressWarnings("unused") 3299 LN ln, 3300 @SuppressWarnings("unused") 3301 byte[] lnKey) { 3302 } 3303 3304 @Override noteMemoryExceeded()3305 public void noteMemoryExceeded() { 3306 stats.incMemoryExceeded(); 3307 } 3308 close()3309 public void close() { 3310 /* Indicate that we're finished. */ 3311 if (progressListener != null) { 3312 progressListener.progress(PreloadConfig.Phases.PRELOAD, 3313 progressCounter, progressCounter); 3314 } 3315 } 3316 } 3317 3318 /* 3319 * An extension of SortedLSNTreeWalker that latches the root IN. 3320 */ 3321 private class PreloadLSNTreeWalker extends SortedLSNTreeWalker { 3322 PreloadLSNTreeWalker(DatabaseImpl[] dbs, long[] rootLsns, TreeNodeProcessor callback, PreloadConfig conf)3323 PreloadLSNTreeWalker(DatabaseImpl[] dbs, 3324 long[] rootLsns, 3325 TreeNodeProcessor callback, 3326 PreloadConfig conf) 3327 throws DatabaseException { 3328 3329 super(dbs, 3330 false /*setDbState*/, 3331 rootLsns, 3332 callback, 3333 null, null); /* savedException, exception predicate */ 3334 accumulateLNs = conf.getLoadLNs(); 3335 setLSNBatchSize(conf.getLSNBatchSize()); 3336 setInternalMemoryLimit(conf.getInternalMemoryLimit()); 3337 } 3338 3339 @Override walk()3340 public void walk() 3341 throws DatabaseException { 3342 3343 int nDbs = dbImpls.length; 3344 int nDbsLatched = 0; 3345 try { 3346 try { 3347 for (int i = 0; i < nDbs; i += 1) { 3348 DatabaseImpl dbImpl = dbImpls[i]; 3349 dbImpl.getTree().latchRootLatchExclusive(); 3350 nDbsLatched += 1; 3351 } 3352 } catch (Exception e) { 3353 throw EnvironmentFailureException.unexpectedException 3354 (EnvironmentImpl.this, 3355 "Couldn't latch all DatabaseImpls during preload", e); 3356 } 3357 3358 walkInternal(); 3359 } finally { 3360 3361 /* 3362 * Release latches in reverse acquisition order to avoid 3363 * deadlocks with possible concurrent preload operations. 3364 */ 3365 for (int i = nDbsLatched - 1; i >= 0; i -= 1) { 3366 DatabaseImpl dbImpl = dbImpls[i]; 3367 dbImpl.getTree().releaseRootLatch(); 3368 } 3369 } 3370 } 3371 3372 /* 3373 * Method to get the Root IN for this DatabaseImpl's tree. 3374 */ 3375 @Override getRootIN(DatabaseImpl dbImpl, @SuppressWarnings(R) long rootLsn)3376 protected IN getRootIN(DatabaseImpl dbImpl, 3377 @SuppressWarnings("unused") long rootLsn) { 3378 return dbImpl.getTree().getRootINRootAlreadyLatched( 3379 CacheMode.UNCHANGED, false /*exclusive*/); 3380 } 3381 3382 @Override fetchAndInsertIntoTree()3383 protected boolean fetchAndInsertIntoTree() { 3384 return true; 3385 } 3386 } 3387 getRecoveryProgressListener()3388 public ProgressListener<RecoveryProgress> getRecoveryProgressListener() { 3389 return recoveryProgressListener; 3390 } 3391 getClassLoader()3392 public ClassLoader getClassLoader() { 3393 return classLoader; 3394 } 3395 getDupConvertPreloadConfig()3396 public PreloadConfig getDupConvertPreloadConfig() { 3397 return dupConvertPreloadConfig; 3398 } 3399 } 3400