/* * Destroys the cookie tree */ int rewrite_session_destroy( struct rewrite_info *info ) { int count; assert( info != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ /* * Should call per-session destruction routine ... */ count = avl_free( info->li_cookies, rewrite_session_free ); info->li_cookies = NULL; #if 0 fprintf( stderr, "count = %d; num_cookies = %d\n", count, info->li_num_cookies ); #endif assert( count == info->li_num_cookies ); info->li_num_cookies = 0; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; }
void bdb_idl_cache_del_id( struct bdb_info *bdb, DB *db, DBT *key, ID id ) { bdb_idl_cache_entry_t *cache_entry, idl_tmp; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_rdwr_wlock( &bdb->bi_idl_tree_rwlock ); cache_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( cache_entry != NULL ) { bdb_idl_delete( cache_entry->idl, id ); if ( cache_entry->idl[0] == 0 ) { if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) cache_entry, bdb_idl_entry_cmp ) == NULL ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_cache_del: " "AVL delete failed\n", 0, 0, 0 ); } --bdb->bi_idl_cache_size; ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); IDL_LRU_DELETE( bdb, cache_entry ); ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); free( cache_entry->kstr.bv_val ); free( cache_entry->idl ); free( cache_entry ); } } ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); }
/* * Defines and inits a var with session scope */ int rewrite_session_var_set_f( struct rewrite_info *info, const void *cookie, const char *name, const char *value, int flags ) { struct rewrite_session *session; struct rewrite_var *var; assert( info != NULL ); assert( cookie != NULL ); assert( name != NULL ); assert( value != NULL ); session = rewrite_session_find( info, cookie ); if ( session == NULL ) { session = rewrite_session_init( info, cookie ); if ( session == NULL ) { return REWRITE_ERR; } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_mutex_lock( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( session->ls_vars, name ); if ( var != NULL ) { assert( var->lv_value.bv_val != NULL ); (void)rewrite_var_replace( var, value, flags ); } else { var = rewrite_var_insert_f( &session->ls_vars, name, value, flags ); if ( var == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_return( info, session ); return REWRITE_ERR; } } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_session_return( info, session ); return REWRITE_SUCCESS; }
int bdb_dn2id_delete( BackendDB *be, DB_TXN *txn, char *pdn, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT key; DB *db = bdb->bi_id2parent->bdi_db; idNode *n; DBTzero(&key); key.size = sizeof(e->e_id); key.data = &e->e_id; rc = db->del( db, txn, &key, 0); ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr); n = avl_delete(&bdb->bi_tree, &e->e_id, node_find_cmp); if (n) { if (n->i_parent) { ldap_pvt_thread_rdwr_wlock(&n->i_parent->i_kids_rdwr); avl_delete(&n->i_parent->i_kids, &n->i_rdn->nrdn, node_frdn_cmp); ldap_pvt_thread_rdwr_wunlock(&n->i_parent->i_kids_rdwr); } free(n->i_rdn); ldap_pvt_thread_rdwr_destroy(&n->i_kids_rdwr); free(n); } if (e->e_id == 1) bdb->bi_troot = NULL; ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr); return rc; }
static int ndb_oc_create( struct ndb_info *ni, NdbOcInfo *oci, int create ) { char buf[4096], *ptr; int i, rc = 0, col; if ( create ) { ptr = buf + sprintf( buf, "CREATE TABLE `%s` (eid bigint unsigned NOT NULL, vid int unsigned NOT NULL", oci->no_table.bv_val ); } col = 0; if ( oci->no_oc->soc_required ) { for ( i=0; oci->no_oc->soc_required[i]; i++ ); col += i; } if ( oci->no_oc->soc_allowed ) { for ( i=0; oci->no_oc->soc_allowed[i]; i++ ); col += i; } /* assume all are present */ oci->no_attrs = (struct ndb_attrinfo **)ch_malloc( col * sizeof(struct ndb_attrinfo *)); col = 2; ldap_pvt_thread_rdwr_wlock( &ni->ni_ai_rwlock ); if ( oci->no_oc->soc_required ) { rc = ndb_ai_check( ni, oci, oci->no_oc->soc_required, &ptr, &col, create ); } if ( !rc && oci->no_oc->soc_allowed ) { rc = ndb_ai_check( ni, oci, oci->no_oc->soc_allowed, &ptr, &col, create ); } ldap_pvt_thread_rdwr_wunlock( &ni->ni_ai_rwlock ); /* shrink down to just the needed size */ oci->no_attrs = (struct ndb_attrinfo **)ch_realloc( oci->no_attrs, oci->no_nattrs * sizeof(struct ndb_attrinfo *)); if ( create ) { ptr = lutil_strcopy( ptr, ", PRIMARY KEY(eid, vid) ) ENGINE=ndb PARTITION BY KEY(eid)" ); rc = mysql_real_query( &ni->ni_sql, buf, ptr - buf ); if ( rc ) { Debug( LDAP_DEBUG_ANY, "ndb_oc_create: CREATE TABLE %s failed, %s (%d)\n", oci->no_table.bv_val, mysql_error(&ni->ni_sql), mysql_errno(&ni->ni_sql) ); } } return rc; }
/* * remaining fields require backend cache lock to access * These items are specific to the BDB backend and should * be hidden. */ int bei_state; /* for the cache */ #define CACHE_ENTRY_UNDEFINED 0 #define CACHE_ENTRY_CREATING 1 #define CACHE_ENTRY_READY 2 #define CACHE_ENTRY_DELETED 3 #define CACHE_ENTRY_COMMITTED 4 int bei_refcnt; /* # threads ref'ing this entry */ Entry *bei_lrunext; /* for cache lru list */ Entry *bei_lruprev; } EntryInfo; #undef BEI #define BEI(e) ((EntryInfo *) ((e)->e_private)) static int bdb_cache_delete_entry_internal(Cache *cache, Entry *e); #ifdef LDAP_DEBUG static void bdb_lru_print(Cache *cache); #endif #if 0 /* unused */ static int bdb_cache_entry_rdwr_lock(Entry *e, int rw) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, ENTRY, "bdb_cache_entry_rdwr_lock: %s lock on ID %ld\n", rw ? "w" : "r", e->e_id, 0 ); #else Debug( LDAP_DEBUG_ARGS, "entry_rdwr_%slock: ID: %ld\n", rw ? "w" : "r", e->e_id, 0); #endif if (rw) return ldap_pvt_thread_rdwr_wlock(&BEI(e)->bei_rdwr); else return ldap_pvt_thread_rdwr_rlock(&BEI(e)->bei_rdwr); }
/* * Deletes a session */ int rewrite_session_delete( struct rewrite_info *info, const void *cookie ) { struct rewrite_session *session, tmp = { 0 }; assert( info != NULL ); assert( cookie != NULL ); session = rewrite_session_find( info, cookie ); if ( session == NULL ) { return REWRITE_SUCCESS; } if ( --session->ls_count > 0 ) { rewrite_session_return( info, session ); return REWRITE_SUCCESS; } rewrite_session_clean( session ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ assert( info->li_num_cookies > 0 ); info->li_num_cookies--; /* * There is nothing to delete in the return value */ tmp.ls_cookie = ( void * )cookie; avl_delete( &info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); free( session ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; }
static void rewrite_session_clean( void *v_session ) { struct rewrite_session *session = (struct rewrite_session *)v_session; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &session->ls_vars_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rewrite_var_delete( session->ls_vars ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &session->ls_vars_mutex ); ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); ldap_pvt_thread_mutex_unlock( &session->ls_mutex ); ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ }
void bdb_cache_release_all( Cache *cache ) { Entry *e; int rc; /* set cache write lock */ ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, ENTRY, "bdb_cache_release_all: enter\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_release_all\n", 0, 0, 0 ); #endif while ( (e = cache->c_lrutail) != NULL && BEI(e)->bei_refcnt == 0 ) { #ifdef LDAP_RDWR_DEBUG assert(!ldap_pvt_thread_rdwr_active(&BEI(e)->bei_rdwr)); #endif /* delete from cache and lru q */ /* XXX do we need rc ? */ rc = bdb_cache_delete_entry_internal( cache, e ); bdb_cache_entry_private_destroy( e ); bdb_entry_return( e ); } if ( cache->c_cursize ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_release_all: Entry cache could not be emptied.\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "Entry-cache could not be emptied\n", 0, 0, 0 ); #endif } /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); }
/* This function links a node into its parent's i_kids tree. */ static int bdb_insert_kid( void *v_a, void *v_tree ) { idNode *a = v_a; Avlnode *tree = v_tree; int rc; if (a->i_rdn->parent == 0) return 0; a->i_parent = bdb_find_id_node(a->i_rdn->parent, tree); if (!a->i_parent) return -1; ldap_pvt_thread_rdwr_wlock(&a->i_parent->i_kids_rdwr); rc = avl_insert( &a->i_parent->i_kids, (caddr_t) a, node_rdn_cmp, avl_dup_error ); ldap_pvt_thread_rdwr_wunlock(&a->i_parent->i_kids_rdwr); return rc; }
/* * Defines and inits a variable with global scope */ int rewrite_param_set( struct rewrite_info *info, const char *name, const char *value ) { struct rewrite_var *var; assert( info != NULL ); assert( name != NULL ); assert( value != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ var = rewrite_var_find( info->li_params, name ); if ( var != NULL ) { assert( var->lv_value.bv_val != NULL ); free( var->lv_value.bv_val ); var->lv_value.bv_val = strdup( value ); var->lv_value.bv_len = strlen( value ); } else { var = rewrite_var_insert( &info->li_params, name, value ); if ( var == NULL ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_ERR; } } #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; }
/* * Destroys the parameter tree */ int rewrite_param_destroy( struct rewrite_info *info ) { int count; assert( info != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ count = avl_free( info->li_params, rewrite_param_free ); info->li_params = NULL; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_params_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return REWRITE_SUCCESS; }
void bdb_idl_cache_add_id( struct bdb_info *bdb, DB *db, DBT *key, ID id ) { bdb_idl_cache_entry_t *cache_entry, idl_tmp; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_rdwr_wlock( &bdb->bi_idl_tree_rwlock ); cache_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( cache_entry != NULL ) { if ( !BDB_IDL_IS_RANGE( cache_entry->idl ) && cache_entry->idl[0] < BDB_IDL_DB_MAX ) { size_t s = BDB_IDL_SIZEOF( cache_entry->idl ) + sizeof(ID); cache_entry->idl = ch_realloc( cache_entry->idl, s ); } bdb_idl_insert( cache_entry->idl, id ); } ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); }
/* Create an entryinfo in the cache. Caller must release the locks later. */ static int bdb_entryinfo_add_internal( struct bdb_info *bdb, EntryInfo *ei, EntryInfo **res ) { EntryInfo *ei2 = NULL; *res = NULL; ei2 = bdb_cache_entryinfo_new( &bdb->bi_cache ); bdb_cache_entryinfo_lock( ei->bei_parent ); ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock ); ei2->bei_id = ei->bei_id; ei2->bei_parent = ei->bei_parent; #ifdef BDB_HIER ei2->bei_rdn = ei->bei_rdn; #endif #ifdef SLAP_ZONE_ALLOC ei2->bei_bdb = bdb; #endif /* Add to cache ID tree */ if (avl_insert( &bdb->bi_cache.c_idtree, ei2, bdb_id_cmp, bdb_id_dup_err )) { EntryInfo *eix = ei2->bei_lrunext; bdb_cache_entryinfo_free( &bdb->bi_cache, ei2 ); ei2 = eix; #ifdef BDB_HIER /* It got freed above because its value was * assigned to ei2. */ ei->bei_rdn.bv_val = NULL; #endif } else { int rc; bdb->bi_cache.c_eiused++; ber_dupbv( &ei2->bei_nrdn, &ei->bei_nrdn ); /* This is a new leaf node. But if parent had no kids, then it was * a leaf and we would be decrementing that. So, only increment if * the parent already has kids. */ if ( ei->bei_parent->bei_kids || !ei->bei_parent->bei_id ) bdb->bi_cache.c_leaves++; rc = avl_insert( &ei->bei_parent->bei_kids, ei2, bdb_rdn_cmp, avl_dup_error ); #ifdef BDB_HIER /* it's possible for hdb_cache_find_parent to beat us to it */ if ( !rc ) { ei->bei_parent->bei_ckids++; } #endif } *res = ei2; return 0; }
void bdb_idl_cache_put( struct bdb_info *bdb, DB *db, DBT *key, ID *ids, int rc ) { bdb_idl_cache_entry_t idl_tmp; bdb_idl_cache_entry_t *ee, *eprev; if ( rc == DB_NOTFOUND || BDB_IDL_IS_ZERO( ids )) return; DBT2bv( key, &idl_tmp.kstr ); ee = (bdb_idl_cache_entry_t *) ch_malloc( sizeof( bdb_idl_cache_entry_t ) ); ee->db = db; ee->idl = (ID*) ch_malloc( BDB_IDL_SIZEOF ( ids ) ); BDB_IDL_CPY( ee->idl, ids ); ee->idl_lru_prev = NULL; ee->idl_lru_next = NULL; ee->idl_flags = 0; ber_dupbv( &ee->kstr, &idl_tmp.kstr ); ldap_pvt_thread_rdwr_wlock( &bdb->bi_idl_tree_rwlock ); if ( avl_insert( &bdb->bi_idl_tree, (caddr_t) ee, bdb_idl_entry_cmp, avl_dup_error )) { ch_free( ee->kstr.bv_val ); ch_free( ee->idl ); ch_free( ee ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); return; } ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); /* LRU_ADD */ if ( bdb->bi_idl_lru_head ) { assert( bdb->bi_idl_lru_tail != NULL ); assert( bdb->bi_idl_lru_head->idl_lru_prev != NULL ); assert( bdb->bi_idl_lru_head->idl_lru_next != NULL ); ee->idl_lru_next = bdb->bi_idl_lru_head; ee->idl_lru_prev = bdb->bi_idl_lru_head->idl_lru_prev; bdb->bi_idl_lru_head->idl_lru_prev->idl_lru_next = ee; bdb->bi_idl_lru_head->idl_lru_prev = ee; } else { ee->idl_lru_next = ee->idl_lru_prev = ee; bdb->bi_idl_lru_tail = ee; } bdb->bi_idl_lru_head = ee; if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) { int i; eprev = bdb->bi_idl_lru_tail; for ( i = 0; (ee = eprev) != NULL && i < 10; i++ ) { eprev = ee->idl_lru_prev; if ( eprev == ee ) { eprev = NULL; } if ( ee->idl_flags & CACHE_ENTRY_REFERENCED ) { ee->idl_flags ^= CACHE_ENTRY_REFERENCED; continue; } if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) ee, bdb_idl_entry_cmp ) == NULL ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_cache_put: " "AVL delete failed\n", 0, 0, 0 ); } IDL_LRU_DELETE( bdb, ee ); i++; --bdb->bi_idl_cache_size; ch_free( ee->kstr.bv_val ); ch_free( ee->idl ); ch_free( ee ); } bdb->bi_idl_lru_tail = eprev; assert( bdb->bi_idl_lru_tail != NULL || bdb->bi_idl_lru_head == NULL ); } bdb->bi_idl_cache_size++; ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_idl_tree_rwlock ); }
static int ndb_oc_list( struct ndb_info *ni, const NdbDictionary::Dictionary *myDict, struct berval *oname, int implied, NdbOcs *out ) { const NdbDictionary::Table *myTable; NdbOcInfo *oci, octmp; ObjectClass *oc; int i, rc; /* shortcut top */ if ( ber_bvstrcasecmp( oname, &slap_schema.si_oc_top->soc_cname )) { octmp.no_name = *oname; oci = (NdbOcInfo *)avl_find( ni->ni_oc_tree, &octmp, ndb_name_cmp ); if ( oci ) { oc = oci->no_oc; } else { oc = oc_bvfind( oname ); if ( !oc ) { /* undefined - shouldn't happen */ return LDAP_INVALID_SYNTAX; } } if ( oc->soc_sups ) { int i; for ( i=0; oc->soc_sups[i]; i++ ) { rc = ndb_oc_list( ni, myDict, &oc->soc_sups[i]->soc_cname, 1, out ); if ( rc ) return rc; } } } else { oc = slap_schema.si_oc_top; } /* Only insert once */ for ( i=0; i<out->no_ntext; i++ ) if ( out->no_text[i].bv_val == oc->soc_cname.bv_val ) break; if ( i == out->no_ntext ) { for ( i=0; i<out->no_nitext; i++ ) if ( out->no_itext[i].bv_val == oc->soc_cname.bv_val ) break; if ( i == out->no_nitext ) { if ( implied ) out->no_itext[out->no_nitext++] = oc->soc_cname; else out->no_text[out->no_ntext++] = oc->soc_cname; } } /* ignore top, etc... */ if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) return 0; if ( !oci ) { ldap_pvt_thread_rdwr_runlock( &ni->ni_oc_rwlock ); oci = (NdbOcInfo *)ch_malloc( sizeof( NdbOcInfo )+oc->soc_cname.bv_len+1 ); oci->no_table.bv_val = (char *)(oci+1); strcpy( oci->no_table.bv_val, oc->soc_cname.bv_val ); oci->no_table.bv_len = oc->soc_cname.bv_len; oci->no_name = oci->no_table; oci->no_oc = oc; oci->no_flag = 0; oci->no_nsets = 0; oci->no_nattrs = 0; ldap_pvt_thread_rdwr_wlock( &ni->ni_oc_rwlock ); if ( avl_insert( &ni->ni_oc_tree, oci, ndb_name_cmp, ndb_oc_dup_err )) { octmp.no_oc = oci->no_oc; ch_free( oci ); oci = (NdbOcInfo *)octmp.no_oc; } /* see if the oc table already exists in the DB */ myTable = myDict->getTable( oci->no_table.bv_val ); rc = ndb_oc_create( ni, oci, myTable == NULL ); ldap_pvt_thread_rdwr_wunlock( &ni->ni_oc_rwlock ); ldap_pvt_thread_rdwr_rlock( &ni->ni_oc_rwlock ); if ( rc ) return rc; } /* Only insert once */ for ( i=0; i<out->no_ninfo; i++ ) if ( out->no_info[i] == oci ) break; if ( i == out->no_ninfo ) out->no_info[out->no_ninfo++] = oci; return 0; }
/* * cache_add_entry_rw - create and lock an entry in the cache * returns: 0 entry has been created and locked * 1 entry already existed * -1 something bad happened * other Berkeley DB locking error code */ int bdb_cache_add_entry_rw( DB_ENV *env, Cache *cache, Entry *e, int rw, u_int32_t locker, DB_LOCK *lock ) { int i, rc; Entry *ee; #ifdef NEW_LOGGING LDAP_LOG( CACHE, ENTRY, "bdb_cache_add_entry_rw: add (%s):%s to cache\n", e->e_dn, rw ? "w" : "r", 0 ); #endif /* set cache write lock */ ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); assert( e->e_private == NULL ); if( bdb_cache_entry_private_init(e) != 0 ) { /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, ERR, "bdb_cache_add_entry_rw: add (%s):%ld private init failed!\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> bdb_cache_add_entry( %ld ): \"%s\": private init failed!\n", e->e_id, e->e_dn, 0 ); #endif return( -1 ); } if ( avl_insert( &cache->c_dntree, (caddr_t) e, entry_dn_cmp, avl_dup_error ) != 0 ) { /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_add_entry: (%s):%ld already in cache.\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_add_entry( %ld ): \"%s\": already in dn cache\n", e->e_id, e->e_dn, 0 ); #endif bdb_cache_entry_private_destroy(e); return( 1 ); } /* id tree */ if ( avl_insert( &cache->c_idtree, (caddr_t) e, entry_id_cmp, avl_dup_error ) != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_add_entry: (%s):%ls already in cache.\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> bdb_cache_add_entry( %ld ): \"%s\": already in id cache\n", e->e_id, e->e_dn, 0 ); #endif /* delete from dn tree inserted above */ if ( avl_delete( &cache->c_dntree, (caddr_t) e, entry_dn_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 ); #endif } bdb_cache_entry_private_destroy(e); /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( -1 ); } rc = bdb_cache_entry_db_lock( env, locker, e, rw, 0, lock ); switch ( rc ) { case 0 : break; case DB_LOCK_DEADLOCK : case DB_LOCK_NOTGRANTED : /* undo avl changes immediately */ if ( avl_delete( &cache->c_idtree, (caddr_t) e, entry_id_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> can't delete from id cache\n", 0, 0, 0 ); #endif } if ( avl_delete( &cache->c_dntree, (caddr_t) e, entry_dn_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_add_entry: can't delete (%s) from cache.\n", e->e_dn, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 ); #endif } /* fall through */ default : bdb_cache_entry_private_destroy(e); ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return rc; } /* put the entry into 'CREATING' state */ /* will be marked after when entry is returned */ BEI(e)->bei_state = CACHE_ENTRY_CREATING; BEI(e)->bei_refcnt = 1; /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); /* lru */ LRU_ADD( cache, e ); if ( ++cache->c_cursize > cache->c_maxsize ) { /* * find the lru entry not currently in use and delete it. * in case a lot of entries are in use, only look at the * first 10 on the tail of the list. */ i = 0; while ( cache->c_lrutail != NULL && BEI(cache->c_lrutail)->bei_refcnt != 0 && i < 10 ) { /* move this in-use entry to the front of the q */ ee = cache->c_lrutail; LRU_DELETE( cache, ee ); LRU_ADD( cache, ee ); i++; } /* * found at least one to delete - try to get back under * the max cache size. */ while ( cache->c_lrutail != NULL && BEI(cache->c_lrutail)->bei_refcnt == 0 && cache->c_cursize > cache->c_maxsize ) { e = cache->c_lrutail; /* delete from cache and lru q */ /* XXX do we need rc ? */ rc = bdb_cache_delete_entry_internal( cache, e ); bdb_cache_entry_private_destroy( e ); bdb_entry_return( e ); } } /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( 0 ); }
/* * Inits a session */ struct rewrite_session * rewrite_session_init( struct rewrite_info *info, const void *cookie ) { struct rewrite_session *session, tmp; int rc; assert( info != NULL ); assert( cookie != NULL ); #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ tmp.ls_cookie = ( void * )cookie; session = ( struct rewrite_session * )avl_find( info->li_cookies, ( caddr_t )&tmp, rewrite_cookie_cmp ); if ( session ) { session->ls_count++; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ return session; } session = calloc( sizeof( struct rewrite_session ), 1 ); if ( session == NULL ) { return NULL; } session->ls_cookie = ( void * )cookie; session->ls_count = 1; #ifdef USE_REWRITE_LDAP_PVT_THREADS if ( ldap_pvt_thread_mutex_init( &session->ls_mutex ) ) { free( session ); return NULL; } if ( ldap_pvt_thread_rdwr_init( &session->ls_vars_mutex ) ) { ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); free( session ); return NULL; } #endif /* USE_REWRITE_LDAP_PVT_THREADS */ rc = avl_insert( &info->li_cookies, ( caddr_t )session, rewrite_cookie_cmp, rewrite_cookie_dup ); info->li_num_cookies++; #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_wunlock( &info->li_cookies_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ if ( rc != 0 ) { #ifdef USE_REWRITE_LDAP_PVT_THREADS ldap_pvt_thread_rdwr_destroy( &session->ls_vars_mutex ); ldap_pvt_thread_mutex_destroy( &session->ls_mutex ); #endif /* USE_REWRITE_LDAP_PVT_THREADS */ free( session ); return NULL; } return session; }
/* * cache_update_entry - update a LOCKED entry which has been deleted. * returns: 0 entry has been created and locked * 1 entry already existed * -1 something bad happened */ int bdb_cache_update_entry( Cache *cache, Entry *e ) { int i, rc; Entry *ee; /* set cache write lock */ ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); assert( e->e_private ); if ( avl_insert( &cache->c_dntree, (caddr_t) e, entry_dn_cmp, avl_dup_error ) != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_update_entry: (%s):%ld already in dn cache\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_update_entry( %ld ): \"%s\": already in dn cache\n", e->e_id, e->e_dn, 0 ); #endif /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( 1 ); } /* id tree */ if ( avl_insert( &cache->c_idtree, (caddr_t) e, entry_id_cmp, avl_dup_error ) != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_update_entry: (%s)%ld already in id cache\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> bdb_cache_update_entry( %ld ): \"%s\": already in id cache\n", e->e_id, e->e_dn, 0 ); #endif /* delete from dn tree inserted above */ if ( avl_delete( &cache->c_dntree, (caddr_t) e, entry_dn_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_update_entry: can't delete (%s)%ld from dn cache.\n", e->e_dn, e->e_id, 0 ); #else Debug( LDAP_DEBUG_ANY, "====> can't delete from dn cache\n", 0, 0, 0 ); #endif } /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( -1 ); } /* put the entry into 'CREATING' state */ /* will be marked after when entry is returned */ BEI(e)->bei_state = CACHE_ENTRY_CREATING; /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); /* lru */ LRU_ADD( cache, e ); if ( ++cache->c_cursize > cache->c_maxsize ) { /* * find the lru entry not currently in use and delete it. * in case a lot of entries are in use, only look at the * first 10 on the tail of the list. */ i = 0; while ( cache->c_lrutail != NULL && BEI(cache->c_lrutail)->bei_refcnt != 0 && i < 10 ) { /* move this in-use entry to the front of the q */ ee = cache->c_lrutail; LRU_DELETE( cache, ee ); LRU_ADD( cache, ee ); i++; } /* * found at least one to delete - try to get back under * the max cache size. */ while ( cache->c_lrutail != NULL && BEI(cache->c_lrutail)->bei_refcnt == 0 && cache->c_cursize > cache->c_maxsize ) { e = cache->c_lrutail; /* delete from cache and lru q */ /* XXX do we need rc ? */ rc = bdb_cache_delete_entry_internal( cache, e ); bdb_cache_entry_private_destroy( e ); bdb_entry_return( e ); } } /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( 0 ); }
Entry * bdb_cache_find_entry_id( DB_ENV *env, Cache *cache, ID id, int rw, u_int32_t locker, DB_LOCK *lock ) { Entry e; Entry *ep; int count = 0; int rc; e.e_id = id; try_again: /* set cache read lock */ ldap_pvt_thread_rdwr_rlock( &cache->c_rwlock ); if ( (ep = (Entry *) avl_find( cache->c_idtree, (caddr_t) &e, entry_id_cmp )) != NULL ) { int state; ID ep_id; count++; assert( ep->e_private ); ep_id = ep->e_id; state = BEI(ep)->bei_state; /* * entry is deleted or not fully created yet */ if ( state != CACHE_ENTRY_READY && state != CACHE_ENTRY_COMMITTED ) { assert(state != CACHE_ENTRY_UNDEFINED); /* free cache read lock */ ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_find_entry_id: (%ld)->%ld not ready (%d).\n", id, ep_id, state ); #else Debug(LDAP_DEBUG_TRACE, "====> bdb_cache_find_entry_id( %ld ): %ld (not ready) %d\n", id, ep_id, state); #endif ldap_pvt_thread_yield(); goto try_again; } /* acquire reader lock */ rc = bdb_cache_entry_db_lock ( env, locker, ep, rw, 0, lock ); #if 0 if ( bdb_cache_entry_rdwr_trylock(ep, rw) == LDAP_PVT_THREAD_EBUSY ) { #endif if ( rc ) { /* will be changed to retry beyond threshold */ /* could not acquire entry lock... * owner cannot free as we have the cache locked. * so, unlock the cache, yield, and try again. */ /* free cache read lock */ ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, INFO, "bdb_cache_find_entry_id: %ld -> %ld (busy) %d.\n", id, ep_id, state ); #else Debug(LDAP_DEBUG_TRACE, "====> bdb_cache_find_entry_id( %ld ): %ld (busy) %d\n", id, ep_id, state); Debug(LDAP_DEBUG_TRACE, "locker = %d\n", locker, 0, 0); #endif ldap_pvt_thread_yield(); goto try_again; } /* Mark entry in-use */ BEI(ep)->bei_refcnt++; /* free cache read lock */ ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); /* lru */ LRU_DELETE( cache, ep ); LRU_ADD( cache, ep ); /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_find_entry_id: %ld -> %s found %d tries.\n", ep_id, ep->e_dn, count ); #else Debug(LDAP_DEBUG_TRACE, "====> bdb_cache_find_entry_id( %ld ) \"%s\" (found) (%d tries)\n", ep_id, ep->e_dn, count); #endif return( ep ); } /* free cache read lock */ ldap_pvt_thread_rdwr_runlock( &cache->c_rwlock ); return( NULL ); } /* * cache_delete_entry - delete the entry e from the cache. the caller * should have obtained e (increasing its ref count) via a call to one * of the cache_find_* routines. the caller should *not* call the * cache_return_entry() routine prior to calling cache_delete_entry(). * it performs this function. * * returns: 0 e was deleted ok * 1 e was not in the cache * -1 something bad happened */ int bdb_cache_delete_entry( Cache *cache, Entry *e ) { int rc; /* set cache write lock */ ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); assert( e->e_private ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, ENTRY, "bdb_cache_delete_entry: delete %ld.\n", e->e_id, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_delete_entry( %ld )\n", e->e_id, 0, 0 ); #endif /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); rc = bdb_cache_delete_entry_internal( cache, e ); /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); return( rc ); }
int bdb_dn2id_add( BackendDB *be, DB_TXN *txn, struct berval *pdn, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc, rlen, nrlen; DBT key, data; DB *db = bdb->bi_id2parent->bdi_db; diskNode *d; idNode *n; nrlen = dn_rdnlen( be, &e->e_nname ); if (nrlen) { rlen = dn_rdnlen( be, &e->e_name ); } else { rlen = 0; } d = ch_malloc(sizeof(diskNode) + rlen + nrlen + 2); d->rdn.bv_len = rlen; d->nrdn.bv_len = nrlen; d->rdn.bv_val = (char *)(d+1); d->nrdn.bv_val = d->rdn.bv_val + rlen + 1; strncpy(d->rdn.bv_val, e->e_dn, rlen); d->rdn.bv_val[rlen] = '\0'; strncpy(d->nrdn.bv_val, e->e_ndn, nrlen); d->nrdn.bv_val[nrlen] = '\0'; d->rdn.bv_val -= (long)d; d->nrdn.bv_val -= (long)d; if (pdn->bv_len) { bdb_dn2id(be, txn, pdn, &d->parent, 0); } else { d->parent = 0; } DBTzero(&key); DBTzero(&data); key.data = &e->e_id; key.size = sizeof(ID); key.flags = DB_DBT_USERMEM; data.data = d; data.size = sizeof(diskNode) + rlen + nrlen + 2; data.flags = DB_DBT_USERMEM; rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); if (rc == 0) { ldap_pvt_thread_rdwr_wlock(&bdb->bi_tree_rdwr); n = bdb_add_node( e->e_id, data.data, bdb); ldap_pvt_thread_rdwr_wunlock(&bdb->bi_tree_rdwr); if (d->parent) { ldap_pvt_thread_rdwr_rlock(&bdb->bi_tree_rdwr); bdb_insert_kid(n, bdb->bi_tree); ldap_pvt_thread_rdwr_runlock(&bdb->bi_tree_rdwr); } } else { free(d); } return rc; }
/* Walk up the tree from a child node, looking for an ID that's already * been linked into the cache. */ int hdb_cache_find_parent( Operation *op, DB_TXN *txn, ID id, EntryInfo **res ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; EntryInfo ei, eip, *ei2 = NULL, *ein = NULL, *eir = NULL; int rc, add; ei.bei_id = id; ei.bei_kids = NULL; ei.bei_ckids = 0; for (;;) { rc = hdb_dn2id_parent( op, txn, &ei, &eip.bei_id ); if ( rc ) break; /* Save the previous node, if any */ ei2 = ein; /* Create a new node for the current ID */ ein = bdb_cache_entryinfo_new( &bdb->bi_cache ); ein->bei_id = ei.bei_id; ein->bei_kids = ei.bei_kids; ein->bei_nrdn = ei.bei_nrdn; ein->bei_rdn = ei.bei_rdn; ein->bei_ckids = ei.bei_ckids; #ifdef SLAP_ZONE_ALLOC ein->bei_bdb = bdb; #endif ei.bei_ckids = 0; add = 1; /* This node is not fully connected yet */ ein->bei_state |= CACHE_ENTRY_NOT_LINKED; /* If this is the first time, save this node * to be returned later. */ if ( eir == NULL ) { eir = ein; ein->bei_finders++; } again: /* Insert this node into the ID tree */ ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock ); if ( avl_insert( &bdb->bi_cache.c_idtree, (caddr_t)ein, bdb_id_cmp, bdb_id_dup_err ) ) { EntryInfo *eix = ein->bei_lrunext; if ( bdb_cache_entryinfo_trylock( eix )) { ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); ldap_pvt_thread_yield(); goto again; } ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); /* Someone else created this node just before us. * Free our new copy and use the existing one. */ bdb_cache_entryinfo_free( &bdb->bi_cache, ein ); /* if it was the node we were looking for, just return it */ if ( eir == ein ) { *res = eix; rc = 0; break; } ein = ei2; ei2 = eix; add = 0; /* otherwise, link up what we have and return */ goto gotparent; } /* If there was a previous node, link it to this one */ if ( ei2 ) ei2->bei_parent = ein; /* Look for this node's parent */ par2: if ( eip.bei_id ) { ei2 = (EntryInfo *) avl_find( bdb->bi_cache.c_idtree, (caddr_t) &eip, bdb_id_cmp ); } else { ei2 = &bdb->bi_cache.c_dntree; } if ( ei2 && bdb_cache_entryinfo_trylock( ei2 )) { ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); ldap_pvt_thread_yield(); ldap_pvt_thread_rdwr_wlock( &bdb->bi_cache.c_rwlock ); goto par2; } if ( add ) bdb->bi_cache.c_eiused++; if ( ei2 && ( ei2->bei_kids || !ei2->bei_id )) bdb->bi_cache.c_leaves++; ldap_pvt_thread_rdwr_wunlock( &bdb->bi_cache.c_rwlock ); gotparent: /* Got the parent, link in and we're done. */ if ( ei2 ) { bdb_cache_entryinfo_lock( eir ); ein->bei_parent = ei2; if ( avl_insert( &ei2->bei_kids, (caddr_t)ein, bdb_rdn_cmp, avl_dup_error) == 0 ) ei2->bei_ckids++; /* Reset all the state info */ for (ein = eir; ein != ei2; ein=ein->bei_parent) ein->bei_state &= ~CACHE_ENTRY_NOT_LINKED; bdb_cache_entryinfo_unlock( ei2 ); eir->bei_finders--; *res = eir; break; } ei.bei_kids = NULL; ei.bei_id = eip.bei_id; ei.bei_ckids = 1; avl_insert( &ei.bei_kids, (caddr_t)ein, bdb_rdn_cmp, avl_dup_error ); } return rc; }
void bdb_cache_return_entry_rw ( DB_ENV *env, Cache *cache, Entry *e, int rw, DB_LOCK *lock ) { ID id; int refcnt, freeit = 1; /* set cache write lock */ ldap_pvt_thread_rdwr_wlock( &cache->c_rwlock ); assert( e->e_private ); bdb_cache_entry_db_unlock( env, lock ); #if 0 bdb_cache_entry_rdwr_unlock(e, rw); #endif id = e->e_id; refcnt = --BEI(e)->bei_refcnt; /* * if the entry is returned when in CREATING state, it is deleted * but not freed because it may belong to someone else (do_add, * for instance) */ if ( BEI(e)->bei_state == CACHE_ENTRY_CREATING ) { /* set lru mutex */ ldap_pvt_thread_mutex_lock( &cache->lru_mutex ); bdb_cache_delete_entry_internal( cache, e ); /* free lru mutex */ ldap_pvt_thread_mutex_unlock( &cache->lru_mutex ); freeit = 0; /* now the entry is in DELETED state */ } if ( BEI(e)->bei_state == CACHE_ENTRY_COMMITTED ) { BEI(e)->bei_state = CACHE_ENTRY_READY; /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_return_entry_rw: return (%ld):%s, refcnt=%d\n", id, rw ? "w" : "r", refcnt ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_return_entry_%s( %ld ): created (%d)\n", rw ? "w" : "r", id, refcnt ); #endif } else if ( BEI(e)->bei_state == CACHE_ENTRY_DELETED ) { if( refcnt > 0 ) { /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_return_entry_rw: %ld, delete pending (%d).\n", id, refcnt, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_return_entry_%s( %ld ): delete pending (%d)\n", rw ? "w" : "r", id, refcnt ); #endif } else { bdb_cache_entry_private_destroy( e ); if ( freeit ) { bdb_entry_return( e ); } /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_return_entry_rw: (%ld): deleted (%d)\n", id, refcnt, 0 ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_return_entry_%s( %ld ): deleted (%d)\n", rw ? "w" : "r", id, refcnt ); #endif } } else { /* free cache write lock */ ldap_pvt_thread_rdwr_wunlock( &cache->c_rwlock ); #ifdef NEW_LOGGING LDAP_LOG( CACHE, DETAIL1, "bdb_cache_return_entry_rw: ID %ld:%s returned (%d)\n", id, rw ? "w": "r", refcnt ); #else Debug( LDAP_DEBUG_TRACE, "====> bdb_cache_return_entry_%s( %ld ): returned (%d)\n", rw ? "w" : "r", id, refcnt); #endif } }