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 8 package com.sleepycat.je; 9 10 import java.io.Closeable; 11 import java.io.File; 12 import java.io.PrintStream; 13 import java.util.List; 14 import java.util.Map; 15 import java.util.concurrent.ConcurrentHashMap; 16 import java.util.logging.Level; 17 18 import javax.transaction.xa.Xid; 19 20 import com.sleepycat.je.Durability.ReplicaAckPolicy; 21 import com.sleepycat.je.dbi.DatabaseImpl; 22 import com.sleepycat.je.dbi.DbConfigManager; 23 import com.sleepycat.je.dbi.DbEnvPool; 24 import com.sleepycat.je.dbi.DbTree; 25 import com.sleepycat.je.dbi.DbTree.TruncateDbResult; 26 import com.sleepycat.je.dbi.EnvironmentImpl; 27 import com.sleepycat.je.dbi.RepConfigProxy; 28 import com.sleepycat.je.dbi.StartupTracker.Phase; 29 import com.sleepycat.je.dbi.TriggerManager; 30 import com.sleepycat.je.txn.HandleLocker; 31 import com.sleepycat.je.txn.Locker; 32 import com.sleepycat.je.txn.LockerFactory; 33 import com.sleepycat.je.txn.Txn; 34 import com.sleepycat.je.utilint.DatabaseUtil; 35 import com.sleepycat.je.utilint.LoggerUtils; 36 import com.sleepycat.je.utilint.Pair; 37 38 /** 39 * A database environment. Environments include support for some or all of 40 * caching, locking, logging and transactions. 41 * 42 * <p>To open an existing environment with default attributes the application 43 * may use a default environment configuration object or null: 44 * <blockquote> 45 * <pre> 46 * // Open an environment handle with default attributes. 47 * Environment env = new Environment(home, new EnvironmentConfig()); 48 * </pre> 49 * </blockquote> 50 * or 51 * <blockquote><pre> 52 * Environment env = new Environment(home, null); 53 * </pre></blockquote> 54 * <p>Note that many Environment objects may access a single environment.</p> 55 * <p>To create an environment or customize attributes, the application should 56 * customize the configuration class. For example:</p> 57 * <blockquote><pre> 58 * EnvironmentConfig envConfig = new EnvironmentConfig(); 59 * envConfig.setTransactional(true); 60 * envConfig.setAllowCreate(true); 61 * envConfig.setCacheSize(1000000); 62 * Environment newlyCreatedEnv = new Environment(home, envConfig); 63 * </pre></blockquote> 64 * 65 * <p>Note that environment configuration parameters can also be set through 66 * the <environment home>/je.properties file. This file takes precedence 67 * over any programmatically specified configuration parameters so that 68 * configuration changes can be made without recompiling. Environment 69 * configuration follows this order of precedence:</p> 70 * 71 * <ol> 72 * <li>Configuration parameters specified in 73 * <environment home>/je.properties take first precedence. 74 * <li> Configuration parameters set in the EnvironmentConfig object used at 75 * Environment construction e tameters not set by the application are set to 76 * system defaults, described along with the parameter name String constants 77 * in the EnvironmentConfig class. 78 * </ol> 79 * 80 * <p>An <em>environment handle</em> is an Environment instance. More than one 81 * Environment instance may be created for the same physical directory, which 82 * is the same as saying that more than one Environment handle may be open at 83 * one time for a given environment.</p> 84 * 85 * The Environment handle should not be closed while any other handle remains 86 * open that is using it as a reference (for example, {@link 87 * com.sleepycat.je.Database Database} or {@link com.sleepycat.je.Transaction 88 * Transaction}. Once {@link com.sleepycat.je.Environment#close 89 * Environment.close} is called, this object may not be accessed again. 90 */ 91 public class Environment implements Closeable { 92 93 /** 94 * @hidden 95 * envImpl is a reference to the shared underlying environment. 96 */ 97 protected EnvironmentImpl envImpl; 98 private TransactionConfig defaultTxnConfig; 99 private EnvironmentMutableConfig handleConfig; 100 private final EnvironmentConfig appliedFinalConfig; 101 102 private final Map<Database, Database> referringDbs; 103 private final Map<Transaction, Transaction> referringDbTxns; 104 105 /** 106 * @hidden 107 * The name of the cleaner daemon thread. This constant is passed to an 108 * ExceptionEvent's threadName argument when an exception is thrown in the 109 * cleaner daemon thread. 110 */ 111 public static final String CLEANER_NAME = "Cleaner"; 112 113 /** 114 * @hidden 115 * The name of the IN Compressor daemon thread. This constant is passed to 116 * an ExceptionEvent's threadName argument when an exception is thrown in 117 * the IN Compressor daemon thread. 118 */ 119 public static final String INCOMP_NAME = "INCompressor"; 120 121 /** 122 * @hidden 123 * The name of the Checkpointer daemon thread. This constant is passed to 124 * an ExceptionEvent's threadName argument when an exception is thrown in 125 * the Checkpointer daemon thread. 126 */ 127 public static final String CHECKPOINTER_NAME = "Checkpointer"; 128 129 /** 130 * @hidden 131 * The name of the StatCapture daemon thread. This constant is passed to 132 * an ExceptionEvent's threadName argument when an exception is thrown in 133 * the StatCapture daemon thread. 134 */ 135 public static final String STATCAPTURE_NAME = "StatCapture"; 136 137 /** 138 * Creates a database environment handle. 139 * 140 * @param envHome The database environment's home directory. 141 * 142 * @param configuration The database environment attributes. If null, 143 * default attributes are used. 144 * 145 * @throws EnvironmentNotFoundException if the environment does not exist 146 * (does not contain at least one log file) and the {@code 147 * EnvironmentConfig AllowCreate} parameter is false. 148 * 149 * @throws EnvironmentLockedException when an environment cannot be opened 150 * for write access because another process has the same environment open 151 * for write access. <strong>Warning:</strong> This exception should be 152 * handled when an environment is opened by more than one process. 153 * 154 * @throws VersionMismatchException when the existing log is not compatible 155 * with the version of JE that is running. This occurs when a later 156 * version of JE was used to create the log. <strong>Warning:</strong> 157 * This exception should be handled when more than one version of JE may be 158 * used to access an environment. 159 * 160 * @throws EnvironmentFailureException if an unexpected, internal or 161 * environment-wide failure occurs. 162 * 163 * @throws UnsupportedOperationException if this environment was previously 164 * opened for replication and is not being opened read-only. 165 * 166 * @throws IllegalArgumentException if an invalid parameter is specified, 167 * for example, an invalid {@code EnvironmentConfig} parameter. 168 */ Environment(File envHome, EnvironmentConfig configuration)169 public Environment(File envHome, EnvironmentConfig configuration) 170 throws EnvironmentNotFoundException, 171 EnvironmentLockedException, 172 VersionMismatchException, 173 DatabaseException, 174 IllegalArgumentException { 175 176 this(envHome, configuration, true /*openIfNeeded*/, 177 null /*repConfigProxy*/, null /*envImplParam*/); 178 } 179 180 /** 181 * @hidden 182 * Replication support. 183 */ Environment(File envHome, EnvironmentConfig configuration, RepConfigProxy repConfigProxy, EnvironmentImpl envImplParam)184 protected Environment(File envHome, 185 EnvironmentConfig configuration, 186 RepConfigProxy repConfigProxy, 187 EnvironmentImpl envImplParam) { 188 this(envHome, configuration, true /*openIfNeeded*/, repConfigProxy, 189 envImplParam); 190 } 191 192 /** 193 * Gets an Environment for an existing EnvironmentImpl. Used by utilities 194 * such as the JMX MBean which don't want to open the environment or be 195 * reference counted. The calling application must take care not to retain 196 */ Environment(File envHome)197 Environment(File envHome) { 198 this(envHome, null /*configuration*/, false /*openIfNeeded*/, 199 null /*repConfigProxy*/, null /*envImplParam*/); 200 } 201 202 /** 203 * @hidden 204 * Internal common constructor. 205 * 206 * @param envImpl is non-null only when used by EnvironmentIml to create an 207 * InternalEnvironment. 208 */ Environment(File envHome, EnvironmentConfig envConfig, boolean openIfNeeded, RepConfigProxy repConfigProxy, EnvironmentImpl envImplParam)209 protected Environment(File envHome, 210 EnvironmentConfig envConfig, 211 boolean openIfNeeded, 212 RepConfigProxy repConfigProxy, 213 EnvironmentImpl envImplParam) { 214 215 /* If openIfNeeded is false, then envConfig must be null. */ 216 assert openIfNeeded || envConfig == null || envImplParam != null; 217 218 envImpl = null; 219 referringDbs = new ConcurrentHashMap<Database, Database>(); 220 referringDbTxns = new ConcurrentHashMap<Transaction, Transaction>(); 221 222 DatabaseUtil.checkForNullParam(envHome, "envHome"); 223 224 appliedFinalConfig = 225 setupHandleConfig(envHome, envConfig, repConfigProxy); 226 227 if (envImplParam != null) { 228 /* We're creating an InternalEnvironment in EnvironmentImpl. */ 229 envImpl = envImplParam; 230 } else { 231 /* Open a new or existing environment in the shared pool. */ 232 envImpl = makeEnvironmentImpl(envHome, 233 envConfig, 234 openIfNeeded, 235 repConfigProxy); 236 } 237 } 238 239 /** 240 * @hidden 241 * MakeEnvironmentImpl is called both by the Environment constructor and 242 * by the ReplicatedEnvironment constructor when recreating the environment 243 * for a hard recovery. 244 */ makeEnvironmentImpl(File envHome, EnvironmentConfig envConfig, boolean openIfNeeded, RepConfigProxy repConfigProxy)245 protected EnvironmentImpl makeEnvironmentImpl 246 (File envHome, 247 EnvironmentConfig envConfig, 248 boolean openIfNeeded, 249 RepConfigProxy repConfigProxy) { 250 251 envImpl = DbEnvPool.getInstance().getEnvironment 252 (envHome, 253 appliedFinalConfig, 254 envConfig != null /*checkImmutableParams*/, 255 openIfNeeded, 256 setupRepConfig(envHome, repConfigProxy, envConfig)); 257 258 if (envImpl != null) { 259 envImpl.registerMBean(this); 260 } 261 262 return envImpl; 263 } 264 265 /** 266 * Validate the parameters specified in the environment config. Applies 267 * the configurations specified in the je.properties file to override any 268 * programmatically set configurations. Create a copy to save in this 269 * handle. The main reason to return a config instead of using the 270 * handleConfig field is to return an EnvironmentConfig instead of a 271 * EnvironmentMutableConfig. 272 */ setupHandleConfig(File envHome, EnvironmentConfig envConfig, RepConfigProxy repConfig)273 private EnvironmentConfig setupHandleConfig(File envHome, 274 EnvironmentConfig envConfig, 275 RepConfigProxy repConfig) 276 throws IllegalArgumentException { 277 278 /* If the user specified a null object, use the default */ 279 EnvironmentConfig baseConfig = (envConfig == null) ? 280 EnvironmentConfig.DEFAULT : envConfig; 281 282 /* Make a copy, apply je.properties, and init the handle config. */ 283 EnvironmentConfig useConfig = baseConfig.clone(); 284 285 /* Apply the je.properties file. */ 286 if (useConfig.getLoadPropertyFile()) { 287 DbConfigManager.applyFileConfig(envHome, 288 DbInternal.getProps(useConfig), 289 false); // forReplication 290 } 291 copyToHandleConfig(useConfig, useConfig, repConfig); 292 return useConfig; 293 } 294 295 /** 296 * @hidden 297 * Obtain a validated replication configuration. In a non-HA environment, 298 * return null. 299 */ 300 protected RepConfigProxy setupRepConfig(final File envHome, final RepConfigProxy repConfigProxy, final EnvironmentConfig envConfig)301 setupRepConfig(final File envHome, 302 final RepConfigProxy repConfigProxy, 303 final EnvironmentConfig envConfig) { 304 305 return null; 306 } 307 308 /** 309 * The Environment.close method closes the Berkeley DB environment. 310 * 311 * <p>When the last environment handle is closed, allocated resources are 312 * freed, and daemon threads are stopped, even if they are performing work. 313 * For example, if the cleaner is still cleaning the log, it will be 314 * stopped at the next reasonable opportunity and perform no more cleaning 315 * operations.</p> 316 * 317 * <p>The Environment handle should not be closed while any other handle 318 * that refers to it is not yet closed; for example, database environment 319 * handles must not be closed while database handles remain open, or 320 * transactions in the environment have not yet committed or aborted. 321 * Specifically, this includes {@link com.sleepycat.je.Database Database}, 322 * {@link com.sleepycat.je.Cursor Cursor} and {@link 323 * com.sleepycat.je.Transaction Transaction} handles.</p> 324 * 325 * <p>If this handle has already been closed, this method does nothing and 326 * returns without throwing an exception.</p> 327 * 328 * <p>In multithreaded applications, only a single thread should call 329 * Environment.close.</p> 330 * 331 * <p>The environment handle may not be used again after this method has 332 * been called, regardless of the method's success or failure, with one 333 * exception: the {@code close} method itself may be called any number of 334 * times.</p> 335 * 336 * <p>WARNING: To guard against memory leaks, the application should 337 * discard all references to the closed handle. While BDB makes an effort 338 * to discard references from closed objects to the allocated memory for an 339 * environment, this behavior is not guaranteed. The safe course of action 340 * for an application is to discard all references to closed BDB 341 * objects.</p> 342 * 343 * @throws EnvironmentFailureException if an unexpected, internal or 344 * environment-wide failure occurs. 345 * 346 * @throws IllegalStateException if any open databases or transactions 347 * refer to this handle. 348 */ close()349 public synchronized void close() 350 throws DatabaseException { 351 352 if (envImpl == null) { 353 return; 354 } 355 356 if (!envImpl.isValid()) { 357 358 /* 359 * We're trying to close on an environment that has seen a fatal 360 * exception. Try to do the minimum, such as closing file 361 * descriptors, to support re-opening the environment in the same 362 * JVM. 363 */ 364 try { 365 envImpl.closeAfterInvalid(); 366 } finally { 367 envImpl = null; 368 } 369 return; 370 } 371 372 final StringBuilder errors = new StringBuilder(); 373 try { 374 checkForCloseErrors(errors); 375 376 try { 377 envImpl.close(); 378 } catch (RuntimeException e) { 379 if (!envImpl.isValid()) { 380 /* Propagate if env is invalidated. */ 381 throw e; 382 } 383 errors.append 384 ("\nWhile closing Environment encountered exception: "); 385 errors.append(e).append("\n"); 386 } 387 388 if (errors.length() > 0) { 389 throw new IllegalStateException(errors.toString()); 390 } 391 } finally { 392 envImpl = null; 393 } 394 } 395 396 /** 397 * Close an InternalEnvironment handle. We do not call 398 * EnvironmentImpl.close here, since an InternalEnvironment is not 399 * registered like a non-internal handle. However, we must call 400 * checkForCloseErrors to auto-close internal databases, as well as check 401 * for errors. 402 */ closeInternalHandle()403 synchronized void closeInternalHandle() { 404 final StringBuilder errors = new StringBuilder(); 405 checkForCloseErrors(errors); 406 if (errors.length() > 0) { 407 throw new IllegalStateException(errors.toString()); 408 } 409 } 410 checkForCloseErrors(StringBuilder errors)411 private void checkForCloseErrors(StringBuilder errors) { 412 413 checkOpenDbs(errors); 414 415 checkOpenTxns(errors); 416 417 if (!isInternalHandle()) { 418 419 /* 420 * Only check for open XA transactions against user created 421 * environment handles. 422 */ 423 checkOpenXATransactions(errors); 424 } 425 } 426 427 /** 428 * Appends error messages to the errors argument if there are 429 * open XA transactions associated with the underlying EnvironmentImpl. 430 */ checkOpenXATransactions(final StringBuilder errors)431 private void checkOpenXATransactions(final StringBuilder errors) { 432 Xid[] openXids = envImpl.getTxnManager().XARecover(); 433 if (openXids != null && openXids.length > 0) { 434 errors.append("There "); 435 int nXATxns = openXids.length; 436 if (nXATxns == 1) { 437 errors.append("is 1 existing XA transaction opened"); 438 errors.append(" in the Environment.\n"); 439 errors.append("It"); 440 } else { 441 errors.append("are "); 442 errors.append(nXATxns); 443 errors.append(" existing transactions opened in"); 444 errors.append(" the Environment.\n"); 445 errors.append("They"); 446 } 447 errors.append(" will be left open ...\n"); 448 } 449 } 450 451 /** 452 * Appends error messages to the errors argument if there are open 453 * transactions associated with the environment. 454 */ checkOpenTxns(final StringBuilder errors)455 private void checkOpenTxns(final StringBuilder errors) { 456 int nTxns = (referringDbTxns == null) ? 0 : referringDbTxns.size(); 457 if (nTxns == 0) { 458 return; 459 } 460 461 errors.append("There "); 462 if (nTxns == 1) { 463 errors.append("is 1 existing transaction opened"); 464 errors.append(" against the Environment.\n"); 465 } else { 466 errors.append("are "); 467 errors.append(nTxns); 468 errors.append(" existing transactions opened against"); 469 errors.append(" the Environment.\n"); 470 } 471 errors.append("Aborting open transactions ...\n"); 472 473 for (Transaction txn : referringDbTxns.keySet()) { 474 try { 475 errors.append("aborting " + txn); 476 txn.abort(); 477 } catch (RuntimeException e) { 478 if (!envImpl.isValid()) { 479 /* Propagate if env is invalidated. */ 480 throw e; 481 } 482 errors.append("\nWhile aborting transaction "); 483 errors.append(txn.getId()); 484 errors.append(" encountered exception: "); 485 errors.append(e).append("\n"); 486 } 487 } 488 } 489 490 /** 491 * Appends error messages to the errors argument if there are open database 492 * handles associated with the environment. 493 */ checkOpenDbs(final StringBuilder errors)494 private void checkOpenDbs(final StringBuilder errors) { 495 496 if (referringDbs.isEmpty()) { 497 return; 498 } 499 500 int nOpenUserDbs = 0; 501 502 for (Database db : referringDbs.keySet()) { 503 String dbName = ""; 504 try { 505 506 /* 507 * Save the db name before we attempt the close, it's 508 * unavailable after the close. 509 */ 510 dbName = db.getDebugName(); 511 512 if (!db.getDatabaseImpl().isInternalDb()) { 513 nOpenUserDbs += 1; 514 errors.append("Unclosed Database: "); 515 errors.append(dbName).append("\n"); 516 } 517 db.close(); 518 } catch (RuntimeException e) { 519 if (!envImpl.isValid()) { 520 /* Propagate if env is invalidated. */ 521 throw e; 522 } 523 errors.append("\nWhile closing Database "); 524 errors.append(dbName); 525 errors.append(" encountered exception: "); 526 errors.append(LoggerUtils.getStackTrace(e)).append("\n"); 527 } 528 } 529 530 if (nOpenUserDbs > 0) { 531 errors.append("Databases left open: "); 532 errors.append(nOpenUserDbs).append("\n"); 533 } 534 } 535 536 /** 537 * Opens, and optionally creates, a <code>Database</code>. 538 * 539 * @param txn For a transactional database, an explicit transaction may be 540 * specified, or null may be specified to use auto-commit. For a 541 * non-transactional database, null must be specified. 542 * 543 * @param databaseName The name of the database. 544 * 545 * @param dbConfig The database attributes. If null, default attributes 546 * are used. 547 * 548 * @return Database handle. 549 * 550 * @throws DatabaseExistsException if the database already exists and the 551 * {@code DatabaseConfig ExclusiveCreate} parameter is true. 552 * 553 * @throws DatabaseNotFoundException if the database does not exist and the 554 * {@code DatabaseConfig AllowCreate} parameter is false. 555 * 556 * @throws OperationFailureException if one of the <a 557 * href="../je/OperationFailureException.html#readFailures">Read Operation 558 * Failures</a> occurs. If the database does not exist and the {@link 559 * DatabaseConfig#setAllowCreate AllowCreate} parameter is true, then one 560 * of the <a 561 * href="../je/OperationFailureException.html#writeFailures">Write 562 * Operation Failures</a> may also occur. 563 * 564 * @throws EnvironmentFailureException if an unexpected, internal or 565 * environment-wide failure occurs. 566 * 567 * @throws IllegalStateException if this handle or the underlying 568 * environment has been closed. 569 * 570 * @throws IllegalArgumentException if an invalid parameter is specified, 571 * for example, an invalid {@code DatabaseConfig} property. 572 * 573 * @throws IllegalStateException if DatabaseConfig properties are changed 574 * and there are other open handles for this database. 575 */ openDatabase(Transaction txn, String databaseName, DatabaseConfig dbConfig)576 public synchronized Database openDatabase(Transaction txn, 577 String databaseName, 578 DatabaseConfig dbConfig) 579 throws DatabaseNotFoundException, 580 DatabaseExistsException, 581 IllegalArgumentException, 582 IllegalStateException { 583 584 checkHandleIsValid(); 585 checkEnv(); 586 587 try { 588 if (dbConfig == null) { 589 dbConfig = DatabaseConfig.DEFAULT; 590 } 591 592 Database db = new Database(this); 593 setupDatabase(txn, db, databaseName, dbConfig, 594 false /*isInternalDb*/); 595 return db; 596 } catch (Error E) { 597 envImpl.invalidate(E); 598 throw E; 599 } 600 } 601 602 /** 603 * Opens an internal database for internal JE use. 604 * - permits opening DBs with reserved (internal) names. 605 * - permits opening a transactional DB in a non-transactional env. 606 * 607 * DbConfig should not be null. Note that the dbConfig argument determines 608 * whether the database that is created is to be replicated or is 609 * standalone. The current default is for dbConfig to be replicated, so use 610 * DatabaseConfig.setReplicated(false) to create a local internal database. 611 */ openInternalDatabase(Transaction txn, String databaseName, DatabaseConfig dbConfig)612 synchronized Database openInternalDatabase(Transaction txn, 613 String databaseName, 614 DatabaseConfig dbConfig) 615 throws DatabaseNotFoundException, DatabaseExistsException { 616 617 assert DbTree.isReservedDbName(databaseName) : databaseName; 618 Database db = new Database(this); 619 setupDatabase(txn, db, databaseName, dbConfig, true /*isInternalDb*/); 620 return db; 621 } 622 623 /** 624 * Opens and optionally creates a <code>SecondaryDatabase</code>. 625 * 626 * <p>Note that the associations between primary and secondary databases 627 * are not stored persistently. Whenever a primary database is opened for 628 * write access by the application, the appropriate associated secondary 629 * databases should also be opened by the application. This is necessary 630 * to ensure data integrity when changes are made to the primary 631 * database.</p> 632 * 633 * @param txn For a transactional database, an explicit transaction may be 634 * specified, or null may be specified to use auto-commit. For a 635 * non-transactional database, null must be specified. 636 * 637 * @param databaseName The name of the database. 638 * 639 * @param primaryDatabase the primary database with which the secondary 640 * database will be associated. The primary database must not be 641 * configured for duplicates. 642 * 643 * @param dbConfig The secondary database attributes. If null, default 644 * attributes are used. 645 * 646 * @return Database handle. 647 * 648 * @throws DatabaseExistsException if the database already exists and the 649 * {@code DatabaseConfig ExclusiveCreate} parameter is true. 650 * 651 * @throws DatabaseNotFoundException if the database does not exist and the 652 * {@code DatabaseConfig AllowCreate} parameter is false. 653 * 654 * @throws OperationFailureException if one of the <a 655 * href="../je/OperationFailureException.html#readFailures">Read Operation 656 * Failures</a> occurs. If the database does not exist and the {@link 657 * DatabaseConfig#setAllowCreate AllowCreate} parameter is true, then one 658 * of the <a 659 * href="../je/OperationFailureException.html#writeFailures">Write 660 * Operation Failures</a> may also occur. 661 * 662 * @throws EnvironmentFailureException if an unexpected, internal or 663 * environment-wide failure occurs. 664 * 665 * @throws IllegalStateException if this handle or the underlying 666 * environment has been closed. 667 * 668 * @throws IllegalArgumentException if an invalid parameter is specified, 669 * for example, an invalid {@code SecondaryConfig} property. 670 * 671 * @throws IllegalStateException if DatabaseConfig properties are changed 672 * and there are other open handles for this database. 673 */ 674 public synchronized openSecondaryDatabase(Transaction txn, String databaseName, Database primaryDatabase, SecondaryConfig dbConfig)675 SecondaryDatabase openSecondaryDatabase(Transaction txn, 676 String databaseName, 677 Database primaryDatabase, 678 SecondaryConfig dbConfig) 679 throws DatabaseNotFoundException, 680 DatabaseExistsException, 681 DatabaseException, 682 IllegalArgumentException, 683 IllegalStateException { 684 685 checkHandleIsValid(); 686 checkEnv(); 687 try { 688 envImpl.getSecondaryAssociationLock(). 689 writeLock().lockInterruptibly(); 690 } catch (InterruptedException e) { 691 throw new ThreadInterruptedException(envImpl, e); 692 } 693 try { 694 if (dbConfig == null) { 695 dbConfig = SecondaryConfig.DEFAULT; 696 } 697 final SecondaryDatabase db = 698 new SecondaryDatabase(this, dbConfig, primaryDatabase); 699 700 setupDatabase(txn, db, databaseName, dbConfig, 701 false /*isInternalDb*/); 702 return db; 703 } catch (Error E) { 704 envImpl.invalidate(E); 705 throw E; 706 } finally { 707 envImpl.getSecondaryAssociationLock().writeLock().unlock(); 708 } 709 } 710 711 /** 712 * The meat of open database processing. 713 * 714 * @param txn may be null 715 * @param newDb is the Database handle which houses this database 716 * 717 * @throws IllegalArgumentException via openDatabase and 718 * openSecondaryDatabase 719 * 720 * @see HandleLocker 721 */ setupDatabase(Transaction txn, Database newDb, String databaseName, DatabaseConfig dbConfig, boolean isInternalDb)722 private void setupDatabase(Transaction txn, 723 Database newDb, 724 String databaseName, 725 DatabaseConfig dbConfig, 726 boolean isInternalDb) 727 throws DatabaseNotFoundException, DatabaseExistsException { 728 729 checkEnv(); 730 DatabaseUtil.checkForNullParam(databaseName, "databaseName"); 731 732 LoggerUtils.envLogMsg(Level.FINEST, envImpl, 733 "Environment.open: " + " name=" + databaseName + 734 " dbConfig=" + dbConfig); 735 736 final boolean autoTxnIsReplicated = 737 dbConfig.getReplicated() && envImpl.isReplicated(); 738 739 /* 740 * Check that the open configuration is valid and doesn't conflict with 741 * the envImpl configuration. 742 */ 743 dbConfig.validateOnDbOpen(databaseName, autoTxnIsReplicated); 744 validateDbConfigAgainstEnv(dbConfig, databaseName, isInternalDb); 745 746 /* Perform eviction before each operation that allocates memory. */ 747 envImpl.criticalEviction(false /*backgroundIO*/); 748 749 DatabaseImpl database = null; 750 boolean operationOk = false; 751 HandleLocker handleLocker = null; 752 final Locker locker = LockerFactory.getWritableLocker 753 (this, txn, isInternalDb, dbConfig.getTransactional(), 754 autoTxnIsReplicated, null); 755 try { 756 757 /* 758 * Create the handle locker and lock the NameLN of an existing 759 * database. A read lock on the NameLN is acquired for both locker 760 * and handleLocker. Note: getDb may return a deleted database. 761 */ 762 handleLocker = newDb.initHandleLocker(envImpl, locker); 763 database = envImpl.getDbTree().getDb(locker, databaseName, 764 handleLocker); 765 766 boolean dbCreated = false; 767 final boolean databaseExists = 768 (database != null) && !database.isDeleted(); 769 770 if (databaseExists) { 771 if (dbConfig.getAllowCreate() && 772 dbConfig.getExclusiveCreate()) { 773 throw new DatabaseExistsException 774 ("Database " + databaseName + " already exists"); 775 } 776 777 newDb.initExisting(this, locker, database, databaseName, 778 dbConfig); 779 } else { 780 /* Release deleted DB. [#13415] */ 781 envImpl.getDbTree().releaseDb(database); 782 database = null; 783 784 if (!isInternalDb && 785 DbTree.isReservedDbName(databaseName)) { 786 throw new IllegalArgumentException 787 (databaseName + " is a reserved database name."); 788 } 789 790 if (!dbConfig.getAllowCreate()) { 791 throw new DatabaseNotFoundException("Database " + 792 databaseName + 793 " not found."); 794 } 795 796 /* 797 * Init a new DB. This calls DbTree.createDb and the new 798 * database is returned. A write lock on the NameLN is 799 * acquired by locker and a read lock by the handleLocker. 800 */ 801 database = newDb.initNew(this, locker, databaseName, dbConfig); 802 dbCreated = true; 803 } 804 805 /* 806 * The open is successful. We add the opened database handle to 807 * this environment to track open handles in general, and to the 808 * locker so that it can be invalidated by a user txn abort. 809 */ 810 operationOk = true; 811 addReferringHandle(newDb); 812 locker.addOpenedDatabase(newDb); 813 814 /* Run triggers before any subsequent auto commits. */ 815 final boolean firstWriteHandle = 816 newDb.isWritable() && 817 (newDb.getDatabaseImpl().noteWriteHandleOpen() == 1); 818 819 if (dbCreated || firstWriteHandle) { 820 TriggerManager.runOpenTriggers(locker, newDb, dbCreated); 821 } 822 } finally { 823 824 /* 825 * If the open fails, decrement the DB usage count, release 826 * handle locks and remove references from other objects. In other 827 * cases this is done by Database.close() or invalidate(), the 828 * latter in the case of a user txn abort. 829 */ 830 if (!operationOk) { 831 envImpl.getDbTree().releaseDb(database); 832 if (handleLocker != null) { 833 handleLocker.operationEnd(false); 834 } 835 newDb.removeReferringAssociations(); 836 } 837 838 /* 839 * Tell the locker that this operation is over. Some types of 840 * lockers (BasicLocker and auto Txn) will actually finish. 841 */ 842 locker.operationEnd(operationOk); 843 } 844 } 845 846 /** 847 * @throws IllegalArgumentException via openDatabase and 848 * openSecondaryDatabase 849 */ validateDbConfigAgainstEnv(DatabaseConfig dbConfig, String databaseName, boolean isInternalDb)850 private void validateDbConfigAgainstEnv(DatabaseConfig dbConfig, 851 String databaseName, 852 boolean isInternalDb) 853 throws IllegalArgumentException { 854 855 /* 856 * R/W database handles on a replicated database must be transactional, 857 * for now. In the future we may support non-transactional database 858 * handles. 859 */ 860 if (envImpl.isReplicated() && 861 dbConfig.getReplicated() && 862 !dbConfig.getReadOnly()) { 863 if (!dbConfig.getTransactional()) { 864 throw new IllegalArgumentException 865 ("Read/Write Database instances for replicated " + 866 "database " + databaseName + " must be transactional."); 867 } 868 } 869 870 /* Check operation's transactional status against the Environment */ 871 if (!isInternalDb && 872 dbConfig.getTransactional() && 873 !(envImpl.isTransactional())) { 874 throw new IllegalArgumentException 875 ("Attempted to open Database " + databaseName + 876 " transactionally, but parent Environment is" + 877 " not transactional"); 878 } 879 880 /* Check read/write status */ 881 if (envImpl.isReadOnly() && (!dbConfig.getReadOnly())) { 882 throw new IllegalArgumentException 883 ("Attempted to open Database " + databaseName + 884 " as writable but parent Environment is read only "); 885 } 886 } 887 888 /** 889 * Removes a database from the environment, discarding all records in the 890 * database and removing the database name itself. 891 * 892 * <p>Compared to deleting all the records in a database individually, 893 * {@code removeDatabase} is a very efficient operation. Some internal 894 * housekeeping information is updated, but the database records are not 895 * read or written, and very little I/O is needed.</p> 896 * 897 * <p>When called on a database configured with secondary indices, the 898 * application is responsible for also removing all associated secondary 899 * indices. To guarantee integrity, a primary database and all of its 900 * secondary databases should be removed atomically using a single 901 * transaction.</p> 902 * 903 * <p>Applications should not remove a database with open {@link Database 904 * Database} handles. If the database is open with the same transaction as 905 * passed in the {@code txn} parameter, {@link IllegalStateException} is 906 * thrown by this method. If the database is open using a different 907 * transaction, this method will block until all database handles are 908 * closed, or until the conflict is resolved by throwing {@link 909 * LockConflictException}.</p> 910 * 911 * @param txn For a transactional environment, an explicit transaction 912 * may be specified or null may be specified to use auto-commit. For a 913 * non-transactional environment, null must be specified. 914 * 915 * @param databaseName The database to be removed. 916 * 917 * @throws DatabaseNotFoundException if the database does not exist. 918 * 919 * @throws OperationFailureException if one of the <a 920 * href="../je/OperationFailureException.html#writeFailures">Write 921 * Operation Failures</a> occurs. 922 * 923 * @throws EnvironmentFailureException if an unexpected, internal or 924 * environment-wide failure occurs. 925 * 926 * @throws UnsupportedOperationException if this is a read-only 927 * environment. 928 * 929 * @throws IllegalStateException if the database is currently open using 930 * the transaction passed in the {@code txn} parameter, or if this handle 931 * or the underlying environment has been closed. 932 * 933 * @throws IllegalArgumentException if an invalid parameter is specified. 934 */ removeDatabase(final Transaction txn, final String databaseName)935 public void removeDatabase(final Transaction txn, 936 final String databaseName) 937 throws DatabaseNotFoundException { 938 939 DatabaseUtil.checkForNullParam(databaseName, "databaseName"); 940 941 new DbNameOperation<Void>(txn, databaseName) { 942 943 Pair<DatabaseImpl, Void> runWork(final Locker locker) 944 throws DatabaseNotFoundException, 945 DbTree.NeedRepLockerException { 946 947 final DatabaseImpl dbImpl = 948 dbTree.dbRemove(locker, databaseName, null /*checkId*/); 949 950 return new Pair<>(dbImpl, null); 951 } 952 953 void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { 954 TriggerManager.runRemoveTriggers(locker, dbImpl); 955 } 956 }.run(); 957 } 958 959 /** 960 * Renames a database, without removing the records it contains. 961 * 962 * <p>Applications should not rename a database with open {@link Database 963 * Database} handles. If the database is open with the same transaction as 964 * passed in the {@code txn} parameter, {@link IllegalStateException} is 965 * thrown by this method. If the database is open using a different 966 * transaction, this method will block until all database handles are 967 * closed, or until the conflict is resolved by throwing {@link 968 * LockConflictException}.</p> 969 * 970 * @param txn For a transactional environment, an explicit transaction 971 * may be specified or null may be specified to use auto-commit. For a 972 * non-transactional environment, null must be specified. 973 * 974 * @param databaseName The new name of the database. 975 * 976 * @throws DatabaseNotFoundException if the database does not exist. 977 * 978 * @throws OperationFailureException if one of the <a 979 * href="../je/OperationFailureException.html#writeFailures">Write 980 * Operation Failures</a> occurs. 981 * 982 * @throws EnvironmentFailureException if an unexpected, internal or 983 * environment-wide failure occurs. 984 * 985 * @throws UnsupportedOperationException if this is a read-only 986 * environment. 987 * 988 * @throws IllegalStateException if the database is currently open using 989 * the transaction passed in the {@code txn} parameter, or if this handle 990 * or the underlying environment has been closed. 991 * 992 * @throws IllegalArgumentException if an invalid parameter is specified. 993 */ renameDatabase(final Transaction txn, final String databaseName, final String newName)994 public void renameDatabase(final Transaction txn, 995 final String databaseName, 996 final String newName) 997 throws DatabaseNotFoundException { 998 999 DatabaseUtil.checkForNullParam(databaseName, "databaseName"); 1000 DatabaseUtil.checkForNullParam(newName, "newName"); 1001 1002 new DbNameOperation<Void>(txn, databaseName) { 1003 1004 Pair<DatabaseImpl, Void> runWork(final Locker locker) 1005 throws DatabaseNotFoundException, 1006 DbTree.NeedRepLockerException { 1007 1008 final DatabaseImpl dbImpl = 1009 dbTree.dbRename(locker, databaseName, newName); 1010 1011 return new Pair<>(dbImpl, null); 1012 } 1013 1014 void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { 1015 TriggerManager.runRenameTriggers(locker, dbImpl, newName); 1016 } 1017 }.run(); 1018 } 1019 1020 /** 1021 * Empties the database, discarding all the records it contains, without 1022 * removing the database name. 1023 * 1024 * <p>Compared to deleting all the records in a database individually, 1025 * {@code truncateDatabase} is a very efficient operation. Some internal 1026 * housekeeping information is updated, but the database records are not 1027 * read or written, and very little I/O is needed.</p> 1028 * 1029 * <p>When called on a database configured with secondary indices, the 1030 * application is responsible for also truncating all associated secondary 1031 * indices. To guarantee integrity, a primary database and all of its 1032 * secondary databases should be truncated atomically using a single 1033 * transaction.</p> 1034 * 1035 * <p>Applications should not truncate a database with open {@link Database 1036 * Database} handles. If the database is open with the same transaction as 1037 * passed in the {@code txn} parameter, {@link IllegalStateException} is 1038 * thrown by this method. If the database is open using a different 1039 * transaction, this method will block until all database handles are 1040 * closed, or until the conflict is resolved by throwing {@link 1041 * LockConflictException}.</p> 1042 * 1043 * @param txn For a transactional environment, an explicit transaction may 1044 * be specified or null may be specified to use auto-commit. For a 1045 * non-transactional environment, null must be specified. 1046 * 1047 * @param databaseName The database to be truncated. 1048 * 1049 * @param returnCount If true, count and return the number of records 1050 * discarded. 1051 * 1052 * @return The number of records discarded, or -1 if returnCount is false. 1053 * 1054 * @throws DatabaseNotFoundException if the database does not exist. 1055 * 1056 * @throws OperationFailureException if one of the <a 1057 * href="../je/OperationFailureException.html#writeFailures">Write 1058 * Operation Failures</a> occurs. 1059 * 1060 * @throws EnvironmentFailureException if an unexpected, internal or 1061 * environment-wide failure occurs. 1062 * 1063 * @throws UnsupportedOperationException if this is a read-only 1064 * environment. 1065 * 1066 * @throws IllegalStateException if the database is currently open using 1067 * the transaction passed in the {@code txn} parameter, or if this handle 1068 * or the underlying environment has been closed. 1069 * 1070 * @throws IllegalArgumentException if an invalid parameter is specified. 1071 */ truncateDatabase(final Transaction txn, final String databaseName, final boolean returnCount)1072 public long truncateDatabase(final Transaction txn, 1073 final String databaseName, 1074 final boolean returnCount) 1075 throws DatabaseNotFoundException { 1076 1077 DatabaseUtil.checkForNullParam(databaseName, "databaseName"); 1078 1079 return (new DbNameOperation<Long>(txn, databaseName) { 1080 1081 Pair<DatabaseImpl, Long> runWork(final Locker locker) 1082 throws DatabaseNotFoundException, 1083 DbTree.NeedRepLockerException { 1084 1085 final TruncateDbResult result = 1086 dbTree.truncate(locker, databaseName, returnCount); 1087 1088 return new Pair<>(result.newDb, result.recordCount); 1089 } 1090 1091 void runTriggers(final Locker locker, final DatabaseImpl dbImpl) { 1092 TriggerManager.runTruncateTriggers(locker, dbImpl); 1093 } 1094 }).run(); 1095 } 1096 1097 /** 1098 * Runs a DB naming operation: remove, truncate or rename. The common code 1099 * is factored out here. In particular this class handles non-replicated 1100 * DBs in a replicated environment, when auto-commit is used. 1101 * <p> 1102 * For a non-replicated DB, an auto-commit txn must be created by calling 1103 * LockerFactory.getWritableLocker with the autoTxnIsReplicated param set 1104 * to false. If autoTxnIsReplicated is set to true in a replicated 1105 * environment, HA consistency checks will be made when the txn is begun 1106 * and acks will be enforced at commit. For example, for an HA node in an 1107 * unknown state, the consistency checks would fail and prevent performing 1108 * the operation on the local/non-replicated DB. 1109 * <p> 1110 * Unfortunately, we need to create a txn/locker in order to query the DB 1111 * metadata, to determine whether it is replicated. Therefore, we always 1112 * attempt the operation initially with autoTxnIsReplicated set to false. 1113 * The DbTree name operation methods (see DbTree.lockNameLN) will throw an 1114 * internal exception (NeedRepLockerException) if a non-replicated 1115 * auto-commit txn is used on a replicated DB. That signals this class to 1116 * retry the operation with autoTxnIsReplicated set to true. 1117 * <p> 1118 * Via an unlikely series of DB renaming it is possible that on the 2nd try 1119 * with a replicated txn, we find that the DB is non-replicated. However, 1120 * there is little harm in proceeding, since the consistency check is 1121 * already done. 1122 */ 1123 private abstract class DbNameOperation<R> { 1124 1125 private final Transaction txn; 1126 private final String databaseName; 1127 final DbTree dbTree; 1128 1129 DbNameOperation(final Transaction txn, final String databaseName) { 1130 this.txn = txn; 1131 this.databaseName = databaseName; 1132 1133 checkHandleIsValid(); 1134 checkEnv(); 1135 checkWritable(); 1136 1137 dbTree = envImpl.getDbTree(); 1138 } 1139 1140 /** Run the DB name operation. */ 1141 abstract Pair<DatabaseImpl, R> runWork(final Locker locker) 1142 throws DatabaseNotFoundException, DbTree.NeedRepLockerException; 1143 1144 /** Run triggers after a successful DB name operation. */ 1145 abstract void runTriggers(final Locker locker, 1146 final DatabaseImpl dbImpl); 1147 1148 /** 1149 * Try the operation with autoTxnIsReplicated=false, and then again 1150 * with autoTxnIsReplicated=true if NeedRepLockerException is thrown. 1151 */ 1152 R run() throws DatabaseNotFoundException { 1153 try { 1154 return runOnce(getWritableLocker(false)); 1155 } catch (DbTree.NeedRepLockerException e) { 1156 try { 1157 return runOnce(getWritableLocker(true)); 1158 } catch (DbTree.NeedRepLockerException e2) { 1159 /* Should never happen. */ 1160 throw EnvironmentFailureException.unexpectedException( 1161 envImpl, e); 1162 } 1163 } 1164 } 1165 1166 private R runOnce(final Locker locker) 1167 throws DatabaseNotFoundException, DbTree.NeedRepLockerException { 1168 1169 boolean success = false; 1170 try { 1171 final Pair<DatabaseImpl, R> results = runWork(locker); 1172 final DatabaseImpl dbImpl = results.first(); 1173 if (dbImpl == null) { 1174 /* Should never happen. */ 1175 throw EnvironmentFailureException.unexpectedState(envImpl); 1176 } 1177 success = true; 1178 runTriggers(locker, dbImpl); 1179 return results.second(); 1180 } catch (Error E) { 1181 envImpl.invalidate(E); 1182 throw E; 1183 } finally { 1184 locker.operationEnd(success); 1185 } 1186 } 1187 1188 private Locker getWritableLocker(boolean autoTxnIsReplicated) { 1189 return LockerFactory.getWritableLocker( 1190 Environment.this, txn, false /*isInternalDb*/, 1191 envImpl.isTransactional(), autoTxnIsReplicated); 1192 } 1193 } 1194 1195 /** 1196 * For unit testing. Returns the current memory usage in bytes for all 1197 * btrees in the envImpl. 1198 */ 1199 long getMemoryUsage() 1200 throws DatabaseException { 1201 1202 checkHandleIsValid(); 1203 checkEnv(); 1204 1205 return envImpl.getMemoryBudget().getCacheMemoryUsage(); 1206 } 1207 1208 /** 1209 * Returns the database environment's home directory. 1210 * 1211 * @return The database environment's home directory. 1212 * 1213 * @throws EnvironmentFailureException if an unexpected, internal or 1214 * environment-wide failure occurs. 1215 * 1216 * @throws IllegalStateException if this handle or the underlying 1217 * environment has been closed. 1218 */ 1219 public File getHome() 1220 throws DatabaseException { 1221 1222 checkHandleIsValid(); 1223 1224 return envImpl.getEnvironmentHome(); 1225 } 1226 1227 /* 1228 * Transaction management 1229 */ 1230 1231 /** 1232 * Returns the default txn config for this environment handle. 1233 */ 1234 TransactionConfig getDefaultTxnConfig() { 1235 return defaultTxnConfig; 1236 } 1237 1238 /** 1239 * Copies the handle properties out of the config properties, and 1240 * initializes the default transaction config. 1241 */ 1242 private void copyToHandleConfig(EnvironmentMutableConfig useConfig, 1243 EnvironmentConfig initStaticConfig, 1244 RepConfigProxy initRepConfig) { 1245 1246 /* 1247 * Create the new objects, initialize them, then change the instance 1248 * fields. This avoids synchronization issues. 1249 */ 1250 EnvironmentMutableConfig newHandleConfig = 1251 new EnvironmentMutableConfig(); 1252 useConfig.copyHandlePropsTo(newHandleConfig); 1253 this.handleConfig = newHandleConfig; 1254 1255 TransactionConfig newTxnConfig = 1256 TransactionConfig.DEFAULT.clone(); 1257 newTxnConfig.setNoSync(handleConfig.getTxnNoSync()); 1258 newTxnConfig.setWriteNoSync(handleConfig.getTxnWriteNoSync()); 1259 newTxnConfig.setDurability(handleConfig.getDurability()); 1260 1261 if (initStaticConfig != null) { 1262 newTxnConfig.setSerializableIsolation 1263 (initStaticConfig.getTxnSerializableIsolation()); 1264 newTxnConfig.setReadCommitted 1265 (initStaticConfig.getTxnReadCommitted()); 1266 } else { 1267 newTxnConfig.setSerializableIsolation 1268 (defaultTxnConfig.getSerializableIsolation()); 1269 newTxnConfig.setReadCommitted 1270 (defaultTxnConfig.getReadCommitted()); 1271 newTxnConfig.setConsistencyPolicy 1272 (defaultTxnConfig.getConsistencyPolicy()); 1273 } 1274 if (initRepConfig != null) { 1275 newTxnConfig.setConsistencyPolicy 1276 (initRepConfig.getConsistencyPolicy()); 1277 } 1278 this.defaultTxnConfig = newTxnConfig; 1279 } 1280 1281 /** 1282 * Creates a new transaction in the database environment. 1283 * 1284 * <p>Transaction handles are free-threaded; transactions handles may be 1285 * used concurrently by multiple threads.</p> 1286 * 1287 * <p>Cursors may not span transactions; that is, each cursor must be 1288 * opened and closed within a single transaction. The parent parameter is a 1289 * placeholder for nested transactions, and must currently be null.</p> 1290 * 1291 * @param txnConfig The transaction attributes. If null, default 1292 * attributes are used. 1293 * 1294 * @return The newly created transaction's handle. 1295 * 1296 * @throws com.sleepycat.je.rep.InsufficientReplicasException if the Master 1297 * in a replicated environment could not contact a quorum of replicas as 1298 * determined by the {@link ReplicaAckPolicy}. 1299 * 1300 * @throws com.sleepycat.je.rep.ReplicaConsistencyException if a replica 1301 * in a replicated environment cannot become consistent within the timeout 1302 * period. 1303 * 1304 * @throws EnvironmentFailureException if an unexpected, internal or 1305 * environment-wide failure occurs. 1306 * 1307 * @throws UnsupportedOperationException if this is not a transactional 1308 * environment. 1309 * 1310 * @throws IllegalStateException if this handle or the underlying 1311 * environment has been closed. 1312 * 1313 * @throws IllegalArgumentException if an invalid parameter is specified, 1314 * for example, an invalid {@code TransactionConfig} parameter. 1315 */ 1316 public Transaction beginTransaction(Transaction parent, 1317 TransactionConfig txnConfig) 1318 throws DatabaseException, 1319 IllegalArgumentException { 1320 1321 try { 1322 return beginTransactionInternal(parent, txnConfig, 1323 false /*isInternalTxn*/); 1324 } catch (Error E) { 1325 if (envImpl != null) { 1326 envImpl.invalidate(E); 1327 } 1328 throw E; 1329 } 1330 } 1331 1332 /** 1333 * Like beginTransaction, but does not require that the Environment is 1334 * transactional. 1335 */ 1336 Transaction beginInternalTransaction(TransactionConfig txnConfig) { 1337 return beginTransactionInternal(null /*parent*/, txnConfig, 1338 true /*isInternalTxn*/); 1339 } 1340 1341 /** 1342 * @throws IllegalArgumentException via beginTransaction. 1343 * @throws UnsupportedOperationException via beginTransaction. 1344 */ 1345 private Transaction beginTransactionInternal(Transaction parent, 1346 TransactionConfig txnConfig, 1347 boolean isInternalTxn ) 1348 throws DatabaseException { 1349 1350 checkHandleIsValid(); 1351 checkEnv(); 1352 1353 if (parent != null) { 1354 throw new IllegalArgumentException 1355 ("Parent txn is non-null. " + 1356 "Nested transactions are not supported."); 1357 } 1358 1359 if (!isInternalTxn && !envImpl.isTransactional()) { 1360 throw new UnsupportedOperationException 1361 ("Transactions can not be used in a non-transactional " + 1362 "environment"); 1363 } 1364 1365 checkTxnConfig(txnConfig); 1366 1367 /* 1368 * Apply txn config defaults. We don't need to clone unless we have to 1369 * apply the env default, since we don't hold onto a txn config 1370 * reference. 1371 */ 1372 TransactionConfig useConfig = null; 1373 if (txnConfig == null) { 1374 useConfig = defaultTxnConfig; 1375 } else { 1376 if (defaultTxnConfig.getNoSync() || 1377 defaultTxnConfig.getWriteNoSync()) { 1378 1379 /* 1380 * The environment sync settings have been set, check if any 1381 * were set in the user's txn config. If none were set in the 1382 * user's config, apply the environment defaults 1383 */ 1384 if (!txnConfig.getNoSync() && 1385 !txnConfig.getSync() && 1386 !txnConfig.getWriteNoSync()) { 1387 useConfig = txnConfig.clone(); 1388 if (defaultTxnConfig.getWriteNoSync()) { 1389 useConfig.setWriteNoSync(true); 1390 } else { 1391 useConfig.setNoSync(true); 1392 } 1393 } 1394 } 1395 1396 if ((defaultTxnConfig.getDurability() != null) && 1397 (txnConfig.getDurability() == null)) { 1398 1399 /* 1400 * Inherit transaction durability from the environment in the 1401 * absence of an explicit transaction config durability. 1402 */ 1403 if (useConfig == null) { 1404 useConfig = txnConfig.clone(); 1405 } 1406 useConfig.setDurability(defaultTxnConfig.getDurability()); 1407 } 1408 1409 if ((defaultTxnConfig.getConsistencyPolicy() != null) && 1410 (txnConfig.getConsistencyPolicy() == null)) { 1411 if (useConfig == null) { 1412 useConfig = txnConfig.clone(); 1413 } 1414 useConfig.setConsistencyPolicy 1415 (defaultTxnConfig.getConsistencyPolicy()); 1416 } 1417 1418 /* Apply isolation level default. */ 1419 if (!txnConfig.getSerializableIsolation() && 1420 !txnConfig.getReadCommitted() && 1421 !txnConfig.getReadUncommitted()) { 1422 if (defaultTxnConfig.getSerializableIsolation()) { 1423 if (useConfig == null) { 1424 useConfig = txnConfig.clone(); 1425 } 1426 useConfig.setSerializableIsolation(true); 1427 } else if (defaultTxnConfig.getReadCommitted()) { 1428 if (useConfig == null) { 1429 useConfig = txnConfig.clone(); 1430 } 1431 useConfig.setReadCommitted(true); 1432 } 1433 } 1434 1435 /* No environment level defaults applied. */ 1436 if (useConfig == null) { 1437 useConfig = txnConfig; 1438 } 1439 } 1440 Txn internalTxn = envImpl.txnBegin(parent, useConfig); 1441 Transaction txn = new Transaction(this, internalTxn); 1442 addReferringHandle(txn); 1443 return txn; 1444 } 1445 1446 /** 1447 * Checks the txnConfig object to ensure that its correctly configured and 1448 * is compatible with the configuration of the Environment. 1449 * 1450 * @param txnConfig the configuration being checked. 1451 * 1452 * @throws IllegalArgumentException via beginTransaction 1453 */ 1454 private void checkTxnConfig(TransactionConfig txnConfig) 1455 throws IllegalArgumentException { 1456 1457 if (txnConfig == null) { 1458 return; 1459 } 1460 if ((txnConfig.getSerializableIsolation() && 1461 txnConfig.getReadUncommitted()) || 1462 (txnConfig.getSerializableIsolation() && 1463 txnConfig.getReadCommitted()) || 1464 (txnConfig.getReadUncommitted() && 1465 txnConfig.getReadCommitted())) { 1466 throw new IllegalArgumentException 1467 ("Only one may be specified: SerializableIsolation, " + 1468 "ReadCommitted or ReadUncommitted"); 1469 } 1470 if ((txnConfig.getDurability() != null) && 1471 ((defaultTxnConfig.getSync() || 1472 defaultTxnConfig.getNoSync() || 1473 defaultTxnConfig.getWriteNoSync()))) { 1474 throw new IllegalArgumentException 1475 ("Mixed use of deprecated durability API for the " + 1476 "Environment with the new durability API for " + 1477 "TransactionConfig.setDurability()"); 1478 } 1479 if ((defaultTxnConfig.getDurability() != null) && 1480 ((txnConfig.getSync() || 1481 txnConfig.getNoSync() || 1482 txnConfig.getWriteNoSync()))) { 1483 throw new IllegalArgumentException 1484 ("Mixed use of new durability API for the " + 1485 "Environment with the deprecated durability API for " + 1486 "TransactionConfig."); 1487 } 1488 } 1489 1490 /** 1491 * Synchronously checkpoint the database environment. 1492 * <p> 1493 * This is an optional action for the application since this activity 1494 * is, by default, handled by a database environment owned background 1495 * thread. 1496 * <p> 1497 * A checkpoint has the side effect of flushing all preceding 1498 * non-transactional write operations, as well as any preceding 1499 * transactions that were committed with {@link 1500 * Durability.SyncPolicy#NO_SYNC no-sync durability}. However, for best 1501 * performance, checkpoints should be used only to bound recovery time. 1502 * {@link #flushLog} can be used to write buffered data for durability 1503 * purposes. 1504 * 1505 * @param ckptConfig The checkpoint attributes. If null, default 1506 * attributes are used. 1507 * 1508 * @throws EnvironmentFailureException if an unexpected, internal or 1509 * environment-wide failure occurs. 1510 * 1511 * @throws IllegalStateException if this handle or the underlying 1512 * environment has been closed. 1513 */ 1514 public void checkpoint(CheckpointConfig ckptConfig) 1515 throws DatabaseException { 1516 1517 try { 1518 checkHandleIsValid(); 1519 checkEnv(); 1520 CheckpointConfig useConfig = 1521 (ckptConfig == null) ? CheckpointConfig.DEFAULT : ckptConfig; 1522 envImpl.invokeCheckpoint(useConfig, "api"); 1523 } catch (Error E) { 1524 if (envImpl != null) { 1525 envImpl.invalidate(E); 1526 } 1527 throw E; 1528 } 1529 } 1530 1531 /** 1532 * Synchronously flushes database environment databases to stable storage. 1533 * Calling this method is equivalent to forcing a checkpoint and setting 1534 * {@link CheckpointConfig#setMinimizeRecoveryTime} to true. 1535 * <p> 1536 * A checkpoint has the side effect of flushing all preceding 1537 * non-transactional write operations, as well as any preceding 1538 * transactions that were committed with {@link 1539 * Durability.SyncPolicy#NO_SYNC no-sync durability}. However, for best 1540 * performance, checkpoints should be used only to bound recovery time. 1541 * {@link #flushLog} can be used to write buffered data for durability 1542 * purposes. 1543 * 1544 * @throws EnvironmentFailureException if an unexpected, internal or 1545 * environment-wide failure occurs. 1546 * 1547 * @throws IllegalStateException if this handle or the underlying 1548 * environment has been closed. 1549 */ 1550 public void sync() 1551 throws DatabaseException { 1552 1553 try { 1554 checkHandleIsValid(); 1555 checkEnv(); 1556 CheckpointConfig config = new CheckpointConfig(); 1557 config.setForce(true); 1558 config.setMinimizeRecoveryTime(true); 1559 envImpl.invokeCheckpoint(config, "sync"); 1560 } catch (Error E) { 1561 if (envImpl != null) { 1562 envImpl.invalidate(E); 1563 } 1564 throw E; 1565 } 1566 } 1567 1568 /** 1569 * Writes buffered data to the log, and optionally performs an fsync to 1570 * guarantee that data is written to the physical device. 1571 * <p> 1572 * This method is used to make durable, by writing to the log, all 1573 * preceding non-transactional write operations, as well as any preceding 1574 * transactions that were committed with {@link 1575 * Durability.SyncPolicy#NO_SYNC no-sync durability}. If the {@code fsync} 1576 * parameter is true, it can also be used to flush all logged data to the 1577 * physical storage device, by performing an fsync. 1578 * <p> 1579 * Note that this method <em>does not</em> flush previously unwritten data 1580 * in deferred-write databases; that is done by calling {@link 1581 * Database#sync} or performing a checkpoint. 1582 * 1583 * @param fsync is true to perform an fsync as well as a file write, or 1584 * false to perform only a file write. 1585 * 1586 * @throws EnvironmentFailureException if an unexpected, internal or 1587 * environment-wide failure occurs. 1588 * 1589 * @throws IllegalStateException if this handle or the underlying 1590 * environment has been closed. 1591 */ 1592 public void flushLog(boolean fsync) { 1593 try { 1594 checkHandleIsValid(); 1595 checkEnv(); 1596 envImpl.flushLog(fsync); 1597 } catch (Error E) { 1598 if (envImpl != null) { 1599 envImpl.invalidate(E); 1600 } 1601 throw E; 1602 } 1603 } 1604 1605 /** 1606 * Synchronously invokes database environment log cleaning. This method is 1607 * called periodically by the cleaner daemon thread. 1608 * 1609 * <p>Zero or more log files will be cleaned as necessary to bring the disk 1610 * space utilization of the environment above the configured minimum 1611 * utilization threshold. The threshold is determined by the {@link 1612 * EnvironmentConfig#CLEANER_MIN_UTILIZATION} configuration setting.</p> 1613 * 1614 * <p>Note that <code>cleanLog</code> does not perform the complete task of 1615 * cleaning a log file. Eviction and checkpointing migrate records that 1616 * are marked by the cleaner, and a full checkpoint is necessary following 1617 * cleaning before cleaned files will be deleted (or renamed). Checkpoints 1618 * normally occur periodically and when the environment is closed.</p> 1619 * 1620 * <p>This is an optional action for the application since this activity 1621 * is, by default, handled by one or more database environment owned 1622 * background threads.</p> 1623 * 1624 * <p>There are two intended use cases for the <code>cleanLog</code> 1625 * method. The first case is where the application wishes to disable the 1626 * built-in cleaner threads using the {@link 1627 * EnvironmentConfig#ENV_RUN_CLEANER} property. To replace the 1628 * functionality of the cleaner threads, the application should call 1629 * <code>cleanLog</code> periodically.</p> 1630 * 1631 * <p>In the second use case, "batch cleaning", the application disables 1632 * the cleaner threads for maximum performance during active periods, and 1633 * calls <code>cleanLog</code> during periods when the application is 1634 * quiescent or less active than usual. If the cleaner has a large number 1635 * of files to clean, <code>cleanLog</code> may stop without reaching the 1636 * target utilization; to ensure that the target utilization is reached, 1637 * <code>cleanLog</code> should be called in a loop until it returns 1638 * zero. And to complete the work of cleaning, a checkpoint is necessary. 1639 * An example of performing batch cleaning follows.</p> 1640 * 1641 * <pre> 1642 * Environment env; 1643 * boolean anyCleaned = false; 1644 * while (env.cleanLog() > 0) { 1645 * anyCleaned = true; 1646 * } 1647 * if (anyCleaned) { 1648 * CheckpointConfig force = new CheckpointConfig(); 1649 * force.setForce(true); 1650 * env.checkpoint(force); 1651 * } 1652 * </pre> 1653 * 1654 * <p><em>WARNING:</em>If batch cleaning (shown above) is performed 1655 * immediately before closing the environment, then the built-in cleaner 1656 * threads should normally be disabled using {@link 1657 * EnvironmentConfig#ENV_RUN_CLEANER} during the batch cleaning process. 1658 * If the built-in cleaner threads are actively working on one or more log 1659 * files, then those files will not be processed by the {@code cleanLog} 1660 * method. Closing the environment will abort the work being done by the 1661 * built-in cleaner threads, and log cleaning may be incomplete.</p> 1662 * 1663 * @return The number of log files that were cleaned, and that will be 1664 * deleted (or renamed) when a qualifying checkpoint occurs. 1665 * 1666 * @throws EnvironmentFailureException if an unexpected, internal or 1667 * environment-wide failure occurs. 1668 * 1669 * @throws UnsupportedOperationException if this is a read-only or 1670 * memory-only environment. 1671 * 1672 * @throws IllegalStateException if this handle or the underlying 1673 * environment has been closed. 1674 */ 1675 public int cleanLog() 1676 throws DatabaseException { 1677 1678 try { 1679 checkHandleIsValid(); 1680 checkEnv(); 1681 return envImpl.invokeCleaner(); 1682 } catch (Error E) { 1683 if (envImpl != null) { 1684 envImpl.invalidate(E); 1685 } 1686 throw E; 1687 } 1688 } 1689 1690 /** 1691 * Synchronously invokes the mechanism for keeping memory usage within the 1692 * cache size boundaries. 1693 * 1694 * <p>This is an optional action for the application since this activity 1695 * is, by default, handled by a database environment owned background 1696 * thread.</p> 1697 * 1698 * @throws EnvironmentFailureException if an unexpected, internal or 1699 * environment-wide failure occurs. 1700 * 1701 * @throws IllegalStateException if this handle or the underlying 1702 * environment has been closed. 1703 */ 1704 public void evictMemory() 1705 throws DatabaseException { 1706 1707 try { 1708 checkHandleIsValid(); 1709 checkEnv(); 1710 envImpl.invokeEvictor(); 1711 } catch (Error E) { 1712 if (envImpl != null) { 1713 envImpl.invalidate(E); 1714 } 1715 throw E; 1716 } 1717 } 1718 1719 /** 1720 * Synchronously invokes the compressor mechanism which compacts in memory 1721 * data structures after delete operations. 1722 * 1723 * <p>This is an optional action for the application since this activity 1724 * is, by default, handled by a database environment owned background 1725 * thread.</p> 1726 * 1727 * @throws EnvironmentFailureException if an unexpected, internal or 1728 * environment-wide failure occurs. 1729 * 1730 * @throws IllegalStateException if this handle or the underlying 1731 * environment has been closed. 1732 */ 1733 public void compress() 1734 throws DatabaseException { 1735 1736 try { 1737 checkHandleIsValid(); 1738 checkEnv(); 1739 envImpl.invokeCompressor(); 1740 } catch (Error E) { 1741 if (envImpl != null) { 1742 envImpl.invalidate(E); 1743 } 1744 throw E; 1745 } 1746 } 1747 1748 /** 1749 * Preloads the cache with multiple databases. This method should only be 1750 * called when there are no operations being performed on the specified 1751 * databases in other threads. Executing preload during concurrent updates 1752 * of the specified databases may result in some or all of the tree being 1753 * loaded into the JE cache. Executing preload during any other types of 1754 * operations may result in JE exceeding its allocated cache 1755 * size. preload() effectively locks all of the specified database and 1756 * therefore will lock out the checkpointer, cleaner, and compressor, as 1757 * well as not allow eviction to occur. If databases are replicated and 1758 * the environment is in the replica state, then the replica may become 1759 * temporarily disconnected from the master if the replica needs to replay 1760 * changes against the database and is locked out because the time taken by 1761 * the preload operation exceeds {@link 1762 * com.sleepycat.je.rep.ReplicationConfig#FEEDER_TIMEOUT}. 1763 * 1764 * @param config The PreloadConfig object that specifies the parameters 1765 * of the preload. 1766 * 1767 * @return A PreloadStats object with the result of the preload operation 1768 * and various statistics about the preload() operation. 1769 * 1770 * @throws OperationFailureException if one of the <a 1771 * href="OperationFailureException.html#readFailures">Read Operation 1772 * Failures</a> occurs. 1773 * 1774 * @throws EnvironmentFailureException if an unexpected, internal or 1775 * environment-wide failure occurs. 1776 * 1777 * @throws IllegalStateException if any of the databases has been closed. 1778 * 1779 * @see Database#preload(PreloadConfig) 1780 */ 1781 public PreloadStats preload(final Database[] databases, 1782 final PreloadConfig config) 1783 throws DatabaseException { 1784 1785 try { 1786 checkHandleIsValid(); 1787 checkEnv(); 1788 DatabaseUtil.checkForZeroLengthArrayParam(databases, "databases"); 1789 PreloadConfig useConfig = 1790 (config == null) ? new PreloadConfig() : config; 1791 int nDbs = databases.length; 1792 DatabaseImpl[] dbImpls = new DatabaseImpl[nDbs]; 1793 for (int i = 0; i < nDbs; i += 1) { 1794 dbImpls[i] = DbInternal.getDatabaseImpl(databases[i]); 1795 } 1796 return envImpl.preload(dbImpls, useConfig); 1797 } catch (Error E) { 1798 if (envImpl != null) { 1799 envImpl.invalidate(E); 1800 } 1801 throw E; 1802 } 1803 } 1804 1805 /** 1806 * Returns this object's configuration. 1807 * 1808 * @return This object's configuration. 1809 * 1810 * @throws EnvironmentFailureException if an unexpected, internal or 1811 * environment-wide failure occurs. 1812 * 1813 * @throws IllegalStateException if this handle has been closed. 1814 */ 1815 public EnvironmentConfig getConfig() 1816 throws DatabaseException { 1817 1818 try { 1819 checkHandleIsValid(); 1820 EnvironmentConfig config = envImpl.cloneConfig(); 1821 handleConfig.copyHandlePropsTo(config); 1822 config.fillInEnvironmentGeneratedProps(envImpl); 1823 return config; 1824 } catch (Error E) { 1825 if (envImpl != null) { 1826 envImpl.invalidate(E); 1827 } 1828 throw E; 1829 } 1830 } 1831 1832 /** 1833 * Sets database environment attributes. 1834 * 1835 * <p>Attributes only apply to a specific Environment object and are not 1836 * necessarily shared by other Environment objects accessing this 1837 * database environment.</p> 1838 * 1839 * @param mutableConfig The database environment attributes. If null, 1840 * default attributes are used. 1841 * 1842 * @throws EnvironmentFailureException if an unexpected, internal or 1843 * environment-wide failure occurs. 1844 * 1845 * @throws IllegalStateException if this handle has been closed. 1846 */ 1847 public synchronized 1848 void setMutableConfig(EnvironmentMutableConfig mutableConfig) 1849 throws DatabaseException { 1850 1851 /* 1852 * This method is synchronized so that we atomically call both 1853 * EnvironmentImpl.setMutableConfig and copyToHandleConfig. This 1854 * ensures that the handle and the EnvironmentImpl properties match. 1855 */ 1856 try { 1857 checkHandleIsValid(); 1858 DatabaseUtil.checkForNullParam(mutableConfig, "mutableConfig"); 1859 1860 /* 1861 * Change the mutable properties specified in the given 1862 * configuration. 1863 */ 1864 envImpl.setMutableConfig(mutableConfig); 1865 1866 /* Reset the handle config properties. */ 1867 copyToHandleConfig(mutableConfig, null, null); 1868 } catch (Error E) { 1869 if (envImpl != null) { 1870 envImpl.invalidate(E); 1871 } 1872 throw E; 1873 } 1874 } 1875 1876 /** 1877 * Returns database environment attributes. 1878 * 1879 * @return Environment attributes. 1880 * 1881 * @throws EnvironmentFailureException if an unexpected, internal or 1882 * environment-wide failure occurs. 1883 * 1884 * @throws IllegalStateException if this handle has been closed. 1885 */ 1886 public EnvironmentMutableConfig getMutableConfig() 1887 throws DatabaseException { 1888 1889 try { 1890 checkHandleIsValid(); 1891 EnvironmentMutableConfig config = 1892 envImpl.cloneMutableConfig(); 1893 handleConfig.copyHandlePropsTo(config); 1894 config.fillInEnvironmentGeneratedProps(envImpl); 1895 return config; 1896 } catch (Error E) { 1897 if (envImpl != null) { 1898 envImpl.invalidate(E); 1899 } 1900 throw E; 1901 } 1902 } 1903 1904 /** 1905 * Returns the general database environment statistics. 1906 * 1907 * @param config The general statistics attributes. If null, default 1908 * attributes are used. 1909 * 1910 * @return The general database environment statistics. 1911 * 1912 * @throws EnvironmentFailureException if an unexpected, internal or 1913 * environment-wide failure occurs. 1914 * 1915 * @throws IllegalStateException if this handle or the underlying 1916 * environment has been closed. 1917 */ 1918 public EnvironmentStats getStats(StatsConfig config) 1919 throws DatabaseException { 1920 1921 checkHandleIsValid(); 1922 checkEnv(); 1923 try { 1924 StatsConfig useConfig = 1925 (config == null) ? StatsConfig.DEFAULT : config; 1926 1927 if (envImpl != null) { 1928 return envImpl.loadStats(useConfig); 1929 } 1930 return new EnvironmentStats(); 1931 } catch (Error E) { 1932 if (envImpl != null) { 1933 envImpl.invalidate(E); 1934 } 1935 throw E; 1936 } 1937 } 1938 1939 /** 1940 * Returns the database environment's locking statistics. 1941 * 1942 * @param config The locking statistics attributes. If null, default 1943 * attributes are used. 1944 * 1945 * @return The database environment's locking statistics. 1946 * 1947 * @throws EnvironmentFailureException if an unexpected, internal or 1948 * environment-wide failure occurs. 1949 * 1950 * @throws IllegalStateException if this handle or the underlying 1951 * environment has been closed. 1952 * 1953 * @deprecated as of 4.0.10, replaced by {@link 1954 * Environment#getStats(StatsConfig)}.</p> 1955 */ 1956 public LockStats getLockStats(StatsConfig config) 1957 throws DatabaseException { 1958 1959 try { 1960 checkHandleIsValid(); 1961 checkEnv(); 1962 StatsConfig useConfig = 1963 (config == null) ? StatsConfig.DEFAULT : config; 1964 1965 return envImpl.lockStat(useConfig); 1966 } catch (Error E) { 1967 if (envImpl != null) { 1968 envImpl.invalidate(E); 1969 } 1970 throw E; 1971 } 1972 } 1973 1974 /** 1975 * Returns the database environment's transactional statistics. 1976 * 1977 * @param config The transactional statistics attributes. If null, 1978 * default attributes are used. 1979 * 1980 * @return The database environment's transactional statistics. 1981 * 1982 * @throws EnvironmentFailureException if an unexpected, internal or 1983 * environment-wide failure occurs. 1984 * 1985 * @throws IllegalStateException if this handle or the underlying 1986 * environment has been closed. 1987 */ 1988 public TransactionStats getTransactionStats(StatsConfig config) 1989 throws DatabaseException { 1990 1991 try { 1992 checkHandleIsValid(); 1993 checkEnv(); 1994 StatsConfig useConfig = 1995 (config == null) ? StatsConfig.DEFAULT : config; 1996 return envImpl.txnStat(useConfig); 1997 } catch (Error E) { 1998 if (envImpl != null) { 1999 envImpl.invalidate(E); 2000 } 2001 throw E; 2002 } 2003 } 2004 2005 /** 2006 * Returns a List of database names for the database environment. 2007 * 2008 * <p>Each element in the list is a String.</p> 2009 * 2010 * @return A List of database names for the database environment. 2011 * 2012 * @throws OperationFailureException if one of the <a 2013 * href="OperationFailureException.html#readFailures">Read Operation 2014 * Failures</a> occurs. 2015 * 2016 * @throws EnvironmentFailureException if an unexpected, internal or 2017 * environment-wide failure occurs. 2018 * 2019 * @throws IllegalStateException if this handle or the underlying 2020 * environment has been closed. 2021 */ 2022 public List<String> getDatabaseNames() 2023 throws DatabaseException { 2024 2025 try { 2026 checkHandleIsValid(); 2027 checkEnv(); 2028 return envImpl.getDbTree().getDbNames(); 2029 } catch (Error E) { 2030 if (envImpl != null) { 2031 envImpl.invalidate(E); 2032 } 2033 throw E; 2034 } 2035 } 2036 2037 /** 2038 * Returns if the database environment is consistent and correct. 2039 * 2040 * <p>Verification is an expensive operation that should normally only be 2041 * used for troubleshooting and debugging.</p> 2042 * 2043 * @param config The verification attributes. If null, default 2044 * attributes are used. 2045 * 2046 * @param out The stream to which verification debugging information is 2047 * written. 2048 * 2049 * @return true if the database environment is consistent and correct. 2050 * 2051 * @throws EnvironmentFailureException if an unexpected, internal or 2052 * environment-wide failure occurs. 2053 * 2054 * @throws IllegalStateException if this handle or the underlying 2055 * environment has been closed. 2056 */ 2057 public boolean verify(VerifyConfig config, PrintStream out) 2058 throws DatabaseException { 2059 2060 try { 2061 checkHandleIsValid(); 2062 checkEnv(); 2063 VerifyConfig useConfig = 2064 (config == null) ? VerifyConfig.DEFAULT : config; 2065 return envImpl.verify(useConfig, out); 2066 } catch (Error E) { 2067 if (envImpl != null) { 2068 envImpl.invalidate(E); 2069 } 2070 throw E; 2071 } 2072 } 2073 2074 /** 2075 * Returns the transaction associated with this thread if implied 2076 * transactions are being used. Implied transactions are used in an XA or 2077 * JCA "Local Transaction" environment. In an XA environment the 2078 * XAEnvironment.start() entrypoint causes a transaction to be created and 2079 * become associated with the calling thread. Subsequent API calls 2080 * implicitly use that transaction. XAEnvironment.end() causes the 2081 * transaction to be disassociated with the thread. In a JCA Local 2082 * Transaction environment, the call to JEConnectionFactory.getConnection() 2083 * causes a new transaction to be created and associated with the calling 2084 * thread. 2085 * 2086 * @throws IllegalStateException if this handle or the underlying 2087 * environment has been closed. 2088 */ 2089 public Transaction getThreadTransaction() 2090 throws DatabaseException { 2091 2092 checkHandleIsValid(); 2093 checkEnv(); 2094 try { 2095 return envImpl.getTxnManager().getTxnForThread(); 2096 } catch (Error E) { 2097 if (envImpl != null) { 2098 envImpl.invalidate(E); 2099 } 2100 throw E; 2101 } 2102 } 2103 2104 /** 2105 * Sets the transaction associated with this thread if implied transactions 2106 * are being used. Implied transactions are used in an XA or JCA "Local 2107 * Transaction" environment. In an XA environment the 2108 * XAEnvironment.start() entrypoint causes a transaction to be created and 2109 * become associated with the calling thread. Subsequent API calls 2110 * implicitly use that transaction. XAEnvironment.end() causes the 2111 * transaction to be disassociated with the thread. In a JCA Local 2112 * Transaction environment, the call to JEConnectionFactory.getConnection() 2113 * causes a new transaction to be created and associated with the calling 2114 * thread. 2115 * 2116 * @throws IllegalStateException if this handle or the underlying 2117 * environment has been closed. 2118 */ 2119 public void setThreadTransaction(Transaction txn) { 2120 2121 checkHandleIsValid(); 2122 checkEnv(); 2123 try { 2124 envImpl.getTxnManager().setTxnForThread(txn); 2125 } catch (Error E) { 2126 envImpl.invalidate(E); 2127 throw E; 2128 } 2129 } 2130 2131 /** 2132 * Returns whether this {@code Environment} is open, valid and can be used. 2133 * If this method returns false, {@link #close} should be called as soon as 2134 * possible. 2135 * 2136 * <p>When an {@link EnvironmentFailureException}, or one of its 2137 * subclasses, is caught, the {@code isValid} method should be called to 2138 * determine whether the {@code Environment} can continue to be used, or 2139 * should be closed.</p> 2140 */ 2141 public boolean isValid() { 2142 return envImpl != null && 2143 envImpl.isValid(); 2144 } 2145 2146 /** 2147 * Print a detailed report about the costs of different phases of 2148 * environment startup. This report is by default logged to the je.info 2149 * file if startup takes longer than je.env.startupThreshold. 2150 */ 2151 public void printStartupInfo(PrintStream out) { 2152 envImpl.getStartupTracker().displayStats(out, Phase.TOTAL_ENV_OPEN); 2153 } 2154 2155 /* 2156 * Non public api -- helpers 2157 */ 2158 2159 /** 2160 * Let the Environment remember what's opened against it. 2161 */ 2162 private void addReferringHandle(Database db) { 2163 referringDbs.put(db, db); 2164 } 2165 2166 /** 2167 * Lets the Environment remember what's opened against it. 2168 */ 2169 private void addReferringHandle(Transaction txn) { 2170 referringDbTxns.put(txn, txn); 2171 } 2172 2173 /** 2174 * The referring db has been closed. 2175 */ 2176 void removeReferringHandle(Database db) { 2177 referringDbs.remove(db); 2178 } 2179 2180 /** 2181 * The referring Transaction has been closed. 2182 */ 2183 void removeReferringHandle(Transaction txn) { 2184 referringDbTxns.remove(txn); 2185 } 2186 2187 /** 2188 * For internal use only. 2189 * @hidden 2190 * @throws IllegalStateException if the environment is not open. 2191 */ 2192 public void checkHandleIsValid() { 2193 if (envImpl == null) { 2194 throw new IllegalStateException 2195 ("Attempt to use non-open Environment object()."); 2196 } 2197 } 2198 2199 /* 2200 * Debugging aids. 2201 */ 2202 2203 /** 2204 * Internal entrypoint. 2205 */ 2206 EnvironmentImpl getEnvironmentImpl() { 2207 2208 /* Bandaid: Avoid NPE when handle is closed. [#22002] */ 2209 checkHandleIsValid(); 2210 2211 return envImpl; 2212 } 2213 2214 /* Returns true, if this is a handle allocated internally by JE. */ 2215 protected boolean isInternalHandle() { 2216 return false; 2217 } 2218 2219 /** 2220 * For internal use only. 2221 * @hidden 2222 * Throws if the envImpl is invalid. 2223 */ 2224 protected void checkEnv() 2225 throws DatabaseException, EnvironmentFailureException { 2226 2227 if (envImpl == null) { 2228 return; 2229 } 2230 envImpl.checkIfInvalid(); 2231 envImpl.checkNotClosed(); 2232 } 2233 2234 /** 2235 * @throws UnsupportedOperationException via the database operation methods 2236 * (remove, truncate, rename) and potentially other methods that require a 2237 * writable environment. 2238 */ 2239 private void checkWritable() { 2240 if (envImpl.isReadOnly()) { 2241 throw new UnsupportedOperationException 2242 ("Environment is Read-Only."); 2243 } 2244 } 2245 } 2246