#include "back-bdb.h"
+#include "config.h"
+
+#include "lutil.h"
+
#ifdef DB_DIRTY_READ
# define SLAP_BDB_ALLOW_DIRTY_READ
#endif
-int
-bdb_db_config(
- BackendDB *be,
- const char *fname,
- int lineno,
- int argc,
- char **argv )
-{
- struct bdb_info *bdb = (struct bdb_info *) be->be_private;
+static ObjectClass *bdb_oc;
- if ( bdb == NULL ) {
- fprintf( stderr, "%s: line %d: "
- "bdb database info is null!\n",
- fname, lineno );
- return 1;
- }
+static ConfigDriver bdb_cf_oc, bdb_cf_gen;
- /* directory is the DB_HOME */
- if ( strcasecmp( argv[0], "directory" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr, "%s: line %d: "
- "missing dir in \"directory <dir>\" line\n",
- fname, lineno );
- return 1;
- }
- if ( bdb->bi_dbenv_home ) {
- free( bdb->bi_dbenv_home );
- }
- bdb->bi_dbenv_home = ch_strdup( argv[1] );
+enum {
+ BDB_CHKPT = 1,
+ BDB_CONFIG,
+ BDB_DIRECTORY,
+ BDB_NOSYNC,
+ BDB_DIRTYR,
+ BDB_INDEX,
+ BDB_LOCKD,
+ BDB_SSTACK
+};
+static ConfigTable bdbcfg[] = {
+ { "", "", 0, 0, 0, ARG_MAGIC,
+ bdb_cf_oc, NULL, NULL, NULL },
+ { "directory", "dir", 2, 2, 0, ARG_STRING|ARG_MAGIC|BDB_DIRECTORY,
+ bdb_cf_gen, "( OLcfgAt:1.1 NAME 'dbDirectory' "
+ "DESC 'Directory for database content' "
+ "EQUALITY caseIgnoreMatch "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { "cachesize", "size", 2, 2, 0, ARG_INT|ARG_OFFSET,
+ (void *)offsetof(struct bdb_info, bi_cache.c_maxsize),
+ "( OLcfgAt:1.2 NAME 'dbCacheSize' "
+ "DESC 'Entry cache size in entries' "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { "checkpoint", "kbyte> <min", 3, 3, 0, ARG_MAGIC|BDB_CHKPT,
+ bdb_cf_gen, "( OLcfgAt:1.3 NAME 'dbCheckpoint' "
+ "DESC 'Database checkpoint interval in kbytes and minutes' "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )",NULL, NULL },
+ { "dbconfig", "DB_CONFIG setting", 3, 0, 0, ARG_MAGIC|BDB_CONFIG,
+ bdb_cf_gen, "( OLcfgAt:1.13 NAME 'dbConfig' "
+ "DESC 'BerkeleyDB DB_CONFIG configuration directives' "
+ "SYNTAX OMsDirectoryString )",NULL, NULL },
+ { "dbnosync", NULL, 1, 2, 0, ARG_ON_OFF|ARG_MAGIC|BDB_NOSYNC,
+ bdb_cf_gen, "( OLcfgAt:1.4 NAME 'dbNoSync' "
+ "DESC 'Disable synchronous database writes' "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "dirtyread", NULL, 1, 2, 0,
#ifdef SLAP_BDB_ALLOW_DIRTY_READ
- } else if ( strcasecmp( argv[0], "dirtyread" ) == 0 ) {
- bdb->bi_db_opflags |= DB_DIRTY_READ;
-#endif
- /* transaction logging configuration */
- } else if ( strcasecmp( argv[0], "dbnosync" ) == 0 ) {
- bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC;
-
- /* slapadd/slapindex logging configuration */
- } else if ( strcasecmp( argv[0], "fasttool" ) == 0 ) {
- if ( slapMode & SLAP_TOOL_MODE )
-#if DB_VERSION_FULL >= 0x04030015
- bdb->bi_dbenv_xflags |= DB_LOG_INMEMORY;
+ ARG_ON_OFF|ARG_MAGIC|BDB_DIRTYR, bdb_cf_gen,
#else
- bdb->bi_dbenv_xflags |= DB_TXN_NOT_DURABLE;
+ ARG_IGNORED, NULL,
#endif
+ "( OLcfgAt:1.5 NAME 'dbDirtyRead' "
+ "DESC 'Allow reads of uncommitted data' "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "idlcachesize", "size", 2, 2, 0, ARG_INT|ARG_OFFSET,
+ (void *)offsetof(struct bdb_info,bi_idl_cache_max_size),
+ "( OLcfgAt:1.6 NAME 'dbIDLcacheSize' "
+ "DESC 'IDL cache size in IDLs' "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { "index", "attr> <[pres,eq,approx,sub]", 3, 3, 0, ARG_MAGIC|BDB_INDEX,
+ bdb_cf_gen, "( OLcfgAt:1.7 NAME 'dbIndex' "
+ "DESC 'Attribute index parameters' "
+ "SYNTAX OMsDirectoryString )", NULL, NULL },
+ { "linearindex", NULL, 1, 2, 0, ARG_ON_OFF|ARG_OFFSET,
+ (void *)offsetof(struct bdb_info, bi_linear_index),
+ "( OLcfgAt:1.8 NAME 'dbLinearIndex' "
+ "DESC 'Index attributes one at a time' "
+ "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },
+ { "lockdetect", "policy", 2, 2, 0, ARG_MAGIC|BDB_LOCKD,
+ bdb_cf_gen, "( OLcfgAt:1.9 NAME 'dbLockDetect' "
+ "DESC 'Deadlock detection algorithm' "
+ "SYNTAX OMsDirectoryString SINGLE-VALUE )", NULL, NULL },
+ { "mode", "mode", 2, 2, 0, ARG_INT|ARG_OFFSET,
+ (void *)offsetof(struct bdb_info, bi_dbenv_mode),
+ "( OLcfgAt:1.10 NAME 'dbMode' "
+ "DESC 'Unix permissions of database files' "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { "searchstack", "depth", 2, 2, 0, ARG_INT|ARG_MAGIC|BDB_SSTACK,
+ bdb_cf_gen, "( OLcfgAt:1.11 NAME 'dbSearchStack' "
+ "DESC 'Depth of search stack in IDLs' "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { "shm_key", "key", 2, 2, 0, ARG_INT|ARG_OFFSET,
+ (void *)offsetof(struct bdb_info, bi_shm_key),
+ "( OLcfgAt:1.12 NAME 'dbShmKey' "
+ "DESC 'Key for shared memory region' "
+ "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },
+ { NULL, NULL, 0, 0, 0, ARG_IGNORED,
+ NULL, NULL, NULL, NULL }
+};
- /* slapindex algorithm tuning */
- } else if ( strcasecmp( argv[0], "linearindex" ) == 0 ) {
- bdb->bi_linear_index = 1;
+static ConfigOCs bdbocs[] = {
+ { "( OLcfgOc:1.1 "
+ "NAME 'bdbConfig' "
+ "DESC 'BDB backend configuration' "
+ "SUP olcDatabaseConfig "
+ "MUST dbDirectory "
+ "MAY ( dbCacheSize $ dbCheckpoint $ dbConfig $ dbNoSync $ "
+ "dbDirtyRead $ dbIDLcacheSize $ dbIndex $ dbLinearIndex $ "
+ "dbLockDetect $ dbMode $ dbSearchStack $ dbShmKey ) )",
+ Cft_Database, &bdb_oc },
+ { NULL, 0, NULL }
+};
- /* transaction checkpoint configuration */
- } else if ( strcasecmp( argv[0], "checkpoint" ) == 0 ) {
- if ( argc < 3 ) {
- fprintf( stderr, "%s: line %d: "
- "missing parameters in \"checkpoint <kbyte> <min>\" line\n",
- fname, lineno );
- return 1;
- }
- bdb->bi_txn_cp = 1;
- bdb->bi_txn_cp_kbyte = strtol( argv[1], NULL, 0 );
- bdb->bi_txn_cp_min = strtol( argv[2], NULL, 0 );
-
- /* lock detect configuration */
- } else if ( strcasecmp( argv[0], "lockdetect" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr, "%s: line %d: "
- "missing parameters in \"lockDetect <policy>\" line\n",
- fname, lineno );
- return 1;
- }
+static int
+bdb_cf_oc(ConfigArgs *c)
+{
+ if ( c->op == SLAP_CONFIG_EMIT ) {
+ value_add_one( &c->rvalue_vals, &bdb_oc->soc_cname );
+ return 0;
+ }
+ return 1;
+}
- if( strcasecmp( argv[1], "default" ) == 0 ) {
- bdb->bi_lock_detect = DB_LOCK_DEFAULT;
+static slap_verbmasks bdb_lockd[] = {
+ { BER_BVC("default"), DB_LOCK_DEFAULT },
+ { BER_BVC("oldest"), DB_LOCK_OLDEST },
+ { BER_BVC("random"), DB_LOCK_RANDOM },
+ { BER_BVC("youngest"), DB_LOCK_YOUNGEST },
+ { BER_BVC("fewest"), DB_LOCK_MINLOCKS },
+ { BER_BVNULL, 0 }
+};
- } else if( strcasecmp( argv[1], "oldest" ) == 0 ) {
- bdb->bi_lock_detect = DB_LOCK_OLDEST;
+static int
+bdb_cf_gen(ConfigArgs *c)
+{
+ struct bdb_info *bdb = c->be->be_private;
+ int rc;
- } else if( strcasecmp( argv[1], "random" ) == 0 ) {
- bdb->bi_lock_detect = DB_LOCK_RANDOM;
+ if ( c->op == SLAP_CONFIG_EMIT ) {
+ rc = 0;
+ switch( c->type ) {
+ case BDB_CHKPT:
+ if (bdb->bi_txn_cp ) {
+ char buf[64];
+ struct berval bv;
+ bv.bv_len = sprintf( buf, "%d %d", bdb->bi_txn_cp_kbyte,
+ bdb->bi_txn_cp_min );
+ bv.bv_val = buf;
+ value_add_one( &c->rvalue_vals, &bv );
+ } else{
+ rc = 1;
+ }
+ break;
- } else if( strcasecmp( argv[1], "youngest" ) == 0 ) {
- bdb->bi_lock_detect = DB_LOCK_YOUNGEST;
+ case BDB_DIRECTORY:
+ if ( bdb->bi_dbenv_home ) {
+ c->value_string = ch_strdup( bdb->bi_dbenv_home );
+ } else {
+ rc = 1;
+ }
+ break;
- } else if( strcasecmp( argv[1], "fewest" ) == 0 ) {
- bdb->bi_lock_detect = DB_LOCK_MINLOCKS;
+ case BDB_CONFIG:
+ if ( bdb->bi_db_config ) {
+ int i;
+ struct berval bv;
- } else {
- fprintf( stderr, "%s: line %d: "
- "bad policy (%s) in \"lockDetect <policy>\" line\n",
- fname, lineno, argv[1] );
- return 1;
+ bv.bv_val = c->log;
+ for (i=0; !BER_BVISNULL(&bdb->bi_db_config[i]); i++) {
+ bv.bv_len = sprintf( bv.bv_val, "{%d}%s", i,
+ bdb->bi_db_config[i].bv_val );
+ value_add_one( &c->rvalue_vals, &bv );
+ }
+ }
+ if ( !c->rvalue_vals ) rc = 1;
+ break;
+
+ case BDB_NOSYNC:
+ if ( bdb->bi_dbenv_xflags & DB_TXN_NOSYNC )
+ c->value_int = 1;
+ break;
+
+ case BDB_INDEX:
+ bdb_attr_index_unparse( bdb, &c->rvalue_vals );
+ if ( !c->rvalue_vals ) rc = 1;
+ break;
+
+ case BDB_LOCKD:
+ rc = 1;
+ if ( bdb->bi_lock_detect != DB_LOCK_DEFAULT ) {
+ int i;
+ for (i=0; !BER_BVISNULL(&bdb_lockd[i].word); i++) {
+ if ( bdb->bi_lock_detect == bdb_lockd[i].mask ) {
+ value_add_one( &c->rvalue_vals, &bdb_lockd[i].word );
+ rc = 0;
+ break;
+ }
+ }
+ }
+ break;
+
+ case BDB_SSTACK:
+ c->value_int = bdb->bi_search_stack_depth;
+ break;
}
+ return rc;
+ }
+ switch( c->type ) {
+ case BDB_CHKPT:
+ bdb->bi_txn_cp = 1;
+ bdb->bi_txn_cp_kbyte = strtol( c->argv[1], NULL, 0 );
+ bdb->bi_txn_cp_min = strtol( c->argv[2], NULL, 0 );
+ break;
- /* mode with which to create new database files */
- } else if ( strcasecmp( argv[0], "mode" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr, "%s: line %d: "
- "missing mode in \"mode <mode>\" line\n",
- fname, lineno );
- return 1;
+ case BDB_CONFIG: {
+ char *ptr = c->line + STRLENOF("dbconfig");
+ struct berval bv;
+ while (!isspace(*ptr)) ptr++;
+ while (isspace(*ptr)) ptr++;
+
+ /* If we're just starting up...
+ */
+ if ( !bdb->bi_db_is_open ) {
+ FILE *f;
+ /* If a DB_CONFIG file exists, or we don't know the path
+ * to the DB_CONFIG file, ignore these directives
+ */
+ if ( bdb->bi_db_has_config || !bdb->bi_db_config_path )
+ break;
+ f = fopen( bdb->bi_db_config_path, "a" );
+ if ( f ) {
+ /* FIXME: EBCDIC probably needs special handling */
+ fprintf( f, "%s\n", ptr );
+ fclose( f );
+ }
}
- bdb->bi_dbenv_mode = strtol( argv[1], NULL, 0 );
-
- /* attribute to index */
- } else if ( strcasecmp( argv[0], "index" ) == 0 ) {
- int rc;
- if ( argc < 2 ) {
- fprintf( stderr, "%s: line %d: "
- "missing attr in \"index <attr> [pres,eq,approx,sub]\" line\n",
- fname, lineno );
- return 1;
- } else if ( argc > 3 ) {
- fprintf( stderr, "%s: line %d: "
- "extra junk after \"index <attr> [pres,eq,approx,sub]\" "
- "line (ignored)\n",
- fname, lineno );
+ ber_str2bv( ptr, 0, 1, &bv );
+ ber_bvarray_add( &bdb->bi_db_config, &bv );
}
- rc = bdb_attr_index_config( bdb, fname, lineno, argc - 1, &argv[1] );
+ break;
- if( rc != LDAP_SUCCESS ) return 1;
+ case BDB_DIRECTORY: {
+ FILE *f;
+ char *ptr;
- /* unique key for shared memory regions */
- } else if ( strcasecmp( argv[0], "shm_key" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr,
- "%s: line %d: missing key in \"shm_key <key>\" line\n",
- fname, lineno );
- return( 1 );
- }
- bdb->bi_shm_key = atoi( argv[1] );
+ bdb->bi_dbenv_home = c->value_string;
- /* size of the cache in entries */
- } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr,
- "%s: line %d: missing size in \"cachesize <size>\" line\n",
- fname, lineno );
- return( 1 );
- }
- bdb->bi_cache.c_maxsize = atoi( argv[1] );
+ /* See if a DB_CONFIG file already exists here */
+ bdb->bi_db_config_path = ch_malloc( strlen( bdb->bi_dbenv_home ) +
+ STRLENOF(LDAP_DIRSEP) + STRLENOF("DB_CONFIG"));
+ ptr = lutil_strcopy( bdb->bi_db_config_path, bdb->bi_dbenv_home );
+ *ptr++ = LDAP_DIRSEP[0];
+ strcpy( ptr, "DB_CONFIG" );
- /* depth of search stack cache in units of (IDL)s */
- } else if ( strcasecmp( argv[0], "searchstack" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr,
- "%s: line %d: missing depth in \"searchstack <depth>\" line\n",
- fname, lineno );
- return( 1 );
+ f = fopen( bdb->bi_db_config_path, "r" );
+ if ( f ) {
+ bdb->bi_db_has_config = 1;
+ fclose(f);
}
- bdb->bi_search_stack_depth = atoi( argv[1] );
- if ( bdb->bi_search_stack_depth < MINIMUM_SEARCH_STACK_DEPTH ) {
- fprintf( stderr,
- "%s: line %d: depth %d too small, using %d\n",
- fname, lineno, bdb->bi_search_stack_depth,
- MINIMUM_SEARCH_STACK_DEPTH );
- bdb->bi_search_stack_depth = MINIMUM_SEARCH_STACK_DEPTH;
}
+ break;
- /* size of the IDL cache in entries */
- } else if ( strcasecmp( argv[0], "idlcachesize" ) == 0 ) {
- if ( argc < 2 ) {
- fprintf( stderr,
- "%s: line %d: missing size in \"idlcachesize <size>\" line\n",
- fname, lineno );
- return( 1 );
- }
- if ( !( slapMode & SLAP_TOOL_MODE ) )
- bdb->bi_idl_cache_max_size = atoi( argv[1] );
-#ifdef BDB_PSEARCH
- } else if ( strcasecmp( argv[0], "sessionlog" ) == 0 ) {
- int se_id = 0, se_size = 0;
- struct slap_session_entry *sent;
- if ( argc < 3 ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: line %d: missing arguments in \"sessionlog <id> <size>\""
- " line\n", fname, lineno, 0 );
- return( 1 );
- }
+ case BDB_NOSYNC:
+ if ( c->value_int )
+ bdb->bi_dbenv_xflags |= DB_TXN_NOSYNC;
+ else
+ bdb->bi_dbenv_xflags &= ~DB_TXN_NOSYNC;
+ break;
- se_id = atoi( argv[1] );
+ case BDB_INDEX:
+ rc = bdb_attr_index_config( bdb, c->fname, c->lineno,
+ c->argc - 1, &c->argv[1] );
- if ( se_id < 0 || se_id > 999 ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: line %d: session log id %d is out of range [0..999]\n",
- fname, lineno , se_id );
- return( 1 );
- }
+ if( rc != LDAP_SUCCESS ) return 1;
+ break;
- se_size = atoi( argv[2] );
- if ( se_size < 0 ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: line %d: session log size %d is negative\n",
- fname, lineno , se_size );
- return( 1 );
+ case BDB_LOCKD:
+ rc = verb_to_mask( c->argv[1], bdb_lockd );
+ if ( BER_BVISNULL(&bdb_lockd[rc].word) ) {
+ fprintf( stderr, "%s: "
+ "bad policy (%s) in \"lockDetect <policy>\" line\n",
+ c->log, c->argv[1] );
+ return 1;
}
+ bdb->bi_lock_detect = rc;
+ break;
- LDAP_LIST_FOREACH( sent, &bdb->bi_session_list, se_link ) {
- if ( sent->se_id == se_id ) {
- Debug( LDAP_DEBUG_ANY,
- "%s: line %d: session %d already exists\n",
- fname, lineno , se_id );
- return( 1 );
- }
+ case BDB_SSTACK:
+ if ( c->value_int < MINIMUM_SEARCH_STACK_DEPTH ) {
+ fprintf( stderr,
+ "%s: depth %d too small, using %d\n",
+ c->log, c->value_int, MINIMUM_SEARCH_STACK_DEPTH );
+ c->value_int = MINIMUM_SEARCH_STACK_DEPTH;
}
- sent = (struct slap_session_entry *) ch_calloc( 1,
- sizeof( struct slap_session_entry ));
- sent->se_id = se_id;
- sent->se_size = se_size;
- LDAP_LIST_INSERT_HEAD( &bdb->bi_session_list, sent, se_link );
-#endif /* BDB_PSEARCH */
- /* anything else */
- } else {
- return SLAP_CONF_UNKNOWN;
+ bdb->bi_search_stack_depth = c->value_int;
+ break;
}
+ return 0;
+}
+
+int bdb_back_init_cf( BackendInfo *bi )
+{
+ int rc;
+ bi->bi_cf_table = bdbcfg;
+ rc = config_register_schema( bdbcfg, bdbocs );
+ if ( rc ) return rc;
+ bdbcfg[0].ad = slap_schema.si_ad_objectClass;
return 0;
}