]> git.sur5r.net Git - openldap/commitdiff
Introduction of first version of transaction processing (TP) into BDB2.
authorKurt Spanier <ksp@openldap.org>
Mon, 1 Mar 1999 11:30:18 +0000 (11:30 +0000)
committerKurt Spanier <ksp@openldap.org>
Mon, 1 Mar 1999 11:30:18 +0000 (11:30 +0000)
16 files changed:
servers/slapd/back-bdb2/add.c
servers/slapd/back-bdb2/back-bdb2.h
servers/slapd/back-bdb2/close.c
servers/slapd/back-bdb2/dbcache.c
servers/slapd/back-bdb2/idl.c
servers/slapd/back-bdb2/modify.c
servers/slapd/back-bdb2/nextid.c
servers/slapd/back-bdb2/porter.c
servers/slapd/back-bdb2/proto-back-bdb2.h
servers/slapd/back-bdb2/startup.c
servers/slapd/back-bdb2/txn.c
servers/slapd/back-bdb2/txn.h
servers/slapd/init.c
servers/slapd/slap.h
servers/slapd/tools/ldif2id2entry-bdb2.c
tests/data/slapd-bdb2-repl-slave.conf

index e04f77591fc66852c28001e61335f1c0ff029257..2383e5979f55d18e907312661dda2d80cca2812b 100644 (file)
@@ -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;
        }
index f7d7e589055370502c4165c4023503ff009675b7..a40c4f5195fa6171d116546ca30f76cec058ac00 100644 (file)
@@ -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;
index 9a78f07ab17a239e31f239b4e7d0271ab626fae5..2d573533b63fa57b8171e1b92265c2d798d4fff0 100644 (file)
 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 );
index 405e9e924dd779b52314464758b1e2c0e45f73c8..1e303b37985dc8f2ba082ab6fce698645024619b 100644 (file)
@@ -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 );
 }
index d82078b3f77efc7bae2a6c77d851c4bbe02f41d2..3b8f1bd24c77e1aaa9d4e5c85244b758465ffecb 100644 (file)
@@ -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 );
        }
index 3178f66985e83c309c279bbc419891674b5b7d1c..f638aa7059b197bebb2c85e76d48b305cbdb2a9d 100644 (file)
@@ -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;
        }
index 4021b8e473f968ecd30d59e0716a7d0a97d823ff..88121201ca81878a5b9f38046e1d510eb46a14e0 100644 (file)
 #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;
        }
index 96f0576d471da674287f5556da24dce35671e7af..d28e0f9ed96fb6fc38f387a9eccffde787267f1e 100644 (file)
@@ -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 );
 }
 
 
index 5020e531c09381d8f087a46e926bb8ae93b3a7fd..cd5fa7852d72242512427d6608b51bbfcc13f02b 100644 (file)
@@ -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
index 6f6d73c814ec213fea64ac179588b15c0e466c84..f678f64e7477e4d1461849c72a8df1cc1b7f5870 100644 (file)
@@ -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;
index 817678b5df1cd0cbf5c76a73859abbec935d2cbd..7d1ced6b343063697a3c810ad18e1a4e8c1726bc 100644 (file)
@@ -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 );
+}
+
+
index d701dd555340e35b8064c103da8fe6827b649436..37414e222bc61448d48dd3788a8ce3a9cdb3853e 100644 (file)
 
 
 
-#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"
index 43af8d0a14d7f7b825a51f78ccc3315a874a012d..dca72737b5b6b507eb64a1fa02ae9f7fa9b490a4 100644 (file)
@@ -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,
index e478f2b95d0aec2e381c192b2f1c488970ba86d7..6ba2b25b3ff8511a45ece608b168fc61ebebca25 100644 (file)
@@ -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 */
index 38f9b99327f2c48c7dfced35109dfe55049543d8..7b24ec928a004eaaac4487f17d8dd6a5e339cf8b 100644 (file)
@@ -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();
 
index 81f7caaba36ae685f7a2af2122bad167e67c54ff..fee73745412d268ae78809bb27d234810b50d604 100644 (file)
@@ -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"