## Berkeley DB Java Edition 3.2.76 Change Log

The changes between 3.2.74 and 3.2.76 are described directly below. A full list of all changes since JE 2.1.34 is also available below.

### Changes since 3.2.74

### Log File On-Disk Format Changes:

None.

### New Features:

None.

### General Environment Changes:

1. Fixed a bug in which ByteBuffer.array() was not being offset by ByteBuffer.arrayOffset(). This could result in a DbChecksumException. [#15941] [#16107]

### Direct Persistence Layer (DPL) and Collections API:

None.

### API Changes:

None.

### Utility Changes:

None.

### Configuration, Documentation, Test and Build Changes:

None.

### Full list of changes since JE 2.1.34

All changes from JE 3.0.11, 3.0.12, 3.1.0, 3.2.13, 3.2.21, 3.2.23 and 3.2.76 are listed here.

For additional details, please see the documentation and Release Notes included in your download package or on our website.

### Log File On-Disk Format Changes:

1. JE 3.2.13 has moved to on-disk file format 5.

   The change is forward compatible in that JE files created with release 3.1.0 and earlier can be read when opened with JE 3.2.13. The change is not backward compatible in that files created with JE 3.2.13 cannot be read by earlier releases. Note that if an existing environment is opened read/write, a new log file is written by JE 3.2.13 and the environment can no longer be read by earlier releases.[#15195] (3.2.13)

2. JE 3.0.11 has moved to on-disk file format 4.
   The change is forward compatible in that JE files created with release 2.1.30 and earlier can be read when opened with JE 3.0.11. The change is not backward compatible in that files created with JE 3.0.11 cannot be read by earlier releases. Note that if an earlier environment is opened read/write, a new log file is written by JE 3.0.11 and the environment can no longer be read by earlier releases. (3.0.11)
3. An upgrade problem was inadvertently introduced between JE 2.0.90, which was released in Nov 1, 2005 and the following JE 2.1.34 release in January 2006. The problem does not apply to you if you have an environment created with JE 2.0.90 or earlier, and have since successfully opened it with JE 2.1.30. Likewise, a 2.0.90 and earlier environment that has been closed cleanly with Environment.close() will not encounter this problem, nor will most environments that have more than 30 Mb of data. The problem manifests as the following stack trace. A workaround is described below.

       com.sleepycat.je.DatabaseException: JE 3.0.11: searchResult=class com.sleepycat.
       je.tree.IN nodeId=479 nEntries=0
              at com.sleepycat.je.tree.Tree.getParentBINForChildLN(Tree.java:1031)
       ...
       Caused by: java.lang.ClassCastException: com.sleepycat.je.tree.IN
              at com.sleepycat.je.tree.Tree.getParentBINForChildLN(Tree.java:1021)

   (3.0.11)

### New Features:

1. A new Direct Persistence Layer adds a built-in Plain Old Java Object (POJO)-based persistent object model, which provides support for complex object models without compromises in performance. For an introduction to the Direct Persistence Layer API, see Getting Started with the Direct Persistence Layer.

   JE 3.0.11 introduced the beta release of the DPL, while JE 3.1 is the GA release. Please see the Release Notes for more information. [#13894]

2. A new "deferred write" database mode provides better performance for temporary databases or databases which rapidly modify data by reducing the amount of I/O incurred. In a normal durable database, every new version of a data record is written to disk; in deferred write mode, JE avoids disk I/O until cache is exceeded or Database.sync() is called. See the Getting Started Guide, Chapter 3 (Databases) for more information. [#13936](3.0.11)
3. `com.sleepycat.je.util.DbBackup` is a new helper class which simplifies backups by managing JE background activity in an open environment. See the Getting Started Guide, Chapter 7 (Backing up and Restoring Berkeley DB Java Edition Applications) and the Javadoc for DbBackup for more information. [#14022](3.0.11)
4. The `com.sleepycat.collections` package is now fully compatible with the Java Collections framework. In previous releases, `Collections.size()` was not supported, and collection iterators had to be explicitly closed. These incompatibilities have been addressed to provide full interoperability with other Java libraries that use the Java Collections Framework interfaces. [#14154] [#12986](3.0.11)
5. The `com.sleepycat.bind.tuple` package now has bindings that correctly sort negative floating point numbers. See the following new APIs:

         SortedFloatBinding, SortedDoubleBinding,
         TupleInput.readSortedFloat, TupleInput.readSortedDouble,
         TupleOutput.writeSortedFloat, TupleOutput.writeSortedDouble.

   [#14127](3.0.11)
6. Added a new method, com.sleepycat.je.Database.count(), which has been optimized to execute faster than the count obtained from a database scan. Note that the count may not be accurate in the face of concurrent update operations.(3.1.0)

   This functionality is also exposed through the new method com.sleepycat.persist.EntityIndex.count() and is also used by com.sleepycat.collections.StoredMap.size() and com.sleepycat.collections.StoredCollection.size(). See the Javadoc for full details. [#14060](3.1.0)

7. A new method, EnvironmentConfig.setExceptionListener() provides a notification mechanism for asynchronous exceptions thrown by JE daemon threads. See the Javadoc for more details. [#15018](3.1.0)
8. Added three new configuration properties to limit the amount of I/O performed by JE background activities such as cleaning and checkpointing: je.env.backgroundReadLimit, je.env.backgroundWriteLimit, je.env.backgroundSleepInterval. The amount of I/O performed by JE background threads sometimes spikes, which increases the response time (latency) of user operations that are performed in other threads. By setting these new properties, an application can limit the amount of background I/O in order to reduce the the response time of user operations. [#15158][Metalink 5839909.993] (3.2.13)
9. Tuple bindings now support the java.math.BigInteger type. Like other tuple binding values, BigInteger values are sorted in natural integer order by default, without using a custom comparator. For details please see the Javadoc for:

       com.sleepycat.bind.tuple.TupleInput.readBigInteger
       com.sleepycat.bind.tuple.TupleOutput.writeBigInteger
       com.sleepycat.bind.tuple.BigIntegerBinding

   [#15244] (3.2.13)
10. The java.math.BigInteger class is now a DPL simple type. Values of this type are sorted in natural integer order by default, and BigInteger can be used as the type of a primary or secondary key field. DPL class evolution will automatically widen all other integer types (byte, char, short, int, long) to a BigInteger -- in an existing class, changing from any of these types to BigInteger is a compatible type change. [#15244] (3.2.13)
11. The JE Deferred Write mode is now explicitly available in the DPL. Deferred Write mode may be set for an entire DPL store using StoreConfig.setDeferredWrite and all index changes may be flushed to disk using EntityStore.sync. [#15249] (3.2.13)
12. When setting the Environment configuration property je.log.memOnly to true, a non-existent environment directory may now be specified and the je.lock file will not be written. Note that memory-only mode is primarily useful with automated tests to avoid file cleanup and it not recommended for production use. If you need a low durability mode for production use, see the Deferred Write mode (Database.setDeferredWrite). [#15255] (3.2.13)
13. Restored a previously disabled feature where Cursor.putCurrent can be used to change the data for a record in a duplicates database when a custom duplicate comparator is configured that does not compare all bytes of the data (this is called a partial comparator). This feature was previously disabled in 3.2.28 to prevent data corruption (see [#15527]). The data corruption issues have been fixed and the feature is now enabled. See DatabaseConfig.setDuplicateComparator for more information. Note that a partial comparator may also be configured for keys using DatabaseConfig.setBtreeComparator. However, such a database may not also be configured for duplicates. See DatabaseConfig.setBtreeComparator for more information. [#15704] (3.2.49)

### General Environment Changes:

1. A user reported an OutOfMemoryError in a deployment using fairly large (512K) records. We finally tracked the problem down to the behavior of the standard java.util.zip.Adler32 class, which JE uses to checksum log records. Our research found JVM implementation notes which said that a JVM may temporarily disable garbage collection when executing the native code for Adler32.

   One workaround for the user was to use -Dje.disable.java.adler32=true at runtime. This forces JE to its own, slower Adler32 implementation. It's an existing flag that was used to work around a Java 1.4 problem with the Adler32 implementation.

   A second workaround provided in (3.1.0) is the je.adler32.chunkSize property. Setting this parameter will cause JE to pass chunks of the log record to the checksumming class so that the GC does not block. 0 means do not chunk.

   Note that the Adler32 memory allocation issue is reported in this Sun bug entry to be fixed in various releases of the Sun JVM. [#14149] (3.1.0)

2. Shared latches are now used on all internal nodes of the b-tree, which increases concurrency for many operations. Shared latches are only enabled when je.env.sharedLatches is set to true; the default value is false. The default may change in a future release. [#14168](3.0.11)
3. Fixed a bug where an internal latch was not taken during the deletion of log cleaning metadata or database metadata. [#14214](3.0.11)
4. Fixed a bug where internal node latches were not released in a corner case where the database has duplicate records and there are concurrent readers and writers. [#14230](3.0.11)
5. Invalidate the Environment when an Error such as java.lang.OutOfMemoryError is thrown during database operations, so that RunRecoveryException will be thrown if further operations are attempted. [#14300](3.1.0)
6. Calling com.sleepycat.je.Transaction.toString() after the transaction was closed resulted in a NullPointerException. This is now fixed. [#14349](3.0.11)
7. In a corner case requiring a certain pattern of inserts coupled with btree splits and checkpoints, a data record could be lost after an environment recovery following a non-clean shutdown. This has been fixed. [#14424](3.0.11)
8. The following NullPointerException could be seen when je.cleaner.threads > 0. This has been fixed.

       java.lang.NullPointerException
       	at com.sleepycat.je.cleaner.UtilizationProfile.getCheapestFileToClean(UtilizationProfile.java:201)
       	at com.sleepycat.je.cleaner.FileSelector.selectFileForCleaning(FileSelector.java:205)
       	at com.sleepycat.je.cleaner.FileProcessor.doClean(FileProcessor.java:201)
       	at com.sleepycat.je.cleaner.FileProcessor.onWakeup(FileProcessor.java:143)

   [#14431](3.0.11)
9. Cursor.getSearchBothRange() was incorrectly using the custom duplicate key comparator instead of the main btree key comparator, if the database was configured with a custom duplicate comparator. [#14464](3.0.11)
10. Fixed a bug that caused a NullPointerException when Database.sync() is called on a newly created, empty deferred-write database. [#14781](3.1.0)
11. Fixed a bug where high concurrency updates on Java 1.6 could result in this exception from JE daemon threads: `com.sleepycat.util.RuntimeExceptionWrapper: Channel closed, may be due to thread interrupt.` [#14571](3.1.0)
12. Fixed a bug that caused a NullPointerException in the cleaner thread when running under a JDK1.6 beta. The exception was not fatal, and looked like this:

        <Cleaner name="Cleaner-1"/> caught exception: java.lang.NullPointerException
        java.lang.NullPointerException
                at java.util.TreeMap.getEntry(TreeMap.java:324)
                at java.util.TreeMap.remove(TreeMap.java:580)
                at java.util.TreeSet.remove(TreeSet.java:259)
                at com.sleepycat.je.cleaner.FileSelector.selectFileForCleaning(FileSelector.java:236)
                at com.sleepycat.je.cleaner.FileProcessor.doClean(FileProcessor.java:201)
                at com.sleepycat.je.cleaner.FileProcessor.onWakeup(FileProcessor.java:143)
                at com.sleepycat.je.utilint.DaemonThread.run(DaemonThread.java:189)
                at java.lang.Thread.run(Thread.java:619)
        Continuing

    [#14877](3.1.0)
13. Fixed a bug that resulted in poor cache eviction management, and therefore poor performance when there is a high level of log cleaning in conjunction with a high level of cache eviction. This was a performance regression from the JE 2.1.30 release. One symptom of the problem is that the ratio of EnvironmentStats.getNBINSsStripped() to EnvironmentStats.getNNodesSelected() is lower in 3.0 than in 2.1.30. [#15062](3.1.0)
14. Fixed a bug that resulted in poor cache eviction management and could trigger OutOfMemoryException. A symptom of the problem is that EnvironmentStats.getCacheDataBytes() could become negative. [#15129]
15. Fixed a bug where JE incorrectly handled the case where the environment consists of a single log file, there is a checksum error immediately following the file header, and the application repeatedly attempts to open the environment without heeding the DatabaseExceptions thrown by new Environment(). The first two open attempts correctly warned the application that the 00000000.jdb file should be moved away; the third attempt incorrectly threw a ClassCastException. [#15133][Metalink 5802188.992] (3.2.13)
16. Fixed a bug where latches were not released when a LockNotGrantedException was thrown, resulting in a deadlock. This problem only applies to applications which use TransactionConfig.setNoWait(). One symptom of the problem are threads which are waiting on com.sleepycat.je.tree.IN.latch, in this manner:

        "Thread-20" prio=5 tid=0x00538990 nid=0x1824400 waiting on condition [0xf181f000..0xf1820ab0]
        at sun.misc.Unsafe.park(Native Method)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:118)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:681)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:711)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1041)
        at java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync.wlock(ReentrantReadWriteLock.java:342)
        at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:637)
        at com.sleepycat.je.latch.Java5SharedLatchImpl.acquireExclusive(Java5SharedLatchImpl.java:91)
        at com.sleepycat.je.tree.IN.latch(IN.java:329)
                    ...

    [#15142] (3.2.13)
17. A minor change was made to the way that checkpoints are scheduled. As a result, checkpoints are performed at slightly more regular intervals than before. [#15169] (3.2.13)
18. Fixed a bug where a mutex deadlock could occur under low memory conditions. (3.2.21)
19. Fixed a bug where a monitor (synchronized lock) deadlock could occur under low memory conditions. This problem was discovered during internal testing and has not been reported from the field. [#15176] (3.2.13)
20. Improve log cleaning by improving the counting of obsolete record sizes. The utilization of a given log file is now known more accurately, which means that cleaning can be more efficient. The improvement impacts applications that insert both large and small records, and that delete or update them asymmetrically; for example, both large and small records are inserted but only small records are deleted. A new Environment configuration property was also added: je.cleaner.fetchObsoleteSize; if set to true, this property causes log records to be fetched in order to count their sizes accurately when a database is truncated or removed, and when running recovery. [#15195] Metalink: 5872288.993 (3.2.13)
21. Fixed a bug where the wrong comparator could be used in the first insertion of a duplicate record when the application has specified both a custom BtreeComparator and a custom DuplicateComparator. [#15197] (3.2.13)
22. Fixed a race condition which could occur when there are concurrent Environment instantiations and closings. An application could erroneously get access to a invalidated (closed) Environment instance. [#15200] (3.2.13)
23. Fixed a bug in JE's management of its internal utilization statistics which could result in an OutOfMemoryError. The problem was initially reported on this JE Forum thread. This bug sometimes caused OutOfMemoryError when both of the following conditions occurred: 1) A very large data set is used or the applications runs for a very long internal without closing the environment, and 2) the cache is large enough to fit all data records into memory. [#15214] (3.2.13)
24. Fixed a bug which could result in a ConcurrentModificationException and this stack trace when running under Java 1.4.

        Exception in thread "Thread-0" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:448)
        at java.util.AbstractList$Itr.next(AbstractList.java:419)
        at com.sleepycat.je.latch.SharedLatchImpl.indexOf(SharedLatchImpl.java:246)
        at com.sleepycat.je.latch.SharedLatchImpl.acquireExclusiveNoWait(SharedLatchImpl.java:131)
        at com.sleepycat.je.tree.IN.latchNoWait(IN.java:352)
        ...

    [#15231] (3.2.13)
25. Fixed a bug which could occur when je.env.sharedLatches=true and the application is executing inserts, which manifested as this intermittent stack trace:

        Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
         at java.util.concurrent.locks.ReentrantReadWriteLock$Sync.tryReleaseShared(ReentrantReadWriteLock.java:275)
         at java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared(AbstractQueuedSynchronizer.java:1180)
         at java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.unlock(ReentrantReadWriteLock.java:576)
         at com.sleepycat.je.latch.Java5SharedLatchImpl.releaseIfOwner(Java5SharedLatchImpl.java:227)
         at com.sleepycat.je.tree.IN.releaseLatchIfOwner(IN.java:405)
         at com.sleepycat.je.tree.Tree.searchSplitsAllowed(Tree.java:1701)
         at com.sleepycat.je.tree.Tree.findBinForInsert(Tree.java:3321)
         at com.sleepycat.je.tree.Tree.insert(Tree.java:2475)
        ...

    [#15233] (3.2.13)
26. Database.sync now flushes the log to disk so that all changes are durable. Before, some changes might not be durable if a crash occurred after the sync and prior to the log buffer naturally being written as further changes were made or during the next checkpoint or Environment.close. [#15254] (3.2.13)
27. Fixed a bug where use of XAEnvironment and a non 8-bit encoding could cause BufferOverflowExceptions during recovery. The following stack trace shows the problem.

        com.sleepycat.je.RunRecoveryException: java.nio.BufferOverflowException
        at com.sleepycat.je.log.LogManager.log(LogManager.java:284)
        at com.sleepycat.je.log.LogManager.log(LogManager.java:181)
        at com.sleepycat.je.log.TraceLogHandler.publish(TraceLogHandler.java:41)
        at java.util.logging.Logger.log(Logger.java:428)
        at java.util.logging.Logger.doLog(Logger.java:450)
        at java.util.logging.Logger.log(Logger.java:473)
        at com.sleepycat.je.utilint.Tracer.trace(Tracer.java:71)
        at com.sleepycat.je.recovery.RecoveryManager.undoLNs(RecoveryManager.java:995)
        at com.sleepycat.je.recovery.RecoveryManager.buildTree(RecoveryManager.java:428)
        at com.sleepycat.je.recovery.RecoveryManager.recover(RecoveryManager.java:153)
        at com.sleepycat.je.dbi.EnvironmentImpl.<init>(EnvironmentImpl.java:338)
        at com.sleepycat.je.dbi.DbEnvPool.getEnvironment(DbEnvPool.java:101)
        at com.sleepycat.je.dbi.DbEnvPool.getEnvironment(DbEnvPool.java:53)
        at com.sleepycat.je.Environment.<init>(Environment.java:100)
        at com.sleepycat.je.XAEnvironment.<init>(XAEnvironment.java:35)

    This problem was reported in this JE forum thread, and a patch was posted there. [#15293] (3.2.21)
28. Fixed a bug where an exception similar to the following exception could occur after calling Environment.removeDatabase() for a deferred write database for which Database.sync() was never called.

        com.sleepycat.je.DatabaseException: (JE 3.0.12) Database XXX id=404 IN
        type=BIN/2 id=3335404 not expected on INList
        at com.sleepycat.je.evictor.Evictor.selectIN(Evictor.java:469)
        at com.sleepycat.je.evictor.Evictor.evictBatch(Evictor.java:330)
        at com.sleepycat.je.evictor.Evictor.doEvict(Evictor.java:242)
        at com.sleepycat.je.evictor.Evictor.doCriticalEviction(Evictor.java:266)
        at com.sleepycat.je.dbi.CursorImpl.close(CursorImpl.java:666)
        at com.sleepycat.je.Cursor.close(Cursor.java:243)
        at com.sleepycat.je.Database.putInternal(Database.java:571)
        at com.sleepycat.je.Database.putNoOverwrite(Database.java:530)

    This problem was reported in this JE forum thread. [#15317] (3.2.21)
29. Fixed a bug in JE debugging code that caused an assertion to fire when running with opening and closing multiple environments with assertions enabled. The stack trace would look something like this:

        java.lang.AssertionError at
        com.sleepycat.je.latch.Java5SharedLatchImpl.releaseIfOwner(Java5SharedLatchImpl.java:205).

    This problem was reported in this JE forum thread. [#15329] (3.2.21)
30. Fixed a race condition at Environment startup which could result in a deadlock between the Cleaner thread and the thread instantiating the Environment object. This problem can only occur with pre-existing environments. The thread that is calling new Environment() will hang with a stack trace similar to this:

         at sun.misc.Unsafe.park(Native Method)
           - parking to wait for  <0x06bc5308> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
         at java.util.concurrent.locks.LockSupport.park(Unknown Source)
         at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source)
         at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(Unknown Source)
         at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(Unknown Source)
         at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(Unknown Source)
         at java.util.concurrent.locks.ReentrantLock.lock(Unknown Source)
         at com.sleepycat.je.latch.Java5LatchImpl.acquire(Java5LatchImpl.java:84)
         at com.sleepycat.je.dbi.INList.latchMinor(INList.java:309)
         at com.sleepycat.je.dbi.INList.latchMinorAndDumpAddedINs(INList.java:298)
         at com.sleepycat.je.dbi.INList.releaseMajorLatch(INList.java:284)
         at com.sleepycat.je.dbi.MemoryBudget.calcTreeCacheUsage(MemoryBudget.java:586)
         at com.sleepycat.je.dbi.MemoryBudget.initCacheMemoryUsage(MemoryBudget.java:563)
         at com.sleepycat.je.dbi.EnvironmentImpl.<init>(EnvironmentImpl.java:368)
         at com.sleepycat.je.dbi.DbEnvPool.getEnvironment(DbEnvPool.java:101)

    [#15364] (3.2.21)
31. Fixed a bug regarding databases which support sorted duplicates where the wrong key comparator can be used in certain cases by the compressor daemon. The problem results in some wasted work for the compressor daemon, and the possibility that a user specified custom duplicate comparator is called with the wrong type of data, but will not affect database correctness or database operations. This problem was reported in this JE forum thread. [#15375] (3.2.21)
32. Fixed a problem with log cleaning and deferred write databases. Before, log files were often not cleaned when data in deferred write databases overflowed to disk, was modified, and became obsolete. This problem has been corrected; however, to ensure log cleaning occurs you must either 1) call Database.sync before Database.close, or 2) call Environment.removeDatabase before Environment.close() [#15391] (3.2.21)
33. Fixed a bug which in rare cases caused a DatabaseException with the message "NULL_LSN without KnownDeleted" during recovery when opening an Environment read-only, following an abnormal shutdown. [#15397] (3.2.21)
34. Fixed a bug which resulted in a NullPointerException when Environment.close() is called with java.util.logging.level set to FINE. This problem was reported in this JE forum thread. (3.2.21)
35. Fixed a rare case in which an Error (for example, a java.lang.OutOfMemoryError) is caught and can trigger a transaction abort, but fails to invalidate the environment. Since OutOfMemoryError can result in unpredictable behavior upon subsequent I/O activity, JE's general choice of action is to invalidate the environment and throw RunRecoveryException on all subsequent operations. Although this is not proven, it seems possible that this failure to invalidate the environment could lead to data corruption, so this bug fix, although small in scope, is deemed critical. [#15417](3.2.23)
36. Fixed a bug which allowed operations other than commit() and rollback() to occur on XAEnvironment instances which had been "prepared". Changed the XAEnvironment.prepare() method to return XA_RDONLY for read-only transactions. The problem was initially reported on this JE Forum thread. [#15423] (3.2.23)
37. Fixed a bug that causes a memory leak for applications where many Environment objects are opened and closed and the CurrentTransaction or TransactionRunner class is used. The problem was reported in this JE Forum thread [#15444] (3.2.28)
38. Fixed a bug that prevents correct recovery of data records when duplicates are configured (DatabaseConfig.setSortedDuplicates(true)) for a deferred-write database (DatabaseConfig.setDeferredWrite(true)). When a crash occurs and duplicate data records are recovered that were flushed after the last checkpoint, the wrong key is used for those records. This bug does not occur when the environment is closed normally or a checkpoint is performed after writing data records. [#15474](3.2.28)
39. Fixed a bug that prevents Database.preload from working when duplicates are configured (DatabaseConfig.setSortedDuplicates(true)) for the database. When the preload method was called for a database for which duplicate records exist, an assertion would fire or a NullPointerException would be thrown, depending on whether assertions are enabled. [#15475] (3.2.28)
40. Enhanced SerialBinding and the Direct Persistence Layer to use the current thread's context class loader when loading application classes. This allows the JE jar file to be deployed in application servers and other containers as a shared library rather than as an application jar. [#15447] (3.2.28)
41. Fixed a bug that caused JE to incorrectly behave as if the cache was very full. The symptoms of this bug are:
    - Because the problem is a cumulative accounting error, symptoms appear after running for a long period of time.
    - JE slows down or methods fail to return. Thread dumps show that the com.sleepycat.je.evictor.Evictor class is active and looping.
    - Dumping EnvironmentStats shows that the adminBytes size (EnvironmentStats.getAdminBytes()) is unreasonably large and may be larger than the maximum cache size or the heap size.
    - The problem occurs more frequently when blocks of sequential records are deleted.
    [#15505] (3.2.28)
42. Fixed a bug where the cache usage accounting could become inaccurate if the cache size was changed while the application is active (using Environment.setMutableConfig()) and there are outstanding record locks. [#15505] (3.2.28)
43. Fixed a bug which could degrade the performance of cache eviction. The problem can only be seen by applications which execute Database.delete(), Cursor.delete(), Environment.removeDatabase() or Environment.truncateDatabase(), and is very timing dependent. The symptom is thread dumps which show that the application is frequently executing the java.io.File.exists() call with this stack trace:

               at java.io.File.exists(File.java:733)
               at com.sleepycat.je.cleaner.UtilizationProfile.putFileSummary(UtilizationProfile.java:747)
               at com.sleepycat.je.cleaner.UtilizationTracker.evictMemory(UtilizationTracker.java:118)
               at com.sleepycat.je.evictor.Evictor.evictBatch(Evictor.java:313)
               at com.sleepycat.je.evictor.Evictor.doEvict(Evictor.java:253)

    [#15512]
44. Fixed a bug that caused incorrect query results and possibly errors during recovery (data corruption) when updating a record in a database with duplicates configured and when a custom duplicate comparator is configured that does not compare all data bytes. Now, when updating a record in a database with duplicates configured, the data may not be changed by updating the record. A DatabaseException will be thrown if this is attempted, in order to prevent incorrect query results and data corruption.

    This limitation will be removed in a future release in order to allow changing the data of a record in a database with duplicates configured, when a custom duplicate comparator is used that does not compare all data bytes. But note that even then, changing the sort order of a duplicate will not be possible by updating the record. To change the sort order of any record (with or without duplicates configured), you must delete and then re-insert the record.

    The problem was reported in this JE Forum thread. [#15527] (3.2.28)

45. Fixed a bug where a lock was not released when Environment.openSecondaryDatabase threw an exception during population of the secondary. The unreleased lock was reported via an exception when closing the Environment. This bug was not reported from the field and could only occur if SecondaryConfig.setAllowPopulate(true) was called and a foreign key constraint was violated. [#15558] (3.2.30)
46. Fixed a bug where a non-transactional SecondaryCursor did not hold a lock on the associated primary record. The bug allowed other threads to change or delete the primary record. The problem was reported in this JE Forum thread [#15573] (3.2.31)
47. Fixed a bug that could cause the following exception when deleting and inserting duplicates in multiple threads. The bug would only occur if a duplicate record was deleted by one thread and the same record was inserted by another thread very soon afterward, before the first thread released the lock (moved the cursor or committed the transaction).

        com.sleepycat.je.latch.LatchException: (JE 3.2.23) BIN45 already held at
           com.sleepycat.je.latch.Java5SharedLatchImpl.acquireExclusive(Java5SharedLatchImpl.java:87)
        at com.sleepycat.je.tree.IN.latch(IN.java:326)
        at com.sleepycat.je.tree.IN.latch(IN.java:365)
        at com.sleepycat.je.dbi.CursorImpl.latchBIN(CursorImpl.java:457)
        at com.sleepycat.je.tree.Tree.insertDuplicate(Tree.java:2879)

    The problem was reported in this JE Forum thread [#15574](3.2.31)
48. Fixed a bug which could cause the following exception for deferred write databases with deleted records. This can only occur if the default daemon compressor thread is running.

         com.sleepycat.je.DatabaseException: (JE 3.2.29) fetchTarget of null lsn parent IN=226141 lastFullVersion=0xffffffff/0xffffffff
           parent.getDirty()=true state=10 NULL_LSN without KnownDeleted
        com.sleepycat.je.DatabaseException: (JE 3.2.29) fetchTarget of null lsn parent IN=226141 lastFullVersion=0xffffffff/0xffffffff
           parent.getDirty()=true state=10 NULL_LSN without KnownDeleted
        at com.sleepycat.je.tree.IN.fetchTarget(IN.java:942)
        at com.sleepycat.je.tree.BIN.compress(BIN.java:670)
        at com.sleepycat.je.incomp.INCompressor.compressBin(INCompressor.java:503)
        at com.sleepycat.je.incomp.INCompressor.doCompress(INCompressor.java:414)
        at com.sleepycat.je.incomp.INCompressor.onWakeup(INCompressor.java:342)
        at com.sleepycat.je.utilint.DaemonThread.run(DaemonThread.java:191)

    The problem was reported in this JE Forum thread [#15588](3.2.32)
49. Fixed a bug that caused data loss when deleting and then inserting a record with the same key in a deferred-write database. Depending on timing of the application threads and JE compressor thread, the inserted record could be deleted internally and appear to vanish. The problem first appeared in JE 3.2.32. The problem was reported in this JE Forum thread. [#15684]
50. Fixed a bug where the wrong key or duplicate data could be returned by queries when a custom btree or duplicate comparator is configured that does not compare all bytes. The bug could occur in the following situation:

    1. In transaction T, a previously existing record with key K is deleted.
    2. In T, a record with key K' is inserted, where K' and K are not identical byte arrays, but are considered equal by the custom key comparator.
    3. T is aborted.

    If the timing is right, the previously existing record would not be restored correctly when the transaction is aborted. Instead of having key K it would have key K'. When the previously existing record is returned by a query, key K' would be incorrectly returned.

    The same thing could occur for data elements (rather than keys) when using a duplicates database with a custom duplicate comparator (rather than a custom btree comparator).

    This problem was initially reported in this JE Forum thread. [#15704](3.2.49)

51. Fixed a bug where com.sleepycat.collections.CurrentTransaction.getInstance() could return a different CurrentTransaction instance when called more than once with the same environment parameter. This was counter to the behavior specified in the javadoc, and has been fixed. The problem was initially reported in this JE Forum thread. [#15721](3.2.49)
52. Fixed cache under-budgeting errors for 64-bit JVM platforms. The JE cache size is now more accurate on 64-bit JVM platforms and less extra heap memory is needed. Note that in general, for a given application and a given in-cache data set, a larger cache and heap size is always needed for 64-bit than for 32-bit platforms. [#15774] (3.2.59)
53. Fixed a cache memory budgeting error that could cause OutOfMemoryError. The problem occurs when a large log (thousands of log files or more) is processed by the log cleaner, the log contains a very small amount of active (non-obsolete) data, and the application has a very low write rate. [#15831](3.2.59)
54. Improved behavior and performance when a small JE cache is configured (1 MB or less) or all cache memory is used by locks in a large transaction. Before, cache eviction sometimes caused excessive log growth when no memory was available for use by the Btree. Now, a minimum amount is reserved for the Btree. By default, this minimum amount is 500 KB or the amount initially available in the cache when the environment is opened, whichever is smaller. The je.tree.minMemory configuration parameter can be used to override the default amount. Several other changes were also made to prevent cache eviction from causing uncontrolled log growth. [#15831](3.2.59)
55. Fixed a bug where some operations on a closed (or invalid) com.sleepycat.je.Environment handle were not detected and resulted in a NullPointerException within JE. JE now throws a com.sleepycat.je.DatabaseException in this circumstance. A specific instance of the problem was reported for the com.sleepycat.je.Environment.getThreadTransaction operation in this JE Forum thread. [#15861](3.2.68)
56. Fixed a bug which prevented prepared, but not committed, transactions (i.e. distributed transactions) from being held open past a checkpoint. This was originally reported on the JE OTN forum [#15872](3.2.65)
57. Fixed a bug which could cause possible data corruption when an IOException is thrown on a disk write. In addition, JE has been changed to throw a RunRecoveryException when an IOException occurs on a disk write, thereby preventing further operations on the environment. [#15754](3.2.66)
58. Fixed a bug that caused various exceptions when using Environment.removeDatabase or truncateDatabase. Two examples of exceptions caused by this bug are below.

        com.sleepycat.je.DatabaseException: (JE 3.2.44) Database
        relations_database14269 id=26 rootLsn=0xffffffff/ 0xffffffff  IN type=DBIN/2
        id=29976291 not expected on INList
        at com.sleepycat.je.evictor.Evictor.selectIN(Evictor.java:511)
        at com.sleepycat.je.evictor.Evictor.evictBatch(Evictor.java:354)
        at com.sleepycat.je.evictor.Evictor.doEvict(Evictor.java:249)
        at com.sleepycat.je.evictor.Evictor.doCriticalEviction(Evictor.java:274)

        com.sleepycat.je.DatabaseException: (JE 3.2.21) can't find database 8188589
        at com.sleepycat.je.dbi.DbTree.modifyDbRoot(DbTree.java:270)
        at com.sleepycat.je.recovery.Checkpointer.flushIN(Checkpointer.java:746)
        at com.sleepycat.je.recovery.Checkpointer.flushDirtyNodes(Checkpointer.java:669)
        at com.sleepycat.je.recovery.Checkpointer.doCheckpoint(Checkpointer.java:447)

    This bug was reported in two forum threads:
    http://forums.oracle.com/forums/thread.jspa?messageID=2202574
    http://forums.oracle.com/forums/thread.jspa?threadID=574359

    [#15805](3.2.68)

59. Fixed a bug in the remove method of the Iterator instances returned by the StoredCollection.iterator method in the collections package. This bug caused ArrayIndexOutOfBoundsException in some cases when calling next, previous, hasNext or hasPrevious after calling remove. (Note that this issue does not apply to StoredIterator instances returned by the StoredCollection.storedIterator method.) This bug was reported in this forum thread:
    http://forums.oracle.com/forums/thread.jspa?messageID=2187896
    [#15858](3.2.68)
60. Fixed a bug in the remove method of the StoredIterator instances returned by StoredCollection.storedIterator method in the collections package. If the sequence of methods next-remove-previous was called, previous would sometimes return the removed record. If the sequence of methods previous-remove-next was called, next would sometimes return the removed record. (Note that this issue does not apply to Iterator instances returned by the StoredCollection.iterator method.) [#15909](3.2.68)
61. Fixed a bug that could cause LogFileNotFoundException when using a Deferred Write database (DatabaseConfig.setDeferrredWrite(true)). The bug could occur when a Deferred Write database was opened sometime after opening the Environment. The bug was very unlikely to occur if all Deferred Write databases were opened immediately after opening the Environment. (3.2.74) [#15913]
62. Fixed a bug that could cause Database.sync to hang. [#15920]
63. Fixed a bug that caused an ArrayIndexOutOfBoundsException to be thrown when nodeIds get too large. (3.2.74) [#15926]
64. Fixed a bug in com.sleepycat.je.Transaction.setTxnTimeout() which permitted transaction timeouts even when the method was called with a value of 0. That was contrary to the documented description, and has been fixed. The problem was initially reported in this JE Forum thread. (3.2.74) [#15964]
65. Enforce a limit on the maximum size that a DeadlockException message string may be to limit OOMEs. (3.2.74) [#15977]
66. Fixed the following NullPointerException which could be seen when opening an existing environment with a log of less than 1345 bytes:

        Caused by: com.sleepycat.je.DatabaseException: (JE 3.2.68) last LSN=0x0/0x1d2
        at com.sleepycat.je.recovery.RecoveryManager.traceAndThrowException(RecoveryManager.java:2365)
        at com.sleepycat.je.recovery.RecoveryManager.redoLNs(RecoveryManager.java:1182)
        at com.sleepycat.je.recovery.RecoveryManager.buildTree(RecoveryManager.java:440)
        at com.sleepycat.je.recovery.RecoveryManager.recover(RecoveryManager.java:153)
        at com.sleepycat.je.dbi.EnvironmentImpl.<init>(EnvironmentImpl.java:348)
        at com.sleepycat.je.dbi.DbEnvPool.getEnvironment(DbEnvPool.java:102)
        at com.sleepycat.je.dbi.DbEnvPool.getEnvironment(DbEnvPool.java:54)
        at com.sleepycat.je.Environment.<init>(Environment.java:103)
        Caused by: java.lang.NullPointerException
        at com.sleepycat.je.utilint.DbLsn.compareTo(DbLsn.java:76)
        at com.sleepycat.je.recovery.RecoveryManager.redoLNs(RecoveryManager.java:1081)
        ... 34 more

    The log has no user data and only holds the beginning of JE internal data structures so no data is lost, but the environment can't be reopened until the log file is removed. The problem was initially reported in this JE Forum thread. (3.2.74)[#16016]
67. A problem was fixed in which ByteBuffer.array() was not being offset by ByteBuffer.arrayOffset(). This could result in a DbChecksumException. [#15941] (3.2.76) [#16107]

### API Changes:

1. Iterators returned by StoredCollection.iterator() no longer need closing. The original StoredIterator is now available using the new StoredCollection.storedIterator() method. See the Release Notes for more information on collection API changes. [#12986](3.0.11)
2. Database.entry now supports equals() and hashCode(). [#13778](3.0.11)
3. Key comparators can now be stored as serialized objects using the new DatabaseConfig.setBtreeComparator(Comparator) and DatabaseConfig.setDuplicateComparator(Comparator) methods. This allows a single comparator class to handle more than one key format. [#14422](3.0.11)
4. SecondaryDatabase.delete has been corrected to delete all keys (and their associated primary records) in the presence of duplicates. Before, only the first of a duplicate set (and its associated primary) was deleted. Please note this behavior change. [#14506](3.0.11)
5. Added `com.sleepycat.je.jca.ra.JEConnection.removeDatabase(), com.sleepycat.je.jca.ra.JEConnection.truncateDatabase()`to support database truncation and removal for JCS users. [#15105]
6. For debugging usage, DatabaseEntry.toString() now outputs the data as decimal bytes. The new DatabaseEntry.MAX_DUMP_BYTES (default 100) static field can be changed to limit the number of bytes that are output. [#15248] (3.2.13)
7. Added je.evictor.forcedYield to improve GC behavior for systems with unfair thread scheduling and/or many environments open. [#15329] (3.2.21)
8. The Collections API has been enhanced so that auto-commit works for the standard Java Iterator.remove(), set() and add() methods. Previously it was necessary to explicitly begin and commit a transaction in order to call these methods, when the underlying Database was transactional. Note that starting a transaction is still necessary when calling these methods if the StoredCollection.storedIterator method is used. [#15401] (3.2.21)
9. Added the EnvironmentStats.getAdminBytes() and getLockBytes() methods, which return the amount of cache used for transactions, administrative structures such as log cleaning metadata, and locks. These values are a subset of the value returned by Environment.getCacheDataBytes() and can provide more insight into how the cache is allocated between actual data and other objects. [#15505] (3.2.28)
10. Added the EnvironmentStats.getTotalLogSize method. This new method returns the approximate total size of the JE log files in bytes. It could be used, for example, to detect that the log has exceeded an application disk space limit. [#15480] (3.2.28)
11. Added `Environment.scanLog()` which allows programmatic scanning of the JE log. The function and restrictions are detailed in the javadoc. [#15532](3.2.49)
12. Added DeadlockException.getOwnerTxnIds() and DeadlockException.getWaiterTxnIds() methods to support programmatic processing of DeadlockExceptions. These return a long[] containing the txnids of owners and waiters on the lock that caused the timeout. [#15665](3.2.49)

### Utility Changes:

1. DbVerify will now verify all databases in the environment if the "-s" flag is omitted. In previous versions, "-s" was a mandatory parameter. A new option, "-c" has been added which will check log cleaner metadata. [#14239](3.0.11)
2. com.sleepycat.je.util.DbCacheSize is now callable programmatically, in addition to being usable as a command line program. A new option, -r, for recalculating utilization is also available. DbCacheSize is not an officially supported utility and is not documented; for details, please see the DbCacheSize.java source file. [#15217] (3.2.13)
3. Added more options for -k to DbPrintLog. Options may now specify text, binary, hex, or obfuscate. "text" dumps the records as strings, "binary" dumps the records as unsigned bytes, and "hex" as unsigned hex bytes. "obfuscate" dumps no data and only shows the number of bytes in the key and data. "none" doesn't show any information about the key or data.[#15773] (3.2.52)

### Configuration, Documentation, and Build Changes:

1. Ant 1.6.0 or later is required to build JE from the provided sources.(3.0.11)
2. The directions in the installation page on how to compile a non-debug jar were updated.(3.0.11)
3. The "Writing Transactional Applications" guide has been corrected to make it clear that nested transactions are not yet supported in JE. [#14079](3.0.11)
4. A variety of problems noted by our faithful readers have been fixed.
   - The examples now specify a character encoding when constructing a String object.
   - The examples use the base interface type when possible, rather than a specific collection class.
   - ExampleDatabaseLoad.loadFile() now closes its FileInputStream.
   - Two examples in the Concurrency chapter of the "Writing Transactional Applications" manual were updated to correctly return after a commit.
   (3.0.11)
5. In response to popular demand, the JE jarfile in a JE package is now named je-<version>.jar instead of just je.jar. For example, the jar in this release is named je-3.1.0.jar. [#14669](3.1.0)
6. Fixed Javadoc for EnvironmentMutableConfig.setTxnWriteNoSync(). The Javadoc for this method incorrectly stated that this type of durability would not survive JVM failures. setTxnWriteNoSync style durability does, in fact, survive JVM crashes.
7. The Javadoc for the com.sleepycat.persist.SecondaryIndex class was enhanced to discuss: One-to-Many versus Many-to-One for Related Entities; Key Placement with Many-to-Many for Related Entities; and Many-to-Many Versus a Relationship Entity.
8. The Java Collections Tutorial and associated example code was updated to remove mention of StoredIterator and the requirement to close stored iterators. As of JE 3.0.11, iterators over stored collections no longer need to be closed. [#15202] (3.2.13)
9. Several sporadic test failures were fixed and the test suite ("ant test") should now run reliably on all platforms.
10. Fixed a build problem where the DPL (com.sleepycat.persist package) was compiled to run on Java 1.6 only. This caused a failure when attempting to access DPL classes, via compilation or execution:

        java.lang.UnsupportedClassVersionError: Bad version number in .class file

    or

        class file has wrong version 50.0, should be 49.0

    The DPL classes have been rebuilt to target Java 1.5. This problem was introduced in JE 3.2.42. The problem was reported in this JE Forum thread Note that in Java 1.6, if "-source 1.5" is specified this does not cause "-target 1.5" to be the default target setting. This is a change to javac in Java 1.6 and was the source of the JE build problem. [#15675] (3.2.43)
11. Fixed a problem that occurs when an empty directory (test/regress) that is part of the release package is not created when unpacking the archive. Specifically this occurred after using the Eclipse import command. This caused a failure when attempting to re-build JE from sources:

        .../test/regress does not exist!

    The JE build now creates this directory if it is missing. This problem was introduced in JE 3.2.42. The problem was reported in this JE Forum thread. [#15679] (3.2.43)
12. A new property, `je.log.useODSYNC`, has been added which causes all JE log files (`*.jdb`) to be opened using the `O_DSYNC` flag. This causes all JE writes to be written directly to disk before the `write()` call returns (rather than forced later when `fsync()` is called). The default value for this parameter is `false` (do not force each `write()` to disk).

    This property should always be set to `true` when the environment directory resides on a "remote" system accessed using (e.g.) NFS or SMB and should be set to `false` when the environment directory is on a local disk.

    JE expects the `write` system call to flush data to the operating system, and the `fsync` system call to flush data to disk. Depending on the remote file system configuration, some systems may cache data from `write()` calls on the server side, even after control is returned to the calling client (JE), which makes JE unable to guarantee the consistency of the log. Setting this property to `true` prevents server-side caching and guarantees that all remote `write()` calls are durable. Enabling this parameter will cause some performance degradation, varying by system and workload. [#15775] (3.2.62)

13. The chapter on Using Join Cursors in the Getting Started Guide incorrectly stated that the array of secondary cursors must be null terminated. This is not true, and has been corrected. [#15832](3.2.59)

### Direct Persistence Layer:

1. Fixed a bug where `"UnsupportedOperationException: Class evolution is not supported"` was thrown when performing class enhancement. This problem would occur when creating a store without enhancing classes and then using enhancement later, or when creating a store with class enhancement and then not using enhancement later. [#14651](3.0.12)
2. Fixed a bug where `"ArrayIndexOutOfBoundsException: 2147483646"` was thrown when updating a record with a secondary key. The problem occurred when a single instance was used for both the primary key and secondary key fields. [#14665](3.0.12)
3. Fixed a bug where `"IllegalArgumentException: Class is not persistent"` was thrown for a class that was correctly made persistent using a proxy class. The problem occurred when one proxy class referenced another. [#14665](3.0.12)
4. Before, if a custom key class (composite key class) was defined but the @KeyField annotation was not included, an UnsupportedOperationException would occur when trying to put() a record, and the exception message was not meaningful. Now, an IllegalArgumentException will occur when getting the index, with a meaningful exception message. [#14673](3.0.12)
5. Class evolution is now implemented in the Direct Persistence Layer. For more information please see the release notes and the package specification for the com.sleepycat.persist.evolve package. Also note that if you have deployed a store using the JE 3.0.12 beta release, before changing your persistent classes for the first time you must open and close your store using the JE 3.1 release; see the release notes for more information. [#14762]
6. Fixed a bug that prevented opening a read-only store when a primary key sequence was used. [#14941]
7. Fixed a bug that prevented using EntityJoin with read-uncommitted (for example, CursorConfig.READ_UNCOMMITTED). The fix is a change to JE secondary databases that allows a partial DatabaseEntry to be passed as the data parameter to a search method, when using read-uncommitted. [#14966]
8. Fixed a bug in EntityStore.getStoreNames() which resulted in this stack trace:

       java.lang.StringIndexOutOfBoundsException: String index out of range: -9
       	at java.lang.String.substring(Unknown Source)
       	at com.sleepycat.persist.impl.Store.getStoreNames(Store.java:209)
       	at com.sleepycat.persist.EntityStore.getStoreNames(EntityStore.java:186)

   [#14978]
9. Fixed a bug that caused an IllegalArgumentException when calling EntityStore.getSecondaryIndex for a @SecondaryKey that was declared on a superclass of the entity class. [#14978]
10. The EntityStore.getSubclassIndex method has been added. This method should be used instead of getSecondaryIndex when the secondary key field is in a subclass of an entity class. The index returned by getSubclassIndex is used to access only entities of that subclass. Note that in the previous release, calling getSecondaryIndex in such a situation would fail, and it was necessary to call registerClass as a workaround. [#15102]
11. A bug was fixed that caused an IllegalArgumentException with the message "Not a key class". This occurred when using a TO_MANY secondary index with a composite key class. The workaround for the bug was to call registerClass for the key class, and this is no longer necessary. [#15103]
12. An optional verbose option was added to the ClassEnhancer to print the name of each class file that is enhanced. See ClassEnhancer for more information. [#14680](3.0.12)
13. Class evolution is now implemented in the Direct Persistence Layer. For more information please see the release notes and the package specification for the com.sleepycat.persist.evolve package. Also note that if you have deployed a store using the JE 3.0.12 beta release, before changing your persistent classes for the first time you must open and close your store using the JE 3.1 release; see the release notes for more information. [#14762](3.1.0)
14. Fixed a bug that prevented opening a read-only store when a primary key sequence was used. [#14941](3.1.0)
15. Fixed a bug that prevented using EntityJoin with read-uncommitted (for example, CursorConfig.READ_UNCOMMITTED). The fix is a change to JE secondary databases that allows a partial DatabaseEntry to be passed as the data parameter to a search method, when using read-uncommitted. [#14966](3.1.0)
16. Fixed a bug in EntityStore.getStoreNames() which resulted in this stack trace:

        java.lang.StringIndexOutOfBoundsException: String index out of range: -9
        	at java.lang.String.substring(Unknown Source)
        	at com.sleepycat.persist.impl.Store.getStoreNames(Store.java:209)
        	at com.sleepycat.persist.EntityStore.getStoreNames(EntityStore.java:186)

    [#14978](3.1.0)
17. Fixed a bug that caused an IllegalArgumentException when calling EntityStore.getSecondaryIndex for a @SecondaryKey that was declared on a superclass of the entity class. [#14978](3.1.0)
18. The EntityStore.getSubclassIndex method has been added. This method should be used instead of getSecondaryIndex when the secondary key field is in a subclass of an entity class. The index returned by getSubclassIndex is used to access only entities of that subclass. Note that in the previous release, calling getSecondaryIndex in such a situation would fail, and it was necessary to call registerClass as a workaround. [#15102](3.1.0)
19. A bug was fixed that caused an IllegalArgumentException with the message "Not a key class". This occurred when using a TO_MANY secondary index with a composite key class. The workaround for the bug was to call registerClass for the key class, and this is no longer necessary. [#15103](3.1.0)
20. Fixed a bug where the wrong key class was validated when calling EntityStore.getSecondaryIndex for a read-only store with a TO_MANY secondary. The application would see an IllegalArgumentException prefixed with "Wrong secondary key class:". [#15156] (3.2.13)
21. Fixed a bug where the DPL was not working correctly with implicit transactions in an XA environment. The problem was reported in this JE Forum thread.. Now, when an XAEnvironment is used, XA transactions are implicit when a null transaction parameter, or no transaction parameter, is used in the DPL API. [#15206] (3.2.13)
22. Fixed a potential performance problem with secondary indexes that are defined in entity subclasses. When an instance of an entity subclass is stored (via PrimaryIndex.put), we now create any secondary indexes that are defined on that subclass. Before, the secondary indexes were not created until EntityStore.getSubclassIndex was called. This was not technically a bug, since there was no loss of data and secondary indexes were created when they were used. But now the index is created as soon as possible, so that the index does not have to populated from scratch when it is first accessed. [#15247] (3.2.13)
23. Added the StoreConfig.setSecondaryBulkLoad and getSecondaryBulkLoad methods. This new mode allows a bulk load of the primary without updating any secondaries until they are needed by the application. The secondaries are automatically populated when needed. See StoreConfig.setSecondaryBulkLoad for details. [#15525] (3.2.31)

    Fixed a bug where all secondary databases were not opened in a single transactional along with the primary database as documented. This bug has not been reported from the field and is unlikely to have caused a problem, since database open rarely fails except as the result of a catastrophic error, in which case the store would not be usable anyway. But when the new method setSecondaryBulkLoad(true) is used, a secondary database could fail to open while populating it if a foreign key constraint is violated. [#15525] (3.2.31)

24. If a DPL class cannot be loaded via Thread.getContextClassLoader, as a fall-back we now try loading it via the ordinary Class.forName(String) method. This makes the DPL work with the Scala language. [#15576] (3.2.31)
25. Fixed a DPL bug where a primary key sequence could not be used with a custom comparator. For a primary key with a sequence it is now possible to use a composite key class containing a single integer key field, and implement Comparable in that key class as described in the javadoc. The problem was initially reported in this JE Forum thread[#15717](3.2.49)
26. Fixed a DPL bug that occurs when @SecondaryKey(...,onRelatedEntityDelete=NULLIFY) is used on a field that is in a superclass of the entity class rather than in the entity class itself. This caused an exception similar to the following, although a different exception could also occur:

        java.lang.IllegalArgumentException: Key field object may not be null
        at com.sleepycat.persist.impl.RecordOutput.writeKeyObject(RecordOutput.java:101)
        at com.sleepycat.persist.impl.RawAccessor.writeField(RawAccessor.java:219)
        at com.sleepycat.persist.impl.RawAccessor.writeSecKeyFields(RawAccessor.java:114)
        at com.sleepycat.persist.impl.ComplexFormat.writeObject(ComplexFormat.java:479)
        at com.sleepycat.persist.impl.PersistEntityBinding.writeEntity(PersistEntityBinding.java:114)
        at com.sleepycat.persist.impl.PersistKeyCreator.nullifyForeignKey(PersistKeyCreator.java:139)
        ...

    The problem was initially reported in this JE Forum Thread.[#15733](3.2.49)
27. Before, when a proxied object contained an embedded reference to itself, this caused StackOverflowException. Now, a more meaningful IllegalArgumentException is thrown. This occurs, for example, if a container (List, Map, etc) contains itself as an element, since containers are proxied. This limitation is now documented in the PersistentProxy class description. The Entity class description also mentions a limitation on nested object depth (12,000 is the practical maximum depth) and exceeding this limit can cause stack overflow. The problem was initially reported in this JE Forum Thread. [#15815](3.2.55)
28. Fixed a bug where adding or removing @SecondaryKey for an existing field could cause IndexOutOfBoundsException. The bug would occur in one of two circumstances:
    - If @SecondaryKey is added to an existing field that happens to be the only non-key field in the class.
    - If @SecondaryKey is removed from an existing field that happens to be the only secondary key field in the class.

    This bug was reported on this forum thread. An example stack trace follows, although the stack trace for this problem varies.

        java.lang.IndexOutOfBoundsException
        at com.sleepycat.bind.tuple.TupleInput.readUnsignedInt(TupleInput.java:414)
        at com.sleepycat.bind.tuple.TupleInput.readInt(TupleInput.java:233)
        at com.sleepycat.persist.impl.SimpleFormat$FInt.readPrimitiveField(SimpleFormat.java:403)
        at com.sleepycat.persist.impl.ReflectionAccessor$PrimitiveAccess.read(ReflectionAccessor.java:429)
        at com.sleepycat.persist.impl.ReflectionAccessor.readNonKeyFields(ReflectionAccessor.java:274)
        at com.sleepycat.persist.impl.ComplexFormat$PlainFieldReader.readFields(ComplexFormat.java:1606)
        at com.sleepycat.persist.impl.ComplexFormat$MultiFieldReader.readFields(ComplexFormat.java:1814)
        at com.sleepycat.persist.impl.ComplexFormat$EvolveReader.readObject(ComplexFormat.java:1943)
        at com.sleepycat.persist.impl.PersistEntityBinding.readEntity(PersistEntityBinding.java:88)
        at com.sleepycat.persist.impl.PersistEntityBinding.entryToObject(PersistEntityBinding.java:58)
        at com.sleepycat.persist.EntityValueAdapter.entryToValue(EntityValueAdapter.java:56)
        at com.sleepycat.persist.BasicCursor.returnValue(BasicCursor.java:206)
        at com.sleepycat.persist.BasicCursor.next(BasicCursor.java:74)
        at com.sleepycat.persist.BasicIterator.hasNext(BasicIterator.java:50)

    [#15524] (3.2.55)
29. Fixed a DPL bug where a primary key sequence could not be used with a custom comparator. For a primary key with a sequence it is now possible to use a composite key class containing a single integer key field, and implement Comparable in that key class as described in the Javadoc. The problem was initially reported in this JE Forum thread[#15717]
30. Fixed a class evolution bug where adding a new field and converting a field (using a field Converter) in the same class could cause IndexOutOfBoundsException. [#15797](3.2.59}
31. Added examples/persist/DplDump.java example program. [#15870](3.2.68)
32. Added examples/persist/ScalaPersonExample.scala example program.(3.2.68)
33. Fixed a bug where EntityStore.evolve() did not overwrite entities and therefore data evolution on read was not prevented and any previously configured Conversion classes were still required. [#15874](3.2.68)

#### Workaround for upgrade issue between JE 2.0.90 and JE 2.1.30

If you are upgrading from a release of JE that is 2.0.90 or earlier, then you should ensure that you call Environment.close() prior to upgrading. If you do not close the environment cleanly, and you have very recently created a new database, you may see the following exception:

>     com.sleepycat.je.DatabaseException: JE 3.0.11: searchResult=class
>     com.sleepycat. je.tree.IN nodeId=479 nEntries=0
>           at com.sleepycat.je.tree.Tree.getParentBINForChildLN(Tree.java:1031)
>     ...
>     Caused by: java.lang.ClassCastException: com.sleepycat.je.tree.IN
>            at
>            com.sleepycat.je.tree.Tree.getParentBINForChildLN(Tree.java:1021)

The data in the environment was not corrupted, and the environment can be successfully opened with the following steps which remove any new files create by JE 3.0.11, and then call Environment.close() prior to upgrading.

To remove any data created by JE 3.0.11:

- First take a directory listing of your Environment and examine all the *.jdb files written at the time of the attempted upgrade. For example:

      -rwx------   1 cwl      other      19629 May  5 11:26 00000000.jdb
      -rw-r--r--   1 cwl      other       3014 May  8 11:36 00000001.jdb <-- new file

- Examine all the new files to verify that they use file version 4 by doing:

      java com.sleepycat.je.util.DbPrintLog -h <envhome> -s <lastfilenumber>

  where <lastfilenumber> is a hex number of the last file (e.g. '-s 0x1' in the case above). You should see output like this:

      <DbPrintLog>
      <entry lsn="0x1/0x0" type="FileHeader/0" prev="0x0" size="24" cksum="800588407"><FileHeader num="0x1" lastEntryInPrevFileOffset="0x4c87"
      logVersion="0x4" time=" 2006-05-08 12:50:20.63"/></entry>

                 ...

  The first file header record shows a logVersion of 0x4. These files were written during the attempted upgrade and can be deleted.

To close the environment cleanly after any JE 3.0.11 data has been removed:

- Once the version 4 log files have been deleted, perform a checkpoint using the old (pre-2.0.90) version of JE. You can do this by calling Environment.close() from your application code or by invoking the unadvertised DbRunAction utility:

      java -cp "je-1.7.1.jar:je-3.0.11.jar" com.sleepycat.je.util.DbRunAction -h <envdir>

  Since DbRunAction is not present in releases prior to 2.1.30, you should include the latest release in the classpath, but after the old release. That will run a checkpoint on the old environment using the old version of JE. Several lines of output will be produced. Verify that the last log file was written to by taking a directory listing.
- Finally, perform another checkpoint using the newer version of JE. After this, the environment will be fully upgraded.

      java -cp "je-3.0.11.jar" com.sleepycat.je.util.DbRunAction -h <envdir>