slapd-mtread.c revision 1.1.1.1 1 /* $NetBSD: slapd-mtread.c,v 1.1.1.1 2014/05/28 09:58:54 tron Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2014 The OpenLDAP Foundation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17 /* ACKNOWLEDGEMENTS:
18 * This work was initially developed by Kurt Spanier for inclusion
19 * in OpenLDAP Software.
20 */
21
22 /*
23 * This tool is a MT reader. It behaves like slapd-read however
24 * with one or more threads simultaneously using the same connection.
25 * If -M is enabled, then M threads will also perform write operations.
26 */
27
28 #include "portable.h"
29
30 #include <stdio.h>
31 #include "ldap_pvt_thread.h"
32
33 #include "ac/stdlib.h"
34
35 #include "ac/ctype.h"
36 #include "ac/param.h"
37 #include "ac/socket.h"
38 #include "ac/string.h"
39 #include "ac/unistd.h"
40 #include "ac/wait.h"
41
42 #include "ldap.h"
43 #include "lutil.h"
44
45 #include "ldap_pvt.h"
46
47 #include "slapd-common.h"
48
49 #define MAXCONN 512
50 #define LOOPS 100
51 #define RETRIES 0
52 #define DEFAULT_BASE "ou=people,dc=example,dc=com"
53
54 static void
55 do_conn( char *uri, char *manager, struct berval *passwd,
56 LDAP **ld, int nobind, int maxretries, int conn_num );
57
58 static void
59 do_read( LDAP *ld, char *entry,
60 char **attrs, int noattrs, int nobind, int maxloop,
61 int maxretries, int delay, int force, int chaserefs, int idx );
62
63 static void
64 do_random( LDAP *ld,
65 char *sbase, char *filter, char **attrs, int noattrs, int nobind,
66 int innerloop, int maxretries, int delay, int force, int chaserefs,
67 int idx );
68
69 static void
70 do_random2( LDAP *ld,
71 char *sbase, char *filter, char **attrs, int noattrs, int nobind,
72 int innerloop, int maxretries, int delay, int force, int chaserefs,
73 int idx );
74
75 static void *
76 do_onethread( void *arg );
77
78 static void *
79 do_onerwthread( void *arg );
80
81 #define MAX_THREAD 1024
82 /* Use same array for readers and writers, offset writers by MAX_THREAD */
83 int rt_pass[MAX_THREAD*2];
84 int rt_fail[MAX_THREAD*2];
85 int *rwt_pass = rt_pass + MAX_THREAD;
86 int *rwt_fail = rt_fail + MAX_THREAD;
87 ldap_pvt_thread_t rtid[MAX_THREAD*2], *rwtid = rtid + MAX_THREAD;
88
89 /*
90 * Shared globals (command line args)
91 */
92 LDAP *ld = NULL;
93 char *entry = NULL;
94 char *filter = NULL;
95 int loops = LOOPS;
96 int outerloops = 1;
97 int retries = RETRIES;
98 int delay = 0;
99 int force = 0;
100 int chaserefs = 0;
101 char *srchattrs[] = { "1.1", NULL };
102 char **attrs = srchattrs;
103 int noattrs = 0;
104 int nobind = 0;
105 int threads = 1;
106 int rwthreads = 0;
107 int verbose = 0;
108
109 int noconns = 1;
110 LDAP **lds = NULL;
111
112 static void
113 thread_error(int idx, char *string)
114 {
115 char thrstr[BUFSIZ];
116
117 snprintf(thrstr, BUFSIZ, "error on tidx: %d: %s", idx, string);
118 tester_error( thrstr );
119 }
120
121 static void
122 thread_output(int idx, char *string)
123 {
124 char thrstr[BUFSIZ];
125
126 snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string);
127 tester_error( thrstr );
128 }
129
130 static void
131 thread_verbose(int idx, char *string)
132 {
133 char thrstr[BUFSIZ];
134
135 if (!verbose)
136 return;
137 snprintf(thrstr, BUFSIZ, "tidx: %d says: %s", idx, string);
138 tester_error( thrstr );
139 }
140
141 static void
142 usage( char *name )
143 {
144 fprintf( stderr,
145 "usage: %s "
146 "-H <uri> | ([-h <host>] -p <port>) "
147 "-D <manager> "
148 "-w <passwd> "
149 "-e <entry> "
150 "[-A] "
151 "[-C] "
152 "[-F] "
153 "[-N] "
154 "[-v] "
155 "[-c connections] "
156 "[-f filter] "
157 "[-i <ignore>] "
158 "[-l <loops>] "
159 "[-L <outerloops>] "
160 "[-m threads] "
161 "[-M threads] "
162 "[-r <maxretries>] "
163 "[-t <delay>] "
164 "[-T <attrs>] "
165 "[<attrs>] "
166 "\n",
167 name );
168 exit( EXIT_FAILURE );
169 }
170
171 int
172 main( int argc, char **argv )
173 {
174 int i;
175 char *uri = NULL;
176 char *host = "localhost";
177 int port = -1;
178 char *manager = NULL;
179 struct berval passwd = { 0, NULL };
180 char outstr[BUFSIZ];
181 int ptpass;
182 int testfail = 0;
183
184
185 tester_init( "slapd-mtread", TESTER_READ );
186
187 /* by default, tolerate referrals and no such object */
188 tester_ignore_str2errlist( "REFERRAL,NO_SUCH_OBJECT" );
189
190 while ( (i = getopt( argc, argv, "ACc:D:e:Ff:H:h:i:L:l:M:m:p:r:t:T:w:v" )) != EOF ) {
191 switch ( i ) {
192 case 'A':
193 noattrs++;
194 break;
195
196 case 'C':
197 chaserefs++;
198 break;
199
200 case 'H': /* the server uri */
201 uri = strdup( optarg );
202 break;
203
204 case 'h': /* the servers host */
205 host = strdup( optarg );
206
207 case 'i':
208 tester_ignore_str2errlist( optarg );
209 break;
210
211 case 'N':
212 nobind++;
213 break;
214
215 case 'v':
216 verbose++;
217 break;
218
219 case 'p': /* the servers port */
220 if ( lutil_atoi( &port, optarg ) != 0 ) {
221 usage( argv[0] );
222 }
223 break;
224
225 case 'D': /* the servers manager */
226 manager = strdup( optarg );
227 break;
228
229 case 'w': /* the server managers password */
230 passwd.bv_val = strdup( optarg );
231 passwd.bv_len = strlen( optarg );
232 memset( optarg, '*', passwd.bv_len );
233 break;
234
235 case 'c': /* the number of connections */
236 if ( lutil_atoi( &noconns, optarg ) != 0 ) {
237 usage( argv[0] );
238 }
239 break;
240
241 case 'e': /* DN to search for */
242 entry = strdup( optarg );
243 break;
244
245 case 'f': /* the search request */
246 filter = strdup( optarg );
247 break;
248
249 case 'F':
250 force++;
251 break;
252
253 case 'l': /* the number of loops */
254 if ( lutil_atoi( &loops, optarg ) != 0 ) {
255 usage( argv[0] );
256 }
257 break;
258
259 case 'L': /* the number of outerloops */
260 if ( lutil_atoi( &outerloops, optarg ) != 0 ) {
261 usage( argv[0] );
262 }
263 break;
264
265 case 'M': /* the number of R/W threads */
266 if ( lutil_atoi( &rwthreads, optarg ) != 0 ) {
267 usage( argv[0] );
268 }
269 if (rwthreads > MAX_THREAD)
270 rwthreads = MAX_THREAD;
271 break;
272
273 case 'm': /* the number of threads */
274 if ( lutil_atoi( &threads, optarg ) != 0 ) {
275 usage( argv[0] );
276 }
277 if (threads > MAX_THREAD)
278 threads = MAX_THREAD;
279 break;
280
281 case 'r': /* the number of retries */
282 if ( lutil_atoi( &retries, optarg ) != 0 ) {
283 usage( argv[0] );
284 }
285 break;
286
287 case 't': /* delay in seconds */
288 if ( lutil_atoi( &delay, optarg ) != 0 ) {
289 usage( argv[0] );
290 }
291 break;
292
293 case 'T':
294 attrs = ldap_str2charray( optarg, "," );
295 if ( attrs == NULL ) {
296 usage( argv[0] );
297 }
298 break;
299
300 default:
301 usage( argv[0] );
302 break;
303 }
304 }
305
306 if (( entry == NULL ) || ( port == -1 && uri == NULL ))
307 usage( argv[0] );
308
309 if ( *entry == '\0' ) {
310 fprintf( stderr, "%s: invalid EMPTY entry DN.\n",
311 argv[0] );
312 exit( EXIT_FAILURE );
313 }
314
315 if ( argv[optind] != NULL ) {
316 attrs = &argv[optind];
317 }
318
319 if (noconns < 1)
320 noconns = 1;
321 if (noconns > MAXCONN)
322 noconns = MAXCONN;
323 lds = (LDAP **) calloc( sizeof(LDAP *), noconns);
324 if (lds == NULL) {
325 fprintf( stderr, "%s: Memory error: calloc noconns.\n",
326 argv[0] );
327 exit( EXIT_FAILURE );
328 }
329
330 uri = tester_uri( uri, host, port );
331 /* One connection and one connection only */
332 do_conn( uri, manager, &passwd, &ld, nobind, retries, 0 );
333 lds[0] = ld;
334 for(i = 1; i < noconns; i++) {
335 do_conn( uri, manager, &passwd, &lds[i], nobind, retries, i );
336 }
337
338 ldap_pvt_thread_initialize();
339
340 snprintf(outstr, BUFSIZ, "MT Test Start: conns: %d (%s)", noconns, uri);
341 tester_error(outstr);
342 snprintf(outstr, BUFSIZ, "Threads: RO: %d RW: %d", threads, rwthreads);
343 tester_error(outstr);
344
345 /* Set up read only threads */
346 for ( i = 0; i < threads; i++ ) {
347 ldap_pvt_thread_create( &rtid[i], 0, do_onethread, &rtid[i]);
348 snprintf(outstr, BUFSIZ, "Created RO thread %d", i);
349 thread_verbose(-1, outstr);
350 }
351 /* Set up read/write threads */
352 for ( i = 0; i < rwthreads; i++ ) {
353 ldap_pvt_thread_create( &rwtid[i], 0, do_onerwthread, &rwtid[i]);
354 snprintf(outstr, BUFSIZ, "Created RW thread %d", i + MAX_THREAD);
355 thread_verbose(-1, outstr);
356 }
357
358 ptpass = outerloops * loops;
359
360 /* wait for read only threads to complete */
361 for ( i = 0; i < threads; i++ )
362 ldap_pvt_thread_join(rtid[i], NULL);
363 /* wait for read/write threads to complete */
364 for ( i = 0; i < rwthreads; i++ )
365 ldap_pvt_thread_join(rwtid[i], NULL);
366
367 for(i = 0; i < noconns; i++) {
368 if ( lds[i] != NULL ) {
369 ldap_unbind_ext( lds[i], NULL, NULL );
370 }
371 }
372 free( lds );
373
374 for ( i = 0; i < threads; i++ ) {
375 snprintf(outstr, BUFSIZ, "RO thread %d pass=%d fail=%d", i,
376 rt_pass[i], rt_fail[i]);
377 tester_error(outstr);
378 if (rt_fail[i] != 0 || rt_pass[i] != ptpass) {
379 snprintf(outstr, BUFSIZ, "FAIL RO thread %d", i);
380 tester_error(outstr);
381 testfail++;
382 }
383 }
384 for ( i = 0; i < rwthreads; i++ ) {
385 snprintf(outstr, BUFSIZ, "RW thread %d pass=%d fail=%d", i + MAX_THREAD,
386 rwt_pass[i], rwt_fail[i]);
387 tester_error(outstr);
388 if (rwt_fail[i] != 0 || rwt_pass[i] != ptpass) {
389 snprintf(outstr, BUFSIZ, "FAIL RW thread %d", i);
390 tester_error(outstr);
391 testfail++;
392 }
393 }
394 snprintf(outstr, BUFSIZ, "MT Test complete" );
395 tester_error(outstr);
396
397 if (testfail)
398 exit( EXIT_FAILURE );
399 exit( EXIT_SUCCESS );
400 }
401
402 static void *
403 do_onethread( void *arg )
404 {
405 int i, j, thisconn;
406 LDAP **mlds;
407 char thrstr[BUFSIZ];
408 int rc, refcnt = 0;
409 int idx = (ldap_pvt_thread_t *)arg - rtid;
410
411 mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
412 if (mlds == NULL) {
413 thread_error( idx, "Memory error: thread calloc for noconns" );
414 exit( EXIT_FAILURE );
415 }
416
417 for ( j = 0; j < outerloops; j++ ) {
418 for(i = 0; i < noconns; i++) {
419 mlds[i] = ldap_dup(lds[i]);
420 if (mlds[i] == NULL) {
421 thread_error( idx, "ldap_dup error" );
422 }
423 }
424 rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
425 snprintf(thrstr, BUFSIZ,
426 "RO Thread conns: %d refcnt: %d (rc = %d)",
427 noconns, refcnt, rc);
428 thread_verbose(idx, thrstr);
429
430 thisconn = (idx + j) % noconns;
431 if (thisconn < 0 || thisconn >= noconns)
432 thisconn = 0;
433 if (mlds[thisconn] == NULL) {
434 thread_error( idx, "(failed to dup)");
435 tester_perror( "ldap_dup", "(failed to dup)" );
436 exit( EXIT_FAILURE );
437 }
438 snprintf(thrstr, BUFSIZ, "Using conn %d", thisconn);
439 thread_verbose(idx, thrstr);
440 if ( filter != NULL ) {
441 if (strchr(filter, '['))
442 do_random2( mlds[thisconn], entry, filter, attrs,
443 noattrs, nobind, loops, retries, delay, force,
444 chaserefs, idx );
445 else
446 do_random( mlds[thisconn], entry, filter, attrs,
447 noattrs, nobind, loops, retries, delay, force,
448 chaserefs, idx );
449
450 } else {
451 do_read( mlds[thisconn], entry, attrs,
452 noattrs, nobind, loops, retries, delay, force,
453 chaserefs, idx );
454 }
455 for(i = 0; i < noconns; i++) {
456 (void) ldap_destroy(mlds[i]);
457 mlds[i] = NULL;
458 }
459 }
460 free( mlds );
461 return( NULL );
462 }
463
464 static void *
465 do_onerwthread( void *arg )
466 {
467 int i, j, thisconn;
468 LDAP **mlds, *ld;
469 char thrstr[BUFSIZ];
470 char dn[256], uids[32], cns[32], *base;
471 LDAPMod *attrp[5], attrs[4];
472 char *oc_vals[] = { "top", "OpenLDAPperson", NULL };
473 char *cn_vals[] = { NULL, NULL };
474 char *sn_vals[] = { NULL, NULL };
475 char *uid_vals[] = { NULL, NULL };
476 int ret;
477 int adds = 0;
478 int dels = 0;
479 int rc, refcnt = 0;
480 int idx = (ldap_pvt_thread_t *)arg - rtid;
481
482 mlds = (LDAP **) calloc( sizeof(LDAP *), noconns);
483 if (mlds == NULL) {
484 thread_error( idx, "Memory error: thread calloc for noconns" );
485 exit( EXIT_FAILURE );
486 }
487
488 snprintf(uids, sizeof(uids), "rwtest%04d", idx);
489 snprintf(cns, sizeof(cns), "rwtest%04d", idx);
490 /* add setup */
491 for (i = 0; i < 4; i++) {
492 attrp[i] = &attrs[i];
493 attrs[i].mod_op = 0;
494 }
495 attrp[4] = NULL;
496 attrs[0].mod_type = "objectClass";
497 attrs[0].mod_values = oc_vals;
498 attrs[1].mod_type = "cn";
499 attrs[1].mod_values = cn_vals;
500 cn_vals[0] = &cns[0];
501 attrs[2].mod_type = "sn";
502 attrs[2].mod_values = sn_vals;
503 sn_vals[0] = &cns[0];
504 attrs[3].mod_type = "uid";
505 attrs[3].mod_values = uid_vals;
506 uid_vals[0] = &uids[0];
507
508 for ( j = 0; j < outerloops; j++ ) {
509 for(i = 0; i < noconns; i++) {
510 mlds[i] = ldap_dup(lds[i]);
511 if (mlds[i] == NULL) {
512 thread_error( idx, "ldap_dup error" );
513 }
514 }
515 rc = ldap_get_option(mlds[0], LDAP_OPT_SESSION_REFCNT, &refcnt);
516 snprintf(thrstr, BUFSIZ,
517 "RW Thread conns: %d refcnt: %d (rc = %d)",
518 noconns, refcnt, rc);
519 thread_verbose(idx, thrstr);
520
521 thisconn = (idx + j) % noconns;
522 if (thisconn < 0 || thisconn >= noconns)
523 thisconn = 0;
524 if (mlds[thisconn] == NULL) {
525 thread_error( idx, "(failed to dup)");
526 tester_perror( "ldap_dup", "(failed to dup)" );
527 exit( EXIT_FAILURE );
528 }
529 snprintf(thrstr, BUFSIZ, "START RW Thread using conn %d", thisconn);
530 thread_verbose(idx, thrstr);
531
532 ld = mlds[thisconn];
533 if (entry != NULL)
534 base = entry;
535 else
536 base = DEFAULT_BASE;
537 snprintf(dn, 256, "cn=%s,%s", cns, base);
538
539 adds = 0;
540 dels = 0;
541 for (i = 0; i < loops; i++) {
542 ret = ldap_add_ext_s(ld, dn, &attrp[0], NULL, NULL);
543 if (ret == LDAP_SUCCESS) {
544 adds++;
545 ret = ldap_delete_ext_s(ld, dn, NULL, NULL);
546 if (ret == LDAP_SUCCESS) {
547 dels++;
548 rt_pass[idx]++;
549 } else {
550 thread_output(idx, ldap_err2string(ret));
551 rt_fail[idx]++;
552 }
553 } else {
554 thread_output(idx, ldap_err2string(ret));
555 rt_fail[idx]++;
556 }
557 }
558
559 snprintf(thrstr, BUFSIZ,
560 "INNER STOP RW Thread using conn %d (%d/%d)",
561 thisconn, adds, dels);
562 thread_verbose(idx, thrstr);
563
564 for(i = 0; i < noconns; i++) {
565 (void) ldap_destroy(mlds[i]);
566 mlds[i] = NULL;
567 }
568 }
569
570 free( mlds );
571 return( NULL );
572 }
573
574 static void
575 do_conn( char *uri, char *manager, struct berval *passwd,
576 LDAP **ldp, int nobind, int maxretries, int conn_num )
577 {
578 LDAP *ld = NULL;
579 int version = LDAP_VERSION3;
580 int i = 0, do_retry = maxretries;
581 int rc = LDAP_SUCCESS;
582 char thrstr[BUFSIZ];
583
584 retry:;
585 ldap_initialize( &ld, uri );
586 if ( ld == NULL ) {
587 snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
588 tester_error( thrstr );
589 tester_perror( "ldap_initialize", NULL );
590 exit( EXIT_FAILURE );
591 }
592
593 (void) ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
594 (void) ldap_set_option( ld, LDAP_OPT_REFERRALS,
595 chaserefs ? LDAP_OPT_ON : LDAP_OPT_OFF );
596
597 if ( do_retry == maxretries ) {
598 snprintf( thrstr, BUFSIZ, "do_conn #%d\n", conn_num );
599 thread_verbose( -1, thrstr );
600 }
601
602 if ( nobind == 0 ) {
603 rc = ldap_sasl_bind_s( ld, manager, LDAP_SASL_SIMPLE, passwd, NULL, NULL, NULL );
604 if ( rc != LDAP_SUCCESS ) {
605 snprintf( thrstr, BUFSIZ, "connection: %d", conn_num );
606 tester_error( thrstr );
607 tester_ldap_error( ld, "ldap_sasl_bind_s", NULL );
608 switch ( rc ) {
609 case LDAP_BUSY:
610 case LDAP_UNAVAILABLE:
611 if ( do_retry > 0 ) {
612 ldap_unbind_ext( ld, NULL, NULL );
613 ld = NULL;
614 do_retry--;
615 if ( delay != 0 ) {
616 sleep( delay );
617 }
618 goto retry;
619 }
620 /* fallthru */
621 default:
622 break;
623 }
624 exit( EXIT_FAILURE );
625 }
626 }
627 *ldp = ld;
628 }
629
630 static void
631 do_random( LDAP *ld,
632 char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
633 int innerloop, int maxretries, int delay, int force, int chaserefs,
634 int idx )
635 {
636 int i = 0, do_retry = maxretries;
637 char *attrs[ 2 ];
638 int rc = LDAP_SUCCESS;
639 int nvalues = 0;
640 char **values = NULL;
641 LDAPMessage *res = NULL, *e = NULL;
642 char thrstr[BUFSIZ];
643
644 attrs[ 0 ] = LDAP_NO_ATTRS;
645 attrs[ 1 ] = NULL;
646
647 snprintf( thrstr, BUFSIZ,
648 "Read(%d): base=\"%s\", filter=\"%s\".\n",
649 innerloop, sbase, filter );
650 thread_verbose( idx, thrstr );
651
652 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
653 filter, attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res );
654 switch ( rc ) {
655 case LDAP_SIZELIMIT_EXCEEDED:
656 case LDAP_TIMELIMIT_EXCEEDED:
657 case LDAP_SUCCESS:
658 nvalues = ldap_count_entries( ld, res );
659 if ( nvalues == 0 ) {
660 if ( rc ) {
661 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
662 }
663 break;
664 }
665
666 values = malloc( ( nvalues + 1 ) * sizeof( char * ) );
667 for ( i = 0, e = ldap_first_entry( ld, res ); e != NULL; i++, e = ldap_next_entry( ld, e ) )
668 {
669 values[ i ] = ldap_get_dn( ld, e );
670 }
671 values[ i ] = NULL;
672
673 ldap_msgfree( res );
674
675 if ( do_retry == maxretries ) {
676 snprintf( thrstr, BUFSIZ,
677 "Read base=\"%s\" filter=\"%s\" got %d values.\n",
678 sbase, filter, nvalues );
679 thread_verbose( idx, thrstr );
680 }
681
682 for ( i = 0; i < innerloop; i++ ) {
683 int r = ((double)nvalues)*rand()/(RAND_MAX + 1.0);
684
685 do_read( ld, values[ r ],
686 srchattrs, noattrs, nobind, 1, maxretries,
687 delay, force, chaserefs, idx );
688 }
689 for( i = 0; i < nvalues; i++) {
690 if (values[i] != NULL)
691 ldap_memfree( values[i] );
692 }
693 free( values );
694 break;
695
696 default:
697 tester_ldap_error( ld, "ldap_search_ext_s", NULL );
698 break;
699 }
700
701 snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc );
702 thread_verbose( idx, thrstr );
703 }
704
705 /* substitute a generated int into the filter */
706 static void
707 do_random2( LDAP *ld,
708 char *sbase, char *filter, char **srchattrs, int noattrs, int nobind,
709 int innerloop, int maxretries, int delay, int force, int chaserefs,
710 int idx )
711 {
712 int i = 0, do_retry = maxretries;
713 int rc = LDAP_SUCCESS;
714 int lo, hi, range;
715 int flen;
716 LDAPMessage *res = NULL, *e = NULL;
717 char *ptr, *ftail;
718 char thrstr[BUFSIZ];
719 char fbuf[BUFSIZ];
720
721 snprintf( thrstr, BUFSIZ,
722 "Read(%d): base=\"%s\", filter=\"%s\".\n",
723 innerloop, sbase, filter );
724 thread_verbose( idx, thrstr );
725
726 ptr = strchr(filter, '[');
727 if (!ptr)
728 return;
729 ftail = strchr(filter, ']');
730 if (!ftail || ftail < ptr)
731 return;
732
733 sscanf(ptr, "[%d-%d]", &lo, &hi);
734 range = hi - lo + 1;
735
736 flen = ptr - filter;
737 ftail++;
738
739 for ( i = 0; i < innerloop; i++ ) {
740 int r = ((double)range)*rand()/(RAND_MAX + 1.0);
741 sprintf(fbuf, "%.*s%d%s", flen, filter, r, ftail);
742
743 rc = ldap_search_ext_s( ld, sbase, LDAP_SCOPE_SUBTREE,
744 fbuf, srchattrs, noattrs, NULL, NULL, NULL,
745 LDAP_NO_LIMIT, &res );
746 if ( res != NULL ) {
747 ldap_msgfree( res );
748 }
749 if ( rc == 0 ) {
750 rt_pass[idx]++;
751 } else {
752 int first = tester_ignore_err( rc );
753 char buf[ BUFSIZ ];
754
755 rt_fail[idx]++;
756 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
757
758 /* if ignore.. */
759 if ( first ) {
760 /* only log if first occurrence */
761 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
762 tester_ldap_error( ld, buf, NULL );
763 }
764 continue;
765 }
766
767 /* busy needs special handling */
768 tester_ldap_error( ld, buf, NULL );
769 if ( rc == LDAP_BUSY && do_retry > 0 ) {
770 do_retry--;
771 continue;
772 }
773 break;
774 }
775 }
776
777 snprintf( thrstr, BUFSIZ, "Search done (%d).\n", rc );
778 thread_verbose( idx, thrstr );
779 }
780
781 static void
782 do_read( LDAP *ld, char *entry,
783 char **attrs, int noattrs, int nobind, int maxloop,
784 int maxretries, int delay, int force, int chaserefs, int idx )
785 {
786 int i = 0, do_retry = maxretries;
787 int rc = LDAP_SUCCESS;
788 char thrstr[BUFSIZ];
789
790 retry:;
791 if ( do_retry == maxretries ) {
792 snprintf( thrstr, BUFSIZ, "Read(%d): entry=\"%s\".\n",
793 maxloop, entry );
794 thread_verbose( idx, thrstr );
795 }
796
797 snprintf(thrstr, BUFSIZ, "LD %p cnt: %d (retried %d) (%s)", \
798 (void *) ld, maxloop, (do_retry - maxretries), entry);
799 thread_verbose( idx, thrstr );
800
801 for ( ; i < maxloop; i++ ) {
802 LDAPMessage *res = NULL;
803
804 rc = ldap_search_ext_s( ld, entry, LDAP_SCOPE_BASE,
805 NULL, attrs, noattrs, NULL, NULL, NULL,
806 LDAP_NO_LIMIT, &res );
807 if ( res != NULL ) {
808 ldap_msgfree( res );
809 }
810
811 if ( rc == 0 ) {
812 rt_pass[idx]++;
813 } else {
814 int first = tester_ignore_err( rc );
815 char buf[ BUFSIZ ];
816
817 rt_fail[idx]++;
818 snprintf( buf, sizeof( buf ), "ldap_search_ext_s(%s)", entry );
819
820 /* if ignore.. */
821 if ( first ) {
822 /* only log if first occurrence */
823 if ( ( force < 2 && first > 0 ) || abs(first) == 1 ) {
824 tester_ldap_error( ld, buf, NULL );
825 }
826 continue;
827 }
828
829 /* busy needs special handling */
830 tester_ldap_error( ld, buf, NULL );
831 if ( rc == LDAP_BUSY && do_retry > 0 ) {
832 do_retry--;
833 goto retry;
834 }
835 break;
836 }
837 }
838 }
839