KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > je > dbi > EnvironmentImpl


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: EnvironmentImpl.java,v 1.255 2006/12/04 18:47:41 cwl Exp $
7  */

8
9 package com.sleepycat.je.dbi;
10
11 import java.io.File JavaDoc;
12 import java.io.IOException JavaDoc;
13 import java.io.PrintStream JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.logging.ConsoleHandler JavaDoc;
18 import java.util.logging.FileHandler JavaDoc;
19 import java.util.logging.Handler JavaDoc;
20 import java.util.logging.Level JavaDoc;
21 import java.util.logging.Logger JavaDoc;
22 import java.util.logging.SimpleFormatter JavaDoc;
23
24 import com.sleepycat.je.CheckpointConfig;
25 import com.sleepycat.je.Database;
26 import com.sleepycat.je.DatabaseConfig;
27 import com.sleepycat.je.DatabaseException;
28 import com.sleepycat.je.DbInternal;
29 import com.sleepycat.je.Environment;
30 import com.sleepycat.je.EnvironmentConfig;
31 import com.sleepycat.je.EnvironmentMutableConfig;
32 import com.sleepycat.je.EnvironmentStats;
33 import com.sleepycat.je.ExceptionListener;
34 import com.sleepycat.je.LockStats;
35 import com.sleepycat.je.RunRecoveryException;
36 import com.sleepycat.je.StatsConfig;
37 import com.sleepycat.je.Transaction;
38 import com.sleepycat.je.TransactionConfig;
39 import com.sleepycat.je.TransactionStats;
40 import com.sleepycat.je.VerifyConfig;
41 import com.sleepycat.je.cleaner.Cleaner;
42 import com.sleepycat.je.cleaner.UtilizationProfile;
43 import com.sleepycat.je.cleaner.UtilizationTracker;
44 import com.sleepycat.je.config.EnvironmentParams;
45 import com.sleepycat.je.evictor.Evictor;
46 import com.sleepycat.je.incomp.INCompressor;
47 import com.sleepycat.je.latch.Latch;
48 import com.sleepycat.je.latch.LatchSupport;
49 import com.sleepycat.je.latch.SharedLatch;
50 import com.sleepycat.je.log.FileManager;
51 import com.sleepycat.je.log.LatchedLogManager;
52 import com.sleepycat.je.log.LogManager;
53 import com.sleepycat.je.log.SyncedLogManager;
54 import com.sleepycat.je.log.TraceLogHandler;
55 import com.sleepycat.je.recovery.Checkpointer;
56 import com.sleepycat.je.recovery.RecoveryInfo;
57 import com.sleepycat.je.recovery.RecoveryManager;
58 import com.sleepycat.je.tree.BIN;
59 import com.sleepycat.je.tree.BINReference;
60 import com.sleepycat.je.tree.IN;
61 import com.sleepycat.je.tree.Key;
62 import com.sleepycat.je.txn.Locker;
63 import com.sleepycat.je.txn.Txn;
64 import com.sleepycat.je.txn.TxnManager;
65 import com.sleepycat.je.utilint.DbLsn;
66 import com.sleepycat.je.utilint.NotImplementedYetException;
67 import com.sleepycat.je.utilint.PropUtil;
68 import com.sleepycat.je.utilint.TestHook;
69 import com.sleepycat.je.utilint.TestHookExecute;
70 import com.sleepycat.je.utilint.Tracer;
71
72 /**
73  * Underlying Environment implementation. There is a single instance for any
74  * database environment opened by the application.
75  */

76 public class EnvironmentImpl implements EnvConfigObserver {
77    
78     /*
79      * Set true and run unit tests for NO_LOCKING_MODE test.
80      * EnvironmentConfigTest.testInconsistentParams will fail. [#13788]
81      */

82     private static final boolean TEST_NO_LOCKING_MODE = false;
83
84     /* Attributes of the entire environment */
85     private DbEnvState envState;
86     private boolean closing; // true if close has begun
87
private File JavaDoc envHome;
88     private int referenceCount; // count of opened Database and DbTxns
89
private boolean isTransactional; // true if env opened with DB_INIT_TRANS
90
private boolean isNoLocking; // true if env has no locking
91
private boolean isReadOnly; // true if env opened with the read only flag.
92
private boolean isMemOnly; // true if je.log.memOnly=true
93
private boolean directNIO; // true to use direct NIO buffers
94
private static boolean fairLatches;// true if user wants fair latches
95
private static boolean useSharedLatchesForINs;
96     /* true if offset tracking should be used for deferred write dbs. */
97     private boolean deferredWriteTemp;
98
99     private MemoryBudget memoryBudget;
100     private static int adler32ChunkSize;
101
102     /* Save so we don't have to look it up in the config manager frequently. */
103     private long lockTimeout;
104     private long txnTimeout;
105
106     /* DatabaseImpl */
107     private DbTree dbMapTree;
108     private long mapTreeRootLsn = DbLsn.NULL_LSN;
109     private Latch mapTreeRootLatch;
110     private INList inMemoryINs;
111
112     /* Services */
113     private DbConfigManager configManager;
114     private List JavaDoc configObservers;
115     private Logger JavaDoc envLogger;
116     protected LogManager logManager;
117     private FileManager fileManager;
118     private TxnManager txnManager;
119     
120     /* Daemons */
121     private Evictor evictor;
122     private INCompressor inCompressor;
123     private Checkpointer checkpointer;
124     private Cleaner cleaner;
125
126     /* Replication */
127     private boolean isReplicated;
128     private ReplicatorInstance repInstance;
129
130     /* Stats, debug information */
131     private RecoveryInfo lastRecoveryInfo;
132     private RunRecoveryException savedInvalidatingException;
133
134     /* If true, call Thread.yield() at strategic points (stress test aid) */
135     private static boolean forcedYield = false;
136
137     /*
138      * Used by Database to protect access to the trigger list. A single latch
139      * for all databases is used to prevent deadlocks.
140      */

141     private SharedLatch triggerLatch;
142
143     /**
144      * The exception listener for this envimpl, if any has been specified.
145      */

146     private ExceptionListener exceptionListener = null;
147
148     /*
149      * Configuration and tracking of background IO limits. Managed by the
150      * updateBackgroundReads, updateBackgroundWrites and sleepAfterBackgroundIO
151      * methods. The limits and the backlog are volatile because we check them
152      * outside the synchronized block. Other fields are updated and checked
153      * while synchronized on the tracking mutex object. The sleep mutex is
154      * used to block multiple background threads while sleeping.
155      */

156     private volatile int backgroundSleepBacklog;
157     private volatile int backgroundReadLimit;
158     private volatile int backgroundWriteLimit;
159     private long backgroundSleepInterval;
160     private int backgroundReadCount;
161     private long backgroundWriteBytes;
162     private TestHook backgroundSleepHook;
163     private Object JavaDoc backgroundTrackingMutex = new Object JavaDoc();
164     private Object JavaDoc backgroundSleepMutex = new Object JavaDoc();
165
166     /*
167      * ThreadLocal.get() is not cheap so we want to minimize calls to it. We
168      * only use ThreadLocals for the TreeStatsAccumulator which are only called
169      * in limited circumstances. Use this reference count to indicate that a
170      * thread has set a TreeStatsAccumulator. When it's done, it decrements
171      * the counter. It's static so that we don't have to pass around the
172      * EnvironmentImpl.
173      */

174     private static int threadLocalReferenceCount = 0;
175
176     /**
177      * DbPrintLog doesn't need btree and dup comparators to function properly
178      * don't require any instantiations. This flag, if true, indicates that
179      * we've been called from DbPrintLog.
180      */

181     private static boolean noComparators = false;
182     
183     /*
184      * A preallocated RunRecoveryException that is used in OOME and other
185      * java.lang.Error situations so that allocation does not need to be done
186      * in the OOME context.
187      */

188     public final RunRecoveryException SAVED_RRE = DbInternal.makeNoArgsRRE();
189
190     public static final boolean JAVA5_AVAILABLE;
191
192     private static final String JavaDoc DISABLE_JAVA_ADLER32 =
193     "je.disable.java.adler32";
194
195     static {
196     boolean ret = false;
197     if (System.getProperty(DISABLE_JAVA_ADLER32) == null) {
198
199         /*
200          * Use this to determine if we're in J5.
201          */

202         String JavaDoc javaVersion = System.getProperty("java.version");
203         if (javaVersion != null &&
204         !javaVersion.startsWith("1.4.")) {
205         ret = true;
206         }
207     }
208     JAVA5_AVAILABLE = ret;
209     }
210
211     /**
212      * Create a database environment to represent the data in envHome.
213      * dbHome. Properties from the je.properties file in that directory are
214      * used to initialize the system wide property bag. Properties passed to
215      * this method are used to influence the open itself.
216      *
217      * @param envHome absolute path of the database environment
218      * home directory
219      *
220      * @param envConfig
221      *
222      * @throws DatabaseException on all other failures
223      */

224     public EnvironmentImpl(File JavaDoc envHome, EnvironmentConfig envConfig)
225         throws DatabaseException {
226
227         try {
228             this.envHome = envHome;
229             envState = DbEnvState.INIT;
230             mapTreeRootLatch = LatchSupport.makeLatch("MapTreeRoot", this);
231
232             /* Set up configuration parameters */
233             configManager = new DbConfigManager(envConfig);
234             configObservers = new ArrayList JavaDoc();
235             addConfigObserver(this);
236
237             /*
238              * Decide on memory budgets based on environment config params and
239              * memory available to this process.
240              */

241             memoryBudget = new MemoryBudget(this, configManager);
242
243             /*
244              * Set up debug logging. Depending on configuration, add handlers,
245              * set logging level.
246              */

247             envLogger = initLogger(envHome);
248
249             /*
250              * Essential services. These must exist before recovery.
251              */

252         forcedYield =
253         configManager.getBoolean(EnvironmentParams.ENV_FORCED_YIELD);
254             isTransactional =
255         configManager.getBoolean(EnvironmentParams.ENV_INIT_TXN);
256             isNoLocking = !(configManager.getBoolean
257                 (EnvironmentParams.ENV_INIT_LOCKING));
258         if (isTransactional && isNoLocking) {
259         if (TEST_NO_LOCKING_MODE) {
260             isNoLocking = !isTransactional;
261         } else {
262             throw new IllegalArgumentException JavaDoc
263             ("Can't set 'je.env.isNoLocking' and " +
264              "'je.env.isTransactional';");
265         }
266         }
267
268         directNIO =
269         configManager.getBoolean(EnvironmentParams.LOG_DIRECT_NIO);
270         fairLatches =
271         configManager.getBoolean(EnvironmentParams.ENV_FAIR_LATCHES);
272             isReadOnly =
273         configManager.getBoolean(EnvironmentParams.ENV_RDONLY);
274             isMemOnly =
275                 configManager.getBoolean(EnvironmentParams.LOG_MEMORY_ONLY);
276         useSharedLatchesForINs =
277         configManager.getBoolean(EnvironmentParams.ENV_SHARED_LATCHES);
278         adler32ChunkSize =
279         configManager.getInt(EnvironmentParams.ADLER32_CHUNK_SIZE);
280
281         exceptionListener = envConfig.getExceptionListener();
282
283             /*
284              * This property indicates that we should use obsolete offset
285              * tracking for deferred write dbs. Very likely to be a temporary
286              * property.
287              */

288             deferredWriteTemp =
289         configManager.getBoolean(
290                                   EnvironmentParams.LOG_DEFERREDWRITE_TEMP);
291
292             fileManager = new FileManager(this, envHome, isReadOnly);
293             if (!envConfig.getAllowCreate() && !fileManager.filesExist()) {
294                 throw new DatabaseException
295             ("Environment.setAllowCreate is false so environment " +
296                      " creation is not permitted, but there is no " +
297                      " pre-existing environment in " + envHome);
298             }
299
300             if (fairLatches) {
301                 logManager = new LatchedLogManager(this, isReadOnly);
302             } else {
303                 logManager = new SyncedLogManager(this, isReadOnly);
304             }
305
306             inMemoryINs = new INList(this);
307             txnManager = new TxnManager(this);
308
309             /*
310              * Daemons are always made here, but only started after recovery.
311              * We want them to exist so we can call them programatically even
312              * if the daemon thread is not started.
313              */

314             createDaemons();
315
316             /*
317          * Recovery will recreate the dbMapTree from the log if it exists.
318          */

319             dbMapTree = new DbTree(this);
320
321             referenceCount = 0;
322
323             triggerLatch = LatchSupport.makeSharedLatch("TriggerLatch", this);
324
325             /*
326              * Do not do recovery and start daemons if this environment is for
327              * a utility.
328              */

329             if (configManager.getBoolean(EnvironmentParams.ENV_RECOVERY)) {
330
331                 /*
332                  * Run recovery. Note that debug logging to the database log
333                  * is disabled until recovery is finished.
334                  */

335                 try {
336                     RecoveryManager recoveryManager =
337             new RecoveryManager(this);
338                     lastRecoveryInfo = recoveryManager.recover(isReadOnly);
339                 } finally {
340                     try {
341                         /* Flush to get all exception tracing out to the log.*/
342                         logManager.flush();
343                         fileManager.clear();
344                     } catch (IOException JavaDoc e) {
345                         throw new DatabaseException(e.getMessage());
346                     }
347                 }
348             } else {
349                 isReadOnly = true;
350         noComparators = true;
351             }
352
353             /* Initialize mutable properties and start daemons. */
354             envConfigUpdate(configManager);
355
356             /*
357              * Cache a few critical values. We keep our timeout in millis
358              * instead of microseconds because Object.wait takes millis.
359              */

360             lockTimeout =
361         PropUtil.microsToMillis(configManager.getLong
362                     (EnvironmentParams.LOCK_TIMEOUT));
363             txnTimeout =
364         PropUtil.microsToMillis(configManager.getLong
365                     (EnvironmentParams.TXN_TIMEOUT));
366
367             /* Initialize the environment memory usage number. */
368             memoryBudget.initCacheMemoryUsage();
369
370             /* Mark as open. */
371             open();
372         } catch (DatabaseException e) {
373
374             /* Release any environment locks if there was a problem. */
375             if (fileManager != null) {
376                 try {
377                     /*
378                      * Clear again, in case an exception in logManager.flush()
379                      * caused us to skip the earlier call to clear().
380                      */

381                     fileManager.clear();
382                     fileManager.close();
383                 } catch (IOException JavaDoc IOE) {
384
385             /*
386              * Klockwork - ok
387              * Eat it, we want to throw the original exception.
388              */

389                 }
390             }
391             throw e;
392         }
393     }
394
395     /**
396      * Respond to config updates.
397      */

398     public void envConfigUpdate(DbConfigManager mgr)
399         throws DatabaseException {
400
401         runOrPauseDaemons(mgr);
402         
403         backgroundReadLimit = mgr.getInt
404             (EnvironmentParams.ENV_BACKGROUND_READ_LIMIT);
405         backgroundWriteLimit = mgr.getInt
406             (EnvironmentParams.ENV_BACKGROUND_WRITE_LIMIT);
407         backgroundSleepInterval = PropUtil.microsToMillis(mgr.getLong
408             (EnvironmentParams.ENV_BACKGROUND_SLEEP_INTERVAL));
409     }
410     
411     /**
412      * Read configurations for daemons, instantiate.
413      */

414     private void createDaemons()
415         throws DatabaseException {
416
417         /* Evictor */
418         evictor = new Evictor(this, "Evictor");
419
420         /* Checkpointer */
421
422         /*
423          * Make sure that either log-size-based or time-based checkpointing
424          * is enabled.
425          */

426         long checkpointerWakeupTime =
427             Checkpointer.getWakeupPeriod(configManager);
428         checkpointer = new Checkpointer(this,
429                                         checkpointerWakeupTime,
430                                         Environment.CHECKPOINTER_NAME);
431
432         /* INCompressor */
433         long compressorWakeupInterval =
434             PropUtil.microsToMillis
435         (configManager.getLong
436          (EnvironmentParams.COMPRESSOR_WAKEUP_INTERVAL));
437         inCompressor = new INCompressor(this, compressorWakeupInterval,
438                                         Environment.INCOMP_NAME);
439
440     /* The cleaner is not time-based so no wakeup interval is used. */
441     cleaner = new Cleaner(this, Environment.CLEANER_NAME);
442     }
443
444     /**
445      * Run or pause daemons, depending on config properties.
446      */

447     private void runOrPauseDaemons(DbConfigManager mgr)
448         throws DatabaseException {
449
450         if (!isReadOnly) {
451             /* INCompressor */
452             inCompressor.runOrPause
453                 (mgr.getBoolean(EnvironmentParams.ENV_RUN_INCOMPRESSOR));
454
455             /* Cleaner. Do not start it if running in-memory */
456             cleaner.runOrPause
457                 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CLEANER) &&
458                  !isMemOnly);
459
460             /*
461              * Checkpointer. Run in both transactional and non-transactional
462              * environments to guarantee recovery time.
463              */

464             checkpointer.runOrPause
465                 (mgr.getBoolean(EnvironmentParams.ENV_RUN_CHECKPOINTER));
466         }
467
468         /* Evictor */
469         evictor.runOrPause
470             (mgr.getBoolean(EnvironmentParams.ENV_RUN_EVICTOR));
471     }
472         
473     /**
474      * Return the incompressor. In general, don't use this directly because
475      * it's easy to forget that the incompressor can be null at times (i.e
476      * during the shutdown procedure. Instead, wrap the functionality within
477      * this class, like lazyCompress.
478      */

479     public INCompressor getINCompressor() {
480     return inCompressor;
481     }
482
483     /**
484      * Returns the UtilizationTracker.
485      */

486     public UtilizationTracker getUtilizationTracker() {
487         return cleaner.getUtilizationTracker();
488     }
489
490     /**
491      * Returns the UtilizationProfile.
492      */

493     public UtilizationProfile getUtilizationProfile() {
494         return cleaner.getUtilizationProfile();
495     }
496
497     /**
498      * If a background read limit has been configured and that limit is
499      * exceeded when the cumulative total is incremented by the given number of
500      * reads, increment the sleep backlog to cause a sleep to occur. Called by
501      * background activities such as the cleaner after performing a file read
502      * operation.
503      *
504      * @see #sleepAfterBackgroundIO
505      */

506     public void updateBackgroundReads(int nReads) {
507
508         /*
509          * Make a copy of the volatile limit field since it could change
510          * between the time we check it and the time we use it below.
511          */

512         int limit = backgroundReadLimit;
513         if (limit > 0) {
514             synchronized (backgroundTrackingMutex) {
515                 backgroundReadCount += nReads;
516                 if (backgroundReadCount >= limit) {
517                     backgroundSleepBacklog += 1;
518                     /* Remainder is rolled forward. */
519                     backgroundReadCount -= limit;
520                     assert backgroundReadCount >= 0;
521                 }
522             }
523         }
524     }
525
526     /**
527      * If a background write limit has been configured and that limit is
528      * exceeded when the given amount written is added to the cumulative total,
529      * increment the sleep backlog to cause a sleep to occur. Called by
530      * background activities such as the checkpointer and evictor after
531      * performing a file write operation.
532      *
533      * <p>The number of writes is estimated by dividing the bytes written by
534      * the log buffer size. Since the log write buffer is shared by all
535      * writers, this is the best approximation possible.</p>
536      *
537      * @see #sleepAfterBackgroundIO
538      */

539     public void updateBackgroundWrites(int writeSize, int logBufferSize) {
540
541         /*
542          * Make a copy of the volatile limit field since it could change
543          * between the time we check it and the time we use it below.
544          */

545         int limit = backgroundWriteLimit;
546         if (limit > 0) {
547             synchronized (backgroundTrackingMutex) {
548                 backgroundWriteBytes += writeSize;
549                 int writeCount = (int) (backgroundWriteBytes / logBufferSize);
550                 if (writeCount >= limit) {
551                     backgroundSleepBacklog += 1;
552                     /* Remainder is rolled forward. */
553                     backgroundWriteBytes -= (limit * logBufferSize);
554                     assert backgroundWriteBytes >= 0;
555                 }
556             }
557         }
558     }
559
560     /**
561      * If the sleep backlog is non-zero (set by updateBackgroundReads or
562      * updateBackgroundWrites), sleep for the configured interval and decrement
563      * the backlog.
564      *
565      * <p>If two threads call this method and the first call causes a sleep,
566      * the call by the second thread will block until the first thread's sleep
567      * interval is over. When the call by the second thread is unblocked, if
568      * another sleep is needed then the second thread will sleep again. In
569      * other words, when lots of sleeps are needed, background threads may
570      * backup. This is intended to give foreground threads a chance to "catch
571      * up" when background threads are doing a lot of IO.</p>
572      */

573     public void sleepAfterBackgroundIO() {
574         if (backgroundSleepBacklog > 0) {
575             synchronized (backgroundSleepMutex) {
576                 /* Sleep. Rethrow interrupts if they occur. */
577                 try {
578             /* FindBugs: OK that we're sleeping with a mutex held. */
579                     Thread.sleep(backgroundSleepInterval);
580                 } catch (InterruptedException JavaDoc e) {
581                     Thread.currentThread().interrupt();
582                 }
583                 /* Assert has intentional side effect for unit testing. */
584                 assert TestHookExecute.doHookIfSet(backgroundSleepHook);
585             }
586             synchronized (backgroundTrackingMutex) {
587                 /* Decrement backlog last to make other threads wait. */
588                 if (backgroundSleepBacklog > 0) {
589                     backgroundSleepBacklog -= 1;
590                 }
591             }
592         }
593     }
594
595     /* For unit testing only. */
596     public void setBackgroundSleepHook(TestHook hook) {
597         backgroundSleepHook = hook;
598     }
599
600     /**
601      * Log the map tree root and save the LSN.
602      */

603     public void logMapTreeRoot()
604         throws DatabaseException {
605
606         mapTreeRootLatch.acquire();
607         try {
608             mapTreeRootLsn = logManager.log(dbMapTree);
609         } finally {
610             mapTreeRootLatch.release();
611         }
612     }
613
614     /**
615      * Force a rewrite of the map tree root if required.
616      */

617     public void rewriteMapTreeRoot(long cleanerTargetLsn)
618         throws DatabaseException {
619
620         mapTreeRootLatch.acquire();
621         try {
622             if (DbLsn.compareTo(cleanerTargetLsn, mapTreeRootLsn) == 0) {
623
624                 /*
625          * The root entry targetted for cleaning is in use. Write a
626          * new copy.
627                  */

628                 mapTreeRootLsn = logManager.log(dbMapTree);
629             }
630         } finally {
631             mapTreeRootLatch.release();
632         }
633     }
634
635     /**
636      * @return the mapping tree root LSN.
637      */

638     public long getRootLsn() {
639         return mapTreeRootLsn;
640     }
641         
642     /**
643      * Set the mapping tree from the log. Called during recovery.
644      */

645     public void readMapTreeFromLog(long rootLsn)
646         throws DatabaseException {
647
648         dbMapTree = (DbTree) logManager.get(rootLsn);
649         dbMapTree.setEnvironmentImpl(this);
650
651         /* Set the map tree root */
652         mapTreeRootLatch.acquire();
653         try {
654             mapTreeRootLsn = rootLsn;
655         } finally {
656             mapTreeRootLatch.release();
657         }
658     }
659
660     /**
661      * Tells the asynchronous IN compressor thread about a BIN with a deleted
662      * entry.
663      */

664     public void addToCompressorQueue(BIN bin,
665                                      Key deletedKey,
666                                      boolean doWakeup)
667         throws DatabaseException {
668         
669         /*
670          * May be called by the cleaner on its last cycle, after the compressor
671          * is shut down.
672          */

673         if (inCompressor != null) {
674             inCompressor.addBinKeyToQueue(bin, deletedKey, doWakeup);
675         }
676     }
677
678     /**
679      * Tells the asynchronous IN compressor thread about a BINReference with a
680      * deleted entry.
681      */

682     public void addToCompressorQueue(BINReference binRef,
683                                  boolean doWakeup)
684         throws DatabaseException {
685         
686         /*
687          * May be called by the cleaner on its last cycle, after the compressor
688          * is shut down.
689          */

690         if (inCompressor != null) {
691             inCompressor.addBinRefToQueue(binRef, doWakeup);
692         }
693     }
694
695     /**
696      * Tells the asynchronous IN compressor thread about a collections of
697      * BINReferences with deleted entries.
698      */

699     public void addToCompressorQueue(Collection JavaDoc binRefs,
700                                      boolean doWakeup)
701         throws DatabaseException {
702
703         /*
704          * May be called by the cleaner on its last cycle, after the compressor
705          * is shut down.
706          */

707         if (inCompressor != null) {
708             inCompressor.addMultipleBinRefsToQueue(binRefs, doWakeup);
709         }
710     }
711
712     /**
713      * Do lazy compression at opportune moments.
714      */

715     public void lazyCompress(IN in)
716         throws DatabaseException {
717
718         /*
719          * May be called by the cleaner on its last cycle, after the compressor
720          * is shut down.
721          */

722         if (inCompressor != null) {
723             inCompressor.lazyCompress(in);
724         }
725     }
726
727     /**
728      * Initialize the debugging logging system. Note that publishing to the
729      * database log is not permitted until we've initialized the file manager
730      * in recovery. We can't log safely before that.
731      */

732     private Logger JavaDoc initLogger(File JavaDoc envHome)
733         throws DatabaseException {
734
735         /* XXX, this creates problems in unit tests, not sure why yet
736            Logger logger = Logger.getLogger(EnvironmentImpl.class.getName() +
737            "." + envNum); */

738         Logger JavaDoc logger = Logger.getAnonymousLogger();
739
740         /*
741          * Disable handlers inherited from parents, we want JE to control its
742          * own behavior. Add our handlers based on configuration
743          */

744         logger.setUseParentHandlers(false);
745
746         /* Set the logging level. */
747         Level JavaDoc level =
748         Tracer.parseLevel(this, EnvironmentParams.JE_LOGGING_LEVEL);
749         logger.setLevel(level);
750
751         /* Log to console. */
752         if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_CONSOLE)) {
753             Handler JavaDoc consoleHandler = new ConsoleHandler JavaDoc();
754             consoleHandler.setLevel(level);
755             logger.addHandler(consoleHandler);
756         }
757
758         /* Log to text file. */
759         Handler JavaDoc fileHandler = null;
760         try {
761             if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_FILE)) {
762
763                 /* Log with a rotating set of files, use append mode. */
764                 int limit =
765                     configManager.getInt(EnvironmentParams.
766                      JE_LOGGING_FILE_LIMIT);
767                 int count =
768                     configManager.getInt(EnvironmentParams.
769                      JE_LOGGING_FILE_COUNT);
770                 String JavaDoc logFilePattern = envHome + "/" + Tracer.INFO_FILES;
771
772                 fileHandler = new FileHandler JavaDoc(logFilePattern,
773                                               limit, count, true);
774                 fileHandler.setFormatter(new SimpleFormatter JavaDoc());
775                 fileHandler.setLevel(level);
776                 logger.addHandler(fileHandler);
777             }
778         } catch (IOException JavaDoc e) {
779             throw new DatabaseException(e.getMessage());
780         }
781
782         return logger;
783     }
784
785     /**
786      * Add the database log as one of the debug logging destinations when the
787      * logging system is sufficiently initialized.
788      */

789     public void enableDebugLoggingToDbLog()
790         throws DatabaseException {
791
792         if (configManager.getBoolean(EnvironmentParams.JE_LOGGING_DBLOG)) {
793             Handler JavaDoc dbLogHandler = new TraceLogHandler(this);
794             Level JavaDoc level =
795                 Level.parse(configManager.get(EnvironmentParams.
796                           JE_LOGGING_LEVEL));
797             dbLogHandler.setLevel(level);
798             envLogger.addHandler(dbLogHandler);
799         }
800     }
801
802     /**
803      * Close down the logger.
804      */

805     public void closeLogger() {
806         Handler JavaDoc [] handlers = envLogger.getHandlers();
807         for (int i = 0; i < handlers.length; i++) {
808             handlers[i].close();
809         }
810     }
811
812     /**
813      * Not much to do, mark state.
814      */

815     public void open() {
816         envState = DbEnvState.OPEN;
817     }
818
819     /**
820      * Invalidate the environment. Done when a fatal exception
821      * (RunRecoveryException) is thrown.
822      */

823     public void invalidate(RunRecoveryException e) {
824
825         /*
826          * Remember the fatal exception so we can redisplay it if the
827          * environment is called by the application again. Set some state in
828          * the exception so the exception message will be clear that this was
829          * an earlier exception.
830          */

831         savedInvalidatingException = e;
832         envState = DbEnvState.INVALID;
833     requestShutdownDaemons();
834     }
835
836     public void invalidate(Error JavaDoc e) {
837     savedInvalidatingException = (RunRecoveryException)
838         SAVED_RRE.initCause(e);
839     envState = DbEnvState.INVALID;
840     requestShutdownDaemons();
841     }
842
843     /**
844      * @return true if environment is open.
845      */

846     public boolean isOpen() {
847         return (envState == DbEnvState.OPEN);
848     }
849
850     /**
851      * @return true if close has begun, although the state may still be open.
852      */

853     public boolean isClosing() {
854         return closing;
855     }
856
857     public boolean isClosed() {
858         return (envState == DbEnvState.CLOSED);
859     }
860
861     /**
862      * When a RunRecoveryException occurs or the environment is closed, further
863      * writing can cause log corruption.
864      */

865     public boolean mayNotWrite() {
866         return (envState == DbEnvState.INVALID) ||
867                (envState == DbEnvState.CLOSED);
868     }
869
870     public void checkIfInvalid()
871         throws RunRecoveryException {
872
873         if (envState == DbEnvState.INVALID) {
874             savedInvalidatingException.setAlreadyThrown();
875         if (savedInvalidatingException == SAVED_RRE) {
876         savedInvalidatingException.fillInStackTrace();
877         }
878             throw savedInvalidatingException;
879         }
880     }
881
882     public void checkNotClosed()
883         throws DatabaseException {
884
885         if (envState == DbEnvState.CLOSED) {
886             throw new DatabaseException
887                 ("Attempt to use a Environment that has been closed.");
888         }
889     }
890
891     public synchronized void close()
892         throws DatabaseException {
893
894         if (--referenceCount <= 0) {
895             doClose(true);
896         }
897     }
898
899     public synchronized void close(boolean doCheckpoint)
900         throws DatabaseException {
901
902         if (--referenceCount <= 0) {
903             doClose(doCheckpoint);
904         }
905     }
906
907     private void doClose(boolean doCheckpoint)
908         throws DatabaseException {
909
910     StringBuffer JavaDoc errors = new StringBuffer JavaDoc();
911
912         try {
913             Tracer.trace(Level.FINE, this,
914                          "Close of environment " +
915                          envHome + " started");
916
917         try {
918         envState.checkState(DbEnvState.VALID_FOR_CLOSE,
919                     DbEnvState.CLOSED);
920         } catch (DatabaseException DBE) {
921         throw DBE;
922         }
923
924             /*
925              * Begin shutdown of the deamons before checkpointing. Cleaning
926              * during the checkpoint is wasted and slows down the checkpoint.
927              */

928             requestShutdownDaemons();
929
930             /* Checkpoint to bound recovery time. */
931             if (doCheckpoint &&
932                 !isReadOnly &&
933                 (envState != DbEnvState.INVALID) &&
934         logManager.getLastLsnAtRecovery() !=
935         fileManager.getLastUsedLsn()) {
936
937                 /*
938                  * Force a checkpoint. Don't allow deltas (minimize recovery
939                  * time) because they cause inefficiencies for two reasons: (1)
940                  * recovering BINDeltas causes extra random I/O in order to
941                  * reconstitute BINS, which can greatly increase recovery time,
942                  * and (2) logging deltas during close causes redundant logging
943                  * by the full checkpoint after recovery.
944                  */

945                 CheckpointConfig ckptConfig = new CheckpointConfig();
946                 ckptConfig.setForce(true);
947                 ckptConfig.setMinimizeRecoveryTime(true);
948                 try {
949                     invokeCheckpoint
950                         (ckptConfig,
951                          false, // flushAll
952
"close");
953                 } catch (DatabaseException IE) {
954                     errors.append("\nException performing checkpoint: ");
955                     errors.append(IE.toString()).append("\n");
956                 }
957             }
958         
959         try {
960         shutdownDaemons();
961         } catch (InterruptedException JavaDoc IE) {
962         errors.append("\nException shutting down daemon threads: ");
963         errors.append(IE.toString()).append("\n");
964         }
965
966             /* Flush log. */
967             Tracer.trace(Level.FINE, this,
968                          "Env " + envHome + " daemons shutdown");
969         try {
970         logManager.flush();
971         } catch (DatabaseException DBE) {
972         errors.append("\nException flushing log manager: ");
973         errors.append(DBE.toString()).append("\n");
974         }
975
976         try {
977         fileManager.clear();
978         } catch (IOException JavaDoc IOE) {
979         errors.append("\nException clearing file manager: ");
980         errors.append(IOE.toString()).append("\n");
981         } catch (DatabaseException DBE) {
982         errors.append("\nException clearing file manager: ");
983         errors.append(DBE.toString()).append("\n");
984         }
985
986         try {
987         fileManager.close();
988         } catch (IOException JavaDoc IOE) {
989         errors.append("\nException clearing file manager: ");
990         errors.append(IOE.toString()).append("\n");
991         } catch (DatabaseException DBE) {
992         errors.append("\nException clearing file manager: ");
993         errors.append(DBE.toString()).append("\n");
994         }
995
996         try {
997         inMemoryINs.clear();
998         } catch (DatabaseException DBE) {
999         errors.append("\nException closing file manager: ");
1000        errors.append(DBE.toString()).append("\n");
1001        }
1002
1003            closeLogger();
1004
1005            DbEnvPool.getInstance().remove(envHome);
1006
1007        try {
1008        checkLeaks();
1009        LatchSupport.clearNotes();
1010        } catch (DatabaseException DBE) {
1011        errors.append("\nException performing validity checks: ");
1012        errors.append(DBE.toString()).append("\n");
1013        }
1014        } finally {
1015            envState = DbEnvState.CLOSED;
1016    }
1017
1018    if (errors.length() > 0 &&
1019        savedInvalidatingException == null) {
1020
1021        /* Don't whine again if we've already whined. */
1022        throw new RunRecoveryException(this, errors.toString());
1023    }
1024    }
1025
1026    /*
1027     * Clear as many resources as possible, even in the face of an environment
1028     * that has received a fatal error, in order to support reopening the
1029     * environment in the same JVM.
1030     */

1031    public synchronized void closeAfterRunRecovery()
1032        throws DatabaseException {
1033
1034        try {
1035            shutdownDaemons();
1036        } catch (InterruptedException JavaDoc IE) {
1037        /* Klockwork - ok */
1038        }
1039
1040        try {
1041            fileManager.clear();
1042        } catch (Exception JavaDoc e) {
1043        /* Klockwork - ok */
1044        }
1045
1046        try {
1047            fileManager.close();
1048        } catch (Exception JavaDoc e) {
1049        /* Klockwork - ok */
1050        }
1051
1052        DbEnvPool.getInstance().remove(envHome);
1053    }
1054
1055    public synchronized void forceClose()
1056        throws DatabaseException {
1057
1058        referenceCount = 1;
1059        close();
1060    }
1061
1062    public synchronized void incReferenceCount() {
1063        referenceCount++;
1064    }
1065
1066    public static int getThreadLocalReferenceCount() {
1067        return threadLocalReferenceCount;
1068    }
1069
1070    public static synchronized void incThreadLocalReferenceCount() {
1071        threadLocalReferenceCount++;
1072    }
1073
1074    public static synchronized void decThreadLocalReferenceCount() {
1075        threadLocalReferenceCount--;
1076    }
1077
1078    public static boolean getNoComparators() {
1079    return noComparators;
1080    }
1081
1082    /**
1083     * Debugging support. Check for leaked locks and transactions.
1084     */

1085    private void checkLeaks()
1086        throws DatabaseException {
1087
1088        /* Only enabled if this check leak flag is true. */
1089        if (!configManager.getBoolean(EnvironmentParams.ENV_CHECK_LEAKS)) {
1090            return;
1091        }
1092
1093        boolean clean = true;
1094        StatsConfig statsConfig = new StatsConfig();
1095
1096        /* Fast stats will not return NTotalLocks below. */
1097        statsConfig.setFast(false);
1098
1099        LockStats lockStat = lockStat(statsConfig);
1100        if (lockStat.getNTotalLocks() != 0) {
1101            clean = false;
1102            System.out.println("Problem: " + lockStat.getNTotalLocks() +
1103                               " locks left");
1104            txnManager.getLockManager().dump();
1105        }
1106
1107        TransactionStats txnStat = txnStat(statsConfig);
1108        if (txnStat.getNActive() != 0) {
1109            clean = false;
1110            System.out.println("Problem: " + txnStat.getNActive() +
1111                               " txns left");
1112            TransactionStats.Active[] active = txnStat.getActiveTxns();
1113            if (active != null) {
1114                for (int i = 0; i < active.length; i += 1) {
1115                    System.out.println(active[i]);
1116                }
1117            }
1118        }
1119
1120        if (LatchSupport.countLatchesHeld() > 0) {
1121            clean = false;
1122            System.out.println("Some latches held at env close.");
1123            LatchSupport.dumpLatchesHeld();
1124        }
1125
1126        assert clean:
1127            "Lock, transaction, or latch left behind at environment close";
1128    }
1129
1130    /**
1131     * Invoke a checkpoint programatically. Note that only one checkpoint may
1132     * run at a time.
1133     */

1134    public boolean invokeCheckpoint(CheckpointConfig config,
1135                                    boolean flushAll,
1136                                    String JavaDoc invokingSource)
1137        throws DatabaseException {
1138
1139        if (checkpointer != null) {
1140            checkpointer.doCheckpoint(config, flushAll, invokingSource);
1141            return true;
1142        } else {
1143            return false;
1144        }
1145    }
1146
1147    /**
1148     * Flip the log to a new file, forcing an fsync. Return the LSN of the
1149     * trace record in the new file.
1150     */

1151    public long forceLogFileFlip()
1152    throws DatabaseException {
1153
1154    Tracer newRec = new Tracer("File Flip");
1155    return logManager.logForceFlip(newRec);
1156    }
1157
1158    /**
1159     * Invoke a compress programatically. Note that only one compress may run
1160     * at a time.
1161     */

1162    public boolean invokeCompressor()
1163        throws DatabaseException {
1164
1165        if (inCompressor != null) {
1166            inCompressor.doCompress();
1167            return true;
1168        } else {
1169            return false;
1170        }
1171    }
1172
1173    public void invokeEvictor()
1174        throws DatabaseException {
1175
1176        if (evictor != null) {
1177            evictor.doEvict(Evictor.SOURCE_MANUAL);
1178        }
1179    }
1180
1181    public int invokeCleaner()
1182        throws DatabaseException {
1183
1184        if (cleaner != null) {
1185            return cleaner.doClean(true, // cleanMultipleFiles
1186
false); // forceCleaning
1187
} else {
1188            return 0;
1189        }
1190    }
1191
1192    private void requestShutdownDaemons() {
1193
1194        closing = true;
1195
1196        if (inCompressor != null) {
1197            inCompressor.requestShutdown();
1198    }
1199
1200        if (evictor != null) {
1201            evictor.requestShutdown();
1202    }
1203
1204        if (checkpointer != null) {
1205            checkpointer.requestShutdown();
1206    }
1207
1208        if (cleaner != null) {
1209            cleaner.requestShutdown();
1210    }
1211    }
1212
1213    /**
1214     * Ask all daemon threads to shut down.
1215     */

1216    private void shutdownDaemons()
1217        throws InterruptedException JavaDoc {
1218
1219        shutdownINCompressor();
1220
1221        /*
1222         * Cleaner has to be shutdown before checkpointer because former calls
1223         * the latter.
1224         */

1225        shutdownCleaner();
1226        shutdownCheckpointer();
1227
1228        /*
1229         * The evictor has to get shutdown last because the other daemons might
1230         * create changes to the memory usage which result in a notify to
1231         * eviction.
1232         */

1233        shutdownEvictor();
1234    }
1235
1236    /**
1237     * Available for the unit tests.
1238     */

1239    public void shutdownINCompressor()
1240        throws InterruptedException JavaDoc {
1241
1242        if (inCompressor != null) {
1243            inCompressor.shutdown();
1244
1245            /*
1246             * If daemon thread doesn't shutdown for any reason, at least clear
1247             * the reference to the environment so it can be GC'd.
1248             */

1249            inCompressor.clearEnv();
1250            inCompressor = null;
1251        }
1252        return;
1253    }
1254
1255    public void shutdownEvictor()
1256        throws InterruptedException JavaDoc {
1257
1258        if (evictor != null) {
1259            evictor.shutdown();
1260
1261            /*
1262             * If daemon thread doesn't shutdown for any reason, at least clear
1263             * the reference to the environment so it can be GC'd.
1264             */

1265            evictor.clearEnv();
1266            evictor = null;
1267        }
1268        return;
1269    }
1270
1271    void shutdownCheckpointer()
1272        throws InterruptedException JavaDoc {
1273
1274        if (checkpointer != null) {
1275            checkpointer.shutdown();
1276
1277            /*
1278             * If daemon thread doesn't shutdown for any reason, at least clear
1279             * the reference to the environment so it can be GC'd.
1280             */

1281            checkpointer.clearEnv();
1282            checkpointer = null;
1283        }
1284        return;
1285    }
1286
1287    /**
1288     * public for unit tests.
1289     */

1290    public void shutdownCleaner()
1291        throws InterruptedException JavaDoc {
1292
1293        if (cleaner != null) {
1294            cleaner.shutdown();
1295
1296            /*
1297             * Don't call clearEnv -- Cleaner.shutdown does this for each
1298             * cleaner thread. Don't set the cleaner field to null because we
1299             * use it to get the utilization profile and tracker.
1300             */

1301        }
1302        return;
1303    }
1304
1305    public boolean isNoLocking() {
1306    return isNoLocking;
1307    }
1308
1309    public boolean isTransactional() {
1310        return isTransactional;
1311    }
1312
1313    public boolean isReadOnly() {
1314        return isReadOnly;
1315    }
1316
1317    public boolean isMemOnly() {
1318        return isMemOnly;
1319    }
1320
1321    public static boolean getFairLatches() {
1322    return fairLatches;
1323    }
1324
1325    public static boolean getSharedLatches() {
1326    return useSharedLatchesForINs;
1327    }
1328
1329    public boolean getDeferredWriteTemp() {
1330        return deferredWriteTemp;
1331    }
1332
1333    public boolean useDirectNIO() {
1334        return directNIO;
1335    }
1336
1337    public static int getAdler32ChunkSize() {
1338    return adler32ChunkSize;
1339    }
1340
1341    /* DatabaseImpl access. */
1342    public DatabaseImpl createDb(Locker locker,
1343                                 String JavaDoc databaseName,
1344                                 DatabaseConfig dbConfig,
1345                                 Database databaseHandle)
1346        throws DatabaseException {
1347
1348        return dbMapTree.createDb(locker,
1349                                  databaseName,
1350                                  dbConfig,
1351                                  databaseHandle);
1352    }
1353
1354    /**
1355     * Get a database object given a database name.
1356     *
1357     * @param databaseName target database.
1358     *
1359     * @return null if database doesn't exist.
1360     */

1361    public DatabaseImpl getDb(Locker locker,
1362                              String JavaDoc databaseName,
1363                              Database databaseHandle)
1364        throws DatabaseException {
1365
1366        return dbMapTree.getDb(locker, databaseName, databaseHandle);
1367    }
1368
1369    public List JavaDoc getDbNames()
1370        throws DatabaseException {
1371
1372        return dbMapTree.getDbNames();
1373    }
1374
1375    /**
1376     * For debugging.
1377     */

1378    public void dumpMapTree()
1379        throws DatabaseException {
1380
1381        dbMapTree.dump();
1382    }
1383
1384    /**
1385     * Rename a database.
1386     */

1387    public void dbRename(Locker locker, String JavaDoc databaseName, String JavaDoc newName)
1388        throws DatabaseException {
1389
1390        dbMapTree.dbRename(locker, databaseName, newName);
1391    }
1392
1393    /**
1394     * Remove a database.
1395     */

1396    public void dbRemove(Locker locker, String JavaDoc databaseName)
1397        throws DatabaseException {
1398
1399        dbMapTree.dbRemove(locker, databaseName);
1400    }
1401
1402    /**
1403     * Truncate a database. Return a new DatabaseImpl object which represents
1404     * the new truncated database. The old database is marked as deleted.
1405     * @deprecated This supports Database.truncate(), which is deprecated.
1406     */

1407    public TruncateResult truncate(Locker locker,
1408                                   DatabaseImpl database)
1409        throws DatabaseException {
1410
1411        return dbMapTree.truncate(locker, database, true);
1412    }
1413
1414    /**
1415     * Truncate a database.
1416     */

1417    public long truncate(Locker locker,
1418                         String JavaDoc databaseName,
1419                         boolean returnCount)
1420        throws DatabaseException {
1421
1422        return dbMapTree.truncate(locker, databaseName, returnCount);
1423    }
1424
1425    /**
1426     * Transactional services.
1427     */

1428    public Txn txnBegin(Transaction parent, TransactionConfig txnConfig)
1429        throws DatabaseException {
1430
1431        if (!isTransactional) {
1432            throw new DatabaseException("beginTransaction called, " +
1433                                        " but Environment was not opened "+
1434                                        "with transactional cpabilities");
1435        }
1436
1437        return txnManager.txnBegin(parent, txnConfig);
1438    }
1439
1440    /* Services. */
1441    public LogManager getLogManager() {
1442        return logManager;
1443    }
1444
1445    public FileManager getFileManager() {
1446        return fileManager;
1447    }
1448
1449    public DbTree getDbMapTree() {
1450        return dbMapTree;
1451    }
1452
1453    /**
1454     * Returns the config manager for the current base configuration.
1455     *
1456     * <p>The configuration can change, but changes are made by replacing the
1457     * config manager object with a enw one. To use a consistent set of
1458     * properties, call this method once and query the returned manager
1459     * repeatedly for each property, rather than getting the config manager via
1460     * this method for each property individually.</p>
1461     */

1462    public DbConfigManager getConfigManager() {
1463        return configManager;
1464    }
1465    
1466    /**
1467     * Clones the current configuration.
1468     */

1469    public EnvironmentConfig cloneConfig() {
1470        return DbInternal.cloneConfig(configManager.getEnvironmentConfig());
1471    }
1472    
1473    /**
1474     * Clones the current mutable configuration.
1475     */

1476    public EnvironmentMutableConfig cloneMutableConfig() {
1477        return DbInternal.cloneMutableConfig
1478        (configManager.getEnvironmentConfig());
1479    }
1480
1481    /**
1482     * Throws an exception if an immutable property is changed.
1483     */

1484    public void checkImmutablePropsForEquality(EnvironmentConfig config)
1485        throws IllegalArgumentException JavaDoc {
1486
1487        DbInternal.checkImmutablePropsForEquality
1488            (configManager.getEnvironmentConfig(), config);
1489    }
1490
1491    /**
1492     * Changes the mutable config properties that are present in the given
1493     * config, and notifies all config observer.
1494     */

1495    public synchronized void setMutableConfig(EnvironmentMutableConfig config)
1496        throws DatabaseException {
1497
1498        /* Clone the current config. */
1499        EnvironmentConfig newConfig =
1500            DbInternal.cloneConfig(configManager.getEnvironmentConfig());
1501
1502        /* Copy in the mutable props. */
1503        DbInternal.copyMutablePropsTo(config, newConfig);
1504
1505        /*
1506         * Update the current config and notify observers. The config manager
1507         * is replaced with a new instance that uses the new configuration.
1508         * This avoid synchronization issues: other threads that have a
1509         * referenced to the old configuration object are not impacted.
1510         *
1511         * Notify listeners in reverse order of registration so that the
1512         * environment listener is notified last and it can start daemon
1513         * threads after they are configured.
1514         */

1515        configManager = new DbConfigManager(newConfig);
1516        for (int i = configObservers.size() - 1; i >= 0; i -= 1) {
1517            EnvConfigObserver o = (EnvConfigObserver) configObservers.get(i);
1518            o.envConfigUpdate(configManager);
1519        }
1520    }
1521
1522    public void setExceptionListener(ExceptionListener exceptionListener) {
1523
1524    this.exceptionListener = exceptionListener;
1525    }
1526
1527    public ExceptionListener getExceptionListener() {
1528    return exceptionListener;
1529    }
1530
1531    /**
1532     * Adds an observer of mutable config changes.
1533     */

1534    public synchronized void addConfigObserver(EnvConfigObserver o) {
1535        configObservers.add(o);
1536    }
1537
1538    /**
1539     * Removes an observer of mutable config changes.
1540     */

1541    public synchronized void removeConfigObserver(EnvConfigObserver o) {
1542        configObservers.remove(o);
1543    }
1544
1545    public INList getInMemoryINs() {
1546        return inMemoryINs;
1547    }
1548
1549    public TxnManager getTxnManager() {
1550        return txnManager;
1551    }
1552
1553    public Checkpointer getCheckpointer() {
1554        return checkpointer;
1555    }
1556
1557    public Cleaner getCleaner() {
1558        return cleaner;
1559    }
1560
1561    public MemoryBudget getMemoryBudget() {
1562        return memoryBudget;
1563    }
1564
1565    /**
1566     * @return environment Logger, for use in debugging output.
1567     */

1568    public Logger JavaDoc getLogger() {
1569        return envLogger;
1570    }
1571
1572    /*
1573     * Verification, must be run while system is quiescent.
1574     */

1575    public boolean verify(VerifyConfig config, PrintStream JavaDoc out)
1576        throws DatabaseException {
1577
1578        /* For now, verify all databases */
1579        return dbMapTree.verify(config, out);
1580    }
1581
1582    public void verifyCursors()
1583        throws DatabaseException {
1584
1585        inCompressor.verifyCursors();
1586    }
1587
1588    /*
1589     * Statistics
1590     */

1591
1592    /**
1593     * Retrieve and return stat information.
1594     */

1595    synchronized public EnvironmentStats loadStats(StatsConfig config)
1596        throws DatabaseException {
1597
1598        EnvironmentStats stats = new EnvironmentStats();
1599        inCompressor.loadStats(config, stats);
1600        evictor.loadStats(config, stats);
1601        checkpointer.loadStats(config, stats);
1602        cleaner.loadStats(config, stats);
1603        logManager.loadStats(config, stats);
1604        memoryBudget.loadStats(config, stats);
1605        return stats;
1606    }
1607
1608    /**
1609     * Retrieve lock statistics
1610     */

1611    synchronized public LockStats lockStat(StatsConfig config)
1612        throws DatabaseException {
1613
1614        return txnManager.lockStat(config);
1615    }
1616
1617    /**
1618     * Retrieve txn statistics
1619     */

1620    synchronized public TransactionStats txnStat(StatsConfig config)
1621        throws DatabaseException {
1622
1623        return txnManager.txnStat(config);
1624    }
1625
1626    public int getINCompressorQueueSize()
1627        throws DatabaseException {
1628
1629        return inCompressor.getBinRefQueueSize();
1630    }
1631
1632    /**
1633     * Info about the last recovery
1634     */

1635    public RecoveryInfo getLastRecoveryInfo() {
1636        return lastRecoveryInfo;
1637    }
1638
1639    /**
1640     * Get the environment home directory.
1641     */

1642    public File JavaDoc getEnvironmentHome() {
1643        return envHome;
1644    }
1645
1646    public long getTxnTimeout() {
1647        return txnTimeout;
1648    }
1649
1650    public long getLockTimeout() {
1651        return lockTimeout;
1652    }
1653
1654    /**
1655     * Returns the shared trigger latch.
1656     */

1657    public SharedLatch getTriggerLatch() {
1658        return triggerLatch;
1659    }
1660
1661    public Evictor getEvictor() {
1662        return evictor;
1663    }
1664
1665    void alertEvictor() {
1666        if (evictor != null) {
1667            evictor.alert();
1668        }
1669    }
1670
1671    /**
1672     * Return true if this environment is part of a replication group.
1673     */

1674    public boolean isReplicated() {
1675        return isReplicated;
1676    }
1677
1678    public ReplicatorInstance getReplicator() {
1679        throw new NotImplementedYetException();
1680    }
1681
1682    public void setReplicator(ReplicatorInstance repInstance) {
1683        this.repInstance = repInstance;
1684    }
1685
1686    /**
1687     * For stress testing. Should only ever be called from an assert.
1688     */

1689    public static boolean maybeForceYield() {
1690        if (forcedYield) {
1691        Thread.yield();
1692    }
1693    return true; // so assert doesn't fire
1694
}
1695}
1696
Popular Tags