From: Kurt Spanier Date: Mon, 1 Mar 1999 11:30:18 +0000 (+0000) Subject: Introduction of first version of transaction processing (TP) into BDB2. X-Git-Tag: OPENLDAP_SLAPD_BACK_LDAP~537 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=5d2699b7ce4bce0b4848fc6274c9f0c15a7264d1;p=openldap Introduction of first version of transaction processing (TP) into BDB2. --- diff --git a/servers/slapd/back-bdb2/add.c b/servers/slapd/back-bdb2/add.c index e04f77591f..2383e5979f 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 f7d7e58905..a40c4f5195 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 9a78f07ab1..2d573533b6 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 405e9e924d..1e303b3798 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 d82078b3f7..3b8f1bd24c 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 3178f66985..f638aa7059 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 4021b8e473..88121201ca 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 96f0576d47..d28e0f9ed9 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 5020e531c0..cd5fa7852d 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 6f6d73c814..f678f64e74 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 817678b5df..7d1ced6b34 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( ¤ttime_mutex ); + time( ¤ttime ); + now = currenttime; + ldap_pvt_thread_mutex_unlock( ¤ttime_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 d701dd5553..37414e222b 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 43af8d0a14..dca72737b5 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 e478f2b95d..6ba2b25b3f 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 38f9b99327..7b24ec928a 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 81f7caaba3..fee7374541 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"