/* * bdb_idl_notin - return a intersection ~b (or a minus b) */ int bdb_idl_notin( ID *a, ID *b, ID *ids ) { ID ida, idb; ID cursora = 0, cursorb = 0; if( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) || BDB_IDL_IS_RANGE( b ) ) { BDB_IDL_CPY( ids, a ); return 0; } if( BDB_IDL_IS_RANGE( a ) ) { BDB_IDL_CPY( ids, a ); return 0; } ida = bdb_idl_first( a, &cursora ), idb = bdb_idl_first( b, &cursorb ); ids[0] = 0; while( ida != NOID ) { if ( idb == NOID ) { /* we could shortcut this */ ids[++ids[0]] = ida; ida = bdb_idl_next( a, &cursora ); } else if ( ida < idb ) { ids[++ids[0]] = ida; ida = bdb_idl_next( a, &cursora ); } else if ( ida > idb ) { idb = bdb_idl_next( b, &cursorb ); } else { ida = bdb_idl_next( a, &cursora ); idb = bdb_idl_next( b, &cursorb ); } } return 0; }
/* 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; }
/* Append sorted list b to sorted list a. The result is unsorted but * a[1] is the min of the result and a[a[0]] is the max. */ int bdb_idl_append( ID *a, ID *b ) { ID ida, idb, tmp, swap = 0; if ( BDB_IDL_IS_ZERO( b ) ) { return 0; } if ( BDB_IDL_IS_ZERO( a ) ) { BDB_IDL_CPY( a, b ); return 0; } if ( b[0] == 1 ) { return bdb_idl_append_one( a, BDB_IDL_FIRST( b )); } ida = BDB_IDL_LAST( a ); idb = BDB_IDL_LAST( b ); if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) || a[0] + b[0] >= BDB_IDL_UM_MAX ) { a[2] = IDL_MAX( ida, idb ); a[1] = IDL_MIN( a[1], b[1] ); a[0] = NOID; return 0; } if ( ida > idb ) { swap = idb; a[a[0]] = idb; b[b[0]] = ida; } if ( b[1] < a[1] ) { tmp = a[1]; a[1] = b[1]; } else { tmp = b[1]; } a[0]++; a[a[0]] = tmp; { int i = b[0] - 1; AC_MEMCPY(a+a[0]+1, b+2, i * sizeof(ID)); a[0] += i; } if ( swap ) { b[b[0]] = swap; } 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 ); }
/* * idl_union - return a = a union b */ int bdb_idl_union( ID *a, ID *b ) { ID ida, idb; ID cursora = 0, cursorb = 0, cursorc; if ( BDB_IDL_IS_ZERO( b ) ) { return 0; } if ( BDB_IDL_IS_ZERO( a ) ) { BDB_IDL_CPY( a, b ); return 0; } if ( BDB_IDL_IS_RANGE( a ) || BDB_IDL_IS_RANGE(b) ) { over: ida = IDL_MIN( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) ); idb = IDL_MAX( BDB_IDL_LAST(a), BDB_IDL_LAST(b) ); a[0] = NOID; a[1] = ida; a[2] = idb; return 0; } ida = bdb_idl_first( a, &cursora ); idb = bdb_idl_first( b, &cursorb ); cursorc = b[0]; /* The distinct elements of a are cat'd to b */ while( ida != NOID || idb != NOID ) { if ( ida < idb ) { if( ++cursorc > BDB_IDL_UM_MAX ) { goto over; } b[cursorc] = ida; ida = bdb_idl_next( a, &cursora ); } else { if ( ida == idb ) ida = bdb_idl_next( a, &cursora ); idb = bdb_idl_next( b, &cursorb ); } } /* b is copied back to a in sorted order */ a[0] = cursorc; cursora = 1; cursorb = 1; cursorc = b[0]+1; while (cursorb <= b[0] || cursorc <= a[0]) { if (cursorc > a[0]) idb = NOID; else idb = b[cursorc]; if (cursorb <= b[0] && b[cursorb] < idb) a[cursora++] = b[cursorb++]; else { a[cursora++] = idb; cursorc++; } } return 0; }
/* * idl_intersection - return a = a intersection b */ int bdb_idl_intersection( ID *a, ID *b ) { ID ida, idb; ID idmax, idmin; ID cursora = 0, cursorb = 0, cursorc; int swap = 0; if ( BDB_IDL_IS_ZERO( a ) || BDB_IDL_IS_ZERO( b ) ) { a[0] = 0; return 0; } idmin = IDL_MAX( BDB_IDL_FIRST(a), BDB_IDL_FIRST(b) ); idmax = IDL_MIN( BDB_IDL_LAST(a), BDB_IDL_LAST(b) ); if ( idmin > idmax ) { a[0] = 0; return 0; } else if ( idmin == idmax ) { a[0] = 1; a[1] = idmin; return 0; } if ( BDB_IDL_IS_RANGE( a ) ) { if ( BDB_IDL_IS_RANGE(b) ) { /* If both are ranges, just shrink the boundaries */ a[1] = idmin; a[2] = idmax; return 0; } else { /* Else swap so that b is the range, a is a list */ ID *tmp = a; a = b; b = tmp; swap = 1; } } /* If a range completely covers the list, the result is * just the list. If idmin to idmax is contiguous, just * turn it into a range. */ if ( BDB_IDL_IS_RANGE( b ) && BDB_IDL_FIRST( b ) <= BDB_IDL_FIRST( a ) && BDB_IDL_LAST( b ) >= BDB_IDL_LAST( a ) ) { if (idmax - idmin + 1 == a[0]) { a[0] = NOID; a[1] = idmin; a[2] = idmax; } goto done; } /* Fine, do the intersection one element at a time. * First advance to idmin in both IDLs. */ cursora = cursorb = idmin; ida = bdb_idl_first( a, &cursora ); idb = bdb_idl_first( b, &cursorb ); cursorc = 0; while( ida <= idmax || idb <= idmax ) { if( ida == idb ) { a[++cursorc] = ida; ida = bdb_idl_next( a, &cursora ); idb = bdb_idl_next( b, &cursorb ); } else if ( ida < idb ) { ida = bdb_idl_next( a, &cursora ); } else { idb = bdb_idl_next( b, &cursorb ); } } a[0] = cursorc; done: if (swap) BDB_IDL_CPY( b, a ); return 0; }
static int hdb_dn2idl_internal( struct dn2id_cookie *cx ) { BDB_IDL_ZERO( cx->tmp ); if ( cx->bdb->bi_idl_cache_size ) { char *ptr = ((char *)&cx->id)-1; cx->key.data = ptr; cx->key.size = sizeof(ID)+1; if ( cx->prefix == DN_SUBTREE_PREFIX ) { ID *ids = cx->depth ? cx->tmp : cx->ids; *ptr = cx->prefix; cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, ids); if ( cx->rc == LDAP_SUCCESS ) { if ( cx->depth ) { bdb_idl_delete( cx->tmp, cx->id ); /* ITS#6983, drop our own ID */ bdb_idl_append( cx->ids, cx->tmp ); cx->need_sort = 1; } return cx->rc; } } *ptr = DN_ONE_PREFIX; cx->rc = bdb_idl_cache_get(cx->bdb, cx->db, &cx->key, cx->tmp); if ( cx->rc == LDAP_SUCCESS ) { goto gotit; } if ( cx->rc == DB_NOTFOUND ) { return cx->rc; } } bdb_cache_entryinfo_lock( cx->ei ); /* If number of kids in the cache differs from on-disk, load * up all the kids from the database */ if ( cx->ei->bei_ckids+1 != cx->ei->bei_dkids ) { EntryInfo ei; db_recno_t dkids = cx->ei->bei_dkids; ei.bei_parent = cx->ei; /* Only one thread should load the cache */ while ( cx->ei->bei_state & CACHE_ENTRY_ONELEVEL ) { bdb_cache_entryinfo_unlock( cx->ei ); ldap_pvt_thread_yield(); bdb_cache_entryinfo_lock( cx->ei ); if ( cx->ei->bei_ckids+1 == cx->ei->bei_dkids ) { goto synced; } } cx->ei->bei_state |= CACHE_ENTRY_ONELEVEL; bdb_cache_entryinfo_unlock( cx->ei ); cx->rc = cx->db->cursor( cx->db, NULL, &cx->dbc, cx->bdb->bi_db_opflags ); if ( cx->rc ) goto done_one; cx->data.data = &cx->dbuf; cx->data.ulen = sizeof(ID); cx->data.dlen = sizeof(ID); cx->data.flags = DB_DBT_USERMEM | DB_DBT_PARTIAL; /* The first item holds the parent ID. Ignore it. */ cx->key.data = &cx->nid; cx->key.size = sizeof(ID); cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_SET ); if ( cx->rc ) { cx->dbc->c_close( cx->dbc ); goto done_one; } /* If the on-disk count is zero we've never checked it. * Count it now. */ if ( !dkids ) { cx->dbc->c_count( cx->dbc, &dkids, 0 ); cx->ei->bei_dkids = dkids; } cx->data.data = cx->buf; cx->data.ulen = BDB_IDL_UM_SIZE * sizeof(ID); cx->data.flags = DB_DBT_USERMEM; if ( dkids > 1 ) { /* Fetch the rest of the IDs in a loop... */ while ( (cx->rc = cx->dbc->c_get( cx->dbc, &cx->key, &cx->data, DB_MULTIPLE | DB_NEXT_DUP )) == 0 ) { u_int8_t *j; size_t len; void *ptr; DB_MULTIPLE_INIT( ptr, &cx->data ); while (ptr) { DB_MULTIPLE_NEXT( ptr, &cx->data, j, len ); if (j) { EntryInfo *ei2; diskNode *d = (diskNode *)j; short nrlen; BDB_DISK2ID( j + len - sizeof(ID), &ei.bei_id ); nrlen = ((d->nrdnlen[0] ^ 0x80) << 8) | d->nrdnlen[1]; ei.bei_nrdn.bv_len = nrlen; /* nrdn/rdn are set in-place. * hdb_cache_load will copy them as needed */ ei.bei_nrdn.bv_val = d->nrdn; ei.bei_rdn.bv_len = len - sizeof(diskNode) - ei.bei_nrdn.bv_len; ei.bei_rdn.bv_val = d->nrdn + ei.bei_nrdn.bv_len + 1; bdb_idl_append_one( cx->tmp, ei.bei_id ); hdb_cache_load( cx->bdb, &ei, &ei2 ); } } } } cx->rc = cx->dbc->c_close( cx->dbc ); done_one: bdb_cache_entryinfo_lock( cx->ei ); cx->ei->bei_state &= ~CACHE_ENTRY_ONELEVEL; bdb_cache_entryinfo_unlock( cx->ei ); if ( cx->rc ) return cx->rc; } else { /* The in-memory cache is in sync with the on-disk data. * do we have any kids? */ synced: cx->rc = 0; if ( cx->ei->bei_ckids > 0 ) { /* Walk the kids tree; order is irrelevant since bdb_idl_sort * will sort it later. */ avl_apply( cx->ei->bei_kids, apply_func, cx->tmp, -1, AVL_POSTORDER ); } bdb_cache_entryinfo_unlock( cx->ei ); } if ( !BDB_IDL_IS_RANGE( cx->tmp ) && cx->tmp[0] > 3 ) bdb_idl_sort( cx->tmp, cx->buf ); if ( cx->bdb->bi_idl_cache_max_size && !BDB_IDL_IS_ZERO( cx->tmp )) { char *ptr = ((char *)&cx->id)-1; cx->key.data = ptr; cx->key.size = sizeof(ID)+1; *ptr = DN_ONE_PREFIX; bdb_idl_cache_put( cx->bdb, cx->db, &cx->key, cx->tmp, cx->rc ); } gotit: if ( !BDB_IDL_IS_ZERO( cx->tmp )) { if ( cx->prefix == DN_SUBTREE_PREFIX ) { bdb_idl_append( cx->ids, cx->tmp ); cx->need_sort = 1; if ( !(cx->ei->bei_state & CACHE_ENTRY_NO_GRANDKIDS)) { ID *save, idcurs; EntryInfo *ei = cx->ei; int nokids = 1; save = cx->op->o_tmpalloc( BDB_IDL_SIZEOF( cx->tmp ), cx->op->o_tmpmemctx ); BDB_IDL_CPY( save, cx->tmp ); idcurs = 0; cx->depth++; for ( cx->id = bdb_idl_first( save, &idcurs ); cx->id != NOID; cx->id = bdb_idl_next( save, &idcurs )) { EntryInfo *ei2; cx->ei = NULL; if ( bdb_cache_find_id( cx->op, cx->txn, cx->id, &cx->ei, ID_NOENTRY, NULL )) continue; if ( cx->ei ) { ei2 = cx->ei; if ( !( ei2->bei_state & CACHE_ENTRY_NO_KIDS )) { BDB_ID2DISK( cx->id, &cx->nid ); hdb_dn2idl_internal( cx ); if ( !BDB_IDL_IS_ZERO( cx->tmp )) nokids = 0; } bdb_cache_entryinfo_lock( ei2 ); ei2->bei_finders--; bdb_cache_entryinfo_unlock( ei2 ); } } cx->depth--; cx->op->o_tmpfree( save, cx->op->o_tmpmemctx ); if ( nokids ) { bdb_cache_entryinfo_lock( ei ); ei->bei_state |= CACHE_ENTRY_NO_GRANDKIDS; bdb_cache_entryinfo_unlock( ei ); } } /* Make sure caller knows it had kids! */ cx->tmp[0]=1; cx->rc = 0; } else { BDB_IDL_CPY( cx->ids, cx->tmp ); } } return cx->rc; }
static int substring_candidates( Operation *op, DB_TXN *rtxn, SubstringsAssertion *sub, ID *ids, ID *tmp ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr; Debug( LDAP_DEBUG_TRACE, "=> bdb_substring_candidates (%s)\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); BDB_IDL_ALL( bdb, ids ); rc = bdb_index_param( op->o_bd, sub->sa_desc, LDAP_FILTER_SUBSTRINGS, &db, &mask, &prefix ); if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, "<= bdb_substring_candidates: (%s) not indexed\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); return 0; } if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "<= bdb_substring_candidates: (%s) " "index_param failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); return 0; } mr = sub->sa_desc->ad_type->sat_substr; if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (mr->smr_filter)( LDAP_FILTER_SUBSTRINGS, mask, sub->sa_desc->ad_type->sat_syntax, mr, &prefix, sub, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates: (%s) " "MR filter failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); return 0; } if( keys == NULL ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates: (0x%04lx) no keys (%s)\n", mask, sub->sa_desc->ad_cname.bv_val, 0 ); return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = bdb_key_read( op->o_bd, db, rtxn, &keys[i], tmp, NULL, 0 ); if( rc == DB_NOTFOUND ) { BDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates: (%s) " "key read failed (%d)\n", sub->sa_desc->ad_cname.bv_val, rc, 0 ); break; } if( BDB_IDL_IS_ZERO( tmp ) ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates: (%s) NULL\n", sub->sa_desc->ad_cname.bv_val, 0, 0 ); BDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { BDB_IDL_CPY( ids, tmp ); } else { bdb_idl_intersection( ids, tmp ); } if( BDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= bdb_substring_candidates: %ld, first=%ld, last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids) ); return( rc ); }
static int equality_candidates( Operation *op, DB_TXN *rtxn, AttributeAssertion *ava, ID *ids, ID *tmp ) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr; Debug( LDAP_DEBUG_TRACE, "=> bdb_equality_candidates (%s)\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { EntryInfo *ei = NULL; rc = bdb_cache_find_ndn( op, rtxn, &ava->aa_value, &ei ); if ( rc == LDAP_SUCCESS ) { /* exactly one ID can match */ ids[0] = 1; ids[1] = ei->bei_id; } if ( ei ) { bdb_cache_entryinfo_unlock( ei ); } return rc; } BDB_IDL_ALL( bdb, ids ); rc = bdb_index_param( op->o_bd, ava->aa_desc, LDAP_FILTER_EQUALITY, &db, &mask, &prefix ); if ( rc == LDAP_INAPPROPRIATE_MATCHING ) { Debug( LDAP_DEBUG_ANY, "<= bdb_equality_candidates: (%s) not indexed\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "<= bdb_equality_candidates: (%s) " "index_param failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); return 0; } mr = ava->aa_desc->ad_type->sat_equality; if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (mr->smr_filter)( LDAP_FILTER_EQUALITY, mask, ava->aa_desc->ad_type->sat_syntax, mr, &prefix, &ava->aa_value, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_equality_candidates: (%s, %s) " "MR filter failed (%d)\n", prefix.bv_val, ava->aa_desc->ad_cname.bv_val, rc ); return 0; } if( keys == NULL ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_equality_candidates: (%s) no keys\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = bdb_key_read( op->o_bd, db, rtxn, &keys[i], tmp, NULL, 0 ); if( rc == DB_NOTFOUND ) { BDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_equality_candidates: (%s) " "key read failed (%d)\n", ava->aa_desc->ad_cname.bv_val, rc, 0 ); break; } if( BDB_IDL_IS_ZERO( tmp ) ) { Debug( LDAP_DEBUG_TRACE, "<= bdb_equality_candidates: (%s) NULL\n", ava->aa_desc->ad_cname.bv_val, 0, 0 ); BDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { BDB_IDL_CPY( ids, tmp ); } else { bdb_idl_intersection( ids, tmp ); } if( BDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= bdb_equality_candidates: id=%ld, first=%ld, last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids) ); return( rc ); }
static int list_candidates( Operation *op, DB_TXN *rtxn, Filter *flist, int ftype, ID *ids, ID *tmp, ID *save ) { int rc = 0; Filter *f; Debug( LDAP_DEBUG_FILTER, "=> bdb_list_candidates 0x%x\n", ftype, 0, 0 ); for ( f = flist; f != NULL; f = f->f_next ) { /* ignore precomputed scopes */ if ( f->f_choice == SLAPD_FILTER_COMPUTED && f->f_result == LDAP_SUCCESS ) { continue; } BDB_IDL_ZERO( save ); rc = bdb_filter_candidates( op, rtxn, f, save, tmp, save+BDB_IDL_UM_SIZE ); if ( rc != 0 ) { if ( rc == DB_LOCK_DEADLOCK ) return rc; if ( ftype == LDAP_FILTER_AND ) { rc = 0; continue; } break; } if ( ftype == LDAP_FILTER_AND ) { if ( f == flist ) { BDB_IDL_CPY( ids, save ); } else { bdb_idl_intersection( ids, save ); } if( BDB_IDL_IS_ZERO( ids ) ) break; } else { if ( f == flist ) { BDB_IDL_CPY( ids, save ); } else { bdb_idl_union( ids, save ); } } } if( rc == LDAP_SUCCESS ) { Debug( LDAP_DEBUG_FILTER, "<= bdb_list_candidates: id=%ld first=%ld last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids) ); } else { Debug( LDAP_DEBUG_FILTER, "<= bdb_list_candidates: undefined rc=%d\n", rc, 0, 0 ); } return rc; }
static int comp_equality_candidates ( Operation *op, DB_TXN *rtxn, MatchingRuleAssertion *mra, ComponentAssertion *ca, ID *ids, ID *tmp, ID *stack) { struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; DB *db; int i; int rc; slap_mask_t mask; struct berval prefix = {0, NULL}; struct berval *keys = NULL; MatchingRule *mr = mra->ma_rule; Syntax *sat_syntax; ComponentReference* cr_list, *cr; AttrInfo *ai; BDB_IDL_ALL( bdb, ids ); if ( !ca->ca_comp_ref ) return 0; ai = bdb_attr_mask( op->o_bd->be_private, mra->ma_desc ); if( ai ) { cr_list = ai->ai_cr; } else { return 0; } /* find a component reference to be indexed */ sat_syntax = ca->ca_ma_rule->smr_syntax; for ( cr = cr_list ; cr ; cr = cr->cr_next ) { if ( cr->cr_string.bv_len == ca->ca_comp_ref->cr_string.bv_len && strncmp( cr->cr_string.bv_val, ca->ca_comp_ref->cr_string.bv_val,cr->cr_string.bv_len ) == 0 ) break; } if ( !cr ) return 0; rc = bdb_index_param( op->o_bd, mra->ma_desc, LDAP_FILTER_EQUALITY, &db, &mask, &prefix ); if( rc != LDAP_SUCCESS ) { return 0; } if( !mr ) { return 0; } if( !mr->smr_filter ) { return 0; } rc = (ca->ca_ma_rule->smr_filter)( LDAP_FILTER_EQUALITY, cr->cr_indexmask, sat_syntax, ca->ca_ma_rule, &prefix, &ca->ca_ma_value, &keys, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { return 0; } if( keys == NULL ) { return 0; } for ( i= 0; keys[i].bv_val != NULL; i++ ) { rc = bdb_key_read( op->o_bd, db, rtxn, &keys[i], tmp, NULL, 0 ); if( rc == DB_NOTFOUND ) { BDB_IDL_ZERO( ids ); rc = 0; break; } else if( rc != LDAP_SUCCESS ) { break; } if( BDB_IDL_IS_ZERO( tmp ) ) { BDB_IDL_ZERO( ids ); break; } if ( i == 0 ) { BDB_IDL_CPY( ids, tmp ); } else { bdb_idl_intersection( ids, tmp ); } if( BDB_IDL_IS_ZERO( ids ) ) break; } ber_bvarray_free_x( keys, op->o_tmpmemctx ); Debug( LDAP_DEBUG_TRACE, "<= comp_equality_candidates: id=%ld, first=%ld, last=%ld\n", (long) ids[0], (long) BDB_IDL_FIRST(ids), (long) BDB_IDL_LAST(ids) ); 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; }