/* Find a db/key pair in the IDL cache. If ids is non-NULL, * copy the cached IDL into it, otherwise just return the status. */ int bdb_idl_cache_get( struct bdb_info *bdb, DB *db, DBT *key, ID *ids ) { bdb_idl_cache_entry_t idl_tmp; bdb_idl_cache_entry_t *matched_idl_entry; int rc = LDAP_NO_SUCH_OBJECT; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_rdwr_rlock( &bdb->bi_idl_tree_rwlock ); matched_idl_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( matched_idl_entry != NULL ) { if ( matched_idl_entry->idl && ids ) BDB_IDL_CPY( ids, matched_idl_entry->idl ); matched_idl_entry->idl_flags |= CACHE_ENTRY_REFERENCED; if ( matched_idl_entry->idl ) rc = LDAP_SUCCESS; else rc = DB_NOTFOUND; } ldap_pvt_thread_rdwr_runlock( &bdb->bi_idl_tree_rwlock ); return rc; }
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 ); }
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 ); }
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 ); }
int bdb_tool_idl_add( BackendDB *be, DB *db, DB_TXN *txn, DBT *key, ID id ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; bdb_tool_idl_cache *ic, itmp; bdb_tool_idl_cache_entry *ice; int rc; if ( !bdb->bi_idl_cache_max_size ) return bdb_idl_insert_key( be, db, txn, key, id ); DBT2bv( key, &itmp.kstr ); ic = avl_find( (Avlnode *)db->app_private, &itmp, bdb_tool_idl_cmp ); /* No entry yet, create one */ if ( !ic ) { DBC *curs; DBT data; ID nid; int rc; ic = ch_malloc( sizeof( bdb_tool_idl_cache ) + itmp.kstr.bv_len ); ic->kstr.bv_len = itmp.kstr.bv_len; ic->kstr.bv_val = (char *)(ic+1); AC_MEMCPY( ic->kstr.bv_val, itmp.kstr.bv_val, ic->kstr.bv_len ); ic->head = ic->tail = NULL; ic->last = 0; ic->count = 0; avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp, avl_dup_error ); /* load existing key count here */ rc = db->cursor( db, NULL, &curs, 0 ); if ( rc ) return rc; data.ulen = sizeof( ID ); data.flags = DB_DBT_USERMEM; data.data = &nid; rc = curs->c_get( curs, key, &data, DB_SET ); if ( rc == 0 ) { if ( nid == 0 ) { ic->count = BDB_IDL_DB_SIZE+1; } else { db_recno_t count; curs->c_count( curs, &count, 0 ); ic->count = count; BDB_DISK2ID( &nid, &ic->first ); } } curs->c_close( curs ); } /* are we a range already? */ if ( ic->count > BDB_IDL_DB_SIZE ) { ic->last = id; return 0; /* Are we at the limit, and converting to a range? */ } else if ( ic->count == BDB_IDL_DB_SIZE ) { int n; for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) /* counting */ ; if ( n ) { ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); ic->tail->next = bdb_tool_idl_free_list; bdb_tool_idl_free_list = ic->head; bdb->bi_idl_cache_size -= n; ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); } ic->head = ic->tail = NULL; ic->last = id; ic->count++; return 0; } /* No free block, create that too */ if ( !ic->tail || ( ic->count & (IDBLOCK-1)) == 0) { ice = NULL; ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); if ( bdb->bi_idl_cache_size >= bdb->bi_idl_cache_max_size ) { ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); rc = bdb_tool_idl_flush_db( db, ic ); if ( rc ) return rc; avl_insert( (Avlnode **)&db->app_private, ic, bdb_tool_idl_cmp, avl_dup_error ); ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_lrulock ); } bdb->bi_idl_cache_size++; if ( bdb_tool_idl_free_list ) { ice = bdb_tool_idl_free_list; bdb_tool_idl_free_list = ice->next; } ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_lrulock ); if ( !ice ) { ice = ch_malloc( sizeof( bdb_tool_idl_cache_entry )); } memset( ice, 0, sizeof( *ice )); if ( !ic->head ) { ic->head = ice; } else { ic->tail->next = ice; } ic->tail = ice; if ( !ic->count ) ic->first = id; } ice = ic->tail; ice->ids[ ic->count & (IDBLOCK-1) ] = id; ic->count++; return 0; }
int bdb_idl_delete_key( BackendDB *be, DB *db, DB_TXN *tid, DBT *key, ID id ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data; DBC *cursor; ID lo, hi, tmp; char *err; { char buf[16]; #ifdef NEW_LOGGING LDAP_LOG( INDEX, ARGS, "bdb_idl_delete_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); #else Debug( LDAP_DEBUG_ARGS, "bdb_idl_delete_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); #endif } assert( id != NOID ); #ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_entry_t *matched_idl_entry, idl_tmp; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_mutex ); matched_idl_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( matched_idl_entry != NULL ) { if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) matched_idl_entry, bdb_idl_entry_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: AVL delete failed\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "AVL delete failed\n", 0, 0, 0 ); #endif } --bdb->bi_idl_cache_size; IDL_LRU_DELETE( bdb, matched_idl_entry ); free( matched_idl_entry->kstr.bv_val ); free( matched_idl_entry->idl ); free( matched_idl_entry ); } ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_mutex ); } #endif DBTzero( &data ); data.data = &tmp; data.size = sizeof( id ); data.ulen = data.size; data.flags = DB_DBT_USERMEM; rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if ( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif return rc; } /* Fetch the first data item for this key, to see if it * exists and if it's a range. */ rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW ); err = "c_get"; if ( rc == 0 ) { if ( tmp != 0 ) { /* Not a range, just delete it */ if (tmp != id) { /* position to correct item */ tmp = id; rc = cursor->c_get( cursor, key, &data, DB_GET_BOTH | DB_RMW ); if ( rc != 0 ) { err = "c_get id"; goto fail; } } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del id"; goto fail; } } else { /* It's a range, see if we need to rewrite * the boundaries */ data.data = &lo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } data.data = &hi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } if ( id == lo || id == hi ) { if ( id == lo ) { id++; lo = id; } else if ( id == hi ) { id--; hi = id; } if ( lo >= hi ) { /* The range has collapsed... */ rc = db->del( db, tid, key, 0 ); if ( rc != 0 ) { err = "del"; goto fail; } } else { if ( id == lo ) { /* reposition on lo slot */ data.data = &lo; cursor->c_get( cursor, key, &data, DB_PREV ); lo = id; } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del"; goto fail; } } if ( lo <= hi ) { data.data = &id; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put lo/hi"; goto fail; } } } } } else { /* initial c_get failed, nothing was done */ fail: if ( rc != DB_NOTFOUND ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: %s failed: %s (%d)\n", err, db_strerror(rc), rc ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); #endif } cursor->c_close( cursor ); return rc; } rc = cursor->c_close( cursor ); if( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_delete_key: c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif } return rc; }
int bdb_idl_insert_key( BackendDB *be, DB *db, DB_TXN *tid, DBT *key, ID id ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data; DBC *cursor; ID lo, hi, tmp; char *err; { char buf[16]; #ifdef NEW_LOGGING LDAP_LOG( INDEX, ARGS, "bdb_idl_insert_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); #else Debug( LDAP_DEBUG_ARGS, "bdb_idl_insert_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); #endif } assert( id != NOID ); #ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_entry_t *matched_idl_entry, idl_tmp; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_mutex ); matched_idl_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( matched_idl_entry != NULL ) { if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) matched_idl_entry, bdb_idl_entry_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: AVL delete failed\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "AVL delete failed\n", 0, 0, 0 ); #endif } --bdb->bi_idl_cache_size; IDL_LRU_DELETE( bdb, matched_idl_entry ); free( matched_idl_entry->kstr.bv_val ); free( matched_idl_entry->idl ); free( matched_idl_entry ); } ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_mutex ); } #endif DBTzero( &data ); data.size = sizeof( ID ); data.ulen = data.size; data.flags = DB_DBT_USERMEM; rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if ( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_insert_key: cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif return rc; } data.data = &tmp; /* Fetch the first data item for this key, to see if it * exists and if it's a range. */ rc = cursor->c_get( cursor, key, &data, DB_SET | DB_RMW ); err = "c_get"; if ( rc == 0 ) { if ( tmp != 0 ) { /* not a range, count the number of items */ db_recno_t count; rc = cursor->c_count( cursor, &count, 0 ); if ( rc != 0 ) { err = "c_count"; goto fail; } if ( count >= BDB_IDL_DB_MAX ) { /* No room, convert to a range */ DBT key2 = *key; key2.dlen = key2.ulen; key2.flags |= DB_DBT_PARTIAL; lo = tmp; data.data = &hi; rc = cursor->c_get( cursor, &key2, &data, DB_NEXT_NODUP ); if ( rc != 0 && rc != DB_NOTFOUND ) { err = "c_get next_nodup"; goto fail; } if ( rc == DB_NOTFOUND ) { rc = cursor->c_get( cursor, key, &data, DB_LAST ); if ( rc != 0 ) { err = "c_get last"; goto fail; } } else { rc = cursor->c_get( cursor, key, &data, DB_PREV ); if ( rc != 0 ) { err = "c_get prev"; goto fail; } } if ( id < lo ) lo = id; else if ( id > hi ) hi = id; rc = db->del( db, tid, key, 0 ); if ( rc != 0 ) { err = "del"; goto fail; } data.data = &id; id = 0; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put 0"; goto fail; } id = lo; rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); if ( rc != 0 ) { err = "c_put lo"; goto fail; } id = hi; rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); if ( rc != 0 ) { err = "c_put hi"; goto fail; } } else { /* There's room, just store it */ goto put1; } } else { /* It's a range, see if we need to rewrite * the boundaries */ hi = id; data.data = &lo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } if ( id > lo ) { data.data = &hi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } } if ( id < lo || id > hi ) { /* Delete the current lo/hi */ rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del"; goto fail; } data.data = &id; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put lo/hi"; goto fail; } } } } else if ( rc == DB_NOTFOUND ) { put1: data.data = &id; rc = cursor->c_put( cursor, key, &data, DB_NODUPDATA ); /* Don't worry if it's already there */ if ( rc != 0 && rc != DB_KEYEXIST ) { err = "c_put id"; goto fail; } } else { /* initial c_get failed, nothing was done */ fail: #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_insert_key: %s failed: %s (%d)\n", err, db_strerror(rc), rc ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); #endif cursor->c_close( cursor ); return rc; } rc = cursor->c_close( cursor ); if( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_insert_key: c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif } return rc; }
int bdb_idl_fetch_key( BackendDB *be, DB *db, DB_TXN *tid, DBT *key, ID *ids ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data; DBC *cursor; ID *i; void *ptr; size_t len; int rc2; int flags = bdb->bi_db_opflags | DB_MULTIPLE; #ifdef SLAP_IDL_CACHE bdb_idl_cache_entry_t idl_tmp; #endif /* If using BerkeleyDB 4.0, the buf must be large enough to * grab the entire IDL in one get(), otherwise BDB will leak * resources on subsequent get's. We can safely call get() * twice - once for the data, and once to get the DB_NOTFOUND * result meaning there's no more data. See ITS#2040 for details. * This bug is fixed in BDB 4.1 so a smaller buffer will work if * stack space is too limited. * * configure now requires Berkeley DB 4.1. */ #if (DB_VERSION_MAJOR == 4) && (DB_VERSION_MINOR == 0) # define BDB_ENOUGH 5 #else # define BDB_ENOUGH 1 #endif ID buf[BDB_IDL_DB_SIZE*BDB_ENOUGH]; char keybuf[16]; #ifdef NEW_LOGGING LDAP_LOG( INDEX, ARGS, "bdb_idl_fetch_key: %s\n", bdb_show_key( key, keybuf ), 0, 0 ); #else Debug( LDAP_DEBUG_ARGS, "bdb_idl_fetch_key: %s\n", bdb_show_key( key, keybuf ), 0, 0 ); #endif assert( ids != NULL ); #ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_entry_t *matched_idl_entry; DBT2bv( key, &idl_tmp.kstr ); idl_tmp.db = db; ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_mutex ); matched_idl_entry = avl_find( bdb->bi_idl_tree, &idl_tmp, bdb_idl_entry_cmp ); if ( matched_idl_entry != NULL ) { BDB_IDL_CPY( ids, matched_idl_entry->idl ); IDL_LRU_DELETE( bdb, matched_idl_entry ); IDL_LRU_ADD( bdb, matched_idl_entry ); ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_mutex ); return LDAP_SUCCESS; } ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_mutex ); } #endif DBTzero( &data ); data.data = buf; data.ulen = sizeof(buf); data.flags = DB_DBT_USERMEM; if ( tid ) flags |= DB_RMW; rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif return rc; } rc = cursor->c_get( cursor, key, &data, flags | DB_SET ); if (rc == 0) { i = ids; while (rc == 0) { u_int8_t *j; DB_MULTIPLE_INIT( ptr, &data ); while (ptr) { DB_MULTIPLE_NEXT(ptr, &data, j, len); if (j) { ++i; AC_MEMCPY( i, j, sizeof(ID) ); } } rc = cursor->c_get( cursor, key, &data, flags | DB_NEXT_DUP ); } if ( rc == DB_NOTFOUND ) rc = 0; ids[0] = i - ids; /* On disk, a range is denoted by 0 in the first element */ if (ids[1] == 0) { if (ids[0] != BDB_IDL_RANGE_SIZE) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "=> bdb_idl_fetch_key: range size mismatch: " "expected %ld, got %ld\n", BDB_IDL_RANGE_SIZE, ids[0], 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "range size mismatch: expected %d, got %ld\n", BDB_IDL_RANGE_SIZE, ids[0], 0 ); #endif cursor->c_close( cursor ); return -1; } BDB_IDL_RANGE( ids, ids[2], ids[3] ); } data.size = BDB_IDL_SIZEOF(ids); } rc2 = cursor->c_close( cursor ); if (rc2) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 ); #endif return rc2; } if( rc == DB_NOTFOUND ) { return rc; } else if( rc != 0 ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: get failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "get failed: %s (%d)\n", db_strerror(rc), rc, 0 ); #endif return rc; } else if ( data.size == 0 || data.size % sizeof( ID ) ) { /* size not multiple of ID size */ #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size, 0 ); #endif return -1; } else if ( data.size != BDB_IDL_SIZEOF(ids) ) { /* size mismatch */ #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: get size mismatch: expected %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "get size mismatch: expected %ld, got %ld\n", (long) ((1 + ids[0]) * sizeof( ID )), (long) data.size, 0 ); #endif return -1; } #ifdef SLAP_IDL_CACHE if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_entry_t *ee; 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 ) ); ee->idl_lru_prev = NULL; ee->idl_lru_next = NULL; BDB_IDL_CPY( ee->idl, ids ); ber_dupbv( &ee->kstr, &idl_tmp.kstr ); ldap_pvt_thread_mutex_lock( &bdb->bi_idl_tree_mutex ); 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 ); } else { IDL_LRU_ADD( bdb, ee ); if ( ++bdb->bi_idl_cache_size > bdb->bi_idl_cache_max_size ) { int i = 0; while ( bdb->bi_idl_lru_tail != NULL && i < 10 ) { ee = bdb->bi_idl_lru_tail; if ( avl_delete( &bdb->bi_idl_tree, (caddr_t) ee, bdb_idl_entry_cmp ) == NULL ) { #ifdef NEW_LOGGING LDAP_LOG( INDEX, ERR, "bdb_idl_fetch_key: AVL delete failed\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "AVL delete failed\n", 0, 0, 0 ); #endif } IDL_LRU_DELETE( bdb, ee ); i++; --bdb->bi_idl_cache_size; ch_free( ee->kstr.bv_val ); ch_free( ee->idl ); ch_free( ee ); } } } ldap_pvt_thread_mutex_unlock( &bdb->bi_idl_tree_mutex ); } #endif return rc; }
int bdb_id2entry_rw( BackendDB *be, DB_TXN *tid, ID id, Entry **e, int rw, u_int32_t locker, DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; DB *db = bdb->bi_id2entry->bdi_db; DBT key, data; struct berval bv; int rc = 0, ret = 0; *e = NULL; DBTzero( &key ); key.data = (char *) &id; key.size = sizeof(ID); DBTzero( &data ); data.flags = DB_DBT_MALLOC; if ((*e = bdb_cache_find_entry_id(bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock)) != NULL) { return 0; } /* fetch it */ rc = db->get( db, tid, &key, &data, bdb->bi_db_opflags | ( rw ? DB_RMW : 0 )); if( rc != 0 ) { return rc; } DBT2bv( &data, &bv ); rc = entry_decode( &bv, e ); if( rc == 0 ) { (*e)->e_id = id; } else { /* only free on error. On success, the entry was * decoded in place. */ ch_free( data.data ); } if ( rc == 0 ) { #ifdef BDB_HIER bdb_fix_dn(be, id, *e); #endif ret = bdb_cache_add_entry_rw( bdb->bi_dbenv, &bdb->bi_cache, *e, rw, locker, lock); while ( ret == 1 || ret == -1 ) { Entry *ee; int add_loop_cnt = 0; if ( (*e)->e_private != NULL ) { free ((*e)->e_private); } (*e)->e_private = NULL; if ( (ee = bdb_cache_find_entry_id (bdb->bi_dbenv, &bdb->bi_cache, id, rw, locker, lock) ) != NULL) { bdb_entry_return ( *e ); *e = ee; return 0; } if ( ++add_loop_cnt == BDB_MAX_ADD_LOOP ) { bdb_entry_return ( *e ); *e = NULL; return LDAP_BUSY; } } if ( ret != 0 ) { if ( (*e)->e_private != NULL ) free ( (*e)->e_private ); bdb_entry_return( *e ); *e = NULL; } rc = ret; } if (rc == 0) { bdb_cache_entry_commit(*e); } return rc; }