X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-mdb%2Fsearch.c;h=98b5f2557f20895337e8f407c5698097505a3feb;hb=ee66ed41d0cb0ac2a45ab07dba369299d4733970;hp=c63db9c1640f89373f318f1f201471e582cda9d6;hpb=98cd6e28571a2a0351d1b5f707514c5832e503c0;p=openldap diff --git a/servers/slapd/back-mdb/search.c b/servers/slapd/back-mdb/search.c index c63db9c164..98b5f2557f 100644 --- a/servers/slapd/back-mdb/search.c +++ b/servers/slapd/back-mdb/search.c @@ -31,10 +31,9 @@ static int search_candidates( Operation *op, SlapReply *rs, Entry *e, - MDB_txn *txn, + IdScopes *isc, MDB_cursor *mci, ID *ids, - ID2L scopes, ID *stack ); static int parse_paged_cookie( Operation *op, SlapReply *rs ); @@ -131,9 +130,8 @@ static int search_aliases( Operation *op, SlapReply *rs, ID e_id, - MDB_txn *txn, + IdScopes *isc, MDB_cursor *mci, - ID2L scopes, ID *stack ) { ID *aliases, *curscop, *visited, *newsubs, *oldsubs, *tmp; @@ -159,7 +157,7 @@ static int search_aliases( /* Find all aliases in database */ MDB_IDL_ZERO( aliases ); - rs->sr_err = mdb_filter_candidates( op, txn, &af, aliases, + rs->sr_err = mdb_filter_candidates( op, isc->mt, &af, aliases, curscop, visited ); if (rs->sr_err != LDAP_SUCCESS || MDB_IDL_IS_ZERO( aliases )) { return rs->sr_err; @@ -177,7 +175,7 @@ static int search_aliases( /* Set curscop to only the aliases in the current scope. Start with * all the aliases, then get the intersection with the scope. */ - rs->sr_err = mdb_idscope( op, txn, e_id, aliases, curscop ); + rs->sr_err = mdb_idscope( op, isc->mt, e_id, aliases, curscop ); /* Dereference all of the aliases in the current scope. */ cursora = 0; @@ -199,7 +197,7 @@ static int search_aliases( /* Actually dereference the alias */ MDB_IDL_ZERO(tmp); - a = deref_base( op, rs, a, &matched, txn, + a = deref_base( op, rs, a, &matched, isc->mt, tmp, visited ); if (a) { /* If the target was not already in our current scopes, @@ -208,10 +206,18 @@ static int search_aliases( ID2 mid; mid.mid = a->e_id; mid.mval.mv_data = NULL; - if (mdb_id2l_insert(scopes, &mid) == 0) { + if (op->ors_scope == LDAP_SCOPE_SUBTREE) { + isc->id = a->e_id; + /* if ID is a child of any of our current scopes, + * ignore it, it's already included. + */ + if (mdb_idscopechk(op, isc)) + goto skip; + } + if (mdb_id2l_insert(isc->scopes, &mid) == 0) { mdb_idl_insert(newsubs, a->e_id); } - mdb_entry_return( op, a ); +skip: mdb_entry_return( op, a ); } else if (matched) { /* Alias could not be dereferenced, or it deref'd to @@ -318,19 +324,73 @@ static void *search_stack( Operation *op ); typedef struct ww_ctx { MDB_txn *txn; + MDB_cursor *mcd; /* if set, save cursor context */ + ID key; + MDB_val data; int flag; } ww_ctx; +/* ITS#7904 if we get blocked while writing results to client, + * release the current reader txn and reacquire it after we + * unblock. + * Slight problem - if we're doing a scope-based walk (mdb_dn2id_walk) + * to return results, we need to remember the state of the mcd cursor. + * If the node that cursor was pointing to gets deleted while we're + * blocked, we may be unable to restore the cursor position. In that + * case return an LDAP_BUSY error - let the client know this search + * couldn't succeed, but might succeed on a retry. + */ static void mdb_writewait( Operation *op, slap_callback *sc ) { ww_ctx *ww = sc->sc_private; if ( !ww->flag ) { + if ( ww->mcd ) { + MDB_val key, data; + mdb_cursor_get( ww->mcd, &key, &data, MDB_GET_CURRENT ); + memcpy( &ww->key, key.mv_data, sizeof(ID) ); + ww->data.mv_size = data.mv_size; + ww->data.mv_data = op->o_tmpalloc( data.mv_size, op->o_tmpmemctx ); + memcpy(ww->data.mv_data, data.mv_data, data.mv_size); + } mdb_txn_reset( ww->txn ); ww->flag = 1; } } +static int +mdb_waitfixup( Operation *op, ww_ctx *ww, MDB_cursor *mci, MDB_cursor *mcd ) +{ + int rc = 0; + ww->flag = 0; + mdb_txn_renew( ww->txn ); + mdb_cursor_renew( ww->txn, mci ); + mdb_cursor_renew( ww->txn, mcd ); + if ( ww->mcd ) { + MDB_val key, data; + key.mv_size = sizeof(ID); + key.mv_data = &ww->key; + data = ww->data; + rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH ); + if ( rc == MDB_NOTFOUND ) { + data = ww->data; + rc = mdb_cursor_get( mcd, &key, &data, MDB_GET_BOTH_RANGE ); + /* the loop will skip this node using NEXT_DUP but we want it + * sent, so go back one space first + */ + if ( rc == MDB_SUCCESS ) + mdb_cursor_get( mcd, &key, &data, MDB_PREV_DUP ); + else + rc = LDAP_BUSY; + } else if ( rc ) { + rc = LDAP_OTHER; + } + op->o_tmpfree( ww->data.mv_data, op->o_tmpmemctx ); + ww->data.mv_data = NULL; + } + return rc; +} + int mdb_search( Operation *op, SlapReply *rs ) { @@ -585,7 +645,7 @@ dn2entry_retry: scopes[1].mid = base->e_id; scopes[1].mval.mv_data = NULL; rs->sr_err = search_candidates( op, rs, base, - ltid, mci, candidates, scopes, stack ); + &isc, mci, candidates, stack ); ncand = MDB_IDL_N( candidates ); if ( !base->e_id || ncand == NOID ) { /* grab entry count from id2entry stat @@ -628,6 +688,17 @@ dn2entry_retry: tentries = ncand; } + wwctx.flag = 0; + /* If we're running in our own read txn */ + if ( moi == &opinfo ) { + cb.sc_writewait = mdb_writewait; + cb.sc_private = &wwctx; + wwctx.txn = ltid; + wwctx.mcd = NULL; + cb.sc_next = op->o_callback; + op->o_callback = &cb; + } + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { PagedResultsState *ps = op->o_pagedresults_state; /* deferred cookie parsing */ @@ -678,6 +749,7 @@ dn2entry_retry: iscopes[0] = 0; } + wwctx.mcd = mcd; isc.id = base->e_id; isc.numrdns = 0; rc = mdb_dn2id_walk( op, &isc ); @@ -690,16 +762,6 @@ dn2entry_retry: id = mdb_idl_first( candidates, &cursor ); } - wwctx.flag = 0; - /* If we're running in our own read txn */ - if ( moi == &opinfo ) { - cb.sc_writewait = mdb_writewait; - cb.sc_private = &wwctx; - wwctx.txn = ltid; - cb.sc_next = op->o_callback; - op->o_callback = &cb; - } - while (id != NOID) { int scopeok; @@ -962,14 +1024,9 @@ notfound: rs->sr_flags = 0; send_search_reference( op, rs ); - if ( wwctx.flag ) { - wwctx.flag = 0; - mdb_txn_renew( ltid ); - mdb_cursor_renew( ltid, mci ); - mdb_cursor_renew( ltid, mcd ); - } - mdb_entry_return( op, e ); + if (e != base) + mdb_entry_return( op, e ); rs->sr_entry = NULL; e = NULL; @@ -977,6 +1034,14 @@ notfound: ber_bvarray_free( erefs ); rs->sr_ref = NULL; + if ( wwctx.flag ) { + rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd ); + if ( rs->sr_err ) { + send_ldap_result( op, rs ); + goto done; + } + } + goto loop_continue; } @@ -1005,12 +1070,6 @@ notfound: rs->sr_flags = 0; rs->sr_err = LDAP_SUCCESS; rs->sr_err = send_search_entry( op, rs ); - if ( wwctx.flag ) { - wwctx.flag = 0; - mdb_txn_renew( ltid ); - mdb_cursor_renew( ltid, mci ); - mdb_cursor_renew( ltid, mcd ); - } rs->sr_attrs = NULL; rs->sr_entry = NULL; if (e != base) @@ -1037,6 +1096,13 @@ notfound: } goto done; } + if ( wwctx.flag ) { + rs->sr_err = mdb_waitfixup( op, &wwctx, mci, mcd ); + if ( rs->sr_err ) { + send_ldap_result( op, rs ); + goto done; + } + } } } else { @@ -1125,7 +1191,7 @@ done: rs->sr_v2ref = NULL; } if (base) - mdb_entry_return( op,base); + mdb_entry_return( op, base ); scope_chunk_ret( op, scopes ); return rs->sr_err; @@ -1214,10 +1280,9 @@ static int search_candidates( Operation *op, SlapReply *rs, Entry *e, - MDB_txn *txn, + IdScopes *isc, MDB_cursor *mci, ID *ids, - ID2L scopes, ID *stack ) { struct mdb_info *mdb = (struct mdb_info *) op->o_bd->be_private; @@ -1280,13 +1345,13 @@ static int search_candidates( } if( op->ors_deref & LDAP_DEREF_SEARCHING ) { - rc = search_aliases( op, rs, e->e_id, txn, mci, scopes, stack ); + rc = search_aliases( op, rs, e->e_id, isc, mci, stack ); } else { rc = LDAP_SUCCESS; } if ( rc == LDAP_SUCCESS ) { - rc = mdb_filter_candidates( op, txn, f, ids, + rc = mdb_filter_candidates( op, isc->mt, f, ids, stack, stack+MDB_IDL_UM_SIZE ); }