[freenet-cvs] r14749 - in trunk/contrib/bdb: . dist src/com/sleepycat/bind/serial src/com/sleepycat/bind/tuple src/com/sleepycat/collections src/com/sleepycat/je src/com/sleepycat/je/cleaner src/com/sleepycat/je/config src/com/sleepycat/je/dbi src/com/sleepycat/je/evictor src/com/sleepycat/je/incomp src/com/sleepycat/je/jca/ra src/com/sleepycat/je/log src/com/sleepycat/je/recovery src/com/sleepycat/je/tree src/com/sleepycat/je/txn src/com/sleepycat/je/util src/com/sleepycat/je/utilint src/com/sleepycat/persist src/com/sleepycat/persist/impl src/com/sleepycat/persist/model test test/com/sleepycat/collections/test test/com/sleepycat/je test/com/sleepycat/je/cleaner test/com/sleepycat/je/dbi test/com/sleepycat/je/evictor test/com/sleepycat/je/test test/com/sleepycat/je/tree test/com/sleepycat/je/txn test/com/sleepycat/persist/test

nextgens at freenetproject.org nextgens at freenetproject.org
Fri Aug 17 14:14:29 UTC 2007


Author: nextgens
Date: 2007-08-17 14:14:29 +0000 (Fri, 17 Aug 2007)
New Revision: 14749

Modified:
   trunk/contrib/bdb/README
   trunk/contrib/bdb/build.properties
   trunk/contrib/bdb/build.xml
   trunk/contrib/bdb/dist/build.properties
   trunk/contrib/bdb/example.properties
   trunk/contrib/bdb/src/com/sleepycat/bind/serial/SerialBinding.java
   trunk/contrib/bdb/src/com/sleepycat/bind/tuple/TupleTupleMarshalledKeyCreator.java
   trunk/contrib/bdb/src/com/sleepycat/collections/CurrentTransaction.java
   trunk/contrib/bdb/src/com/sleepycat/collections/TransactionRunner.java
   trunk/contrib/bdb/src/com/sleepycat/je/Cursor.java
   trunk/contrib/bdb/src/com/sleepycat/je/Database.java
   trunk/contrib/bdb/src/com/sleepycat/je/Environment.java
   trunk/contrib/bdb/src/com/sleepycat/je/EnvironmentStats.java
   trunk/contrib/bdb/src/com/sleepycat/je/JEVersion.java
   trunk/contrib/bdb/src/com/sleepycat/je/SecondaryCursor.java
   trunk/contrib/bdb/src/com/sleepycat/je/cleaner/Cleaner.java
   trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileProcessor.java
   trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileSelector.java
   trunk/contrib/bdb/src/com/sleepycat/je/cleaner/TrackedFileSummary.java
   trunk/contrib/bdb/src/com/sleepycat/je/cleaner/UtilizationProfile.java
   trunk/contrib/bdb/src/com/sleepycat/je/config/BooleanConfigParam.java
   trunk/contrib/bdb/src/com/sleepycat/je/config/EnvironmentParams.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/CursorImpl.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/DatabaseImpl.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/DbTree.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/EnvironmentImpl.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/GetMode.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/MemoryBudget.java
   trunk/contrib/bdb/src/com/sleepycat/je/dbi/SortedLSNTreeWalker.java
   trunk/contrib/bdb/src/com/sleepycat/je/evictor/Evictor.java
   trunk/contrib/bdb/src/com/sleepycat/je/incomp/INCompressor.java
   trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEConnection.java
   trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnection.java
   trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnectionFactory.java
   trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/ra.xml
   trunk/contrib/bdb/src/com/sleepycat/je/log/FileReader.java
   trunk/contrib/bdb/src/com/sleepycat/je/log/INFileReader.java
   trunk/contrib/bdb/src/com/sleepycat/je/log/LatchedLogManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/log/LogManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/log/StatsFileReader.java
   trunk/contrib/bdb/src/com/sleepycat/je/log/SyncedLogManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/recovery/Checkpointer.java
   trunk/contrib/bdb/src/com/sleepycat/je/recovery/RecoveryManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/BIN.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/BINDelta.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/DBIN.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/IN.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/LN.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/MapLN.java
   trunk/contrib/bdb/src/com/sleepycat/je/tree/Tree.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/BasicLocker.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/DummyLockManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/LatchedLockManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/Lock.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/LockInfo.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/LockManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/Locker.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/ReadCommittedLocker.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/SyncedLockManager.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/ThreadLocker.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/Txn.java
   trunk/contrib/bdb/src/com/sleepycat/je/txn/WriteLockInfo.java
   trunk/contrib/bdb/src/com/sleepycat/je/util/DbVerify.java
   trunk/contrib/bdb/src/com/sleepycat/je/utilint/VLSN.java
   trunk/contrib/bdb/src/com/sleepycat/persist/StoreConfig.java
   trunk/contrib/bdb/src/com/sleepycat/persist/impl/PersistCatalog.java
   trunk/contrib/bdb/src/com/sleepycat/persist/impl/PersistEntityBinding.java
   trunk/contrib/bdb/src/com/sleepycat/persist/impl/SimpleCatalog.java
   trunk/contrib/bdb/src/com/sleepycat/persist/impl/Store.java
   trunk/contrib/bdb/src/com/sleepycat/persist/model/AnnotationModel.java
   trunk/contrib/bdb/src/com/sleepycat/persist/model/EntityModel.java
   trunk/contrib/bdb/test/com/sleepycat/collections/test/TransactionTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/DatabaseTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/EnvironmentTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/RunRecoveryFailureTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/cleaner/CleanerTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/cleaner/TruncateAndRemoveTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/dbi/DbCursorDuplicateTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/dbi/DbCursorTestBase.java
   trunk/contrib/bdb/test/com/sleepycat/je/evictor/EvictActionTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/evictor/EvictSelectionTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/test/DeferredWriteTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/test/SecondaryTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/tree/MemorySizeTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/txn/LockManagerTest.java
   trunk/contrib/bdb/test/com/sleepycat/je/txn/LockTest.java
   trunk/contrib/bdb/test/com/sleepycat/persist/test/EvolveClasses.java
   trunk/contrib/bdb/test/com/sleepycat/persist/test/OperationTest.java
   trunk/contrib/bdb/test/je.properties
Log:
freenet-ext: update bdb : je-3.2.23 -> je-3.2.42 (http://download.oracle.com/berkeley-db/je-3.2.42.tar.gz)

Modified: trunk/contrib/bdb/README
===================================================================
--- trunk/contrib/bdb/README	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/README	2007-08-17 14:14:29 UTC (rev 14749)
@@ -1,5 +1,5 @@
-Oracle: Berkeley DB, Java Edition 3.2.23: April 06, 2007
+Oracle: Berkeley DB, Java Edition 3.2.42: August 08, 2007
 
-This is Berkeley DB, Java Edition, version 3.2.23 from
+This is Berkeley DB, Java Edition, version 3.2.42 from
 Oracle.  To view the release and installation documentation, load
 the distribution file docs/index.html into your web browser.
\ No newline at end of file

Modified: trunk/contrib/bdb/build.properties
===================================================================
--- trunk/contrib/bdb/build.properties	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/build.properties	2007-08-17 14:14:29 UTC (rev 14749)
@@ -8,6 +8,9 @@
 # Typical j2ee jar for Sun Java Application Server
 #j2ee.jarfile = c:/j2ee1.4AppServer/lib/j2ee.jar
 
+# Typical j2ee jar for OC4J
+#j2ee.jarfile = <OC4J-HOME>/oc4j/j2ee/home/lib/ejb.jar:<OC4J-HOME>/oc4j/j2ee/home/lib/connector.jar:<OC4J-HOME>/oc4j/j2ee/home/lib/oc4j-internal.jar
+
 ##########################################################################
 # Set example.resources to run the JCA examples.
 ##########################################################################
@@ -15,6 +18,8 @@
 #example.resources = c:/j2ee1.4AppServer/lib/appserv-rt.jar
 # JBOSS
 #example.resources = <jehome>/examples/resources/jboss
+# OC4J
+#example.resources = <OC4J-HOME>/je/examples/resources/oc4j/oc4j.jar
 
 ##########################################################################
 # Set example.jca.srcdir to run the JCA examples.
@@ -23,6 +28,8 @@
 #example.jca.srcdir = <jehome>/examples/jca/jboss
 # SJSAS
 #example.jca.srcdir = <jehome>/examples/jca/sjsas8_1
+# OC4J
+#example.jca.srcdir = <OC4J-HOME>/je/examples/jca/oc4j
 
 ##########################################################################
 # Set example.jca.descriptorname to run the JCA examples.
@@ -31,3 +38,5 @@
 #example.jca.descriptorname = jboss.xml
 # SJSAS
 #example.jca.descriptorname = sun-ejb-jar.xml
+# OC4J
+#example.jca.descriptorname = orion-ejb-jar.xml

Modified: trunk/contrib/bdb/build.xml
===================================================================
--- trunk/contrib/bdb/build.xml	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/build.xml	2007-08-17 14:14:29 UTC (rev 14749)
@@ -391,7 +391,7 @@
              includes="bin/**,lib/**,dist/build.properties"/>
         <zip basedir="${basedir}"
              destfile="src.zip"
-	     excludes="test/rpcserver/**,test/experiments/**,test/regress/*/**,test/**/MiniStress.java,test/**/AbortStress.java,dist/,**/jca/README.txt,examples/com/**,src/com/sleepycat/je/rep/**,examples/je/rep/**,test/com/sleepycat/je/rep/**"
+	     excludes="test/rpcserver/**,test/experiments/**,test/standalone/**,test/regress/*/**,test/**/MiniStress.java,test/**/AbortStress.java,dist/,**/jca/README.txt,examples/com/**,src/com/sleepycat/je/rep/**,examples/je/rep/**,test/com/sleepycat/je/rep/**"
              includes="src/**,examples/**,test/**,docs/**,ant/**,regress/,build.xml,build.properties,example.properties,README,LICENSE,FindBugsExclude.xml"/>
         <zip basedir="${basedir}"
              destfile="${zipfile}"

Modified: trunk/contrib/bdb/dist/build.properties
===================================================================
--- trunk/contrib/bdb/dist/build.properties	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/dist/build.properties	2007-08-17 14:14:29 UTC (rev 14749)
@@ -1,4 +1,4 @@
-release.version=3.2.23
-release.numeric.version=3.2.23
+release.version=3.2.42
+release.numeric.version=3.2.42
 release.major=3
 release.minor=2

Modified: trunk/contrib/bdb/example.properties
===================================================================
--- trunk/contrib/bdb/example.properties	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/example.properties	2007-08-17 14:14:29 UTC (rev 14749)
@@ -297,6 +297,13 @@
 # je.env.checkLeaks=true
 # (mutable at run time: false)
 
+# *** Experimental and not fully tested in 3.2.x. ***
+# If true, enable eviction of metadata for closed databases.
+# The default for JE 3.2.x is false but will be changed to true
+# in JE 3.3 and above.
+# je.env.dbEviction=false
+# (mutable at run time: false)
+
 # If true, use latches instead of synchronized blocks to
 # implement the lock table and log write mutexes. Latches require
 # that threads queue to obtain the mutex in question and

Modified: trunk/contrib/bdb/src/com/sleepycat/bind/serial/SerialBinding.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/bind/serial/SerialBinding.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/bind/serial/SerialBinding.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000,2007 Oracle.  All rights reserved.
  *
- * $Id: SerialBinding.java,v 1.28.2.1 2007/02/01 14:49:38 cwl Exp $
+ * $Id: SerialBinding.java,v 1.28.2.3 2007/06/13 23:01:40 mark Exp $
  */
 
 package com.sleepycat.bind.serial;
@@ -76,15 +76,14 @@
     /**
      * Returns the class loader to be used during deserialization, or null if
      * a default class loader should be used.  The default implementation of
-     * this method returns null.
+     * this method returns
+     * <code>Thread.currentThread().getContextClassLoader()</code> to use the
+     * context class loader for the current thread.
      *
      * <p>This method may be overriden to return a dynamically determined class
-     * loader.  For example,
-     * <code>Thread.currentThread().getContextClassLoader()</code> could be
-     * called to use the context class loader for the curren thread.  Or
-     * <code>getBaseClass().getClassLoader()</code> could be called to use the
-     * class loader for the base class, assuming that a base class has been
-     * specified.</p>
+     * loader.  For example, <code>getBaseClass().getClassLoader()</code> could
+     * be called to use the class loader for the base class, assuming that a
+     * base class has been specified.</p>
      *
      * <p>If this method returns null, a default class loader will be used as
      * determined by the <code>java.io.ObjectInputStream.resolveClass</code>
@@ -92,7 +91,7 @@
      */
     public ClassLoader getClassLoader() {
 
-        return null;
+        return Thread.currentThread().getContextClassLoader();
     }
 
     /**

Modified: trunk/contrib/bdb/src/com/sleepycat/bind/tuple/TupleTupleMarshalledKeyCreator.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/bind/tuple/TupleTupleMarshalledKeyCreator.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/bind/tuple/TupleTupleMarshalledKeyCreator.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000,2007 Oracle.  All rights reserved.
  *
- * $Id: TupleTupleMarshalledKeyCreator.java,v 1.27.2.1 2007/02/01 14:49:39 cwl Exp $
+ * $Id: TupleTupleMarshalledKeyCreator.java,v 1.27.2.2 2007/06/01 21:32:54 mark Exp $
  */
 
 package com.sleepycat.bind.tuple;
@@ -61,7 +61,6 @@
     public boolean nullifyForeignKey(TupleInput dataInput,
                                      TupleOutput dataOutput) {
 
-        // XXX null primary key input below may be unexpected by the binding
         MarshalledTupleKeyEntity entity = (MarshalledTupleKeyEntity)
             binding.entryToObject(null, dataInput);
         if (entity.nullifyForeignKey(keyName)) {

Modified: trunk/contrib/bdb/src/com/sleepycat/collections/CurrentTransaction.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/collections/CurrentTransaction.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/collections/CurrentTransaction.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,11 +3,12 @@
  *
  * Copyright (c) 2000,2007 Oracle.  All rights reserved.
  *
- * $Id: CurrentTransaction.java,v 1.46.2.1 2007/02/01 14:49:39 cwl Exp $
+ * $Id: CurrentTransaction.java,v 1.46.2.2 2007/04/12 16:13:16 mark Exp $
  */
 
 package com.sleepycat.collections;
 
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.WeakHashMap;
@@ -71,10 +72,14 @@
      */
     static CurrentTransaction getInstanceInternal(Environment env) {
         synchronized (envMap) {
-            CurrentTransaction myEnv = (CurrentTransaction) envMap.get(env);
+            CurrentTransaction myEnv = null;
+            WeakReference myEnvRef = (WeakReference) envMap.get(env);
+            if (myEnvRef != null) {
+                myEnv = (CurrentTransaction) myEnvRef.get();
+            }
             if (myEnv == null) {
                 myEnv = new CurrentTransaction(env);
-                envMap.put(env, myEnv);
+                envMap.put(env, new WeakReference(myEnv));
             }
             return myEnv;
         }

Modified: trunk/contrib/bdb/src/com/sleepycat/collections/TransactionRunner.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/collections/TransactionRunner.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/collections/TransactionRunner.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000,2007 Oracle.  All rights reserved.
  *
- * $Id: TransactionRunner.java,v 1.44.2.1 2007/02/01 14:49:40 cwl Exp $
+ * $Id: TransactionRunner.java,v 1.44.2.3 2007/06/01 22:26:53 mark Exp $
  */
 
 package com.sleepycat.collections;
@@ -239,9 +239,9 @@
                         } catch (Throwable e2) {
 
                             /*
-                             * XXX We should really throw a 3rd exception that
-                             * wraps both e and e2, to give the user a complete
-                             * set of error information.
+                             * We print this stack trace so that the
+                             * information is not lost when we throw the
+                             * original exception.
                              */
 			    if (DbCompat.TRANSACTION_RUNNER_PRINT_STACK_TRACES) {
 				e2.printStackTrace();

Modified: trunk/contrib/bdb/src/com/sleepycat/je/Cursor.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/Cursor.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/Cursor.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Cursor.java,v 1.202.2.1 2007/02/01 14:49:41 cwl Exp $
+ * $Id: Cursor.java,v 1.202.2.2 2007/06/13 21:22:17 mark Exp $
  */
 
 package com.sleepycat.je;
@@ -244,12 +244,22 @@
      * Javadoc for this public method is generated via
      * the doc templates in the doc_src directory.
      */
-    public synchronized void close()
+    public void close()
         throws DatabaseException {
 
+        close(true /*releaseNonTxnLocks*/);
+    }
+
+    /**
+     * @param releaseNonTxnLocks should normally be true.  See
+     * CursorImpl.close(boolean) [#15573]
+     */
+    synchronized void close(boolean releaseNonTxnLocks)
+        throws DatabaseException {
+
 	try {
 	    checkState(false);
-	    cursorImpl.close();
+	    cursorImpl.close(releaseNonTxnLocks);
 	    if (dbHandle != null) {
 		dbHandle.removeCursor(this);
 	    }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/Database.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/Database.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/Database.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Database.java,v 1.216.2.1 2007/02/01 14:49:41 cwl Exp $
+ * $Id: Database.java,v 1.216.2.2 2007/07/02 19:54:48 mark Exp $
  */
 
 package com.sleepycat.je;
@@ -280,6 +280,7 @@
 
         if (databaseImpl != null) {
             databaseImpl.removeReferringHandle(this);
+            envHandle.getEnvironmentImpl().releaseDb(databaseImpl);
             databaseImpl = null;
 
             /* 
@@ -1105,6 +1106,14 @@
         envHandle.removeReferringHandle(this);
         if (databaseImpl != null) {
             databaseImpl.removeReferringHandle(this);
+            envHandle.getEnvironmentImpl().releaseDb(databaseImpl);
+
+            /*
+             * Database.close may be called after an abort.  By setting the
+             * databaseImpl field to null we ensure that close won't call
+             * releaseDb or endOperation. [#13415]
+             */
+            databaseImpl = null;
         }
     }
 

Modified: trunk/contrib/bdb/src/com/sleepycat/je/Environment.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/Environment.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/Environment.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Environment.java,v 1.179.2.1 2007/02/01 14:49:41 cwl Exp $
+ * $Id: Environment.java,v 1.179.2.2 2007/07/02 19:54:48 mark Exp $
  */
 
 package com.sleepycat.je;
@@ -402,6 +402,7 @@
         validateDbConfigAgainstEnv(dbConfig, databaseName);
 
         Locker locker = null;
+        DatabaseImpl database = null;
         boolean operationOk = false;
 	boolean dbIsClosing = false;
         try {
@@ -434,12 +435,9 @@
                                    locker.isTransactional();
             }
 
-            DatabaseImpl database = environmentImpl.getDb(locker,
-                                                          databaseName,
-                                                          newDb);
+            database = environmentImpl.getDb(locker, databaseName, newDb);
             boolean databaseExists =
-                (database == null) ? false : 
-                ((database.isDeleted()) ? false : true);
+                (database != null) && !database.isDeleted();
 
             if (databaseExists) {
                 if (dbConfig.getAllowCreate() &&
@@ -452,6 +450,10 @@
 
                 newDb.initExisting(this, locker, database, dbConfig);
             } else {
+                /* Release deleted DB. [#13415] */
+                environmentImpl.releaseDb(database);
+                database = null;
+
                 /* No database. Create if we're allowed to. */
                 if (dbConfig.getAllowCreate()) {
 
@@ -493,6 +495,18 @@
                 locker.setHandleLockOwner(operationOk, newDb, dbIsClosing);
                 locker.operationEnd(operationOk);
             }
+
+            /*
+             * Normally releaseDb will be called when the DB is closed, or by
+             * abort if a transaction is used, or by setHandleLockOwner if a
+             * non-transactional locker is used.  But when the open operation
+             * fails and the Database.databaseImpl field was not initialized,
+             * we must call releaseDb here. [#13415]
+             */
+            if ((!operationOk || dbIsClosing) &&
+                newDb.getDatabaseImpl() == null) {
+                environmentImpl.releaseDb(database);
+            }
         }
     }
 

Modified: trunk/contrib/bdb/src/com/sleepycat/je/EnvironmentStats.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/EnvironmentStats.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/EnvironmentStats.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,12 +3,13 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: EnvironmentStats.java,v 1.43.2.1 2007/02/01 14:49:41 cwl Exp $
+ * $Id: EnvironmentStats.java,v 1.43.2.3 2007/05/23 20:31:05 mark Exp $
  */
 
 package com.sleepycat.je;
 
 import java.io.Serializable;
+import java.text.DecimalFormat;
 
 import com.sleepycat.je.utilint.DbLsn;
 
@@ -241,6 +242,10 @@
     private int  nLogBuffers;    // number of existing log buffers
     private long bufferBytes;    // cache consumed by the log buffers, 
                                  // in bytes
+    private long adminBytes;     // part of cache used by transactions,
+                                 // log cleaning metadata, and other 
+                                 // administrative structures
+    private long lockBytes;      // part of cache used by locks
 
     /*
      * Log activity
@@ -271,6 +276,11 @@
      * chunk size controlled by je.log.iteratorReadSize is too small.
      */
     private long nRepeatIteratorReads;
+
+    /*
+     * Approximation of the total log size in bytes.
+     */
+    private long totalLogSize;
     
     /**
      * Internal use only.
@@ -344,6 +354,7 @@
         nRepeatFaultReads = 0;
 	nTempBufferWrites = 0;
         nRepeatIteratorReads = 0;
+        totalLogSize = 0;
     }
 
     /**
@@ -699,6 +710,23 @@
     }
 
     /**
+     * The number of bytes of JE cache used for holding transaction objects,
+     * log cleaning metadata, and other administrative structures. This is a
+     * subset of cacheDataBytes.
+     */
+    public long getAdminBytes() {
+        return adminBytes;
+    }
+
+    /**
+     * The number of bytes of JE cache used for holding lock objects.
+     * This is a subset of cacheDataBytes.
+     */
+    public long getLockBytes() {
+        return lockBytes;
+    }
+
+    /**
      * Javadoc for this public method is generated via
      * the doc templates in the doc_src directory.
      */
@@ -750,6 +778,14 @@
      * Javadoc for this public method is generated via
      * the doc templates in the doc_src directory.
      */
+    public long getTotalLogSize() {
+        return totalLogSize;
+    }
+
+    /**
+     * Javadoc for this public method is generated via
+     * the doc templates in the doc_src directory.
+     */
     public int getSplitBins() {
         return splitBins;
     }
@@ -764,6 +800,20 @@
     /**
      * Internal use only.
      */
+    public void setAdminBytes(long adminBytes) {
+        this.adminBytes = adminBytes;
+    }
+
+    /**
+     * Internal use only.
+     */
+    public void setLockBytes(long lockBytes) {
+        this.lockBytes = lockBytes;
+    }
+
+    /**
+     * Internal use only.
+     */
     public void setNNotResident(long nNotResident) {
         this.nNotResident = nNotResident;
     }
@@ -1100,6 +1150,13 @@
     /**
      * Internal use only.
      */
+    public void setTotalLogSize(long val) {
+        totalLogSize = val;
+    }
+
+    /**
+     * Internal use only.
+     */
     public void setSplitBins(int val) {
         splitBins = val;
     }
@@ -1109,79 +1166,109 @@
      * the doc templates in the doc_src directory.
      */
     public String toString() {
+        DecimalFormat f = new DecimalFormat("###,###,###,###,###,###,###");
+
         StringBuffer sb = new StringBuffer();
-        sb.append("splitBins=").append(splitBins).append('\n');
-        sb.append("dbClosedBins=").append(dbClosedBins).append('\n');
-        sb.append("cursorsBins=").append(cursorsBins).append('\n');
-        sb.append("nonEmptyBins=").append(nonEmptyBins).append('\n');
-        sb.append("processedBins=").append(processedBins).append('\n');
-        sb.append("inCompQueueSize=").append(inCompQueueSize).append('\n');
+        sb.append("\nCompression stats\n");
+        sb.append("splitBins=").append(f.format(splitBins)).append('\n');
+        sb.append("dbClosedBins=").append(f.format(dbClosedBins)).append('\n');
+        sb.append("cursorsBins=").append(f.format(cursorsBins)).append('\n');
+        sb.append("nonEmptyBins=").append(f.format(nonEmptyBins)).append('\n');
+        sb.append("processedBins=").
+            append(f.format(processedBins)).append('\n');
+        sb.append("inCompQueueSize=").
+            append(f.format(inCompQueueSize)).append('\n');
 
         // Evictor
-        sb.append("nEvictPasses=").append(nEvictPasses).append('\n');
-        sb.append("nNodesSelected=").append(nNodesSelected).append('\n');
-        sb.append("nNodesScanned=").append(nNodesScanned).append('\n');
+        sb.append("\nEviction stats\n");
+        sb.append("nEvictPasses=").append(f.format(nEvictPasses)).append('\n');
+        sb.append("nNodesSelected=").
+            append(f.format(nNodesSelected)).append('\n');
+        sb.append("nNodesScanned=").
+            append(f.format(nNodesScanned)).append('\n');
         sb.append("nNodesExplicitlyEvicted=").
-           append(nNodesExplicitlyEvicted).append('\n');
-        sb.append("nBINsStripped=").append(nBINsStripped).append('\n');
-        sb.append("requiredEvictBytes=").append(requiredEvictBytes).
-            append('\n');
+           append(f.format(nNodesExplicitlyEvicted)).append('\n');
+        sb.append("nBINsStripped=").
+            append(f.format(nBINsStripped)).append('\n');
+        sb.append("requiredEvictBytes=").
+            append(f.format(requiredEvictBytes)).append('\n');
 
         // Checkpointer
-        sb.append("nCheckpoints=").append(nCheckpoints).append('\n');
-        sb.append("lastCheckpointId=").append(lastCheckpointId).append('\n');
-        sb.append("nFullINFlush=").append(nFullINFlush).append('\n');
-        sb.append("nFullBINFlush=").append(nFullBINFlush).append('\n');
-        sb.append("nDeltaINFlush=").append(nDeltaINFlush).append('\n');
+        sb.append("\nCheckpoint stats\n");
+        sb.append("nCheckpoints=").append(f.format(nCheckpoints)).append('\n');
+        sb.append("lastCheckpointId=").
+            append(f.format(lastCheckpointId)).append('\n');
+        sb.append("nFullINFlush=").append(f.format(nFullINFlush)).append('\n');
+        sb.append("nFullBINFlush=").
+            append(f.format(nFullBINFlush)).append('\n');
+        sb.append("nDeltaINFlush=").
+            append(f.format(nDeltaINFlush)).append('\n');
         sb.append("lastCheckpointStart=").
            append(DbLsn.getNoFormatString(lastCheckpointStart)).append('\n');
         sb.append("lastCheckpointEnd=").
            append(DbLsn.getNoFormatString(lastCheckpointEnd)).append('\n');
 
         // Cleaner
-        sb.append("cleanerBacklog=").append(cleanerBacklog).append('\n');
-        sb.append("nCleanerRuns=").append(nCleanerRuns).append('\n');
-        sb.append("nCleanerDeletions=").append(nCleanerDeletions).append('\n');
-        sb.append("nINsObsolete=").append(nINsObsolete).append('\n');
-        sb.append("nINsCleaned=").append(nINsCleaned).append('\n');
-        sb.append("nINsDead=").append(nINsDead).append('\n');
-        sb.append("nINsMigrated=").append(nINsMigrated).append('\n');
-        sb.append("nLNsObsolete=").append(nLNsObsolete).append('\n');
-        sb.append("nLNsCleaned=").append(nLNsCleaned).append('\n');
-        sb.append("nLNsDead=").append(nLNsDead).append('\n');
-        sb.append("nLNsLocked=").append(nLNsLocked).append('\n');
-        sb.append("nLNsMigrated=").append(nLNsMigrated).append('\n');
-        sb.append("nLNsMarked=").append(nLNsMarked).append('\n');
+        sb.append("\nCleaner stats\n");
+        sb.append("cleanerBacklog=").
+            append(f.format(cleanerBacklog)).append('\n');
+        sb.append("nCleanerRuns=").
+            append(f.format(nCleanerRuns)).append('\n');
+        sb.append("nCleanerDeletions=").
+            append(f.format(nCleanerDeletions)).append('\n');
+        sb.append("nINsObsolete=").append(f.format(nINsObsolete)).append('\n');
+        sb.append("nINsCleaned=").append(f.format(nINsCleaned)).append('\n');
+        sb.append("nINsDead=").append(f.format(nINsDead)).append('\n');
+        sb.append("nINsMigrated=").append(f.format(nINsMigrated)).append('\n');
+        sb.append("nLNsObsolete=").append(f.format(nLNsObsolete)).append('\n');
+        sb.append("nLNsCleaned=").append(f.format(nLNsCleaned)).append('\n');
+        sb.append("nLNsDead=").append(f.format(nLNsDead)).append('\n');
+        sb.append("nLNsLocked=").append(f.format(nLNsLocked)).append('\n');
+        sb.append("nLNsMigrated=").append(f.format(nLNsMigrated)).append('\n');
+        sb.append("nLNsMarked=").append(f.format(nLNsMarked)).append('\n');
         sb.append("nLNQueueHits=").
-            append(nLNQueueHits).append('\n');
+            append(f.format(nLNQueueHits)).append('\n');
         sb.append("nPendingLNsProcessed=").
-            append(nPendingLNsProcessed).append('\n');
+            append(f.format(nPendingLNsProcessed)).append('\n');
         sb.append("nMarkedLNsProcessed=").
-            append(nMarkedLNsProcessed).append('\n');
+            append(f.format(nMarkedLNsProcessed)).append('\n');
         sb.append("nToBeCleanedLNsProcessed=").
-            append(nToBeCleanedLNsProcessed).append('\n');
+            append(f.format(nToBeCleanedLNsProcessed)).append('\n');
         sb.append("nClusterLNsProcessed=").
-            append(nClusterLNsProcessed).append('\n');
+            append(f.format(nClusterLNsProcessed)).append('\n');
         sb.append("nPendingLNsLocked=").
-            append(nPendingLNsLocked).append('\n');
+            append(f.format(nPendingLNsLocked)).append('\n');
         sb.append("nCleanerEntriesRead=").
-           append(nCleanerEntriesRead).append('\n');
+            append(f.format(nCleanerEntriesRead)).append('\n');
 
         // Cache
-        sb.append("nNotResident=").append(nNotResident).append('\n');
-        sb.append("nCacheMiss=").append(nCacheMiss).append('\n');
-        sb.append("nLogBuffers=").append(nLogBuffers).append('\n');
-        sb.append("bufferBytes=").append(bufferBytes).append('\n');
-        sb.append("cacheDataBytes=").append(cacheDataBytes).append('\n');
-        sb.append("cacheTotalBytes=").append(getCacheTotalBytes()).
-            append('\n');
-        sb.append("nFSyncs=").append(nFSyncs).append('\n');
-        sb.append("nFSyncRequests=").append(nFSyncRequests).append('\n');
-        sb.append("nFSyncTimeouts=").append(nFSyncTimeouts).append('\n');
-        sb.append("nRepeatFaultReads=").append(nRepeatFaultReads).append('\n');
-        sb.append("nTempBufferWrite=").append(nTempBufferWrites).append('\n');
+        sb.append("\nCache stats\n");
+        sb.append("nNotResident=").append(f.format(nNotResident)).append('\n');
+        sb.append("nCacheMiss=").append(f.format(nCacheMiss)).append('\n');
+        sb.append("nLogBuffers=").append(f.format(nLogBuffers)).append('\n');
+        sb.append("bufferBytes=").append(f.format(bufferBytes)).append('\n');
+        sb.append("cacheDataBytes=").
+            append(f.format(cacheDataBytes)).append('\n');
+        sb.append("adminBytes=").append(f.format(adminBytes)).append('\n');
+        sb.append("lockBytes=").append(f.format(lockBytes)).append('\n');
+        sb.append("cacheTotalBytes=").
+            append(f.format(getCacheTotalBytes())).append('\n');
+
+        // Logging
+        sb.append("\nLogging stats\n");
+        sb.append("nFSyncs=").append(f.format(nFSyncs)).append('\n');
+        sb.append("nFSyncRequests=").
+            append(f.format(nFSyncRequests)).append('\n');
+        sb.append("nFSyncTimeouts=").
+            append(f.format(nFSyncTimeouts)).append('\n');
+        sb.append("nRepeatFaultReads=").
+            append(f.format(nRepeatFaultReads)).append('\n');
+        sb.append("nTempBufferWrite=").
+            append(f.format(nTempBufferWrites)).append('\n');
         sb.append("nRepeatIteratorReads=").
-            append(nRepeatIteratorReads).append('\n');
+            append(f.format(nRepeatIteratorReads)).append('\n');
+        sb.append("totalLogSize=").
+            append(f.format(totalLogSize)).append('\n');
 
         return sb.toString();
     }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/JEVersion.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/JEVersion.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/JEVersion.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: JEVersion.java,v 1.93.2.9 2007/04/04 14:27:33 cwl Exp $
+ * $Id: JEVersion.java,v 1.93.2.20 2007/08/06 16:43:22 cwl Exp $
  */
 
 package com.sleepycat.je;
@@ -19,7 +19,7 @@
      * the doc templates in the doc_src directory.
      */
     public static final JEVersion CURRENT_VERSION =
-        new JEVersion(3, 2, 23, null);
+        new JEVersion(3, 2, 42, null);
     
     private int majorNum;
     private int minorNum;

Modified: trunk/contrib/bdb/src/com/sleepycat/je/SecondaryCursor.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/SecondaryCursor.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/SecondaryCursor.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: SecondaryCursor.java,v 1.35.2.1 2007/02/01 14:49:41 cwl Exp $
+ * $Id: SecondaryCursor.java,v 1.35.2.2 2007/06/13 21:22:17 mark Exp $
  */
 
 package com.sleepycat.je;
@@ -704,7 +704,12 @@
         Locker locker = cursorImpl.getLocker();
         Cursor cursor = null;
         try {
-	    cursor = new Cursor(primaryDb, locker, null);
+
+            /*
+             * Use Cursor constructor with DatabaseImpl parameter so that the
+             * non-transactional locker is used in the primary cursor. [#15573]
+             */
+	    cursor = new Cursor(primaryDb.getDatabaseImpl(), locker, null);
             OperationStatus status =
                 cursor.search(pKey, data, lockMode, SearchMode.SET);
             if (status != OperationStatus.SUCCESS) {
@@ -779,8 +784,14 @@
             }
             return OperationStatus.SUCCESS;
         } finally {
+
+            /*
+             * Do not release non-transactional locks when closing the primary
+             * cursor.  They are held until all locks for this operation are
+             * released by the secondary cursor.  [#15573]
+             */
             if (cursor != null) {
-                cursor.close();
+                cursor.close(false /*releaseNonTxnLocks*/);
             }
         }
     }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/cleaner/Cleaner.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/cleaner/Cleaner.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/cleaner/Cleaner.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Cleaner.java,v 1.183.2.2 2007/03/08 22:32:53 mark Exp $
+ * $Id: Cleaner.java,v 1.183.2.5 2007/07/02 19:54:48 mark Exp $
  */
 
 package com.sleepycat.je.cleaner;
@@ -405,6 +405,7 @@
         stat.setNPendingLNsLocked(nPendingLNsLocked);
         stat.setNCleanerEntriesRead(nEntriesRead);
         stat.setNRepeatIteratorReads(nRepeatIteratorReads);
+        stat.setTotalLogSize(profile.getTotalLogSize());
         
         if (config.getClear()) {
             nCleanerRuns = 0;
@@ -430,6 +431,13 @@
         }
     }
 
+    /**
+     * For unit testing.
+     */
+    void injectFileForCleaning(Long fileNum) {
+        fileSelector.putBackFileForCleaning(fileNum);
+    }
+
     /** 
      * Deletes all files that are safe-to-delete, if there are no read/only
      * processes and concurrent backups.
@@ -632,19 +640,23 @@
 
                 DatabaseId dbId = info.getDbId();
                 DatabaseImpl db = dbMapTree.getDb(dbId, lockTimeout);
+                try {
+                    byte[] key = info.getKey();
+                    byte[] dupKey = info.getDupKey();
+                    LN ln = info.getLN();
 
-                byte[] key = info.getKey();
-                byte[] dupKey = info.getDupKey();
-                LN ln = info.getLN();
+                    /* Evict before processing each entry. */
+                    if (DO_CRITICAL_EVICTION) {
+                        env.getEvictor().
+                            doCriticalEviction(true); // backgroundIO
+                    }
 
-                /* Evict before processing each entry. */
-                if (DO_CRITICAL_EVICTION) {
-                    env.getEvictor().doCriticalEviction(true); // backgroundIO
+                    processPendingLN
+                        (ln, db, key, dupKey, location);
+                } finally {
+                    dbMapTree.releaseDb(db);
                 }
 
-                processPendingLN
-                    (ln, db, key, dupKey, location);
-
                 /* Sleep if background read/write limit was exceeded. */
                 env.sleepAfterBackgroundIO();
             }
@@ -655,8 +667,12 @@
             for (int i = 0; i < pendingDBs.length; i += 1) {
                 DatabaseId dbId = pendingDBs[i];
                 DatabaseImpl db = dbMapTree.getDb(dbId, lockTimeout);
-                if (db == null || db.isDeleteFinished()) {
-                    fileSelector.removePendingDB(dbId);
+                try {
+                    if (db == null || db.isDeleteFinished()) {
+                        fileSelector.removePendingDB(dbId);
+                    }
+                } finally {
+                    dbMapTree.releaseDb(db);
                 }
             }
         }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileProcessor.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileProcessor.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileProcessor.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: FileProcessor.java,v 1.17.2.1 2007/02/01 14:49:42 cwl Exp $
+ * $Id: FileProcessor.java,v 1.17.2.6 2007/07/02 19:54:48 mark Exp $
  */
 
 package com.sleepycat.je.cleaner;
@@ -25,6 +25,7 @@
 import com.sleepycat.je.dbi.EnvironmentImpl;
 import com.sleepycat.je.dbi.MemoryBudget;
 import com.sleepycat.je.log.CleanerFileReader;
+import com.sleepycat.je.log.LogFileNotFoundException;
 import com.sleepycat.je.tree.BIN;
 import com.sleepycat.je.tree.ChildReference;
 import com.sleepycat.je.tree.DIN;
@@ -239,6 +240,7 @@
              */
             resetPerRunCounters();
             boolean finished = false;
+            boolean fileDeleted = false;
             long fileNumValue = fileNum.longValue();
             int runId = ++cleaner.nCleanerRuns;
             try {
@@ -261,11 +263,28 @@
                     accumulatePerRunCounters();
                     finished = true;
                 }
-            } catch (IOException IOE) {
-                Tracer.trace(env, "Cleaner", "doClean", "", IOE);
-                throw new DatabaseException(IOE);
+            } catch (LogFileNotFoundException e) {
+
+                /*
+                 * File was deleted.  Although it is possible that the file was
+                 * deleted externally it is much more likely that the file was
+                 * deleted normally after being cleaned earlier (this was
+                 * observed prior to JE 3.2.29), and that we are mistakedly
+                 * processing the file repeatedly.  Since the file does not
+                 * exist, ignore the error so that the cleaner will continue.
+                 * The tracing below will indicate that the file was deleted.
+                 * Remove the file completely from the FileSelector and
+                 * UtilizationProfile so that we don't repeatedly attempt to
+                 * process it. [#15528]
+                 */
+                fileDeleted = true;
+                profile.removeFile(fileNum);
+                fileSelector.removeAllFileReferences(fileNum);
+            } catch (IOException e) {
+                Tracer.trace(env, "Cleaner", "doClean", "", e);
+                throw new DatabaseException(e);
             } finally {
-                if (!finished) {
+                if (!finished && !fileDeleted) {
                     fileSelector.putBackFileForCleaning(fileNum);
                 }
                 String traceMsg =
@@ -273,6 +292,7 @@
                     " on file 0x" + Long.toHexString(fileNumValue) + 
                     " invokedFromDaemon=" + invokedFromDaemon +
                     " finished=" + finished +
+                    " fileDeleted=" + fileDeleted +
                     " nEntriesRead=" + nEntriesReadThisRun +
                     " nINsObsolete=" + nINsObsoleteThisRun +
                     " nINsCleaned=" + nINsCleanedThisRun +
@@ -370,8 +390,13 @@
          */
         Set checkPendingDbSet = new HashSet();
 
-        /* Use local caching to reduce DbTree.getDb overhead. */
+        /*
+         * Use local caching to reduce DbTree.getDb overhead.  Do not call
+         * releaseDb after getDb with the dbCache, since the entire dbCache
+         * will be released at the end of thie method.
+         */
         Map dbCache = new HashMap();
+        DbTree dbMapTree = env.getDbMapTree();
 
         try {
             /* Create the file reader. */
@@ -380,7 +405,6 @@
             /* Validate all entries before ever deleting a file. */
             reader.setAlwaysValidateChecksum(true);
 
-            DbTree dbMapTree = env.getDbMapTree();
             TreeLocation location = new TreeLocation();
 
             int nProcessedLNs = 0;
@@ -507,7 +531,6 @@
                     DatabaseImpl db = dbMapTree.getDb
                         (dbId, cleaner.lockTimeout, dbCache);
                     targetIN.setDatabase(db);
-                    
                     processIN(targetIN, db, logLsn, deferredWriteDbs);
                     
                 } else if (isRoot) {
@@ -545,6 +568,9 @@
             /* Subtract the overhead of this method from the budget. */
             budget.updateMiscMemoryUsage(0 - adjustMem);
 
+            /* Release all cached DBs. */
+            dbMapTree.releaseDbs(dbCache);
+
             /* Allow flushing of TFS when cleaning is complete. */
             if (tfs != null) {
                 tfs.setAllowFlush(true);
@@ -579,6 +605,10 @@
         long logLsn = DbLsn.makeLsn
             (fileNum.longValue(), offset.longValue());
 
+        /*
+         * Do not call releaseDb after this getDb, since the entire dbCache
+         * will be released later.
+         */
         DatabaseImpl db = env.getDbMapTree().getDb
             (info.getDbId(), cleaner.lockTimeout, dbCache);
 
@@ -1010,15 +1040,11 @@
             long treeLsn = result.parent.getLsn(result.index);
 
             /* 
-             * Any entry that is in the log should not have a NULL_LSN in the
-             * in-memory tree, even for a deferred write database. The 
-             * in-memory tree should always have a lsn that shows the last 
-             * on-disk version.
+             * The IN in the tree is a never-written IN for a DW db so the IN
+	     * in the file is obsolete. [#15588]
              */
             if (treeLsn == DbLsn.NULL_LSN) {
-                throw new DatabaseException
-                    ("Deferred Write IN should not have a NULL_LSN " +
-                     " logLsn=" + DbLsn.getNoFormatString(logLsn));
+		return null;
             }
  
             int compareVal = DbLsn.compareTo(treeLsn, logLsn);
@@ -1106,10 +1132,12 @@
                 return null;
             }
 
-            /* bozo, how can the root's lsn be less that the logLsn?
-               This may have been an artifact of when we didn't properly
-               propagate the logging of the rootIN up to the root
-               ChildReference. Remove? */
+            /*
+             * A root LSN less than the log LSN must be an artifact of when we
+             * didn't properly propagate the logging of the rootIN up to the
+             * root ChildReference.  We still do this for compatibility with
+             * old log versions but may be able to remove it in the future.
+             */
             if (DbLsn.compareTo(root.getLsn(), logLsn) <= 0) {
                 IN rootIN = (IN) root.fetchTarget(db, null);
                 rootIN.latch(Cleaner.UPDATE_GENERATION);
@@ -1171,16 +1199,6 @@
     }
 
     /**
-     * XXX: Was this intended to override Thread.toString()?  If so it no
-     * longer does, because we separated Thread from DaemonThread.
-     */
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("<Cleaner name=\"").append(name).append("\"/>");
-        return sb.toString();
-    }
-
-    /**
      * A cache of LNInfo by LSN offset.  Used to hold a set of LNs that are
      * to be processed.  Keeps track of memory used, and when full (over
      * budget) the next offset should be queried and removed.

Modified: trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileSelector.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileSelector.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/cleaner/FileSelector.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: FileSelector.java,v 1.15.2.1 2007/02/01 14:49:42 cwl Exp $
+ * $Id: FileSelector.java,v 1.15.2.2 2007/05/31 21:55:32 mark Exp $
  */
 
 package com.sleepycat.je.cleaner;
@@ -253,6 +253,18 @@
     }
 
     /**
+     * Removes all references to a file.
+     */
+    synchronized void removeAllFileReferences(Long file) {
+        toBeCleanedFiles.remove(file);
+        beingCleanedFiles.remove(file);
+        cleanedFiles.remove(file);
+        checkpointedFiles.remove(file);
+        fullyProcessedFiles.remove(file);
+        safeToDeleteFiles.remove(file);
+    }
+
+    /**
      * When file cleaning is aborted, move the file back from the being-cleaned
      * set to the to-be-cleaned set.
      */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/cleaner/TrackedFileSummary.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/cleaner/TrackedFileSummary.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/cleaner/TrackedFileSummary.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: TrackedFileSummary.java,v 1.9.2.1 2007/02/01 14:49:42 cwl Exp $
+ * $Id: TrackedFileSummary.java,v 1.9.2.2 2007/05/15 14:48:39 mark Exp $
  */
 
 package com.sleepycat.je.cleaner;
@@ -124,10 +124,12 @@
         add(other);
 
         /*
-         * Add the offsets.  The memory budget has already been updated for the
-         * offsets to be added, so we only need to account for a difference
-         * when we merge them.
+         * Add the offsets and the memory used [#15505] by the other tracker.
+         * The memory budget has already been updated for the offsets to be
+         * added, so we only need to account for a possible difference of one
+         * segment when we merge them.
          */
+        memSize += other.memSize;
         if (other.obsoleteOffsets != null) {
             if (obsoleteOffsets != null) {
                 /* Merge the other offsets into our list. */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/cleaner/UtilizationProfile.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/cleaner/UtilizationProfile.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/cleaner/UtilizationProfile.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: UtilizationProfile.java,v 1.52.2.2 2007/03/07 00:40:24 mark Exp $
+ * $Id: UtilizationProfile.java,v 1.52.2.7 2007/07/02 19:54:48 mark Exp $
  */
 
 package com.sleepycat.je.cleaner;
@@ -95,6 +95,7 @@
     private SortedMap fileSummaryMap;   // cached fileNum -> FileSummary
     private boolean cachePopulated;
     private boolean rmwFixEnabled;
+    private long totalLogSize;
 
     /**
      * Minimum overall utilization threshold that triggers cleaning.  Is
@@ -176,6 +177,29 @@
     }
 
     /**
+     * Returns an approximation of the total log size.  Used for stats.
+     */
+    long getTotalLogSize() {
+
+        /* Start with the size known to the profile. */
+        long size = totalLogSize;
+
+        /*
+         * Add sizes that are known to the tracker but are not yet in the
+         * profile.  The FileSummary.totalSize field is the delta for new
+         * log entries added.  Typically the last log file is only one that
+         * will have a delta, but previous files may also not have been added
+         * to the profile yet.
+         */
+        TrackedFileSummary[] trackedFiles = tracker.getTrackedFiles();
+        for (int i = 0; i < trackedFiles.length; i += 1) {
+            size += trackedFiles[i].totalSize;
+        }
+
+        return size;
+    }
+
+    /**
      * Returns the cheapest file to clean from the given list of files.  This
      * method is used to select the first file to be cleaned in the batch of
      * to-be-cleaned files.
@@ -582,10 +606,13 @@
             assert cachePopulated;
 
             /* Remove from the cache. */
-            if (fileSummaryMap.remove(fileNum) != null) {
+            FileSummary oldSummary =
+                (FileSummary) fileSummaryMap.remove(fileNum);
+            if (oldSummary != null) {
                 MemoryBudget mb = env.getMemoryBudget();
                 mb.updateMiscMemoryUsage
                     (0 - MemoryBudget.UTILIZATION_PROFILE_ENTRY);
+                totalLogSize -= oldSummary.totalSize;
             }
         }
 
@@ -711,14 +738,29 @@
 
             /*
              * An obsolete node may have been counted after its file was
-             * deleted, for example, when compressing a BIN.  Do not insert
-             * a new profile record if no corresponding log file exists.
+             * deleted, for example, when compressing a BIN.  Do not insert a
+             * new profile record if no corresponding log file exists.  But if
+             * the file number is greater than the last known file, this is a
+             * new file that has been buffered but not yet flushed to disk; in
+             * that case we should insert a new profile record.
              */
-            File file = new File
-                (env.getFileManager().getFullFileName
-                    (fileNum, FileManager.JE_SUFFIX));
-            if (!file.exists()) {
-                return null;
+            if (!fileSummaryMap.isEmpty() &&
+                fileNum < ((Long) fileSummaryMap.lastKey()).longValue()) {
+                File file = new File
+                    (env.getFileManager().getFullFileName
+                        (fileNum, FileManager.JE_SUFFIX));
+                if (!file.exists()) {
+
+                    /*
+                     * File was deleted by the cleaner.  Remove it from the
+                     * UtilizationTracker and return.  Note that a file is
+                     * normally removed from the tracker by
+                     * FileSummaryLN.writeToLog method when it is called via
+                     * insertFileSummary below. [#15512]
+                     */
+                    env.getLogManager().removeTrackedFile(tfs);
+                    return null;
+                }
             }
 
             summary = new FileSummary();
@@ -732,6 +774,7 @@
         FileSummary tmp = new FileSummary();
         tmp.add(summary);
         tmp.add(tfs);
+        totalLogSize += tfs.totalSize;
         int sequence = tmp.getEntriesCounted();
 
         /* Insert an LN with the existing and tracked summary info. */
@@ -898,6 +941,8 @@
         int oldMemorySize = fileSummaryMap.size() *
             MemoryBudget.UTILIZATION_PROFILE_ENTRY;
 
+        totalLogSize = 0;
+
         /*
          * It is possible to have an undeleted FileSummaryLN in the database
          * for a deleted log file if we crash after deleting a file but before
@@ -959,7 +1004,9 @@
                     if (Arrays.binarySearch(existingFiles, fileNumLong) >= 0) {
 
                         /* File exists, cache the FileSummaryLN. */
-                        fileSummaryMap.put(fileNumLong, ln.getBaseSummary());
+                        FileSummary summary = ln.getBaseSummary();
+                        fileSummaryMap.put(fileNumLong, summary);
+                        totalLogSize += summary.totalSize;
 
                         /*
                          * Update old version records to the new version.  A
@@ -1101,6 +1148,12 @@
         boolean operationOk = false;
         try {
             autoTxn = new AutoTxn(env, new TransactionConfig());
+
+            /*
+             * releaseDb is not called after this getDb or createDb because we
+             * want to prohibit eviction of this database until the environment
+             * is closed.
+             */
             DatabaseImpl db = dbTree.getDb
                 (autoTxn, DbTree.UTILIZATION_DB_NAME, null);
             if (db == null) {
@@ -1256,20 +1309,21 @@
         DatabaseId dbId = entry.getDbId();
         DatabaseImpl db = env.getDbMapTree().getDb(dbId);
 
-        /* 
-         * The whole database is gone, so this LN is obsolete. No need
-         * to worry about delete cleanup; this is just verification and
-         * no cleaning is done.
-         */
-        if (db == null || db.isDeleted()) {
-            return true;
-        }
-
         /*
          * Search down to the bottom most level for the parent of this LN.
          */
         BIN bin = null;
         try {
+
+            /* 
+             * The whole database is gone, so this LN is obsolete. No need
+             * to worry about delete cleanup; this is just verification and
+             * no cleaning is done.
+             */
+            if (db == null || db.isDeleted()) {
+                return true;
+            }
+
             Tree tree = db.getTree();
             TreeLocation location = new TreeLocation();
             boolean parentFound = tree.getParentBINForChildLN
@@ -1307,6 +1361,7 @@
                                " was found in tree."); 
             return false;
         } finally {
+            env.getDbMapTree().releaseDb(db);
             if (bin != null) {
                 bin.releaseLatch();
             }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/config/BooleanConfigParam.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/config/BooleanConfigParam.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/config/BooleanConfigParam.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: BooleanConfigParam.java,v 1.25.2.1 2007/02/01 14:49:43 cwl Exp $
+ * $Id: BooleanConfigParam.java,v 1.25.2.2 2007/06/04 17:03:30 linda Exp $
  */
 
 package com.sleepycat.je.config;
@@ -20,7 +20,7 @@
      * Set a boolean parameter w/default.
      * @param configName
      * @param defaultValue
-     * @param forReplication TODO
+     * @param forReplication true if param is only used for replication
      */
     BooleanConfigParam(String configName,
                        boolean defaultValue,

Modified: trunk/contrib/bdb/src/com/sleepycat/je/config/EnvironmentParams.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/config/EnvironmentParams.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/config/EnvironmentParams.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: EnvironmentParams.java,v 1.84.2.3 2007/03/07 01:24:35 mark Exp $
+ * $Id: EnvironmentParams.java,v 1.84.2.4 2007/07/02 19:54:49 mark Exp $
  */
 
 package com.sleepycat.je.config;
@@ -207,6 +207,16 @@
                                false,            // mutable
                                false,            // forReplication
      "# If true, use shared latches for Internal Nodes (INs).\n");
+    
+    public static final BooleanConfigParam ENV_DB_EVICTION =
+        new BooleanConfigParam("je.env.dbEviction",
+                               false,            // default
+                               false,            // mutable
+                               false,            // forReplication
+     "# *** Experimental and not fully tested in 3.2.x. ***\n" +
+     "# If true, enable eviction of metadata for closed databases.\n" +
+     "# The default for JE 3.2.x is false but will be changed to true\n" +
+     "# in JE 3.3 and above.");
 
     public static final IntConfigParam ADLER32_CHUNK_SIZE =
         new IntConfigParam("je.adler32.chunkSize",

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/CursorImpl.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/CursorImpl.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/CursorImpl.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: CursorImpl.java,v 1.320.2.1 2007/02/01 14:49:44 cwl Exp $
+ * $Id: CursorImpl.java,v 1.320.2.3 2007/06/13 21:22:17 mark Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -646,10 +646,26 @@
     }
 
     /**
+     * Close a cursor with releaseNonTxnLocks=true.
+     */
+    public void close()
+        throws DatabaseException {
+
+        close(true /*releaseNonTxnLocks*/);
+    }
+
+    /**
      * Close a cursor.
+     *
+     * @param releaseNonTxnLocks should normally be true to release
+     * non-transactional locks when a cursor is closed.  However, some
+     * operations may wish to hold non-transactional locks if the locker is
+     * re-used in another cursor.  For example, see
+     * SecondaryCursor.readPrimaryAfterGet. [#15573]
+     *
      * @throws DatabaseException if the cursor was previously closed.
      */
-    public void close()
+    public void close(boolean releaseNonTxnLocks)
         throws DatabaseException {
 
         assert assertCursorState(false) : dumpToString(true);
@@ -657,7 +673,7 @@
         removeCursor();
         locker.unRegisterCursor(this);
 
-        if (!retainNonTxnLocks) {
+        if (releaseNonTxnLocks && !retainNonTxnLocks) {
             locker.releaseNonTxnLocks();
         }
 
@@ -1178,10 +1194,16 @@
 		/* Check that data compares equal before replacing it. */
 		boolean keysEqual = false;
 
+                /*
+                 * Do not use a custom duplicate comaprator here because we do
+                 * not support replacing the data if it is different, even if
+                 * the custom comparator considers it equal.  If we were to
+                 * support this we would have to update the key in the BIN
+                 * slot. [#15527]
+                 */
 		if (foundDataBytes != null) {
-                    keysEqual = Key.compareKeys
-                        (foundDataBytes, newData,
-			 database.getDuplicateComparator()) == 0;
+                    keysEqual =
+                        Key.compareKeys(foundDataBytes, newData, null) == 0;
 		}
 
 		if (!keysEqual) {

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/DatabaseImpl.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/DatabaseImpl.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/DatabaseImpl.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: DatabaseImpl.java,v 1.157.2.5 2007/03/09 17:37:09 linda Exp $
+ * $Id: DatabaseImpl.java,v 1.157.2.7 2007/07/02 19:54:49 mark Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -92,6 +92,7 @@
     private BtreeStats stats;     // most recent btree stats w/ !DB_FAST_STAT
     private long eofNodeId;       // Logical EOF node for range locking
     private short deleteState;    // one of four delete states.
+    private int useCount = 0;     // If non-zero, eviction is prohibited
 
     /*
      * The user defined Btree and duplicate comparison functions, if specified.
@@ -220,13 +221,20 @@
     }
 
     /**
-     * Clone.  For now just pass off to the super class for a field-by-field
-     * copy.
+     * Clone.  For the most part, just pass off to the super class for a
+     * field-by-field copy.
      */
-    public Object clone()
-        throws CloneNotSupportedException {
+    public DatabaseImpl cloneDb()
+        throws DatabaseException {
 
-        return super.clone();
+        try {
+            DatabaseImpl newDb = (DatabaseImpl) clone();
+            /* The cloned DB could have a non-zero use count. [#13415] */
+            newDb.useCount = 0;
+            return newDb;
+	} catch (CloneNotSupportedException e) {
+	    throw new DatabaseException(e);
+        }
     }
 
     /**
@@ -436,6 +444,69 @@
     }
 
     /**
+     * Increments the use count of this DB to prevent it from being
+     * evicted.  Called by the DbTree.createDb/getDb methods that return a
+     * DatabaseImpl.  Must be called while holding a lock on the MapLN. See
+     * isInUse. [#13415]
+     */
+    void incrementUseCount() {
+        if (envImpl.getDbEviction()) {
+            /* Synchronize to update useCount atomically. */
+            synchronized (this) {
+                useCount += 1;
+            }
+        }
+    }
+
+    /**
+     * Decrements the use count of this DB, allowing it to be evicted if the
+     * use count reaches zero.  Called via DbTree.releaseDb to release a
+     * DatabaseImpl that was returned by a DbTree.createDb/getDb method. See
+     * isInUse. [#13415]
+     */
+    void decrementUseCount() {
+        if (envImpl.getDbEviction()) {
+            /* Synchronize to update useCount atomically. */
+            synchronized (this) {
+                assert useCount > 0;
+                useCount -= 1;
+            }
+        }
+    }
+
+    /**
+     * Returns whether this DB is in use and cannot be evicted.  Called by
+     * MapLN.isEvictable while holding a write-lock on the MapLN and a latch on
+     * its parent BIN. [#13415]
+     *
+     * When isInUse returns false (while holding a write-lock on the MapLN and
+     * a latch on the parent BIN), it guarantees that the database object
+     * is not in use and cannot be acquired by another thread (via
+     * DbTree.createDb/getDb) until both the MapLN lock and BIN latch are
+     * released.  This guarantee is due to the fact that DbTree.createDb/getDb
+     * only increment the use count while holding a read-lock on the MapLN.
+     * Therefore, it is safe to evict the MapLN when isInUse returns false.
+     *
+     * When isInUse returns true, it is possible that another thread may
+     * decrement the use count at any time, since no locking or latching is
+     * performed when calling DbTree.releaseDb (which calls decrementUseCount).
+     * Therefore, it is not guaranteed that the MapLN is in use when isInUse
+     * returns true.  A true result means: the DB may be in use, so it is not
+     * safe to evict it.
+     */
+    public boolean isInUse() {
+        if (envImpl.getDbEviction()) {
+            /* Synchronize to read the up-to-date value of useCount. */
+            synchronized (this) {
+                return (useCount > 0);
+            }
+        } else {
+            /* Always prohibit eviction when je.env.dbEviction=false. */
+            return true;
+        }
+    }
+
+    /**
      * Flush all dirty nodes for this database to disk.
      */
     public synchronized void sync(boolean flushLog) 
@@ -592,6 +663,8 @@
                 (snapshot.getTrackedFiles());
         } finally {
             deleteState = DELETED;
+            /* releaseDb to balance getDb called by truncate/remove. */
+            envImpl.releaseDb(this);
         }
     }
 
@@ -1209,10 +1282,16 @@
 	    in.latch();
 	    try {
 		int index = inEntry.index;
-		if (in.isEntryKnownDeleted(index) ||
-		    in.getLsn(index) != lsn) {
-		    return null;
-		}
+                if (index < 0) {
+                    /* Negative index signifies a DupCountLN. */
+                    DIN din = (DIN) in;
+                    return din.getDupCountLN();
+                } else {
+                    if (in.isEntryKnownDeleted(index) ||
+                        in.getLsn(index) != lsn) {
+                        return null;
+                    }
+                }
 		return in.fetchTarget(index);
 	    } finally {
 		in.releaseLatch();

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/DbTree.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/DbTree.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/DbTree.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: DbTree.java,v 1.170.2.1 2007/02/01 14:49:44 cwl Exp $
+ * $Id: DbTree.java,v 1.170.2.2 2007/07/02 19:54:49 mark Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -12,6 +12,7 @@
 import java.io.UnsupportedEncodingException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -42,7 +43,69 @@
 import com.sleepycat.je.txn.Locker;
 
 /**
- * Represents the DatabaseImpl Naming Tree.
+ * DbTree represents the database directory for this environment. DbTree is
+ * itself implemented through two databases. The nameDatabase maps
+ * databaseName-> an internal databaseId. The idDatabase maps
+ * databaseId->DatabaseImpl.
+ * 
+ * For example, suppose we have two databases, foo and bar. We have the
+ * following structure:
+ *
+ *           nameDatabase                          idDatabase
+ *               IN                                    IN
+ *                |                                     |   
+ *               BIN                                   BIN
+ *    +-------------+--------+            +---------------+--------+      
+ *  .               |        |            .               |        |
+ * NameLNs         NameLN    NameLN      MapLNs for   MapLN        MapLN
+ * for internal    key=bar   key=foo     internal dbs key=53       key=79
+ * dbs             data=     data=                    data=        data=
+ *                 dbId79    dbId53                   DatabaseImpl DatabaseImpl
+ *                                                        |            |
+ *                                                   Tree for foo  Tree for bar
+ *                                                        |            |
+ *                                                     root IN       root IN
+ *
+ * Databases, Cursors, the cleaner, compressor, and other entities have
+ * references to DatabaseImpls. It's important that object identity is properly
+ * maintained, and that all constituents reference the same DatabaseImpl for
+ * the same db, lest they develop disparate views of the in-memory database;
+ * corruption would ensue. To ensure that, all entities must obtain their
+ * DatabaseImpl by going through the idDatabase.
+ * 
+ * DDL type operations such as create, rename, remove and truncate get their
+ * transactional semantics by transactionally locking the NameLN appropriately.
+ * A read-lock on the NameLN, called a handle lock, is maintained for all DBs
+ * opened via the public API (openDatabase).  This prevents them from being
+ * renamed or removed while open.
+ *
+ * However, for internal database operations, no handle lock on the NameLN is
+ * acacuiqred and MapLNs are locked with short-lived non-transactional Lockers.
+ * An entity that is trying to get a reference to the DatabaseImpl gets a short
+ * lived read lock just for the fetch of the MapLN. A write lock on the MapLN
+ * is taken when the database is created, deleted, or when the MapLN is
+ * evicted. (see DatabaseImpl.isInUse())
+ * 
+ * The nameDatabase operates pretty much as a regular application database in
+ * terms of eviction and recovery. The idDatabase requires special treatment
+ * for both eviction and recovery.
+ * 
+ * The issues around eviction of the idDatabase center on the need to ensure
+ * that there are no other current references to the DatabaseImpl other than
+ * that held by the mapLN. The presence of a current reference would both make
+ * the DatabaseImpl not GC'able, and more importantly, would lead to object
+ * identify confusion later on. For example, if the MapLN is evicted while
+ * there is a current reference to its DatabaseImpl, and then refetched, there
+ * will be two in-memory versions of the DatabaseImpl. Since locks on the
+ * idDatabase are short lived, DatabaseImpl.useCount acts as a reference count
+ * of active current references. DatabaseImpl.useCount must be modified and
+ * read in conjunction with appropropriate locking on the MapLN. See
+ * DatabaseImpl.isInUse() for details.
+ *
+ * This reference count checking is only needed when the entire MapLN is
+ * evicted. It's possible to evict only the root IN of the database in
+ * question, since that doesn't interfere with the DatabaseImpl object
+ * identity.
  */
 public class DbTree implements Loggable {
 
@@ -151,6 +214,10 @@
     /**
      * Create a database.
      *
+     * Increments the use count of the new DB to prevent it from being evicted.
+     * releaseDb should be called when the returned object is no longer used,
+     * to allow it to be evicted.  See DatabaseImpl.isInUse.  [#13415]
+     *
      * Do not evict (do not call CursorImpl.setAllowEviction(true)) during low
      * level DbTree operation. [#15176]
      *
@@ -193,6 +260,8 @@
             idDbLocker = new BasicLocker(envImpl);
             idCursor = new CursorImpl(idDatabase, idDbLocker);
             idCursor.putLN(newId.getBytes(), new MapLN(newDb), false);
+            /* Increment DB use count with lock held. */
+            newDb.incrementUseCount();
             operationOk = true;
 	} catch (UnsupportedEncodingException UEE) {
 	    throw new DatabaseException(UEE);
@@ -212,6 +281,7 @@
 
         return newDb;
     }
+
     /**
      * Called by the Tree to propagate a root change.  If the tree is a data
      * database, we will write the MapLn that represents this db to the log. If
@@ -341,9 +411,10 @@
                 ("Attempted to " + action + " non-existent database " +
                  databaseName);
         }
-        result.nameCursor = new CursorImpl(nameDatabase, locker);
+        boolean success = false;
+        try {
+            result.nameCursor = new CursorImpl(nameDatabase, locker);
 
-        try {
             /* Position the cursor at the specified NameLN. */
             DatabaseEntry key =
                 new DatabaseEntry(databaseName.getBytes("UTF-8"));
@@ -374,14 +445,17 @@
                                             databaseName + "," + handleCount + 
                                             " open Dbs exist");
             }
+            success = true;
 	} catch (UnsupportedEncodingException UEE) {
-            result.nameCursor.releaseBIN();
-            result.nameCursor.close();
 	    throw new DatabaseException(UEE);
-        } catch (DatabaseException e) {
-            result.nameCursor.releaseBIN();
-            result.nameCursor.close();
-	    throw e;
+        } finally {
+            if (!success) {
+                releaseDb(result.dbImpl);
+                if (result.nameCursor != null) {
+                    result.nameCursor.releaseBIN();
+                    result.nameCursor.close();
+                }
+            }
         }
 
         return result;
@@ -400,8 +474,8 @@
         throws DatabaseException {
 
         CursorImpl nameCursor = null;
+        NameLockResult result = lockNameLN(locker, databaseName, "rename");
         try {
-            NameLockResult result = lockNameLN(locker, databaseName, "rename");
             nameCursor = result.nameCursor;
             if (nameCursor == null) {
                 return false;
@@ -422,6 +496,7 @@
 	} catch (UnsupportedEncodingException UEE) {
 	    throw new DatabaseException(UEE);
         } finally {
+            releaseDb(result.dbImpl);
             if (nameCursor != null) {
                 nameCursor.releaseBIN();
                 nameCursor.close();
@@ -436,8 +511,8 @@
         throws DatabaseException {
 
         CursorImpl nameCursor = null;
+        NameLockResult result = lockNameLN(locker, databaseName, "remove");
         try {
-            NameLockResult result = lockNameLN(locker, databaseName, "remove");
             nameCursor = result.nameCursor;
             if (nameCursor == null) {
                 return;
@@ -456,6 +531,9 @@
                  * Schedule database for final deletion during commit. This 
                  * should be the last action taken, since this will take
                  * effect immediately for non-txnal lockers.
+                 *
+                 * Do not call releaseDb here on result.dbImpl, since that is
+                 * taken care of by markDeleteAtTxnEnd.
                  */
                 locker.markDeleteAtTxnEnd(result.dbImpl, true);
             }
@@ -484,9 +562,8 @@
 
         CursorImpl nameCursor = null;
         Locker idDbLocker = null;
+        NameLockResult result = lockNameLN(locker, databaseName, "truncate");
         try {
-            NameLockResult result = lockNameLN(locker, databaseName,
-                                               "truncate");
             nameCursor = result.nameCursor;
             if (nameCursor == null) {
                 return 0;
@@ -497,7 +574,8 @@
                  * nameLN refer to the id of the new database.
                  */
                 DatabaseId newId = new DatabaseId(getNextDbId());
-                DatabaseImpl newDb = (DatabaseImpl) result.dbImpl.clone();
+                DatabaseImpl newDb = result.dbImpl.cloneDb();
+                newDb.incrementUseCount();
                 newDb.setId(newId);
                 newDb.setTree(new Tree(newDb));
             
@@ -538,6 +616,9 @@
                 /* 
                  * Marking the lockers should be the last action, since
                  * it takes effect immediately for non-txnal lockers.
+                 *
+                 * Do not call releaseDb here on result.dbImpl or newDb, since
+                 * that is taken care of by markDeleteAtTxnEnd.
                  */
 
                 /* Schedule old database for deletion if txn commits. */
@@ -548,9 +629,6 @@
 
                 return recordCount;
             }
-
-	} catch (CloneNotSupportedException CNSE) {
-	    throw new DatabaseException(CNSE);
         } finally {
             if (nameCursor != null) {
                 nameCursor.releaseBIN();
@@ -655,9 +733,18 @@
              */
             DatabaseImpl newDb;
             DatabaseId newId = new DatabaseId(getNextDbId());
-	    newDb = (DatabaseImpl) oldDatabase.clone();
+	    newDb = oldDatabase.cloneDb();
+            newDb.incrementUseCount();
             newDb.setId(newId);
             newDb.setTree(new Tree(newDb));
+
+            /*
+             * The non-deprecated truncate starts with an old database with a
+             * incremented use count because lockNameLN is called, which calls
+             * getDb.  To normalize the situation here we must increment it,
+             * since we don't call lockNameLN/getDb.
+             */
+            oldDatabase.incrementUseCount();
             
             /* Insert the new db into id -> name map */
             CursorImpl idCursor = null; 
@@ -694,8 +781,6 @@
             nameCursor.putCurrent(dataDbt, null, null);
 
             return new TruncateResult(newDb, (int) count);
-	} catch (CloneNotSupportedException CNSE) {
-	    throw new DatabaseException(CNSE);
 	} catch (UnsupportedEncodingException UEE) {
 	    throw new DatabaseException(UEE);
         } finally {
@@ -721,6 +806,7 @@
         throws DatabaseException {
 
         try {
+            /* Use count is not incremented for idDatabase and nameDatabase. */
             if (databaseName.equals(ID_DB_NAME)) {
                 return idDatabase;
             } else if (databaseName.equals(NAME_DB_NAME)) {
@@ -734,7 +820,6 @@
             CursorImpl nameCursor = null;
             DatabaseId id = null;
             try {
-
                 nameCursor = new CursorImpl(nameDatabase, nameLocker);
                 DatabaseEntry keyDbt =
 		    new DatabaseEntry(databaseName.getBytes("UTF-8"));
@@ -824,6 +909,11 @@
      * be specified by daemons with their own timeout configuration.  public
      * for unit tests.
      *
+     * Increments the use count of the given DB to prevent it from being
+     * evicted.  releaseDb should be called when the returned object is no
+     * longer used, to allow it to be evicted.  See DatabaseImpl.isInUse.
+     * [#13415]
+     *
      * Do not evict (do not call CursorImpl.setAllowEviction(true)) during low
      * level DbTree operation. [#15176]
      */
@@ -866,6 +956,8 @@
 			    idCursor.getCurrentLNAlreadyLatched(LockType.READ);
                         assert mapLN != null; /* Should be locked. */
                         foundDbImpl =  mapLN.getDatabase();
+                        /* Increment DB use count with lock held. */
+                        foundDbImpl.incrementUseCount();
                     } 
                     break;
 		} catch (DeadlockException DE) {
@@ -896,6 +988,33 @@
         }
     }
 
+    /**
+     * Decrements the use count of the given DB, allowing it to be evicted if
+     * the use count reaches zero.  Must be called to release a DatabaseImpl
+     * that was returned by a method in this class.  See DatabaseImpl.isInUse.
+     * [#13415]
+     */
+    public void releaseDb(DatabaseImpl db) {
+        /* Use count is not incremented for idDatabase and nameDatabase. */
+        if (db != null &&
+            db != idDatabase &&
+            db != nameDatabase) {
+            db.decrementUseCount();
+        }
+    }
+
+    /**
+     * Calls releaseDb for all DBs in the given map of DatabaseId to
+     * DatabaseImpl.  See getDb(DatabaseId, long, Map). [#13415]
+     */
+    public void releaseDbs(Map dbCache) {
+        if (dbCache != null) {
+            for (Iterator i = dbCache.values().iterator(); i.hasNext();) {
+                releaseDb((DatabaseImpl) i.next());
+            }
+        }
+    }
+
     /* 
      * We need to cache a database name in the dbImpl for later use in error
      * messages, when it may be unsafe to walk the mapping tree.  Finding a

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/EnvironmentImpl.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/EnvironmentImpl.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/EnvironmentImpl.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: EnvironmentImpl.java,v 1.256.2.6 2007/04/04 18:36:07 cwl Exp $
+ * $Id: EnvironmentImpl.java,v 1.256.2.7 2007/07/02 19:54:49 mark Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -97,6 +97,7 @@
     private static boolean useSharedLatchesForINs;
     /* true if offset tracking should be used for deferred write dbs. */
     private boolean deferredWriteTemp;
+    private boolean dbEviction;
 
     private MemoryBudget memoryBudget;
     private static int adler32ChunkSize;
@@ -277,9 +278,10 @@
                 configManager.getBoolean(EnvironmentParams.LOG_MEMORY_ONLY);
 	    useSharedLatchesForINs =
 		configManager.getBoolean(EnvironmentParams.ENV_SHARED_LATCHES);
+	    dbEviction =
+		configManager.getBoolean(EnvironmentParams.ENV_DB_EVICTION);
 	    adler32ChunkSize = 
 		configManager.getInt(EnvironmentParams.ADLER32_CHUNK_SIZE);
-
 	    exceptionListener = envConfig.getExceptionListener();
 
             /* 
@@ -1343,6 +1345,13 @@
 	return useSharedLatchesForINs;
     }
 
+    /**
+     * Returns whether DB/MapLN eviction is enabled.
+     */
+    boolean getDbEviction() {
+        return dbEviction;
+    }
+
     public boolean getDeferredWriteTemp() {
         return deferredWriteTemp;
     }
@@ -1355,7 +1364,13 @@
 	return adler32ChunkSize;
     }
 
-    /* DatabaseImpl access. */
+    /**
+     * Creates a new database object given a database name.
+     *
+     * Increments the use count of the new DB to prevent it from being evicted.
+     * releaseDb should be called when the returned object is no longer used,
+     * to allow it to be evicted.  See DatabaseImpl.isInUse.  [#13415]
+     */
     public DatabaseImpl createDb(Locker locker,
                                  String databaseName,
                                  DatabaseConfig dbConfig,
@@ -1371,6 +1386,11 @@
     /**
      * Get a database object given a database name.
      *
+     * Increments the use count of the given DB to prevent it from being
+     * evicted.  releaseDb should be called when the returned object is no
+     * longer used, to allow it to be evicted.  See DatabaseImpl.isInUse.
+     * [#13415]
+     *
      * @param databaseName target database.
      *
      * @return null if database doesn't exist.
@@ -1383,6 +1403,16 @@
         return dbMapTree.getDb(locker, databaseName, databaseHandle);
     }
 
+    /**
+     * Decrements the use count of the given DB, allowing it to be evicted if
+     * the use count reaches zero.  Must be called to release a DatabaseImpl
+     * that was returned by createDb or getDb.  See DatabaseImpl.isInUse.
+     * [#13415]
+     */
+    public void releaseDb(DatabaseImpl db) {
+        dbMapTree.releaseDb(db);
+    }
+
     public List getDbNames()
         throws DatabaseException {
 

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/GetMode.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/GetMode.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/GetMode.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: GetMode.java,v 1.7.2.1 2007/02/01 14:49:44 cwl Exp $
+ * $Id: GetMode.java,v 1.7.2.2 2007/08/06 16:00:06 cwl Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -21,12 +21,12 @@
         this.forward = forward;
     }
 
-    public static final GetMode NEXT =         new GetMode("NEXT", true);
-    public static final GetMode PREV =         new GetMode("PREV", false);
-    public static final GetMode NEXT_DUP =     new GetMode("NEXT_DUP", true);
-    public static final GetMode PREV_DUP =     new GetMode("PREV_DUP", false);
-    public static final GetMode NEXT_NODUP =   new GetMode("NEXT_NODUP", true);
-    public static final GetMode PREV_NODUP =   new GetMode("PREV_NODUP", false);
+    public static final GetMode NEXT =       new GetMode("NEXT", true);
+    public static final GetMode PREV =       new GetMode("PREV", false);
+    public static final GetMode NEXT_DUP =   new GetMode("NEXT_DUP", true);
+    public static final GetMode PREV_DUP =   new GetMode("PREV_DUP", false);
+    public static final GetMode NEXT_NODUP = new GetMode("NEXT_NODUP", true);
+    public static final GetMode PREV_NODUP = new GetMode("PREV_NODUP", false);
 
     public final boolean isForward() {
         return forward;

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/MemoryBudget.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/MemoryBudget.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/MemoryBudget.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: MemoryBudget.java,v 1.54.2.2 2007/02/14 19:46:42 linda Exp $
+ * $Id: MemoryBudget.java,v 1.54.2.6 2007/07/13 02:32:05 cwl Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -131,16 +131,16 @@
     private final static int KEY_OVERHEAD_64 = 24;
 
     // 24
-    private final static int LOCK_OVERHEAD_32 = 32;
-    private final static int LOCK_OVERHEAD_64 = 56;
+    private final static int LOCK_OVERHEAD_32 = 24;
+    private final static int LOCK_OVERHEAD_64 = 48;
 
     // 25
     private final static int LOCKINFO_OVERHEAD_32 = 16;
     private final static int LOCKINFO_OVERHEAD_64 = 32;
 
     // 37
-    private final static int WRITE_LOCKINFO_OVERHEAD_32 = 32;
-    private final static int WRITE_LOCKINFO_OVERHEAD_64 = 40;
+    private final static int WRITE_LOCKINFO_OVERHEAD_32 = 24;
+    private final static int WRITE_LOCKINFO_OVERHEAD_64 = 32;
 
     /* 
      * Txn memory is the size for the Txn + a hashmap entry
@@ -347,8 +347,7 @@
 
     /*
      * Amount of memory cached for locks. Protected by the
-     * LockManager.lockTableLatches[lockTableIndex].  Individual elements of
-     * array may be negative, but the sum will be >= 0.
+     * LockManager.lockTableLatches[lockTableIndex].
      */
     private long[] lockMemoryUsage;
 
@@ -391,7 +390,7 @@
         envImpl.addConfigObserver(this);
 
         /* Peform first time budget initialization. */
-        reset(configManager);
+        reset(configManager, true);
 
         /*
          * Calculate IN and BIN overheads, which are a function of
@@ -418,7 +417,7 @@
          * hasn't changed, since that is expensive and may cause I/O.
          */
         long oldLogBufferBudget = logBufferBudget;
-        reset(configManager);
+        reset(configManager, false);
         if (oldLogBufferBudget != logBufferBudget) {
             envImpl.getLogManager().resetPool(configManager);
         }
@@ -427,7 +426,8 @@
     /**
      * Initialize at construction time and when the cache is resized.
      */
-    private void reset(DbConfigManager configManager)
+    private void reset(DbConfigManager configManager,
+		       boolean resetLockMemoryUsage)
         throws DatabaseException {
 
         /* 
@@ -530,9 +530,11 @@
         logBufferBudget = newLogBufferBudget;
         trackerBudget = newTrackerBudget;
         cacheBudget = newMaxMemory - newLogBufferBudget;
-	nLockTables = 
-            configManager.getInt(EnvironmentParams.N_LOCK_TABLES);
-	lockMemoryUsage = new long[nLockTables];
+	if (resetLockMemoryUsage) {
+	    nLockTables = 
+		configManager.getInt(EnvironmentParams.N_LOCK_TABLES);
+	    lockMemoryUsage = new long[nLockTables];
+	}
     }
 
     /**
@@ -644,6 +646,12 @@
     }
 
     public long getCacheMemoryUsage() {
+	long accLockMemoryUsage = accumulateLockUsage();
+
+	return treeMemoryUsage + miscMemoryUsage + accLockMemoryUsage;
+    }
+
+    private long accumulateLockUsage() {
 	long accLockMemoryUsage = 0;
 	if (nLockTables == 1) {
 	    accLockMemoryUsage = lockMemoryUsage[0];
@@ -652,7 +660,7 @@
 		accLockMemoryUsage += lockMemoryUsage[i];
 	    }
 	}
-	return treeMemoryUsage + miscMemoryUsage + accLockMemoryUsage;
+        return accLockMemoryUsage;
     }
 
     /**
@@ -662,6 +670,13 @@
         return treeMemoryUsage;
     }
 
+    /**
+     * Used for unit testing.
+     */
+    public long getMiscMemoryUsage() {
+        return miscMemoryUsage;
+    }
+
     public long getLogBufferBudget() {
         return logBufferBudget;
     }
@@ -717,5 +732,7 @@
 
     void loadStats(StatsConfig config, EnvironmentStats stats) {
         stats.setCacheDataBytes(getCacheMemoryUsage());
+        stats.setAdminBytes(miscMemoryUsage);
+        stats.setLockBytes(accumulateLockUsage());
     }
 }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/dbi/SortedLSNTreeWalker.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/dbi/SortedLSNTreeWalker.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/dbi/SortedLSNTreeWalker.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: SortedLSNTreeWalker.java,v 1.17.2.2 2007/03/07 01:24:36 mark Exp $
+ * $Id: SortedLSNTreeWalker.java,v 1.17.2.3 2007/05/01 19:27:23 mark Exp $
  */
 
 package com.sleepycat.je.dbi;
@@ -209,7 +209,7 @@
         MemoryBudget mb = envImpl.getMemoryBudget();
 	inList.latchMajor();
 	try {
-            /* consolidate the INList first. */
+            /* Consolidate the INList first. */
             inList.latchMinorAndDumpAddedINs();
 
 	    Iterator iter = inList.iterator();
@@ -419,6 +419,8 @@
 		DupCountLN dcl = (DupCountLN) din.getDupCountLN();
 		callback.processDupCount(dcl.getDupCount());
 	    } else {
+                /* Negative index signifies a DupCountLN. */
+                addToLsnINMap(new Long(lsn), in, -1);
 		Node node = fetchLSN(lsn, lnKeyEntry);
 		callback.processLSN
                     (lsn, LogEntryType.LOG_DUPCOUNTLN, node,
@@ -481,6 +483,9 @@
 	 */
     }
 
+    /**
+     * @param index a negative index signifies a DupCountLN.
+     */
     protected void addToLsnINMap(Long lsn, IN in, int index) {
     }
 

Modified: trunk/contrib/bdb/src/com/sleepycat/je/evictor/Evictor.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/evictor/Evictor.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/evictor/Evictor.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Evictor.java,v 1.86.2.4 2007/03/07 01:24:37 mark Exp $
+ * $Id: Evictor.java,v 1.86.2.6 2007/07/02 19:54:50 mark Exp $
  */
 
 package com.sleepycat.je.evictor;
@@ -31,10 +31,12 @@
 import com.sleepycat.je.log.LogManager;
 import com.sleepycat.je.recovery.Checkpointer;
 import com.sleepycat.je.tree.BIN;
+import com.sleepycat.je.tree.ChildReference;
 import com.sleepycat.je.tree.IN;
 import com.sleepycat.je.tree.Node;
 import com.sleepycat.je.tree.SearchResult;
 import com.sleepycat.je.tree.Tree;
+import com.sleepycat.je.tree.WithRootLatched;
 import com.sleepycat.je.utilint.DaemonThread;
 import com.sleepycat.je.utilint.DbLsn;
 import com.sleepycat.je.utilint.TestHook;
@@ -133,12 +135,6 @@
         active = false;
     }
 
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("<Evictor name=\"").append(name).append("\"/>");
-        return sb.toString();
-    }
-
     /**
      * Evictor doesn't have a work queue so just throw an exception if it's
      * ever called.
@@ -361,8 +357,13 @@
                     break;
                 } else {
                     assert evictProfile.count(target);//intentional side effect
-                    evictBytes += evict
-                        (inList, target, scanIter, backgroundIO, tracker);
+                    if (target.isDbRoot()) {
+                        evictBytes += evictRoot
+                            (inList, target, scanIter, backgroundIO);
+                    } else {
+                        evictBytes += evict
+                            (inList, target, scanIter, backgroundIO, tracker);
+                    }
                 }
                 nBatchSets++;
             }
@@ -516,15 +517,6 @@
                 }
 
                 /* 
-                 * Don't evict the DatabaseImpl Id Mapping Tree (db 0), both
-                 * for object identity reasons and because the id mapping tree
-                 * should stay cached.
-                 */
-                if (db.getId().equals(DbTree.ID_DB_ID)) {
-                    continue;
-                }
-
-                /* 
                  * If this is a read only database and we have at least one
                  * target, skip any dirty INs (recovery dirties INs even in a
                  * read-only environment). We take at least one target so we
@@ -619,6 +611,18 @@
      * in a non-duplicate tree.  This isn't always optimimal, but is the best
      * we can do considering that BINs in duplicate trees may contain a mix of
      * LNs and DINs.
+     *
+     * BINs in the mapping tree are also assigned the same level as user DB
+     * BINs.  When doing by-level eviction (lruOnly=false), this seems
+     * counter-intuitive since we should evict user DB nodes before mapping DB
+     * nodes.  But that does occur because mapping DB INs referencing an open
+     * DB are unevictable.  The level is only used for selecting among
+     * evictable nodes.
+     *
+     * If we did NOT normalize the level for the mapping DB, then INs for
+     * closed evictable DBs would not be evicted until after all nodes in all
+     * user DBs were evicted.  If there were large numbers of closed DBs, this
+     * would have a negative performance impact.
      */
     public int normalizeLevel(IN in, int evictType) {
 
@@ -632,6 +636,75 @@
     }
 
     /**
+     * Evict this DB root node.  [#13415]
+     * @return number of bytes evicted.
+     */
+    private long evictRoot(final INList inList,
+                           final IN target,
+                           final ScanIterator scanIter,
+                           final boolean backgroundIO) 
+        throws DatabaseException {
+
+        final DatabaseImpl db = target.getDatabase();
+
+        class RootEvictor implements WithRootLatched {
+
+            boolean flushed = false;
+            long evictBytes = 0;
+
+            public IN doWork(ChildReference root)
+                throws DatabaseException {
+
+                IN rootIN = (IN) root.fetchTarget(db, null);
+                rootIN.latch(false);
+                try {
+                    /* Re-check that all conditions still hold. */
+                    if (rootIN == target &&
+                        rootIN.isDbRoot() &&
+                        rootIN.isEvictable()) {
+
+                        /* Flush if dirty. */
+                        if (!envImpl.isReadOnly() && rootIN.getDirty()) {
+                            long newLsn = rootIN.log 
+                                (envImpl.getLogManager(),
+                                 false, // allowDeltas
+                                 isProvisionalRequired(rootIN),
+                                 true,  // proactiveMigration
+                                 backgroundIO,
+                                 null); // parent
+                            root.setLsn(newLsn);
+                            flushed = true;
+                        }
+
+                        /* Take off the INList and adjust memory budget. */
+                        scanIter.mark();
+                        inList.removeLatchAlreadyHeld(rootIN);
+                        scanIter.resetToMark();
+                        evictBytes = rootIN.getInMemorySize();
+
+                        /* Evict IN. */
+                        root.clearTarget();
+                    }
+                } finally {
+                    rootIN.releaseLatch();
+                }
+                return null;
+            }
+        }
+
+        /* Attempt to evict the DB root IN. */
+        RootEvictor evictor = new RootEvictor();
+        db.getTree().withRootLatchedExclusive(evictor);
+
+        /* If the root IN was flushed, write the dirtied MapLN. */
+        if (evictor.flushed) {
+            envImpl.getDbMapTree().modifyDbRoot(db);
+        }
+
+        return evictor.evictBytes;
+    }
+
+    /**
      * Strip or evict this node.
      * @return number of bytes evicted.
      */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/incomp/INCompressor.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/incomp/INCompressor.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/incomp/INCompressor.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: INCompressor.java,v 1.125.2.2 2007/03/07 01:24:37 mark Exp $
+ * $Id: INCompressor.java,v 1.125.2.5 2007/07/02 19:54:50 mark Exp $
  */
 
 package com.sleepycat.je.incomp;
@@ -97,12 +97,6 @@
         binRefQueueSync = new Object();
     }
 
-    public String toString() {
-	StringBuffer sb = new StringBuffer();
-	sb.append("<INCompressor name=\"").append(name).append("\"/>");
-	return sb.toString();
-    }
-
     synchronized public void clearEnv() {
 	env = null;
     }
@@ -126,20 +120,28 @@
 	    queueSnapshot = new ArrayList(binRefQueue.values());
         }
 
-        /* Use local caching to reduce DbTree.getDb overhead. */
+        /*
+         * Use local caching to reduce DbTree.getDb overhead.  Do not call
+         * releaseDb after each getDb, since the entire dbCache will be
+         * released at the end.
+         */
+        DbTree dbTree = env.getDbMapTree();
         Map dbCache = new HashMap();
-
-	Iterator it = queueSnapshot.iterator();
-	while (it.hasNext()) {
-	    BINReference binRef = (BINReference) it.next();
-            DatabaseImpl db = env.getDbMapTree().getDb
-                (binRef.getDatabaseId(), lockTimeout, dbCache);
-	    BIN bin = searchForBIN(db, binRef);
-	    if (bin != null) {
-		bin.verifyCursors();
-		bin.releaseLatch();
-	    }
-	}
+        try {
+            Iterator it = queueSnapshot.iterator();
+            while (it.hasNext()) {
+                BINReference binRef = (BINReference) it.next();
+                DatabaseImpl db = dbTree.getDb
+                    (binRef.getDatabaseId(), lockTimeout, dbCache);
+                BIN bin = searchForBIN(db, binRef);
+                if (bin != null) {
+                    bin.verifyCursors();
+                    bin.releaseLatch();
+                }
+            }
+        } finally {
+            dbTree.releaseDbs(dbCache);
+        }
     }
 
     /**
@@ -462,8 +464,9 @@
                     env.getUtilizationProfile().countAndLogSummaries
                         (summaries);
                 }
-                
+
             } finally {
+                dbTree.releaseDbs(dbCache);
                 assert LatchSupport.countLatchesHeld() == 0;
                 accumulatePerRunCounters();
             }
@@ -790,7 +793,10 @@
                                  Map dbCache) 
         throws DatabaseException {
 
-        /* Find the database. */
+        /*
+         * Find the database.  Do not call releaseDb after this getDb, since
+         * the entire dbCache will be released later.
+         */
         binSearch.db = dbTree.getDb
             (binRef.getDatabaseId(), lockTimeout, dbCache);
         if ((binSearch.db == null) ||(binSearch.db.isDeleted())) {  

Modified: trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEConnection.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEConnection.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEConnection.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: JEConnection.java,v 1.13.2.1 2007/02/01 14:49:45 cwl Exp $
+ * $Id: JEConnection.java,v 1.13.2.2 2007/05/22 20:36:39 cwl Exp $
  */
 
 package com.sleepycat.je.jca.ra;
@@ -24,82 +24,35 @@
  * &lt;JEHOME&gt;/examples/jca/simple/SimpleBean.java for more information on 
  * how to build the resource adaptor and use a JEConnection.
  */
-public class JEConnection {
+public interface JEConnection {
 
-    private JEManagedConnection mc;
-    private JELocalTransaction txn;
+    public void setManagedConnection(JEManagedConnection mc,
+				     JELocalTransaction lt);
 
-    public JEConnection(JEManagedConnection mc) {
-        this.mc = mc;
-    }
+    public JELocalTransaction getLocalTransaction();
 
-    protected void setManagedConnection(JEManagedConnection mc,
-					JELocalTransaction lt) {
-	this.mc = mc;
-	if (txn == null) {
-	    txn = lt;
-	}
-    }
+    public void setLocalTransaction(JELocalTransaction txn);
 
-    JELocalTransaction getLocalTransaction() {
-	return txn;
-    }
-
-    void setLocalTransaction(JELocalTransaction txn) {
-	this.txn = txn;
-    }
-
     public Environment getEnvironment()
-	throws ResourceException {
+	throws ResourceException;
 
-	return mc.getEnvironment();
-    }
-
     public Database openDatabase(String name, DatabaseConfig config)
-	throws DatabaseException {
+	throws DatabaseException;
 
-	return mc.openDatabase(name, config);
-    }
-
     public SecondaryDatabase openSecondaryDatabase(String name,
 						   Database primaryDatabase,
 						   SecondaryConfig config)
-	throws DatabaseException {
+	throws DatabaseException;
 
-	return mc.openSecondaryDatabase(name, primaryDatabase, config);
-    }
-
     public void removeDatabase(String databaseName)
-	throws DatabaseException {
+	throws DatabaseException;
 
-	mc.removeDatabase(databaseName);
-    }
-
     public long truncateDatabase(String databaseName, boolean returnCount)
-	throws DatabaseException {
+	throws DatabaseException;
 
-	return mc.truncateDatabase(databaseName, returnCount);
-    }
-
     public Transaction getTransaction()
-	throws ResourceException {
+	throws ResourceException;
 
-	if (txn == null) {
-	    return null;
-	}
-
-	try {
-	    return txn.getTransaction();
-	} catch (DatabaseException DE) {
-	    ResourceException ret = new ResourceException(DE.toString());
-	    ret.initCause(DE);
-	    throw ret;
-	}
-    }
-
     public void close()
-	throws JEException {
-
-	mc.close();
-    }
+	throws JEException;
 }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnection.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnection.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnection.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: JEManagedConnection.java,v 1.13.2.1 2007/02/01 14:49:45 cwl Exp $
+ * $Id: JEManagedConnection.java,v 1.13.2.2 2007/05/22 20:36:39 cwl Exp $
  */
 
 package com.sleepycat.je.jca.ra;
@@ -67,7 +67,7 @@
         throws ResourceException {
 
 	if (conn == null) {
-	    conn = new JEConnection(this);
+	    conn = new JEConnectionImpl(this);
 	}
 	return conn;
     }
@@ -115,7 +115,7 @@
     public void associateConnection(Object connection)
 	throws ResourceException {
 
-	conn = (JEConnection) connection;
+	conn = (JEConnectionImpl) connection;
 	conn.setManagedConnection(this, savedLT);
 	savedLT = null;
     }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnectionFactory.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnectionFactory.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/JEManagedConnectionFactory.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: JEManagedConnectionFactory.java,v 1.9.2.1 2007/02/01 14:49:45 cwl Exp $
+ * $Id: JEManagedConnectionFactory.java,v 1.9.2.2 2007/05/22 20:36:39 cwl Exp $
  */
 
 package com.sleepycat.je.jca.ra;
@@ -26,6 +26,9 @@
 public class JEManagedConnectionFactory
     implements ManagedConnectionFactory, Serializable {
 
+    private String userName;
+    private String password;
+
     public JEManagedConnectionFactory() {
     }
 
@@ -76,6 +79,22 @@
         return null;
     }
 
+    public void setUserName(String userName) {
+	this.userName = userName;
+    }
+
+    public String getUserName() {
+	return userName;
+    }
+
+    public void setPassword(String password) {
+	this.password = password;
+    }
+
+    public String getPassword() {
+	return password;
+    }
+
     public void setLogWriter(PrintWriter out)
 	throws ResourceException {
 

Modified: trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/ra.xml
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/ra.xml	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/jca/ra/ra.xml	2007-08-17 14:14:29 UTC (rev 14749)
@@ -24,7 +24,7 @@
       </connectionfactory-impl-class>
       <connection-interface>com.sleepycat.je.jca.ra.JEConnection
       </connection-interface>
-      <connection-impl-class>com.sleepycat.je.jca.ra.JEConnection
+      <connection-impl-class>com.sleepycat.je.jca.ra.JEConnectionImpl
       </connection-impl-class>
       <transaction-support>LocalTransaction</transaction-support>
       <!--

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/FileReader.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/FileReader.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/FileReader.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: FileReader.java,v 1.99.2.3 2007/04/04 14:28:22 cwl Exp $
+ * $Id: FileReader.java,v 1.99.2.4 2007/05/31 21:55:32 mark Exp $
  */
 
 package com.sleepycat.je.log;
@@ -267,7 +267,8 @@
 
                 readBasicHeader(dataBuffer);
                 if (currentEntryHeader.getReplicate()) {
-                    dataBuffer = readData(currentEntryHeader.getVariablePortionSize(), true);
+                    dataBuffer = readData
+                        (currentEntryHeader.getVariablePortionSize(), true);
                     currentEntryHeader.readVariablePortion(dataBuffer);
                 }
 
@@ -338,26 +339,38 @@
         } catch (DatabaseException e) {
             eof = true;
             /* Report on error. */
-            LogEntryType problemType =
-                LogEntryType.findType(currentEntryHeader.getType(),
-				      currentEntryHeader.getVersion());
-            Tracer.trace(envImpl, "FileReader", "readNextEntry",
-			 "Halted log file reading at file 0x" +
-                         Long.toHexString(readBufferFileNum) +
-                         " offset 0x" +
-                         Long.toHexString(nextEntryOffset) +
-                         " offset(decimal)=" + nextEntryOffset +
-                         ":\nentry="+ problemType +
-                         "(typeNum=" + currentEntryHeader.getType() +
-                         ",version=" + currentEntryHeader.getVersion() +
-                         ")\nprev=0x" +
-                         Long.toHexString(currentEntryPrevOffset) +
-                         "\nsize=" + currentEntryHeader.getItemSize() +
-                         "\nNext entry should be at 0x" +
-                         Long.toHexString((nextEntryOffset +
+            if (currentEntryHeader != null) {
+                LogEntryType problemType =
+                    LogEntryType.findType(currentEntryHeader.getType(),
+                                          currentEntryHeader.getVersion());
+                Tracer.trace(envImpl, "FileReader", "readNextEntry",
+                             "Halted log file reading at file 0x" +
+                             Long.toHexString(readBufferFileNum) +
+                             " offset 0x" +
+                             Long.toHexString(nextEntryOffset) +
+                             " offset(decimal)=" + nextEntryOffset +
+                             ":\nentry="+ problemType +
+                             "(typeNum=" + currentEntryHeader.getType() +
+                             ",version=" + currentEntryHeader.getVersion() +
+                             ")\nprev=0x" +
+                             Long.toHexString(currentEntryPrevOffset) +
+                             "\nsize=" + currentEntryHeader.getItemSize() +
+                             "\nNext entry should be at 0x" +
+                             Long.toHexString((nextEntryOffset +
                                            currentEntryHeader.getSize() +
                                            currentEntryHeader.getItemSize())) +
-                         "\n:", e);
+                             "\n:", e);
+            } else {
+                Tracer.trace(envImpl, "FileReader", "readNextEntry",
+                             "Halted log file reading at file 0x" +
+                             Long.toHexString(readBufferFileNum) +
+                             " offset 0x" +
+                             Long.toHexString(nextEntryOffset) +
+                             " offset(decimal)=" + nextEntryOffset +
+                             " prev=0x" +
+                             Long.toHexString(currentEntryPrevOffset),
+                             e);
+            }
             throw e;
         }
         return foundEntry;

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/INFileReader.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/INFileReader.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/INFileReader.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: INFileReader.java,v 1.52.2.2 2007/03/08 22:32:54 mark Exp $
+ * $Id: INFileReader.java,v 1.52.2.3 2007/08/06 16:00:20 cwl Exp $
  */
 
 package com.sleepycat.je.log;
@@ -293,8 +293,8 @@
              * Do partial load of db and txn id tracking entries if necessary.
              * Note that these entries do not overlap with targetLogEntry.
              *
-             * XXX We're doing a full load for now, since LNLogEntry does not
-             * read the db and txn id in a partial load, only the node id.
+             * We're doing a full load for now, since LNLogEntry does not read
+             * the db and txn id in a partial load, only the node id.
              */
             LNLogEntry lnEntry = null;
             if (dbIdTrackingEntry != null) {

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/LatchedLogManager.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/LatchedLogManager.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/LatchedLogManager.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: LatchedLogManager.java,v 1.17.2.1 2007/02/01 14:49:47 cwl Exp $
+ * $Id: LatchedLogManager.java,v 1.17.2.2 2007/06/13 03:55:37 mark Exp $
  */
 
 package com.sleepycat.je.log;
@@ -83,7 +83,21 @@
             logWriteLatch.release();
         }
     }
+    
+    /**
+     * @see LogManager#removeTrackedFile
+     */
+    public void removeTrackedFile(TrackedFileSummary tfs)
+        throws DatabaseException {
 
+        logWriteLatch.acquire();
+        try {
+            removeTrackedFileInternal(tfs);
+        } finally {
+            logWriteLatch.release();
+        }
+    }
+
     /**
      * @see LogManager#countObsoleteLNs
      */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/LogManager.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/LogManager.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/LogManager.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: LogManager.java,v 1.163.2.3 2007/03/09 21:04:12 mark Exp $
+ * $Id: LogManager.java,v 1.163.2.4 2007/06/13 03:55:37 mark Exp $
  */
 
 package com.sleepycat.je.log;
@@ -821,6 +821,16 @@
     }
 
     /**
+     * Removes the tracked summary for the given file.
+     */
+    abstract public void removeTrackedFile(TrackedFileSummary tfs)
+        throws DatabaseException;
+
+    protected void removeTrackedFileInternal(TrackedFileSummary tfs) {
+        tfs.reset();
+    }
+
+    /**
      * Count node as obsolete under the log write latch.  This is done here
      * because the log write latch is managed here, and all utilization
      * counting must be performed under the log write latch.

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/StatsFileReader.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/StatsFileReader.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/StatsFileReader.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: StatsFileReader.java,v 1.15.2.1 2007/02/01 14:49:47 cwl Exp $
+ * $Id: StatsFileReader.java,v 1.15.2.2 2007/06/04 17:03:30 linda Exp $
  */
 
 package com.sleepycat.je.log;
@@ -187,7 +187,7 @@
                    8 bytes txn id
                    8 bytes lastlogged LSN (backpointer for txn)
                 */
-                /** BOZO -- the header size is undercounted for replication */
+           
                 int overhead = (info.count*46) + info.headerBytes;
                 realTotalBytes += (info.totalBytes-overhead);
             }

Modified: trunk/contrib/bdb/src/com/sleepycat/je/log/SyncedLogManager.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/log/SyncedLogManager.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/log/SyncedLogManager.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: SyncedLogManager.java,v 1.18.2.1 2007/02/01 14:49:47 cwl Exp $
+ * $Id: SyncedLogManager.java,v 1.18.2.2 2007/06/13 03:55:37 mark Exp $
  */
 
 package com.sleepycat.je.log;
@@ -77,7 +77,18 @@
             return getUnflushableTrackedSummaryInternal(file);
         }
     }
+    
+    /**
+     * @see LogManager#removeTrackedFile
+     */
+    public void removeTrackedFile(TrackedFileSummary tfs)
+        throws DatabaseException {
 
+        synchronized (logWriteLatch) {
+            removeTrackedFileInternal(tfs);
+        }
+    }
+
     /**
      * @see LogManager#countObsoleteLNs
      */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/recovery/Checkpointer.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/recovery/Checkpointer.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/recovery/Checkpointer.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: Checkpointer.java,v 1.140.2.2 2007/03/07 01:24:39 mark Exp $
+ * $Id: Checkpointer.java,v 1.140.2.3 2007/06/01 21:32:56 mark Exp $
  */
 
 package com.sleepycat.je.recovery;
@@ -146,12 +146,6 @@
         checkpointId = lastCheckpointId;
     }
 
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("<Checkpointer name=\"").append(name).append("\"/>");
-        return sb.toString();
-    }
-
     /**
      * Load stats.
      */

Modified: trunk/contrib/bdb/src/com/sleepycat/je/recovery/RecoveryManager.java
===================================================================
--- trunk/contrib/bdb/src/com/sleepycat/je/recovery/RecoveryManager.java	2007-08-17 14:09:41 UTC (rev 14748)
+++ trunk/contrib/bdb/src/com/sleepycat/je/recovery/RecoveryManager.java	2007-08-17 14:14:29 UTC (rev 14749)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002,2007 Oracle.  All rights reserved.
  *
- * $Id: RecoveryManager.java,v 1.211.2.3 2007/03/28 15:53:44 cwl Exp $
+ * $Id: RecoveryManager.java,v 1.211.2.4 2007/07/02 19:54:51 mark Exp $
  */
 
 package com.sleepycat.je.recovery;
@@ -651,8 +651,12 @@
                 DatabaseId dbId = reader.getDatabaseId();
                 if (dbId.equals(DbTree.ID_DB_ID)) {
                     DatabaseImpl db = dbMapTree.getDb(dbId);
-                    replayOneIN(reader, db, false, recorder);
-                    info.numMapINs++;
+                    try {
+                        replayOneIN(reader, db, false, recorder);
+                        info.numMapINs++;
+                    } finally {
+                        dbMapTree.releaseDb(db);
+                    }
                 }
             }
 
@@ -731,18 +735,24 @@
                 }
                 if (isTarget) {
                     DatabaseImpl db = dbMapTree.getDb(dbId);
-                    if (db == null) {
-                        // This db has been deleted, ignore the entry.
-                    } else {
-                        replayOneIN(reader, db, requireExactMatch, recorder);
-                        numINsSeen++;
+                    try {
+                        if (db == null) {
+                            // This db has been deleted, ignore the entry.
+                        } else {
+                            replayOneIN(reader, db, requireExactMatch,
+                                        recorder);
+                            numINsSeen++;
 
-                        /*
-                         * Add any db that we encounter IN's for because
-                         * they'll be part of the in-memory tree and therefore
-                         * should be included in the INList rebuild.
-                         */
-                        inListRebuildDbIds.add(dbId);
+                            /*
+                             * Add any db that we encounter IN's for because
+                             * they'll be part of the in-memory tree and
+                             * therefore should be included in the INList
+                             * rebuild.
+                             */
+                            inListRebuildDbIds.add(dbId);
+                        }
+                    } finally {
+                        dbMapTree.releaseDb(db);
                     }
                 }
             }
@@ -787,13 +797,17 @@
                 DatabaseId dbId = reader.getDatabaseId();
                 if (targetDbs.contains(dbId)) {
                     DatabaseImpl db = dbMapTree.getDb(dbId);
-                    if (db == null) {
-                        // This db has been deleted, ignore the entry.
-                    } else {
-                        replayOneIN(reader, 
-                                    db, 
-                                    true,  // requireExactMatch,
-                                    null); // level recorder
+                    try {
+                        if (db == null) {
+                            // This db has been deleted, ignore the entry.
+                        } else {
+                            replayOneIN(reader, 
+                                        db, 
+                                        true,  // requireExactMatch,
+                                        null); // level recorder
+                        }
+                    } finally {
+                        dbMapTree.releaseDb(db);
                     }
                 }
             }
@@ -934,46 +948,49 @@
 			    reader.getAbortKnownDeleted();
 			DatabaseId dbId = reader.getDatabaseId();
 			DatabaseImpl db = dbMapTree.getDb(dbId);
-                        
-			/* Database may be null if it's been deleted. */
-			if (db != null) {
-			    ln.postFetchInit(db, logLsn);
-			    try {
-                                undo(detailedTraceLevel,
-                                     db,
-                                     location,
-                                     ln,
-                                     reader.getKey(),
-                                     reader.getDupTreeKey(),
-                                     logLsn, 
-