environments.
Added slapd modrdn children check (ITS#1053,1192)
Added slapd sb_max_incoming_auth support (ITS#1181)
Added slapd crypt salt format support (ITS#1202)
+ Added slapd subtree replication support
Added slurpd include support (ITS#121)
Added -lldap critical client control checks
+ Added ldbm sync daemon support
+ Added ldbm per-backend db_env support
Updated slapd schema check handling
- Updated ldbm to use BerkeleyDB's CDB (ITS#1176)
- Updated ldbm error handling
Updated slapd filter checks
Updated slapd single-value checks
+ Updated ldbm to use BerkeleyDB's CDB (ITS#1176)
+ Updated ldbm error handling
Updated ldaptcl API (contrib)
Updated -lldap sasl/tls referral handling
Updated -lldap pthread code
#include <ldap_cdefs.h>
+/* dummy DB_ENV for non Berkeley DB */
+#if !defined( LDBM_USE_DBBTREE ) && !defined( LDBM_USE_DBHASH )
+# define DB_ENV void
+#endif
+
#if defined( LDBM_USE_DBBTREE ) || defined( LDBM_USE_DBHASH )
/*****************************************************************
# ifndef DEFAULT_DB_PAGE_SIZE
# define DEFAULT_DB_PAGE_SIZE 4096
# endif
+#else
+# define DB_ENV void
#endif
LDAP_LDBM_F (int) ldbm_initialize( const char * );
LDAP_LDBM_F (int) ldbm_shutdown( void );
+LDAP_LDBM_F (DB_ENV*) ldbm_initialize_env(const char *, int dbcachesize, int *envdirok);
+LDAP_LDBM_F (void) ldbm_shutdown_env(DB_ENV *);
+
LDAP_LDBM_F (int) ldbm_errno( LDBM ldbm );
-LDAP_LDBM_F (LDBM) ldbm_open( char *name, int rw, int mode, int dbcachesize );
+LDAP_LDBM_F (LDBM) ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize );
LDAP_LDBM_F (void) ldbm_close( LDBM ldbm );
LDAP_LDBM_F (void) ldbm_sync( LDBM ldbm );
LDAP_LDBM_F (void) ldbm_datum_free( LDBM ldbm, Datum data );
#define LDBM_UNLOCK (ldap_pvt_thread_mutex_unlock(&ldbm_big_mutex))
#endif
+#if !defined( HAVE_BERKELEY_DB ) || (DB_VERSION_MAJOR < 3)
+ /* a dbEnv for BERKELEYv2 */
+DB_ENV *ldbm_Env = NULL; /* real or fake, depending on db and version */
+#endif
+
/*******************************************************************
* *
#endif
}
-/* a dbEnv for BERKELEYv2 */
-DB_ENV *ldbm_Env = NULL;
+#if DB_VERSION_MAJOR < 3
int ldbm_initialize( const char* home )
{
ldap_pvt_thread_mutex_init( &ldbm_big_mutex );
#endif
-#if DB_VERSION_MAJOR < 3
ldbm_Env = calloc( 1, sizeof( DB_ENV ));
if( ldbm_Env == NULL ) return 1;
ldbm_Env->db_errcall = ldbm_db_errcall;
ldbm_Env->db_errpfx = "==>";
-#else
- ldbm_Env = NULL;
-#endif
envFlags = DB_CREATE;
#endif
#endif
-#if DB_VERSION_MAJOR >= 3
- err = db_env_create( &ldbm_Env, 0 );
-#else
envFlags |= DB_USE_ENVIRON;
err = db_appinit( home, NULL, ldbm_Env, envFlags );
-#endif
if ( err ) {
#ifdef LDAP_SYSLOG
sprintf( error, "%s (%d)\n", STRERROR( err ), err );
syslog( LOG_INFO,
-#if DB_VERSION_MAJOR >= 3
- "ldbm_initialize(): FATAL error in db_env_create() : %s\n",
-#else
"ldbm_initialize(): FATAL error in db_appinit() : %s\n",
-#endif
error );
#endif
return( 1 );
}
-#if DB_VERSION_MAJOR > 2
- ldbm_Env->set_errcall( ldbm_Env, ldbm_db_errcall );
- ldbm_Env->set_errpfx( ldbm_Env, "==>" );
-
-#ifdef HAVE_BERKELEY_DB_THREAD
- envFlags |= DB_INIT_CDB | DB_INIT_MPOOL;
-#endif
- envFlags |= DB_USE_ENVIRON;
-
-#if (DB_VERSION_MAJOR > 3) || (DB_VERSION_MINOR >= 1)
- err = ldbm_Env->open( ldbm_Env, home, envFlags, 0 );
-#else
- err = ldbm_Env->open( ldbm_Env, home, NULL, envFlags, 0 );
-#endif
-
- if ( err != 0 ) {
-#ifdef LDAP_SYSLOG
- char error[BUFSIZ];
-
- sprintf( error, "%s (%d)\n", STRERROR( err ), err );
- syslog( LOG_INFO,
- "ldbm_initialize(): FATAL error in dbEnv->open() : %s\n",
- error );
-#endif
- ldbm_Env->close( ldbm_Env, 0 );
- return( 1 );
- }
-#endif
-
return 0;
}
{
if( !ldbm_initialized ) return 1;
-#if DB_VERSION_MAJOR >= 3
- ldbm_Env->close( ldbm_Env, 0 );
-#else
db_appexit( ldbm_Env );
-#endif
#ifndef HAVE_BERKELEY_DB_THREAD
ldap_pvt_thread_mutex_destroy( &ldbm_big_mutex );
return 0;
}
+#else /* Berkeley v3 or greater */
+
+
+int ldbm_initialize( const char * home )
+{
+ /* v3 uses ldbm_initialize_env */
+ return 0;
+}
+
+
+int ldbm_shutdown( void )
+{
+ return 0;
+}
+
+
+#endif
+
+
+
#else /* some DB other than Berkeley V2 or greater */
int ldbm_initialize( const char * home )
#endif /* HAVE_BERKELEY_DB */
+#if defined( HAVE_BERKELEY_DB ) && (DB_VERSION_MAJOR >= 3)
+
+
+DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
+{
+ DB_ENV *env = NULL;
+ int err;
+ u_int32_t envFlags;
+
+ envFlags =
+#if defined( DB_PRIVATE ) /* comment out DB_PRIVATE setting to use */
+ DB_PRIVATE | /* db_stat to view cache behavior */
+#endif
+#if defined( HAVE_BERKELEY_DB_THREAD )
+ DB_THREAD |
+#endif
+ DB_CREATE;
+
+ err = db_env_create( &env, 0 );
+
+ if ( err ) {
+ char error[BUFSIZ];
+
+ sprintf( error, "%s (%d)\n", STRERROR( err ), err );
+
+#ifdef LDAP_SYSLOG
+ syslog( LOG_INFO, "ldbm_initialize_env(): FATAL error in db_env_create() : %s\n", error );
+#endif
+ return( NULL );
+ }
+
+ env->set_errcall( env, ldbm_db_errcall );
+ env->set_errpfx( env, "==>" );
+ if (dbcachesize)
+ env->set_cachesize( env, 0, dbcachesize, 0 );
+
+ envFlags |= DB_INIT_MPOOL | DB_INIT_CDB | DB_USE_ENVIRON;
+
+ err = env->open( env, home, envFlags, 0 );
+
+ if ( err != 0 )
+ {
+ char error[BUFSIZ];
+
+ sprintf( error, "%s (%d)\n", STRERROR( err ), err );
+
+#ifdef LDAP_SYSLOG
+ syslog( LOG_INFO,
+ "ldbm_initialize_env(): FATAL error in dbEnv->open() : %s\n",
+ error );
+#endif
+ env->close( env, 0 );
+ return( NULL );
+ }
+
+ *envdirok = 1;
+ return env;
+}
+
+void ldbm_shutdown_env(DB_ENV *env)
+{
+ env->close( env, 0 );
+}
+
+
+#else
+
+DB_ENV *ldbm_initialize_env(const char *home, int dbcachesize, int *envdirok)
+{
+ return ldbm_Env;
+}
+
+void ldbm_shutdown_env(DB_ENV *env)
+{
+}
+
+
+#endif
+
+
#if defined( LDBM_USE_DBHASH ) || defined( LDBM_USE_DBBTREE )
/*****************************************************************
*****************************************************************/
LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
{
LDBM ret = NULL;
LDBM_LOCK;
- err = db_create( &ret, ldbm_Env, 0 );
+ err = db_create( &ret, env, 0 );
if ( err != 0 ) {
(void)ret->close(ret, 0);
LDBM_UNLOCK;
ret->set_pagesize( ret, DEFAULT_DB_PAGE_SIZE );
ret->set_malloc( ret, ldbm_malloc );
+ /* ret->set_cachesize( ret, 0, dbcachesize, 0 ); */
err = ret->open( ret, name, NULL, DB_TYPE, rw, mode);
*****************************************************************/
LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
{
LDBM db;
#ifdef HAVE_ST_BLKSIZE
*****************************************************************/
LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
{
LDBM db;
/* ARGSUSED */
LDBM
-ldbm_open( char *name, int rw, int mode, int dbcachesize )
+ldbm_open( DB_ENV *env, char *name, int rw, int mode, int dbcachesize )
{
LDBM ldbm;
DBCache li_dbcache[MAXDBCACHE];
ldap_pvt_thread_mutex_t li_dbcache_mutex;
ldap_pvt_thread_cond_t li_dbcache_cv;
+ DB_ENV *li_dbenv;
+ int li_envdirok;
+ int li_dbsyncfreq;
+ int li_dbsyncwaitn;
+ int li_dbsyncwaitinterval;
+ ldap_pvt_thread_t li_dbsynctid;
+ int li_dbshutdown;
};
LDAP_END_DECL
{
li->li_dbwritesync = 0;
+ /* run sync thread */
+ } else if ( strcasecmp( argv[0], "dbsync" ) == 0 ) {
+#ifndef NO_THREADS
+ int i;
+ if ( argc < 2 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: missing frquency value in \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n",
+ fname, lineno, 0 );
+ return 1;
+ }
+
+ i = atoi( argv[1] );
+
+ if( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n",
+ fname, lineno, i );
+ return 1;
+ }
+
+ li->li_dbsyncfreq = i;
+
+ if ( argc > 2 ) {
+ i = atoi( argv[2] );
+ if ( i < 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n",
+ fname, lineno, i );
+ return 1;
+ }
+ li ->li_dbsyncwaitn = i;
+ }
+
+ if ( argc > 3 ) {
+ i = atoi( argv[3] );
+ if ( i <= 0 ) {
+ Debug( LDAP_DEBUG_ANY,
+ "%s: line %d: frquency value (%d) invalid \"dbsync <frequency> [<wait-times> [wait-interval]]\" line\n",
+ fname, lineno, i );
+ return 1;
+ }
+ li ->li_dbsyncwaitinterval = i;
+ }
+
+ /* turn off writesync when sync policy is in place */
+ li->li_dbwritesync = 0;
+
+#else
+ Debug( LDAP_DEBUG_ANY,
+ "\"dbsync\" policies not supported in non-threaded environments\n", 0, 0, 0);
+ return 1;
+#endif
+
+
/* anything else */
} else {
fprintf( stderr,
struct stat st;
#endif
- sprintf( buf, "%s" LDAP_DIRSEP "%s%s",
- li->li_directory, name, suffix );
+ if (li->li_envdirok)
+ sprintf( buf, "%s%s", name, suffix );
+ else
+ sprintf( buf, "%s" LDAP_DIRSEP "%s%s",
+ li->li_directory, name, suffix );
if( li->li_dblocking ) {
flags |= LDBM_LOCKING;
flags |= LDBM_NOSYNC;
}
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_ENTRY,
+ "ldbm_cache_open: \"%s\", %d, %o\n", buf, flags, li->li_mode ));
+#else
Debug( LDAP_DEBUG_TRACE, "=> ldbm_cache_open( \"%s\", %d, %o )\n", buf,
flags, li->li_mode );
+#endif
+
curtime = slap_get_time();
empty = MAXDBCACHE;
{
/* we don't want to use an open cache with different
* permissions (esp. if we need write but the open
- * cache is read-only). So close this one if
+ * cache is read-only). So close this one if
* possible, and re-open below.
*
* FIXME: what about the case where the refcount
break;
}
li->li_dbcache[i].dbc_refcnt++;
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+ "ldbm_cache_open: cache %d\n", i ));
+#else
Debug( LDAP_DEBUG_TRACE,
"<= ldbm_cache_open (cache %d)\n", i, 0, 0 );
+#endif
+
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( &li->li_dbcache[i] );
}
free( li->li_dbcache[i].dbc_name );
li->li_dbcache[i].dbc_name = NULL;
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+ "ldbm_cache_open: no unused db to close - waiting\n" ));
+#else
Debug( LDAP_DEBUG_ANY,
"ldbm_cache_open no unused db to close - waiting\n",
0, 0, 0 );
+#endif
+
ldap_pvt_thread_cond_wait( &li->li_dbcache_cv,
&li->li_dbcache_mutex );
/* after waiting for a free slot, go back to square
}
} while (i == MAXDBCACHE);
- if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode,
+ if ( (li->li_dbcache[i].dbc_db = ldbm_open( li->li_dbenv, buf, flags, li->li_mode,
li->li_dbcachesize )) == NULL )
{
int err = errno;
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_ERR,
+ "ldbm_cache_open: \"%s\" failed, errono=%d, reason=%s\n",
+ buf, err, err > -1 && err < sys_nerr ? sys_errlist[err] :
+ "unknown" ));
+#else
Debug( LDAP_DEBUG_TRACE,
"<= ldbm_cache_open NULL \"%s\" errno=%d reason=\"%s\")\n",
buf, err, err > -1 && err < sys_nerr ?
sys_errlist[err] : "unknown" );
+#endif
+
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( NULL );
}
assert( li->li_dbcache[i].dbc_maxindirect < 256 );
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_ARGS,
+ "ldbm_cache_open: blksize:%ld maxids:%d maxindirect:%d\n",
+ li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
+ li->li_dbcache[i].dbc_maxindirect ));
+#else
Debug( LDAP_DEBUG_ARGS,
"ldbm_cache_open (blksize %ld) (maxids %d) (maxindirect %d)\n",
li->li_dbcache[i].dbc_blksize, li->li_dbcache[i].dbc_maxids,
li->li_dbcache[i].dbc_maxindirect );
+#endif
+
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+ "ldbm_cache_open: opened %d\n", i ));
+#else
Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 );
+#endif
+
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
return( &li->li_dbcache[i] );
}
ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
for ( i = 0; i < MAXDBCACHE; i++ ) {
if ( li->li_dbcache[i].dbc_name != NULL ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+ "ldbm_cache_flush_all: flushing db (%s)\n",
+ li->li_dbcache[i].dbc_name ));
+#else
Debug( LDAP_DEBUG_TRACE, "ldbm flushing db (%s)\n",
li->li_dbcache[i].dbc_name, 0, 0 );
+#endif
+
ldbm_sync( li->li_dbcache[i].dbc_db );
li->li_dbcache[i].dbc_dirty = 0;
if ( li->li_dbcache[i].dbc_refcnt != 0 ) {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_INFO,
+ "ldbm_cache_flush_all: couldn't close db (%s), refcnt=%d\n",
+ li->li_dbcache[i].dbc_name, li->li_dbcache[i].dbc_refcnt ));
+#else
Debug( LDAP_DEBUG_TRACE,
"refcnt = %d, couldn't close db (%s)\n",
li->li_dbcache[i].dbc_refcnt,
li->li_dbcache[i].dbc_name, 0 );
+#endif
+
} else {
+#ifdef NEW_LOGGING
+ LDAP_LOG(( "cache", LDAP_LEVEL_DETAIL1,
+ "ldbm_cache_flush_all: ldbm closing db (%s)\n",
+ li->li_dbcache[i].dbc_name ));
+#else
Debug( LDAP_DEBUG_TRACE,
"ldbm closing db (%s)\n",
li->li_dbcache[i].dbc_name, 0, 0 );
+#endif
+
ldap_pvt_thread_cond_signal( &li->li_dbcache_cv );
ldbm_close( li->li_dbcache[i].dbc_db );
free( li->li_dbcache[i].dbc_name );
ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
}
+void
+ldbm_cache_sync( Backend *be )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ int i;
+
+ ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex );
+ for ( i = 0; i < MAXDBCACHE; i++ ) {
+ if ( li->li_dbcache[i].dbc_name != NULL && li->li_dbcache[i].dbc_dirty ) {
+ Debug( LDAP_DEBUG_TRACE, "ldbm syncing db (%s)\n",
+ li->li_dbcache[i].dbc_name, 0, 0 );
+ ldbm_sync( li->li_dbcache[i].dbc_db );
+ li->li_dbcache[i].dbc_dirty = 0;
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex );
+}
+
Datum
ldbm_cache_fetch(
DBCache *db,
return( rc );
}
+
+void *
+ldbm_cache_sync_daemon(
+ void *be_ptr
+)
+{
+ Backend *be = (Backend *)be_ptr;
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ Debug( LDAP_DEBUG_ANY, "synchronizer starting for %s\n", li->li_directory, 0, 0 );
+
+ while (!li->li_dbshutdown) {
+ int i = li->li_dbsyncwaitn;
+
+ sleep( li->li_dbsyncfreq );
+
+ while (i && ldap_pvt_thread_pool_backload(&connection_pool) != 0) {
+ Debug( LDAP_DEBUG_TRACE, "delay syncing %s\n", li->li_directory, 0, 0 );
+ sleep(li->li_dbsyncwaitinterval);
+ i--;
+ }
+
+ if (!li->li_dbshutdown) {
+ Debug( LDAP_DEBUG_TRACE, "syncing %s\n", li->li_directory, 0, 0 );
+ ldbm_cache_sync( be );
+ }
+ }
+
+ Debug( LDAP_DEBUG_ANY, "synchronizer stopping\n", 0, 0, 0 );
+
+ return NULL;
+}
{
/* terminate the underlying database system */
ldbm_shutdown();
-
return 0;
}
/* default database directory */
li->li_directory = ch_strdup( DEFAULT_DB_DIRECTORY );
+ /* DB_ENV environment pointer for DB3 */
+ li->li_dbenv = 0;
+
+ /* envdirok is turned on by ldbm_initialize_env if DB3 */
+ li->li_envdirok = 0;
+
+ /* syncfreq is 0 if disabled, or # seconds */
+ li->li_dbsyncfreq = 0;
+
+ /* wait up to dbsyncwaitn times if server is busy */
+ li->li_dbsyncwaitn = 12;
+
+ /* delay interval */
+ li->li_dbsyncwaitinterval = 5;
+
+ /* flag to notify ldbm_cache_sync_daemon to shut down */
+ li->li_dbshutdown = 0;
+
/* initialize various mutex locks & condition variables */
ldap_pvt_thread_mutex_init( &li->li_root_mutex );
ldap_pvt_thread_mutex_init( &li->li_add_mutex );
BackendDB *be
)
{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+ li->li_dbenv = ldbm_initialize_env( li->li_directory,
+ li->li_dbcachesize, &li->li_envdirok );
+
+ /* sync thread */
+ if ( li->li_dbsyncfreq > 0 )
+ {
+ int rc;
+ rc = ldap_pvt_thread_create( &li->li_dbsynctid,
+ 0, ldbm_cache_sync_daemon, (void*)be );
+
+ if ( rc != 0 )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "sync ldap_pvt_thread_create failed (%d)\n", rc, 0, 0 );
+ return 1;
+ }
+ }
+
return 0;
}
{
/* should free/destroy every in be_private */
struct ldbminfo *li = (struct ldbminfo *) be->be_private;
+
+ if (li->li_dbenv)
+ ldbm_shutdown_env(li->li_dbenv);
+
free( li->li_directory );
attr_index_destroy( li->li_attrs );
void ldbm_cache_close LDAP_P(( Backend *be, DBCache *db ));
void ldbm_cache_really_close LDAP_P(( Backend *be, DBCache *db ));
void ldbm_cache_flush_all LDAP_P(( Backend *be ));
+void ldbm_cache_sync LDAP_P(( Backend *be ));
Datum ldbm_cache_fetch LDAP_P(( DBCache *db, Datum key ));
int ldbm_cache_store LDAP_P(( DBCache *db, Datum key, Datum data, int flags ));
int ldbm_cache_delete LDAP_P(( DBCache *db, Datum key ));