X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-ldbm%2Fdbcache.c;h=b9407f4d1a8461ea9e3e1c26c4ef1dce26bf596e;hb=4d36fd5a3ed407b0a53004d1431f1669222138b4;hp=56c259c8698d6f1a4b2130f443076acacdb983c3;hpb=2054d40b7ce1a74c349fd0d523a275ccfdee85c7;p=openldap diff --git a/servers/slapd/back-ldbm/dbcache.c b/servers/slapd/back-ldbm/dbcache.c index 56c259c869..b9407f4d1a 100644 --- a/servers/slapd/back-ldbm/dbcache.c +++ b/servers/slapd/back-ldbm/dbcache.c @@ -1,153 +1,252 @@ /* 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" #include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include #include -#include -#include "portable.h" + #include "slap.h" -#include "ldapconfig.h" #include "back-ldbm.h" -#ifndef SYSERRLIST_IN_STDIO -extern int sys_nerr; -extern char *sys_errlist[]; -#endif -extern time_t currenttime; -extern pthread_mutex_t currenttime_mutex; - -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]; - LDBM db; +#ifdef HAVE_ST_BLKSIZE struct stat st; +#endif - sprintf( buf, "%s/%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; + } 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; - pthread_mutex_lock( ¤ttime_mutex ); - curtime = currenttime; - pthread_mutex_unlock( ¤ttime_mutex ); - oldtime = curtime; - - pthread_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 ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); - return( &li->li_dbcache[i] ); - } - /* 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; - } - } + empty = MAXDBCACHE; + + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + 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; + } - /* 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 ) { - pthread_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; - } + 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; } - i = lru; } - ldbm_close( li->li_dbcache[i].dbc_db ); - free( li->li_dbcache[i].dbc_name ); - li->li_dbcache[i].dbc_name = NULL; - } - if ( (li->li_dbcache[i].dbc_db = ldbm_open( buf, flags, li->li_mode, - li->li_dbcachesize )) == NULL ) { + 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 ); + /* 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. + */ + } + } + } while (i == MAXDBCACHE); + + 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", - buf, errno, errno > -1 && errno < sys_nerr ? - sys_errlist[errno] : "unknown" ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); + "<= 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 = strdup( buf ); + 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; - } else { + } else +#endif + { li->li_dbcache[i].dbc_blksize = DEFAULT_BLOCKSIZE; } li->li_dbcache[i].dbc_maxids = (li->li_dbcache[i].dbc_blksize / - sizeof(ID)) - 2; - li->li_dbcache[i].dbc_maxindirect = (SLAPD_LDBM_MIN_MAXIDS / - li->li_dbcache[i].dbc_maxids) + 1; - + sizeof(ID)) - ID_BLOCK_IDS_OFFSET; + 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 %d) (maxids %d) (maxindirect %d)\n", + "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 ); - pthread_mutex_unlock( &li->li_dbcache_mutex ); +#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; - pthread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { - pthread_cond_signal( &li->li_dbcache_cv ); + if( li->li_dbwritesync && db->dbc_dirty ) { + ldbm_sync( db->dbc_db ); + db->dbc_dirty = 0; } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + 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; - pthread_mutex_lock( &li->li_dbcache_mutex ); - if ( --db->dbc_refcnt == 0 ) { - pthread_cond_signal( &li->li_dbcache_cv ); + ldap_pvt_thread_mutex_lock( &li->li_dbcache_mutex ); + 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 ); } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } void @@ -156,54 +255,88 @@ ldbm_cache_flush_all( Backend *be ) struct ldbminfo *li = (struct ldbminfo *) be->be_private; int i; - pthread_mutex_lock( &li->li_dbcache_mutex ); + 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 ); - pthread_mutex_lock( &li->li_dbcache[i].dbc_mutex ); +#endif + ldbm_sync( li->li_dbcache[i].dbc_db ); - pthread_mutex_unlock( &li->li_dbcache[i].dbc_mutex ); + 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; + } } } - pthread_mutex_unlock( &li->li_dbcache_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); } -Datum -ldbm_cache_fetch( - struct dbcache *db, - Datum key -) +void +ldbm_cache_sync( Backend *be ) { - Datum data; -#ifdef LDBM_USE_DB2 - memset( &data, 0, sizeof( data ) ); -#endif + struct ldbminfo *li = (struct ldbminfo *) be->be_private; + int i; - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* increment reader count */ - db->dbc_readers++ - pthread_mutex_unlock( &db->dbc_mutex ); + 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 - - data = ldbm_fetch( db->dbc_db, key ); - -#ifdef reentrant_database - pthread_mutex_lock( &db->dbc_mutex ); - /* decrement reader count & signal any waiting writers */ - if ( --db->dbc_readers == 0 ) { - pthread_cond_signal( &db->dbc_cv ); + ldbm_sync( li->li_dbcache[i].dbc_db ); + li->li_dbcache[i].dbc_dirty = 0; + } } -#endif - pthread_mutex_unlock( &db->dbc_mutex ); + ldap_pvt_thread_mutex_unlock( &li->li_dbcache_mutex ); +} - return( data ); +Datum +ldbm_cache_fetch( + DBCache *db, + Datum key +) +{ + return ldbm_fetch( db->dbc_db, key ); } int ldbm_cache_store( - struct dbcache *db, + DBCache *db, Datum key, Datum data, int flags @@ -211,14 +344,6 @@ ldbm_cache_store( { int rc; - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* wait for reader count to drop to zero */ - while ( db->dbc_readers > 0 ) { - pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex ); - } -#endif - #ifdef LDBM_DEBUG Statslog( LDAP_DEBUG_STATS, "=> ldbm_cache_store(): key.dptr=%s, key.dsize=%d\n", @@ -237,32 +362,74 @@ ldbm_cache_store( flags, 0, 0, 0, 0 ); #endif /* LDBM_DEBUG */ + db->dbc_dirty = 1; rc = ldbm_store( db->dbc_db, key, data, flags ); - pthread_mutex_unlock( &db->dbc_mutex ); - return( rc ); } int ldbm_cache_delete( - struct dbcache *db, + DBCache *db, Datum key ) { int rc; - pthread_mutex_lock( &db->dbc_mutex ); -#ifdef reentrant_database - /* wait for reader count to drop to zero - then write */ - while ( db->dbc_readers > 0 ) { - pthread_cond_wait( &db->dbc_cv, &db->dbc_mutex ); - } -#endif - + db->dbc_dirty = 1; rc = ldbm_delete( db->dbc_db, key ); - pthread_mutex_unlock( &db->dbc_mutex ); - 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; +}