int hdb_dn2id_parent( Operation *op, DB_TXN *txn, EntryInfo *ei, ID *idp ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBT key, data; DBC *cursor; int rc = 0; diskNode *d; char *ptr; ID nid; DBTzero(&key); key.size = sizeof(ID); key.data = &nid; key.ulen = sizeof(ID); key.flags = DB_DBT_USERMEM; BDB_ID2DISK( ei->bei_id, &nid ); DBTzero(&data); data.flags = DB_DBT_USERMEM; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; data.ulen = sizeof(diskNode) + (SLAP_LDAPDN_MAXLEN * 2); d = op->o_tmpalloc( data.ulen, op->o_tmpmemctx ); data.data = d; rc = cursor->c_get( cursor, &key, &data, DB_SET ); if ( rc == 0 ) { if (d->nrdnlen[0] & 0x80) { rc = LDAP_OTHER; } else { db_recno_t dkids; ptr = (char *) data.data + data.size - sizeof(ID); BDB_DISK2ID( ptr, idp ); ei->bei_nrdn.bv_len = (d->nrdnlen[0] << 8) | d->nrdnlen[1]; ber_str2bv( d->nrdn, ei->bei_nrdn.bv_len, 1, &ei->bei_nrdn ); ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - ei->bei_nrdn.bv_len; ptr = d->nrdn + ei->bei_nrdn.bv_len + 1; ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); /* How many children does this node have? */ cursor->c_count( cursor, &dkids, 0 ); ei->bei_dkids = dkids; } } cursor->c_close( cursor ); op->o_tmpfree( d, op->o_tmpmemctx ); return rc; }
int bdb_tool_entry_open( BackendDB *be, int mode ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; /* initialize key and data thangs */ DBTzero( &key ); DBTzero( &data ); key.flags = DB_DBT_USERMEM; key.data = &nid; key.size = key.ulen = sizeof( nid ); data.flags = DB_DBT_USERMEM; if (cursor == NULL) { int rc = bdb->bi_id2entry->bdi_db->cursor( bdb->bi_id2entry->bdi_db, bdb->bi_cache.c_txn, &cursor, bdb->bi_db_opflags ); if( rc != 0 ) { return -1; } } /* Set up for threaded slapindex */ if (( slapMode & (SLAP_TOOL_QUICK|SLAP_TOOL_READONLY)) == SLAP_TOOL_QUICK ) { if ( !bdb_tool_info ) { #ifdef USE_TRICKLE ldap_pvt_thread_mutex_init( &bdb_tool_trickle_mutex ); ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond ); ldap_pvt_thread_cond_init( &bdb_tool_trickle_cond_end ); ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_trickle_task, bdb->bi_dbenv ); #endif ldap_pvt_thread_mutex_init( &bdb_tool_index_mutex ); ldap_pvt_thread_cond_init( &bdb_tool_index_cond_main ); ldap_pvt_thread_cond_init( &bdb_tool_index_cond_work ); if ( bdb->bi_nattrs ) { int i; bdb_tool_threads = slap_tool_thread_max - 1; if ( bdb_tool_threads > 1 ) { bdb_tool_index_threads = ch_malloc( bdb_tool_threads * sizeof( int )); bdb_tool_index_rec = ch_malloc( bdb->bi_nattrs * sizeof( IndexRec )); bdb_tool_index_tcount = bdb_tool_threads - 1; for (i=1; i<bdb_tool_threads; i++) { int *ptr = ch_malloc( sizeof( int )); *ptr = i; ldap_pvt_thread_pool_submit( &connection_pool, bdb_tool_index_task, ptr ); } } } bdb_tool_info = bdb; } } return 0; }
int bdb_dn2id( Operation *op, struct berval *dn, EntryInfo *ei, DB_TXN *txn, DB_LOCK *lock ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBC *cursor; int rc; DBT key, data; ID nid; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id(\"%s\")\n", dn->bv_val, 0, 0 ); DBTzero( &key ); key.size = dn->bv_len + 2; key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); ((char *)key.data)[0] = DN_BASE_PREFIX; AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); /* store the ID */ DBTzero( &data ); data.data = &nid; data.ulen = sizeof(ID); data.flags = DB_DBT_USERMEM; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) goto func_leave; rc = bdb_dn2id_lock( bdb, dn, 0, txn, lock ); if ( rc ) goto nolock; /* fetch it */ rc = cursor->c_get( cursor, &key, &data, DB_SET ); nolock: cursor->c_close( cursor ); func_leave: if( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: get failed: %s (%d)\n", db_strerror( rc ), rc, 0 ); } else { BDB_DISK2ID( &nid, &ei->bei_id ); Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id: got id=0x%lx\n", ei->bei_id, 0, 0 ); } op->o_tmpfree( key.data, op->o_tmpmemctx ); return rc; }
int bdb_dn2id_children( BackendDB *be, DB_TXN *txn, struct berval *dn, int flags ) { int rc; DBT key, data; struct bdb_info *bdb = (struct bdb_info *) be->be_private; DB *db = bdb->bi_dn2id->bdi_db; ID id; #ifdef NEW_LOGGING LDAP_LOG ( INDEX, ARGS, "=> bdb_dn2id_children( %s )\n", dn->bv_val, 0, 0 ); #else Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children( %s )\n", dn->bv_val, 0, 0 ); #endif DBTzero( &key ); key.size = dn->bv_len + 2; key.data = ch_malloc( key.size ); ((char *)key.data)[0] = DN_ONE_PREFIX; AC_MEMCPY( &((char *)key.data)[1], dn->bv_val, key.size - 1 ); /* we actually could do a empty get... */ DBTzero( &data ); data.data = &id; data.ulen = sizeof(id); data.flags = DB_DBT_USERMEM; data.doff = 0; data.dlen = sizeof(id); rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags | flags ); free( key.data ); #ifdef NEW_LOGGING LDAP_LOG ( INDEX, DETAIL1, "<= bdb_dn2id_children( %s ): %schildren (%d)\n", dn->bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : db_strerror(rc)), rc ); #else Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children( %s ): %schildren (%d)\n", dn->bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : db_strerror(rc) ), rc ); #endif return rc; }
int hdb_dn2id_children( Operation *op, DB_TXN *txn, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBT key, data; DBC *cursor; int rc; ID id; diskNode d; DBTzero(&key); key.size = sizeof(ID); key.data = &e->e_id; key.flags = DB_DBT_USERMEM; BDB_ID2DISK( e->e_id, &id ); /* IDL cache is in host byte order */ if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, &key, NULL ); if ( rc != LDAP_NO_SUCH_OBJECT ) { return rc; } } key.data = &id; DBTzero(&data); data.data = &d; data.ulen = sizeof(d); data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; data.dlen = sizeof(d); rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) return rc; rc = cursor->c_get( cursor, &key, &data, DB_SET ); if ( rc == 0 ) { db_recno_t dkids; rc = cursor->c_count( cursor, &dkids, 0 ); if ( rc == 0 ) { BEI(e)->bei_dkids = dkids; if ( dkids < 2 ) rc = DB_NOTFOUND; } } cursor->c_close( cursor ); return rc; }
/* read a key */ int bdb_key_read( Backend *be, DB *db, DB_TXN *txn, struct berval *k, ID *ids, DBC **saved_cursor, int get_flag ) { int rc; DBT key; Debug( LDAP_DEBUG_TRACE, "=> key_read\n", 0, 0, 0 ); DBTzero( &key ); bv2DBT(k,&key); key.ulen = key.size; key.flags = DB_DBT_USERMEM; rc = bdb_idl_fetch_key( be, db, txn, &key, ids, saved_cursor, get_flag ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_index_read: failed (%d)\n", rc, 0, 0 ); } else { Debug( LDAP_DEBUG_TRACE, "<= bdb_index_read %ld candidates\n", (long) BDB_IDL_N(ids), 0, 0 ); } return rc; }
static int bdb_cache_entry_db_lock( struct bdb_info *bdb, DB_TXN *txn, EntryInfo *ei, int rw, int tryOnly, DB_LOCK *lock ) { #ifdef NO_DB_LOCK return 0; #else int rc; DBT lockobj; int db_rw; if ( !lock ) return 0; if (rw) db_rw = DB_LOCK_WRITE; else db_rw = DB_LOCK_READ; DBTzero( &lockobj ); lockobj.data = &ei->bei_id; lockobj.size = sizeof(ei->bei_id) + 1; rc = LOCK_GET(bdb->bi_dbenv, TXN_ID(txn), tryOnly ? DB_LOCK_NOWAIT : 0, &lockobj, db_rw, lock); if (rc && !tryOnly) { Debug( LDAP_DEBUG_TRACE, "bdb_cache_entry_db_lock: entry %ld, rw %d, rc %d\n", ei->bei_id, rw, rc ); } return rc; #endif /* NO_DB_LOCK */ }
int bdb_last_id( BackendDB *be, DB_TXN *tid ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; ID id = 0; unsigned char idbuf[sizeof(ID)]; DBT key, data; DBC *cursor; DBTzero( &key ); key.flags = DB_DBT_USERMEM; key.data = (char *) idbuf; key.ulen = sizeof( idbuf ); DBTzero( &data ); data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; /* Get a read cursor */ rc = bdb->bi_id2entry->bdi_db->cursor( bdb->bi_id2entry->bdi_db, tid, &cursor, 0 ); if (rc == 0) { rc = cursor->c_get(cursor, &key, &data, DB_LAST); cursor->c_close(cursor); } switch(rc) { case DB_NOTFOUND: rc = 0; break; case 0: BDB_DISK2ID( idbuf, &id ); break; default: Debug( LDAP_DEBUG_ANY, "=> bdb_last_id: get failed: %s (%d)\n", db_strerror(rc), rc, 0 ); goto done; } bdb->bi_lastid = id; done: return rc; }
int bdb_dn2id_children( Operation *op, DB_TXN *txn, Entry *e ) { DBT key, data; struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; ID id; int rc; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_children(\"%s\")\n", e->e_nname.bv_val, 0, 0 ); DBTzero( &key ); key.size = e->e_nname.bv_len + 2; key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); ((char *)key.data)[0] = DN_ONE_PREFIX; AC_MEMCPY( &((char *)key.data)[1], e->e_nname.bv_val, key.size - 1 ); if ( bdb->bi_idl_cache_size ) { rc = bdb_idl_cache_get( bdb, db, &key, NULL ); if ( rc != LDAP_NO_SUCH_OBJECT ) { op->o_tmpfree( key.data, op->o_tmpmemctx ); return rc; } } /* we actually could do a empty get... */ DBTzero( &data ); data.data = &id; data.ulen = sizeof(id); data.flags = DB_DBT_USERMEM; data.doff = 0; data.dlen = sizeof(id); rc = db->get( db, txn, &key, &data, bdb->bi_db_opflags ); op->o_tmpfree( key.data, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_children(\"%s\"): %s (%d)\n", e->e_nname.bv_val, rc == 0 ? "" : ( rc == DB_NOTFOUND ? "no " : db_strerror(rc) ), rc ); return rc; }
int bdb_dn2idl( Operation *op, DB_TXN *txn, struct berval *ndn, EntryInfo *ei, ID *ids, ID *stack ) { int rc; DBT key; struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; int prefix = ( op->ors_scope == LDAP_SCOPE_ONELEVEL ) ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2idl(\"%s\")\n", ndn->bv_val, 0, 0 ); #ifndef BDB_MULTIPLE_SUFFIXES if ( prefix == DN_SUBTREE_PREFIX && ( ei->bei_id == 0 || ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len ))) { BDB_IDL_ALL(bdb, ids); return 0; } #endif DBTzero( &key ); key.size = ndn->bv_len + 2; key.ulen = key.size; key.flags = DB_DBT_USERMEM; key.data = op->o_tmpalloc( key.size, op->o_tmpmemctx ); ((char *)key.data)[0] = prefix; AC_MEMCPY( &((char *)key.data)[1], ndn->bv_val, key.size - 1 ); BDB_IDL_ZERO( ids ); rc = bdb_idl_fetch_key( op->o_bd, db, txn, &key, ids, NULL, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2idl: get failed: %s (%d)\n", db_strerror( rc ), rc, 0 ); } else { Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2idl: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST( ids ), (long) BDB_IDL_LAST( ids ) ); } op->o_tmpfree( key.data, op->o_tmpmemctx ); return rc; }
int bdb_id2entry_put( BackendDB *be, DB_TXN *tid, Entry *e, int flag ) { 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; #ifdef BDB_HIER struct berval odn, ondn; /* We only store rdns, and they go in the id2parent database. */ odn = e->e_name; ondn = e->e_nname; e->e_name = slap_empty_bv; e->e_nname = slap_empty_bv; #endif DBTzero( &key ); key.data = (char *) &e->e_id; key.size = sizeof(ID); rc = entry_encode( e, &bv ); #ifdef BDB_HIER e->e_name = odn; e->e_nname = ondn; #endif if( rc != LDAP_SUCCESS ) { return -1; } DBTzero( &data ); bv2DBT( &bv, &data ); rc = db->put( db, tid, &key, &data, flag ); free( bv.bv_val ); return rc; }
/* This function initializes the trees at startup time. */ int bdb_build_tree( Backend *be ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBC *cursor; DBT key, data; ID id; idNode *node; bdb->bi_tree = NULL; rc = bdb->bi_id2parent->bdi_db->cursor( bdb->bi_id2parent->bdi_db, NULL, &cursor, bdb->bi_db_opflags ); if( rc != 0 ) { return NOID; } DBTzero( &key ); DBTzero( &data ); key.data = (char *)&id; key.ulen = sizeof( id ); key.flags = DB_DBT_USERMEM; data.flags = DB_DBT_MALLOC; while (cursor->c_get( cursor, &key, &data, DB_NEXT ) == 0) { bdb_add_node( id, data.data, bdb ); } cursor->c_close( cursor ); rc = avl_apply(bdb->bi_tree, bdb_insert_kid, bdb->bi_tree, -1, AVL_INORDER ); return rc; }
/* Add or remove stuff from index files */ int bdb_key_change( Backend *be, DB *db, DB_TXN *txn, struct berval *k, ID id, int op ) { int rc; DBT key; Debug( LDAP_DEBUG_TRACE, "=> key_change(%s,%lx)\n", op == SLAP_INDEX_ADD_OP ? "ADD":"DELETE", (long) id, 0 ); DBTzero( &key ); bv2DBT(k,&key); key.ulen = key.size; key.flags = DB_DBT_USERMEM; if (op == SLAP_INDEX_ADD_OP) { /* Add values */ #ifdef BDB_TOOL_IDL_CACHING if ( slapMode & SLAP_TOOL_QUICK ) rc = bdb_tool_idl_add( be, db, txn, &key, id ); else #endif rc = bdb_idl_insert_key( be, db, txn, &key, id ); if ( rc == DB_KEYEXIST ) rc = 0; } else { /* Delete values */ rc = bdb_idl_delete_key( be, db, txn, &key, id ); if ( rc == DB_NOTFOUND ) rc = 0; } Debug( LDAP_DEBUG_TRACE, "<= key_change %d\n", rc, 0, 0 ); return rc; }
/* Atomically release and reacquire a lock */ int bdb_cache_entry_db_relock( struct bdb_info *bdb, DB_TXN *txn, EntryInfo *ei, int rw, int tryOnly, DB_LOCK *lock ) { #ifdef NO_DB_LOCK return 0; #else int rc; DBT lockobj; DB_LOCKREQ list[2]; if ( !lock ) return 0; DBTzero( &lockobj ); lockobj.data = &ei->bei_id; lockobj.size = sizeof(ei->bei_id) + 1; list[0].op = DB_LOCK_PUT; list[0].lock = *lock; list[1].op = DB_LOCK_GET; list[1].lock = *lock; list[1].mode = rw ? DB_LOCK_WRITE : DB_LOCK_READ; list[1].obj = &lockobj; rc = bdb->bi_dbenv->lock_vec(bdb->bi_dbenv, TXN_ID(txn), tryOnly ? DB_LOCK_NOWAIT : 0, list, 2, NULL ); if (rc && !tryOnly) { Debug( LDAP_DEBUG_TRACE, "bdb_cache_entry_db_relock: entry %ld, rw %d, rc %d\n", ei->bei_id, rw, rc ); } else { *lock = list[1].lock; } return rc; #endif }
int bdb_id2entry_delete( BackendDB *be, DB_TXN *tid, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; DB *db = bdb->bi_id2entry->bdi_db; DBT key; int rc; bdb_cache_delete_entry(&bdb->bi_cache, e); DBTzero( &key ); key.data = (char *) &e->e_id; key.size = sizeof(ID); /* delete from database */ rc = db->del( db, tid, &key, 0 ); return rc; }
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; }
int hdb_dn2id( Operation *op, struct berval *in, EntryInfo *ei, DB_TXN *txn, DBC **cursor ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBT key, data; int rc = 0, nrlen; diskNode *d; char *ptr; unsigned char dlen[2]; ID idp, parentID; Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id(\"%s\")\n", in->bv_val, 0, 0 ); nrlen = dn_rdnlen( op->o_bd, in ); if (!nrlen) nrlen = in->bv_len; DBTzero(&key); key.size = sizeof(ID); key.data = &idp; key.ulen = sizeof(ID); key.flags = DB_DBT_USERMEM; parentID = ( ei->bei_parent != NULL ) ? ei->bei_parent->bei_id : 0; BDB_ID2DISK( parentID, &idp ); DBTzero(&data); data.size = sizeof(diskNode) + nrlen - sizeof(ID) - 1; data.ulen = data.size * 3; data.dlen = data.ulen; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; rc = db->cursor( db, txn, cursor, bdb->bi_db_opflags ); if ( rc ) return rc; d = op->o_tmpalloc( data.size * 3, op->o_tmpmemctx ); d->nrdnlen[1] = nrlen & 0xff; d->nrdnlen[0] = (nrlen >> 8) | 0x80; dlen[0] = d->nrdnlen[0]; dlen[1] = d->nrdnlen[1]; ptr = lutil_strncopy( d->nrdn, in->bv_val, nrlen ); *ptr = '\0'; data.data = d; rc = (*cursor)->c_get( *cursor, &key, &data, DB_GET_BOTH_RANGE ); if ( rc == 0 && (dlen[1] != d->nrdnlen[1] || dlen[0] != d->nrdnlen[0] || strncmp( d->nrdn, in->bv_val, nrlen ))) { rc = DB_NOTFOUND; } if ( rc == 0 ) { ptr = (char *) data.data + data.size - sizeof(ID); BDB_DISK2ID( ptr, &ei->bei_id ); ei->bei_rdn.bv_len = data.size - sizeof(diskNode) - nrlen; ptr = d->nrdn + nrlen + 1; ber_str2bv( ptr, ei->bei_rdn.bv_len, 1, &ei->bei_rdn ); if ( ei->bei_parent != NULL && !ei->bei_parent->bei_dkids ) { db_recno_t dkids; /* How many children does the parent have? */ /* FIXME: do we need to lock the parent * entryinfo? Seems safe... */ (*cursor)->c_count( *cursor, &dkids, 0 ); ei->bei_parent->bei_dkids = dkids; } } op->o_tmpfree( d, op->o_tmpmemctx ); if( rc != 0 ) { Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: get failed: %s (%d)\n", db_strerror( rc ), rc, 0 ); } else { Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id: got id=0x%lx\n", ei->bei_id, 0, 0 ); } return rc; }
int hdb_dn2id_delete( Operation *op, DB_TXN *txn, EntryInfo *eip, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBT key, data; DBC *cursor; diskNode *d; int rc; ID nid; unsigned char dlen[2]; Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_delete 0x%lx: \"%s\"\n", e->e_id, e->e_ndn, 0 ); DBTzero(&key); key.size = sizeof(ID); key.ulen = key.size; key.flags = DB_DBT_USERMEM; BDB_ID2DISK( eip->bei_id, &nid ); DBTzero(&data); data.size = sizeof(diskNode) + BEI(e)->bei_nrdn.bv_len - sizeof(ID) - 1; data.ulen = data.size; data.dlen = data.size; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; key.data = &nid; d = op->o_tmpalloc( data.size, op->o_tmpmemctx ); d->nrdnlen[1] = BEI(e)->bei_nrdn.bv_len & 0xff; d->nrdnlen[0] = (BEI(e)->bei_nrdn.bv_len >> 8) | 0x80; dlen[0] = d->nrdnlen[0]; dlen[1] = d->nrdnlen[1]; memcpy( d->nrdn, BEI(e)->bei_nrdn.bv_val, BEI(e)->bei_nrdn.bv_len+1 ); data.data = d; rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if ( rc ) goto func_leave; /* Delete our ID from the parent's list */ rc = cursor->c_get( cursor, &key, &data, DB_GET_BOTH_RANGE ); if ( rc == 0 ) { if ( dlen[1] == d->nrdnlen[1] && dlen[0] == d->nrdnlen[0] && !strcmp( d->nrdn, BEI(e)->bei_nrdn.bv_val )) rc = cursor->c_del( cursor, 0 ); else rc = DB_NOTFOUND; } /* Delete our ID from the tree. With sorted duplicates, this * will leave any child nodes still hanging around. This is OK * for modrdn, which will add our info back in later. */ if ( rc == 0 ) { BDB_ID2DISK( e->e_id, &nid ); rc = cursor->c_get( cursor, &key, &data, DB_SET ); if ( rc == 0 ) rc = cursor->c_del( cursor, 0 ); } cursor->c_close( cursor ); func_leave: op->o_tmpfree( d, op->o_tmpmemctx ); /* Delete IDL cache entries */ if ( rc == 0 && bdb->bi_idl_cache_size ) { ID tmp[2]; char *ptr = ((char *)&tmp[1])-1; key.data = ptr; key.size = sizeof(ID)+1; tmp[1] = eip->bei_id; *ptr = DN_ONE_PREFIX; bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); if ( eip ->bei_parent ) { *ptr = DN_SUBTREE_PREFIX; for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) { tmp[1] = eip->bei_id; bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); } /* Handle DB with empty suffix */ if ( !op->o_bd->be_suffix[0].bv_len && eip ) { tmp[1] = eip->bei_id; bdb_idl_cache_del_id( bdb, db, &key, e->e_id ); } } } Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 ); return rc; }
/* We add two elements to the DN2ID database - a data item under the parent's * entryID containing the child's RDN and entryID, and an item under the * child's entryID containing the parent's entryID. */ int hdb_dn2id_add( Operation *op, DB_TXN *txn, EntryInfo *eip, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; DBT key, data; ID nid; int rc, rlen, nrlen; diskNode *d; char *ptr; Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2id_add 0x%lx: \"%s\"\n", e->e_id, e->e_ndn, 0 ); nrlen = dn_rdnlen( op->o_bd, &e->e_nname ); if (nrlen) { rlen = dn_rdnlen( op->o_bd, &e->e_name ); } else { nrlen = e->e_nname.bv_len; rlen = e->e_name.bv_len; } d = op->o_tmpalloc(sizeof(diskNode) + rlen + nrlen, op->o_tmpmemctx); d->nrdnlen[1] = nrlen & 0xff; d->nrdnlen[0] = (nrlen >> 8) | 0x80; ptr = lutil_strncopy( d->nrdn, e->e_nname.bv_val, nrlen ); *ptr++ = '\0'; ptr = lutil_strncopy( ptr, e->e_name.bv_val, rlen ); *ptr++ = '\0'; BDB_ID2DISK( e->e_id, ptr ); DBTzero(&key); DBTzero(&data); key.size = sizeof(ID); key.flags = DB_DBT_USERMEM; BDB_ID2DISK( eip->bei_id, &nid ); key.data = &nid; /* Need to make dummy root node once. Subsequent attempts * will fail harmlessly. */ if ( eip->bei_id == 0 ) { diskNode dummy = {{0, 0}, "", "", ""}; data.data = &dummy; data.size = sizeof(diskNode); data.flags = DB_DBT_USERMEM; db->put( db, txn, &key, &data, DB_NODUPDATA ); } data.data = d; data.size = sizeof(diskNode) + rlen + nrlen; data.flags = DB_DBT_USERMEM; rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); if (rc == 0) { BDB_ID2DISK( e->e_id, &nid ); BDB_ID2DISK( eip->bei_id, ptr ); d->nrdnlen[0] ^= 0x80; rc = db->put( db, txn, &key, &data, DB_NODUPDATA ); } /* Update all parents' IDL cache entries */ if ( rc == 0 && bdb->bi_idl_cache_size ) { ID tmp[2]; char *ptr = ((char *)&tmp[1])-1; key.data = ptr; key.size = sizeof(ID)+1; tmp[1] = eip->bei_id; *ptr = DN_ONE_PREFIX; bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); if ( eip->bei_parent ) { *ptr = DN_SUBTREE_PREFIX; for (; eip && eip->bei_parent->bei_id; eip = eip->bei_parent) { tmp[1] = eip->bei_id; bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); } /* Handle DB with empty suffix */ if ( !op->o_bd->be_suffix[0].bv_len && eip ) { tmp[1] = eip->bei_id; bdb_idl_cache_add_id( bdb, db, &key, e->e_id ); } } } op->o_tmpfree( d, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= hdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 ); 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_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_dn2id_add( Operation *op, DB_TXN *txn, EntryInfo *eip, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; int rc; DBT key, data; ID nid; char *buf; struct berval ptr, pdn; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_add 0x%lx: \"%s\"\n", e->e_id, e->e_ndn, 0 ); assert( e->e_id != NOID ); DBTzero( &key ); key.size = e->e_nname.bv_len + 2; key.ulen = key.size; key.flags = DB_DBT_USERMEM; buf = op->o_tmpalloc( key.size, op->o_tmpmemctx ); key.data = buf; buf[0] = DN_BASE_PREFIX; ptr.bv_val = buf + 1; ptr.bv_len = e->e_nname.bv_len; AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); ptr.bv_val[ptr.bv_len] = '\0'; DBTzero( &data ); data.data = &nid; data.size = sizeof( nid ); BDB_ID2DISK( e->e_id, &nid ); /* store it -- don't override */ rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); if( rc != 0 ) { char buf[ SLAP_TEXT_BUFLEN ]; snprintf( buf, sizeof( buf ), "%s => bdb_dn2id_add dn=\"%s\" ID=0x%lx", op->o_log_prefix, e->e_name.bv_val, e->e_id ); Debug( LDAP_DEBUG_ANY, "%s: put failed: %s %d\n", buf, db_strerror(rc), rc ); goto done; } #ifndef BDB_MULTIPLE_SUFFIXES if( !be_issuffix( op->o_bd, &ptr )) #endif { buf[0] = DN_SUBTREE_PREFIX; rc = db->put( db, txn, &key, &data, DB_NOOVERWRITE ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add 0x%lx: subtree (%s) put failed: %d\n", e->e_id, ptr.bv_val, rc ); goto done; } #ifdef BDB_MULTIPLE_SUFFIXES if( !be_issuffix( op->o_bd, &ptr )) #endif { dnParent( &ptr, &pdn ); key.size = pdn.bv_len + 2; key.ulen = key.size; pdn.bv_val[-1] = DN_ONE_PREFIX; key.data = pdn.bv_val-1; ptr = pdn; rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add 0x%lx: parent (%s) insert failed: %d\n", e->e_id, ptr.bv_val, rc ); goto done; } } #ifndef BDB_MULTIPLE_SUFFIXES while( !be_issuffix( op->o_bd, &ptr )) #else for (;;) #endif { ptr.bv_val[-1] = DN_SUBTREE_PREFIX; rc = bdb_idl_insert_key( op->o_bd, db, txn, &key, e->e_id ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_add 0x%lx: subtree (%s) insert failed: %d\n", e->e_id, ptr.bv_val, rc ); break; } #ifdef BDB_MULTIPLE_SUFFIXES if( be_issuffix( op->o_bd, &ptr )) break; #endif dnParent( &ptr, &pdn ); key.size = pdn.bv_len + 2; key.ulen = key.size; key.data = pdn.bv_val - 1; ptr = pdn; } } done: op->o_tmpfree( buf, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_add 0x%lx: %d\n", e->e_id, rc, 0 ); return rc; }
int bdb_dn2id_delete( Operation *op, DB_TXN *txn, EntryInfo *eip, Entry *e ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db = bdb->bi_dn2id->bdi_db; char *buf; DBT key; struct berval pdn, ptr; int rc; Debug( LDAP_DEBUG_TRACE, "=> bdb_dn2id_delete 0x%lx: \"%s\"\n", e->e_id, e->e_ndn, 0 ); DBTzero( &key ); key.size = e->e_nname.bv_len + 2; buf = op->o_tmpalloc( key.size, op->o_tmpmemctx ); key.data = buf; key.flags = DB_DBT_USERMEM; buf[0] = DN_BASE_PREFIX; ptr.bv_val = buf+1; ptr.bv_len = e->e_nname.bv_len; AC_MEMCPY( ptr.bv_val, e->e_nname.bv_val, e->e_nname.bv_len ); ptr.bv_val[ptr.bv_len] = '\0'; /* delete it */ rc = db->del( db, txn, &key, 0 ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: delete failed: %s %d\n", e->e_id, db_strerror(rc), rc ); goto done; } #ifndef BDB_MULTIPLE_SUFFIXES if( !be_issuffix( op->o_bd, &ptr )) #endif { buf[0] = DN_SUBTREE_PREFIX; rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n", e->e_id, ptr.bv_val, rc ); goto done; } #ifdef BDB_MULTIPLE_SUFFIXES if( !be_issuffix( op->o_bd, &ptr )) #endif { dnParent( &ptr, &pdn ); key.size = pdn.bv_len + 2; key.ulen = key.size; pdn.bv_val[-1] = DN_ONE_PREFIX; key.data = pdn.bv_val - 1; ptr = pdn; rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: parent (%s) delete failed: %d\n", e->e_id, ptr.bv_val, rc ); goto done; } } #ifndef BDB_MULTIPLE_SUFFIXES while( !be_issuffix( op->o_bd, &ptr )) #else for (;;) #endif { ptr.bv_val[-1] = DN_SUBTREE_PREFIX; rc = bdb_idl_delete_key( op->o_bd, db, txn, &key, e->e_id ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_dn2id_delete 0x%lx: subtree (%s) delete failed: %d\n", e->e_id, ptr.bv_val, rc ); goto done; } #ifdef BDB_MULTIPLE_SUFFIXES if( be_issuffix( op->o_bd, &ptr )) break; #endif dnParent( &ptr, &pdn ); key.size = pdn.bv_len + 2; key.ulen = key.size; key.data = pdn.bv_val - 1; ptr = pdn; } } done: op->o_tmpfree( buf, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= bdb_dn2id_delete 0x%lx: %d\n", e->e_id, rc, 0 ); return rc; }
int hdb_dn2idl( Operation *op, DB_TXN *txn, struct berval *ndn, EntryInfo *ei, ID *ids, ID *stack ) { struct bdb_info *bdb = (struct bdb_info *)op->o_bd->be_private; struct dn2id_cookie cx; Debug( LDAP_DEBUG_TRACE, "=> hdb_dn2idl(\"%s\")\n", ndn->bv_val, 0, 0 ); #ifndef BDB_MULTIPLE_SUFFIXES if ( op->ors_scope != LDAP_SCOPE_ONELEVEL && ( ei->bei_id == 0 || ( ei->bei_parent->bei_id == 0 && op->o_bd->be_suffix[0].bv_len ))) { BDB_IDL_ALL( bdb, ids ); return 0; } #endif cx.id = ei->bei_id; BDB_ID2DISK( cx.id, &cx.nid ); cx.ei = ei; cx.bdb = bdb; cx.db = cx.bdb->bi_dn2id->bdi_db; cx.prefix = (op->ors_scope == LDAP_SCOPE_ONELEVEL) ? DN_ONE_PREFIX : DN_SUBTREE_PREFIX; cx.ids = ids; cx.tmp = stack; cx.buf = stack + BDB_IDL_UM_SIZE; cx.op = op; cx.txn = txn; cx.need_sort = 0; cx.depth = 0; if ( cx.prefix == DN_SUBTREE_PREFIX ) { ids[0] = 1; ids[1] = cx.id; } else { BDB_IDL_ZERO( ids ); } if ( cx.ei->bei_state & CACHE_ENTRY_NO_KIDS ) return LDAP_SUCCESS; DBTzero(&cx.key); cx.key.ulen = sizeof(ID); cx.key.size = sizeof(ID); cx.key.flags = DB_DBT_USERMEM; DBTzero(&cx.data); hdb_dn2idl_internal(&cx); if ( cx.need_sort ) { char *ptr = ((char *)&cx.id)-1; if ( !BDB_IDL_IS_RANGE( cx.ids ) && cx.ids[0] > 3 ) bdb_idl_sort( cx.ids, cx.tmp ); cx.key.data = ptr; cx.key.size = sizeof(ID)+1; *ptr = cx.prefix; cx.id = ei->bei_id; if ( cx.bdb->bi_idl_cache_max_size ) bdb_idl_cache_put( cx.bdb, cx.db, &cx.key, cx.ids, cx.rc ); } if ( cx.rc == DB_NOTFOUND ) cx.rc = LDAP_SUCCESS; return cx.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, nlo, nhi, nid; char *err; { char buf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_insert_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); } assert( id != NOID ); DBTzero( &data ); data.size = sizeof( ID ); data.ulen = data.size; data.flags = DB_DBT_USERMEM; BDB_ID2DISK( id, &nid ); rc = db->cursor( db, tid, &cursor, bdb->bi_db_opflags ); if ( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } data.data = &nlo; /* 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 ); err = "c_get"; if ( rc == 0 ) { if ( nlo != 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; db_recno_t i; key2.dlen = key2.ulen; key2.flags |= DB_DBT_PARTIAL; BDB_DISK2ID( &nlo, &lo ); data.data = &nhi; 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; } } BDB_DISK2ID( &nhi, &hi ); /* Update hi/lo if needed, then delete all the items * between lo and hi */ if ( id < lo ) { lo = id; nlo = nid; } else if ( id > hi ) { hi = id; nhi = nid; } data.data = &nid; /* Don't fetch anything, just position cursor */ data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; data.dlen = data.ulen = 0; rc = cursor->c_get( cursor, key, &data, DB_SET ); if ( rc != 0 ) { err = "c_get 2"; goto fail; } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del range1"; goto fail; } /* Delete all the records */ for ( i=1; i<count; i++ ) { rc = cursor->c_get( cursor, &key2, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get next_dup"; goto fail; } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del range"; goto fail; } } /* Store the range marker */ data.size = data.ulen = sizeof(ID); data.flags = DB_DBT_USERMEM; nid = 0; rc = cursor->c_put( cursor, key, &data, DB_KEYFIRST ); if ( rc != 0 ) { err = "c_put range"; goto fail; } nid = nlo; rc = cursor->c_put( cursor, key, &data, DB_KEYLAST ); if ( rc != 0 ) { err = "c_put lo"; goto fail; } nid = nhi; 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 = &nlo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } BDB_DISK2ID( &nlo, &lo ); if ( id > lo ) { data.data = &nhi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } BDB_DISK2ID( &nhi, &hi ); } 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 = &nid; 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 = &nid; 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: Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); cursor->c_close( cursor ); return rc; } /* If key was added (didn't already exist) and using IDL cache, * update key in IDL cache. */ if ( !rc && bdb->bi_idl_cache_max_size ) { bdb_idl_cache_add_id( bdb, db, key, id ); } rc = cursor->c_close( cursor ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_insert_key: " "c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); } 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 *txn, DBT *key, ID *ids, DBC **saved_cursor, int get_flag ) { struct bdb_info *bdb = (struct bdb_info *) be->be_private; int rc; DBT data, key2, *kptr; DBC *cursor; ID *i; void *ptr; size_t len; int rc2; int flags = bdb->bi_db_opflags | DB_MULTIPLE; int opflag; /* 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_FULL < 0x04010000 # define BDB_ENOUGH 5 #else /* We sometimes test with tiny IDLs, and BDB always wants buffers * that are at least one page in size. */ # if BDB_IDL_DB_SIZE < 4096 # define BDB_ENOUGH 2048 # else # define BDB_ENOUGH 1 # endif #endif ID buf[BDB_IDL_DB_SIZE*BDB_ENOUGH]; char keybuf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_fetch_key: %s\n", bdb_show_key( key, keybuf ), 0, 0 ); assert( ids != NULL ); if ( saved_cursor && *saved_cursor ) { opflag = DB_NEXT; } else if ( get_flag == LDAP_FILTER_GE ) { opflag = DB_SET_RANGE; } else if ( get_flag == LDAP_FILTER_LE ) { opflag = DB_FIRST; } else { opflag = DB_SET; } /* only non-range lookups can use the IDL cache */ if ( bdb->bi_idl_cache_size && opflag == DB_SET ) { rc = bdb_idl_cache_get( bdb, db, key, ids ); if ( rc != LDAP_NO_SUCH_OBJECT ) return rc; } DBTzero( &data ); data.data = buf; data.ulen = sizeof(buf); data.flags = DB_DBT_USERMEM; /* If we're not reusing an existing cursor, get a new one */ if( opflag != DB_NEXT ) { rc = db->cursor( db, txn, &cursor, bdb->bi_db_opflags ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } } else { cursor = *saved_cursor; } /* If this is a LE lookup, save original key so we can determine * when to stop. If this is a GE lookup, save the key since it * will be overwritten. */ if ( get_flag == LDAP_FILTER_LE || get_flag == LDAP_FILTER_GE ) { DBTzero( &key2 ); key2.flags = DB_DBT_USERMEM; key2.ulen = sizeof(keybuf); key2.data = keybuf; key2.size = key->size; AC_MEMCPY( keybuf, key->data, key->size ); kptr = &key2; } else { kptr = key; } len = key->size; rc = cursor->c_get( cursor, kptr, &data, flags | opflag ); /* skip presence key on range inequality lookups */ while (rc == 0 && kptr->size != len) { rc = cursor->c_get( cursor, kptr, &data, flags | DB_NEXT_NODUP ); } /* If we're doing a LE compare and the new key is greater than * our search key, we're done */ if (rc == 0 && get_flag == LDAP_FILTER_LE && memcmp( kptr->data, key->data, key->size ) > 0 ) { rc = DB_NOTFOUND; } 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; BDB_DISK2ID( j, i ); } } 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) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "range size mismatch: expected %d, got %ld\n", BDB_IDL_RANGE_SIZE, ids[0], 0 ); cursor->c_close( cursor ); return -1; } BDB_IDL_RANGE( ids, ids[2], ids[3] ); } data.size = BDB_IDL_SIZEOF(ids); } if ( saved_cursor && rc == 0 ) { if ( !*saved_cursor ) *saved_cursor = cursor; rc2 = 0; } else rc2 = cursor->c_close( cursor ); if (rc2) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "close failed: %s (%d)\n", db_strerror(rc2), rc2, 0 ); return rc2; } if( rc == DB_NOTFOUND ) { return rc; } else if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "get failed: %s (%d)\n", db_strerror(rc), rc, 0 ); return rc; } else if ( data.size == 0 || data.size % sizeof( ID ) ) { /* size not multiple of ID size */ Debug( LDAP_DEBUG_ANY, "=> bdb_idl_fetch_key: " "odd size: expected %ld multiple, got %ld\n", (long) sizeof( ID ), (long) data.size, 0 ); return -1; } else if ( data.size != BDB_IDL_SIZEOF(ids) ) { /* size mismatch */ 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 ); return -1; } if ( bdb->bi_idl_cache_max_size ) { bdb_idl_cache_put( bdb, db, key, ids, rc ); } return rc; }
static int bdb_tool_idl_flush_one( void *v1, void *arg ) { bdb_tool_idl_cache *ic = v1; DB *db = arg; struct bdb_info *bdb = bdb_tool_info; bdb_tool_idl_cache_entry *ice; DBC *curs; DBT key, data; int i, rc; ID id, nid; /* Freshly allocated, ignore it */ if ( !ic->head && ic->count <= BDB_IDL_DB_SIZE ) { return 0; } rc = db->cursor( db, NULL, &curs, 0 ); if ( rc ) return -1; DBTzero( &key ); DBTzero( &data ); bv2DBT( &ic->kstr, &key ); data.size = data.ulen = sizeof( ID ); data.flags = DB_DBT_USERMEM; data.data = &nid; rc = curs->c_get( curs, &key, &data, DB_SET ); /* If key already exists and we're writing a range... */ if ( rc == 0 && ic->count > BDB_IDL_DB_SIZE ) { /* If it's not currently a range, must delete old info */ if ( nid ) { /* Skip lo */ while ( curs->c_get( curs, &key, &data, DB_NEXT_DUP ) == 0 ) curs->c_del( curs, 0 ); nid = 0; /* Store range marker */ curs->c_put( curs, &key, &data, DB_KEYFIRST ); } else { /* Skip lo */ rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP ); /* Get hi */ rc = curs->c_get( curs, &key, &data, DB_NEXT_DUP ); /* Delete hi */ curs->c_del( curs, 0 ); } BDB_ID2DISK( ic->last, &nid ); curs->c_put( curs, &key, &data, DB_KEYLAST ); rc = 0; } else if ( rc && rc != DB_NOTFOUND ) { rc = -1; } else if ( ic->count > BDB_IDL_DB_SIZE ) { /* range, didn't exist before */ nid = 0; rc = curs->c_put( curs, &key, &data, DB_KEYLAST ); if ( rc == 0 ) { BDB_ID2DISK( ic->first, &nid ); rc = curs->c_put( curs, &key, &data, DB_KEYLAST ); if ( rc == 0 ) { BDB_ID2DISK( ic->last, &nid ); rc = curs->c_put( curs, &key, &data, DB_KEYLAST ); } } if ( rc ) { rc = -1; } } else { int n; /* Just a normal write */ rc = 0; for ( ice = ic->head, n=0; ice; ice = ice->next, n++ ) { int end; if ( ice->next ) { end = IDBLOCK; } else { end = ic->count & (IDBLOCK-1); if ( !end ) end = IDBLOCK; } for ( i=0; i<end; i++ ) { if ( !ice->ids[i] ) continue; BDB_ID2DISK( ice->ids[i], &nid ); rc = curs->c_put( curs, &key, &data, DB_NODUPDATA ); if ( rc ) { if ( rc == DB_KEYEXIST ) { rc = 0; continue; } rc = -1; break; } } if ( rc ) { rc = -1; break; } } if ( ic->head ) { 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 ); } } if ( ic != db->app_private ) { ch_free( ic ); } else { ic->head = ic->tail = NULL; } curs->c_close( curs ); return rc; }
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, nid, nlo, nhi; char *err; { char buf[16]; Debug( LDAP_DEBUG_ARGS, "bdb_idl_delete_key: %lx %s\n", (long) id, bdb_show_key( key, buf ), 0 ); } assert( id != NOID ); if ( bdb->bi_idl_cache_size ) { bdb_idl_cache_del( bdb, db, key ); } BDB_ID2DISK( id, &nid ); 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 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "cursor failed: %s (%d)\n", db_strerror(rc), rc, 0 ); 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 ); err = "c_get"; if ( rc == 0 ) { if ( tmp != 0 ) { /* Not a range, just delete it */ if (tmp != nid) { /* position to correct item */ tmp = nid; rc = cursor->c_get( cursor, key, &data, DB_GET_BOTH ); 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 = &nlo; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get lo"; goto fail; } BDB_DISK2ID( &nlo, &lo ); data.data = &nhi; rc = cursor->c_get( cursor, key, &data, DB_NEXT_DUP ); if ( rc != 0 ) { err = "c_get hi"; goto fail; } BDB_DISK2ID( &nhi, &hi ); 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 = &nlo; cursor->c_get( cursor, key, &data, DB_PREV ); } rc = cursor->c_del( cursor, 0 ); if ( rc != 0 ) { err = "c_del"; goto fail; } } if ( lo <= hi ) { BDB_ID2DISK( id, &nid ); data.data = &nid; 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 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: " "%s failed: %s (%d)\n", err, db_strerror(rc), rc ); } cursor->c_close( cursor ); return rc; } rc = cursor->c_close( cursor ); if( rc != 0 ) { Debug( LDAP_DEBUG_ANY, "=> bdb_idl_delete_key: c_close failed: %s (%d)\n", db_strerror(rc), rc, 0 ); } return rc; }
/* reindex entries on the fly */ static void * bdb_online_index( void *ctx, void *arg ) { struct re_s *rtask = arg; BackendDB *be = rtask->arg; struct bdb_info *bdb = be->be_private; Connection conn = {0}; OperationBuffer opbuf; Operation *op; DBC *curs; DBT key, data; DB_TXN *txn; DB_LOCK lock; ID id, nid; EntryInfo *ei; int rc, getnext = 1; int i; connection_fake_init( &conn, &opbuf, ctx ); op = &opbuf.ob_op; op->o_bd = be; DBTzero( &key ); DBTzero( &data ); id = 1; key.data = &nid; key.size = key.ulen = sizeof(ID); key.flags = DB_DBT_USERMEM; data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; data.dlen = data.ulen = 0; while ( 1 ) { if ( slapd_shutdown ) break; rc = TXN_BEGIN( bdb->bi_dbenv, NULL, &txn, bdb->bi_db_opflags ); if ( rc ) break; if ( getnext ) { getnext = 0; BDB_ID2DISK( id, &nid ); rc = bdb->bi_id2entry->bdi_db->cursor( bdb->bi_id2entry->bdi_db, txn, &curs, bdb->bi_db_opflags ); if ( rc ) { TXN_ABORT( txn ); break; } rc = curs->c_get( curs, &key, &data, DB_SET_RANGE ); curs->c_close( curs ); if ( rc ) { TXN_ABORT( txn ); if ( rc == DB_NOTFOUND ) rc = 0; if ( rc == DB_LOCK_DEADLOCK ) { ldap_pvt_thread_yield(); continue; } break; } BDB_DISK2ID( &nid, &id ); } ei = NULL; rc = bdb_cache_find_id( op, txn, id, &ei, 0, &lock ); if ( rc ) { TXN_ABORT( txn ); if ( rc == DB_LOCK_DEADLOCK ) { ldap_pvt_thread_yield(); continue; } if ( rc == DB_NOTFOUND ) { id++; getnext = 1; continue; } break; } if ( ei->bei_e ) { rc = bdb_index_entry( op, txn, BDB_INDEX_UPDATE_OP, ei->bei_e ); if ( rc == DB_LOCK_DEADLOCK ) { TXN_ABORT( txn ); ldap_pvt_thread_yield(); continue; } if ( rc == 0 ) { rc = TXN_COMMIT( txn, 0 ); txn = NULL; } if ( rc ) break; } id++; getnext = 1; } for ( i = 0; i < bdb->bi_nattrs; i++ ) { if ( bdb->bi_attrs[ i ]->ai_indexmask & BDB_INDEX_DELETING || bdb->bi_attrs[ i ]->ai_newmask == 0 ) { continue; } bdb->bi_attrs[ i ]->ai_indexmask = bdb->bi_attrs[ i ]->ai_newmask; bdb->bi_attrs[ i ]->ai_newmask = 0; } ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); bdb->bi_index_task = NULL; ldap_pvt_runqueue_remove( &slapd_rq, rtask ); ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); return NULL; }