]> git.sur5r.net Git - openldap/commitdiff
ITS#5191 do all pagedresult control parsing in the frontend, don't
authorHoward Chu <hyc@openldap.org>
Thu, 1 Nov 2007 15:11:22 +0000 (15:11 +0000)
committerHoward Chu <hyc@openldap.org>
Thu, 1 Nov 2007 15:11:22 +0000 (15:11 +0000)
re-parse in the backend. Keep track of pagedresult controls and state
in backglue.

servers/slapd/back-bdb/search.c
servers/slapd/back-sql/search.c
servers/slapd/backglue.c
servers/slapd/controls.c
servers/slapd/slap.h

index 17c1a84a2ec0f54462834a367827087925302b56..047a0c314757693e2fc90a7165f2c88b0abdd124 100644 (file)
@@ -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;
 }
index e0777f3e8252d1a9198a88b040c75b67a6a2e896..0da8590cd48b372cd13fdc8daad04b896d87f717 100644 (file)
@@ -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;
 }
index 78d0633cc2f82c2406173f3e20b4e598d4afbe74..f91f1959101e4d608971b63d8cbeec49eca26477 100644 (file)
@@ -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; k<i; k++ ) {
+                                               if ( !strcmp(rs->sr_ctrls[k]->ldctl_oid,
+                                                       LDAP_CONTROL_PAGEDRESULTS )) {
+                                                       newpage = 1;
+                                                       break;
+                                               }
+                                       }
+                                       if ( newpage ) {
+                                               for ( k=0; k<j; k++ ) {
+                                                       if ( !strcmp(gs->ctrls[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;
                        }
index 665e320955ca9621eedfe7b00567abf6e51ca0b7..e220fc103690fded92604f5aa14ffc08f8eb3b4a 100644 (file)
@@ -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;
 }
 
index 8e12ed64c6f2224a8c0e9ee9588b631006771800..eb387104e632df0c88035b0af03875a6f901dfe7 100644 (file)
@@ -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 {