X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldbm%2Fdbcache.c;h=b9407f4d1a8461ea9e3e1c26c4ef1dce26bf596e;hb=4d36fd5a3ed407b0a53004d1431f1669222138b4;hp=3da8ed422649322b2c875edc12ec2497c20f6074;hpb=a28f9e03be4a91e1a33ce3886fe2182c8e859327;p=openldap diff --git a/servers/slapd/back-ldbm/dbcache.c b/servers/slapd/back-ldbm/dbcache.c index 3da8ed4226..b9407f4d1a 100644 --- a/servers/slapd/back-ldbm/dbcache.c +++ b/servers/slapd/back-ldbm/dbcache.c @@ -1,4 +1,9 @@ /* ldbmcache.c - maintain a cache of open ldbm files */ +/* $OpenLDAP$ */ +/* + * Copyright 1998-2002 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ #include "portable.h" @@ -8,101 +13,168 @@ #include #include #include - +#include #include -#ifdef HAVE_SYS_PARAM_H -#include -#endif - -#include "ldapconfig.h" #include "slap.h" #include "back-ldbm.h" -struct dbcache * +DBCache * ldbm_cache_open( Backend *be, - char *name, - char *suffix, + const char *name, + const char *suffix, int flags ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; - int i, lru; - time_t oldtime, curtime; + int i, lru, empty; + time_t oldtime; char buf[MAXPATHLEN]; #ifdef HAVE_ST_BLKSIZE struct stat st; #endif - sprintf( buf, "%s%s%s%s", li->li_directory, DEFAULT_DIRSEP, 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; + } else { + flags |= LDBM_NOLOCKING; + } + + if( li->li_dbwritesync ) { + flags |= LDBM_SYNC; + } else { + flags |= LDBM_NOSYNC; + } + +#ifdef NEW_LOGGING + LDAP_LOG( CACHE, 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 + - lru = 0; - curtime = slap_get_time(); - oldtime = curtime; + empty = MAXDBCACHE; ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); - for ( i = 0; i < MAXDBCACHE && li->li_dbcache[i].dbc_name != NULL; - i++ ) { - /* already open - return it */ - if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) { - li->li_dbcache[i].dbc_refcnt++; - Debug( LDAP_DEBUG_TRACE, - "<= ldbm_cache_open (cache %d)\n", i, 0, 0 ); - ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); - return( &li->li_dbcache[i] ); - } + do { + lru = 0; + oldtime = 1; + for ( i = 0; i < MAXDBCACHE; i++ ) { + /* see if this slot is free */ + if ( li->li_dbcache[i].dbc_name == NULL) { + if (empty == MAXDBCACHE) + empty = i; + continue; + } - /* keep track of lru db */ - if ( li->li_dbcache[i].dbc_lastref < oldtime && - li->li_dbcache[i].dbc_refcnt == 0 ) { - lru = i; - oldtime = li->li_dbcache[i].dbc_lastref; + if ( strcmp( li->li_dbcache[i].dbc_name, buf ) == 0 ) { + /* already open - return it */ + if (li->li_dbcache[i].dbc_flags != flags + && li->li_dbcache[i].dbc_refcnt == 0) + { + /* 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 + * possible, and re-open below. + * + * FIXME: what about the case where the refcount + * is > 0? right now, we're using it anyway and + * just praying. Can there be more than one open + * cache to the same db? + * + * Also, it's really only necessary to compare the + * read-only flag, instead of all of the flags, + * but for now I'm checking all of them. + */ + lru = i; + empty = MAXDBCACHE; + break; + } + li->li_dbcache[i].dbc_refcnt++; +#ifdef NEW_LOGGING + LDAP_LOG( CACHE, DETAIL1, + "ldbm_cache_open: cache %d\n", i, 0, 0 ); +#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] ); + } + + /* keep track of lru db */ + if (( li->li_dbcache[i].dbc_refcnt == 0 ) && + (( oldtime == 1 ) || + ( li->li_dbcache[i].dbc_lastref < oldtime )) ) + { + lru = i; + oldtime = li->li_dbcache[i].dbc_lastref; + } } - } - /* no empty slots, not already open - close lru and use that slot */ - if ( i == MAXDBCACHE ) { - i = lru; - if ( li->li_dbcache[i].dbc_refcnt != 0 ) { - Debug( LDAP_DEBUG_ANY, - "ldbm_cache_open no unused db to close - waiting\n", - 0, 0, 0 ); - lru = -1; - while ( lru == -1 ) { + i = empty; + if ( i == MAXDBCACHE ) { + /* no empty slots, not already open - close lru and use that slot */ + if ( li->li_dbcache[lru].dbc_refcnt == 0 ) { + i = lru; + ldbm_close( li->li_dbcache[i].dbc_db ); + free( li->li_dbcache[i].dbc_name ); + li->li_dbcache[i].dbc_name = NULL; + } else { +#ifdef NEW_LOGGING + LDAP_LOG( CACHE, INFO, + "ldbm_cache_open: no unused db to close - waiting\n", + 0, 0, 0 ); +#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 ); - for ( i = 0; i < MAXDBCACHE; i++ ) { - if ( li->li_dbcache[i].dbc_refcnt - == 0 ) { - lru = i; - break; - } - } + &li->li_dbcache_mutex ); + /* after waiting for a free slot, go back to square + * one: look for an open cache for this db, or an + * empty slot, or an unref'ed cache, or wait again. + */ } - i = lru; } - ldbm_close( li->li_dbcache[i].dbc_db ); - free( li->li_dbcache[i].dbc_name ); - li->li_dbcache[i].dbc_name = NULL; - } + } while (i == MAXDBCACHE); - if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode, - li->li_dbcachesize )) == NULL ) { + 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, 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", + "<= 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 ); } li->li_dbcache[i].dbc_name = ch_strdup( buf ); li->li_dbcache[i].dbc_refcnt = 1; - li->li_dbcache[i].dbc_lastref = curtime; + li->li_dbcache[i].dbc_lastref = slap_get_time(); + li->li_dbcache[i].dbc_flags = flags; + li->li_dbcache[i].dbc_dirty = 0; #ifdef HAVE_ST_BLKSIZE if ( stat( buf, &st ) == 0 ) { li->li_dbcache[i].dbc_blksize = st.st_blksize; @@ -113,41 +185,66 @@ ldbm_cache_open( } li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize / sizeof(ID)) - ID_BLOCK_IDS_OFFSET; - li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS / - li->li_dbcache[i].dbc_maxids) + 1; + li->li_dbcache[i].dbc_maxindirect = ( SLAPD_LDBM_MIN_MAXIDS / + li->li_dbcache[i].dbc_maxids ) + 1; + assert( li->li_dbcache[i].dbc_maxindirect < 256 ); + +#ifdef NEW_LOGGING + LDAP_LOG( CACHE, 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, DETAIL1, "<= ldbm_cache_open: (opened %d)\n", i, 0, 0 ); +#else Debug( LDAP_DEBUG_TRACE, "<= ldbm_cache_open (opened %d)\n", i, 0, 0 ); +#endif + + ldap_pvt_thread_mutex_init( &li->li_dbcache[i].dbc_write_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); return( &li->li_dbcache[i] ); } void -ldbm_cache_close( Backend *be, struct dbcache *db ) +ldbm_cache_close( Backend *be, DBCache *db ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; + if( li->li_dbwritesync && db->dbc_dirty ) { + ldbm_sync( db->dbc_db ); + db->dbc_dirty = 0; + } + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { + if ( --db->dbc_refcnt <= 0 ) { + db->dbc_refcnt = 0; ldap_pvt_thread_cond_signal( &li->li_dbcache_cv ); } ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } void -ldbm_cache_really_close( Backend *be, struct dbcache *db ) +ldbm_cache_really_close( Backend *be, DBCache *db ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { + if ( --db->dbc_refcnt <= 0 ) { + db->dbc_refcnt = 0; ldap_pvt_thread_cond_signal( &li->li_dbcache_cv ); ldbm_close( db->dbc_db ); free( db->dbc_name ); db->dbc_name = NULL; + ldap_pvt_thread_mutex_destroy( &db->dbc_write_mutex ); } ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } @@ -161,25 +258,68 @@ ldbm_cache_flush_all( Backend *be ) 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, DETAIL1, + "ldbm_cache_flush_all: flushing db (%s)\n", + li->li_dbcache[i].dbc_name, 0, 0 ); +#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 ); -#ifdef SLAP_CLEANUP + li->li_dbcache[i].dbc_dirty = 0; if ( li->li_dbcache[i].dbc_refcnt != 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CACHE, 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,0); +#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, DETAIL1, + "ldbm_cache_flush_all: ldbm closing db (%s)\n", + li->li_dbcache[i].dbc_name, 0, 0 ); +#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 ); li->li_dbcache[i].dbc_name = NULL; } -#endif /* SLAP_CLEANUP */ + } + } + 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 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( CACHE, DETAIL1, "ldbm_cache_sync: " + "ldbm syncing db (%s)\n", li->li_dbcache[i].dbc_name, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "ldbm syncing 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; } } ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); @@ -187,22 +327,16 @@ ldbm_cache_flush_all( Backend *be ) Datum ldbm_cache_fetch( - struct dbcache *db, + DBCache *db, Datum key ) { - Datum data; - - ldbm_datum_init( data ); - - data = ldbm_fetch( db->dbc_db, key ); - - return( data ); + return ldbm_fetch( db->dbc_db, key ); } int ldbm_cache_store( - struct dbcache *db, + DBCache *db, Datum key, Datum data, int flags @@ -228,6 +362,7 @@ ldbm_cache_store( flags, 0, 0, 0, 0 ); #endif /* LDBM_DEBUG */ + db->dbc_dirty = 1; rc = ldbm_store( db->dbc_db, key, data, flags ); return( rc ); @@ -235,13 +370,66 @@ ldbm_cache_store( int ldbm_cache_delete( - struct dbcache *db, + DBCache *db, Datum key ) { int rc; + db->dbc_dirty = 1; rc = ldbm_delete( db->dbc_db, key ); return( rc ); } + +void * +ldbm_cache_sync_daemon( + void *be_ptr +) +{ + Backend *be = (Backend *)be_ptr; + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + +#ifdef NEW_LOGGING + LDAP_LOG ( CACHE, ARGS, "ldbm_cache_sync_daemon:" + " synchronizer starting for %s\n", li->li_directory, 0, 0 ); +#else + Debug( LDAP_DEBUG_ANY, "synchronizer starting for %s\n", li->li_directory, 0, 0 ); +#endif + + while (!li->li_dbshutdown) { + int i = li->li_dbsyncwaitn; + + sleep( li->li_dbsyncfreq ); + + while (i && ldap_pvt_thread_pool_backload(&connection_pool) != 0) { +#ifdef NEW_LOGGING + LDAP_LOG ( CACHE, DETAIL1, "ldbm_cache_sync_daemon:" + " delay syncing %s\n", li->li_directory, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "delay syncing %s\n", li->li_directory, 0, 0 ); +#endif + sleep(li->li_dbsyncwaitinterval); + i--; + } + + if (!li->li_dbshutdown) { +#ifdef NEW_LOGGING + LDAP_LOG ( CACHE, DETAIL1, "ldbm_cache_sync_daemon:" + " syncing %s\n", li->li_directory, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, "syncing %s\n", li->li_directory, 0, 0 ); +#endif + ldbm_cache_sync( be ); + } + } + +#ifdef NEW_LOGGING + LDAP_LOG ( CACHE, DETAIL1, "ldbm_cache_sync_daemon:" + " synchronizer stopping\n", 0, 0, 0); +#else + Debug( LDAP_DEBUG_ANY, "synchronizer stopping\n", 0, 0, 0 ); +#endif + + return NULL; +}