You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2018/01/23 07:20:58 UTC

[directory-server] 03/05: Adding transaction to partitions

This is an automated email from the ASF dual-hosted git repository.

elecharny pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/directory-server.git

commit be82b0ce2b78fa903a1818d27a351d07f2a977ce
Author: Emmanuel Lécharny <el...@symas.com>
AuthorDate: Wed Jan 10 07:05:52 2018 +0100

    Adding transaction to partitions
---
 .../server/core/api/LdapCoreSessionConnection.java |   2 +-
 .../context/AbstractOperationContext.java          |  22 +
 .../server/core/api/partition/PartitionNexus.java  |  11 +
 .../core/api/partition/PartitionReadTxn.java       |   6 +
 .../server/core/api/partition/PartitionTxn.java    |  30 +
 .../core/api/partition/PartitionWriteTxn.java      |   6 +
 .../directory/server/core/jndi/ServerContext.java  |   1 +
 .../server/core/DefaultDirectoryService.java       |   2 +
 .../apache/directory/server/installers/config.ldif | 828 +++++++++++++++++++++
 .../core/partition/impl/btree/jdbm/JdbmIndex.java  |   4 +-
 .../core/partition/impl/btree/jdbm/JdbmTable.java  | 358 ++++-----
 .../impl/btree/jdbm/KeyTupleBTreeCursor.java       |   2 +-
 .../btree/jdbm/JdbmTableWithDuplicatesTest.java    |   9 -
 .../partition/impl/btree/mavibot/MavibotTable.java | 159 ++--
 mavibotv2-partition/pom.xml                        | 146 ++++
 .../impl/btree/mavibot/AbstractMavibotTxn.java     |  96 +++
 .../partition/impl/btree/mavibot/DnSerializer.java | 206 +++++
 .../impl/btree/mavibot/KeyTupleValueCursor.java    | 239 ++----
 .../impl/btree/mavibot/LdifTupleComparator.java    |  57 ++
 .../impl/btree/mavibot/LdifTupleReaderWriter.java  | 162 ++++
 .../impl/btree/mavibot/MavibotCursor.java          | 292 ++++----
 .../impl/btree/mavibot/MavibotDnIndex.java         | 123 +++
 .../impl/btree/mavibot/MavibotEntrySerializer.java | 382 ++++++++++
 .../partition/impl/btree/mavibot/MavibotIndex.java | 261 +++----
 .../impl/btree/mavibot/MavibotMasterTable.java     |  58 ++
 .../mavibot/MavibotParentIdAndRdnSerializer.java   | 302 ++++++++
 .../impl/btree/mavibot/MavibotPartition.java       | 540 ++++++++++++++
 .../impl/btree/mavibot/MavibotRdnIndex.java        | 126 ++++
 .../impl/btree/mavibot/MavibotReadTxn.java         |  11 +
 .../partition/impl/btree/mavibot/MavibotTable.java | 255 ++++---
 .../partition/impl/btree/mavibot/MavibotTxn.java   |   9 +
 .../impl/btree/mavibot/MavibotWriteTxn.java        |  18 +
 .../impl/btree/mavibot/ValueTreeCursor.java        | 155 ++++
 pom.xml                                            |   1 +
 .../ldap/handlers/extended/PwdModifyHandler.java   |   1 +
 .../ldap/handlers/request/BindRequestHandler.java  |   1 +
 .../ldap/handlers/sasl/SimpleMechanismHandler.java |   1 +
 .../ldap/handlers/sasl/ntlm/NtlmSaslServer.java    |   1 +
 .../ldap/handlers/sasl/plain/PlainSaslServer.java  |   1 +
 .../server/operations/modify/ModifyReferralIT.java |  14 +-
 .../server/operations/search/PagedSearchApiIT.java |   7 +-
 .../operations/search/PersistentSearchApiIT.java   | 740 ++++++++++++++++++
 .../directory/server/xdbm/AbstractTable.java       |  36 +-
 .../org/apache/directory/server/xdbm/Table.java    |  95 ++-
 .../directory/server/xdbm/impl/avl/AvlTable.java   |  62 +-
 45 files changed, 4877 insertions(+), 961 deletions(-)

diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java b/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
index b2b6d12..74cf1db 100644
--- a/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/LdapCoreSessionConnection.java
@@ -1206,7 +1206,7 @@ public class LdapCoreSessionConnection extends AbstractLdapConnection
 
         int newId = messageId.incrementAndGet();
 
-        BindOperationContext bindContext = new BindOperationContext( null );
+        BindOperationContext bindContext = new BindOperationContext( directoryService, null );
         bindContext.setCredentials( bindRequest.getCredentials() );
 
         bindContext.setDn( bindRequest.getDn().apply( directoryService.getSchemaManager() ) );
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java b/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
index 8fffa95..4f04179 100644
--- a/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/interceptor/context/AbstractOperationContext.java
@@ -31,6 +31,7 @@ import org.apache.directory.api.ldap.model.message.Control;
 import org.apache.directory.api.ldap.model.name.Dn;
 import org.apache.directory.server.core.api.CoreSession;
 import org.apache.directory.server.core.api.LdapPrincipal;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 
 
 /**
@@ -74,6 +75,9 @@ public abstract class AbstractOperationContext implements OperationContext
 
     /** A flag used to tell if we should consider referrals as standard entries */
     protected boolean throwReferral;
+    
+    /** The transaction this operation is ran into */
+    protected PartitionTxn transaction;
 
 
     /**
@@ -443,4 +447,22 @@ public abstract class AbstractOperationContext implements OperationContext
     {
         return !throwReferral;
     }
+
+
+    /**
+     * @return the transaction
+     */
+    public PartitionTxn getTransaction()
+    {
+        return transaction;
+    }
+
+
+    /**
+     * @param transaction the transaction to set
+     */
+    public void setTransaction( PartitionTxn transaction )
+    {
+        this.transaction = transaction;
+    }
 }
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionNexus.java b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionNexus.java
index f648618..0534282 100644
--- a/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionNexus.java
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionNexus.java
@@ -50,6 +50,17 @@ public interface PartitionNexus extends Partition
 
     byte[] ADMIN_PASSWORD_BYTES = Strings.getBytesUtf8( ADMIN_PASSWORD_STRING );
 
+    
+    /**
+     * Start a read transaction
+     */
+    PartitionReadTxn beginReadTransaction();
+
+    
+    /**
+     * Start a write transaction
+     */
+    PartitionWriteTxn beginWriteTransaction();
 
     /**
      * Get's the RootDSE entry for the DSA.
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionReadTxn.java b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionReadTxn.java
new file mode 100644
index 0000000..d74c53f
--- /dev/null
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionReadTxn.java
@@ -0,0 +1,6 @@
+package org.apache.directory.server.core.api.partition;
+
+public interface PartitionReadTxn extends PartitionTxn
+{
+
+}
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionTxn.java b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionTxn.java
new file mode 100644
index 0000000..88841f9
--- /dev/null
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionTxn.java
@@ -0,0 +1,30 @@
+package org.apache.directory.server.core.api.partition;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public interface PartitionTxn extends Closeable
+{
+    /**
+     * Commit a write transaction. It will apply the changes on 
+     * the database.Last, not least, a new version will be created.
+     * If called by a Read transaction, it will simply close it.
+     */
+    void commit() throws IOException;
+    
+    
+    /**
+     * Abort a transaction. If it's a {@link PartitionReadTxn}, it will unlink this transaction
+     * from the version it used. If it's a {@link PartitionWriteTxn}; it will drop all the pending
+     * changes. The latest version will remain the same.
+     */
+    void abort() throws IOException;
+
+    
+    /**
+     * Tells if the transaction has been committed/aborted or not.
+     *  
+     * @return <tt>true</tt> if the transaction has been completed.
+     */
+    boolean isClosed();
+}
diff --git a/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionWriteTxn.java b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionWriteTxn.java
new file mode 100644
index 0000000..effcd3d
--- /dev/null
+++ b/core-api/src/main/java/org/apache/directory/server/core/api/partition/PartitionWriteTxn.java
@@ -0,0 +1,6 @@
+package org.apache.directory.server.core.api.partition;
+
+public interface PartitionWriteTxn extends PartitionTxn
+{
+
+}
diff --git a/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java b/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java
index 5610114..6285de9 100644
--- a/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java
+++ b/core-jndi/src/main/java/org/apache/directory/server/core/jndi/ServerContext.java
@@ -679,6 +679,7 @@ public abstract class ServerContext implements EventContext
     {
         // setup the op context and populate with request controls
         BindOperationContext bindContext = new BindOperationContext( null );
+        bindContext.setTransaction( getDirectoryService().getPartitionNexus().beginReadTransaction() );
         bindContext.setDn( bindDn );
         bindContext.setCredentials( credentials );
         bindContext.setSaslMechanism( saslMechanism );
diff --git a/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java b/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java
index dc4a7b8..5237313 100644
--- a/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java
+++ b/core/src/main/java/org/apache/directory/server/core/DefaultDirectoryService.java
@@ -994,6 +994,7 @@ public class DefaultDirectoryService implements DirectoryService
         }
 
         BindOperationContext bindContext = new BindOperationContext( null );
+        bindContext.setTransaction( partitionNexus.beginReadTransaction() );
         bindContext.setCredentials( credentials );
         bindContext.setDn( principalDn.apply( schemaManager ) );
         bindContext.setInterceptors( getInterceptors( OperationEnum.BIND ) );
@@ -1020,6 +1021,7 @@ public class DefaultDirectoryService implements DirectoryService
         }
 
         BindOperationContext bindContext = new BindOperationContext( null );
+        bindContext.setTransaction( partitionNexus.beginReadTransaction() );
         bindContext.setCredentials( credentials );
         bindContext.setDn( principalDn.apply( schemaManager ) );
         bindContext.setSaslMechanism( saslMechanism );
diff --git a/installers-maven-plugin/src/main/resources/org/apache/directory/server/installers/config.ldif b/installers-maven-plugin/src/main/resources/org/apache/directory/server/installers/config.ldif
new file mode 100644
index 0000000..8861253
--- /dev/null
+++ b/installers-maven-plugin/src/main/resources/org/apache/directory/server/installers/config.ldif
@@ -0,0 +1,828 @@
+version: 1
+dn: ou=config
+ou: config
+objectclass: top
+objectclass: organizationalUnit
+
+dn: ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-directoryService
+ads-directoryserviceid: default
+ads-dsreplicaid: 1
+ads-dssyncperiodmillis: 15000
+ads-dsPasswordHidden: FALSE
+ads-dsallowanonymousaccess: TRUE
+ads-dsaccesscontrolenabled: FALSE
+ads-dsdenormalizeopattrsenabled: FALSE
+ads-enabled: TRUE
+
+dn: ads-changeLogId=defaultChangeLog,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-changeLog
+ads-changeLogId: defaultChangeLog
+ads-changeLogExposed: FALSE
+ads-enabled: FALSE
+
+dn: ads-journalId=defaultJournal,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-journal
+ads-journalId: defaultJournal
+ads-journalFileName: Journal.txt
+ads-journalWorkingDir: /
+ads-journalRotation: 2
+ads-enabled: FALSE
+
+dn: ou=interceptors,ads-directoryServiceId=default,ou=config
+ou: interceptors
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-interceptorId=normalizationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 1
+ads-interceptorclassname: org.apache.directory.server.core.normalization.NormalizationInterceptor
+ads-interceptorid: normalizationInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+objectclass: ads-authenticationInterceptor
+ads-interceptororder: 2
+ads-interceptorclassname: org.apache.directory.server.core.authn.AuthenticationInterceptor
+ads-interceptorid: authenticationInterceptor
+ads-enabled: TRUE
+
+dn: ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+ou: authenticators
+objectclass: top
+objectclass: organizationalUnit
+
+dn: ads-authenticatorid=anonymousauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+ads-authenticatorid: anonymousauthenticator
+objectclass: top
+objectclass: ads-base
+objectClass: ads-authenticator
+objectClass: ads-authenticatorImpl
+ads-authenticatorClass: org.apache.directory.server.core.authn.AnonymousAuthenticator
+ads-baseDn: 
+ads-enabled: TRUE
+
+dn: ads-authenticatorid=simpleauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+ads-authenticatorid: simpleauthenticator
+objectclass: top
+objectclass: ads-base
+objectClass: ads-authenticator
+objectClass: ads-authenticatorImpl
+ads-authenticatorClass: org.apache.directory.server.core.authn.SimpleAuthenticator
+ads-baseDn: 
+ads-enabled: TRUE
+
+dn: ads-authenticatorid=strongauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+ads-authenticatorid: strongauthenticator
+objectclass: top
+objectclass: ads-base
+objectClass: ads-authenticator
+objectClass: ads-authenticatorImpl
+ads-authenticatorClass: org.apache.directory.server.core.authn.StrongAuthenticator
+ads-baseDn: 
+ads-enabled: TRUE
+
+dn: ads-authenticatorid=delegatingauthenticator,ou=authenticators,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+ads-authenticatorid: delegatingauthenticator
+objectclass: top
+objectclass: ads-base
+objectClass: ads-authenticator
+objectClass: ads-authenticatorImpl
+ads-authenticatorClass: org.apache.directory.server.core.authn.DelegatingAuthenticator
+ads-baseDn: 
+ads-enabled: FALSE
+
+dn: ou=passwordPolicies,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectClass: organizationalUnit
+objectClass: top
+ou: passwordPolicies
+
+dn: ads-pwdId=default,ou=passwordPolicies,ads-interceptorId=authenticationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectClass: top
+objectClass: ads-base
+objectClass: ads-passwordPolicy
+ads-pwdId: default
+ads-pwdSafeModify: FALSE
+ads-pwdMaxAge: 0
+ads-pwdFailureCountInterval: 30
+ads-pwdAttribute: userPassword
+ads-pwdMaxFailure: 5
+ads-pwdLockout: TRUE
+ads-pwdMustChange: FALSE
+ads-pwdLockoutDuration: 0
+ads-pwdMinLength: 5
+ads-pwdInHistory: 5
+ads-pwdExpireWarning: 600
+ads-pwdMinAge: 0
+ads-pwdAllowUserChange: TRUE
+ads-pwdGraceAuthNLimit: 5
+ads-pwdCheckQuality: 1
+ads-pwdMaxLength: 0 
+ads-pwdGraceExpire: 0
+ads-pwdMinDelay: 0
+ads-pwdMaxDelay: 0
+ads-pwdMaxIdle: 0
+ads-pwdValidator: org.apache.directory.server.core.api.authn.ppolicy.DefaultPasswordValidator
+ads-enabled: TRUE
+
+dn: ads-interceptorId=referralInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 3
+ads-interceptorclassname: org.apache.directory.server.core.referral.ReferralInterceptor
+ads-interceptorid: referralInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=aciAuthorizationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 4
+ads-interceptorclassname: org.apache.directory.server.core.authz.AciAuthorizationInterceptor
+ads-interceptorid: aciAuthorizationInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=defaultAuthorizationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 5
+ads-interceptorclassname: org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor
+ads-interceptorid: defaultAuthorizationInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=administrativePointInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 6
+ads-interceptorclassname: org.apache.directory.server.core.admin.AdministrativePointInterceptor
+ads-interceptorid: administrativePointInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=exceptionInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 7
+ads-interceptorclassname: org.apache.directory.server.core.exception.ExceptionInterceptor
+ads-interceptorid: exceptionInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=keyDerivationInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-enabled: FALSE
+ads-interceptororder: 8
+ads-interceptorclassname: org.apache.directory.server.core.kerberos.KeyDerivationInterceptor
+ads-interceptorid: keyDerivationInterceptor
+
+dn: ads-interceptorId=passwordHashingInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+objectclass: ads-hashInterceptor
+ads-enabled: TRUE
+ads-interceptororder: 9
+ads-interceptorclassname: org.apache.directory.server.core.hash.ConfigurableHashingInterceptor
+ads-interceptorid: passwordHashingInterceptor
+ads-hashAlgorithm: SSHA
+ads-hashAttribute: 2.5.4.35
+
+dn: ads-interceptorId=schemaInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 10
+ads-interceptorclassname: org.apache.directory.server.core.schema.SchemaInterceptor
+ads-interceptorid: schemaInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=operationalAttributeInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 11
+ads-interceptorclassname: org.apache.directory.server.core.operational.OperationalAttributeInterceptor
+ads-interceptorid: operationalAttributeInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=collectiveAttributeInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 12
+ads-interceptorclassname: org.apache.directory.server.core.collective.CollectiveAttributeInterceptor
+ads-interceptorid: collectiveAttributeInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=subentryInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 13
+ads-interceptorclassname: org.apache.directory.server.core.subtree.SubentryInterceptor
+ads-interceptorid: subentryInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=eventInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 14
+ads-interceptorclassname: org.apache.directory.server.core.event.EventInterceptor
+ads-interceptorid: eventInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=triggerInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 15
+ads-interceptorclassname: org.apache.directory.server.core.trigger.TriggerInterceptor
+ads-interceptorid: triggerInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=journalInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 16
+ads-interceptorclassname: org.apache.directory.server.core.journal.JournalInterceptor
+ads-interceptorid: journalInterceptor
+ads-enabled: TRUE
+
+dn: ads-interceptorId=numberInterceptor,ou=interceptors,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-interceptor
+ads-interceptororder: 17
+ads-interceptorclassname: org.apache.directory.server.core.number.NumberIncrementingInterceptor
+ads-interceptorId: numberInterceptor
+ads-enabled: FALSE
+
+dn: ou=partitions,ads-directoryServiceId=default,ou=config
+ou: partitions
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectClass: ads-base
+objectclass: ads-partition
+objectclass: ads-jdbmPartition
+ads-partitionSuffix: ou=system
+ads-jdbmpartitionoptimizerenabled: TRUE
+ads-partitioncachesize: 10000
+ads-partitionsynconwrite: TRUE
+ads-partitionid: system
+ads-enabled: TRUE
+
+dn: ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ou: indexes
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-indexAttributeId=apacheRdn,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheRdn
+ads-indexHasReverse: TRUE
+ads-indexcachesize: 1000
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apachePresence,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apachePresence
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheOneAlias,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheOneAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheSubAlias,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheSubAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheAlias,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=objectClass,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: objectClass
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=entryCSN,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: entryCSN
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=ou,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: ou
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=uid,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: uid
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=administrativeRole,ou=indexes,ads-partitionId=system,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: administrativeRole
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectClass: ads-base
+objectclass: ads-partition
+objectclass: ads-jdbmPartition
+ads-partitionSuffix: dc=example,dc=com
+ads-contextentry:: ZG46IGRjPWV4YW1wbGUsZGM9Y29tCmRjOiBleGFtcGxlCm9iamVjdGNsY
+ XNzOiBkb21haW4Kb2JqZWN0Y2xhc3M6IHRvcAoK
+ads-jdbmpartitionoptimizerenabled: TRUE
+ads-partitioncachesize: 10000
+ads-partitionsynconwrite: TRUE
+ads-partitionid: example
+ads-enabled: TRUE
+
+dn: ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ou: indexes
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-indexAttributeId=apacheRdn,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheRdn
+ads-indexHasReverse: TRUE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apachePresence,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apachePresence
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheOneAlias,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheOneAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheSubAlias,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheSubAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=apacheAlias,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: apacheAlias
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=dc,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: dc
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=krb5PrincipalName,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: krb5PrincipalName
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=objectClass,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: objectClass
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=entryCSN,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: entryCSN
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=ou,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: ou
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=uid,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: uid
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-indexAttributeId=administrativeRole,ou=indexes,ads-partitionId=example,ou=partitions,ads-directoryServiceId=default,ou=config
+ads-indexattributeid: administrativeRole
+ads-indexHasReverse: FALSE
+ads-indexcachesize: 100
+objectclass: ads-index
+objectclass: ads-jdbmIndex
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ou=servers,ads-directoryServiceId=default,ou=config
+ou: servers
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-serverId=changePasswordServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: ads-server
+objectclass: ads-changePasswordServer
+objectclass: ads-dsBasedServer
+objectclass: ads-base
+objectclass: top
+ads-serverid: changePasswordServer
+ads-enabled: FALSE
+
+dn: ou=transports,ads-serverId=changePasswordServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: transports
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-transportId=tcp,ou=transports,ads-serverId=changePasswordServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 60464
+ads-transportnbthreads: 2
+ads-transportaddress: 0.0.0.0
+ads-transportid: tcp
+objectclass: ads-transport
+objectclass: ads-tcpTransport
+objectClass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-transportId=udp,ou=transports,ads-serverId=changePasswordServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 60464
+ads-transportnbthreads: 2
+ads-transportaddress: 0.0.0.0
+ads-transportid: udp
+objectclass: ads-transport
+objectclass: ads-udpTransport
+objectClass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-serverid: httpServer
+ads-enabled: FALSE
+objectclass: ads-server
+objectclass: ads-httpServer
+objectclass: ads-base
+objectclass: top
+
+dn: ou=transports,ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: transports
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-transportid=http,ou=transports,ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-transport
+objectclass: ads-tcpTransport
+ads-transportid: http
+ads-systemport: 8080
+ads-transportaddress: 0.0.0.0
+ads-enabled: TRUE
+
+dn: ads-transportid=https,ou=transports,ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: top
+objectclass: ads-base
+objectclass: ads-transport
+objectclass: ads-tcpTransport
+ads-transportid: https
+ads-transportaddress: 0.0.0.0
+ads-systemport: 8443
+ads-enabled: TRUE
+
+dn: ou=httpWebApps,ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: organizationalUnit
+objectclass: top
+ou: httpWebApps
+
+dn: ads-id=testapp,ou=httpWebApps,ads-serverId=httpServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-httpwarfile: /path/to/foo/war
+ads-httpappctxpath: /foo
+ads-id: testapp
+objectclass: ads-httpWebApp
+objectclass: ads-base
+objectclass: top
+ads-enabled: FALSE
+
+dn: ads-serverId=kerberosServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: ads-server
+objectclass: ads-kdcServer
+objectclass: ads-dsBasedServer
+objectclass: ads-base
+objectclass: top
+ads-serverid: kerberosServer
+ads-enabled: FALSE
+ads-krbAllowableClockSkew: 300000
+ads-krbBodyChecksumVerified: TRUE
+ads-krbEmptyAddressesAllowed: TRUE
+ads-krbEncryptionTypes: aes128-cts-hmac-sha1-96
+ads-krbEncryptionTypes: des3-cbc-sha1-kd
+ads-krbEncryptionTypes: des-cbc-md5
+ads-krbForwardableAllowed: TRUE
+ads-krbmaximumrenewablelifetime: 604800000
+ads-krbMaximumTicketLifetime: 86400000
+ads-krbPaEncTimestampRequired: TRUE
+ads-krbPostdatedAllowed: TRUE
+ads-krbPrimaryRealm: EXAMPLE.COM
+ads-krbProxiableAllowed: TRUE
+ads-krbRenewableAllowed: TRUE
+ads-searchBaseDN: ou=users,dc=example,dc=com
+
+dn: ou=transports,ads-serverId=kerberosServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: transports
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-transportid=tcp,ou=transports,ads-serverId=kerberosServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 60088
+ads-transportnbthreads: 4
+ads-transportaddress: 0.0.0.0
+ads-transportid: tcp
+objectclass: ads-transport
+objectClass: ads-base
+objectclass: ads-tcpTransport
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-transportid=udp,ou=transports,ads-serverId=kerberosServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 60088
+ads-transportnbthreads: 4
+ads-transportaddress: 0.0.0.0
+ads-transportid: udp
+objectclass: ads-transport
+objectclass: ads-udpTransport
+objectClass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectclass: ads-server
+objectclass: ads-ldapServer
+objectclass: ads-dsBasedServer
+objectclass: ads-base
+objectclass: top
+ads-serverId: ldapServer
+ads-confidentialityRequired: FALSE
+ads-maxSizeLimit: 1000
+ads-maxTimeLimit: 15000
+ads-maxpdusize: 2000000
+ads-saslHost: ldap.example.com
+ads-saslPrincipal: ldap/ldap.example.com@EXAMPLE.COM
+ads-saslRealms: example.com
+ads-saslRealms: apache.org
+ads-searchBaseDN: ou=users,ou=system
+ads-replEnabled: true
+ads-replPingerSleep: 5
+ads-enabled: TRUE
+
+dn: ou=replConsumers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+objectClass: organizationalUnit
+objectClass: top
+ou: replConsumers
+
+dn: ou=transports,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: transports
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-transportid=ldap,ou=transports,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 10389
+ads-transportnbthreads: 8
+ads-transportaddress: 0.0.0.0
+ads-transportid: ldap
+objectclass: ads-transport
+objectclass: ads-tcpTransport
+objectClass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-transportid=ldaps,ou=transports,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-systemport: 10636
+ads-transportenablessl: TRUE
+ads-transportaddress: 0.0.0.0
+ads-transportid: ldaps
+objectclass: ads-transport
+objectclass: ads-tcpTransport
+objectClass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: extendedOpHandlers
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-extendedOpId=gracefulShutdownHandler,ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-extendedOpId: gracefulShutdownHandler
+ads-extendedOpHandlerclass: org.apache.directory.server.ldap.handlers.extended.GracefulShutdownHandler
+objectclass: ads-extendedOpHandler
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-extendedOpId=starttlshandler,ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-extendedOpId: starttlshandler
+ads-extendedOpHandlerclass: org.apache.directory.server.ldap.handlers.extended.StartTlsHandler
+objectclass: ads-extendedOpHandler
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-extendedOpId=storedprochandler,ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-enabled: FALSE
+ads-extendedOpId: storedprochandler
+ads-extendedOpHandlerclass: org.apache.directory.server.ldap.handlers.extended.StoredProcedureExtendedOperationHandler
+objectclass: ads-extendedOpHandler
+objectclass: ads-base
+objectclass: top
+
+dn: ads-extendedOpId=pwdModifyHandler,ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-extendedOpId: pwdModifyHandler
+ads-extendedOpHandlerclass: org.apache.directory.server.ldap.handlers.extended.PwdModifyHandler
+objectclass: ads-extendedOpHandler
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ads-extendedOpId=whoAmIHandler,ou=extendedOpHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-extendedOpId: whoAmIHandler
+ads-extendedOpHandlerclass: org.apache.directory.server.ldap.handlers.extended.WhoAmIHandler
+objectclass: ads-extendedOpHandler
+objectclass: ads-base
+objectclass: top
+ads-enabled: TRUE
+
+dn: ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ou: saslMechHandlers
+objectclass: organizationalUnit
+objectclass: top
+
+dn: ads-saslMechName=CRAM-MD5,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.cramMD5.CramMd5MechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: CRAM-MD5
+ads-enabled: TRUE
+
+dn: ads-saslMechName=DIGEST-MD5,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.digestMD5.DigestMd5MechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: DIGEST-MD5
+ads-enabled: TRUE
+
+dn: ads-saslMechName=GSS-SPNEGO,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.ntlm.NtlmMechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: GSS-SPNEGO
+ads-ntlmMechProvider: com.foo.Bar
+ads-enabled: TRUE
+
+dn: ads-saslMechName=GSSAPI,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.gssapi.GssapiMechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: GSSAPI
+ads-enabled: TRUE
+
+dn: ads-saslMechName=NTLM,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.ntlm.NtlmMechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: NTLM
+ads-ntlmMechProvider: com.foo.Bar
+ads-enabled: TRUE
+
+dn: ads-saslMechName=SIMPLE,ou=saslMechHandlers,ads-serverId=ldapServer,ou=servers,ads-directoryServiceId=default,ou=config
+ads-saslMechClassName: org.apache.directory.server.ldap.handlers.sasl.SimpleMechanismHandler
+objectclass: ads-saslMechHandler
+objectclass: ads-base
+objectclass: top
+ads-saslMechName: SIMPLE
+ads-enabled: TRUE
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
index 90f84e4..b023652 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
@@ -60,9 +60,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     /** A logger for this class */
     private static final Logger LOG = LoggerFactory.getLogger( JdbmIndex.class );
 
-    /**
-     * default duplicate limit before duplicate keys switch to using a btree for values
-     */
+    /** default duplicate limit before duplicate keys switch to using a btree for values */
     public static final int DEFAULT_DUPLICATE_LIMIT = 512;
 
     /**  the key used for the forward btree name */
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
index 85554e1..df94782 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTable.java
@@ -33,6 +33,7 @@ import jdbm.recman.BaseRecordManager;
 import jdbm.recman.CacheRecordManager;
 
 import org.apache.directory.api.ldap.model.cursor.Cursor;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
 import org.apache.directory.api.ldap.model.exception.LdapException;
@@ -41,6 +42,8 @@ import org.apache.directory.api.ldap.model.schema.SchemaManager;
 import org.apache.directory.api.ldap.model.schema.comparators.SerializableComparator;
 import org.apache.directory.api.util.Strings;
 import org.apache.directory.api.util.SynchronizedLRUMap;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
 import org.apache.directory.server.core.avltree.ArrayMarshaller;
 import org.apache.directory.server.core.avltree.ArrayTree;
 import org.apache.directory.server.core.avltree.ArrayTreeCursor;
@@ -77,9 +80,6 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
     /** a cache of duplicate BTrees */
     private final Map<Long, BTree<K, V>> duplicateBtrees;
 
-    /** A Key serializer */
-    private final Serializer keySerializer;
-
     /** A value serializer */
     private final Serializer valueSerializer;
 
@@ -136,7 +136,6 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
         this.numDupLimit = numDupLimit;
         this.recMan = manager;
 
-        this.keySerializer = keySerializer;
         this.valueSerializer = valueSerializer;
 
         this.allowsDuplicates = true;
@@ -200,7 +199,6 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
         this.numDupLimit = Integer.MAX_VALUE;
         this.recMan = manager;
 
-        this.keySerializer = keySerializer;
         this.valueSerializer = valueSerializer;
 
         this.allowsDuplicates = false;
@@ -227,7 +225,7 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
         }
         else
         {
-            bt = new BTree<K, V>( recMan, keyComparator, keySerializer, valueSerializer );
+            bt = new BTree<>( recMan, keyComparator, keySerializer, valueSerializer );
             recId = bt.getRecordId();
             recMan.setNamedObject( name, recId );
             recId = recMan.insert( 0 );
@@ -237,57 +235,13 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     // ------------------------------------------------------------------------
-    // Simple Table Properties
-    // ------------------------------------------------------------------------
-
-    public Serializer getKeySerializer()
-    {
-        return keySerializer;
-    }
-
-
-    public Serializer getValueSerializer()
-    {
-        return valueSerializer;
-    }
-
-
-    /**
-     * @see org.apache.directory.server.xdbm.Table#isDupsEnabled()
-     */
-    public boolean isDupsEnabled()
-    {
-        return allowsDuplicates;
-    }
-
-
-    // ------------------------------------------------------------------------
     // Count Overloads
     // ------------------------------------------------------------------------
     /**
-     * @see Table#greaterThanCount(Object)
-     */
-    public long greaterThanCount( K key ) throws IOException
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
-     * @see Table#lessThanCount(Object)
-     */
-    public long lessThanCount( K key ) throws IOException
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
      * @see org.apache.directory.server.xdbm.Table#count(java.lang.Object)
      */
-    public long count( K key ) throws LdapException
+    @Override
+    public long count( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -328,8 +282,12 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
     // get/has/put/remove Methods and Overloads
     // ------------------------------------------------------------------------
 
+    /**
+     * {@inheritDoc}
+     */
     @SuppressWarnings("unchecked")
-    public V get( K key ) throws LdapException
+    @Override
+    public V get( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -375,9 +333,10 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     /**
-     * @see Table#hasGreaterOrEqual(Object,Object)
+     * {@inheritDoc}
      */
-    public boolean hasGreaterOrEqual( K key, V val ) throws LdapException
+    @Override
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -413,9 +372,10 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     /**
-     * @see Table#hasLessOrEqual(Object,Object)
+     * {@inheritDoc}
      */
-    public boolean hasLessOrEqual( K key, V val ) throws LdapException
+    @Override
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -451,86 +411,95 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     /**
-     * @see org.apache.directory.server.xdbm.Table#hasGreaterOrEqual(Object)
+     * {@inheritDoc}
      */
+    @Override
     @SuppressWarnings("unchecked")
-    public boolean hasGreaterOrEqual( K key ) throws IOException
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
-        // See if we can find the border between keys greater than and less
-        // than in the set of keys.  This will be the spot we search from.
-        jdbm.helper.Tuple tuple = bt.findGreaterOrEqual( key );
-
-        // Test for equality first since it satisfies both greater/less than
-        if ( null != tuple && keyComparator.compare( ( K ) tuple.getKey(), key ) == 0 )
+        try
         {
-            return true;
+            // See if we can find the border between keys greater than and less
+            // than in the set of keys.  This will be the spot we search from.
+            jdbm.helper.Tuple tuple = bt.findGreaterOrEqual( key );
+    
+            // Test for equality first since it satisfies both greater/less than
+            if ( null != tuple && keyComparator.compare( ( K ) tuple.getKey(), key ) == 0 )
+            {
+                return true;
+            }
+    
+            // Greater searches are easy and quick thanks to findGreaterOrEqual
+            // A null return above means there were no equal or greater keys
+            return ( null != tuple );
         }
-
-        // Greater searches are easy and quick thanks to findGreaterOrEqual
-        // A null return above means there were no equal or greater keys
-        if ( null == tuple )
+        catch ( IOException ioe )
         {
-            return false;
+            throw new LdapOtherException( ioe.getMessage() );
         }
-
-        // Not Null! - we found a tuple with equal or greater key value
-        return true;
     }
 
 
     /**
-     * @see Table#hasLessOrEqual(Object)
+     * {@inheritDoc}
      */
     @SuppressWarnings("unchecked")
-    public boolean hasLessOrEqual( K key ) throws IOException
+    @Override
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
-        // Can only find greater than or equal to with JDBM so we find that
-        // and work backwards to see if we can find one less than the key
-        Tuple<K, V> tuple = bt.findGreaterOrEqual( key );
-
-        // Test for equality first since it satisfies equal to condition
-        if ( null != tuple && keyComparator.compare( tuple.getKey(), key ) == 0 )
-        {
-            return true;
-        }
-
-        if ( null == tuple )
-        {
-            /*
-             * Jdbm failed to find a key greater than or equal to the argument
-             * which means all the keys in the table are less than the
-             * supplied key argument.  We can hence return true if the table
-             * contains any Tuples.
-             */
-            return count > 0;
-        }
-        else
+        try
         {
-            /*
-             * We have the next tuple whose key is the next greater than the
-             * key argument supplied.  We use this key to advance a browser to
-             * that tuple and scan down to lesser Tuples until we hit one
-             * that is less than the key argument supplied.  Usually this will
-             * be the previous tuple if it exists.
-             */
-            TupleBrowser browser = bt.browse( tuple.getKey() );
-
-            if ( browser.getPrevious( tuple ) )
+            // Can only find greater than or equal to with JDBM so we find that
+            // and work backwards to see if we can find one less than the key
+            Tuple<K, V> tuple = bt.findGreaterOrEqual( key );
+    
+            // Test for equality first since it satisfies equal to condition
+            if ( null != tuple && keyComparator.compare( tuple.getKey(), key ) == 0 )
             {
                 return true;
             }
+    
+            if ( null == tuple )
+            {
+                /*
+                 * Jdbm failed to find a key greater than or equal to the argument
+                 * which means all the keys in the table are less than the
+                 * supplied key argument.  We can hence return true if the table
+                 * contains any Tuples.
+                 */
+                return count > 0;
+            }
+            else
+            {
+                /*
+                 * We have the next tuple whose key is the next greater than the
+                 * key argument supplied.  We use this key to advance a browser to
+                 * that tuple and scan down to lesser Tuples until we hit one
+                 * that is less than the key argument supplied.  Usually this will
+                 * be the previous tuple if it exists.
+                 */
+                TupleBrowser browser = bt.browse( tuple.getKey() );
+    
+                if ( browser.getPrevious( tuple ) )
+                {
+                    return true;
+                }
+            }
+    
+            return false;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
         }
-
-        return false;
     }
 
 
     /**
-     * @see org.apache.directory.server.xdbm.Table#has(java.lang.Object,
-     * java.lang.Object)
+     * {@inheritDoc}
      */
     @SuppressWarnings("unchecked")
-    public boolean has( K key, V value ) throws LdapException
+    public boolean has( PartitionTxn transaction, K key, V value ) throws LdapException
     {
         if ( key == null )
         {
@@ -562,20 +531,28 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     /**
-     * @see Table#has(java.lang.Object)
+     * {@inheritDoc}
      */
-    public boolean has( K key ) throws IOException
+    @Override
+    public boolean has( PartitionTxn transaction, K key ) throws LdapException
     {
-        return key != null && bt.find( key ) != null;
+        try
+        {
+            return key != null && bt.find( key ) != null;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapException( ioe );
+        }
     }
 
 
     /**
-     * @see org.apache.directory.server.xdbm.Table#put(java.lang.Object,
-     * java.lang.Object)
+     * {@inheritDoc}
      */
+    @Override
     @SuppressWarnings("unchecked")
-    public synchronized void put( K key, V value ) throws Exception
+    public synchronized void put( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -664,20 +641,20 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
             commit( recMan );
         }
-        catch ( Exception e )
+        catch ( IOException | CursorException | LdapException e )
         {
             LOG.error( I18n.err( I18n.ERR_131, key, name ), e );
-            throw e;
+            throw new LdapOtherException( e.getMessage(), e );
         }
     }
 
 
     /**
-     * @see org.apache.directory.server.xdbm.Table#remove(java.lang.Object,
-     * java.lang.Object)
+     * {@inheritDoc}
      */
     @SuppressWarnings("unchecked")
-    public synchronized void remove( K key, V value ) throws IOException
+    @Override
+    public synchronized void remove( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -788,9 +765,10 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
 
 
     /**
-     * @see Table#remove(Object)
+     * {@inheritDoc}
      */
-    public synchronized void remove( K key )
+    @Override
+    public synchronized void remove( PartitionWriteTxn transaction, K key ) throws LdapException
     {
         try
         {
@@ -871,81 +849,107 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
     }
 
 
-    public Cursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>> cursor() throws LdapException
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Cursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>> cursor( PartitionTxn transaction ) throws LdapException
     {
         if ( allowsDuplicates )
         {
-            return new DupsCursor<K, V>( this );
+            return new DupsCursor<>( this );
         }
 
-        return new NoDupsCursor<K, V>( this );
+        return new NoDupsCursor<>( this );
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
     @SuppressWarnings("unchecked")
-    public Cursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>> cursor( K key ) throws Exception
+    public Cursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>> cursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
-            return new EmptyCursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>>();
-        }
-
-        V raw = bt.find( key );
-
-        if ( null == raw )
-        {
-            return new EmptyCursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>>();
+            return new EmptyCursor<>();
         }
 
-        if ( !allowsDuplicates )
-        {
-            return new SingletonCursor<org.apache.directory.api.ldap.model.cursor.Tuple<K, V>>(
-                new org.apache.directory.api.ldap.model.cursor.Tuple<K, V>( key, raw ) );
+        try
+        { 
+            V raw = bt.find( key );
+    
+            if ( null == raw )
+            {
+                return new EmptyCursor<>();
+            }
+    
+            if ( !allowsDuplicates )
+            {
+                return new SingletonCursor<>(
+                    new org.apache.directory.api.ldap.model.cursor.Tuple<K, V>( key, raw ) );
+            }
+    
+            byte[] serialized = ( byte[] ) raw;
+    
+            if ( BTreeRedirectMarshaller.isRedirect( serialized ) )
+            {
+                BTree tree = getBTree( BTreeRedirectMarshaller.INSTANCE.deserialize( serialized ) );
+                return new KeyTupleBTreeCursor<>( tree, key, valueComparator );
+            }
+    
+            ArrayTree<V> set = marshaller.deserialize( serialized );
+    
+            return new KeyTupleArrayCursor<>( set, key );
         }
-
-        byte[] serialized = ( byte[] ) raw;
-
-        if ( BTreeRedirectMarshaller.isRedirect( serialized ) )
+        catch ( IOException ioe )
         {
-            BTree tree = getBTree( BTreeRedirectMarshaller.INSTANCE.deserialize( serialized ) );
-            return new KeyTupleBTreeCursor<K, V>( tree, key, valueComparator );
+            throw new LdapOtherException( ioe.getMessage(), ioe );
         }
-
-        ArrayTree<V> set = marshaller.deserialize( serialized );
-
-        return new KeyTupleArrayCursor<K, V>( set, key );
     }
 
 
+    /**
+     * {@inheritDoc}
+     */
     @SuppressWarnings("unchecked")
-    public Cursor<V> valueCursor( K key ) throws Exception
+    @Override
+    public Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
-            return new EmptyCursor<V>();
+            return new EmptyCursor<>();
         }
 
-        V raw = bt.find( key );
-
-        if ( null == raw )
-        {
-            return new EmptyCursor<V>();
-        }
-
-        if ( !allowsDuplicates )
+        try
         {
-            return new SingletonCursor<V>( raw );
+            V raw = bt.find( key );
+    
+            if ( null == raw )
+            {
+                return new EmptyCursor<>();
+            }
+    
+            if ( !allowsDuplicates )
+            {
+                return new SingletonCursor<>( raw );
+            }
+    
+            byte[] serialized = ( byte[] ) raw;
+    
+            if ( BTreeRedirectMarshaller.isRedirect( serialized ) )
+            {
+                BTree tree = getBTree( BTreeRedirectMarshaller.INSTANCE.deserialize( serialized ) );
+                return new KeyBTreeCursor<>( tree, valueComparator );
+            }
+    
+            return new ArrayTreeCursor<>( marshaller.deserialize( serialized ) );
         }
-
-        byte[] serialized = ( byte[] ) raw;
-
-        if ( BTreeRedirectMarshaller.isRedirect( serialized ) )
+        catch ( IOException ioe )
         {
-            BTree tree = getBTree( BTreeRedirectMarshaller.INSTANCE.deserialize( serialized ) );
-            return new KeyBTreeCursor<V>( tree, valueComparator );
+            throw new LdapOtherException( ioe.getMessage(), ioe );
         }
-
-        return new ArrayTreeCursor<V>( marshaller.deserialize( serialized ) );
     }
 
 
@@ -956,9 +960,17 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
     /**
      * @see Table#close()
      */
-    public synchronized void close() throws IOException
+    @Override
+    public synchronized void close( PartitionTxn transaction ) throws LdapException
     {
-        sync();
+        try
+        {
+            sync();
+        }
+        catch  ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
+        }
     }
 
 
@@ -1143,7 +1155,7 @@ public class JdbmTable<K, V> extends AbstractTable<K, V>
     }
 
 
-    private BTree<V, K> convertToBTree( ArrayTree<V> arrayTree ) throws Exception
+    private BTree<V, K> convertToBTree( ArrayTree<V> arrayTree ) throws IOException, CursorException, LdapException
     {
         BTree<V, K> bTree;
 
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
index be164b2..02549d8 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
+++ b/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
@@ -69,7 +69,7 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      * @param comparator the Comparator used to determine <b>key</b> ordering
      * @throws Exception of there are problems accessing the BTree
      */
-    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception
+    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws IOException
     {
         if ( IS_DEBUG )
         {
diff --git a/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTableWithDuplicatesTest.java b/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTableWithDuplicatesTest.java
index fc24a71..91aa2f6 100644
--- a/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTableWithDuplicatesTest.java
+++ b/jdbm-partition/src/test/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmTableWithDuplicatesTest.java
@@ -159,14 +159,6 @@ public class JdbmTableWithDuplicatesTest
 
 
     @Test
-    public void testSerializers() throws Exception
-    {
-        assertNotNull( table.getKeySerializer() );
-        assertNotNull( ( ( JdbmTable<?, ?> ) table ).getValueSerializer() );
-    }
-
-
-    @Test
     public void testCountOneArg() throws Exception
     {
         assertEquals( 0, table.count( "3" ) );
@@ -590,7 +582,6 @@ public class JdbmTableWithDuplicatesTest
 
         table = new JdbmTable<String, String>( schemaManager, "test", SIZE, recman,
             comparator, comparator, new DefaultSerializer(), null );
-        assertNull( table.getValueSerializer() );
 
         for ( int i = 0; i < SIZE + 1; i++ )
         {
diff --git a/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java b/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
index 124d865..20d78df 100644
--- a/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
+++ b/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
@@ -27,6 +27,7 @@ import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
 import org.apache.directory.mavibot.btree.BTree;
 import org.apache.directory.mavibot.btree.BTreeFactory;
@@ -36,6 +37,8 @@ import org.apache.directory.mavibot.btree.ValueCursor;
 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
 import org.apache.directory.server.core.avltree.ArrayMarshaller;
 import org.apache.directory.server.core.avltree.ArrayTree;
 import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
@@ -140,18 +143,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean isDupsEnabled()
-    {
-        return allowsDuplicates;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     * @throws  
-     */
-    @Override
-    public boolean has( K key ) throws LdapException
+    public boolean has( PartitionTxn partitionTxn, K key ) throws LdapException
     {
         try
         {
@@ -172,7 +164,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean has( K key, V value ) throws LdapException
+    public boolean has( PartitionTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -189,7 +181,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasGreaterOrEqual( K key ) throws Exception
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         TupleCursor<K, V> cursor = null;
 
@@ -199,6 +191,10 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
 
             return cursor.hasNext();
         }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
+        }
         finally
         {
             if ( cursor != null )
@@ -213,7 +209,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasLessOrEqual( K key ) throws Exception
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         TupleCursor<K, V> cursor = null;
 
@@ -248,6 +244,10 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
 
             return false;
         }
+        catch ( Exception e )
+        {
+            throw new LdapException( e );
+        }
         finally
         {
             if ( cursor != null )
@@ -262,7 +262,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasGreaterOrEqual( K key, V val ) throws LdapException
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -274,7 +274,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             throw new UnsupportedOperationException( I18n.err( I18n.ERR_593 ) );
         }
 
-        TupleCursor<V, V> cursor = null;
+        ValueCursor<V> valueCursor = null;
 
         try
         {
@@ -283,21 +283,21 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 return false;
             }
 
-            ValueCursor<V> valueCursor = bt.getValues( key );
+            valueCursor = bt.getValues( key );
 
             int equal = bt.getValueSerializer().compare( val, valueCursor.next() );
 
             return ( equal >= 0 );
         }
-        catch ( Exception e )
+        catch ( KeyNotFoundException | IOException e )
         {
-            throw new LdapException( e );
+            throw new LdapException( e.getMessage() );
         }
         finally
         {
-            if ( cursor != null )
+            if ( valueCursor != null )
             {
-                cursor.close();
+                valueCursor.close();
             }
         }
     }
@@ -307,7 +307,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasLessOrEqual( K key, V val ) throws Exception
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -334,7 +334,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public V get( K key ) throws LdapException
+    public V get( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -360,7 +360,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void put( K key, V value ) throws Exception
+    public void put( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -376,10 +376,10 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 count++;
             }
         }
-        catch ( Exception e )
+        catch ( IOException ioe )
         {
-            LOG.error( I18n.err( I18n.ERR_131, key, name ), e );
-            throw e;
+            LOG.error( I18n.err( I18n.ERR_131, key, name ), ioe );
+            throw new LdapOtherException( ioe.getMessage(), ioe );
         }
     }
 
@@ -388,7 +388,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void remove( K key ) throws Exception
+    public void remove( PartitionWriteTxn transaction, K key ) throws LdapException
     {
         try
         {
@@ -424,14 +424,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 count--;
             }
         }
-        catch ( Exception e )
+        catch ( IOException | KeyNotFoundException e )
         {
             LOG.error( I18n.err( I18n.ERR_133, key, name ), e );
 
-            if ( e instanceof IOException )
-            {
-                throw ( IOException ) e;
-            }
+            throw new LdapOtherException( e.getMessage(), e );
         }
     }
 
@@ -440,7 +437,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void remove( K key, V value ) throws Exception
+    public void remove( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -468,9 +465,9 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<Tuple<K, V>> cursor() throws LdapException
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction ) throws LdapException
     {
-        return new MavibotCursor<K, V>( this );
+        return new MavibotCursor<>( this );
     }
 
 
@@ -478,11 +475,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<Tuple<K, V>> cursor( K key ) throws LdapException
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
-            return new EmptyCursor<Tuple<K, V>>();
+            return new EmptyCursor<>();
         }
 
         try
@@ -491,19 +488,18 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             {
                 V val = bt.get( key );
 
-                return new SingletonCursor<Tuple<K, V>>(
-                    new Tuple<K, V>( key, val ) );
+                return new SingletonCursor<>( new Tuple<K, V>( key, val ) );
             }
             else
             {
                 ValueCursor<V> dupHolder = bt.getValues( key );
 
-                return new KeyTupleValueCursor<K, V>( dupHolder, key );
+                return new KeyTupleValueCursor<>( dupHolder, key );
             }
         }
         catch ( KeyNotFoundException knfe )
         {
-            return new EmptyCursor<Tuple<K, V>>();
+            return new EmptyCursor<>();
         }
         catch ( Exception e )
         {
@@ -516,7 +512,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<V> valueCursor( K key ) throws Exception
+    public Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -529,18 +525,18 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             {
                 V val = bt.get( key );
 
-                return new SingletonCursor<V>( val );
+                return new SingletonCursor<>( val );
             }
             else
             {
                 ValueCursor<V> dupCursor = bt.getValues( key );
 
-                return new ValueTreeCursor<V>( dupCursor );
+                return new ValueTreeCursor<>( dupCursor );
             }
         }
         catch ( KeyNotFoundException knfe )
         {
-            return new EmptyCursor<V>();
+            return new EmptyCursor<>();
         }
         catch ( Exception e )
         {
@@ -553,16 +549,16 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public long count( K key ) throws Exception
+    public long count( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
             return 0;
         }
 
-        if ( bt.isAllowDuplicates() )
+        try
         {
-            try
+            if ( bt.isAllowDuplicates() )
             {
                 ValueCursor<V> dupHolder = bt.getValues( key );
                 int size = dupHolder.size();
@@ -570,58 +566,27 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
 
                 return size;
             }
-            catch ( KeyNotFoundException knfe )
+            else
             {
-                // No key
-                return 0;
+                if ( bt.hasKey( key ) )
+                {
+                    return 1;
+                }
+                else
+                {
+                    return 0;
+                }
             }
         }
-        else
+        catch ( KeyNotFoundException knfe )
         {
-            if ( bt.hasKey( key ) )
-            {
-                return 1;
-            }
-            else
-            {
-                return 0;
-            }
+            // No key
+            return 0;
+        }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
         }
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long greaterThanCount( K key ) throws Exception
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long lessThanCount( K key ) throws Exception
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void close() throws Exception
-    {
-        // do nothing here, the RecordManager will be closed in MavibotMasterTable.close()
     }
 
 
diff --git a/mavibotv2-partition/pom.xml b/mavibotv2-partition/pom.xml
new file mode 100644
index 0000000..8419302
--- /dev/null
+++ b/mavibotv2-partition/pom.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.directory.server</groupId>
+    <artifactId>apacheds-parent</artifactId>
+    <version>2.0.0-M25-SNAPSHOT</version>
+  </parent>
+  <artifactId>apacheds-mavibotv2-partition</artifactId>
+  <name>ApacheDS Mavibot v2 Partition</name>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.directory.junit</groupId>
+      <artifactId>junit-addons</artifactId>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.mavibot</groupId>
+      <artifactId>mavibot</artifactId>
+      <version>1.0.0-M9-SNAPSHOT</version>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-api</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-shared</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-core-avl</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-i18n</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-xdbm-partition</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>apacheds-xdbm-partition</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-model</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-ldap-schema-data</artifactId>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.directory.api</groupId>
+      <artifactId>api-util</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-sources</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <configuration>
+          <archive>
+            <manifestFile>META-INF/MANIFEST.MF</manifestFile>
+            <addMavenDescriptor>false</addMavenDescriptor>
+          </archive>
+        </configuration>
+      </plugin>
+      
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <inherited>true</inherited>
+        <extensions>true</extensions>
+        <configuration>
+          <manifestLocation>META-INF</manifestLocation>
+          <instructions>
+            <Bundle-SymbolicName>${project.groupId}.mavibotv2.partition</Bundle-SymbolicName>
+            <Export-Package>
+                org.apache.directory.server.core.partition.impl.btree.mavibotv2;version=${project.version};-noimport:=true
+            </Export-Package>
+          </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/AbstractMavibotTxn.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/AbstractMavibotTxn.java
new file mode 100644
index 0000000..71d0639
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/AbstractMavibotTxn.java
@@ -0,0 +1,96 @@
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+import java.io.IOException;
+
+import org.apache.directory.mavibot.btree.BTree;
+import org.apache.directory.mavibot.btree.BTreeInfo;
+import org.apache.directory.mavibot.btree.Page;
+import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.mavibot.btree.RecordManagerHeader;
+import org.apache.directory.mavibot.btree.Transaction;
+
+public abstract class AbstractMavibotTxn implements MavibotTxn
+{
+    protected Transaction transaction;
+    
+    protected AbstractMavibotTxn( Transaction transaction )
+    {
+        this.transaction = transaction;
+    }
+    
+    
+    @Override
+    public void commit() throws IOException
+    {
+        transaction.commit();
+    }
+
+    
+    @Override
+    public void abort() throws IOException
+    {
+        transaction.abort();
+    }
+
+    
+    @Override
+    public boolean isClosed()
+    {
+        return transaction.isClosed();
+    }
+
+    
+    @Override
+    public void close() throws IOException
+    {
+        transaction.close();
+    }
+
+    
+    @Override
+    public long getRevision()
+    {
+        return transaction.getRevision();
+    }
+
+    
+    @Override
+    public <K, V> Page<K, V> getPage( BTreeInfo<K, V> btreeInfo, long offset ) throws IOException
+    {
+        return transaction.getPage( btreeInfo, offset );
+    }
+
+    
+    @Override
+    public long getCreationDate()
+    {
+        return transaction.getCreationDate();
+    }
+
+    
+    @Override
+    public RecordManager getRecordManager()
+    {
+        return transaction.getRecordManager();
+    }
+
+    
+    @Override
+    public RecordManagerHeader getRecordManagerHeader()
+    {
+        return transaction.getRecordManagerHeader();
+    }
+
+    
+    @Override
+    public <K, V> BTree<K, V> getBTree( String name )
+    {
+        return transaction.getBTree( name );
+    }
+
+    
+    public Transaction getTransaction()
+    {
+        return transaction;
+    }
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/DnSerializer.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/DnSerializer.java
new file mode 100644
index 0000000..2f60099
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/DnSerializer.java
@@ -0,0 +1,206 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.mavibot.btree.serializer.AbstractElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.BufferHandler;
+import org.apache.directory.server.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Serialize and deserialize a Dn.
+ * </br></br>
+ * <b>This class must *not* be used outside of the server.</b>
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class DnSerializer extends AbstractElementSerializer<Dn>
+{
+    /** The serialVersionUID */
+    private static final long serialVersionUID = 1L;
+
+    /** the logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( DnSerializer.class );
+
+    /**
+     * Speedup for logs
+     */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    private static Comparator<Dn> comp = new Comparator<Dn>()
+    {
+        @Override
+        public int compare( Dn dn1, Dn dn2 )
+        {
+            if ( dn1 == null )
+            {
+                if ( dn2 == null )
+                {
+                    return 0;
+                }
+
+                return -1;
+            }
+
+            if ( dn2 == null )
+            {
+                return 1;
+            }
+
+            return dn1.getNormName().compareTo( dn2.getNormName() );
+        }
+    };
+
+
+    /**
+     * Creates a new instance of DnSerializer.
+     * 
+     * @param schemaManager The reference to the global schemaManager
+     */
+    public DnSerializer()
+    {
+        super( comp );
+    }
+
+
+    /**
+     * <p>
+     * 
+     * This is the place where we serialize Dn
+     * <p>
+     */
+    public byte[] serialize( Dn dn )
+    {
+        try
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            ObjectOutput out = new ObjectOutputStream( baos );
+
+            // First, the Dn
+            dn.writeExternal( out );
+
+            out.flush();
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( ">------------------------------------------------" );
+                LOG.debug( "Serialized " + dn );
+            }
+
+            return baos.toByteArray();
+        }
+        catch ( IOException e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     *  Deserialize a Dn.
+     *  
+     *  @param bytes the byte array containing the serialized Dn
+     *  @return An instance of a Dn object 
+     *  @throws IOException if we can't deserialize the Dn
+     */
+    public Dn deserialize( ByteBuffer buffer ) throws IOException
+    {
+        return deserialize( new BufferHandler( buffer.array() ) );
+    }
+
+
+    @Override
+    public Dn deserialize( BufferHandler bufferHandler ) throws IOException
+    {
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( bufferHandler.getBuffer() ) );
+
+        try
+        {
+            Dn dn = new Dn();
+
+            dn.readExternal( in );
+
+            return dn;
+        }
+        catch ( ClassNotFoundException cnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) );
+            throw new IOException( cnfe.getLocalizedMessage() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Dn fromBytes( byte[] buffer ) throws IOException
+    {
+        return fromBytes( buffer, 0 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Dn fromBytes( byte[] buffer, int pos ) throws IOException
+    {
+        int length = buffer.length - pos;
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( buffer, pos, length ) );
+
+        try
+        {
+            Dn dn = new Dn();
+
+            dn.readExternal( in );
+
+            return dn;
+        }
+        catch ( ClassNotFoundException cnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) );
+            throw new IOException( cnfe.getLocalizedMessage() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?> getType()
+    {
+        return Dn.class;
+    }
+}
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/KeyTupleValueCursor.java
similarity index 50%
copy from jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
copy to mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/KeyTupleValueCursor.java
index be164b2..20b5c06 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/KeyTupleValueCursor.java
@@ -16,14 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.directory.server.core.partition.impl.btree.jdbm;
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
 
 
 import java.io.IOException;
-import java.util.Comparator;
-
-import jdbm.btree.BTree;
-import jdbm.helper.TupleBrowser;
 
 import org.apache.directory.api.ldap.model.constants.Loggers;
 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
@@ -31,19 +27,20 @@ import org.apache.directory.api.ldap.model.cursor.CursorException;
 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.mavibot.btree.ValueCursor;
 import org.apache.directory.server.i18n.I18n;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
- * Cursor over a set of values for the same key which are store in another
- * BTree.  This Cursor is limited to the same key and it's tuples will always
- * return the same key.
+ * Cursor over a set of values for the same key which are store in an in
+ * memory ArrayTree.  This Cursor is limited to the same key and it's tuples
+ * will always return the same key.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
+public class KeyTupleValueCursor<K, V> extends AbstractCursor<Tuple<K, V>>
 {
     /** A dedicated log for cursors */
     private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
@@ -51,35 +48,29 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /** Speedup for logs */
     private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
 
-    private final Comparator<V> comparator;
-    private final BTree btree;
+    private final ValueCursor<V> wrapped;
     private final K key;
 
-    private jdbm.helper.Tuple<K, V> valueTuple = new jdbm.helper.Tuple<K, V>();
     private Tuple<K, V> returnedTuple = new Tuple<K, V>();
-    private TupleBrowser<K, V> browser;
     private boolean valueAvailable;
 
 
     /**
-     * Creates a Cursor over the tuples of a JDBM BTree.
+     * Creates a Cursor over the tuples of an ArrayTree.
      *
-     * @param btree the JDBM BTree to build a Cursor over
+     * @param arrayTree the ArrayTree to build a Tuple returning Cursor over
      * @param key the constant key for which values are returned
-     * @param comparator the Comparator used to determine <b>key</b> ordering
-     * @throws Exception of there are problems accessing the BTree
      */
-    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception
+    public KeyTupleValueCursor( ValueCursor<V> cursor, K key )
     {
+        this.key = key;
+
+        this.wrapped = cursor;
+
         if ( IS_DEBUG )
         {
-            LOG_CURSOR.debug( "Creating KeyTupleBTreeCursor {}", this );
+            LOG_CURSOR.debug( "Creating KeyTupleArrayCursor {}", this );
         }
-
-        this.key = key;
-        this.btree = btree;
-        this.comparator = comparator;
-        this.browser = btree.browse();
     }
 
 
@@ -91,9 +82,6 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
     public boolean available()
     {
         return valueAvailable;
@@ -106,109 +94,35 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
     public void afterKey( K key ) throws Exception
     {
         throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
     public void beforeValue( K key, V value ) throws Exception
     {
-        checkNotClosed( "beforeValue()" );
-        if ( key != null && !key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
-        }
-
-        browser = btree.browse( value );
-        clearValue();
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
-    /**
-     * {@inheritDoc}
-     */
-    @SuppressWarnings("unchecked")
-    public void afterValue( K key, V value ) throws LdapException, CursorException
+    public void afterValue( K key, V value ) throws Exception
     {
-        if ( key != null && !key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
-        }
-
-        try
-        {
-            browser = btree.browse( value );
-
-            /*
-             * While the next value is less than or equal to the element keep
-             * advancing forward to the next item.  If we cannot advance any
-             * further then stop and return.  If we find a value greater than
-             * the element then we stop, backup, and return so subsequent calls
-             * to getNext() will return a value greater than the element.
-             */
-            while ( browser.getNext( valueTuple ) )
-            {
-                checkNotClosed( "afterValue" );
-
-                V next = ( V ) valueTuple.getKey();
-
-                int nextCompared = comparator.compare( next, value );
-
-                if ( nextCompared > 0 )
-                {
-                    /*
-                     * If we just have values greater than the element argument
-                     * then we are before the first element and cannot backup, and
-                     * the call below to getPrevious() will fail.  In this special
-                     * case we just reset the Cursor's browser and return.
-                     */
-                    if ( !browser.getPrevious( valueTuple ) )
-                    {
-                        browser = btree.browse( this.key );
-                    }
-
-                    clearValue();
-
-                    return;
-                }
-            }
-
-            clearValue();
-        }
-        catch ( IOException e )
-        {
-            throw new CursorException( e );
-        }
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
     /**
      * Positions this Cursor over the same keys before the value of the
-     * supplied valueTuple.  The supplied element Tuple's key is not considered at
-     * all.
+     * supplied element Tuple.  The supplied element Tuple's key is not
+     * considered at all.
      *
      * @param element the valueTuple who's value is used to position this Cursor
      * @throws Exception if there are failures to position the Cursor
      */
     public void before( Tuple<K, V> element ) throws LdapException, CursorException
     {
-        checkNotClosed( "before()" );
-        try
-        {
-            browser = btree.browse( element.getValue() );
-            clearValue();
-        }
-        catch ( IOException e )
-        {
-            throw new CursorException( e );
-        }
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
@@ -217,7 +131,7 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public void after( Tuple<K, V> element ) throws LdapException, CursorException
     {
-        afterValue( key, element.getValue() );
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
@@ -226,16 +140,6 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public void beforeFirst() throws LdapException, CursorException
     {
-        checkNotClosed( "beforeFirst()" );
-        try
-        {
-            browser = btree.browse();
-            clearValue();
-        }
-        catch ( IOException e )
-        {
-            throw new CursorException( e );
-        }
     }
 
 
@@ -244,15 +148,6 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public void afterLast() throws LdapException, CursorException
     {
-        checkNotClosed( "afterLast()" );
-        try
-        {
-            browser = btree.browse( null );
-        }
-        catch ( IOException e )
-        {
-            throw new CursorException( e );
-        }
     }
 
 
@@ -261,9 +156,7 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public boolean first() throws LdapException, CursorException
     {
-        beforeFirst();
-
-        return next();
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
@@ -272,40 +165,29 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public boolean last() throws LdapException, CursorException
     {
-        afterLast();
-
-        return previous();
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
     }
 
 
     /**
      * {@inheritDoc}
      */
-    @SuppressWarnings("unchecked")
     public boolean previous() throws LdapException, CursorException
     {
         checkNotClosed( "previous()" );
 
         try
         {
-            if ( browser.getPrevious( valueTuple ) )
+            if ( wrapped.hasPrev() )
             {
-                // work around to fix direction change problem with jdbm browser
-                if ( ( returnedTuple.getValue() != null )
-                    && ( comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 ) )
-                {
-                    browser.getPrevious( valueTuple );
-                }
                 returnedTuple.setKey( key );
-                returnedTuple.setValue( ( V ) valueTuple.getKey() );
-
+                returnedTuple.setValue( wrapped.prev() );
                 valueAvailable = true;
                 return true;
             }
             else
             {
                 clearValue();
-
                 return false;
             }
         }
@@ -319,24 +201,16 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /**
      * {@inheritDoc}
      */
-    @SuppressWarnings("unchecked")
     public boolean next() throws LdapException, CursorException
     {
         checkNotClosed( "next()" );
 
         try
         {
-            if ( browser.getNext( valueTuple ) )
+            if ( wrapped.hasNext() )
             {
-                // work around to fix direction change problem with jdbm browser
-                if ( returnedTuple.getValue() != null
-                    && comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
-                {
-                    browser.getNext( valueTuple );
-                }
-
                 returnedTuple.setKey( key );
-                returnedTuple.setValue( ( V ) valueTuple.getKey() );
+                returnedTuple.setValue( wrapped.next() );
 
                 valueAvailable = true;
                 return true;
@@ -374,12 +248,16 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /**
      * {@inheritDoc}
      */
-    @Override
     public void close() throws IOException
     {
         if ( IS_DEBUG )
         {
-            LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
+            LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this );
+        }
+
+        if ( wrapped != null )
+        {
+            wrapped.close();
         }
 
         super.close();
@@ -389,14 +267,55 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /**
      * {@inheritDoc}
      */
-    @Override
-    public void close( Exception cause ) throws IOException
+    public void close( Exception reason ) throws IOException
     {
         if ( IS_DEBUG )
         {
-            LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
+            LOG_CURSOR.debug( "Closing KeyTupleArrayCursor {}", this );
         }
 
-        super.close( cause );
+        if ( wrapped != null )
+        {
+            wrapped.close();
+        }
+
+        super.close( reason );
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString( String tabs )
+    {
+        StringBuilder sb = new StringBuilder();
+
+        sb.append( tabs ).append( "KeyTupleArrayCursor (" );
+
+        if ( available() )
+        {
+            sb.append( "available)" );
+        }
+        else
+        {
+            sb.append( "absent)" );
+        }
+
+        sb.append( "#" ).append( key );
+
+        sb.append( " :\n" );
+
+        sb.append( wrapped.toString() );
+
+        return sb.toString();
+    }
+
+
+    /**
+     * @see Object#toString()
+     */
+    public String toString()
+    {
+        return toString( "" );
     }
 }
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleComparator.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleComparator.java
new file mode 100644
index 0000000..6779c66
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleComparator.java
@@ -0,0 +1,57 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+import java.util.Comparator;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.mavibot.btree.Tuple;
+
+/**
+ * TODO LdifTupleComparator.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifTupleComparator implements Comparator<Tuple<Dn, String>>
+{
+
+    @Override
+    public int compare( Tuple<Dn, String> t1, Tuple<Dn, String> t2 )
+    {
+        Dn dn1 = t1.getKey();
+        Dn dn2 = t2.getKey();
+
+        if ( dn1.isAncestorOf( dn2 ) )
+        {
+            return -1;
+        }
+        else if ( dn2.isAncestorOf( dn1 ) )
+        {
+            return 1;
+        }
+        else if ( dn1.equals( dn2 ) )
+        {
+            return 0;
+        }
+
+        return dn1.getNormName().compareTo( dn2.getNormName() );
+    }
+
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleReaderWriter.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleReaderWriter.java
new file mode 100644
index 0000000..1f16448
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/LdifTupleReaderWriter.java
@@ -0,0 +1,162 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.ldif.LdifEntry;
+import org.apache.directory.api.ldap.model.ldif.LdifReader;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.mavibot.btree.Tuple;
+import org.apache.directory.mavibot.btree.util.TupleReaderWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * TODO LdifTupleReaderWriter.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class LdifTupleReaderWriter<E> implements TupleReaderWriter<Dn, E>
+{
+
+    private LdifReader reader = null;
+
+    private static final Logger LOG = LoggerFactory.getLogger( LdifTupleReaderWriter.class );
+
+    private String ldifFile;
+    
+    private RandomAccessFile raf;
+    
+    private SchemaManager schemaManager;
+    
+    public LdifTupleReaderWriter( String ldifFile, SchemaManager schemaManager )
+    {
+        this.ldifFile = ldifFile;
+        this.schemaManager = schemaManager;
+        
+        try
+        {
+            raf = new RandomAccessFile( ldifFile, "r" );
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+    
+
+    @Override
+    public Tuple<Dn, E> readSortedTuple( DataInputStream in )
+    {
+        try
+        {
+            if ( in.available() > 0 )
+            {
+                Tuple<Dn, E> t = new Tuple<Dn, E>();
+                t.setKey( new Dn( in.readUTF() ) );
+                
+                String[] tokens = in.readUTF().split( ":" );
+                
+                long offset = Long.valueOf( tokens[0] );
+                
+                int length = Integer.valueOf( tokens[1] );
+                
+                raf.seek( offset );
+                
+                byte[] data = new byte[length];
+                
+                raf.read( data, 0, length );
+                
+                LdifReader reader = new LdifReader();
+                
+                LdifEntry ldifEntry = reader.parseLdif( new String( data ) ).get( 0 );
+                Entry entry = new DefaultEntry( schemaManager, ldifEntry.getEntry() );
+
+                t.setValue( ( E ) entry );
+                
+                return t;
+            }
+        }
+        catch ( Exception e )
+        {
+            LOG.error( "Failed to read a sorted tuple", e );
+        }
+        
+        return null;
+    }
+
+
+    @Override
+    public Tuple<Dn, E> readUnsortedTuple( DataInputStream in )
+    {
+        try
+        {
+            if ( reader == null )
+            {
+                reader = new LdifReader( in );
+            }
+        }
+        catch ( Exception e )
+        {
+            String msg = "Failed to open the LDIF input stream";
+            LOG.error( msg, e );
+
+            throw new RuntimeException( msg, e );
+        }
+
+        Tuple<Dn, E> t = null;
+
+        if ( reader.hasNext() )
+        {
+            LdifEntry ldifEntry = reader.next();
+
+            if ( ldifEntry == null )
+            {
+                throw new IllegalStateException(
+                    "Received null entry while parsing, check the LDIF file for possible incorrect/corrupted entries" );
+            }
+
+            t = new Tuple<Dn, E>();
+
+            t.setKey( ldifEntry.getDn() );
+            t.setValue( ( E ) ( ldifEntry.getOffset() + ":" + ldifEntry.getLengthBeforeParsing() ) );
+        }
+
+        return t;
+    }
+
+
+    @Override
+    public void storeSortedTuple( Tuple<Dn, E> t, DataOutputStream out ) throws IOException
+    {
+        out.writeUTF( t.getKey().getName() );
+        out.writeUTF( ( String ) t.getValue() );
+    }
+
+}
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotCursor.java
similarity index 50%
copy from jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
copy to mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotCursor.java
index be164b2..32910b1 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/KeyTupleBTreeCursor.java
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotCursor.java
@@ -16,76 +16,65 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.directory.server.core.partition.impl.btree.jdbm;
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
 
 
 import java.io.IOException;
-import java.util.Comparator;
 
-import jdbm.btree.BTree;
-import jdbm.helper.TupleBrowser;
-
-import org.apache.directory.api.ldap.model.constants.Loggers;
 import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
 import org.apache.directory.api.ldap.model.cursor.CursorException;
 import org.apache.directory.api.ldap.model.cursor.InvalidCursorPositionException;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.mavibot.btree.TupleCursor;
+import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
 import org.apache.directory.server.i18n.I18n;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 
 /**
- * Cursor over a set of values for the same key which are store in another
- * BTree.  This Cursor is limited to the same key and it's tuples will always
- * return the same key.
+ * Cursor over the Tuples of a Mavibot BTree. If the BTree allows duplicate values,
+ * we will browse each value and return a Tuple for each one of them.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
+class MavibotCursor<K, V> extends AbstractCursor<Tuple<K, V>>
 {
     /** A dedicated log for cursors */
-    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( Loggers.CURSOR_LOG.getName() );
-
-    /** Speedup for logs */
-    private static final boolean IS_DEBUG = LOG_CURSOR.isDebugEnabled();
+    private static final Logger LOG_CURSOR = LoggerFactory.getLogger( "CURSOR" );
 
-    private final Comparator<V> comparator;
-    private final BTree btree;
-    private final K key;
+    /** The table we are building a cursor over */
+    private final MavibotTable<K, V> table;
 
-    private jdbm.helper.Tuple<K, V> valueTuple = new jdbm.helper.Tuple<K, V>();
+    /** The tuple which will be returned */
     private Tuple<K, V> returnedTuple = new Tuple<K, V>();
-    private TupleBrowser<K, V> browser;
-    private boolean valueAvailable;
+
+    /** A flag set when there is a Tuple available */
+    private boolean valueAvailable = false;
+
+    /** The Tuple browser */
+    private TupleCursor<K, V> browser;
 
 
     /**
-     * Creates a Cursor over the tuples of a JDBM BTree.
+     * Creates a Cursor over the tuples of a Mavibot table.
      *
-     * @param btree the JDBM BTree to build a Cursor over
-     * @param key the constant key for which values are returned
-     * @param comparator the Comparator used to determine <b>key</b> ordering
-     * @throws Exception of there are problems accessing the BTree
+     * @param table the JDBM Table to build a Cursor over
      */
-    public KeyTupleBTreeCursor( BTree btree, K key, Comparator<V> comparator ) throws Exception
+    MavibotCursor( MavibotTable<K, V> table )
     {
-        if ( IS_DEBUG )
-        {
-            LOG_CURSOR.debug( "Creating KeyTupleBTreeCursor {}", this );
-        }
-
-        this.key = key;
-        this.btree = btree;
-        this.comparator = comparator;
-        this.browser = btree.browse();
+        LOG_CURSOR.debug( "Creating MavibotCursor {}", this );
+        this.table = table;
     }
 
 
+    /**
+     * Cleanup the returned tuple before reusing it.
+     */
     private void clearValue()
     {
-        returnedTuple.setKey( key );
+        returnedTuple.setKey( null );
         returnedTuple.setValue( null );
         valueAvailable = false;
     }
@@ -100,83 +89,58 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     }
 
 
-    public void beforeKey( K key ) throws Exception
-    {
-        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
-    }
-
-
     /**
-     * {@inheritDoc}
+     * Sets the position before a given key
+     * @param key The key we want to start with
+     * @throws LdapException 
+     * @throws CursorException
      */
-    public void afterKey( K key ) throws Exception
+    public void beforeKey( K key ) throws LdapException, CursorException
     {
-        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
-    }
+        checkNotClosed( "beforeKey()" );
+        closeBrowser( browser );
 
-
-    /**
-     * {@inheritDoc}
-     */
-    public void beforeValue( K key, V value ) throws Exception
-    {
-        checkNotClosed( "beforeValue()" );
-        if ( key != null && !key.equals( this.key ) )
+        try
+        {
+            browser = table.getBTree().browseFrom( key );
+        }
+        catch ( IOException e )
         {
-            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+            throw new CursorException( e );
         }
 
-        browser = btree.browse( value );
         clearValue();
     }
 
 
     /**
-     * {@inheritDoc}
+     * Sets the position before a given key
+     * @param key The key we want to start with
+     * @throws LdapException 
+     * @throws CursorException
      */
-    @SuppressWarnings("unchecked")
-    public void afterValue( K key, V value ) throws LdapException, CursorException
+    public void afterKey( K key ) throws LdapException, CursorException
     {
-        if ( key != null && !key.equals( this.key ) )
-        {
-            throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
-        }
+        checkNotClosed( "afterKey()" );
 
+        closeBrowser( browser );
         try
         {
-            browser = btree.browse( value );
-
-            /*
-             * While the next value is less than or equal to the element keep
-             * advancing forward to the next item.  If we cannot advance any
-             * further then stop and return.  If we find a value greater than
-             * the element then we stop, backup, and return so subsequent calls
-             * to getNext() will return a value greater than the element.
-             */
-            while ( browser.getNext( valueTuple ) )
-            {
-                checkNotClosed( "afterValue" );
+            browser = table.getBTree().browseFrom( key );
 
-                V next = ( V ) valueTuple.getKey();
-
-                int nextCompared = comparator.compare( next, value );
-
-                if ( nextCompared > 0 )
+            if ( table.isDupsEnabled() )
+            {
+                browser.nextKey();
+            }
+            else
+            {
+                if ( browser.hasNextKey() )
                 {
-                    /*
-                     * If we just have values greater than the element argument
-                     * then we are before the first element and cannot backup, and
-                     * the call below to getPrevious() will fail.  In this special
-                     * case we just reset the Cursor's browser and return.
-                     */
-                    if ( !browser.getPrevious( valueTuple ) )
-                    {
-                        browser = btree.browse( this.key );
-                    }
-
-                    clearValue();
-
-                    return;
+                    browser.nextKey();
+                }
+                else
+                {
+                    browser.afterLast();
                 }
             }
 
@@ -184,31 +148,44 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
         }
         catch ( IOException e )
         {
+            clearValue();
             throw new CursorException( e );
         }
     }
 
 
     /**
-     * Positions this Cursor over the same keys before the value of the
-     * supplied valueTuple.  The supplied element Tuple's key is not considered at
-     * all.
-     *
-     * @param element the valueTuple who's value is used to position this Cursor
-     * @throws Exception if there are failures to position the Cursor
+     * Sets the position before a given key and a given value for this key
+     * @param key The key we want to start with
+     * @param value The value we want to start with
+     * @throws LdapException 
+     * @throws CursorException
+     */
+    public void beforeValue( K key, V value ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
+    }
+
+
+    /**
+     * Sets the position after a given key and a given value for this key
+     * @param key The key we want to start with
+     * @param value The value we want to start with
+     * @throws LdapException 
+     * @throws CursorException
+     */
+    public void afterValue( K key, V value ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_596 ) );
+    }
+
+
+    /**
+     * {@inheritDoc}
      */
     public void before( Tuple<K, V> element ) throws LdapException, CursorException
     {
-        checkNotClosed( "before()" );
-        try
-        {
-            browser = btree.browse( element.getValue() );
-            clearValue();
-        }
-        catch ( IOException e )
-        {
-            throw new CursorException( e );
-        }
+        beforeKey( element.getKey() );
     }
 
 
@@ -217,7 +194,7 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
      */
     public void after( Tuple<K, V> element ) throws LdapException, CursorException
     {
-        afterValue( key, element.getValue() );
+        afterKey( element.getKey() );
     }
 
 
@@ -227,15 +204,25 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     public void beforeFirst() throws LdapException, CursorException
     {
         checkNotClosed( "beforeFirst()" );
+
         try
         {
-            browser = btree.browse();
+            if ( browser == null )
+            {
+                browser = table.getBTree().browse();
+            }
+
+            browser.beforeFirst();
             clearValue();
         }
         catch ( IOException e )
         {
             throw new CursorException( e );
         }
+        catch ( KeyNotFoundException knfe )
+        {
+            throw new CursorException( knfe );
+        }
     }
 
 
@@ -245,14 +232,25 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     public void afterLast() throws LdapException, CursorException
     {
         checkNotClosed( "afterLast()" );
+
         try
         {
-            browser = btree.browse( null );
+            if ( browser == null )
+            {
+                browser = table.getBTree().browse();
+            }
+
+            browser.afterLast();
+            clearValue();
         }
         catch ( IOException e )
         {
             throw new CursorException( e );
         }
+        catch ( KeyNotFoundException knfe )
+        {
+            throw new CursorException( knfe );
+        }
     }
 
 
@@ -273,7 +271,6 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     public boolean last() throws LdapException, CursorException
     {
         afterLast();
-
         return previous();
     }
 
@@ -281,31 +278,28 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /**
      * {@inheritDoc}
      */
-    @SuppressWarnings("unchecked")
     public boolean previous() throws LdapException, CursorException
     {
         checkNotClosed( "previous()" );
+        if ( browser == null )
+        {
+            afterLast();
+        }
 
         try
         {
-            if ( browser.getPrevious( valueTuple ) )
+            if ( browser.hasPrev() )
             {
-                // work around to fix direction change problem with jdbm browser
-                if ( ( returnedTuple.getValue() != null )
-                    && ( comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 ) )
-                {
-                    browser.getPrevious( valueTuple );
-                }
-                returnedTuple.setKey( key );
-                returnedTuple.setValue( ( V ) valueTuple.getKey() );
+                org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.prev();
 
+                returnedTuple.setKey( tuple.getKey() );
+                returnedTuple.setValue( tuple.getValue() );
                 valueAvailable = true;
                 return true;
             }
             else
             {
                 clearValue();
-
                 return false;
             }
         }
@@ -319,32 +313,29 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     /**
      * {@inheritDoc}
      */
-    @SuppressWarnings("unchecked")
     public boolean next() throws LdapException, CursorException
     {
-        checkNotClosed( "next()" );
+        checkNotClosed( "previous()" );
+
+        if ( browser == null )
+        {
+            beforeFirst();
+        }
 
         try
         {
-            if ( browser.getNext( valueTuple ) )
+            if ( browser.hasNext() )
             {
-                // work around to fix direction change problem with jdbm browser
-                if ( returnedTuple.getValue() != null
-                    && comparator.compare( ( V ) valueTuple.getKey(), returnedTuple.getValue() ) == 0 )
-                {
-                    browser.getNext( valueTuple );
-                }
-
-                returnedTuple.setKey( key );
-                returnedTuple.setValue( ( V ) valueTuple.getKey() );
+                org.apache.directory.mavibot.btree.Tuple<K, V> tuple = browser.next();
 
+                returnedTuple.setKey( tuple.getKey() );
+                returnedTuple.setValue( tuple.getValue() );
                 valueAvailable = true;
                 return true;
             }
             else
             {
                 clearValue();
-
                 return false;
             }
         }
@@ -361,7 +352,6 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     public Tuple<K, V> get() throws CursorException
     {
         checkNotClosed( "get()" );
-
         if ( valueAvailable )
         {
             return returnedTuple;
@@ -377,12 +367,9 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     @Override
     public void close() throws IOException
     {
-        if ( IS_DEBUG )
-        {
-            LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
-        }
-
+        LOG_CURSOR.debug( "Closing MavibotCursor {}", this );
         super.close();
+        closeBrowser( browser );
     }
 
 
@@ -392,11 +379,20 @@ public class KeyTupleBTreeCursor<K, V> extends AbstractCursor<Tuple<K, V>>
     @Override
     public void close( Exception cause ) throws IOException
     {
-        if ( IS_DEBUG )
+        LOG_CURSOR.debug( "Closing MavibotCursor {}", this );
+        super.close( cause );
+        closeBrowser( browser );
+    }
+
+
+    /**
+     * Close the browser
+     */
+    private void closeBrowser( TupleCursor<K, V> browser )
+    {
+        if ( browser != null )
         {
-            LOG_CURSOR.debug( "Closing KeyTupleBTreeCursor {}", this );
+            browser.close();
         }
-
-        super.close( cause );
     }
 }
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotDnIndex.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotDnIndex.java
new file mode 100644
index 0000000..49be1b5
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotDnIndex.java
@@ -0,0 +1,123 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.ldap.model.schema.comparators.UuidComparator;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.server.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A special index which stores DN objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotDnIndex extends MavibotIndex<Dn>
+{
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotDnIndex.class );
+
+
+    public MavibotDnIndex( String oid )
+    {
+        super( oid, true );
+        initialized = false;
+    }
+
+
+    public void init( SchemaManager schemaManager, AttributeType attributeType ) throws IOException
+    {
+        LOG.debug( "Initializing an Index for attribute '{}'", attributeType.getName() );
+
+        this.attributeType = attributeType;
+
+        if ( attributeId == null )
+        {
+            setAttributeId( attributeType.getName() );
+        }
+
+        if ( this.wkDirPath == null )
+        {
+            NullPointerException e = new NullPointerException( "The index working directory has not be set" );
+            throw e;
+        }
+
+        try
+        {
+            initTables( schemaManager );
+        }
+        catch ( IOException e )
+        {
+            // clean up
+            close();
+            throw e;
+        }
+
+        initialized = true;
+    }
+
+
+    private void initTables( SchemaManager schemaManager ) throws IOException
+    {
+        MatchingRule mr = attributeType.getEquality();
+
+        if ( mr == null )
+        {
+            throw new IOException( I18n.err( I18n.ERR_574, attributeType.getName() ) );
+        }
+
+        /*
+         * The forward key/value map stores attribute values to master table
+         * primary keys.  A value for an attribute can occur several times in
+         * different entries so the forward map can have more than one value.
+         */
+        UuidComparator.INSTANCE.setSchemaManager( schemaManager );
+
+        DnSerializer dnSerializer = new DnSerializer();
+
+        String forwardTableName = attributeType.getOid() + FORWARD_BTREE;
+        forward = new MavibotTable<Dn, String>( recordMan, schemaManager, forwardTableName, dnSerializer,
+            StringSerializer.INSTANCE, true );
+
+        String reverseTableName = attributeType.getOid() + REVERSE_BTREE;
+        reverse = new MavibotTable<String, Dn>( recordMan, schemaManager, reverseTableName, StringSerializer.INSTANCE,
+            dnSerializer, !attributeType.isSingleValued() );
+
+        String path = new File( this.wkDirPath, attributeType.getOid() ).getAbsolutePath();
+        // finally write a text file in the format <OID>-<attribute-name>.txt
+        FileWriter fw = new FileWriter( new File( path + "-" + attributeType.getName() + ".txt" ) );
+        // write the AttributeType description
+        fw.write( attributeType.toString() );
+        fw.close();
+    }
+
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotEntrySerializer.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotEntrySerializer.java
new file mode 100644
index 0000000..96fdf00
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotEntrySerializer.java
@@ -0,0 +1,382 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.DefaultAttribute;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.mavibot.btree.serializer.AbstractElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.BufferHandler;
+import org.apache.directory.server.i18n.I18n;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Serialize and deserialize a ServerEntry. There is a big difference with the standard
+ * Entry serialization : we don't serialize the entry's Dn, we just serialize it's Rdn.
+ * </br></br>
+ * <b>This class must *not* be used outside of the server.</b>
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotEntrySerializer extends AbstractElementSerializer<Entry>
+{
+    /** The serialVersionUID */
+    private static final long serialVersionUID = 1L;
+
+    /** the logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotEntrySerializer.class );
+
+    /**
+     * Speedup for logs
+     */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The schemaManager reference */
+    private static SchemaManager schemaManager;
+
+    private static class EntryComparator implements Comparator<Entry>
+    {
+
+        @Override
+        public int compare( Entry entry1, Entry entry2 )
+        {
+            return entry1.getDn().getName().compareTo( entry1.getDn().getName() );
+        }
+
+    }
+
+    private static Comparator<Entry> comparator = new EntryComparator();
+
+
+    /**
+     * Creates a new instance of ServerEntrySerializer.
+     * The schemaManager MUST be set explicitly using the static {@link #setSchemaManager(SchemaManager)}
+     */
+    public MavibotEntrySerializer()
+    {
+        super( comparator );
+    }
+
+
+    @Override
+    public Comparator<Entry> getComparator()
+    {
+        return comparator;
+    }
+
+
+    /**
+     * <p>
+     * 
+     * This is the place where we serialize entries, and all theirs
+     * elements. the reason why we don't call the underlying methods
+     * (<code>ServerAttribute.write(), Value.write()</code>) is that we need
+     * access to the registries to read back the values.
+     * <p>
+     * The structure used to store the entry is the following :
+     * <ul>
+     *   <li><b>[a byte]</b> : if the Dn is empty 0 will be written else 1</li>
+     *   <li><b>[Rdn]</b> : The entry's Rdn.</li>
+     *   <li><b>[numberAttr]</b> : the bumber of attributes. Can be 0</li>
+     *   <li>For each Attribute :
+     *     <ul>
+     *       <li><b>[attribute's oid]</b> : The attribute's OID to get back
+     *       the attributeType on deserialization</li>
+     *       <li><b>[Attribute]</b> The attribute</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     */
+    public byte[] serialize( Entry entry )
+    {
+        try
+        {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+            ObjectOutput out = new ObjectOutputStream( baos );
+
+            // First, the Dn
+            Dn dn = entry.getDn();
+
+            // Write the Rdn of the Dn
+            if ( dn.isEmpty() )
+            {
+                out.writeByte( 0 );
+            }
+            else
+            {
+                out.writeByte( 1 );
+                Rdn rdn = dn.getRdn();
+                rdn.writeExternal( out );
+            }
+
+            // Then the attributes.
+            out.writeInt( entry.getAttributes().size() );
+
+            // Iterate through the keys. We store the Attribute
+            // here, to be able to restore it in the readExternal :
+            // we need access to the registries, which are not available
+            // in the ServerAttribute class.
+            for ( Attribute attribute : entry.getAttributes() )
+            {
+                AttributeType attributeType = attribute.getAttributeType();
+
+                // Write the oid to be able to restore the AttributeType when deserializing
+                // the attribute
+                String oid = attributeType.getOid();
+
+                out.writeUTF( oid );
+
+                // Write the attribute
+                attribute.writeExternal( out );
+            }
+
+            out.flush();
+
+            // Note : we don't store the ObjectClassAttribute. It has already
+            // been stored as an attribute.
+
+            if ( IS_DEBUG )
+            {
+                LOG.debug( ">------------------------------------------------" );
+                LOG.debug( "Serialize " + entry );
+            }
+
+            byte[] bytes = baos.toByteArray();
+
+            return bytes;
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     *  Deserialize a Entry.
+     *  
+     *  @param bytes the byte array containing the serialized entry
+     *  @return An instance of a Entry object 
+     *  @throws IOException if we can't deserialize the Entry
+     */
+    public Entry deserialize( ByteBuffer buffer ) throws IOException
+    {
+        // read the length
+        int len = buffer.limit();
+
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( buffer.array(), buffer.position(), len ) );
+
+        try
+        {
+            Entry entry = new DefaultEntry( schemaManager );
+
+            // Read the Dn, if any
+            byte hasDn = in.readByte();
+
+            if ( hasDn == 1 )
+            {
+                Rdn rdn = new Rdn( schemaManager );
+                rdn.readExternal( in );
+
+                try
+                {
+                    entry.setDn( new Dn( schemaManager, rdn ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    IOException ioe = new IOException( lide.getMessage() );
+                    ioe.initCause( lide );
+                    throw ioe;
+                }
+            }
+            else
+            {
+                entry.setDn( Dn.EMPTY_DN );
+            }
+
+            // Read the number of attributes
+            int nbAttributes = in.readInt();
+
+            // Read the attributes
+            for ( int i = 0; i < nbAttributes; i++ )
+            {
+                // Read the attribute's OID
+                String oid = in.readUTF();
+
+                try
+                {
+                    AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+
+                    // Create the attribute we will read
+                    Attribute attribute = new DefaultAttribute( attributeType );
+
+                    // Read the attribute
+                    attribute.readExternal( in );
+
+                    entry.add( attribute );
+                }
+                catch ( LdapException ne )
+                {
+                    // We weren't able to find the OID. The attribute will not be added
+                    throw new ClassNotFoundException( ne.getMessage(), ne );
+                }
+            }
+
+            buffer.position( buffer.position() + len ); // previous position + length
+
+            return entry;
+        }
+        catch ( ClassNotFoundException cnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) );
+            throw new IOException( cnfe.getLocalizedMessage() );
+        }
+    }
+
+
+    @Override
+    public Entry deserialize( BufferHandler bufferHandler ) throws IOException
+    {
+        return deserialize( ByteBuffer.wrap( bufferHandler.getBuffer() ) );
+    }
+
+
+    public static void setSchemaManager( SchemaManager schemaManager )
+    {
+        MavibotEntrySerializer.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry fromBytes( byte[] buffer ) throws IOException
+    {
+        return fromBytes( buffer, 0 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Entry fromBytes( byte[] buffer, int pos ) throws IOException
+    {
+        // read the length
+        int len = buffer.length - pos;
+
+        ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( buffer, pos, len ) );
+
+        try
+        {
+            Entry entry = new DefaultEntry( schemaManager );
+
+            // Read the Dn, if any
+            byte hasDn = in.readByte();
+
+            if ( hasDn == 1 )
+            {
+                Rdn rdn = new Rdn( schemaManager );
+                rdn.readExternal( in );
+
+                try
+                {
+                    entry.setDn( new Dn( schemaManager, rdn ) );
+                }
+                catch ( LdapInvalidDnException lide )
+                {
+                    IOException ioe = new IOException( lide.getMessage() );
+                    ioe.initCause( lide );
+                    throw ioe;
+                }
+            }
+            else
+            {
+                entry.setDn( Dn.EMPTY_DN );
+            }
+
+            // Read the number of attributes
+            int nbAttributes = in.readInt();
+
+            // Read the attributes
+            for ( int i = 0; i < nbAttributes; i++ )
+            {
+                // Read the attribute's OID
+                String oid = in.readUTF();
+
+                try
+                {
+                    AttributeType attributeType = schemaManager.lookupAttributeTypeRegistry( oid );
+
+                    // Create the attribute we will read
+                    Attribute attribute = new DefaultAttribute( attributeType );
+
+                    // Read the attribute
+                    attribute.readExternal( in );
+
+                    entry.add( attribute );
+                }
+                catch ( LdapException ne )
+                {
+                    // We weren't able to find the OID. The attribute will not be added
+                    throw new ClassNotFoundException( ne.getMessage(), ne );
+                }
+            }
+
+            return entry;
+        }
+        catch ( ClassNotFoundException cnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) );
+            throw new IOException( cnfe.getLocalizedMessage() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?> getType()
+    {
+        return Entry.class;
+    }
+}
diff --git a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotIndex.java
similarity index 65%
copy from jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
copy to mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotIndex.java
index 90f84e4..e295bad 100644
--- a/jdbm-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/jdbm/JdbmIndex.java
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotIndex.java
@@ -6,32 +6,27 @@
  *  to you under the Apache License, Version 2.0 (the
  *  "License"); you may not use this file except in compliance
  *  with the License.  You may obtain a copy of the License at
- * 
+ *
  *    http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  *  Unless required by applicable law or agreed to in writing,
  *  software distributed under the License is distributed on an
  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  *  KIND, either express or implied.  See the License for the
  *  specific language governing permissions and limitations
  *  under the License.
- * 
+ *
  */
-package org.apache.directory.server.core.partition.impl.btree.jdbm;
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
 
 
 import java.io.File;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.net.URI;
+import java.util.Comparator;
 
-import jdbm.RecordManager;
-import jdbm.helper.ByteArraySerializer;
-import jdbm.helper.MRU;
-import jdbm.recman.BaseRecordManager;
-import jdbm.recman.CacheRecordManager;
-import jdbm.recman.TransactionManager;
-
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
 import org.apache.directory.api.ldap.model.cursor.Cursor;
 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
@@ -40,7 +35,11 @@ import org.apache.directory.api.ldap.model.schema.AttributeType;
 import org.apache.directory.api.ldap.model.schema.MatchingRule;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
 import org.apache.directory.api.ldap.model.schema.comparators.SerializableComparator;
-import org.apache.directory.api.ldap.model.schema.comparators.UuidComparator;
+import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.mavibot.btree.serializer.ByteArraySerializer;
+import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
 import org.apache.directory.server.core.partition.impl.btree.IndexCursorAdaptor;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.directory.server.xdbm.AbstractIndex;
@@ -51,18 +50,16 @@ import org.slf4j.LoggerFactory;
 
 
 /**
- * A Jdbm based index implementation. It creates an Index for a give AttributeType.
+ * A Mavibot based index implementation. It creates an Index for a give AttributeType.
  *
  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
  */
-public class JdbmIndex<K> extends AbstractIndex<K, String>
+public class MavibotIndex<K> extends AbstractIndex<K, String>
 {
     /** A logger for this class */
-    private static final Logger LOG = LoggerFactory.getLogger( JdbmIndex.class );
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotIndex.class.getSimpleName() );
 
-    /**
-     * default duplicate limit before duplicate keys switch to using a btree for values
-     */
+    /** default duplicate limit before duplicate keys switch to using a btree for values */
     public static final int DEFAULT_DUPLICATE_LIMIT = 512;
 
     /**  the key used for the forward btree name */
@@ -76,46 +73,21 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
      * the value of the btree is the entry id of the entry containing an attribute with
      * that value
      */
-    protected JdbmTable<K, String> forward;
+    protected MavibotTable<K, String> forward;
 
     /**
      * the reverse btree where the btree key is the entry id of the entry containing a
      * value for the indexed attribute, and the btree value is the value of the indexed
      * attribute
      */
-    protected JdbmTable<String, K> reverse;
-
-    /**
-     * the JDBM record manager for the file containing this index
-     */
-    protected RecordManager recMan;
-
-    /**
-     * duplicate limit before duplicate keys switch to using a btree for values
-     */
-    protected int numDupLimit = DEFAULT_DUPLICATE_LIMIT;
+    protected MavibotTable<String, K> reverse;
 
     /** a custom working directory path when specified in configuration */
     protected File wkDirPath;
 
+    /** The recordManager */
+    protected RecordManager recordMan;
 
-    /*
-     * NOTE: Duplicate Key Limit
-     *
-     * Jdbm cannot store duplicate keys: meaning it cannot have more than one value
-     * for the same key in the btree.  Thus as a workaround we stuff values for the
-     * same key into a TreeSet.  This is only effective up to some threshold after
-     * which we run into problems with serialization on and off disk.  A threshold
-     * is used to determine when to switch from using a TreeSet to start using another
-     * btree in the same index file just for the values.  This value only btree just
-     * has keys populated without a value for it's btree entries. When the switch
-     * occurs the value for the key in the index btree contains a pointer to the
-     * btree containing it's values.
-     *
-     * This numDupLimit is the threshold at which we switch from using in memory
-     * containers for values of the same key to using a btree for those values
-     * instead with indirection.
-     */
 
     // ------------------------------------------------------------------------
     // C O N S T R U C T O R S
@@ -123,7 +95,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     /**
      * Creates a JdbmIndex instance for a give AttributeId
      */
-    public JdbmIndex( String attributeId, boolean withReverse )
+    public MavibotIndex( String attributeId, boolean withReverse )
     {
         super( attributeId, withReverse );
 
@@ -133,7 +105,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
 
     /**
      * Initialize the index for an Attribute, with a specific working directory (may be null).
-     * 
+     *
      * @param schemaManager The schemaManager to use to get back the Attribute
      * @param attributeType The attributeType this index is created for
      * @throws IOException If the initialization failed
@@ -142,6 +114,12 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     {
         LOG.debug( "Initializing an Index for attribute '{}'", attributeType.getName() );
 
+        // check if the RecordManager reference is null, if yes, then throw an IllegalStateException
+        if ( recordMan == null )
+        {
+            throw new IllegalStateException( "No RecordManager reference was set in the index " + getAttributeId() );
+        }
+
         this.attributeType = attributeType;
 
         if ( attributeId == null )
@@ -151,28 +129,9 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
 
         if ( this.wkDirPath == null )
         {
-            NullPointerException e = new NullPointerException( "The index working directory has not be set" );
-
-            throw e;
+            throw new NullPointerException( "The index working directory has not be set" );
         }
 
-        String path = new File( this.wkDirPath, attributeType.getOid() ).getAbsolutePath();
-
-        BaseRecordManager base = new BaseRecordManager( path );
-        TransactionManager transactionManager = base.getTransactionManager();
-        transactionManager.setMaximumTransactionsInLog( 2000 );
-
-        // see DIRSERVER-2002
-        // prevent the OOM when more than 50k users are loaded at a stretch
-        // adding this system property to make it configurable till JDBM gets replaced by Mavibot
-        String cacheSizeVal = System.getProperty( "jdbm.recman.cache.size", "100" );
-        
-        int recCacheSize = Integer.parseInt( cacheSizeVal );
-        
-        LOG.info( "Setting CacheRecondManager's cache size to {}", recCacheSize );
-
-        recMan = new CacheRecordManager( base, new MRU( recCacheSize ) );
-
         try
         {
             initTables( schemaManager );
@@ -184,27 +143,19 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
             throw e;
         }
 
-        // finally write a text file in the format <OID>-<attribute-name>.txt
-        FileWriter fw = new FileWriter( new File( path + "-" + attributeType.getName() + ".txt" ) );
-        // write the AttributeType description
-        fw.write( attributeType.toString() );
-        fw.close();
-
         initialized = true;
     }
 
 
     /**
      * Initializes the forward and reverse tables used by this Index.
-     * 
+     *
      * @param schemaManager The server schemaManager
      * @throws IOException if we cannot initialize the forward and reverse
      * tables
      */
     private void initTables( SchemaManager schemaManager ) throws IOException
     {
-        SerializableComparator<K> comp;
-
         MatchingRule mr = attributeType.getEquality();
 
         if ( mr == null )
@@ -212,29 +163,39 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
             throw new IOException( I18n.err( I18n.ERR_574, attributeType.getName() ) );
         }
 
-        comp = new SerializableComparator<K>( mr.getOid() );
+        SerializableComparator<K> comp = new SerializableComparator<>( mr.getOid() );
+        comp.setSchemaManager( schemaManager );
 
         /*
          * The forward key/value map stores attribute values to master table
          * primary keys.  A value for an attribute can occur several times in
          * different entries so the forward map can have more than one value.
          */
-        UuidComparator.INSTANCE.setSchemaManager( schemaManager );
-        comp.setSchemaManager( schemaManager );
 
-        if ( mr.getSyntax().isHumanReadable() )
+        ElementSerializer<K> forwardKeySerializer = null;
+
+        if ( !attributeType.getSyntax().isHumanReadable() )
         {
-            forward = new JdbmTable<K, String>( schemaManager, attributeType.getOid() + FORWARD_BTREE, numDupLimit,
-                recMan,
-                comp, UuidComparator.INSTANCE, StringSerializer.INSTANCE, UuidSerializer.INSTANCE );
+            forwardKeySerializer = ( ElementSerializer<K> ) new ByteArraySerializer( ( Comparator<byte[]> ) comp );
         }
         else
         {
-            forward = new JdbmTable<K, String>( schemaManager, attributeType.getOid() + FORWARD_BTREE, numDupLimit,
-                recMan,
-                comp, UuidComparator.INSTANCE, new ByteArraySerializer(), UuidSerializer.INSTANCE );
+            forwardKeySerializer = ( ElementSerializer<K> ) new StringSerializer( ( Comparator<String> ) comp );
+        }
+
+        boolean forwardDups = true;
+
+        String oid = attributeType.getOid();
+        // disable duplicates for entryCSN and entryUUID attribute indices
+        if ( oid.equals( SchemaConstants.ENTRY_CSN_AT_OID ) || oid.equals( SchemaConstants.ENTRY_UUID_AT_OID ) )
+        {
+            forwardDups = false;
         }
 
+        String forwardTableName = attributeType.getOid() + FORWARD_BTREE;
+        forward = new MavibotTable<>( recordMan, schemaManager, forwardTableName, forwardKeySerializer,
+            StringSerializer.INSTANCE, forwardDups, AbstractBTreePartition.DEFAULT_CACHE_SIZE );
+
         /*
          * Now the reverse map stores the primary key into the master table as
          * the key and the values of attributes as the value.  If an attribute
@@ -243,49 +204,37 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
          */
         if ( withReverse )
         {
-            if ( attributeType.isSingleValued() )
-            {
-                reverse = new JdbmTable<String, K>( schemaManager, attributeType.getOid() + REVERSE_BTREE, recMan,
-                    UuidComparator.INSTANCE, UuidSerializer.INSTANCE, null );
-            }
-            else
-            {
-                reverse = new JdbmTable<String, K>( schemaManager, attributeType.getOid() + REVERSE_BTREE, numDupLimit,
-                    recMan,
-                    UuidComparator.INSTANCE, comp, UuidSerializer.INSTANCE, null );
-            }
+            String reverseTableName = attributeType.getOid() + REVERSE_BTREE;
+            reverse = new MavibotTable<>( recordMan, schemaManager, reverseTableName, StringSerializer.INSTANCE,
+                forwardKeySerializer, !attributeType.isSingleValued() );
         }
-    }
-
 
-    // ------------------------------------------------------------------------
-    // C O N F I G U R A T I O N   M E T H O D S
-    // ------------------------------------------------------------------------
-    /**
-     * Gets the threshold at which point duplicate keys use btree indirection to store
-     * their values.
-     *
-     * @return the threshold for storing a keys values in another btree
-     */
-    public int getNumDupLimit()
-    {
-        return numDupLimit;
+        String path = new File( this.wkDirPath, attributeType.getOid() ).getAbsolutePath();
+        
+        // finally write a text file in the format <OID>-<attribute-name>.txt
+        try ( FileWriter fw = new FileWriter( new File( path + "-" + attributeType.getName() + ".txt" ) ) )
+        {
+            // write the AttributeType description
+            fw.write( attributeType.toString() );
+        } 
     }
 
 
     /**
-     * Sets the threshold at which point duplicate keys use btree indirection to store
-     * their values.
+     * Sets the RecordManager
      *
-     * @param numDupLimit the threshold for storing a keys values in another btree
+     * @param rm the RecordManager instance
      */
-    public void setNumDupLimit( int numDupLimit )
+    public void setRecordManager( RecordManager rm )
     {
-        protect( "numDupLimit" );
-        this.numDupLimit = numDupLimit;
+        this.recordMan = rm;
     }
 
 
+    // ------------------------------------------------------------------------
+    // C O N F I G U R A T I O N   M E T H O D S
+    // ------------------------------------------------------------------------
+
     /**
      * Sets the working directory path to something other than the default. Sometimes more
      * performance is gained by locating indices on separate disk spindles.
@@ -294,7 +243,6 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
      */
     public void setWkDirPath( URI wkDirPath )
     {
-        //.out.println( "IDX Defining a WorkingDir : " + wkDirPath );
         protect( "wkDirPath" );
         this.wkDirPath = new File( wkDirPath );
     }
@@ -386,7 +334,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
      */
     public synchronized void add( K attrVal, String id ) throws Exception
     {
-        // The pair to be added must exists
+        // The pair to be removed must exists
         forward.put( attrVal, id );
 
         if ( withReverse )
@@ -456,11 +404,11 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     {
         if ( withReverse )
         {
-            return new IndexCursorAdaptor<K>( ( Cursor ) reverse.cursor(), false );
+            return new IndexCursorAdaptor<>( ( Cursor ) reverse.cursor(), false );
         }
         else
         {
-            return new EmptyIndexCursor<K>();
+            return new EmptyIndexCursor<>();
         }
     }
 
@@ -477,11 +425,11 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     {
         if ( withReverse )
         {
-            return new IndexCursorAdaptor<K>( ( Cursor ) reverse.cursor( id ), false );
+            return new IndexCursorAdaptor<>( ( Cursor ) reverse.cursor( id ), false );
         }
         else
         {
-            return new EmptyIndexCursor<K>();
+            return new EmptyIndexCursor<>();
         }
     }
 
@@ -489,7 +437,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     @SuppressWarnings("unchecked")
     public Cursor<IndexEntry<K, String>> forwardCursor( K key ) throws Exception
     {
-        return new IndexCursorAdaptor<K>( ( Cursor ) forward.cursor( key ), true );
+        return new IndexCursorAdaptor<>( ( Cursor ) forward.cursor( key ), true );
     }
 
 
@@ -501,7 +449,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
         }
         else
         {
-            return new EmptyCursor<K>();
+            return new EmptyCursor<>();
         }
     }
 
@@ -536,7 +484,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     /**
      * {@inheritDoc}
      */
-    public boolean reverse( String id ) throws Exception
+    public boolean reverse( String id ) throws LdapException
     {
         if ( withReverse )
         {
@@ -552,7 +500,7 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
     /**
      * {@inheritDoc}
      */
-    public boolean reverse( String id, K attrVal ) throws Exception
+    public boolean reverse( String id, K attrVal ) throws LdapException
     {
         return forward.has( attrVal, id );
     }
@@ -566,18 +514,22 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
      */
     public synchronized void close() throws IOException
     {
-        if ( forward != null )
+        try
         {
-            forward.close();
-        }
+            if ( forward != null )
+            {
+                forward.close();
+            }
 
-        if ( reverse != null )
+            if ( reverse != null )
+            {
+                reverse.close();
+            }
+        }
+        catch ( Exception e )
         {
-            reverse.close();
+            throw new IOException( e );
         }
-
-        commit( recMan );
-        recMan.close();
     }
 
 
@@ -586,31 +538,14 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
      */
     public synchronized void sync() throws IOException
     {
-        // Commit
-        recMan.commit();
-
-        // And flush the journal
-        if ( ( commitNumber.get() % 4000 ) == 0 )
-        {
-            BaseRecordManager baseRecordManager = null;
-
-            if ( recMan instanceof CacheRecordManager )
-            {
-                baseRecordManager = ( ( BaseRecordManager ) ( ( CacheRecordManager ) recMan ).getRecordManager() );
-            }
-            else
-            {
-                baseRecordManager = ( ( BaseRecordManager ) recMan );
-            }
-
-            baseRecordManager.getTransactionManager().synchronizeLog();
-        }
+        // Nothing to do
     }
 
 
     /**
      * {@inheritDoc}
      */
+    @Override
     public boolean isDupsEnabled()
     {
         if ( withReverse )
@@ -625,20 +560,6 @@ public class JdbmIndex<K> extends AbstractIndex<K, String>
 
 
     /**
-     * Commit the modification on disk
-     * 
-     * @param recordManager The recordManager used for the commit
-     */
-    private void commit( RecordManager recordManager ) throws IOException
-    {
-        if ( commitNumber.incrementAndGet() % 2000 == 0 )
-        {
-            sync();
-        }
-    }
-
-
-    /**
      * @see Object#toString()
      */
     public String toString()
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotMasterTable.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotMasterTable.java
new file mode 100644
index 0000000..67bfb61
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotMasterTable.java
@@ -0,0 +1,58 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.IOException;
+import java.util.UUID;
+
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.server.xdbm.MasterTable;
+
+
+/**
+ * TODO MavibotMasterTable.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotMasterTable extends MavibotTable<String, Entry> implements MasterTable
+{
+    public MavibotMasterTable( RecordManager recordMan, SchemaManager schemaManager, String name, int cacheSize )
+        throws IOException
+    {
+        super( recordMan, schemaManager, name, StringSerializer.INSTANCE, new MavibotEntrySerializer(), false, cacheSize );
+    }
+
+    public MavibotMasterTable( RecordManager recordMan, SchemaManager schemaManager, String name )
+        throws IOException
+    {
+        super( recordMan, schemaManager, name, StringSerializer.INSTANCE, new MavibotEntrySerializer(), false );
+    }
+
+
+    @Override
+    public String getNextId( Entry entry ) throws Exception
+    {
+        return UUID.randomUUID().toString();
+    }
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotParentIdAndRdnSerializer.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotParentIdAndRdnSerializer.java
new file mode 100644
index 0000000..dd18529
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotParentIdAndRdnSerializer.java
@@ -0,0 +1,302 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *  
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License. 
+ *  
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Comparator;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.name.Rdn;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.Serialize;
+import org.apache.directory.mavibot.btree.serializer.AbstractElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.BufferHandler;
+import org.apache.directory.mavibot.btree.util.Strings;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.xdbm.ParentIdAndRdn;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Serialize and deserialize a ParentidAndRdn.
+ * </br></br>
+ * <b>This class must *not* be used outside of the server.</b>
+ *  
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotParentIdAndRdnSerializer extends AbstractElementSerializer<ParentIdAndRdn>
+{
+    /** The serialVersionUID */
+    private static final long serialVersionUID = 1L;
+
+    /** the logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotParentIdAndRdnSerializer.class );
+
+    /**
+     * Speedup for logs
+     */
+    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
+
+    /** The schemaManager reference */
+    private static SchemaManager schemaManager;
+
+    private static Comparator<ParentIdAndRdn> comparator = new Comparator<ParentIdAndRdn>()
+    {
+
+        @Override
+        public int compare( ParentIdAndRdn rdn1, ParentIdAndRdn rdn2 )
+        {
+            return rdn1.compareTo( rdn2 );
+        }
+
+    };
+
+
+    /**
+     * Creates a new instance of ParentIdAndRdnSerializer.
+     * The schemaManager MUST be set explicitly using the static {@link #setSchemaManager(SchemaManager)}
+     */
+    public MavibotParentIdAndRdnSerializer()
+    {
+        super( comparator );
+    }
+
+
+    /**
+     * This is the place where we serialize ParentIdAndRdn. The format is the following :<br/>
+     * <ul>
+     * <li>length</li>
+     * <li>the RDN</li>
+     * <li>the parent ID</li>
+     * <li>Number of children</li>
+     * <li>Number of descendant</li>
+     * <li></li>
+     * <li></li>
+     * <li></li>
+     * </ul>
+     */
+    public byte[] serialize( ParentIdAndRdn parentIdAndRdn )
+    {
+        try
+        {
+            int bufferSize = 1024;
+
+            while ( bufferSize < Integer.MAX_VALUE )
+            {
+                // allocate a big enough buffer for most of the cases
+                byte[] buffer = new byte[bufferSize];
+
+                try
+                {
+                    // The current position.
+                    int pos = 0;
+
+                    // First, the Dn
+                    Rdn[] rdns;
+
+                    try
+                    {
+                        rdns = parentIdAndRdn.getRdns();
+                    }
+                    catch ( NullPointerException npe )
+                    {
+                        throw npe;
+                    }
+
+                    // Write the Rdn of the Dn
+                    // The number of RDN (we may have more than one)
+                    if ( ( rdns == null ) || ( rdns.length == 0 ) )
+                    {
+                        pos = Serialize.serialize( 0, buffer, pos );
+                    }
+                    else
+                    {
+                        pos = Serialize.serialize( rdns.length, buffer, pos );
+
+                        for ( Rdn rdn : rdns )
+                        {
+                            pos = rdn.serialize( buffer, pos );
+                        }
+                    }
+
+                    // Then the parentId.
+                    String parentId = parentIdAndRdn.getParentId();
+                    byte[] parentIdBytes = Strings.getBytesUtf8( parentId );
+                    pos = Serialize.serialize( parentIdBytes, buffer, pos );
+
+                    // The number of children
+                    pos = Serialize.serialize( parentIdAndRdn.getNbChildren(), buffer, pos );
+
+                    // The number of descendants
+                    pos = Serialize.serialize( parentIdAndRdn.getNbDescendants(), buffer, pos );
+
+                    if ( IS_DEBUG )
+                    {
+                        LOG.debug( ">------------------------------------------------" );
+                        LOG.debug( "Serialize " + parentIdAndRdn );
+                    }
+
+
+                    // Copy the serialized data
+                    byte[] result = new byte[pos];
+                    System.arraycopy( buffer, 0, result, 0, pos );
+
+                    return result;
+                }
+                catch ( ArrayIndexOutOfBoundsException aioobe )
+                {
+                    // Bad luck, try with a bigger buffer
+                    bufferSize += bufferSize;
+                }
+            }
+
+            // No reason we should reach this point
+            throw new RuntimeException();
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+
+    /**
+     *  Deserialize a ParentIdAndRdn.
+     *  
+     *  @param bytes the byte array containing the serialized ParentIdAndRdn
+     *  @return An instance of a ParentIdAndRdn object 
+     *  @throws IOException if we can't deserialize the ParentIdAndRdn
+     */
+    public ParentIdAndRdn deserialize( BufferHandler bufferHandler ) throws IOException
+    {
+        return deserialize( ByteBuffer.wrap( bufferHandler.getBuffer() ) );
+    }
+
+
+    @Override
+    public ParentIdAndRdn deserialize( ByteBuffer buffer ) throws IOException
+    {
+        ParentIdAndRdn parentIdAndRdn = fromBytes( buffer.array(), buffer.position() );
+
+        return parentIdAndRdn;
+    }
+
+
+    @Override
+    public int compare( ParentIdAndRdn type1, ParentIdAndRdn type2 )
+    {
+        return type1.compareTo( type2 );
+    }
+
+
+    @Override
+    public Comparator<ParentIdAndRdn> getComparator()
+    {
+        return comparator;
+    }
+
+
+    public static void setSchemaManager( SchemaManager schemaManager )
+    {
+        MavibotParentIdAndRdnSerializer.schemaManager = schemaManager;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ParentIdAndRdn fromBytes( byte[] buffer ) throws IOException
+    {
+        return fromBytes( buffer, 0 );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ParentIdAndRdn fromBytes( byte[] buffer, int pos ) throws IOException
+    {
+        try
+        {
+            ParentIdAndRdn parentIdAndRdn = new ParentIdAndRdn();
+
+            // Read the number of rdns, if any
+            int nbRdns = Serialize.deserializeInt( buffer, pos );
+            pos += 4;
+
+            if ( nbRdns == 0 )
+            {
+                parentIdAndRdn.setRdns( new Rdn[0] );
+            }
+            else
+            {
+                Rdn[] rdns = new Rdn[nbRdns];
+
+                for ( int i = 0; i < nbRdns; i++ )
+                {
+                    Rdn rdn = new Rdn( schemaManager );
+                    pos = rdn.deserialize( buffer, pos );
+                    rdns[i] = rdn;
+                }
+
+                parentIdAndRdn.setRdns( rdns );
+            }
+
+            // Read the parent ID
+            byte[] uuidBytes = Serialize.deserializeBytes( buffer, pos );
+            pos += 4 + uuidBytes.length;
+            String uuid = Strings.utf8ToString( uuidBytes );
+
+            parentIdAndRdn.setParentId( uuid );
+
+            // Read the number of children and descendants
+            int nbChildren = Serialize.deserializeInt( buffer, pos );
+            pos += 4;
+
+            int nbDescendants = Serialize.deserializeInt( buffer, pos );
+            pos += 4;
+
+            parentIdAndRdn.setNbChildren( nbChildren );
+            parentIdAndRdn.setNbDescendants( nbDescendants );
+
+            return parentIdAndRdn;
+        }
+        catch ( LdapInvalidAttributeValueException cnfe )
+        {
+            LOG.error( I18n.err( I18n.ERR_134, cnfe.getLocalizedMessage() ) );
+            throw new IOException( cnfe.getLocalizedMessage() );
+        }
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Class<?> getType()
+    {
+        return ParentIdAndRdn.class;
+    }
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotPartition.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotPartition.java
new file mode 100644
index 0000000..c9c83be
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotPartition.java
@@ -0,0 +1,540 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import net.sf.ehcache.Cache;
+import net.sf.ehcache.Element;
+
+import org.apache.directory.api.ldap.model.constants.SchemaConstants;
+import org.apache.directory.api.ldap.model.cursor.Cursor;
+import org.apache.directory.api.ldap.model.cursor.Tuple;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.entry.Value;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.api.util.exception.MultiException;
+import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.server.constants.ApacheSchemaConstants;
+import org.apache.directory.server.core.api.DnFactory;
+import org.apache.directory.server.core.api.entry.ClonedServerEntry;
+import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
+import org.apache.directory.server.core.api.interceptor.context.OperationContext;
+import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
+import org.apache.directory.server.core.api.partition.Partition;
+import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.xdbm.Index;
+import org.apache.directory.server.xdbm.search.impl.CursorBuilder;
+import org.apache.directory.server.xdbm.search.impl.DefaultOptimizer;
+import org.apache.directory.server.xdbm.search.impl.DefaultSearchEngine;
+import org.apache.directory.server.xdbm.search.impl.EvaluatorBuilder;
+import org.apache.directory.server.xdbm.search.impl.NoOpOptimizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * The Mavibot backed partition.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotPartition extends AbstractBTreePartition
+{
+    /** static logger */
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotPartition.class );
+
+    private static final String MAVIBOT_DB_FILE_EXTN = ".data";
+    
+    private static final FilenameFilter DB_FILTER = ( dir, name ) -> name.endsWith( MAVIBOT_DB_FILE_EXTN ) && !name.startsWith( "master." );
+    
+    private RecordManager recordMan;
+
+    /** the entry cache */
+    private Cache entryCache;
+
+
+    public MavibotPartition( SchemaManager schemaManager, DnFactory dnFactory )
+    {
+        super( schemaManager, dnFactory );
+
+        MavibotEntrySerializer.setSchemaManager( schemaManager );
+
+        // Initialize the cache size
+        if ( cacheSize < 0 )
+        {
+            cacheSize = DEFAULT_CACHE_SIZE;
+            LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
+        }
+        else
+        {
+            LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
+        }
+    }
+    
+    
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doRepair() throws Exception
+    {
+        // Nothing to do
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doInit() throws Exception
+    {
+        if ( !initialized )
+        {
+            // setup optimizer and registries for parent
+            if ( !isOptimizerEnabled() )
+            {
+                setOptimizer( new NoOpOptimizer() );
+            }
+            else
+            {
+                setOptimizer( new DefaultOptimizer<Entry>( this ) );
+            }
+
+            EvaluatorBuilder evaluatorBuilder = new EvaluatorBuilder( this, schemaManager );
+            CursorBuilder cursorBuilder = new CursorBuilder( this, evaluatorBuilder );
+
+            setSearchEngine( new DefaultSearchEngine( this, cursorBuilder, evaluatorBuilder, getOptimizer() ) );
+
+            // Create the underlying directories (only if needed)
+            File partitionDir = new File( getPartitionPath() );
+
+            if ( !partitionDir.exists() && !partitionDir.mkdirs() )
+            {
+                throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY, partitionDir ) );
+            }
+
+            if ( cacheSize < 0 )
+            {
+                cacheSize = DEFAULT_CACHE_SIZE;
+                LOG.debug( "Using the default entry cache size of {} for {} partition", cacheSize, id );
+            }
+            else
+            {
+                LOG.debug( "Using the custom configured cache size of {} for {} partition", cacheSize, id );
+            }
+
+            recordMan = new RecordManager( partitionDir.getPath() );
+
+            // Initialize the indexes
+            super.doInit();
+
+            // First, check if the file storing the data exists
+
+            // Create the master table (the table containing all the entries)
+            Cache masterTableCache = cacheService.getCache( suffixDn.getName() );
+            master = new MavibotMasterTable( recordMan, schemaManager, "master", masterTableCache.getCacheConfiguration().getMaxElementsInMemory() );
+
+            // get all index db files first
+            File[] allIndexDbFiles = partitionDir.listFiles( DB_FILTER );
+
+            // get the names of the db files also
+            List<String> indexDbFileNameList = Arrays.asList( partitionDir.list( DB_FILTER ) );
+
+            // then add all index objects to a list
+            List<String> allIndices = new ArrayList<String>();
+
+            for ( Index<?, String> index : systemIndices.values() )
+            {
+                allIndices.add( index.getAttribute().getOid() );
+            }
+
+            List<Index<?, String>> indexToBuild = new ArrayList<Index<?, String>>();
+
+            // this loop is used for two purposes
+            // one for collecting all user indices
+            // two for finding a new index to be built
+            // just to avoid another iteration for determining which is the new index
+            /* FIXME the below code needs to be modified to suit Mavibot
+                        for ( Index<?, Entry, String> index : userIndices.values() )
+                        {
+                            String indexOid = index.getAttribute().getOid();
+                            allIndices.add( indexOid );
+
+                            // take the part after removing .db from the
+                            String name = indexOid + MAVIBOT_DB_FILE_EXTN;
+
+                            // if the name doesn't exist in the list of index DB files
+                            // this is a new index and we need to build it
+                            if ( !indexDbFileNameList.contains( name ) )
+                            {
+                                indexToBuild.add( index );
+                            }
+                        }
+
+                        if ( indexToBuild.size() > 0 )
+                        {
+                            buildUserIndex( indexToBuild );
+                        }
+
+                        deleteUnusedIndexFiles( allIndices, allIndexDbFiles );
+            */
+
+            if ( cacheService != null )
+            {
+                entryCache = cacheService.getCache( getId() );
+                
+                int cacheSizeConfig = entryCache.getCacheConfiguration().getMaxElementsInMemory();
+
+                if ( cacheSizeConfig < cacheSize )
+                {
+                    entryCache.getCacheConfiguration().setMaxElementsInMemory( cacheSize );
+                }
+            }
+
+            // We are done !
+            initialized = true;
+        }
+    }
+
+
+    @Override
+    protected Index<?, String> convertAndInit( Index<?, String> index ) throws Exception
+    {
+        MavibotIndex<?> mavibotIndex;
+
+        if ( index instanceof MavibotRdnIndex )
+        {
+            mavibotIndex = ( MavibotRdnIndex ) index;
+        }
+        else if ( index instanceof MavibotDnIndex )
+        {
+            mavibotIndex = ( MavibotDnIndex ) index;
+        }
+        else if ( index instanceof MavibotIndex<?> )
+        {
+            mavibotIndex = ( MavibotIndex<?> ) index;
+
+            if ( mavibotIndex.getWkDirPath() == null )
+            {
+                mavibotIndex.setWkDirPath( partitionPath );
+            }
+        }
+        else
+        {
+            LOG.debug( "Supplied index {} is not a MavibotIndex.  "
+                + "Will create new MavibotIndex using copied configuration parameters.", index );
+            mavibotIndex = new MavibotIndex( index.getAttributeId(), true );
+            mavibotIndex.setCacheSize( index.getCacheSize() );
+            mavibotIndex.setWkDirPath( index.getWkDirPath() );
+        }
+
+        mavibotIndex.setRecordManager( recordMan );
+
+        mavibotIndex.init( schemaManager, schemaManager.lookupAttributeTypeRegistry( index.getAttributeId() ) );
+
+        return mavibotIndex;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    protected synchronized void doDestroy() throws Exception
+    {
+        MultiException errors = new MultiException( I18n.err( I18n.ERR_577 ) );
+
+        if ( !initialized )
+        {
+            return;
+        }
+
+        try
+        {
+            super.doDestroy();
+        }
+        catch ( Exception e )
+        {
+            errors.addThrowable( e );
+        }
+
+        // This is specific to the MAVIBOT store : close the record manager
+        try
+        {
+            recordMan.close();
+            LOG.debug( "Closed record manager for {} partition.", suffixDn );
+        }
+        catch ( Throwable t )
+        {
+            LOG.error( I18n.err( I18n.ERR_127 ), t );
+            errors.addThrowable( t );
+        }
+        finally
+        {
+            if ( entryCache != null )
+            {
+                entryCache.removeAll();
+            }
+        }
+
+        if ( errors.size() > 0 )
+        {
+            throw errors;
+        }
+    }
+
+
+    @Override
+    protected Index createSystemIndex( String indexOid, URI path, boolean withReverse ) throws Exception
+    {
+        LOG.debug( "Supplied index {} is not a MavibotIndex.  "
+            + "Will create new MavibotIndex using copied configuration parameters." );
+        MavibotIndex<?> mavibotIndex;
+
+        if ( indexOid.equals( ApacheSchemaConstants.APACHE_RDN_AT_OID ) )
+        {
+            mavibotIndex = new MavibotRdnIndex();
+            mavibotIndex.setAttributeId( ApacheSchemaConstants.APACHE_RDN_AT_OID );
+        }
+        else if ( indexOid.equals( ApacheSchemaConstants.APACHE_ALIAS_AT_OID ) )
+        {
+            mavibotIndex = new MavibotDnIndex( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
+            mavibotIndex.setAttributeId( ApacheSchemaConstants.APACHE_ALIAS_AT_OID );
+        }
+        else
+        {
+            mavibotIndex = new MavibotIndex( indexOid, withReverse );
+        }
+
+        mavibotIndex.setWkDirPath( path );
+
+        return mavibotIndex;
+    }
+
+
+    @Override
+    public void sync() throws Exception
+    {
+        if ( !initialized )
+        {
+            return;
+        }
+
+        // Sync all system indices
+        for ( Index<?, String> idx : systemIndices.values() )
+        {
+            idx.sync();
+        }
+
+        // Sync all user defined userIndices
+        for ( Index<?, String> idx : userIndices.values() )
+        {
+            idx.sync();
+        }
+
+        ( ( MavibotMasterTable ) master ).sync();
+    }
+
+
+    /**jdbm
+     * removes any unused/removed attribute index files present under the partition's
+     * working directory
+     */
+    private void deleteUnusedIndexFiles( List<String> allIndices, File[] dbFiles )
+    {
+
+    }
+
+
+    /**
+     * Builds user defined indexes on a attributes by browsing all the entries present in master db
+     * 
+     * @param userIndexes then user defined indexes to create
+     * @throws Exception in case of any problems while building the index
+     */
+    private void buildUserIndex( List<Index<?, String>> userIndexes ) throws Exception
+    {
+        Cursor<Tuple<String, Entry>> cursor = master.cursor();
+        cursor.beforeFirst();
+
+        while ( cursor.next() )
+        {
+            for ( Index index : userIndexes )
+            {
+                AttributeType atType = index.getAttribute();
+
+                String attributeOid = index.getAttribute().getOid();
+
+                LOG.info( "building the index for attribute type {}", atType );
+
+                Tuple<String, Entry> tuple = cursor.get();
+
+                String id = tuple.getKey();
+                Entry entry = tuple.getValue();
+
+                Attribute entryAttr = entry.get( atType );
+
+                if ( entryAttr != null )
+                {
+                    for ( Value<?> value : entryAttr )
+                    {
+                        index.add( value.getValue(), id );
+                    }
+
+                    // Adds only those attributes that are indexed
+                    presenceIdx.add( attributeOid, id );
+                }
+            }
+        }
+
+        cursor.close();
+    }
+
+
+    /**
+     * {@inheritDoc}}
+     */
+    public String getDefaultId()
+    {
+        return Partition.DEFAULT_ID;
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getRootId()
+    {
+        return Partition.ROOT_ID;
+    }
+
+
+    public RecordManager getRecordMan()
+    {
+        return recordMan;
+    }
+
+
+    public Entry lookupCache( String id )
+    {
+        if ( entryCache == null )
+        {
+            return null;
+        }
+
+        Element el = entryCache.get( id );
+
+        if ( el != null )
+        {
+            return ( Entry ) el.getValue();
+        }
+
+        return null;
+    }
+
+
+    @Override
+    public void addToCache( String id, Entry entry )
+    {
+        if ( entryCache == null )
+        {
+            return;
+        }
+
+        if ( entry instanceof ClonedServerEntry )
+        {
+            entry = ( ( ClonedServerEntry ) entry ).getOriginalEntry();
+        }
+
+        entryCache.put( new Element( id, entry ) );
+    }
+
+
+    @Override
+    public void updateCache( OperationContext opCtx )
+    {
+        if ( entryCache == null )
+        {
+            return;
+        }
+
+        try
+        {
+            if ( opCtx instanceof ModifyOperationContext )
+            {
+                // replace the entry
+                ModifyOperationContext modCtx = ( ModifyOperationContext ) opCtx;
+                Entry entry = modCtx.getAlteredEntry();
+                String id = entry.get( SchemaConstants.ENTRY_UUID_AT ).getString();
+
+                if ( entry instanceof ClonedServerEntry )
+                {
+                    entry = ( ( ClonedServerEntry ) entry ).getOriginalEntry();
+                }
+
+                entryCache.replace( new Element( id, entry ) );
+            }
+            else if ( ( opCtx instanceof MoveOperationContext ) || ( opCtx instanceof MoveAndRenameOperationContext )
+                || ( opCtx instanceof RenameOperationContext ) )
+            {
+                // clear the cache it is not worth updating all the children
+                entryCache.removeAll();
+            }
+            else if ( opCtx instanceof DeleteOperationContext )
+            {
+                // delete the entry
+                DeleteOperationContext delCtx = ( DeleteOperationContext ) opCtx;
+                entryCache.remove( delCtx.getEntry().get( SchemaConstants.ENTRY_UUID_AT ).getString() );
+            }
+        }
+        catch ( LdapException e )
+        {
+            LOG.warn( "Failed to update entry cache", e );
+        }
+    }
+
+    
+    /**
+     * @return The set of system and user indexes
+     */
+    public Set<Index<?, String>> getAllIndices()
+    {
+        Set<Index<?, String>> all = new HashSet<Index<?, String>>( systemIndices.values() );
+        all.addAll( userIndices.values() );
+        
+        return all;
+    }
+
+}
\ No newline at end of file
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotRdnIndex.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotRdnIndex.java
new file mode 100644
index 0000000..4e8220e
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotRdnIndex.java
@@ -0,0 +1,126 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.model.schema.AttributeType;
+import org.apache.directory.api.ldap.model.schema.MatchingRule;
+import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.server.constants.ApacheSchemaConstants;
+import org.apache.directory.server.i18n.I18n;
+import org.apache.directory.server.xdbm.ParentIdAndRdn;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A special index which stores Rdn objects.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class MavibotRdnIndex extends MavibotIndex<ParentIdAndRdn>
+{
+
+    /** A logger for this class */
+    private static final Logger LOG = LoggerFactory.getLogger( MavibotRdnIndex.class );
+
+
+    public MavibotRdnIndex()
+    {
+        super( ApacheSchemaConstants.APACHE_RDN_AT_OID, true );
+        initialized = false;
+    }
+
+
+    public void init( SchemaManager schemaManager, AttributeType attributeType ) throws IOException
+    {
+        LOG.debug( "Initializing an Index for attribute '{}'", attributeType.getName() );
+
+        this.attributeType = attributeType;
+
+        if ( attributeId == null )
+        {
+            setAttributeId( attributeType.getName() );
+        }
+
+        if ( this.wkDirPath == null )
+        {
+            NullPointerException e = new NullPointerException( "The index working directory has not be set" );
+            throw e;
+        }
+
+        String path = new File( this.wkDirPath, attributeType.getOid() ).getAbsolutePath();
+
+        try
+        {
+            initTables( schemaManager );
+        }
+        catch ( IOException e )
+        {
+            // clean up
+            close();
+            throw e;
+        }
+
+        // finally write a text file in the format <OID>-<attribute-name>.txt
+        FileWriter fw = new FileWriter( new File( path + "-" + attributeType.getName() + ".txt" ) );
+
+        // write the AttributeType description
+        fw.write( attributeType.toString() );
+        fw.close();
+
+        initialized = true;
+    }
+
+
+    /**
+     * Initializes the forward and reverse tables used by this Index.
+     *
+     * @param schemaManager The server schemaManager
+     * @throws IOException if we cannot initialize the forward and reverse
+     * tables
+     * @throws NamingException
+     */
+    private void initTables( SchemaManager schemaManager ) throws IOException
+    {
+        MatchingRule mr = attributeType.getEquality();
+
+        if ( mr == null )
+        {
+            throw new IOException( I18n.err( I18n.ERR_574, attributeType.getName() ) );
+        }
+
+        MavibotParentIdAndRdnSerializer.setSchemaManager( schemaManager );
+        MavibotParentIdAndRdnSerializer parentIdAndSerializer = new MavibotParentIdAndRdnSerializer();
+
+        String forwardTableName = attributeType.getOid() + FORWARD_BTREE;
+        forward = new MavibotTable<ParentIdAndRdn, String>( recordMan, schemaManager, forwardTableName,
+            parentIdAndSerializer, StringSerializer.INSTANCE, false );
+
+        String reverseTableName = attributeType.getOid() + REVERSE_BTREE;
+        reverse = new MavibotTable<String, ParentIdAndRdn>( recordMan, schemaManager, reverseTableName,
+            StringSerializer.INSTANCE, parentIdAndSerializer, false );
+    }
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotReadTxn.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotReadTxn.java
new file mode 100644
index 0000000..764cfa0
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotReadTxn.java
@@ -0,0 +1,11 @@
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+import org.apache.directory.mavibot.btree.Transaction;
+
+public class MavibotReadTxn extends AbstractMavibotTxn
+{
+    public MavibotReadTxn( Transaction transaction )
+    {
+        super( transaction );
+    }
+}
diff --git a/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
similarity index 64%
copy from mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
copy to mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
index 124d865..ff03213 100644
--- a/mavibot-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTable.java
@@ -21,29 +21,41 @@ package org.apache.directory.server.core.partition.impl.btree.mavibot;
 
 
 import java.io.IOException;
+import java.util.Map;
 
 import org.apache.directory.api.ldap.model.cursor.Cursor;
 import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapOtherException;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
 import org.apache.directory.mavibot.btree.BTree;
 import org.apache.directory.mavibot.btree.BTreeFactory;
+import org.apache.directory.mavibot.btree.InsertResult;
 import org.apache.directory.mavibot.btree.RecordManager;
+import org.apache.directory.mavibot.btree.Transaction;
 import org.apache.directory.mavibot.btree.TupleCursor;
 import org.apache.directory.mavibot.btree.ValueCursor;
+import org.apache.directory.mavibot.btree.WriteTransaction;
 import org.apache.directory.mavibot.btree.exception.BTreeAlreadyManagedException;
 import org.apache.directory.mavibot.btree.exception.KeyNotFoundException;
 import org.apache.directory.mavibot.btree.serializer.ElementSerializer;
+import org.apache.directory.mavibot.btree.serializer.LongSerializer;
+import org.apache.directory.mavibot.btree.serializer.StringSerializer;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
 import org.apache.directory.server.core.avltree.ArrayMarshaller;
 import org.apache.directory.server.core.avltree.ArrayTree;
 import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
+import org.apache.directory.server.core.partition.impl.btree.mavibot.MavibotIndex;
 import org.apache.directory.server.i18n.I18n;
 import org.apache.directory.server.xdbm.AbstractTable;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import jdbm.helper.Serializer;
+
 
 /**
  * A Mavibot Table. It extends the default Apache DS Table, when Mavibot is the
@@ -64,6 +76,15 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
     /** The used recordManager */
     protected RecordManager recordMan;
 
+    /** the limit at which we start using btree redirection for duplicates */
+    private int numDupLimit = MavibotIndex.DEFAULT_DUPLICATE_LIMIT;
+
+    /** a cache of duplicate BTrees */
+    private final Map<Long, BTree<K, V>> duplicateBtrees;
+
+    /** A value serializer */
+    private final ElementSerializer valueSerializer;
+
 
     /**
      * Creates a new instance of MavibotTable.
@@ -103,20 +124,27 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
     {
         super( schemaManager, name, keySerializer.getComparator(), valueSerializer.getComparator() );
         this.recordMan = recordMan;
+        this.valueSerializer = valueSerializer;
+        duplicateBtrees = null;
 
-        bt = recordMan.getManagedTree( name );
+        try ( Transaction transaction = recordMan.beginReadTransaction() )
+        {
+            bt = transaction.getBTree( name );
+        }
 
         if ( bt == null )
         {
-            bt = BTreeFactory.createPersistedBTree( name, keySerializer, valueSerializer, allowDuplicates, cacheSize );
-
+            // Create a new BTree
+            WriteTransaction writeTransaction = recordMan.beginWriteTransaction();
+                
             try
             {
-                recordMan.manage( bt );
+                bt = recordMan.addBTree( writeTransaction, name, keySerializer, valueSerializer );
+                writeTransaction.commit();
             }
-            catch ( BTreeAlreadyManagedException e )
+            catch ( Exception e )
             {
-                // should never happen
+                writeTransaction.abort();
                 throw new RuntimeException( e );
             }
         }
@@ -129,7 +157,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
         }
 
         this.allowsDuplicates = allowDuplicates;
-        arrayMarshaller = new ArrayMarshaller<V>( valueComparator );
+        arrayMarshaller = new ArrayMarshaller<>( valueComparator );
 
         // Initialize the count
         count = bt.getNbElems();
@@ -140,31 +168,16 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean isDupsEnabled()
-    {
-        return allowsDuplicates;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     * @throws  
-     */
-    @Override
-    public boolean has( K key ) throws LdapException
+    public boolean has( PartitionTxn transaction, K key ) throws LdapException
     {
         try
         {
-            return bt.hasKey( key );
+            return bt.hasKey( ( ( MavibotTxn ) transaction ).getTransaction(), key );
         }
         catch ( IOException ioe )
         {
             throw new LdapException( ioe );
         }
-        catch ( KeyNotFoundException knfe )
-        {
-            throw new LdapException( knfe );
-        }
     }
 
 
@@ -172,11 +185,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean has( K key, V value ) throws LdapException
+    public boolean has( PartitionTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
-            return bt.contains( key, value );
+            return bt.contains( ( ( MavibotTxn ) transaction ).getTransaction(), key, value );
         }
         catch ( IOException e )
         {
@@ -189,16 +202,20 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasGreaterOrEqual( K key ) throws Exception
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         TupleCursor<K, V> cursor = null;
 
         try
         {
-            cursor = bt.browseFrom( key );
+            cursor = bt.browseFrom( ( ( MavibotTxn ) transaction ).getTransaction(), key );
 
             return cursor.hasNext();
         }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
+        }
         finally
         {
             if ( cursor != null )
@@ -213,13 +230,13 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasLessOrEqual( K key ) throws Exception
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         TupleCursor<K, V> cursor = null;
 
         try
         {
-            cursor = bt.browseFrom( key );
+            cursor = bt.browseFrom( ( ( MavibotTxn ) transaction ).getTransaction(), key );
 
             org.apache.directory.mavibot.btree.Tuple<K, V> tuple = null;
 
@@ -248,6 +265,10 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
 
             return false;
         }
+        catch ( IOException ioe )
+        {
+            throw new LdapOtherException( ioe.getMessage() );
+        }
         finally
         {
             if ( cursor != null )
@@ -262,7 +283,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasGreaterOrEqual( K key, V val ) throws LdapException
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -274,16 +295,16 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             throw new UnsupportedOperationException( I18n.err( I18n.ERR_593 ) );
         }
 
-        TupleCursor<V, V> cursor = null;
+        ValueCursor<V> valueCursor = null;
 
         try
         {
-            if ( !bt.hasKey( key ) )
+            if ( !bt.hasKey( ( ( MavibotTxn ) transaction ).getTransaction(), key ) )
             {
                 return false;
             }
 
-            ValueCursor<V> valueCursor = bt.getValues( key );
+            valueCursor = bt.getValues( ( ( MavibotTxn ) transaction ).getTransaction(), key );
 
             int equal = bt.getValueSerializer().compare( val, valueCursor.next() );
 
@@ -295,9 +316,9 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
         }
         finally
         {
-            if ( cursor != null )
+            if ( valueCursor != null )
             {
-                cursor.close();
+                valueCursor.close();
             }
         }
     }
@@ -307,7 +328,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public boolean hasLessOrEqual( K key, V val ) throws Exception
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -319,7 +340,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             throw new UnsupportedOperationException( I18n.err( I18n.ERR_593 ) );
         }
 
-        if ( !bt.hasKey( key ) )
+        if ( !bt.hasKey( ( ( MavibotTxn ) transaction ).getTransaction(), key ) )
         {
             return false;
         }
@@ -334,7 +355,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public V get( K key ) throws LdapException
+    public V get( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -343,7 +364,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
 
         try
         {
-            return bt.get( key );
+            return bt.get( ( ( MavibotTxn ) transaction ).getTransaction(), key );
         }
         catch ( KeyNotFoundException knfe )
         {
@@ -360,7 +381,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void put( K key, V value ) throws Exception
+    public void put( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -369,17 +390,17 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 throw new IllegalArgumentException( I18n.err( I18n.ERR_594 ) );
             }
 
-            V existingVal = bt.insert( key, value );
+            InsertResult<K, V> existingVal = bt.insert( ( ( MavibotWriteTxn ) transaction ).getWriteTransaction(), key, value );
 
             if ( existingVal == null )
             {
                 count++;
             }
         }
-        catch ( Exception e )
+        catch ( IOException ioe )
         {
-            LOG.error( I18n.err( I18n.ERR_131, key, name ), e );
-            throw e;
+            LOG.error( I18n.err( I18n.ERR_131, key, name ), ioe );
+            throw new LdapOtherException( ioe.getMessage(), ioe);
         }
     }
 
@@ -388,7 +409,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void remove( K key ) throws Exception
+    public void remove( PartitionWriteTxn transaction, K key ) throws LdapException
     {
         try
         {
@@ -398,12 +419,13 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             }
 
             // Get the associated valueHolder
-            if ( bt.isAllowDuplicates() )
+            if ( allowsDuplicates )
             {
-                ValueCursor<V> valueCursor = bt.getValues( key );
+                ValueCursor<V> valueCursor = bt.getValues( ( ( MavibotWriteTxn ) transaction ).getWriteTransaction(), key );
                 int size = valueCursor.size();
                 valueCursor.close();
-                org.apache.directory.mavibot.btree.Tuple<K, V> returned = bt.delete( key );
+                org.apache.directory.mavibot.btree.Tuple<K, V> returned = 
+                    bt.delete( ( ( MavibotWriteTxn ) transaction ).getWriteTransaction(), key );
 
                 if ( null == returned )
                 {
@@ -414,7 +436,8 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             }
             else
             {
-                org.apache.directory.mavibot.btree.Tuple<K, V> returned = bt.delete( key );
+                org.apache.directory.mavibot.btree.Tuple<K, V> returned = 
+                    bt.delete( ( ( MavibotWriteTxn ) transaction ).getWriteTransaction(), key );
 
                 if ( null == returned )
                 {
@@ -424,14 +447,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 count--;
             }
         }
-        catch ( Exception e )
+        catch ( IOException ioe )
         {
-            LOG.error( I18n.err( I18n.ERR_133, key, name ), e );
+            LOG.error( I18n.err( I18n.ERR_133, key, name ), ioe );
 
-            if ( e instanceof IOException )
-            {
-                throw ( IOException ) e;
-            }
+            throw new LdapOtherException( ioe.getMessage(), ioe );
         }
     }
 
@@ -440,7 +460,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public void remove( K key, V value ) throws Exception
+    public void remove( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         try
         {
@@ -449,7 +469,8 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 return;
             }
 
-            org.apache.directory.mavibot.btree.Tuple<K, V> tuple = bt.delete( key, value );
+            org.apache.directory.mavibot.btree.Tuple<K, V> tuple = 
+                bt.delete( ( ( MavibotWriteTxn ) transaction ).getWriteTransaction(), key, value );
 
             // We decrement the counter only when the key was found
             if ( tuple != null )
@@ -457,9 +478,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
                 count--;
             }
         }
-        catch ( Exception e )
+        catch ( IOException ioe )
         {
-            LOG.error( I18n.err( I18n.ERR_132, key, value, name ), e );
+            LOG.error( I18n.err( I18n.ERR_132, key, value, name ), ioe );
+
+            throw new LdapOtherException( ioe.getMessage(), ioe );
         }
     }
 
@@ -468,9 +491,9 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<Tuple<K, V>> cursor() throws LdapException
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction ) throws LdapException
     {
-        return new MavibotCursor<K, V>( this );
+        return new MavibotCursor<>( this );
     }
 
 
@@ -478,11 +501,11 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<Tuple<K, V>> cursor( K key ) throws LdapException
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
-            return new EmptyCursor<Tuple<K, V>>();
+            return new EmptyCursor<>();
         }
 
         try
@@ -491,19 +514,18 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
             {
                 V val = bt.get( key );
 
-                return new SingletonCursor<Tuple<K, V>>(
-                    new Tuple<K, V>( key, val ) );
+                return new SingletonCursor<>( new Tuple<K, V>( key, val ) );
             }
             else
             {
                 ValueCursor<V> dupHolder = bt.getValues( key );
 
-                return new KeyTupleValueCursor<K, V>( dupHolder, key );
+                return new KeyTupleValueCursor<>( dupHolder, key );
             }
         }
         catch ( KeyNotFoundException knfe )
         {
-            return new EmptyCursor<Tuple<K, V>>();
+            return new EmptyCursor<>();
         }
         catch ( Exception e )
         {
@@ -516,31 +538,31 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public Cursor<V> valueCursor( K key ) throws Exception
+    public Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
-            return new EmptyCursor<V>();
+            return new EmptyCursor<>();
         }
 
         try
         {
             if ( !allowsDuplicates )
             {
-                V val = bt.get( key );
+                V val = bt.get( ( ( MavibotTxn ) transaction ).getTransaction(), key );
 
-                return new SingletonCursor<V>( val );
+                return new SingletonCursor<>( val );
             }
             else
             {
-                ValueCursor<V> dupCursor = bt.getValues( key );
+                ValueCursor<V> dupCursor = bt.getValues( ( ( MavibotTxn ) transaction ).getTransaction(), key );
 
-                return new ValueTreeCursor<V>( dupCursor );
+                return new ValueTreeCursor<>( dupCursor );
             }
         }
         catch ( KeyNotFoundException knfe )
         {
-            return new EmptyCursor<V>();
+            return new EmptyCursor<>();
         }
         catch ( Exception e )
         {
@@ -553,39 +575,46 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
      * {@inheritDoc}
      */
     @Override
-    public long count( K key ) throws Exception
+    public long count( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
             return 0;
         }
 
-        if ( bt.isAllowDuplicates() )
+        try
         {
-            try
+            if ( allowsDuplicates )
             {
-                ValueCursor<V> dupHolder = bt.getValues( key );
-                int size = dupHolder.size();
-                dupHolder.close();
-
-                return size;
+                try
+                {
+                    ValueCursor dupHolder = (ValueCursor) bt.get( ( ( MavibotTxn ) transaction ).getTransaction(), key );
+                    int size = dupHolder.size();
+                    dupHolder.close();
+    
+                    return size;
+                }
+                catch ( KeyNotFoundException knfe )
+                {
+                    // No key
+                    return 0;
+                }
             }
-            catch ( KeyNotFoundException knfe )
+            else
             {
-                // No key
-                return 0;
+                if ( bt.hasKey( ( ( MavibotTxn ) transaction ).getTransaction(), key ) )
+                {
+                    return 1;
+                }
+                else
+                {
+                    return 0;
+                }
             }
         }
-        else
+        catch ( IOException ioe )
         {
-            if ( bt.hasKey( key ) )
-            {
-                return 1;
-            }
-            else
-            {
-                return 0;
-            }
+            throw new LdapOtherException( ioe.getMessage() );
         }
     }
 
@@ -593,41 +622,6 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    @Override
-    public long greaterThanCount( K key ) throws Exception
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public long lessThanCount( K key ) throws Exception
-    {
-        // take a best guess
-        return Math.min( count, 10L );
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public void close() throws Exception
-    {
-        // do nothing here, the RecordManager will be closed in MavibotMasterTable.close()
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
     public ArrayTree<V> getDupsContainer( byte[] serialized ) throws IOException
     {
         if ( serialized == null )
@@ -661,6 +655,7 @@ public class MavibotTable<K, V> extends AbstractTable<K, V>
     /**
      * @see Object#toString()
      */
+    @Override
     public String toString()
     {
         StringBuilder sb = new StringBuilder();
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTxn.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTxn.java
new file mode 100644
index 0000000..5205040
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotTxn.java
@@ -0,0 +1,9 @@
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+import org.apache.directory.mavibot.btree.Transaction;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+
+public interface MavibotTxn extends PartitionTxn, Transaction
+{
+    Transaction getTransaction();
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotWriteTxn.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotWriteTxn.java
new file mode 100644
index 0000000..bc13160
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/MavibotWriteTxn.java
@@ -0,0 +1,18 @@
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+import org.apache.directory.mavibot.btree.Transaction;
+import org.apache.directory.mavibot.btree.WriteTransaction;
+
+public class MavibotWriteTxn extends AbstractMavibotTxn
+{
+    public MavibotWriteTxn( Transaction transaction )
+    {
+        super( transaction );
+    }
+
+    
+    public WriteTransaction getWriteTransaction()
+    {
+        return ( WriteTransaction ) transaction;
+    }
+}
diff --git a/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/ValueTreeCursor.java b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/ValueTreeCursor.java
new file mode 100644
index 0000000..1ff6069
--- /dev/null
+++ b/mavibotv2-partition/src/main/java/org/apache/directory/server/core/partition/impl/btree/mavibot/ValueTreeCursor.java
@@ -0,0 +1,155 @@
+/*
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *   or more contributor license agreements.  See the NOTICE file
+ *   distributed with this work for additional information
+ *   regarding copyright ownership.  The ASF licenses this file
+ *   to you under the Apache License, Version 2.0 (the
+ *   "License"); you may not use this file except in compliance
+ *   with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing,
+ *   software distributed under the License is distributed on an
+ *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *   KIND, either express or implied.  See the License for the
+ *   specific language governing permissions and limitations
+ *   under the License.
+ *
+ */
+
+package org.apache.directory.server.core.partition.impl.btree.mavibot;
+
+
+import java.io.IOException;
+
+import org.apache.directory.api.ldap.model.cursor.AbstractCursor;
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.mavibot.btree.ValueCursor;
+import org.apache.directory.server.i18n.I18n;
+
+
+/**
+ * TODO ValueTreeCursor.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class ValueTreeCursor<V> extends AbstractCursor<V>
+{
+
+    private ValueCursor<V> wrapped;
+
+    private V available;
+
+    // marker to detect the availability (cause Mavibot supports null values also)
+    private V notAvailable = ( V ) new Object();
+
+
+    public ValueTreeCursor( ValueCursor<V> cursor )
+    {
+        this.wrapped = cursor;
+    }
+
+
+    @Override
+    public boolean available()
+    {
+        return ( available != notAvailable );
+    }
+
+
+    @Override
+    public void before( V element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+    }
+
+
+    @Override
+    public void after( V element ) throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+    }
+
+
+    @Override
+    public void beforeFirst() throws LdapException, CursorException
+    {
+    }
+
+
+    @Override
+    public void afterLast() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+    }
+
+
+    @Override
+    public boolean first() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+    }
+
+
+    @Override
+    public boolean last() throws LdapException, CursorException
+    {
+        throw new UnsupportedOperationException( I18n.err( I18n.ERR_446 ) );
+    }
+
+
+    @Override
+    public boolean previous() throws LdapException, CursorException
+    {
+        try
+        {
+            if ( wrapped.hasPrev() )
+            {
+                available = wrapped.prev();
+                return true;
+            }
+            else
+            {
+                available = notAvailable;
+                return false;
+            }
+        }
+        catch ( IOException e )
+        {
+            throw new CursorException( e );
+        }
+    }
+
+
+    @Override
+    public boolean next() throws LdapException, CursorException
+    {
+        try
+        {
+            if ( wrapped.hasNext() )
+            {
+                available = wrapped.next();
+                return true;
+            }
+            else
+            {
+                available = notAvailable;
+                return false;
+            }
+        }
+        catch ( IOException e )
+        {
+            throw new CursorException( e );
+        }
+    }
+
+
+    @Override
+    public V get() throws CursorException
+    {
+        return available;
+    }
+
+}
diff --git a/pom.xml b/pom.xml
index 3ecbb0a..149ca12 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,7 @@
     <module>all</module>
     <module>jdbm-partition</module>
     <module>mavibot-partition</module>
+    <!--module>mavibotv2-partition</module-->
     <module>xdbm-partition</module>
     <module>core-shared</module>
     <module>core-api</module>
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java
index 6d6d503..4a97063 100644
--- a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/extended/PwdModifyHandler.java
@@ -302,6 +302,7 @@ public class PwdModifyHandler implements ExtendedOperationHandler<PasswordModify
             // The user is not authenticated : we have to use the provided userIdentity
             // and the oldPassword to check if the user is present
             BindOperationContext bindContext = new BindOperationContext( adminSession );
+            bindContext.setTransaction( requestor.getCoreSession().getDirectoryService().getPartitionNexus().beginReadTransaction() );
             bindContext.setDn( userDn );
             bindContext.setCredentials( oldPassword );
 
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/BindRequestHandler.java b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/BindRequestHandler.java
index e35328d..7192302 100644
--- a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/BindRequestHandler.java
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/request/BindRequestHandler.java
@@ -108,6 +108,7 @@ public class BindRequestHandler extends LdapRequestHandler<BindRequest>
         // create a new Bind context, with a null session, as we don't have 
         // any context yet.
         BindOperationContext bindContext = new BindOperationContext( null );
+        bindContext.setTransaction( ldapServer.getDirectoryService().getPartitionNexus().beginReadTransaction() );
 
         // Stores the Dn of the user to check, and its password
         bindContext.setDn( bindRequest.getDn() );
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/SimpleMechanismHandler.java b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/SimpleMechanismHandler.java
index 76c77d0..ae22efa 100644
--- a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/SimpleMechanismHandler.java
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/SimpleMechanismHandler.java
@@ -57,6 +57,7 @@ public class SimpleMechanismHandler implements MechanismHandler
         // create a new Bind context, with a null session, as we don't have 
         // any context yet.
         BindOperationContext bindContext = new BindOperationContext( null );
+        bindContext.setTransaction( ldapSession.getLdapServer().getDirectoryService().getPartitionNexus().beginReadTransaction() );
 
         // Stores the Dn of the user to check, and its password
         bindContext.setDn( bindRequest.getDn() );
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/ntlm/NtlmSaslServer.java b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/ntlm/NtlmSaslServer.java
index ca82431..d72a6d1 100644
--- a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/ntlm/NtlmSaslServer.java
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/ntlm/NtlmSaslServer.java
@@ -205,6 +205,7 @@ public class NtlmSaslServer extends AbstractSaslServer
     private CoreSession authenticate( String user, String password ) throws InvalidNameException, Exception
     {
         BindOperationContext bindContext = new BindOperationContext( getLdapSession().getCoreSession() );
+        bindContext.setTransaction( getLdapSession().getCoreSession().getDirectoryService().getPartitionNexus().beginReadTransaction() );
         bindContext.setDn( new Dn( user ) );
         bindContext.setCredentials( Strings.getBytesUtf8( password ) );
 
diff --git a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/plain/PlainSaslServer.java b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/plain/PlainSaslServer.java
index 54343bc..91757cb 100644
--- a/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/plain/PlainSaslServer.java
+++ b/protocol-ldap/src/main/java/org/apache/directory/server/ldap/handlers/sasl/plain/PlainSaslServer.java
@@ -281,6 +281,7 @@ public class PlainSaslServer extends AbstractSaslServer
             try
             {
                 BindOperationContext bindContext = new BindOperationContext( ldapSession.getCoreSession() );
+                bindContext.setTransaction( ldapSession.getCoreSession().getDirectoryService().getPartitionNexus().beginReadTransaction() );
                 bindContext.setDn( entry.getDn() );
                 bindContext.setCredentials( Strings.getBytesUtf8( password ) );
                 bindContext.setIoSession( ldapSession.getIoSession() );
diff --git a/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyReferralIT.java b/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyReferralIT.java
index 1fd1705..08998b7 100644
--- a/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyReferralIT.java
+++ b/server-integ/src/test/java/org/apache/directory/server/operations/modify/ModifyReferralIT.java
@@ -32,6 +32,8 @@ import javax.naming.directory.DirContext;
 import javax.naming.directory.ModificationItem;
 import javax.naming.ldap.LdapContext;
 
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.message.Control;
 import org.apache.directory.api.ldap.model.message.ModifyRequest;
 import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
 import org.apache.directory.api.ldap.model.message.ModifyResponse;
@@ -117,19 +119,29 @@ public class ModifyReferralIT extends AbstractLdapTestUnit
     public void testOnReferralWithManageDsaITControl() throws Exception
     {
         LdapConnection conn = getWiredConnection( getLdapServer() );
+        
+        Dn target = new Dn( "uid=akarasuluref,ou=users,ou=system" );
 
         ManageDsaIT manageDSAIT = new ManageDsaITImpl();
         manageDSAIT.setCritical( true );
 
         // modify success
         ModifyRequest modifyRequest = new ModifyRequestImpl();
-        modifyRequest.setName( new Dn( "uid=akarasuluref,ou=users,ou=system" ) );
+        modifyRequest.setName( target );
         modifyRequest.add( "description", "referral to akarasulu" );
         modifyRequest.addControl( manageDSAIT );
 
         conn.modify( modifyRequest );
 
         assertTrue( conn.compare( "uid=akarasuluref,ou=users,ou=system", "description", "referral to akarasulu" ) );
+        
+        Entry result = conn.lookup( target, new Control[] {manageDSAIT}, "*" );
+        
+        System.out.println( result );
+
+        result = conn.lookup( target, new Control[] {}, "*" );
+        
+        System.out.println( result );
 
         conn.close();
     }
diff --git a/server-integ/src/test/java/org/apache/directory/server/operations/search/PagedSearchApiIT.java b/server-integ/src/test/java/org/apache/directory/server/operations/search/PagedSearchApiIT.java
index 94e0a0f..09ebd90 100644
--- a/server-integ/src/test/java/org/apache/directory/server/operations/search/PagedSearchApiIT.java
+++ b/server-integ/src/test/java/org/apache/directory/server/operations/search/PagedSearchApiIT.java
@@ -49,7 +49,6 @@ import org.apache.directory.api.ldap.model.message.SearchScope;
 import org.apache.directory.api.ldap.model.message.controls.PagedResults;
 import org.apache.directory.api.ldap.model.message.controls.PagedResultsImpl;
 import org.apache.directory.api.ldap.model.name.Dn;
-import org.apache.directory.api.ldap.util.JndiUtils;
 import org.apache.directory.api.util.Network;
 import org.apache.directory.api.util.Strings;
 import org.apache.directory.ldap.client.api.EntryCursorImpl;
@@ -269,9 +268,6 @@ public class PagedSearchApiIT extends AbstractLdapTestUnit
                     results.add( result );
                 }
 
-                // Now read the next ones
-                Map<String, Control> controls =  cursor.getSearchResultDone().getControls();
-
                 if ( cursor.getSearchResultDone().getLdapResult().getResultCode() == ResultCodeEnum.SIZE_LIMIT_EXCEEDED )
                 {
                     hasSizeLimitException = true;
@@ -279,6 +275,9 @@ public class PagedSearchApiIT extends AbstractLdapTestUnit
                     break;
                 }
                 
+                // Now read the next ones
+                Map<String, Control> controls =  cursor.getSearchResultDone().getControls();
+
                 PagedResults responseControl = ( PagedResults ) controls.get( PagedResults.OID );
                 assertEquals( 0, responseControl.getSize() );
 
diff --git a/server-integ/src/test/java/org/apache/directory/server/operations/search/PersistentSearchApiIT.java b/server-integ/src/test/java/org/apache/directory/server/operations/search/PersistentSearchApiIT.java
new file mode 100644
index 0000000..75919ab
--- /dev/null
+++ b/server-integ/src/test/java/org/apache/directory/server/operations/search/PersistentSearchApiIT.java
@@ -0,0 +1,740 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ * 
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ * 
+ */
+package org.apache.directory.server.operations.search;
+
+
+import static org.apache.directory.server.integ.ServerIntegrationUtils.getWiredContext;
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.List;
+
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchResult;
+import javax.naming.event.EventDirContext;
+import javax.naming.event.NamespaceChangeListener;
+import javax.naming.event.NamingEvent;
+import javax.naming.event.NamingExceptionEvent;
+import javax.naming.event.ObjectChangeListener;
+import javax.naming.ldap.HasControls;
+import javax.naming.ldap.LdapContext;
+
+import org.apache.directory.api.ldap.codec.api.CodecControl;
+import org.apache.directory.api.ldap.codec.api.LdapApiService;
+import org.apache.directory.api.ldap.codec.controls.search.entryChange.EntryChangeDecorator;
+import org.apache.directory.api.ldap.codec.controls.search.persistentSearch.PersistentSearchDecorator;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.DefaultEntry;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.ldif.LdifUtils;
+import org.apache.directory.api.ldap.model.message.Control;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.api.ldap.model.message.controls.ChangeType;
+import org.apache.directory.api.ldap.model.message.controls.EntryChange;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearch;
+import org.apache.directory.api.ldap.model.message.controls.PersistentSearchImpl;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.directory.api.ldap.util.JndiUtils;
+import org.apache.directory.api.util.Network;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.directory.server.annotations.CreateLdapServer;
+import org.apache.directory.server.annotations.CreateTransport;
+import org.apache.directory.server.core.annotations.ApplyLdifs;
+import org.apache.directory.server.core.api.event.EventService;
+import org.apache.directory.server.core.api.event.RegistrationEntry;
+import org.apache.directory.server.core.integ.AbstractLdapTestUnit;
+import org.apache.directory.server.core.integ.FrameworkRunner;
+import org.junit.After;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Test case which tests the correct operation of the persistent search decorator.
+ * 
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+@RunWith(FrameworkRunner.class)
+@CreateLdapServer(
+    transports =
+        {
+            @CreateTransport(protocol = "LDAP")
+    })
+@ApplyLdifs(
+    {
+        // Entry # 2
+        "dn: cn=Tori Amos,ou=system",
+        "objectClass: person",
+        "objectClass: top",
+        "cn: Tori Amos",
+        "description: an American singer-songwriter",
+        "sn: Amos" })
+public class PersistentSearchApiIT extends AbstractLdapTestUnit
+{
+    private static final Logger LOG = LoggerFactory.getLogger( PersistentSearchApiIT.class );
+
+    private static final String BASE = "ou=system";
+    private static final String PERSON_DESCRIPTION = "an American singer-songwriter";
+    private static final String RDN = "cn=Tori Amos";
+
+
+    /**
+     * Creation of required attributes of a person entry.
+     */
+    private Attributes getPersonAttributes( String sn, String cn ) throws LdapException
+    {
+        Attributes attributes = LdifUtils.createJndiAttributes(
+            "objectClass: top",
+            "objectClass: person",
+            "cn", cn,
+            "sn", sn );
+
+        return attributes;
+    }
+
+    EventDirContext ctx;
+    EventService eventService;
+    PSearchListener listener;
+    Thread t;
+
+
+    private void setUpListenerReturnECs() throws Exception
+    {
+        setUpListener( true, new PersistentSearchImpl(), false );
+    }
+
+
+    private void setUpListener( boolean returnECs, PersistentSearch persistentSearch, boolean ignoreEmptyRegistryCheck )
+        throws Exception
+    {
+        ctx = ( EventDirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+        eventService = getLdapServer().getDirectoryService().getEventService();
+        List<RegistrationEntry> registrationEntryList = eventService.getRegistrationEntries();
+
+        if ( !ignoreEmptyRegistryCheck )
+        {
+            assertTrue( registrationEntryList.isEmpty() );
+        }
+
+        persistentSearch.setReturnECs( returnECs );
+        listener = new PSearchListener( persistentSearch );
+        t = new Thread( listener, "PSearchListener" );
+        t.start();
+
+        // let's wait until the listener thread started
+        while ( eventService.getRegistrationEntries().isEmpty() )
+        {
+            Thread.sleep( 100 );
+        }
+
+        // Now we wait until the listener is registered (timing dependent crap)
+        Thread.sleep( 250 );
+    }
+
+
+    private void setUpListener() throws Exception
+    {
+        ctx = ( EventDirContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+        eventService = getLdapServer().getDirectoryService().getEventService();
+        List<RegistrationEntry> registrationEntryList = eventService.getRegistrationEntries();
+        assertTrue( registrationEntryList.isEmpty() );
+
+        listener = new PSearchListener();
+        t = new Thread( listener, "PSearchListener" );
+        t.start();
+
+        // let's wait until the listener thread started
+        while ( eventService.getRegistrationEntries().isEmpty() )
+        {
+            Thread.sleep( 100 );
+        }
+
+        // Now we wait until the listener is registered (timing dependent crap)
+        Thread.sleep( 250 );
+    }
+
+
+    @After
+    public void tearDownListener() throws Exception
+    {
+        if( listener == null )
+        {
+            return;
+        }
+        
+        listener.close();
+        ctx.close();
+
+        while ( !eventService.getRegistrationEntries().isEmpty() )
+        {
+            Thread.sleep( 100 );
+        }
+    }
+
+
+    private void waitForThreadToDie( Thread t ) throws Exception
+    {
+        long start = System.currentTimeMillis();
+
+        while ( t.isAlive() )
+        {
+            Thread.sleep( 200 );
+            if ( System.currentTimeMillis() - start > 1000 )
+            {
+                break;
+            }
+        }
+    }
+
+
+    /**
+     * Shows correct notifications for modify(4) changes.
+     */
+    @Test
+    public void testPsearchModify() throws Exception
+    {
+        setUpListener();
+        ctx.modifyAttributes( RDN, DirContext.REMOVE_ATTRIBUTE,
+            new BasicAttributes( "description", PERSON_DESCRIPTION, true ) );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( RDN, listener.result.getName() );
+    }
+
+
+    /**
+     * Shows correct notifications for moddn(8) changes.
+     */
+    @Test
+    public void testPsearchModifyDn() throws Exception
+    {
+        setUpListener();
+        ctx.rename( RDN, "cn=Jack Black" );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+    }
+
+
+    /**
+     * Shows correct notifications for delete(2) changes.
+     */
+    @Test
+    public void testPsearchDelete() throws Exception
+    {
+        setUpListener();
+        ctx.destroySubcontext( RDN );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( RDN, listener.result.getName() );
+    }
+
+
+    /**
+     * Shows correct notifications for add(1) changes.
+     */
+    @Test
+    public void testPsearchAdd() throws Exception
+    {
+        setUpListener();
+        ctx.createSubcontext( "cn=Jack Black", getPersonAttributes( "Black", "Jack Black" ) );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+    }
+
+
+    /**
+     * Shows correct notifications for modify(4) changes with returned
+     * EntryChangeControl.
+     */
+    @Test
+    public void testPsearchModifyWithEC() throws Exception
+    {
+        setUpListenerReturnECs();
+        ctx.modifyAttributes( RDN, DirContext.REMOVE_ATTRIBUTE, new BasicAttributes( "description", PERSON_DESCRIPTION,
+            true ) );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( RDN, listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.MODIFY );
+    }
+
+
+    /**
+     * Shows correct notifications for moddn(8) changes with returned
+     * EntryChangeControl.
+     */
+    @Test
+    public void testPsearchModifyDnWithEC() throws Exception
+    {
+        setUpListenerReturnECs();
+        ctx.rename( RDN, "cn=Jack Black" );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.MODDN );
+        assertEquals( ( RDN + ",ou=system" ), listener.result.control.getPreviousDn().getName() );
+    }
+
+
+    /**
+     * Shows correct notifications for delete(2) changes with returned
+     * EntryChangeControl.
+     */
+    @Test
+    public void testPsearchDeleteWithEC() throws Exception
+    {
+        setUpListenerReturnECs();
+        ctx.destroySubcontext( RDN );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( RDN, listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.DELETE );
+    }
+
+
+    /**
+     * Shows correct notifications for add(1) changes with returned
+     * EntryChangeControl.
+     */
+    @Test
+    public void testPsearchAddWithEC() throws Exception
+    {
+        setUpListenerReturnECs();
+        ctx.createSubcontext( "cn=Jack Black", getPersonAttributes( "Black", "Jack Black" ) );
+        waitForThreadToDie( t );
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.ADD );
+    }
+
+
+    /**
+     * Shows correct notifications for only add(1) and modify(4) registered changes with returned
+     * EntryChangeControl but not deletes.
+     */
+    @Test
+    public void testPsearchAddModifyEnabledWithEC() throws Exception
+    {
+        PersistentSearch ctrl = new PersistentSearchImpl();
+        ctrl.setReturnECs( true );
+        ctrl.setChangeTypes( ChangeType.ADD.getValue() );
+        ctrl.enableNotification( ChangeType.MODIFY );
+        setUpListener( true, ctrl, false );
+        ctx.createSubcontext( "cn=Jack Black", getPersonAttributes( "Black", "Jack Black" ) );
+        waitForThreadToDie( t );
+
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.ADD );
+        tearDownListener();
+
+        setUpListener( true, ctrl, true );
+        ctx.destroySubcontext( "cn=Jack Black" );
+        waitForThreadToDie( t );
+        assertNull( listener.result );
+
+        // thread is still waiting for notifications try a modify
+        ctx.modifyAttributes( RDN, DirContext.REMOVE_ATTRIBUTE, new BasicAttributes( "description", PERSON_DESCRIPTION,
+            true ) );
+        waitForThreadToDie( t );
+
+        assertNotNull( listener.result );
+        assertEquals( RDN, listener.result.getName() );
+        assertEquals( listener.result.control.getChangeType(), ChangeType.MODIFY );
+    }
+
+
+    /**
+     * Test for DIRSERVER-1908 
+     */
+    @Test
+    public void testPsearchMove() throws Exception
+    {
+        LdapNetworkConnection connection = new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, ldapServer.getPort() );
+        connection.bind( "uid=admin,ou=system", "secret" );
+        
+        Entry newOu = new DefaultEntry( "uid=persist, ou=users,ou=system" );
+        newOu.add( "objectClass", "inetOrgPerson" );
+        newOu.add( "cn", "persist_cn" );
+        newOu.add( "sn", "persist_sn" );
+        
+        connection.add( newOu );
+        
+        SearchRequest sr = new SearchRequestImpl();
+        sr.setBase( new Dn( BASE ) );
+        sr.setFilter( "(objectClass=*)" );
+        sr.setScope( SearchScope.SUBTREE );
+        
+        PersistentSearch ps = new PersistentSearchImpl();
+        ps.setChangesOnly( true );
+        ps.setReturnECs( true );
+        ps.setCritical( true );
+        
+        sr.addControl( ps );
+        
+        final SearchCursor cursor = connection.search( sr );
+        
+        final List<Entry> entryList = new ArrayList<Entry>();
+        
+        Runnable r = new Runnable()
+        {
+            
+            @Override
+            public void run()
+            {
+                try
+                {
+                    while( cursor.next() )
+                    {
+                        entryList.add( cursor.getEntry() );
+                    }
+                }
+                catch( Exception e )
+                {
+                    throw new RuntimeException( e );
+                }
+            }
+        };
+        
+        new Thread( r ).start();
+        
+        connection.move( newOu.getDn(), newOu.getDn().getParent().getParent() );
+        Thread.sleep( 1000 );
+        assertFalse( entryList.isEmpty() );
+        assertEquals( 1, entryList.size() );
+        assertEquals( "uid=persist,ou=system", entryList.get( 0 ).getDn().getName() );
+        
+        connection.close();
+    }
+
+    
+    /**
+     * Shows correct notifications for add(1) changes with returned
+     * EntryChangeControl and changesOnly set to false so we return
+     * the first set of entries.
+     * 
+     * This test is commented out because it exhibits some producer
+     * consumer lockups (server and client being in same process)
+     * 
+     * PLUS ALL THIS GARBAGE IS TIME DEPENDENT!!!!!
+     */
+    //    public void testPsearchAddWithECAndFalseChangesOnly() throws Exception
+    //    {
+    //        PersistentSearchDecorator decorator = new PersistentSearchDecorator();
+    //        decorator.setReturnECs( true );
+    //        decorator.setChangesOnly( false );
+    //        PSearchListener listener = new PSearchListener( decorator );
+    //        Thread t = new Thread( listener );
+    //        t.start();
+    //
+    //        Thread.sleep( 3000 );
+    //
+    //        assertEquals( 5, listener.count );
+    //        ctx.createSubcontext( "cn=Jack Black", getPersonAttributes( "Black", "Jack Black" ) );
+    //
+    //        long start = System.currentTimeMillis();
+    //        while ( t.isAlive() )
+    //        {
+    //            Thread.sleep( 100 );
+    //            if ( System.currentTimeMillis() - start > 3000 )
+    //            {
+    //                break;
+    //            }
+    //        }
+    //
+    //        assertEquals( 6, listener.count );
+    //        assertNotNull( listener.result );
+    //        assertEquals( "cn=Jack Black", listener.result.getName() );
+    //        assertEquals( listener.result.decorator.getChangeType(), ChangeType.ADD );
+    //    }
+
+    /**
+     * Shows notifications functioning with the JNDI notification API of the SUN
+     * provider.
+     *
+    @Test
+    public void testPsearchAbandon() throws Exception
+    {
+        PersistentSearchDecorator decorator = new PersistentSearchDecorator();
+        decorator.setReturnECs( true );
+        PSearchListener listener = new PSearchListener( decorator );
+        Thread t = new Thread( listener );
+        t.start();
+    
+        while ( !listener.isReady )
+        {
+            Thread.sleep( 100 );
+        }
+        Thread.sleep( 250 );
+    
+        ctx.createSubcontext( "cn=Jack Black", getPersonAttributes( "Black", "Jack Black" ) );
+    
+        long start = System.currentTimeMillis();
+        while ( t.isAlive() )
+        {
+            Thread.sleep( 100 );
+            if ( System.currentTimeMillis() - start > 3000 )
+            {
+                break;
+            }
+        }
+    
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+        assertEquals( listener.result.decorator.getChangeType(), ChangeType.ADD );
+        
+        listener = new PSearchListener( decorator );
+    
+        t = new Thread( listener );
+        t.start();
+    
+        ctx.destroySubcontext( "cn=Jack Black" );
+    
+        start = System.currentTimeMillis();
+        while ( t.isAlive() )
+        {
+            Thread.sleep( 100 );
+            if ( System.currentTimeMillis() - start > 3000 )
+            {
+                break;
+            }
+        }
+    
+        // there seems to be a race condition here
+        // assertNull( listener.result );
+        assertNotNull( listener.result );
+        assertEquals( "cn=Jack Black", listener.result.getName() );
+        assertEquals( ChangeType.DELETE, listener.result.decorator.getChangeType() );
+        listener.result = null;
+    
+        // thread is still waiting for notifications try a modify
+        ctx.modifyAttributes( Rdn, DirContext.REMOVE_ATTRIBUTE, new AttributesImpl( "description", PERSON_DESCRIPTION,
+            true ) );
+        start = System.currentTimeMillis();
+        while ( t.isAlive() )
+        {
+            Thread.sleep( 200 );
+            if ( System.currentTimeMillis() - start > 3000 )
+            {
+                break;
+            }
+        }
+    
+        assertNull( listener.result );
+        //assertEquals( Rdn, listener.result.getName() );
+        //assertEquals( listener.result.decorator.getChangeType(), ChangeType.MODIFY );
+    }*/
+
+    class JndiNotificationListener implements NamespaceChangeListener, ObjectChangeListener
+    {
+        boolean hasError = false;
+        ArrayList<EventObject> list = new ArrayList<EventObject>();
+        NamingExceptionEvent exceptionEvent = null;
+
+
+        public void objectAdded( NamingEvent evt )
+        {
+            list.add( 0, evt );
+        }
+
+
+        public void objectRemoved( NamingEvent evt )
+        {
+            list.add( 0, evt );
+        }
+
+
+        public void objectRenamed( NamingEvent evt )
+        {
+            list.add( 0, evt );
+        }
+
+
+        public void namingExceptionThrown( NamingExceptionEvent evt )
+        {
+            hasError = true;
+            exceptionEvent = evt;
+            list.add( 0, evt );
+        }
+
+
+        public void objectChanged( NamingEvent evt )
+        {
+            list.add( 0, evt );
+        }
+    }
+
+    class PSearchListener implements Runnable
+    {
+        boolean isReady = false;
+        PSearchNotification result;
+        final PersistentSearchDecorator persistentSearch;
+        LdapContext ctx;
+        NamingEnumeration<SearchResult> list;
+
+
+        PSearchListener()
+        {
+            persistentSearch = new PersistentSearchDecorator( getLdapServer().getDirectoryService()
+                .getLdapCodecService() );
+        }
+
+
+        PSearchListener( PersistentSearch persistentSearch )
+        {
+            CodecControl<? extends Control> wrapped =
+                getLdapServer().getDirectoryService().getLdapCodecService().newControl( persistentSearch );
+            this.persistentSearch = ( PersistentSearchDecorator ) wrapped;
+        }
+
+
+        void close()
+        {
+            if ( list != null )
+            {
+                try
+                {
+                    list.close();
+                    LOG.debug( "PSearchListener: search naming enumeration closed()" );
+                }
+                catch ( Exception e )
+                {
+                    LOG.error( "Error closing NamingEnumeration on PSearchListener", e );
+                }
+            }
+
+            if ( ctx != null )
+            {
+                try
+                {
+                    ctx.close();
+                    LOG.debug( "PSearchListener: search context closed()" );
+                }
+                catch ( Exception e )
+                {
+                    LOG.error( "Error closing connection on PSearchListener", e );
+                }
+            }
+        }
+
+
+        public void run()
+        {
+            LOG.debug( "PSearchListener.run() called." );
+            LdapApiService codec = getLdapServer().getDirectoryService().getLdapCodecService();
+            persistentSearch.setCritical( true );
+            persistentSearch.setValue( persistentSearch.getValue() );
+
+            Control[] ctxCtls = new Control[]
+                { persistentSearch };
+
+            try
+            {
+                ctx = ( LdapContext ) getWiredContext( getLdapServer() ).lookup( BASE );
+                ctx.setRequestControls( JndiUtils.toJndiControls( codec, ctxCtls ) );
+                isReady = true;
+                LOG.debug( "PSearchListener is ready and about to issue persistent search request." );
+                list = ctx.search( "", "objectClass=*", null );
+                LOG.debug( "PSearchListener search request returned." );
+                EntryChange ecControl = null;
+
+                while ( list.hasMore() )
+                {
+                    LOG.debug( "PSearchListener search request got an item." );
+                    javax.naming.ldap.Control[] controls;
+                    SearchResult sresult = list.next();
+
+                    if ( sresult instanceof HasControls )
+                    {
+                        controls = ( ( HasControls ) sresult ).getControls();
+
+                        if ( controls != null )
+                        {
+                            for ( javax.naming.ldap.Control jndiControl : controls )
+                            {
+                                if ( jndiControl.getID().equals(
+                                    EntryChange.OID ) )
+                                {
+                                    ecControl = ( EntryChange ) JndiUtils.fromJndiControl( codec, jndiControl );
+                                    ( ( EntryChangeDecorator ) ecControl ).decode( jndiControl.getEncodedValue() );
+                                }
+                            }
+                        }
+                    }
+
+                    result = new PSearchNotification( sresult, ecControl );
+                    break;
+                }
+
+                LOG.debug( "PSearchListener broke out of while loop." );
+            }
+            catch ( Exception e )
+            {
+                e.printStackTrace();
+                LOG.error( "PSearchListener encountered error", e );
+            }
+            finally
+            {
+            }
+        }
+    }
+
+    class PSearchNotification extends SearchResult
+    {
+        private static final long serialVersionUID = 1L;
+        final EntryChange control;
+
+
+        public PSearchNotification( SearchResult result, EntryChange control )
+        {
+            super( result.getName(), result.getClassName(), result.getObject(), result.getAttributes(), result
+                .isRelative() );
+            this.control = control;
+        }
+
+
+        public String toString()
+        {
+            StringBuffer buf = new StringBuffer();
+            buf.append( "Dn: " ).append( getName() ).append( "\n" );
+
+            if ( control != null )
+            {
+                buf.append( "    EntryChangeControl =\n" );
+                buf.append( "       changeType   : " ).append( control.getChangeType() ).append( "\n" );
+                buf.append( "       previousDN   : " ).append( control.getPreviousDn() ).append( "\n" );
+                buf.append( "       changeNumber : " ).append( control.getChangeNumber() ).append( "\n" );
+            }
+
+            return buf.toString();
+        }
+    }
+}
diff --git a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/AbstractTable.java b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/AbstractTable.java
index 4173d42..9050fed 100644
--- a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/AbstractTable.java
+++ b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/AbstractTable.java
@@ -24,7 +24,9 @@ import java.io.IOException;
 import java.util.Comparator;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.apache.directory.api.ldap.model.exception.LdapException;
 import org.apache.directory.api.ldap.model.schema.SchemaManager;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
 import org.apache.directory.server.i18n.I18n;
 
 
@@ -119,13 +121,45 @@ public abstract class AbstractTable<K, V> implements Table<K, V>
     /**
      * {@inheritDoc}
      */
-    public long count() throws IOException
+    public long count( PartitionTxn transaction ) throws LdapException
     {
         return count;
     }
 
 
     /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long greaterThanCount( PartitionTxn transaction, K key ) throws LdapException
+    {
+        // take a best guess
+        return Math.min( count, 10L );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public long lessThanCount( PartitionTxn transaction, K key ) throws LdapException
+    {
+        // take a best guess
+        return Math.min( count, 10L );
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean isDupsEnabled()
+    {
+        return allowsDuplicates;
+    }
+
+
+    /**
      * @see Object#toString()
      */
     public String toString()
diff --git a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/Table.java b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/Table.java
index 1f723e2..d13819c 100644
--- a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/Table.java
+++ b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/Table.java
@@ -24,6 +24,9 @@ import java.util.Comparator;
 
 import org.apache.directory.api.ldap.model.cursor.Cursor;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
 
 
 /**
@@ -80,22 +83,24 @@ public interface Table<K, V>
      * this is exactly the same as a get call with a check to see if the
      * returned value is null or not.
      *
+     * @param transaction The transaction we are running in
      * @param key the Object of the key to check for
      * @return true if the key exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    boolean has( K key ) throws Exception;
+    boolean has( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
      * Checks to see if this table has a key with a specific value.
      *
+     * @param transaction The transaction we are running in
      * @param key the key to check for
      * @param value the value to check for
      * @return true if a record with the key and value exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    boolean has( K key, V value ) throws Exception;
+    boolean has( PartitionTxn transaction, K key, V value ) throws LdapException;
 
 
     /**
@@ -104,12 +109,13 @@ public interface Table<K, V>
      * call to return true.  The underlying database must sort keys based on a
      * key comparator because this method depends on key ordering.
      *
+     * @param transaction The transaction we are running in
      * @param key the key to compare keys to
      * @return true if a Tuple with a key greater than or equal to the key
      * argument exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    boolean hasGreaterOrEqual( K key ) throws Exception;
+    boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
@@ -118,12 +124,13 @@ public interface Table<K, V>
      * call to return true.  The underlying database must sort keys based on a
      * key comparator because this method depends on key ordering.
      *
+     * @param transaction The transaction we are running in
      * @param key the key to compare keys to
      * @return true if a Tuple with a key less than or equal to the key
      * argument exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    boolean hasLessOrEqual( K key ) throws Exception;
+    boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
@@ -138,15 +145,16 @@ public interface Table<K, V>
      * If the table does not support duplicates then an
      * UnsupportedOperationException is thrown.
      *
+     * @param transaction The transaction we are running in
      * @param key the key
      * @param val the value to compare values to
      * @return true if a Tuple with a key equal to the key argument and a
      * value greater than the value argument exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      * or if the underlying Db is not of the Btree type that allows sorted
      * duplicate values.
      */
-    boolean hasGreaterOrEqual( K key, V val ) throws Exception;
+    boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException;
 
 
     /**
@@ -161,15 +169,16 @@ public interface Table<K, V>
      * If the table does not support duplicates then an
      * UnsupportedOperationException is thrown.
      *
+     * @param transaction The transaction we are running in
      * @param key the key
      * @param val the value to compare values to
      * @return true if a Tuple with a key equal to the key argument and a
      * value less than the value argument exists, false otherwise
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      * or if the underlying Db is not of the Btree type that allows sorted
      * duplicate values.
      */
-    boolean hasLessOrEqual( K key, V val ) throws Exception;
+    boolean hasLessOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException;
 
 
     // ------------------------------------------------------------------------
@@ -180,59 +189,64 @@ public interface Table<K, V>
      * Gets the value of a record by key if the key exists.  If this Table
      * allows duplicate keys then the first key will be returned.  If this
      * Table sorts keys then the key will be the smallest key in the Table as
-     * specificed by this Table's comparator or the default bytewise lexical
+     * specified by this Table's comparator or the default byte-wise lexical
      * comparator.
      *
+     * @param transaction The transaction we are running in
      * @param key the key of the record
      * @return the value of the record with the specified key if key exists or
      * null if no such key exists.
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    V get( K key ) throws Exception;
+    V get( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
      * Puts a record into this Table.  Null is not allowed for keys or values
      * and should result in an IllegalArgumentException.
      *
+     * @param writeTransaction The transaction we are running in
      * @param key the key of the record
      * @param value the value of the record.
-     * @throws Exception if there is a failure to read or write to the
+     * @throws LdapException if there is a failure to read or write to the
      * underlying Db
      * @throws IllegalArgumentException if a null key or value is used
      */
-    void put( K key, V value ) throws Exception;
+    void put( PartitionWriteTxn writeTransaction, K key, V value ) throws LdapException;
 
 
     /**
      * Removes all records with a specified key from this Table.
      *
+     * @param writeTransaction The transaction we are running in
      * @param key the key of the records to remove
-     * @throws Exception if there is a failure to read or write to
+     * @throws LdapException if there is a failure to read or write to
      * the underlying Db
      */
-    void remove( K key ) throws Exception;
+    void remove( PartitionWriteTxn writeTransaction, K key ) throws LdapException;
 
 
     /**
      * Removes a single key value pair with a specified key and value from
      * this Table.
      *
+     * @param writeTransaction The transaction we are running in
      * @param key the key of the record to remove
      * @param value the value of the record to remove
-     * @throws Exception if there is a failure to read or write to
+     * @throws LdapException if there is a failure to read or write to
      * the underlying Db
      */
-    void remove( K key, V value ) throws Exception;
+    void remove( PartitionWriteTxn writeTransaction, K key, V value ) throws LdapException;
 
 
     /**
      * Creates a Cursor that traverses Tuples in a Table.
      *
+     * @param transaction The transaction we are running in
      * @return a Cursor over Tuples containing the key value pairs
-     * @throws Exception if there are failures accessing underlying stores
+     * @throws LdapException if there are failures accessing underlying stores
      */
-    Cursor<Tuple<K, V>> cursor() throws Exception;
+    Cursor<Tuple<K, V>> cursor( PartitionTxn transaction ) throws LdapException;
 
 
     /**
@@ -244,11 +258,12 @@ public interface Table<K, V>
      * to a specific key.  This Cursor is naturally limited to return only
      * the tuples for the same key.
      *
+     * @param transaction The transaction we are running in
      * @param key the duplicate key to return the Tuples of
      * @return a Cursor over Tuples containing the same key
-     * @throws Exception if there are failures accessing underlying stores
+     * @throws LdapException if there are failures accessing underlying stores
      */
-    Cursor<Tuple<K, V>> cursor( K key ) throws Exception;
+    Cursor<Tuple<K, V>> cursor( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
@@ -261,11 +276,12 @@ public interface Table<K, V>
      * reused to return key value pairs.  This Cursor is naturally limited to
      * return only the values for the same key.
      *
+     * @param transaction The transaction we are running in
      * @param key the duplicate key to return the values of
      * @return a Cursor over values of a key
-     * @throws Exception if there are failures accessing underlying stores
+     * @throws LdapException if there are failures accessing underlying stores
      */
-    Cursor<V> valueCursor( K key ) throws Exception;
+    Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException;
 
 
     // ------------------------------------------------------------------------
@@ -275,21 +291,23 @@ public interface Table<K, V>
     /**
      * Gets the count of the number of Tuples in this Table.
      *
+     * @param transaction The transaction we are running in
      * @return the number of records
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    long count() throws Exception;
+    long count( PartitionTxn transaction ) throws LdapException;
 
 
     /**
      * Gets the count of the number of records in this Table with a specific
      * key: returns the number of duplicates for a key.
      *
+     * @param transaction The transaction we are running in
      * @param key the Object key to count.
      * @return the number of duplicate records for a key.
-     * @throws Exception if there is a failure to read the underlying Db
+     * @throws LdapException if there is a failure to read the underlying Db
      */
-    long count( K key ) throws Exception;
+    long count( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
@@ -297,11 +315,12 @@ public interface Table<K, V>
      * specific key argument provided need not exist for this call to return 
      * a non-zero value.
      *
+     * @param transaction The transaction we are running in
      * @param key the key to use in comparisons
      * @return the number of keys greater than or equal to the key
-     * @throws Exception if there is a failure to read the underlying db
+     * @throws LdapException if there is a failure to read the underlying db
      */
-    long greaterThanCount( K key ) throws Exception;
+    long greaterThanCount( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
@@ -309,17 +328,19 @@ public interface Table<K, V>
      * specific key argument provided need not exist for this call to return 
      * a non-zero value.
      *
+     * @param transaction The transaction we are running in
      * @param key the key to use in comparisons
      * @return the number of keys less than or equal to the key
-     * @throws Exception if there is a failure to read the underlying db
+     * @throws LdapException if there is a failure to read the underlying db
      */
-    long lessThanCount( K key ) throws Exception;
+    long lessThanCount( PartitionTxn transaction, K key ) throws LdapException;
 
 
     /**
      * Closes the underlying Db of this Table.
      *
-     * @throws Exception on any failures
+     * @param transaction The transaction we are running in
+     * @throws LdapException on any failures
      */
-    void close() throws Exception;
+    void close( PartitionTxn transaction ) throws LdapException;
 }
diff --git a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/impl/avl/AvlTable.java b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/impl/avl/AvlTable.java
index 7d53c3b..d398c4c 100644
--- a/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/impl/avl/AvlTable.java
+++ b/xdbm-partition/src/main/java/org/apache/directory/server/xdbm/impl/avl/AvlTable.java
@@ -27,6 +27,8 @@ import org.apache.directory.api.ldap.model.cursor.EmptyCursor;
 import org.apache.directory.api.ldap.model.cursor.SingletonCursor;
 import org.apache.directory.api.ldap.model.cursor.Tuple;
 import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.server.core.api.partition.PartitionTxn;
+import org.apache.directory.server.core.api.partition.PartitionWriteTxn;
 import org.apache.directory.server.core.avltree.AvlSingletonOrOrderedSetCursor;
 import org.apache.directory.server.core.avltree.AvlTree;
 import org.apache.directory.server.core.avltree.AvlTreeCursor;
@@ -69,7 +71,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public void close() throws Exception
+    @Override
+    public void close( PartitionTxn transaction ) throws LdapException
     {
         ( ( AvlTreeMapImpl<K, V> ) avl ).removeAll();
     }
@@ -78,7 +81,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public long count( K key ) throws Exception
+    @Override
+    public long count( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -106,7 +110,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public V get( K key ) throws LdapException
+    @Override
+    public V get( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -134,7 +139,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public long greaterThanCount( K key ) throws Exception
+    @Override
+    public long greaterThanCount( PartitionTxn transaction, K key ) throws LdapException
     {
         return avl.getSize();
     }
@@ -143,7 +149,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean has( K key ) throws Exception
+    @Override
+    public boolean has( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -157,7 +164,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean has( K key, V value ) throws LdapException
+    @Override
+    public boolean has( PartitionTxn transaction, K key, V value ) throws LdapException
     {
         if ( key == null )
         {
@@ -171,7 +179,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean hasGreaterOrEqual( K key ) throws Exception
+    @Override
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -185,7 +194,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean hasGreaterOrEqual( K key, V val ) throws LdapException
+    @Override
+    public boolean hasGreaterOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -212,7 +222,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean hasLessOrEqual( K key ) throws Exception
+    @Override
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -226,7 +237,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean hasLessOrEqual( K key, V val ) throws Exception
+    @Override
+    public boolean hasLessOrEqual( PartitionTxn transaction, K key, V val ) throws LdapException
     {
         if ( key == null )
         {
@@ -253,16 +265,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public boolean isDupsEnabled()
-    {
-        return allowsDuplicates;
-    }
-
-
-    /**
-     * {@inheritDoc}
-     */
-    public long lessThanCount( K key ) throws Exception
+    @Override
+    public long lessThanCount( PartitionTxn transaction, K key ) throws LdapException
     {
         return count;
     }
@@ -271,7 +275,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public void put( K key, V value ) throws Exception
+    @Override
+    public void put( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         if ( ( key == null ) || ( value == null ) )
         {
@@ -288,7 +293,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public void remove( K key ) throws Exception
+    @Override
+    public void remove( PartitionWriteTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -316,7 +322,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public void remove( K key, V value ) throws Exception
+    @Override
+    public void remove( PartitionWriteTxn transaction, K key, V value ) throws LdapException
     {
         if ( avl.remove( key, value ) != null )
         {
@@ -328,7 +335,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public Cursor<Tuple<K, V>> cursor() throws LdapException
+    @Override
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction ) throws LdapException
     {
         if ( !allowsDuplicates )
         {
@@ -343,7 +351,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public Cursor<Tuple<K, V>> cursor( K key ) throws Exception
+    @Override
+    public Cursor<Tuple<K, V>> cursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {
@@ -370,7 +379,8 @@ public class AvlTable<K, V> extends AbstractTable<K, V>
     /**
      * {@inheritDoc}
      */
-    public Cursor<V> valueCursor( K key ) throws Exception
+    @Override
+    public Cursor<V> valueCursor( PartitionTxn transaction, K key ) throws LdapException
     {
         if ( key == null )
         {

-- 
To stop receiving notification emails like this one, please contact
elecharny@apache.org.