From a2847d0068a5812a06ffd4bc4a8dea30eb9bb7e9 Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Wed, 23 Jul 2014 15:55:36 -0500 Subject: [PATCH] ITS#7904 writewait patch Add sc_writewait callback Invoked before a blocked writer waits for socket to be writable. Use in back-mdb to release reader txn while waiting. --- servers/slapd/back-mdb/search.c | 50 +++++++++++++++++++++++++++++++++ servers/slapd/result.c | 17 +++++++++++ servers/slapd/slap.h | 4 +++ 3 files changed, 71 insertions(+) diff --git a/servers/slapd/back-mdb/search.c b/servers/slapd/back-mdb/search.c index 9872c52205..c63db9c164 100644 --- a/servers/slapd/back-mdb/search.c +++ b/servers/slapd/back-mdb/search.c @@ -316,6 +316,21 @@ static void scope_chunk_ret( Operation *op, ID2 *scopes ) static void *search_stack( Operation *op ); +typedef struct ww_ctx { + MDB_txn *txn; + int flag; +} ww_ctx; + +static void +mdb_writewait( Operation *op, slap_callback *sc ) +{ + ww_ctx *ww = sc->sc_private; + if ( !ww->flag ) { + mdb_txn_reset( ww->txn ); + ww->flag = 1; + } +} + int mdb_search( Operation *op, SlapReply *rs ) { @@ -335,6 +350,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; @@ -673,6 +690,16 @@ 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; @@ -935,6 +962,12 @@ 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; @@ -972,6 +1005,12 @@ 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) @@ -1062,6 +1101,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 ) { diff --git a/servers/slapd/result.c b/servers/slapd/result.c index 0f1336a17f..35cddc70d6 100644 --- a/servers/slapd/result.c +++ b/servers/slapd/result.c @@ -279,6 +279,22 @@ rs_entry2modifiable( Operation *op, SlapReply *rs, slap_overinst *on ) return 1; } +/* Check for any callbacks that want to be informed about being blocked + * on output. These callbacks are expected to leave the callback list + * unmodified. Their result is ignored. + */ +static void +slap_writewait_play( + Operation *op ) +{ + slap_callback *sc = op->o_callback; + + for ( ; sc; sc = sc->sc_next ) { + if ( sc->sc_writewait ) + sc->sc_writewait( op, sc ); + } +} + static long send_ldap_ber( Operation *op, BerElement *ber ) @@ -348,6 +364,7 @@ static long send_ldap_ber( } /* wait for socket to be write-ready */ + slap_writewait_play( op ); ldap_pvt_thread_mutex_lock( &conn->c_write2_mutex ); conn->c_writewaiter = 1; slapd_set_write( conn->c_sd, 2 ); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 99100dd9f8..baf8bc3f6b 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2367,10 +2367,14 @@ struct BackendInfo { typedef int (slap_response)( Operation *, SlapReply * ); +struct slap_callback; +typedef void (slap_writewait)( Operation *, struct slap_callback * ); + typedef struct slap_callback { struct slap_callback *sc_next; slap_response *sc_response; slap_response *sc_cleanup; + slap_writewait *sc_writewait; void *sc_private; } slap_callback; -- 2.39.5