Berkeley DB Java Edition 2.0.90 Change Log

Changes since Release 2.0.83 are described here. A full list of all changes since JE 1.7.1 is also available below.

It recommended that all users move to this release. Also see the documentation and Release Notes included in your download package or on our website.


Changes since 2.0.83

Log File On-Disk Format Changes:

General Environment Changes:

  1. Fix a bug which could result in the wrong record being returned from a "get" operation, in a special case where multiple threads are reading and inserting records in close key proximity. The bug could also manifest with the following stacktraces:
    com.sleepycat.je.DatabaseException: fetchTarget of 0x300/0x0 IN=12630615 state=0 
    java.lang.ClassCastException: com.sleepycat.je.log.FileHeader
           at com.sleepycat.je.tree.IN.fetchTarget(IN.java:936)
           at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
           at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
           at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
           at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
           at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
           at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
           at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
           at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
           at com.sleepycat.je.Cursor.search(Cursor.java:929)
           at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
    
    or
    
    java.lang.ArrayIndexOutOfBoundsException: 128
        at com.sleepycat.je.tree.IN.fetchTarget(IN.java:897)
        at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
        at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
        at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
        at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
        at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
        at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
        at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
        at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
        at com.sleepycat.je.Cursor.search(Cursor.java:929)
        at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
        
    or
    
    com.sleepycat.je.DatabaseException: fetchTarget of null lsn IN=749358 state=0 NULL_LSN without KnownDeleted
    Stacktrace: com.sleepycat.je.DatabaseException: fetchTarget of null lsn IN=749358 state=0 NULL_LSN without KnownDeleted at com.sleepycat.je.tree.IN.fetchTarget(IN.java:902)
            at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
            at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
            at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
            at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
            at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
            at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
            at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
            at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
            at com.sleepycat.je.Cursor.search(Cursor.java:929)
            at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
    
    [#13363](2.0.90)

  2. Fix a recovery bug that could prevent opening the environment for applications using duplicates. The user would see a com.sleepycat.je.tree.InconsistentNodeException. The database remains valid and consistent. [#13435](2.0.90)

API Changes:

  1. A new, unadvertised configuration parameter was added in 2.0.83 that was not documented in the 2.0.83 change log or release notes. This new parameter can improve performance for some applications with both of the following characteristics:

    1. Access by key is mostly random. There are few or no "hot" sets of records that are accessed more than others, and most record access is not in sequential key order.
    2. The memory size of the active record set is significantly larger than the configured JE cache size, causing lots of I/O as records are fetched from disk.

    If you have such an application you may want to try adding the following two configuration parameters to your je.properties file:

    je.evictor.lruOnly=false
    je.evictor.nodesPerScan=100
    

    je.evictor.lruOnly is a new setting added in 2.0.83. It changes the eviction algorithm, which is the way in which JE decides to remove records from the cache.

    The default eviction algorithm is LRU (least recently used) and the default setting for the lruOnly parameter is true. With the default algorithm, only the LRU of a Btree node is taken into account when choosing the next Btree node to be evicted.

    When lruOnly is set to false, the eviction algorithm is instead primarily based on the level of the node in the Btree. The lowest level nodes (the leaf nodes) are always evicted first, even if higher level nodes are less recently used. In addition, dirty nodes are evicted after non-dirty nodes.

    Setting lruOnly to false benefits random access applications because it keeps higher level Btree nodes in the tree for as long as possible. For a random key, this increases the likelihood that the relevant Btree internal nodes will be in the cache.

    We recommend that you also change je.evictor.nodesPerScan when you set lruOnly to false. This setting controls the number of Btree nodes that are considered, or sampled, each time a node is evicted. A setting of 100 often produces good results, but this may vary from application to application. The larger the nodesPerScan, the more accurate the algorithm. However, setting it too high is detrimental; the need to consider larger numbers of nodes for each eviction may delay the completion of a given database operation, which will impacts the response time of the application thread. (2.0.83)

Utility Changes:

Configuration, Documentation, and Build Changes:

New Features:



Full list of changes since JE 1.7.1

All changes from JE 2.0.42, 2.0.54, 2.0.83 and 2.0.90 are listed here.

Log File On-Disk Format Changes:

  1. JE 2.0 has moved to on-disk file format 3.

    The change is forward compatible in that JE files created with release 1.7.1 and earlier can be read when opened with JE 2.0.  The change is not backwards compatible in that files created with JE 2.0 cannot be read by earlier releases. Note that if a 1.7.1 environment is opened read/write, a new log file is written by JE 2.0 and the environment can no longer be read by earlier releases.

New Features:

  1. Sequences are now supported in JE. The Sequence API for the JE product is virtually identical to the Sequence API for the Berkeley DB C Edition product. To get started, see the com.sleepycat.je.Sequence class. [#12390](2.0.42)

  2. JE can be used as a J2EE/JCA (Java Connector Architecture) Resource Adapter. For information on how to use the JE J2EE/JCA Resource Adapter with JBoss 3.26 or Sun Java System Application Server 8.1 see JE_HOME/examples/jca/HOWTO-jboss.txt and JE_HOME/examples/jca/HOWTO-sjsas.txt. (2.0.42)

  3. JE supports XA Two Phase Commit through the com.sleepycat.je.XAEnvironment class, which implements the javax.transaction.xa.XAResource interface. (2.0.42)

  4. JE supplies a ready to install JMX (Java Management Extensions) MBean as well as support for adding JE monitoring to an application's custom MBean. See JE_HOME/examples/jmx/README.txt (2.0.42)

  5. Support for read committed (sometimes called degree 2) isolation is now available. Read committed isolation ensures the stability of the current data item read by the cursor, but permits data read by this cursor to be modified or deleted prior to the commit of the transaction. The following new methods and fields are used to configure read committed isolation: [#11766](2.0.42)

    • TransactionConfig.setReadCommitted and getReadCommitted
    • CursorConfig.setReadCommitted and getReadCommitted
    • CursorConfig.READ_COMMITTED and LockMode.READ_COMMITTED
    • StoredCollections.configuredMap (configuredSet, etc)

General Environment Changes:

  1. Log cleaner performance has been improved significantly. In many cases the cleaner will keep disk space utilization at 50%, and overall throughput is also improved in many cases. See the release notes for more detail. [#11597](2.0.42)

  2. The on-disk format for internal btree nodes now compresses LSN entries in order to reduce disk usage. [#12557](2.0.42)

  3. JE cache management overhead has been reduced and cache eviction is more responsive. See the release notes for more detail. [#11600] (2.0.42)

    • JE memory usage calculations could occasionally become corrupted during heavy concurrent activity, which would improperly subdue eviction, resulting in OutOfMemoryException. This has been fixed. [#12273](2.0.42)

    • Memory utilization is now updated more frequently and includes some items previously unaccounted for. [#11844](2.0.42)

    • In JE 1.7.1 and earlier, the log buffers used for write operations could grow and the memory consumed was not properly accounted for, particularly if records with large data and/or duplicate record sets were used. In 2.0, log buffer growth is restricted and the default number of log buffers was reduced to 3. A new property, je.nodeDupTreeMaxEntries was introduced to allow better specification of the characteristics of duplicate sets with large data items. Applications which use duplicates should be aware that the data portion of the data record serves as the key in the internal tree storage of duplicate sets, and it may be desirable to reduce the fanout of the duplicate btree node with the above parameter. A rule of thumb is that (je.nodeDupMaxTreeEntries * data size in bytes) gives the size of an internal duplicate node. If this is very large, this may consume an undesirable amount of memory when writing out that node.[#12605](2.0.42)

  4. Binding performance has been improved by using System.arraycopy in the FastOutputStream and FastInputStream utility classes. [#12002](2.0.42)

  5. Lock timeout messages now include the database name for the contested data record. In addition, there are new instructions in com.sleepycat.je.txn.LockInfo.java on how to modify the source code to compile in debug information which will show the origin of the offending locks. [#11685,#12005](2.0.42)

  6. Error path handling is improved so that all internal latches are released in the event of an IOException. [#12604](2.0.42)

  7. In JE 1.7.1 and earlier, IOExceptions generally resulted in a com.sleepycat.je.RunRecoveryException which invalidate the environment and required a restart. In 2.0, IOException handling is more robust. Transactions that did not make it to disk are rolled back, and where possible, the system will continue to serve read only requests and will attempt read/write requests in the face of continuous IOExceptions. [#11271](2.0.42)

  8. JE now sanity checks that a foreign key database does not not allow duplicate keys. This has been noted in the documentation and a check added to Environment.openSecondaryDatabase. [#12259](2.0.42)

  9. JE could throw a java.util.NoSuchElementException when opening an existing environment with a very small cache, such as 10K and under. [#12090](2.0.42)

  10. "LogException: Couldn't delete ..." could sometimes occur in the checkpointer thread, on Windows platforms only. This was a non-fatal error since the file would be deleted later. Now an informative message is logged, but an exception is not thrown.[#12161](2.0.42)

  11. When opening an environment, JE checks for existing files. This check is now made based on the canonical rather than relative path names for the environment.[#11659](2.0.42)

  12. The objectToEntry method is now implemented in all TupleBinding subclasses (IntegerBinding, etc) so that tuple bindings are fully nestable.

    An example of this usage is a custom binding that dynamically discovers the data types of each of the properties of a Java bean class. For each property, it calls TupleBinding.getPrimitiveBinding using the property's type (class). When the custom binding's objectToEntry method is called, it in turn calls the objectToEntry method of the nested bindings for each property. [#12124](2.0.42)

  13. JE environments could grow in log size even though there had been no write operations because Environment.close() would cause a checkpoint to be written, even if nothing was modified. Checkpoints now only occur when something has been written to the log. [#11861](2.0.42)

  14. A sanity check was added to require that the byte array held within the data parameter for Database.getSearchBoth() is a non-null data value. Previously this caused a NullPointerException. [#12121](2.0.42)

  15. If JE threw an exception during Environment.openDatabase() and exclusive creation was specified, the database lock was not released. [#12608](2.0.42)

  16. A BufferUnderflowException could occur at Environment.open() if the last file in the log was 0 length.[#12631](2.0.42)

  17. JE should transparently handle checksum errors at the very end of the log when calling Environment.open(). In some cases, JE did not successfully skip the bad area and returned an DbChecksumException, often with the error message "null buffer given to checksum validation, probably result of 0's in log file". These cases have been eliminated.[#12650](2.0.42)

  18. The getCause method for IOExceptionWrapper and RuntimeExceptionWrapper is now defined so that nested exceptions appear in stack traces for exceptions thrown by the collections API. [#11992](2.0.42)

  19. In rare circumstances, an application could receive a DatabaseException with the exception message "*** 12562 *** <latch name> not owned after acquire ...". This was due to the fact that JE's internal latching implementation did not take into account the possibility that a thread waiting on a monitor can receive a spurious wakeup, as described in JDK 1.5 Object.wait(). JE now detects and handles that situation. [#12562](2.0.54)

  20. Changed the Collections API to be XA-aware so that it does not attempt to auto-commit when an XA transaction is active. Prior to this fix, the collections API could not be used with XA, which is now available through the JE JCA/JTA implementation. [#12800](2.0.54)

  21. In rare cases, when the application is actively deleting records, a call to Cursor.getSearchKeyRange() could incorrectly return OperationStatus.NOTFOUND. [#12736](2.0.54)

  22. An application which is actively inserting duplicate records could receive a com.sleepycat.je.latch.LatchException with the exception message "<latchName> already held". [#12841](2.0.54)

  23. Opening an existing environment which had deleted records could result in a DatabaseException with this stack trace [#12840](2.0.54):
    com.sleepycat.je.recovery.RecoveryManager.traceAndThrowException(RecoveryManager.java:2125)
    com.sleepycat.je.recovery.RecoveryManager.redoLNs(RecoveryManager.java:1002)
    com.sleepycat.je.recovery.RecoveryManager.buildTree(RecoveryManager.java:539)
    com.sleepycat.je.recovery.RecoveryManager.recover(RecoveryManager.java:155)
    

  24. Opening an existing environment which had processed duplicate records could result in a com.sleepycat.je.DatabaseException with the exception message: "attempt to fetch a deleted entry". [#12847](2.0.54)

  25. In rare cases where multiple aborted transactions contain delete and insert operations for the same key, a com.sleepycat.je.log.LogFileNotFoundException or NOTFOUND status could result. [#12885](2.0.54)

  26. IMPORTANT: Fixed a problem that applies to applications that use LockMode.RMW or the collections API in certain circumstances. The bug could create incorrect internal log cleaning information. In some cases this bug could cause data loss and the application would see a LogFileNotFoundException when trying to access the lost record.

    By default, JE 2.0.83 will ignore cleaner information that is potentially invalid because of this bug. This will reduce cleaner performance to some degree, for an initial time period after upgrading to the new release. It is possible to avoid the performance penalty by setting je.cleaner.rmwFix to false if you are SURE that the RMW bug does not apply to your application. To determine this, use the following rules. The rules should be applied to all use of your application using JE release 2.0.42 and 2.0.54.

    1. If your application has never used transactions the bug does NOT apply.

    2. If your application has never used LockMode.RMW or the collections API the bug does NOT apply.

    3. If it is possible that your application read a record with LockMode.RMW but never wrote it, and then committed the transaction, then the bug DOES apply. One example is fetching records with Database.get(LockMode.RMW) for read purposes only. Another example is using a cursor with LockMode.RMW to loop over a key range and update records. When the end of the key range is encountered, the loop exits, but the loop exit condition is usually a test for a key that is outside of the range. The last key (the one outside of the range) was read with RMW but it is not written. It is best to be conservative and leave je.cleaner.rmwFix at the default setting if there is any doubt.

    4. Rule (3) also applies to the collections API. If you called StoredIterator.setReadModifyWrite(true), and then read a record with that iterator but never wrote it within the same transaction, the bug DOES apply.

    5. If your application used the collections API to create a subMap or subSet, and then called Map.clear or Collection.removeAll on the subMap or subSet, then the bug DOES apply.

    6. Otherwise, the bug does NOT apply and it is safe to set je.cleaner.rmwFix to false.

    Applications that might have been affected by this bug should run the DbVerify utility. The suggested steps are:

    • Switch to JE 2.0.83 to avoid further data loss.

    • Run DbVerify against the environment. If desired, copy the log files to another machine or directory and run DbVerify there to reduce impact on the running application.

    • If DbVerify reports LogFileNotFoundException, use DbDump -r and DbLoad to recreate the affected database and restore the valid data.

    [#13158](2.0.83)

  27. By default, JE no longer uses Java NIO. This change was made to avoid NIO stability problems and out-of-memory errors. NIO can be enabled by setting je.log.useNIO to true. When NIO is disabled (the default setting), the je.log.chunkedNIO and je.log.directNIO settings should not be used. [#12830](2.0.83)

  28. By default, JE no longer uses Java NIO. This change was made to avoid NIO stability problems and out-of-memory errors. NIO can be enabled by setting je.log.useNIO to true. When NIO is disabled (the default setting), the je.log.chunkedNIO and je.log.directNIO settings should not be used. [#12830](2.0.83)

  29. Users could occasionally see the following exception:
         java.lang.NullPointerException
         at com.sleepycat.je.cleaner.UtilizationProfile.getObsoleteDetail(UtilizationProfile.java:579)
         at com.sleepycat.je.cleaner.Cleaner.processFile(Cleaner.java:508)
         at com.sleepycat.je.cleaner.Cleaner.doClean(Cleaner.java:345)
         at com.sleepycat.je.cleaner.Cleaner.onWakeup(Cleaner.java:248)
         at com.sleepycat.je.utilint.DaemonThread.run(DaemonThread.java:183)
         at java.lang.Thread.run(Unknown Source)
    
    The error was benign, and the log cleaner would retry and recover. [#12931](2.0.83)

  30. In rare cases an internal latch would not be released properly during the insertion of duplicate records. The application would see access to that set of duplicate records hang. No exception would be seen. [#12960](2.0.83)

  31. Users could occasionally see the following exception:
         java.lang.ClassCastException: com.sleepycat.je.tree.DIN
         at com.sleepycat.je.cleaner.Cleaner.handleNoMigrationLogging(Cleaner.java:858)
         at com.sleepycat.je.tree.BIN.logInternal (BIN.java:914)
               ...
    
    The error was not persistent, and closing and re-opening the environment would be successful. [#12978](2.0.83)

  32. Added a missing parameter, 'databaseName' to the database stats operation in the JMX Mbean helper. Also, database stats were previously returned in xml format, which could interfere with display in a JMX console; they are now returned as plain text. Improved README for JMX use. [#12999](2.0.83)

  33. In rare circumstances, during environment instantiation (recovery), an application could see the following exception:
        com.sleepycat.je.DatabaseException: attempt to fetch a deleted entry:...
        at com.sleepycat.je.tree.IN.fetchTarget(IN.java:898)
        at com.sleepycat.je.tree.DBIN.matchLNByNodeId(DBIN.java:217)
        at com.sleepycat.je.tree.DIN.matchLNByNodeId(DIN.java:273)
        at com.sleepycat.je.tree.Tree.searchDupTreeByNodeId (Tree.java:960)
        at com.sleepycat.je.tree.Tree.getParentBINForChildLN (Tree.java:916)
        at com.sleepycat.je.recovery.RecoveryManager.redo (RecoveryManager.java:1575)
        at com.sleepycat.je.recovery.RecoveryManager.redoLNs (RecoveryManager.java:969)
    
    [#13034](2.0.83)

  34. During environment instantiation (recovery) of a database created before JE 2.0, an application could see the following exception:
        Caused by: java.nio.BufferUnderflowException
        at java.nio.Buffer.nextGetIndex(Buffer.java:398)
        at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:117)
        at com.sleepycat.je.log.LogUtils.readIntMSB(LogUtils.java:139)
        at com.sleepycat.je.tree.FileSummaryLN.getFileNumber(FileSummaryLN.java:149)
        at com.sleepycat.je.log.INFileReader.processEntry(INFileReader.java:347)
        at com.sleepycat.je.log.FileReader.readLogEntry(FileReader.java:478)
        at com.sleepycat.je.log.FileReader.readNextEntry(FileReader.java:252)
        at com.sleepycat.je.recovery.RecoveryManager.readINsAndTrackIds(RecoveryManager.java:573)
    
    [#13061](2.0.83)

  35. Fixed a bug resulting in corruption of an internal node when an OutOfMemoryError occurs in the middle of a record insertion. Later this could result in the following stack trace:
        IN=... state=0 com.sleepycat.je.DatabaseException: 
        java.nio.BufferUnderflowException
        at com.sleepycat.je.tree.IN.fetchTargetInternal(IN.java:943)
        at com.sleepycat.je.tree.IN.fetchTarget(IN.java:901)
    
    [#13126](2.0.83)

  36. Improve JE's ability to detect and compress sparse internal nodes caused by deleted records. Sparseness in the internal nodes can impact cursor traversal performance. [#13166](2.0.83)

  37. It was possible for an application to see this exception:
    java.lang.NullPointerException
        at com.sleepycat.je.dbi.CursorImpl.checkEnv(CursorImpl.java:2263)
        at com.sleepycat.je.Cursor.checkEnv(Cursor.java:1744)
        at com.sleepycat.je.Cursor.checkState(Cursor.java:1734)
        at com.sleepycat.je.Cursor.close(Cursor.java:233)
        at com.sleepycat.je.Database.get(Database.java:425)
    
    The error was not persistent and would disappear if the environment was closed and reopened. [#13191](2.0.83)

  38. Fix a bug which could result in the wrong record being returned from a "get" operation, in a special case where multiple threads are reading and inserting records in close key proximity. The bug could also manifest with the following stacktraces
    com.sleepycat.je.DatabaseException: fetchTarget of 0x300/0x0 IN=12630615 state=0 
    java.lang.ClassCastException: com.sleepycat.je.log.FileHeader
           at com.sleepycat.je.tree.IN.fetchTarget(IN.java:936)
           at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
           at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
           at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
           at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
           at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
           at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
           at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
           at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
           at com.sleepycat.je.Cursor.search(Cursor.java:929)
           at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
    
    or
    
    java.lang.ArrayIndexOutOfBoundsException: 128
        at com.sleepycat.je.tree.IN.fetchTarget(IN.java:897)
        at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
        at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
        at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
        at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
        at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
        at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
        at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
        at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
        at com.sleepycat.je.Cursor.search(Cursor.java:929)
        at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
        
    or
    
    com.sleepycat.je.DatabaseException: fetchTarget of null lsn IN=749358 state=0 NULL_LSN without KnownDeleted
    Stacktrace: com.sleepycat.je.DatabaseException: fetchTarget of null lsn IN=749358 state=0 NULL_LSN without KnownDeleted at com.sleepycat.je.tree.IN.fetchTarget(IN.java:902)
            at com.sleepycat.je.dbi.CursorImpl.lockLN(CursorImpl.java:2195)
            at com.sleepycat.je.dbi.CursorImpl.fetchCurrent(CursorImpl.java:2119)
            at com.sleepycat.je.dbi.CursorImpl.getCurrentAlreadyLatched(CursorImpl.java:1204)
            at com.sleepycat.je.dbi.CursorImpl.getNextWithKeyChangeStatus(CursorImpl.java:1350)
            at com.sleepycat.je.dbi.CursorImpl.getNext(CursorImpl.java:1279)
            at com.sleepycat.je.dbi.CursorImpl.getNextNoDup(CursorImpl.java:1467)
            at com.sleepycat.je.Cursor.searchInternal(Cursor.java:1216)
            at com.sleepycat.je.Cursor.searchAllowPhantoms(Cursor.java:1046)
            at com.sleepycat.je.Cursor.search(Cursor.java:929)
            at com.sleepycat.je.Cursor.getSearchKeyRange(Cursor.java:535)
    
    [#13363](2.0.90)

  39. Fix a recovery bug that could prevent opening the environment for applications using duplicates. The user would see a com.sleepycat.je.tree.InconsistentNodeException. The database remains valid and consistent. [#13435](2.0.90)

API Changes:

  1. TupleBinding.getPrimitiveBinding can now be passed a primitive type class as well as a primitive wrapper class. The return value for Integer.TYPE and Integer.class, for example, will be the same binding. [#12035](2.0.42)

  2. Improvements have been made to prevent the buffer used in serial and tuple bindings from growing inefficiently, and to provide more alternatives for the application to specify the desired size. For details see com.sleepycat.bind.serial.SerialBase and com.sleepycat.bind.tuple.TupleBase. [#12398](2.0.42)

  3. To conform to ANSI database isolation terminology, "dirty read" has been changed to "read uncommitted" and "degree 2" to "read committed" in the Java API. The dirty read and degree 2 identifiers are deprecated as follows:
    • Added LockMode.READ_COMMITTED, deprecated DEGREE_2
    • Added LockMode.READ_UNCOMMITTED, deprecated DIRTY_READ
    • Added CursorConfig.READ_COMMITTED, deprecated DEGREE_2
    • Added CursorConfig.READ_UNCOMMITTED, deprecated DIRTY_READ
    • Added CursorConfig.get/setReadCommitted, deprecated get/setDegree2
    • Added CursorConfig.get/setReadUncommitted, deprecated get/setDirtyRead
    • Added TransactionConfig.get/setReadCommitted, deprecated get/setDegree2
    • Added TransactionConfig.get/setReadUncommitted,deprecated get/setDirtyRead
    • Added StoredContainer.getCursorConfig, deprecated isDirtyRead
    • Deprecated StoredCollections.dirtyReadMap (dirtyReadSet, etc) which is replaced by configuredMap (configuredSet, etc)
    • Deprecated StoredContainer.isDirtyReadAllowed with no replacement (please use DatabaseConfig.getDirtyRead)
    Also note that StoredCollections.configuredMap (configuredSet, etc) can be used to configure read committed and write lock containers, as well as read uncommitted containers, since all CursorConfig properties are supported. [#11776](2.0.42)

  4. A new ImmutableSecondaryKey property has been added to SecondaryConfig. Specifying that a secondary key is immutable can be used to optimize updates when the secondary key in a primary record will never be changed after that primary record is inserted. See SecondaryConfig.setImmutableSecondaryKey for more information. [#11211](2.0.42)

  5. Added the protected method SerialBinding.getClassLoader so that subclasses may return a specific or dynamically determined class loader. Useful for applications which use multiple class loaders, including applications that serialize Groovy-defined classes. [#12764] [#12749](2.0.54)

  6. Made several statistics classes Serializable so that they can be returned when JE is invoked over over RMI. One such use case is when JMX is used over RMI. [#12766](2.0.54)

  7. The performance of closing and re-opening environments has been improved. In the past, Environment.close() and the subsequent environment reinstantiation could take a long time because proactive log cleaning was executing during environment close. In addition, a more compact form of checkpoint was used in environment close which made the subsequent recovery incur more random I/O. Environment.close() now forgoes any log cleaning activity, and chooses to use a less compact checkpoint in order to ensure that the next environment instantiation is speedy.

    The choice between compact vs. non-compact checkpoints is now available to the application-issued checkpoints through CheckpointConfig.setMinimizeRecoveryTime(). [#12950](2.0.83)


  8. Added JEConnection.openSecondaryDatabase() to support the use of secondary indices through the JCA adaptor. As with primary databases, the JCA adaptor checks for configuration equivalence when the application requests a cached database handle. SecondaryKeyComparator.equals() is used as part of secondary database configuration checking. [#13194](2.0.83)

  9. Database.preload(long maxBytes) has been deprecated in favor of Database.preload(long maxBytes, long maxMillisecs). (2.0.83)

  10. A new, undocumented parameter was added that can improve performance for some applications with both of the following characteristics:

    1. Access by key is mostly random. There are few or no "hot" sets of records that are accessed more than others, and most record access is not in sequential key order.
    2. The memory size of the active record set is significantly larger than the configured JE cache size, causing lots of I/O as records are fetched from disk.

    If you have such an application you may want to try adding the following two configuration parameters to your je.properties file:

    je.evictor.lruOnly=false
    je.evictor.nodesPerScan=100
    

    je.evictor.lruOnly is a new setting added in 2.0.83. It changes the eviction algorithm, which is the way in which JE decides to remove records from the cache.

    The default eviction algorithm is LRU (least recently used) and the default setting for the lruOnly parameter is true. With the default algorithm, only the LRU of a Btree node is taken into account when choosing the next Btree node to be evicted.

    When lruOnly is set to false, the eviction algorithm is instead primarily based on the level of the node in the Btree. The lowest level nodes (the leaf nodes) are always evicted first, even if higher level nodes are less recently used. In addition, dirty nodes are evicted after non-dirty nodes.

    Setting lruOnly to false benefits random access applications because it keeps higher level Btree nodes in the tree for as long as possible. For a random key, this increases the likelihood that the relevant Btree internal nodes will be in the cache.

    We recommend that you also change je.evictor.nodesPerScan when you set lruOnly to false. This setting controls the number of Btree nodes that are considered, or sampled, each time a node is evicted. A setting of 100 often produces good results, but this may vary from application to application. The larger the nodesPerScan, the more accurate the algorithm. However, setting it too high is detrimental; the need to consider larger numbers of nodes for each eviction may delay the completion of a given database operation, which will impacts the response time of the application thread. (2.0.83)

Utility Changes:

  1. The DbVerify utility has been improved. DbVerify previously stopped at the first exception found; it now attempts to proceed past any exceptions encountered and will dump any problematic data records in binary and string format. [#12932](2.0.83)

  2. The DbDump and DbLoad utilities have been improved.

    DbDump is now significantly faster and the [-rR] mode requires far less memory. The [-rR] mode previously did not handle gaps in the log file sequence caused by log cleaning correctly; this has been fixed. A -v flag has been added to report progress status.

    DbLoad now supports a -V flag to report progress status. [#12927](2.0.83)

Configuration, Documentation, and Build Changes:

  1. To better support eviction that is now performed in-line in all threads of activity, the je.evictor.evictBytes configuration setting has been added to allow setting the number of bytes that should be evicted whenever eviction is invoked. Its default value is 512KB. The je.evictor.useMemoryFloor configuration setting is deprecated and no longer used. [#12620](2.0.42)

  2. je.nodeDupTreeMaxEntries was introduced to allow better specification of duplicate set btree sizing. See [#12605] above. (2.0.42)

  3. examples.je.SequenceExample.java has been added to the examples directory. [#12991](2.0.83)

  4. Added notes to the collections package Javadoc to make it clear that collections derived from StoredCollections are also themselves StoredCollections. [#13009](2.0.83)