X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fback-mdb%2Fsearch.c;h=98b5f2557f20895337e8f407c5698097505a3feb;hb=ee66ed41d0cb0ac2a45ab07dba369299d4733970;hp=9872c52205d7292bf7ea6974c606742a8d8794e2;hpb=cb7405ae5cbe2b4b0d29bd376db27c7d56048261;p=openldap diff --git a/servers/slapd/back-mdb/search.c b/servers/slapd/back-mdb/search.c index 9872c52205..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 @@ -316,6 +322,75 @@ static void scope_chunk_ret( Operation *op, ID2 *scopes ) 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 ) { @@ -335,6 +410,8 @@ mdb_search( Operation *op, SlapReply *rs ) int tentries = 0; IdScopes isc; MDB_cursor *mci, *mcd; + ww_ctx wwctx; + slap_callback cb = { 0 }; mdb_op_info opinfo = {{{0}}}, *moi = &opinfo; MDB_txn *ltid = NULL; @@ -568,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 @@ -611,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 */ @@ -661,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 ); @@ -936,7 +1025,8 @@ notfound: send_search_reference( op, rs ); - mdb_entry_return( op, e ); + if (e != base) + mdb_entry_return( op, e ); rs->sr_entry = NULL; e = NULL; @@ -944,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; } @@ -998,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 { @@ -1062,6 +1167,17 @@ nochange: rs->sr_err = LDAP_SUCCESS; done: + if ( cb.sc_private ) { + /* remove our writewait callback */ + slap_callback **scp = &op->o_callback; + while ( *scp ) { + if ( *scp == &cb ) { + *scp = cb.sc_next; + cb.sc_private = NULL; + break; + } + } + } mdb_cursor_close( mcd ); mdb_cursor_close( mci ); if ( moi == &opinfo ) { @@ -1075,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; @@ -1164,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; @@ -1230,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 ); }