]> git.sur5r.net Git - openldap/commitdiff
use Paged Results when talking to targets (in response to ITS#6664)
authorPierangelo Masarati <ando@openldap.org>
Mon, 3 Jan 2011 17:52:55 +0000 (17:52 +0000)
committerPierangelo Masarati <ando@openldap.org>
Mon, 3 Jan 2011 17:52:55 +0000 (17:52 +0000)
doc/man/man5/slapd-meta.5
servers/slapd/back-meta/back-meta.h
servers/slapd/back-meta/config.c
servers/slapd/back-meta/search.c

index 92a694ea72c059fb6b658545bd90d4487354afbf..1af67466f32f330216f67d9597ecbd2b40475198 100644 (file)
@@ -311,6 +311,18 @@ underlying libldap, with rebinding eventually performed if the
 If set before any target specification, it affects all targets, unless
 overridden by any per-target directive.
 
+.TP
+.B client\-pr {accept-unsolicited|DISABLE|<size>}
+This feature allows to use RFC 2696 Paged Results control when performing
+search operations with a specific target.
+When set to a numeric value, Paged Results control is always
+used with \fIsize\fP as the page size.
+When set to \fIaccept-unsolicited\fP, unsolicited Paged Results
+control responses are accepted and honored.
+By default, Paged Results control is not used and responses are not accepted.
+If set before any target specification, it affects all targets, unless
+overridden by any per-target directive.
+
 .TP
 .B default\-target [<target>]
 The "default\-target" directive can also be used during target specification.
index e285ef4bf38b941751ea9c11fe51b652ea98938a..9a6654c759437aae8c83de1775cfb3dd6520f858 100644 (file)
 #ifndef SLAPD_META_H
 #define SLAPD_META_H
 
+#ifdef LDAP_DEVEL
+#define SLAPD_META_CLIENT_PR 1
+#endif /* LDAP_DEVEL */
+
 #include "proto-meta.h"
 
 /* String rewrite library */
@@ -335,6 +339,19 @@ typedef struct metatarget_t {
        slap_mask_t             mt_rep_flags;
 
        int                     mt_version;
+
+#ifdef SLAPD_META_CLIENT_PR
+       /*
+        * client-side paged results:
+        * -1: accept unsolicited paged results responses
+        *  0: off
+        * >0: always request paged results with size == mt_ps
+        */
+#define META_CLIENT_PR_DISABLE                 (0)
+#define META_CLIENT_PR_ACCEPT_UNSOLICITED      (-1)
+       ber_int_t               mt_ps;
+#endif /* SLAPD_META_CLIENT_PR */
+
        time_t                  mt_network_timeout;
        struct timeval          mt_bind_timeout;
 #define META_BIND_TIMEOUT      LDAP_BACK_RESULT_UTIMEOUT
@@ -411,6 +428,12 @@ typedef struct metainfo_t {
 #define META_BACK_QUARANTINE(mi)       LDAP_BACK_ISSET( (mi), LDAP_BACK_F_QUARANTINE )
 
        int                     mi_version;
+
+#ifdef SLAPD_META_CLIENT_PR
+       ber_int_t               mi_ps;
+#endif /* SLAPD_META_CLIENT_PR */
+
+
        time_t                  mi_network_timeout;
        time_t                  mi_conn_ttl;
        time_t                  mi_idle_timeout;
index e6de08a8ebec085754efaf606f7b7ebbac0e5d8c..ae87023b3d3586b56d19ce1c548b172e4429451e 100644 (file)
@@ -168,6 +168,9 @@ meta_back_db_config(
                }
                mt->mt_flags = mi->mi_flags;
                mt->mt_version = mi->mi_version;
+#ifdef SLAPD_META_CLIENT_PR
+               mt->mt_ps = mi->mi_ps;
+#endif /* SLAPD_META_CLIENT_PR */
                mt->mt_network_timeout = mi->mi_network_timeout;
                mt->mt_bind_timeout = mi->mi_bind_timeout;
                for ( c = 0; c < SLAP_OP_LAST; c++ ) {
@@ -1532,6 +1535,33 @@ idassert-authzFrom       "dn:<rootdn>"
                        return( 1 );
                }
 
+#ifdef SLAPD_META_CLIENT_PR
+       } else if ( strcasecmp( argv[ 0 ], "client-pr" ) == 0 ) {
+               int *ps = mi->mi_ntargets ?
+                               &mi->mi_targets[ mi->mi_ntargets - 1 ]->mt_ps
+                               : &mi->mi_ps;
+
+               if ( argc != 2 ) {
+                       Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" needs 1 argument.\n",
+                               fname, lineno, 0 );
+                       return( 1 );
+               }
+
+               if ( strcasecmp( argv[ 1 ], "accept-unsolicited" ) == 0 ) {
+                       *ps = META_CLIENT_PR_ACCEPT_UNSOLICITED;
+
+               } else if ( strcasecmp( argv[ 1 ], "disable" ) == 0 ) {
+                       *ps = META_CLIENT_PR_DISABLE;
+
+               } else if ( lutil_atoi( ps, argv[ 1 ] ) || *ps < -1 ) {
+                       Debug( LDAP_DEBUG_ANY,
+       "%s: line %d: \"client-pr {accept-unsolicited|disable|<size>}\" invalid arg \"%s\".\n",
+                               fname, lineno, argv[ 1 ] );
+                       return( 1 );
+               }
+#endif /* SLAPD_META_CLIENT_PR */
+
        /* anything else */
        } else {
                return SLAP_CONF_UNKNOWN;
index 27127cf166a92d8bb542ab038dbad5740a20cd34..2c958c719004931f69ba9117266976fbcef8d6d8 100644 (file)
@@ -446,7 +446,9 @@ meta_back_search_start(
        dncookie                *dc,
        metaconn_t              **mcp,
        int                     candidate,
-       SlapReply               *candidates )
+       SlapReply               *candidates,
+       struct berval           *prcookie,
+       ber_int_t               prsize )
 {
        metainfo_t              *mi = ( metainfo_t * )op->o_bd->be_private;
        metatarget_t            *mt = mi->mi_targets[ candidate ];
@@ -461,6 +463,9 @@ meta_back_search_start(
        struct timeval          tv, *tvp = NULL;
        int                     nretries = 1;
        LDAPControl             **ctrls = NULL;
+#ifdef SLAPD_META_CLIENT_PR
+       LDAPControl             **save_ctrls = NULL;
+#endif /* SLAPD_META_CLIENT_PR */
 
        /* this should not happen; just in case... */
        if ( msc->msc_ld == NULL ) {
@@ -614,6 +619,85 @@ meta_back_search_start(
                tvp = &tv;
        }
 
+#ifdef SLAPD_META_CLIENT_PR
+       save_ctrls = op->o_ctrls;
+       {
+               LDAPControl *pr_c = NULL, **next_c = NULL;
+               int i = 0, nc = 0;
+
+               if ( save_ctrls ) {
+                       for ( ; save_ctrls[i] != NULL; i++ );
+                       nc = i;
+                       pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, save_ctrls, &next_c );
+               }
+
+               if ( pr_c != NULL ) nc--;
+               if ( mt->mt_ps > 0 || prcookie != NULL ) nc++;
+
+               if ( mt->mt_ps > 0 || prcookie != NULL || pr_c != NULL ) {
+                       int src = 0, dst = 0;
+                       BerElementBuffer berbuf;
+                       BerElement *ber = (BerElement *)&berbuf;
+                       struct berval val = BER_BVNULL;
+                       ber_len_t len;
+
+                       len = sizeof( LDAPControl * )*( nc + 1 ) + sizeof( LDAPControl );
+
+                       if ( mt->mt_ps > 0 || prcookie != NULL ) {
+                               struct berval nullcookie = BER_BVNULL;
+                               ber_tag_t tag;
+
+                               if ( prsize == 0 && mt->mt_ps > 0 ) prsize = mt->mt_ps;
+                               if ( prcookie == NULL ) prcookie = &nullcookie;
+
+                               ber_init2( ber, NULL, LBER_USE_DER );
+                               tag = ber_printf( ber, "{iO}", prsize, prcookie ); 
+                               if ( tag == LBER_ERROR ) {
+                                       /* error */
+                                       (void) ber_free_buf( ber );
+                                       goto done_pr;
+                               }
+
+                               tag = ber_flatten2( ber, &val, 0 );
+                               if ( tag == LBER_ERROR ) {
+                                       /* error */
+                                       (void) ber_free_buf( ber );
+                                       goto done_pr;
+                               }
+
+                               len += val.bv_len + 1;
+                       }
+
+                       op->o_ctrls = op->o_tmpalloc( len, op->o_tmpmemctx );
+                       if ( save_ctrls ) {
+                               for ( ; save_ctrls[ src ] != NULL; src++ ) {
+                                       if ( save_ctrls[ src ] != pr_c ) {
+                                               op->o_ctrls[ dst ] = save_ctrls[ src ];
+                                               dst++;
+                                       }
+                               }
+                       }
+
+                       if ( mt->mt_ps > 0 || prcookie != NULL ) {
+                               op->o_ctrls[ dst ] = (LDAPControl *)&op->o_ctrls[ nc + 1 ];
+
+                               op->o_ctrls[ dst ]->ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
+                               op->o_ctrls[ dst ]->ldctl_iscritical = 1;
+
+                               op->o_ctrls[ dst ]->ldctl_value.bv_val = (char *)&op->o_ctrls[ dst ][ 1 ];
+                               AC_MEMCPY( op->o_ctrls[ dst ]->ldctl_value.bv_val, val.bv_val, val.bv_len + 1 );
+                               op->o_ctrls[ dst ]->ldctl_value.bv_len = val.bv_len;
+                               dst++;
+
+                               (void)ber_free_buf( ber );
+                       }
+
+                       op->o_ctrls[ dst ] = NULL;
+               }
+done_pr:;
+       }
+#endif /* SLAPD_META_CLIENT_PR */
+
 retry:;
        ctrls = op->o_ctrls;
        if ( meta_back_controls_add( op, rs, *mcp, candidate, &ctrls )
@@ -660,6 +744,12 @@ retry:;
 
 done:;
        (void)mi->mi_ldap_extra->controls_free( op, rs, &ctrls );
+#ifdef SLAPD_META_CLIENT_PR
+       if ( save_ctrls != op->o_ctrls ) {
+               op->o_tmpfree( op->o_ctrls, op->o_tmpmemctx );
+               op->o_ctrls = save_ctrls;
+       }
+#endif /* SLAPD_META_CLIENT_PR */
 
        if ( mapped_attrs ) {
                ber_memfree_x( mapped_attrs, op->o_tmpmemctx );
@@ -742,6 +832,7 @@ getconn:;
                candidates[ i ].sr_text = NULL;
                candidates[ i ].sr_ref = NULL;
                candidates[ i ].sr_ctrls = NULL;
+               candidates[ i ].sr_nentries = 0;
 
                /* get largest timeout among candidates */
                if ( mi->mi_targets[ i ]->mt_timeout[ SLAP_OP_SEARCH ]
@@ -758,7 +849,7 @@ getconn:;
                        continue;
                }
 
-               switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
+               switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
                {
                case META_SEARCH_NOT_CANDIDATE:
                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
@@ -975,7 +1066,7 @@ getconn:;
 
                                case META_SEARCH_CANDIDATE:
                                        candidates[ i ].sr_msgid = META_MSGID_IGNORE;
-                                       switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
+                                       switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
                                        {
                                        case META_SEARCH_CANDIDATE:
                                                assert( candidates[ i ].sr_msgid >= 0 );
@@ -1062,7 +1153,7 @@ really_bad:;
 
                                        if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
-                                               switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates ) )
+                                               switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 ) )
                                                {
                                                        /* means that failed but onerr == continue */
                                                case META_SEARCH_NOT_CANDIDATE:
@@ -1142,6 +1233,9 @@ really_bad:;
                                                candidates[ i ].sr_type = REP_RESULT;
                                        }
 
+                                       /* count entries returned by target */
+                                       candidates[ i ].sr_nentries++;
+
                                        is_ok++;
 
                                        e = ldap_first_entry( msc->msc_ld, msg );
@@ -1285,6 +1379,7 @@ really_bad:;
                                } else if ( rc == LDAP_RES_SEARCH_RESULT ) {
                                        char            buf[ SLAP_TEXT_BUFLEN ];
                                        char            **references = NULL;
+                                       LDAPControl     **ctrls = NULL;
 
                                        if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
                                                /* don't retry any more... */
@@ -1308,7 +1403,7 @@ really_bad:;
                                                (char **)&candidates[ i ].sr_matched,
                                                (char **)&candidates[ i ].sr_text,
                                                &references,
-                                               NULL /* &candidates[ i ].sr_ctrls (unused) */ ,
+                                               &ctrls /* &candidates[ i ].sr_ctrls (unused) */ ,
                                                0 );
                                        if ( rs->sr_err != LDAP_SUCCESS ) {
                                                candidates[ i ].sr_err = rs->sr_err;
@@ -1403,7 +1498,7 @@ really_bad:;
 
                                        /* cleanup */
                                        ber_memvfree( (void **)references );
-       
+
                                        sres = slap_map_api2result( rs );
        
                                        if ( LogTest( LDAP_DEBUG_TRACE | LDAP_DEBUG_ANY ) ) {
@@ -1436,6 +1531,93 @@ really_bad:;
                                                break;
        
                                        case LDAP_SUCCESS:
+                                               if ( ctrls != NULL && ctrls[0] != NULL ) {
+#ifdef SLAPD_META_CLIENT_PR
+                                                       LDAPControl *pr_c, **next_c;
+
+                                                       pr_c = ldap_control_find( LDAP_CONTROL_PAGEDRESULTS, ctrls, &next_c );
+                                                       if ( pr_c != NULL ) {
+                                                               BerElementBuffer berbuf;
+                                                               BerElement *ber = (BerElement *)&berbuf;
+                                                               ber_tag_t tag;
+                                                               ber_int_t prsize;
+                                                               struct berval prcookie;
+
+                                                               /* unsolicited, do not accept */
+                                                               if ( mi->mi_targets[i]->mt_ps == 0 ) {
+                                                                       rs->sr_err = LDAP_OTHER;
+                                                                       goto err_pr;
+                                                               }
+
+                                                               ber_init2( ber, &pr_c->ldctl_value, LBER_USE_DER );
+
+                                                               tag = ber_scanf( ber, "{im}", &prsize, &prcookie );
+                                                               if ( tag == LBER_ERROR ) {
+                                                                       rs->sr_err = LDAP_OTHER;
+                                                                       goto err_pr;
+                                                               }
+
+                                                               /* more pages? new search request */
+                                                               if ( !BER_BVISNULL( &prcookie ) && !BER_BVISEMPTY( &prcookie ) ) {
+                                                                       if ( mi->mi_targets[i]->mt_ps > 0 ) {
+                                                                               /* ignore size if specified */
+                                                                               prsize = 0;
+
+                                                                       } else if ( prsize == 0 ) {
+                                                                               /* guess the page size from the entries returned so far */
+                                                                               prsize = candidates[ i ].sr_nentries;
+                                                                       }
+
+                                                                       candidates[ i ].sr_nentries = 0;
+                                                                       candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+                                                                       candidates[ i ].sr_type = REP_INTERMEDIATE;
+                                                               
+                                                                       assert( candidates[ i ].sr_matched == NULL );
+                                                                       assert( candidates[ i ].sr_text == NULL );
+                                                                       assert( candidates[ i ].sr_ref == NULL );
+
+                                                                       switch ( meta_back_search_start( op, rs, &dc, &mc, i, candidates, &prcookie, prsize ) )
+                                                                       {
+                                                                       case META_SEARCH_CANDIDATE:
+                                                                               assert( candidates[ i ].sr_msgid >= 0 );
+                                                                               ldap_controls_free( ctrls );
+                                                                               goto free_message;
+
+                                                                       case META_SEARCH_ERR:
+err_pr:;
+                                                                               candidates[ i ].sr_err = rs->sr_err;
+                                                                               if ( META_BACK_ONERR_STOP( mi ) ) {
+                                                                                       savepriv = op->o_private;
+                                                                                       op->o_private = (void *)i;
+                                                                                       send_ldap_result( op, rs );
+                                                                                       op->o_private = savepriv;
+                                                                                       ldap_controls_free( ctrls );
+                                                                                       goto finish;
+                                                                               }
+                                                                               /* fallthru */
+
+                                                                       case META_SEARCH_NOT_CANDIDATE:
+                                                                               /* means that meta_back_search_start()
+                                                                                * failed but onerr == continue */
+                                                                               candidates[ i ].sr_msgid = META_MSGID_IGNORE;
+                                                                               assert( ncandidates > 0 );
+                                                                               --ncandidates;
+                                                                               break;
+
+                                                                       default:
+                                                                               /* impossible */
+                                                                               assert( 0 );
+                                                                               break;
+                                                                       }
+                                                                       break;
+                                                               }
+                                                       }
+#endif /* SLAPD_META_CLIENT_PR */
+
+                                                       ldap_controls_free( ctrls );
+                                               }
+                                               /* fallthru */
+
                                        case LDAP_REFERRAL:
                                                is_ok++;
                                                break;
@@ -1499,7 +1681,7 @@ really_bad:;
                                        retcode = meta_search_dobind_result( op, rs, &mc, i, candidates, msg );
                                        if ( retcode == META_SEARCH_CANDIDATE ) {
                                                candidates[ i ].sr_msgid = META_MSGID_IGNORE;
-                                               retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates );
+                                               retcode = meta_back_search_start( op, rs, &dc, &mc, i, candidates, NULL, 0 );
                                        }
        
                                        switch ( retcode ) {