diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c
index e04f77591fc66852c28001e61335f1c0ff029257..2383e5979f55d18e907312661dda2d80cca2812b 100644
--- a/servers/slapd/back-bdb2/add.c
+++ b/servers/slapd/back-bdb2/add.c
@@ -254,6 +254,7 @@ bdb2_back_add(
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			bdb2i_check_default_attr_index_add( li, e );
 			break;
 	}
diff --git a/servers/slapd/back-bdb2/back-bdb2.h b/servers/slapd/back-bdb2/back-bdb2.h
index f7d7e589055370502c4165c4023503ff009675b7..a40c4f5195fa6171d116546ca30f76cec058ac00 100644
--- a/servers/slapd/back-bdb2/back-bdb2.h
+++ b/servers/slapd/back-bdb2/back-bdb2.h
@@ -131,9 +131,9 @@ struct attrinfo {
 
 typedef  struct _bdb2_txn_head {
 
-	/*  counter and timer to control checkpoints  */
-	size_t           txn_cnt;
-	time_t           txn_chkp;
+	/*  log size and timer to control checkpoints  */
+	u_int32_t        txn_log;
+	u_int32_t        txn_time;
 
 	/*  a list of all DB files in use  */
 	BDB2_TXN_FILES   *dbFiles;
@@ -145,10 +145,10 @@ typedef  struct _bdb2_txn_head {
 #define  BDB2_DB_ID2CHILDREN_FILE   3
 #define  BDB2_DB_OC_IDX_FILE        4
 
-	/*  a file pointer for the NEXTID file
-		(must be opened appropriately at backend
-		entry and closed on leave  */
-	FILE             *nextidFP;
+	/*  a database handle for the NEXTID file
+		(must be opened like all DB files at startup
+		and closed on shutdown  */
+	LDBM             nextidFile;
 
 	/*  is the default attribute index set to non-none  */
 	int              withDefIDX;
diff --git a/servers/slapd/back-bdb2/close.c b/servers/slapd/back-bdb2/close.c
index 9a78f07ab17a239e31f239b4e7d0271ab626fae5..2d573533b63fa57b8171e1b92265c2d798d4fff0 100644
--- a/servers/slapd/back-bdb2/close.c
+++ b/servers/slapd/back-bdb2/close.c
@@ -12,11 +12,28 @@
 static int
 bdb2i_back_db_close_internal( BackendDB *be )
 {
-	Debug( LDAP_DEBUG_TRACE, "bdb2 backend saving nextid\n", 0, 0, 0 );
-	if ( bdb2i_next_id_save( be ) < 0 ) {
-		Debug( LDAP_DEBUG_ANY, "bdb2 backend nextid save failed!\n", 0, 0, 0 );
+	DB_LOCK         lock;
+
+	/*  since close will probably write the NEXTID file,
+		wee need transaction control  */
+	if ( bdb2i_enter_backend_w( get_dbenv( be ), &lock ) != 0 ) {
+		return( -1 );
 	}
 
+	if ( slapMode != SLAP_TOOL_MODE ) {
+
+		Debug( LDAP_DEBUG_TRACE, "bdb2 backend saving nextid\n", 0, 0, 0 );
+		if ( bdb2i_next_id_save( be ) < 0 ) {
+			Debug( LDAP_DEBUG_ANY, "bdb2 backend nextid save failed!\n",
+					0, 0, 0 );
+		}
+	}
+
+	/*  before closing all files, leave the backend (thus commiting
+		all writes) and set a last checkpoint  */
+	(void) bdb2i_leave_backend_w( get_dbenv( be ), lock );
+	(void) bdb2i_set_txn_checkpoint( get_dbenv( be )->tx_info, 1 );
+
 	/*  close all DB files  */
 	Debug( LDAP_DEBUG_TRACE, "bdb2 backend closing DB files\n", 0, 0, 0 );
 	bdb2i_txn_close_files( be );
diff --git a/servers/slapd/back-bdb2/dbcache.c b/servers/slapd/back-bdb2/dbcache.c
index 405e9e924dd779b52314464758b1e2c0e45f73c8..1e303b37985dc8f2ba082ab6fce698645024619b 100644
--- a/servers/slapd/back-bdb2/dbcache.c
+++ b/servers/slapd/back-bdb2/dbcache.c
@@ -33,6 +33,7 @@ bdb2i_cache_open(
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			{
 				struct	ldbminfo	*li = (struct ldbminfo *) be->be_private;
 				char	buf[MAXPATHLEN];
@@ -64,6 +65,7 @@ bdb2i_cache_close( BackendDB *be, struct dbcache *db )
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			return;
 
 		default:
@@ -84,6 +86,7 @@ bdb2i_cache_really_close( BackendDB *be, struct dbcache *db )
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			return;
 
 		default:
@@ -104,6 +107,7 @@ bdb2i_cache_flush_all( BackendDB *be )
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			return;
 
 		default:
@@ -125,7 +129,7 @@ bdb2i_cache_fetch(
 
 	ldbm_datum_init( data );
 
-	data = ldbm_fetch( db->dbc_db, key );
+	data = bdb2i_db_fetch( db->dbc_db, key );
 
 	return( data );
 }
@@ -162,7 +166,7 @@ bdb2i_cache_store(
 	if ( slapMode == SLAP_TIMEDSERVER_MODE )
 		bdb2i_uncond_start_timing( &time1 );
 
-	rc = ldbm_store( db->dbc_db, key, data, flags );
+	rc = bdb2i_db_store( db->dbc_db, key, data, flags );
 
 	if ( slapMode == SLAP_TIMEDSERVER_MODE ) {
 		char buf[BUFSIZ];
@@ -187,7 +191,7 @@ bdb2i_cache_delete(
 {
 	int	rc;
 
-	rc = ldbm_delete( db->dbc_db, key );
+	rc = bdb2i_db_delete( db->dbc_db, key );
 
 	return( rc );
 }
diff --git a/servers/slapd/back-bdb2/idl.c b/servers/slapd/back-bdb2/idl.c
index d82078b3f77efc7bae2a6c77d851c4bbe02f41d2..3b8f1bd24c77e1aaa9d4e5c85244b758465ffecb 100644
--- a/servers/slapd/back-bdb2/idl.c
+++ b/servers/slapd/back-bdb2/idl.c
@@ -292,7 +292,7 @@ idl_change_first(
 	/* delete old key block */
 	if ( (rc = bdb2i_cache_delete( db, bkey )) != 0 ) {
 		Debug( LDAP_DEBUG_ANY,
-		    "ldbm_delete of (%s) returns %d\n", bkey.dptr, rc,
+		    "bdb2i_db_delete of (%s) returns %d\n", bkey.dptr, rc,
 		    0 );
 		return( rc );
 	}
diff --git a/servers/slapd/back-bdb2/modify.c b/servers/slapd/back-bdb2/modify.c
index 3178f66985e83c309c279bbc419891674b5b7d1c..f638aa7059b197bebb2c85e76d48b305cbdb2a9d 100644
--- a/servers/slapd/back-bdb2/modify.c
+++ b/servers/slapd/back-bdb2/modify.c
@@ -144,6 +144,7 @@ bdb2_back_modify(
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			bdb2i_check_default_attr_index_mod( li, modlist );
 			break;
 	}
diff --git a/servers/slapd/back-bdb2/nextid.c b/servers/slapd/back-bdb2/nextid.c
index 4021b8e473f968ecd30d59e0716a7d0a97d823ff..88121201ca81878a5b9f38046e1d510eb46a14e0 100644
--- a/servers/slapd/back-bdb2/nextid.c
+++ b/servers/slapd/back-bdb2/nextid.c
@@ -13,78 +13,19 @@
 #include "slap.h"
 #include "back-bdb2.h"
 
-/*  XXX the separate handling of the NEXTID file is in contrast to TP  */
-/*  the NEXTID file is beeing opened during database start-up  */
-static ID
-next_id_read( BackendDB *be )
-{
-	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
-	BDB2_TXN_HEAD   *head = &li->li_txn_head;
-	FILE*	fp = head->nextidFP;
-	ID  	id;
-	char	buf[20];
-
-	/*  set the file pointer to the beginnig of the file  */
-	rewind( fp );
-
-	/*  read the nextid  */
-	if ( fgets( buf, sizeof(buf), fp ) == NULL ) {
-		Debug( LDAP_DEBUG_ANY,
-		   "next_id_read: could not fgets nextid from \"%s\"\n",
-		    li->li_nextid_file, 0, 0 );
-		return NOID;
-	}
-
-	id = atol( buf );
-
-	if(id < 1) {
-		Debug( LDAP_DEBUG_ANY,
-			"next_id_read %ld: atol(%s) return non-positive integer\n",
-			id, buf, 0 );
-		return NOID;
-	}
-
-	return id;
-}
+/*  reading and writing NEXTID is handled in txn.c  */
+#define next_id_read(be)  bdb2i_get_nextid( (be) )
+#define next_id_write(be,id)  bdb2i_put_nextid( (be), (id) )
 
-/*  XXX the separate handling of the NEXTID file is in contrast to TP  */
-/*  the NEXTID file is beeing opened during database start-up  */
-static int
-next_id_write( BackendDB *be, ID id )
-{
-	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
-	BDB2_TXN_HEAD   *head = &li->li_txn_head;
-	FILE*	fp = head->nextidFP;
-	char	buf[20];
-	int		rc = 0;
-
-	/*  set the file pointer to the beginnig of the file  */
-	rewind( fp );
-
-	/*  write the nextid  */
-	if ( fprintf( fp, "%ld\n", id ) == EOF ) {
-		Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): cannot fprintf\n",
-		    id, 0, 0 );
-		rc = -1;
-	}
-
-	/*  if forced flushing of files is in effect, do so  */
-	if( li->li_dbcachewsync && ( fflush( fp ) != 0 )) {
-		Debug( LDAP_DEBUG_ANY, "next_id_write %ld: cannot fflush\n",
-		    id, 0, 0 );
-		rc = -1;
-	}
-
-	return rc;
-}
 
 int
 bdb2i_next_id_save( BackendDB *be )
 {
 	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
 	ID id = bdb2i_next_id_get( be );
-	int rc = next_id_write( be, id );
+	int rc;
 
+	rc = next_id_write( be, id );
 	if (rc == 0) {
 		li->li_nextid_wrote = id;
 	}
diff --git a/servers/slapd/back-bdb2/porter.c b/servers/slapd/back-bdb2/porter.c
index 96f0576d471da674287f5556da24dce35671e7af..d28e0f9ed96fb6fc38f387a9eccffde787267f1e 100644
--- a/servers/slapd/back-bdb2/porter.c
+++ b/servers/slapd/back-bdb2/porter.c
@@ -26,6 +26,7 @@ bdb2i_enter_backend_rw( DB_ENV *dbEnv, DB_LOCK *lock, int writer )
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
+		case SLAP_TOOLID_MODE:
 			if ( ( ret = lock_id( dbEnv->lk_info, &locker )) != 0 ) {
 
 				Debug( LDAP_DEBUG_ANY,
@@ -71,6 +72,14 @@ bdb2i_enter_backend_rw( DB_ENV *dbEnv, DB_LOCK *lock, int writer )
 			break;
 	}
 
+	/*  if we are a writer and we have the backend lock,
+		start transaction control  */
+	if ( writer && ( ret == 0 )) {
+
+		ret = bdb2i_start_transction( dbEnv->tx_info );
+
+	}
+
 	return( ret );
 }
 
@@ -78,14 +87,30 @@ bdb2i_enter_backend_rw( DB_ENV *dbEnv, DB_LOCK *lock, int writer )
 int
 bdb2i_leave_backend_rw( DB_ENV *dbEnv, DB_LOCK lock, int writer )
 {
-	int   ret = 0;
+	/*  since one or more error can occure,
+		we must have several return codes that are or'ed at the end  */
+	int   ret_transaction = 0;
+	int   ret_lock        = 0;
+	int   ret_chkp        = 0;
+
+	/*  if we are a writer, finish the transaction  */
+	if ( writer ) {
+
+		ret_transaction = bdb2i_finish_transaction();
 
+	}
+
+	/*  check whether checkpointing is needed  */
+	ret_transaction |= bdb2i_set_txn_checkpoint( dbEnv->tx_info, 0 );
+
+	/*  now release the lock  */
 	switch ( slapMode ) {
 
 		case SLAP_SERVER_MODE:
 		case SLAP_TIMEDSERVER_MODE:
 		case SLAP_TOOL_MODE:
-			switch( ( ret = lock_put( dbEnv->lk_info, lock ))) {
+		case SLAP_TOOLID_MODE:
+			switch( ( ret_lock = lock_put( dbEnv->lk_info, lock ))) {
 
 				case 0:
 					Debug( LDAP_DEBUG_TRACE,
@@ -109,15 +134,14 @@ bdb2i_leave_backend_rw( DB_ENV *dbEnv, DB_LOCK lock, int writer )
 					Debug( LDAP_DEBUG_ANY,
 						"bdb2i_leave_backend() -- %s lock returned ERROR: %s\n",
 						writer ? "write" : "read", strerror( errno ), 0 );
-					ret = errno;
+					ret_lock = errno;
 					break;
 			
 			}
 			break;
 	}
 
-	return( ret );
-
+	return( ret_transaction | ret_lock );
 }
 
 
diff --git a/servers/slapd/back-bdb2/proto-back-bdb2.h b/servers/slapd/back-bdb2/proto-back-bdb2.h
index 5020e531c09381d8f087a46e926bb8ae93b3a7fd..cd5fa7852d72242512427d6608b51bbfcc13f02b 100644
--- a/servers/slapd/back-bdb2/proto-back-bdb2.h
+++ b/servers/slapd/back-bdb2/proto-back-bdb2.h
@@ -179,7 +179,7 @@ void bdb2i_txn_attr_config LDAP_P((
  struct ldbminfo  *li,
  char *attr,
  int open ));
-int bdb2i_txn_open_files LDAP_P(( struct ldbminfo *li ));
+int bdb2i_txn_open_files LDAP_P(( BackendDB *be ));
 void bdb2i_txn_close_files LDAP_P(( BackendDB *be ));
 BDB2_TXN_FILES *bdb2i_get_db_file_cache LDAP_P((
  struct ldbminfo *li,
@@ -191,7 +191,16 @@ void bdb2i_check_default_attr_index_add LDAP_P((
 void bdb2i_check_default_attr_index_mod LDAP_P((
  struct ldbminfo *li,
  LDAPModList *modlist ));
-
+ID bdb2i_get_nextid  LDAP_P(( BackendDB *be ));
+int bdb2i_put_nextid LDAP_P(( BackendDB *be, ID id ));
+int bdb2i_db_store   LDAP_P(( LDBM ldbm, Datum key, Datum data, int flags ));
+int bdb2i_db_delete  LDAP_P(( LDBM ldbm, Datum key ));
+Datum bdb2i_db_fetch LDAP_P(( LDBM ldbm, Datum key ));
+Datum bdb2i_db_firstkey LDAP_P(( LDBM ldbm, DBC **dbch ));
+Datum bdb2i_db_nextkey  LDAP_P(( LDBM ldbm, Datum key, DBC *dbcp ));
+int bdb2i_start_transction   LDAP_P(( DB_TXNMGR *txmgr ));
+int bdb2i_finish_transaction LDAP_P(( ));
+int bdb2i_set_txn_checkpoint LDAP_P(( DB_TXNMGR *txmgr, int forced ));
 
 
 LDAP_END_DECL
diff --git a/servers/slapd/back-bdb2/startup.c b/servers/slapd/back-bdb2/startup.c
index 6f6d73c814ec213fea64ac179588b15c0e466c84..f678f64e7477e4d1461849c72a8df1cc1b7f5870 100644
--- a/servers/slapd/back-bdb2/startup.c
+++ b/servers/slapd/back-bdb2/startup.c
@@ -31,10 +31,14 @@ bdb2i_back_startup_internal(
 )
 {
 	struct ldbtype  *lty = (struct ldbtype *) bi->bi_private;
-	DB_ENV           *dbEnv = lty->lty_dbenv;
-	int    envFlags = DB_CREATE | DB_THREAD | DB_INIT_LOCK | DB_INIT_MPOOL;
-	int    err      = 0;
-	char   *home;
+	DB_ENV          *dbEnv = lty->lty_dbenv;
+	int             envFlags;
+	int             err      = 0;
+	char            *home;
+
+	/*  set the flags for a full-feldged transaction schema  */
+	envFlags = ( DB_CREATE | DB_THREAD | DB_INIT_TXN | DB_INIT_LOG |
+					DB_INIT_LOCK | DB_INIT_MPOOL );
 
 	/*  make sure, dbhome is an absolute path  */
 	if ( *lty->lty_dbhome != *DEFAULT_DIRSEP ) {
@@ -167,7 +171,7 @@ bdb2i_back_db_startup_internal(
 		return 1;
 
 	/*  now open all DB files  */
-	if ( bdb2i_txn_open_files( li ) != 0 )
+	if ( bdb2i_txn_open_files( be ) != 0 )
 		return 1;
 
 	return 0;
diff --git a/servers/slapd/back-bdb2/txn.c b/servers/slapd/back-bdb2/txn.c
index 817678b5df1cd0cbf5c76a73859abbec935d2cbd..7d1ced6b343063697a3c810ad18e1a4e8c1726bc 100644
--- a/servers/slapd/back-bdb2/txn.c
+++ b/servers/slapd/back-bdb2/txn.c
@@ -32,6 +32,13 @@ bdb2i_txn_head_init( BDB2_TXN_HEAD *head )
 
 	}
 
+	/*  set defaults for checkpointing  */
+	head->txn_log  = BDB2_TXN_CHKP_MAX_LOG;
+	head->txn_time = BDB2_TXN_CHKP_MAX_TIME;
+
+	/*  initialize the txn_dirty_mutex  */
+	ldap_pvt_thread_mutex_init( &txn_dirty_mutex );
+
 	return 0;
 }
 
@@ -164,25 +171,37 @@ bdb2i_txn_attr_config(
 	create it (access to the file must be preceeded by a rewind)
 */
 static int
-bdb2i_open_nextid( struct ldbminfo *li )
+bdb2i_open_nextid( BackendDB *be )
 {
+	struct ldbminfo *li = (struct ldbminfo *) be->be_private;
 	BDB2_TXN_HEAD   *head = &li->li_txn_head;
-	FILE            *fp = NULL;
-	char            *file = li->li_nextid_file;
+	LDBM            db = NULL;
+	DB_INFO			dbinfo;
+	DB_ENV			*dbenv = get_dbenv( be );
+	char            fileName[MAXPATHLEN];
+
+	sprintf( fileName, "%s%s%s",
+				li->li_directory, DEFAULT_DIRSEP, NEXTID_NAME );
 
 	/*  try to open the file for read and write  */
-	if ((( fp = fopen( file, "r+" )) == NULL ) &&
-		(( fp = fopen( file, "w+" )) == NULL )) {
+	memset( &dbinfo, 0, sizeof( dbinfo ));
+	dbinfo.db_pagesize  = DEFAULT_DB_PAGE_SIZE;
+	dbinfo.db_malloc    = ldbm_malloc;
+
+	(void) db_open( fileName, DB_RECNO, DB_CREATE | DB_THREAD,
+					li->li_mode, dbenv, &dbinfo, &db );
+
+	if ( db == NULL ) {
 
 			Debug( LDAP_DEBUG_ANY,
 				"bdb2i_open_nextid: could not open \"%s\"\n",
-				file, 0, 0 );
+				NEXTID_NAME, 0, 0 );
 			return( -1 );
 
 	}
 
 	/*  the file is open for read/write  */
-	head->nextidFP = fp;
+	head->nextidFile = db;
 
 	return( 0 );
 }
@@ -192,10 +211,12 @@ bdb2i_open_nextid( struct ldbminfo *li )
 	additional files may be opened during slapd life-time due to
 	default indexes (must be configured in slapd.conf;
 	see bdb2i_txn_attr_config)
+	also, set the counter and timer for TP checkpointing
 */
 int
-bdb2i_txn_open_files( struct ldbminfo *li )
+bdb2i_txn_open_files( BackendDB *be )
 {
+	struct ldbminfo *li = (struct ldbminfo *) be->be_private;
 	BDB2_TXN_HEAD   *head = &li->li_txn_head;
 	BDB2_TXN_FILES  *dbFile;
 	int             rc;
@@ -227,18 +248,12 @@ bdb2i_txn_open_files( struct ldbminfo *li )
 
 	}
 
-	rc = bdb2i_open_nextid( li );
-
-	return rc;
-}
+	rc = bdb2i_open_nextid( be );
 
+	txn_max_pending_log  = head->txn_log;
+	txn_max_pending_time = head->txn_time;
 
-/*  close the NEXTID file  */
-static void
-bdb2i_close_nextid( BDB2_TXN_HEAD *head )
-{
-	fclose( head->nextidFP );
-	head->nextidFP = NULL;
+	return rc;
 }
 
 
@@ -256,7 +271,7 @@ bdb2i_txn_close_files( BackendDB *be )
 
 	}
 
-	bdb2i_close_nextid( head );
+	ldbm_close( head->nextidFile );
 
 }
 
@@ -387,3 +402,385 @@ bdb2i_check_default_attr_index_mod( struct ldbminfo *li, LDAPModList *modlist )
 }
 
 
+/*  get the next ID from the NEXTID file  */
+ID
+bdb2i_get_nextid( BackendDB *be )
+{
+	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
+	BDB2_TXN_HEAD	*head = &li->li_txn_head;
+	ID				id;
+	Datum			key;
+	Datum			data;
+	db_recno_t		rec = NEXTID_RECNO;
+
+	ldbm_datum_init( key );
+	ldbm_datum_init( data );
+
+	key.data = &rec;
+	key.size = sizeof( rec );
+
+	data = bdb2i_db_fetch( head->nextidFile, key );
+	if ( data.data == NULL ) {
+		Debug( LDAP_DEBUG_ANY,
+			"next_id_read: could not get nextid from \"%s\"\n",
+			NEXTID_NAME, 0, 0 );
+		return NOID;
+	}
+
+	id = atol( data.data );
+	ldbm_datum_free( head->nextidFile, data );
+
+	if ( id < 1 ) {
+		Debug( LDAP_DEBUG_ANY,
+			"next_id_read %ld: return non-positive integer\n",
+			id, 0, 0 );
+		return NOID;
+	}
+
+	return( id );
+}
+
+
+int
+bdb2i_put_nextid( BackendDB *be, ID id )
+{
+	struct ldbminfo	*li = (struct ldbminfo *) be->be_private;
+	BDB2_TXN_HEAD	*head = &li->li_txn_head;
+	int				rc, flags;
+	Datum			key;
+	Datum			data;
+	db_recno_t		rec = NEXTID_RECNO;
+	char			buf[20];
+
+	sprintf( buf, "%ld\n", id );
+
+	ldbm_datum_init( key );
+	ldbm_datum_init( data );
+
+	key.data = &rec;
+	key.size = sizeof( rec );
+
+	data.data = &buf;
+	data.size = sizeof( buf );
+
+	flags = LDBM_REPLACE;
+	if ( li->li_dbcachewsync ) flags |= LDBM_SYNC;
+
+	if (( rc = bdb2i_db_store( head->nextidFile, key, data, flags )) != 0 ) {
+		Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): store failed (%d)\n",
+			id, rc, 0 );
+		return( -1 );
+	}
+
+	return( rc );
+}
+
+
+/*  BDB2 backend-private functions of ldbm_store and ldbm_delete  */
+int
+bdb2i_db_store( LDBM ldbm, Datum key, Datum data, int flags )
+{
+	int     rc;
+
+	rc = (*ldbm->put)( ldbm, txnid, &key, &data, flags & ~LDBM_SYNC );
+	rc = (-1 ) * rc;
+
+	if ( txnid != NULL ) {
+
+		/*  if the store was OK, set the dirty flag,
+			otherwise set the abort flag  */
+		if ( rc == 0 ) {
+
+			txn_dirty = 1;
+
+		} else {
+
+			Debug( LDAP_DEBUG_ANY,
+				"bdb2i_db_store: transaction failed: aborted.\n",
+				0, 0, 0 );
+			txn_do_abort = 1;
+
+		}
+	}
+
+	return( rc );
+}
+
+
+int
+bdb2i_db_delete( LDBM ldbm, Datum key )
+{
+	int     rc;
+
+	rc = (*ldbm->del)( ldbm, txnid, &key, 0 );
+	rc = (-1 ) * rc;
+
+	if ( txnid != NULL ) {
+
+		/*  if the delete was OK, set the dirty flag,
+			otherwise set the abort flag  */
+		if ( rc == 0 ) {
+
+			txn_dirty = 1;
+
+		} else {
+
+			Debug( LDAP_DEBUG_ANY,
+				"bdb2i_db_delete: transaction failed: aborted.\n",
+				0, 0, 0 );
+			txn_do_abort = 1;
+
+		}
+	}
+
+	return( rc );
+}
+
+
+Datum
+bdb2i_db_fetch( LDBM ldbm, Datum key )
+{
+	Datum   data;
+	int     rc;
+
+	ldbm_datum_init( data );
+	data.flags = DB_DBT_MALLOC;
+
+	if ( (rc = (*ldbm->get)( ldbm, txnid, &key, &data, 0 )) != 0 ) {
+		if (( txnid != NULL ) && ( rc != DB_NOTFOUND )) {
+
+			Debug( LDAP_DEBUG_ANY,
+				"bdb2i_db_fetch: transaction failed: aborted.\n",
+				0, 0, 0 );
+			txn_do_abort = 1;
+
+		}
+		if ( data.dptr ) free( data.dptr );
+		data.dptr = NULL;
+		data.dsize = 0;
+	}
+
+	return( data );
+}
+
+
+Datum
+bdb2i_db_firstkey( LDBM ldbm, DBC **dbch )
+{
+	Datum	key, data;
+	int		rc;
+	DBC		*dbci;
+
+	ldbm_datum_init( key );
+	ldbm_datum_init( data );
+
+	key.flags = data.flags = DB_DBT_MALLOC;
+
+#if defined( DB_VERSION_MAJOR ) && defined( DB_VERSION_MINOR ) && \
+   DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
+
+	if ( (*ldbm->cursor)( ldbm, txnid, &dbci ))
+
+#else
+
+	if ( (*ldbm->cursor)( ldbm, txnid, &dbci, 0 ))
+
+#endif
+	{
+		if ( txnid != NULL ) {
+
+			Debug( LDAP_DEBUG_ANY,
+				"bdb2i_db_firstkey: transaction failed: aborted.\n",
+				0, 0, 0 );
+			txn_do_abort = 1;
+
+		}
+		return( key );
+	} else {
+		*dbch = dbci;
+		if ( (*dbci->c_get)( dbci, &key, &data, DB_NEXT ) == 0 ) {
+			if ( data.dptr ) free( data.dptr );
+		} else {
+			if ( txnid != NULL ) {
+
+				Debug( LDAP_DEBUG_ANY,
+					"bdb2i_db_firstkey: transaction failed: aborted.\n",
+					0, 0, 0 );
+				txn_do_abort = 1;
+
+			}
+			if ( key.dptr ) free( key.dptr );
+			key.dptr = NULL;
+			key.dsize = 0;
+		}
+	}
+
+	return( key );
+}
+
+
+Datum
+bdb2i_db_nextkey( LDBM ldbm, Datum key, DBC *dbcp )
+{
+	Datum	data;
+	int		rc;
+	void 	*oldKey = key.dptr;
+
+	ldbm_datum_init( data );
+	data.flags = DB_DBT_MALLOC;
+
+	if ( (*dbcp->c_get)( dbcp, &key, &data, DB_NEXT ) == 0 ) {
+		if ( data.dptr ) free( data.dptr );
+	} else {
+		if ( txnid != NULL ) {
+
+			Debug( LDAP_DEBUG_ANY,
+				"bdb2i_db_nextkey: transaction failed: aborted.\n",
+				0, 0, 0 );
+			txn_do_abort = 1;
+
+		}
+		key.dptr = NULL;
+		key.dsize = 0;
+	}
+
+	if ( oldKey ) free( oldKey );
+
+	return( key );
+}
+
+
+/*  Transaction control of write access  */
+/*  Since these functions are only used by one writer at a time,
+	we do not have any concurrency (locking) problem  */
+
+/*  initialize a new transaction  */
+int
+bdb2i_start_transction( DB_TXNMGR *txmgr )
+{
+	int		rc;
+
+	txnid        = NULL;
+	txn_do_abort = 0;
+
+	if (( rc = txn_begin( txmgr, NULL, &txnid )) != 0 ) {
+		Debug( LDAP_DEBUG_ANY, "bdb2i_start_transction failed: %d: errno=%s\n",
+					rc, strerror( errno ), 0 );
+
+		if ( txnid != NULL )
+			(void) txn_abort( txnid );
+		return( -1 );
+	}
+
+	Debug( LDAP_DEBUG_TRACE,
+			"bdb2i_start_transaction: transaction started.\n",
+			0, 0, 0 );
+
+	return( 0 );
+}
+
+
+/*  finish the transaction  */
+int
+bdb2i_finish_transaction()
+{
+	int		rc = 0;
+
+	/*  if transaction was NOT selected, just return  */
+	if ( txnid == NULL ) return( 0 );
+
+	/*  if nothing was wrong so far, we can try to commit the transaction  */
+	/*  complain, if the commit fails  */
+	if (( txn_do_abort == 0 ) && ( txn_commit( txnid )) != 0 ) {
+		Debug( LDAP_DEBUG_ANY,
+			"bdb2i_finish_transaction: transaction commit failed: aborted.\n",
+			0, 0, 0 );
+		txn_do_abort = 1;
+	}
+
+	/*  if anything went wrong, we have to abort the transaction  */
+	if ( txn_do_abort ) {
+		Debug( LDAP_DEBUG_ANY,
+			"bdb2i_finish_transaction: transaction aborted.\n",
+			0, 0, 0 );
+		(void) txn_abort( txnid );
+		rc = -1;
+	} else {
+		Debug( LDAP_DEBUG_TRACE,
+			"bdb2i_finish_transaction: transaction commited.\n",
+			0, 0, 0 );
+	}
+
+	/*  XXX do NOT free the txnid memory !!!  */
+	txnid        = NULL;
+	txn_do_abort = 0;
+
+	return( rc );
+}
+
+
+/*  set a checkpoint
+	either forced (during shutdown) or when logsize or time are exceeded
+	(is called by reader and writer, so protect txn_dirty)
+*/
+int
+bdb2i_set_txn_checkpoint( DB_TXNMGR *txmgr, int forced )
+{
+	int   rc = 0;
+
+	/*  set dirty mutex  */
+	ldap_pvt_thread_mutex_lock( &txn_dirty_mutex );
+
+	if ( txn_dirty ) {
+		int  rc;
+		u_int32_t   logsize;
+		u_int32_t   mins;
+		time_t      now;
+
+		logsize = forced ? (u_int32_t) 0 : txn_max_pending_log;
+		mins    = forced ? (u_int32_t) 0 : txn_max_pending_time;
+
+		ldap_pvt_thread_mutex_lock( &currenttime_mutex );
+		time( &currenttime );
+		now = currenttime;
+		ldap_pvt_thread_mutex_unlock( &currenttime_mutex );
+
+		rc = txn_checkpoint( txmgr, logsize, mins );
+
+		/*  if checkpointing was successful, reset txn_dirty  */
+		if ( rc == 0 ) {
+			DB_TXN_STAT  *statp = NULL;
+
+			/*  check whether the checkpoint was actually written;
+				if so, unset the txn_dirty flag  */
+			if (( rc = txn_stat( txmgr, &statp, ldbm_malloc )) == 0 ) {
+
+				if ( statp && ( statp->st_time_ckp >= now )) {
+
+					Debug( LDAP_DEBUG_TRACE,
+						"bdb2i_set_txn_checkpoint succeded.\n",
+						0, 0, 0 );
+					txn_dirty = 0;
+
+				}
+
+				if ( statp ) free( statp );
+
+			} else {
+				Debug( LDAP_DEBUG_ANY,
+						"bdb2i_set_txn_checkpoint: txn_stat failed: %d\n",
+						rc, 0, 0 );
+			}
+		} else {
+			Debug( LDAP_DEBUG_ANY, "bdb2i_set_txn_checkpoint failed: %d\n",
+					rc, 0, 0 );
+		}
+	}
+
+	/*  release dirty mutex  */
+	ldap_pvt_thread_mutex_unlock( &txn_dirty_mutex );
+
+	return( rc );
+}
+
+
diff --git a/servers/slapd/back-bdb2/txn.h b/servers/slapd/back-bdb2/txn.h
index d701dd555340e35b8064c103da8fe6827b649436..37414e222bc61448d48dd3788a8ce3a9cdb3853e 100644
--- a/servers/slapd/back-bdb2/txn.h
+++ b/servers/slapd/back-bdb2/txn.h
@@ -22,12 +22,27 @@
 
 
 
-#define  BDB2_TXN_CHKP_MAX_CNT     20                   /*  checkpoint every
-                                                            20 transactions */
-#define  BDB2_TXN_CHKP_MAX_TIME    600                  /*  checkpoint after
-                                                            600 seconds     */
+/*  variables for transaction support  */
+DB_TXN                    *txnid       = NULL;
+int                       txn_do_abort = 0;
 
+u_int32_t                 txn_max_pending_log;
+u_int32_t                 txn_max_pending_time;
+int                       txn_dirty = 0;
+ldap_pvt_thread_mutex_t   txn_dirty_mutex;
 
+/*  defaults for checkpointing  */
+#define  BDB2_TXN_CHKP_MAX_LOG     2000    /*  checkpoint every 2MB lock file
+                                               (approx. 20 ADD TXNs)  */
+#define  BDB2_TXN_CHKP_MAX_TIME       5    /*  checkpoint after 5 minutes */
+
+
+/*  the name of the file and the record number of the NEXTID datum  */
+#define NEXTID_NAME    "NEXTID"
+#define NEXTID_RECNO   (db_recno_t) 1
+
+
+/*  default DB files  */
 char  *bdb2i_fixed_filenames[] = {
 
 		"dn", "dn2id", "id2entry", "id2children", "objectclass"
diff --git a/servers/slapd/init.c b/servers/slapd/init.c
index 43af8d0a14d7f7b825a51f78ccc3315a874a012d..dca72737b5b6b507eb64a1fa02ae9f7fa9b490a4 100644
--- a/servers/slapd/init.c
+++ b/servers/slapd/init.c
@@ -84,6 +84,7 @@ slap_init( int mode, char *name )
 		case SLAP_TOOL_MODE:
 #ifdef SLAPD_BDB2
 		case SLAP_TIMEDSERVER_MODE:
+		case SLAP_TOOLID_MODE:
 #endif
 
 			Debug( LDAP_DEBUG_TRACE,
diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h
index e478f2b95d0aec2e381c192b2f1c488970ba86d7..6ba2b25b3ff8511a45ece608b168fc61ebebca25 100644
--- a/servers/slapd/slap.h
+++ b/servers/slapd/slap.h
@@ -232,6 +232,7 @@ extern int			slapMode;
 #define SLAP_TOOL_MODE		2
 #ifdef SLAPD_BDB2
 #  define SLAP_TIMEDSERVER_MODE  3
+#  define SLAP_TOOLID_MODE       4
 #endif
 
 /* temporary aliases */
diff --git a/servers/slapd/tools/ldif2id2entry-bdb2.c b/servers/slapd/tools/ldif2id2entry-bdb2.c
index 38f9b99327f2c48c7dfced35109dfe55049543d8..7b24ec928a004eaaac4487f17d8dd6a5e339cf8b 100644
--- a/servers/slapd/tools/ldif2id2entry-bdb2.c
+++ b/servers/slapd/tools/ldif2id2entry-bdb2.c
@@ -81,7 +81,7 @@ main( int argc, char **argv )
 	 * initialize stuff and figure out which backend we're dealing with
 	 */
 
-	slap_init(SLAP_TOOL_MODE, "ldif2id2entry");
+	slap_init(SLAP_TOOLID_MODE, "ldif2id2entry");
 	read_config( tailorfile );
 
 	if ( dbnum == -1 ) {
@@ -187,18 +187,10 @@ main( int argc, char **argv )
 		}
 	}
 
-	slap_shutdown(dbnum);
-
 	id++;
-	sprintf( line, "%s/NEXTID",
-	    ((struct ldbminfo *) be->be_private)->li_directory );
-	if ( (fp = fopen( line, "w" )) == NULL ) {
-		perror( line );
-		fprintf( stderr, "Could not write next id %ld\n", id );
-	} else {
-		fprintf( fp, "%ld\n", id );
-		fclose( fp );
-	}
+	bdb2i_put_nextid( be, id );
+
+	slap_shutdown(dbnum);
 
 	slap_destroy();
 
diff --git a/tests/data/slapd-bdb2-repl-slave.conf b/tests/data/slapd-bdb2-repl-slave.conf
index 81f7caaba36ae685f7a2af2122bad167e67c54ff..fee73745412d268ae78809bb27d234810b50d604 100644
--- a/tests/data/slapd-bdb2-repl-slave.conf
+++ b/tests/data/slapd-bdb2-repl-slave.conf
@@ -12,7 +12,7 @@ argsfile    ./test-repl/slapd.args
 #######################################################################
 
 backend     bdb2
-home        ./test-db
+home        ./test-repl
 
 database	bdb2
 suffix		"o=University of Michigan, c=US"