From 63ff4b42ab64227bb2be08100bac6446ade5e620 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 20 Aug 2014 13:06:51 -0700 Subject: [PATCH] ITS#7904 more tweaks Must save/restore mcd cursor if we're doing a scope-based search. --- servers/slapd/back-mdb/search.c | 83 ++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/servers/slapd/back-mdb/search.c b/servers/slapd/back-mdb/search.c index c63db9c164..2114c10ad0 100644 --- a/servers/slapd/back-mdb/search.c +++ b/servers/slapd/back-mdb/search.c @@ -318,19 +318,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 ) { @@ -678,6 +732,7 @@ dn2entry_retry: iscopes[0] = 0; } + wwctx.mcd = mcd; isc.id = base->e_id; isc.numrdns = 0; rc = mdb_dn2id_walk( op, &isc ); @@ -688,6 +743,7 @@ dn2entry_retry: cscope = 0; } else { id = mdb_idl_first( candidates, &cursor ); + wwctx.mcd = NULL; } wwctx.flag = 0; @@ -962,12 +1018,6 @@ 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 ); rs->sr_entry = NULL; @@ -977,6 +1027,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 +1063,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 +1089,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 { -- 2.39.5