From 8bc46e741ae53d36941a52e2de59538ab743a572 Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Thu, 1 Nov 2007 15:11:22 +0000 Subject: [PATCH] ITS#5191 do all pagedresult control parsing in the frontend, don't re-parse in the backend. Keep track of pagedresult controls and state in backglue. --- servers/slapd/back-bdb/search.c | 58 ++----------------------- servers/slapd/back-sql/search.c | 58 ++----------------------- servers/slapd/backglue.c | 75 ++++++++++++++++++++++++++++++--- servers/slapd/controls.c | 15 +++---- servers/slapd/slap.h | 3 +- 5 files changed, 84 insertions(+), 125 deletions(-) diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 17c1a84a2e..047a0c3147 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -1123,12 +1123,7 @@ static int search_candidates( static int parse_paged_cookie( Operation *op, SlapReply *rs ) { - LDAPControl **c; int rc = LDAP_SUCCESS; - ber_tag_t tag; - ber_int_t size; - BerElement *ber; - struct berval cookie = BER_BVNULL; PagedResultsState *ps = op->o_pagedresults_state; /* this function must be invoked only if the pagedResults @@ -1136,53 +1131,17 @@ parse_paged_cookie( Operation *op, SlapReply *rs ) * by the frontend */ assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); - /* look for the appropriate ctrl structure */ - for ( c = op->o_ctrls; c[0] != NULL; c++ ) { - if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) - { - break; - } - } - - if ( c[0] == NULL ) { - rs->sr_text = "missing pagedResults control"; - return LDAP_PROTOCOL_ERROR; - } - - /* Tested by frontend */ - assert( c[0]->ldctl_value.bv_len > 0 ); - - /* Parse the control value - * realSearchControlValue ::= SEQUENCE { - * size INTEGER (0..maxInt), - * -- requested page size from client - * -- result set size estimate from server - * cookie OCTET STRING - * } - */ - ber = ber_init( &c[0]->ldctl_value ); - if ( ber == NULL ) { - rs->sr_text = "internal error"; - return LDAP_OTHER; - } - - tag = ber_scanf( ber, "{im}", &size, &cookie ); - - /* Tested by frontend */ - assert( tag != LBER_ERROR ); - assert( size >= 0 ); - /* cookie decoding/checks deferred to backend... */ - if ( cookie.bv_len ) { + if ( ps->ps_cookieval.bv_len ) { PagedResultsCookie reqcookie; - if( cookie.bv_len != sizeof( reqcookie ) ) { + if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { /* bad cookie */ rs->sr_text = "paged results cookie is invalid"; rc = LDAP_PROTOCOL_ERROR; goto done; } - AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); if ( reqcookie > ps->ps_cookie ) { /* bad cookie */ @@ -1198,22 +1157,11 @@ parse_paged_cookie( Operation *op, SlapReply *rs ) } else { /* Initial request. Initialize state. */ -#if 0 - if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { - /* There's another pagedResults control on the - * same connection; reject new pagedResults controls - * (allowed by RFC2696) */ - rs->sr_text = "paged results cookie unavailable; try later"; - rc = LDAP_UNWILLING_TO_PERFORM; - goto done; - } -#endif ps->ps_cookie = 0; ps->ps_count = 0; } done:; - (void)ber_free( ber, 1 ); return rc; } diff --git a/servers/slapd/back-sql/search.c b/servers/slapd/back-sql/search.c index e0777f3e82..0da8590cd4 100644 --- a/servers/slapd/back-sql/search.c +++ b/servers/slapd/back-sql/search.c @@ -2668,12 +2668,7 @@ backsql_entry_release( static int parse_paged_cookie( Operation *op, SlapReply *rs ) { - LDAPControl **c; int rc = LDAP_SUCCESS; - ber_tag_t tag; - ber_int_t size; - BerElement *ber; - struct berval cookie = BER_BVNULL; PagedResultsState *ps = op->o_pagedresults_state; /* this function must be invoked only if the pagedResults @@ -2681,53 +2676,17 @@ parse_paged_cookie( Operation *op, SlapReply *rs ) * by the frontend */ assert( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ); - /* look for the appropriate ctrl structure */ - for ( c = op->o_ctrls; c[0] != NULL; c++ ) { - if ( strcmp( c[0]->ldctl_oid, LDAP_CONTROL_PAGEDRESULTS ) == 0 ) - { - break; - } - } - - if ( c[0] == NULL ) { - rs->sr_text = "missing pagedResults control"; - return LDAP_PROTOCOL_ERROR; - } - - /* Tested by frontend */ - assert( c[0]->ldctl_value.bv_len > 0 ); - - /* Parse the control value - * realSearchControlValue ::= SEQUENCE { - * size INTEGER (0..maxInt), - * -- requested page size from client - * -- result set size estimate from server - * cookie OCTET STRING - * } - */ - ber = ber_init( &c[0]->ldctl_value ); - if ( ber == NULL ) { - rs->sr_text = "internal error"; - return LDAP_OTHER; - } - - tag = ber_scanf( ber, "{im}", &size, &cookie ); - - /* Tested by frontend */ - assert( tag != LBER_ERROR ); - assert( size >= 0 ); - /* cookie decoding/checks deferred to backend... */ - if ( cookie.bv_len ) { + if ( ps->ps_cookieval.bv_len ) { PagedResultsCookie reqcookie; - if( cookie.bv_len != sizeof( reqcookie ) ) { + if( ps->ps_cookieval.bv_len != sizeof( reqcookie ) ) { /* bad cookie */ rs->sr_text = "paged results cookie is invalid"; rc = LDAP_PROTOCOL_ERROR; goto done; } - AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie )); + AC_MEMCPY( &reqcookie, ps->ps_cookieval.bv_val, sizeof( reqcookie )); if ( reqcookie > ps->ps_cookie ) { /* bad cookie */ @@ -2743,22 +2702,11 @@ parse_paged_cookie( Operation *op, SlapReply *rs ) } else { /* Initial request. Initialize state. */ -#if 0 - if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) { - /* There's another pagedResults control on the - * same connection; reject new pagedResults controls - * (allowed by RFC2696) */ - rs->sr_text = "paged results cookie unavailable; try later"; - rc = LDAP_UNWILLING_TO_PERFORM; - goto done; - } -#endif ps->ps_cookie = 0; ps->ps_count = 0; } done:; - (void)ber_free( ber, 1 ); return rc; } diff --git a/servers/slapd/backglue.c b/servers/slapd/backglue.c index 78d0633cc2..f91f195910 100644 --- a/servers/slapd/backglue.c +++ b/servers/slapd/backglue.c @@ -161,6 +161,31 @@ glue_op_response ( Operation *op, SlapReply *rs ) if (!j) { newctrls = ch_malloc((i+1)*sizeof(LDAPControl *)); } else { + /* Forget old pagedResults response if we're sending + * a new one now + */ + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { + int newpage = 0; + for ( k=0; ksr_ctrls[k]->ldctl_oid, + LDAP_CONTROL_PAGEDRESULTS )) { + newpage = 1; + break; + } + } + if ( newpage ) { + for ( k=0; kctrls[k]->ldctl_oid, + LDAP_CONTROL_PAGEDRESULTS )) { + gs->ctrls[k]->ldctl_oid = NULL; + ldap_control_free( gs->ctrls[k] ); + gs->ctrls[k] = gs->ctrls[--j]; + gs->ctrls[j] = NULL; + break; + } + } + } + } newctrls = ch_realloc(gs->ctrls, (j+i+1)*sizeof(LDAPControl *)); } @@ -321,7 +346,7 @@ glue_op_search ( Operation *op, SlapReply *rs ) slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; glueinfo *gi = (glueinfo *)on->on_bi.bi_private; BackendDB *b0 = op->o_bd; - BackendDB *b1 = NULL, *btmp; + BackendDB *btmp; BackendInfo *bi0 = op->o_bd->bd_info; int i; long stoptime = 0, starttime; @@ -360,7 +385,6 @@ glue_op_search ( Operation *op, SlapReply *rs ) tlimit0 = op->ors_tlimit; dn = op->o_req_dn; ndn = op->o_req_ndn; - b1 = op->o_bd; /* * Execute in reverse order, most specific first @@ -375,9 +399,16 @@ glue_op_search ( Operation *op, SlapReply *rs ) } if (!btmp || !btmp->be_search) continue; - if (!dnIsSuffix(&btmp->be_nsuffix[0], &b1->be_nsuffix[0])) + if (!dnIsSuffix(&btmp->be_nsuffix[0], &b0->be_nsuffix[0])) + continue; + if (get_no_subordinate_glue(op) && btmp != b0) continue; - if (get_no_subordinate_glue(op) && btmp != b1) + /* If we remembered which backend we were on before, + * skip down to it now + */ + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED && + op->o_conn->c_pagedresults_state.ps_be && + op->o_conn->c_pagedresults_state.ps_be != btmp ) continue; if (tlimit0 != SLAP_NO_LIMIT) { @@ -449,7 +480,41 @@ glue_op_search ( Operation *op, SlapReply *rs ) case LDAP_X_CANNOT_CHAIN: #endif /* LDAP_CONTROL_X_CHAINING_BEHAVIOR */ goto end_of_loop; - + + case LDAP_SUCCESS: + if ( get_pagedresults( op ) > SLAP_CONTROL_IGNORED ) { + PagedResultsState *ps = op->o_pagedresults_state; + + /* Assume this backend can be forgotten now */ + op->o_conn->c_pagedresults_state.ps_be = NULL; + + /* If we have a full page, exit the loop. We may + * need to remember this backend so we can continue + * from here on a subsequent request. + */ + if ( rs->sr_nentries >= ps->ps_size ) { + /* Don't bother to remember the first backend. + * Only remember the last one if there's more state left. + */ + if ( op->o_bd != b0 && + ( op->o_conn->c_pagedresults_state.ps_cookie || + op->o_bd != gi->gi_n[0].gn_be )) + op->o_conn->c_pagedresults_state.ps_be = op->o_bd; + goto end_of_loop; + } + + /* This backend has run out of entries, but more responses + * can fit in the page. Fake a reset of the state so the + * next backend will start up properly. Only back-[bh]db + * and back-sql look at this state info. + */ + if ( ps->ps_cookieval.bv_len == sizeof( PagedResultsCookie )) { + ps->ps_cookie = 0; + memset( ps->ps_cookieval.bv_val, 0, + sizeof( PagedResultsCookie )); + } + } + default: break; } diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 665e320955..e220fc1036 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -1050,12 +1050,13 @@ static int parsePagedResults ( SlapReply *rs, LDAPControl *ctrl ) { + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + struct berval cookie; + PagedResultsState *ps; int rc = LDAP_SUCCESS; ber_tag_t tag; ber_int_t size; - BerElement *ber; - struct berval cookie = BER_BVNULL; - PagedResultsState *ps; if ( op->o_pagedresults != SLAP_CONTROL_NONE ) { rs->sr_text = "paged results control specified multiple times"; @@ -1080,11 +1081,7 @@ static int parsePagedResults ( * cookie OCTET STRING * } */ - ber = ber_init( &ctrl->ldctl_value ); - if ( ber == NULL ) { - rs->sr_text = "internal error"; - return LDAP_OTHER; - } + ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER ); tag = ber_scanf( ber, "{im}", &size, &cookie ); @@ -1103,6 +1100,7 @@ static int parsePagedResults ( ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx ); *ps = op->o_conn->c_pagedresults_state; ps->ps_size = size; + ps->ps_cookieval = cookie; op->o_pagedresults_state = ps; /* NOTE: according to RFC 2696 3.: @@ -1126,7 +1124,6 @@ static int parsePagedResults ( } done:; - (void)ber_free( ber, 1 ); return rc; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 8e12ed64c6..eb387104e6 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -2330,8 +2330,9 @@ typedef unsigned long PagedResultsCookie; typedef struct PagedResultsState { Backend *ps_be; ber_int_t ps_size; - PagedResultsCookie ps_cookie; int ps_count; + PagedResultsCookie ps_cookie; + struct berval ps_cookieval; } PagedResultsState; struct slap_csn_entry { -- 2.39.5