Back to index

openldap  2.4.31
slapd-mtread.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1999-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* ACKNOWLEDGEMENTS:
00016  * This work was initially developed by Kurt Spanier for inclusion
00017  * in OpenLDAP Software.
00018  */
00019 
00020 /*
00021  * This tool is a MT reader.  It behaves like slapd-read however
00022  * with one or more threads simultaneously using the same connection.
00023  * If -M is enabled, then M threads will also perform write operations.
00024  */
00025 
00026 #include "portable.h"
00027 
00028 #include <stdio.h>
00029 #include "ldap_pvt_thread.h"
00030 
00031 #include "ac/stdlib.h"
00032 
00033 #include "ac/ctype.h"
00034 #include "ac/param.h"
00035 #include "ac/socket.h"
00036 #include "ac/string.h"
00037 #include "ac/unistd.h"
00038 #include "ac/wait.h"
00039 
00040 #include "ldap.h"
00041 #include "lutil.h"
00042 
00043 #include "ldap_pvt.h"
00044 
00045 #include "slapd-common.h"
00046 
00047 #define MAXCONN      512
00048 #define LOOPS 100
00049 #define RETRIES      0
00050 #define DEFAULT_BASE "ou=people,dc=example,dc=com"
00051 
00052 static void
00053 do_conn( char *uri, char *manager, struct berval *passwd,
00054        LDAP **ld, int nobind, int maxretries, int conn_num );
00055 
00056 static void
00057 do_read( LDAP *ld, char *entry,
00058        char **attrs, int noattrs, int nobind, int maxloop,
00059        int maxretries, int delay, int force, int chaserefs, int idx );
00060 
00061 static void
00062 do_random( LDAP *ld,
00063        char *sbase, char *filter, char **attrs, int noattrs, int nobind,
00064        int innerloop, int maxretries, int delay, int force, int chaserefs,
00065        int idx );
00066 
00067 static void
00068 do_random2( LDAP *ld,
00069        char *sbase, char *filter, char **attrs, int noattrs, int nobind,
00070        int innerloop, int maxretries, int delay, int force, int chaserefs,
00071        int idx );
00072 
00073 static void *
00074 do_onethread( void *arg );
00075 
00076 static void *
00077 do_onerwthread( void *arg );
00078 
00079 #define MAX_THREAD   1024
00080 /* Use same array for readers and writers, offset writers by MAX_THREAD */
00081 int    rt_pass[MAX_THREAD*2];
00082 int    rt_fail[MAX_THREAD*2];
00083 int    *rwt_pass = rt_pass + MAX_THREAD;
00084 int    *rwt_fail = rt_fail + MAX_THREAD;
00085 ldap_pvt_thread_t    rtid[MAX_THREAD*2], *rwtid = rtid + MAX_THREAD;
00086 
00087 /*
00088  * Shared globals (command line args)
00089  */
00090 LDAP          *ld = NULL;
00091 char          *entry = NULL;
00092 char          *filter  = NULL;
00093 int           loops = LOOPS;
00094 int           outerloops = 1;
00095 int           retries = RETRIES;
00096 int           delay = 0;
00097 int           force = 0;
00098 int           chaserefs = 0;
00099 char          *srchattrs[] = { "1.1", NULL };
00100 char          **attrs = srchattrs;
00101 int           noattrs = 0;
00102 int           nobind = 0;
00103 int           threads = 1;
00104 int           rwthreads = 0;
00105 int           verbose = 0;
00106 
00107 int           noconns = 1;
00108 LDAP          **lds = NULL;
00109 
00110 static void
00111 thread_error(int idx, char *string)
00112 {
00113        char          thrstr[BUFSIZ];
00114 
00115        snprintf(thrstr, BUFSIZ, "error on tidx: %d: %s", idx, string);
00116        tester_error( thrstr );
00117 }
00118 
00119 static void
00120 thread_output(int idx, char *string)
00121 {
00122        char          thrstr[BUFSIZ];
00123 
00124        snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string);
00125        tester_error( thrstr );
00126 }
00127 
00128 static void
00129 thread_verbose(int idx, char *string)
00130 {
00131        char          thrstr[BUFSIZ];
00132 
00133        if (!verbose)
00134               return;
00135        snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string);
00136        tester_error( thrstr );
00137 }
00138 
00139 static void
00140 usage( char *name )
00141 {
00142         fprintf( stderr,
00143               "usage: %s "
00144               "-H <uri> | ([-h <host>] -p <port>) "
00145               "-D <manager> "
00146               "-w <passwd> "
00147               "-e <entry> "
00148               "[-A] "
00149               "[-C] "
00150               "[-F] "
00151               "[-N] "
00152               "[-v] "
00153               "[-c connections] "
00154               "[-f filter] "
00155               "[-i <ignore>] "
00156               "[-l <loops>] "
00157               "[-L <outerloops>] "
00158               "[-m threads] "
00159               "[-M threads] "
00160               "[-r <maxretries>] "
00161               "[-t <delay>] "
00162               "[-T <attrs>] "
00163               "[<attrs>] "
00164               "\n",
00165               name );
00166        exit( EXIT_FAILURE );
00167 }
00168 
00169 int
00170 main( int argc, char **argv )
00171 {
00172        int           i;
00173        char          *uri = NULL;
00174        char          *host = "localhost";
00175        int           port = -1;
00176        char          *manager = NULL;
00177        struct berval passwd = { 0, NULL };
00178        char          outstr[BUFSIZ];
00179        int           ptpass;
00180        int           testfail = 0;
00181 
00182 
00183        tester_init( "slapd-mtread", TESTER_READ );
00184 
00185        /* by default, tolerate referrals and no such object */
00186        tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
00187 
00188        while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:p:r:t:T:w:v" )) != EOF ) {
00189               switch ( i ) {
00190               case 'A':
00191                      noattrs++;
00192                      break;
00193 
00194               case 'C':
00195                      chaserefs++;
00196                      break;
00197 
00198               case 'H':            /* the server uri */
00199                      uri = strdup( optarg );
00200                      break;
00201 
00202               case 'h':            /* the servers host */
00203                      host = strdup( optarg );
00204 
00205               case 'i':
00206                      tester_ignore_str2errlist( optarg );
00207                      break;
00208 
00209               case 'N':
00210                      nobind++;
00211                      break;
00212 
00213               case 'v':
00214                      verbose++;
00215                      break;
00216 
00217               case 'p':            /* the servers port */
00218                      if ( lutil_atoi( &port, optarg ) != 0 ) {
00219                             usage( argv[0] );
00220                      }
00221                      break;
00222 
00223               case 'D':            /* the servers manager */
00224                      manager = strdup( optarg );
00225                      break;
00226 
00227               case 'w':            /* the server managers password */
00228                      passwd.bv_val = strdup( optarg );
00229                      passwd.bv_len = strlen( optarg );
00230                      memset( optarg, '*', passwd.bv_len );
00231                      break;
00232 
00233               case 'c':            /* the number of connections */
00234                      if ( lutil_atoi( &noconns, optarg ) != 0 ) {
00235                             usage( argv[0] );
00236                      }
00237                      break;
00238 
00239               case 'e':            /* DN to search for */
00240                      entry = strdup( optarg );
00241                      break;
00242 
00243               case 'f':            /* the search request */
00244                      filter = strdup( optarg );
00245                      break;
00246 
00247               case 'F':
00248                      force++;
00249                      break;
00250 
00251               case 'l':            /* the number of loops */
00252                      if ( lutil_atoi( &loops, optarg ) != 0 ) {
00253                             usage( argv[0] );
00254                      }
00255                      break;
00256 
00257               case 'L':            /* the number of outerloops */
00258                      if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
00259                             usage( argv[0] );
00260                      }
00261                      break;
00262 
00263               case 'M':            /* the number of R/W threads */
00264                      if ( lutil_atoi( &rwthreads, optarg ) != 0 ) {
00265                             usage( argv[0] );
00266                      }
00267                      if (rwthreads > MAX_THREAD)
00268                             rwthreads = MAX_THREAD;
00269                      break;
00270 
00271               case 'm':            /* the number of threads */
00272                      if ( lutil_atoi( &threads, optarg ) != 0 ) {
00273                             usage( argv[0] );
00274                      }
00275                      if (threads > MAX_THREAD)
00276                             threads = MAX_THREAD;
00277                      break;
00278 
00279               case 'r':            /* the number of retries */
00280                      if ( lutil_atoi( &retries, optarg ) != 0 ) {
00281                             usage( argv[0] );
00282                      }
00283                      break;
00284 
00285               case 't':            /* delay in seconds */
00286                      if ( lutil_atoi( &delay, optarg ) != 0 ) {
00287                             usage( argv[0] );
00288                      }
00289                      break;
00290 
00291               case 'T':
00292                      attrs = ldap_str2charray( optarg, "," );
00293                      if ( attrs == NULL ) {
00294                             usage( argv[0] );
00295                      }
00296                      break;
00297 
00298               default:
00299                      usage( argv[0] );
00300                      break;
00301               }
00302        }
00303 
00304        if (( entry == NULL ) || ( port == -1 && uri == NULL ))
00305               usage( argv[0] );
00306 
00307        if ( *entry == '\0' ) {
00308               fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
00309                             argv[0] );
00310               exit( EXIT_FAILURE );
00311        }
00312 
00313        if ( argv[optind] != NULL ) {
00314               attrs = &argv[optind];
00315        }
00316 
00317        if (noconns < 1)
00318               noconns = 1;
00319        if (noconns > MAXCONN)
00320               noconns = MAXCONN;
00321        lds = (LDAP **) calloc( sizeof(LDAP *), noconns);
00322        if (lds == NULL) {
00323               fprintf( stderr, "%s: Memory error: calloc noconns.\n",
00324                             argv[0] );
00325               exit( EXIT_FAILURE );
00326        }
00327 
00328        uri = tester_uri( uri, host, port );
00329        /* One connection and one connection only */
00330        do_conn( uri, manager, &passwd, &ld, nobind, retries, 0 );
00331        lds[0] = ld;
00332        for(i = 1; i < noconns; i++) {
00333               do_conn( uri, manager, &passwd, &lds[i], nobind, retries, i );
00334        }
00335 
00336        ldap_pvt_thread_initialize();
00337 
00338        snprintf(outstr, BUFSIZ, "MT Test Start: conns: %d (%s)", noconns, uri);
00339        tester_error(outstr);
00340        snprintf(outstr, BUFSIZ, "Threads: RO: %d RW: %d", threads, rwthreads);
00341        tester_error(outstr);
00342 
00343        /* Set up read only threads */
00344        for ( i = 0; i < threads; i++ ) {
00345               ldap_pvt_thread_create( &rtid[i], 0, do_onethread, &rtid[i]);
00346               snprintf(outstr, BUFSIZ, "Created RO thread %d", i);
00347               thread_verbose(-1, outstr);
00348        }
00349        /* Set up read/write threads */
00350        for ( i = 0; i < rwthreads; i++ ) {
00351               ldap_pvt_thread_create( &rwtid[i], 0, do_onerwthread, &rwtid[i]);
00352               snprintf(outstr, BUFSIZ, "Created RW thread %d", i + MAX_THREAD);
00353               thread_verbose(-1, outstr);
00354        }
00355 
00356        ptpass =  outerloops * loops;
00357 
00358        /* wait for read only threads to complete */
00359        for ( i = 0; i < threads; i++ )
00360               ldap_pvt_thread_join(rtid[i], NULL);
00361        /* wait for read/write threads to complete */
00362        for ( i = 0; i < rwthreads; i++ )
00363               ldap_pvt_thread_join(rwtid[i], NULL);
00364 
00365        for(i = 0; i < noconns; i++) {
00366               if ( lds[i] != NULL ) {
00367                      ldap_unbind_ext( lds[i], NULL, NULL );
00368               }
00369        }
00370        free( lds );
00371 
00372        for ( i = 0; i < threads; i++ ) {
00373               snprintf(outstr, BUFSIZ, "RO thread %d pass=%d fail=%d", i,
00374                      rt_pass[i], rt_fail[i]);
00375               tester_error(outstr);
00376               if (rt_fail[i] != 0 || rt_pass[i] != ptpass) {
00377                      snprintf(outstr, BUFSIZ, "FAIL RO thread %d", i);
00378                      tester_error(outstr);
00379                      testfail++;
00380               }
00381        }
00382        for ( i = 0; i < rwthreads; i++ ) {
00383               snprintf(outstr, BUFSIZ, "RW thread %d pass=%d fail=%d", i + MAX_THREAD,
00384                      rwt_pass[i], rwt_fail[i]);
00385               tester_error(outstr);
00386               if (rwt_fail[i] != 0 || rwt_pass[i] != ptpass) {
00387                      snprintf(outstr, BUFSIZ, "FAIL RW thread %d", i);
00388                      tester_error(outstr);
00389                      testfail++;
00390               }
00391        }
00392        snprintf(outstr, BUFSIZ, "MT Test complete" );
00393        tester_error(outstr);
00394 
00395        if (testfail)
00396               exit( EXIT_FAILURE );
00397        exit( EXIT_SUCCESS );
00398 }
00399 
00400 static void *
00401 do_onethread( void *arg )
00402 {
00403        int           i, j, thisconn;
00404        LDAP          **mlds;
00405        char          thrstr[BUFSIZ];
00406        int           rc, refcnt = 0;
00407        int           idx = (ldap_pvt_thread_t *)arg - rtid;
00408 
00409        mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
00410        if (mlds == NULL) {
00411               thread_error( idx, "Memory error: thread calloc for noconns" );
00412               exit( EXIT_FAILURE );
00413        }
00414 
00415        for ( j = 0; j < outerloops; j++ ) {
00416               for(i = 0; i < noconns; i++) {
00417                      mlds[i] = ldap_dup(lds[i]);
00418                      if (mlds[i] == NULL) {
00419                             thread_error( idx, "ldap_dup error" );
00420                      }
00421               }
00422               rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
00423               snprintf(thrstr, BUFSIZ,
00424                      "RO Thread conns: %d refcnt: %d (rc = %d)",
00425                      noconns, refcnt, rc);
00426               thread_verbose(idx, thrstr);
00427 
00428               thisconn = (idx + j) % noconns;
00429               if (thisconn < 0 || thisconn >= noconns)
00430                      thisconn = 0;
00431               if (mlds[thisconn] == NULL) {
00432                      thread_error( idx, "(failed to dup)");
00433                      tester_perror( "ldap_dup", "(failed to dup)" );
00434                      exit( EXIT_FAILURE );
00435               }
00436               snprintf(thrstr, BUFSIZ, "Using conn %d", thisconn);
00437               thread_verbose(idx, thrstr);
00438               if ( filter != NULL ) {
00439                      if (strchr(filter, '['))
00440                             do_random2( mlds[thisconn], entry, filter, attrs,
00441                                    noattrs, nobind, loops, retries, delay, force,
00442                                    chaserefs, idx );
00443                      else
00444                             do_random( mlds[thisconn], entry, filter, attrs,
00445                                    noattrs, nobind, loops, retries, delay, force,
00446                                    chaserefs, idx );
00447 
00448               } else {
00449                      do_read( mlds[thisconn], entry, attrs,
00450                             noattrs, nobind, loops, retries, delay, force,
00451                             chaserefs, idx );
00452               }
00453               for(i = 0; i < noconns; i++) {
00454                      (void) ldap_destroy(mlds[i]);
00455                      mlds[i] = NULL;
00456               }
00457        }
00458        free( mlds );
00459        return( NULL );
00460 }
00461 
00462 static void *
00463 do_onerwthread( void *arg )
00464 {
00465        int           i, j, thisconn;
00466        LDAP          **mlds, *ld;
00467        char          thrstr[BUFSIZ];
00468        char          dn[256], uids[32], cns[32], *base;
00469        LDAPMod              *attrp[5], attrs[4];
00470        char          *oc_vals[] = { "top", "OpenLDAPperson", NULL };
00471        char          *cn_vals[] = { NULL, NULL };
00472        char          *sn_vals[] = { NULL, NULL };
00473        char          *uid_vals[] = { NULL, NULL };
00474        int           ret;
00475        int           adds = 0;
00476        int           dels = 0;
00477        int           rc, refcnt = 0;
00478        int           idx = (ldap_pvt_thread_t *)arg - rtid;
00479 
00480        mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
00481        if (mlds == NULL) {
00482               thread_error( idx, "Memory error: thread calloc for noconns" );
00483               exit( EXIT_FAILURE );
00484        }
00485 
00486        snprintf(uids, sizeof(uids), "rwtest%04d", idx);
00487        snprintf(cns, sizeof(cns), "rwtest%04d", idx);
00488        /* add setup */
00489        for (i = 0; i < 4; i++) {
00490               attrp[i] = &attrs[i];
00491               attrs[i].mod_op = 0;
00492        }
00493        attrp[4] = NULL;
00494        attrs[0].mod_type = "objectClass";
00495        attrs[0].mod_values = oc_vals;
00496        attrs[1].mod_type = "cn";
00497        attrs[1].mod_values = cn_vals;
00498        cn_vals[0] = &cns[0];
00499        attrs[2].mod_type = "sn";
00500        attrs[2].mod_values = sn_vals;
00501        sn_vals[0] = &cns[0];
00502        attrs[3].mod_type = "uid";
00503        attrs[3].mod_values = uid_vals;
00504        uid_vals[0] = &uids[0];
00505 
00506        for ( j = 0; j < outerloops; j++ ) {
00507               for(i = 0; i < noconns; i++) {
00508                      mlds[i] = ldap_dup(lds[i]);
00509                      if (mlds[i] == NULL) {
00510                             thread_error( idx, "ldap_dup error" );
00511                      }
00512               }
00513               rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
00514               snprintf(thrstr, BUFSIZ,
00515                      "RW Thread conns: %d refcnt: %d (rc = %d)",
00516                      noconns, refcnt, rc);
00517               thread_verbose(idx, thrstr);
00518 
00519               thisconn = (idx + j) % noconns;
00520               if (thisconn < 0 || thisconn >= noconns)
00521                      thisconn = 0;
00522               if (mlds[thisconn] == NULL) {
00523                      thread_error( idx, "(failed to dup)");
00524                      tester_perror( "ldap_dup", "(failed to dup)" );
00525                      exit( EXIT_FAILURE );
00526               }
00527               snprintf(thrstr, BUFSIZ, "START RW Thread using conn %d", thisconn);
00528               thread_verbose(idx, thrstr);
00529 
00530               ld = mlds[thisconn];
00531               if (entry != NULL)
00532                      base = entry;
00533               else
00534                      base = DEFAULT_BASE;
00535               snprintf(dn, 256, "cn=%s,%s", cns, base);
00536 
00537               adds = 0;
00538               dels = 0;
00539               for (i = 0; i < loops; i++) {
00540                      ret = ldap_add_ext_s(ld, dn, &attrp[0], NULL, NULL);
00541                      if (ret == LDAP_SUCCESS) {
00542                             adds++;
00543                             ret = ldap_delete_ext_s(ld, dn, NULL, NULL);
00544                             if (ret == LDAP_SUCCESS) {
00545                                    dels++;
00546                                    rt_pass[idx]++;
00547                             } else {
00548                                    thread_output(idx, ldap_err2string(ret));
00549                                    rt_fail[idx]++;
00550                             }
00551                      } else {
00552                             thread_output(idx, ldap_err2string(ret));
00553                             rt_fail[idx]++;
00554                      }
00555               }
00556 
00557               snprintf(thrstr, BUFSIZ,
00558                      "INNER STOP RW Thread using conn %d (%d/%d)",
00559                      thisconn, adds, dels);
00560               thread_verbose(idx, thrstr);
00561 
00562               for(i = 0; i < noconns; i++) {
00563                      (void) ldap_destroy(mlds[i]);
00564                      mlds[i] = NULL;
00565               }
00566        }
00567 
00568        free( mlds );
00569        return( NULL );
00570 }
00571 
00572 static void
00573 do_conn( char *uri, char *manager, struct berval *passwd,
00574        LDAP **ldp, int nobind, int maxretries, int conn_num )
00575 {
00576        LDAP   *ld = NULL;
00577        int    version = LDAP_VERSION3;
00578        int    i = 0, do_retry = maxretries;
00579        int     rc = LDAP_SUCCESS;
00580        char   thrstr[BUFSIZ];
00581 
00582 retry:;
00583        ldap_initialize( &ld, uri );
00584        if ( ld == NULL ) {
00585               snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
00586               tester_error( thrstr );
00587               tester_perror( "ldap_initialize", NULL );
00588               exit( EXIT_FAILURE );
00589        }
00590 
00591        (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ); 
00592        (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
00593               chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
00594 
00595        if ( do_retry == maxretries ) {
00596               snprintf( thrstr, BUFSIZ, "do_conn #%d\n", conn_num );
00597               thread_verbose( -1, thrstr );
00598        }
00599 
00600        if ( nobind == 0 ) {
00601               rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
00602               if ( rc != LDAP_SUCCESS ) {
00603                      snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
00604                      tester_error( thrstr );
00605                      tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
00606                      switch ( rc ) {
00607                      case LDAP_BUSY:
00608                      case LDAP_UNAVAILABLE:
00609                             if ( do_retry > 0 ) {
00610                                    ldap_unbind_ext( ld, NULL, NULL );
00611                                    ld = NULL;
00612                                    do_retry--;
00613                                    if ( delay != 0 ) {
00614                                        sleep( delay );
00615                                    }
00616                                    goto retry;
00617                             }
00618                      /* fallthru */
00619                      default:
00620                             break;
00621                      }
00622                      exit( EXIT_FAILURE );
00623               }
00624        }
00625        *ldp = ld;
00626 }
00627 
00628 static void
00629 do_random( LDAP *ld,
00630        char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
00631        int innerloop, int maxretries, int delay, int force, int chaserefs,
00632        int idx )
00633 {
00634        int    i = 0, do_retry = maxretries;
00635        char   *attrs[ 2 ];
00636        int     rc = LDAP_SUCCESS;
00637        int    nvalues = 0;
00638        char   **values = NULL;
00639        LDAPMessage *res = NULL, *e = NULL;
00640        char   thrstr[BUFSIZ];
00641 
00642        attrs[ 0 ] = LDAP_NO_ATTRS;
00643        attrs[ 1 ] = NULL;
00644 
00645        snprintf( thrstr, BUFSIZ,
00646                      "Read(%d): base=\"%s\", filter=\"%s\".\n",
00647                      innerloop, sbase, filter );
00648        thread_verbose( idx, thrstr );
00649 
00650        rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
00651               filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
00652        switch ( rc ) {
00653        case LDAP_SIZELIMIT_EXCEEDED:
00654        case LDAP_TIMELIMIT_EXCEEDED:
00655        case LDAP_SUCCESS:
00656               nvalues = ldap_count_entries( ld, res );
00657               if ( nvalues == 0 ) {
00658                      if ( rc ) {
00659                             tester_ldap_error( ld, "ldap_search_ext_s", NULL );
00660                      }
00661                      break;
00662               }
00663 
00664               values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
00665               for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
00666               {
00667                      values[ i ] = ldap_get_dn( ld, e );
00668               }
00669               values[ i ] = NULL;
00670 
00671               ldap_msgfree( res );
00672 
00673               if ( do_retry == maxretries ) {
00674                      snprintf( thrstr, BUFSIZ,
00675                             "Read base=\"%s\" filter=\"%s\" got %d values.\n",
00676                             sbase, filter, nvalues );
00677                      thread_verbose( idx, thrstr );
00678               }
00679 
00680               for ( i = 0; i < innerloop; i++ ) {
00681                      int    r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
00682 
00683                      do_read( ld, values[ r ],
00684                             srchattrs, noattrs, nobind, 1, maxretries,
00685                             delay, force, chaserefs, idx );
00686               }
00687               for( i = 0; i < nvalues; i++) {
00688                      if (values[i] != NULL)
00689                             ldap_memfree( values[i] );
00690               }
00691               free( values );
00692               break;
00693 
00694        default:
00695               tester_ldap_error( ld, "ldap_search_ext_s", NULL );
00696               break;
00697        }
00698 
00699        snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc );
00700        thread_verbose( idx, thrstr );
00701 }
00702 
00703 /* substitute a generated int into the filter */
00704 static void
00705 do_random2( LDAP *ld,
00706        char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
00707        int innerloop, int maxretries, int delay, int force, int chaserefs,
00708        int idx )
00709 {
00710        int    i = 0, do_retry = maxretries;
00711        int     rc = LDAP_SUCCESS;
00712        int           lo, hi, range;
00713        int    flen;
00714        LDAPMessage *res = NULL, *e = NULL;
00715        char   *ptr, *ftail;
00716        char   thrstr[BUFSIZ];
00717        char   fbuf[BUFSIZ];
00718 
00719        snprintf( thrstr, BUFSIZ,
00720                      "Read(%d): base=\"%s\", filter=\"%s\".\n",
00721                      innerloop, sbase, filter );
00722        thread_verbose( idx, thrstr );
00723 
00724        ptr = strchr(filter, '[');
00725        if (!ptr)
00726               return;
00727        ftail = strchr(filter, ']');
00728        if (!ftail || ftail < ptr)
00729               return;
00730 
00731        sscanf(ptr, "[%d-%d]", &lo, &hi);
00732        range = hi - lo + 1;
00733 
00734        flen = ptr - filter;
00735        ftail++;
00736 
00737        for ( i = 0; i < innerloop; i++ ) {
00738               int    r = ((double)range)*rand()/(RAND_MAX + 1.0);
00739               sprintf(fbuf, "%.*s%d%s", flen, filter, r, ftail);
00740 
00741               rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
00742                             fbuf, srchattrs, noattrs, NULL, NULL, NULL,
00743                             LDAP_NO_LIMIT, &res );
00744               if ( res != NULL ) {
00745                      ldap_msgfree( res );
00746               }
00747               if ( rc == 0 ) {
00748                      rt_pass[idx]++;
00749               } else {
00750                      int           first = tester_ignore_err( rc );
00751                      char          buf[ BUFSIZ ];
00752 
00753                      rt_fail[idx]++;
00754                      snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
00755 
00756                      /* if ignore.. */
00757                      if ( first ) {
00758                             /* only log if first occurrence */
00759                             if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
00760                                    tester_ldap_error( ld, buf, NULL );
00761                             }
00762                             continue;
00763                      }
00764 
00765                      /* busy needs special handling */
00766                      tester_ldap_error( ld, buf, NULL );
00767                      if ( rc == LDAP_BUSY && do_retry > 0 ) {
00768                             do_retry--;
00769                             continue;
00770                      }
00771                      break;
00772               }
00773        }
00774 
00775        snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc );
00776        thread_verbose( idx, thrstr );
00777 }
00778 
00779 static void
00780 do_read( LDAP *ld, char *entry,
00781        char **attrs, int noattrs, int nobind, int maxloop,
00782        int maxretries, int delay, int force, int chaserefs, int idx )
00783 {
00784        int    i = 0, do_retry = maxretries;
00785        int     rc = LDAP_SUCCESS;
00786        char   thrstr[BUFSIZ];
00787 
00788 retry:;
00789        if ( do_retry == maxretries ) {
00790               snprintf( thrstr, BUFSIZ, "Read(%d): entry=\"%s\".\n",
00791                      maxloop, entry );
00792               thread_verbose( idx, thrstr );
00793        }
00794 
00795        snprintf(thrstr, BUFSIZ, "LD %p cnt: %d (retried %d) (%s)", \
00796                (void *) ld, maxloop, (do_retry - maxretries), entry);
00797        thread_verbose( idx, thrstr );
00798 
00799        for ( ; i < maxloop; i++ ) {
00800               LDAPMessage *res = NULL;
00801 
00802               rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
00803                             NULL, attrs, noattrs, NULL, NULL, NULL,
00804                             LDAP_NO_LIMIT, &res );
00805               if ( res != NULL ) {
00806                      ldap_msgfree( res );
00807               }
00808 
00809               if ( rc == 0 ) {
00810                      rt_pass[idx]++;
00811               } else {
00812                      int           first = tester_ignore_err( rc );
00813                      char          buf[ BUFSIZ ];
00814 
00815                      rt_fail[idx]++;
00816                      snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
00817 
00818                      /* if ignore.. */
00819                      if ( first ) {
00820                             /* only log if first occurrence */
00821                             if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
00822                                    tester_ldap_error( ld, buf, NULL );
00823                             }
00824                             continue;
00825                      }
00826 
00827                      /* busy needs special handling */
00828                      tester_ldap_error( ld, buf, NULL );
00829                      if ( rc == LDAP_BUSY && do_retry > 0 ) {
00830                             do_retry--;
00831                             goto retry;
00832                      }
00833                      break;
00834               }
00835        }
00836 }