]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
split operations in inner/outer loops
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2006 The OpenLDAP Foundation.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted only as authorized by the OpenLDAP
9  * Public License.
10  *
11  * A copy of this license is available in file LICENSE in the
12  * top-level directory of the distribution or, alternatively, at
13  * <http://www.OpenLDAP.org/license.html>.
14  */
15 /* ACKNOWLEDGEMENTS:
16  * This work was initially developed by Kurt Spanier for inclusion
17  * in OpenLDAP Software.
18  */
19
20 #include "portable.h"
21
22 #include <stdio.h>
23
24 #include <ac/stdlib.h>
25
26 #include <ac/ctype.h>
27 #include <ac/dirent.h>
28 #include <ac/param.h>
29 #include <ac/socket.h>
30 #include <ac/string.h>
31 #include <ac/unistd.h>
32 #include <ac/wait.h>
33
34
35 #include "ldap_defaults.h"
36 #include "lutil.h"
37
38 #include "ldap.h"
39 #include "slapd-common.h"
40
41 #define SEARCHCMD               "slapd-search"
42 #define READCMD                 "slapd-read"
43 #define ADDCMD                  "slapd-addel"
44 #define MODRDNCMD               "slapd-modrdn"
45 #define MODIFYCMD               "slapd-modify"
46 #define BINDCMD                 "slapd-bind"
47 #define MAXARGS                 100
48 #define MAXREQS                 5000
49 #define LOOPS                   100
50 #define OUTERLOOPS              "1"
51 #define RETRIES                 "0"
52
53 #define TSEARCHFILE             "do_search.0"
54 #define TREADFILE               "do_read.0"
55 #define TADDFILE                "do_add."
56 #define TMODRDNFILE             "do_modrdn.0"
57 #define TMODIFYFILE             "do_modify.0"
58 #define TBINDFILE               "do_bind.0"
59
60 static char *get_file_name( char *dirname, char *filename );
61 static int  get_search_filters( char *filename, char *filters[], char *bases[] );
62 static int  get_read_entries( char *filename, char *entries[] );
63 static void fork_child( char *prog, char **args );
64 static void     wait4kids( int nkidval );
65
66 static int      maxkids = 20;
67 static int      nkids;
68
69 #ifdef HAVE_WINSOCK
70 static HANDLE   *children;
71 static char argbuf[BUFSIZ];
72 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
73 #else
74 #define ArgDup(x) strdup(x)
75 #endif
76
77 static void
78 usage( char *name )
79 {
80         fprintf( stderr,
81                 "usage: %s "
82                 "-H <uri> | ([-h <host>] -p <port>) "
83                 "-D <manager> "
84                 "-w <passwd> "
85                 "-d <datadir> "
86                 "[-j <maxchild>] "
87                 "[-l <loops>] "
88                 "[-L <outerloops>] "
89                 "-P <progdir> "
90                 "[-r <maxretries>] "
91                 "[-t <delay>] "
92                 "[-F]\n",
93                 name );
94         exit( EXIT_FAILURE );
95 }
96
97 int
98 main( int argc, char **argv )
99 {
100         int             i, j;
101         char            *uri = NULL;
102         char            *host = "localhost";
103         char            *port = NULL;
104         char            *manager = NULL;
105         char            *passwd = NULL;
106         char            *dirname = NULL;
107         char            *progdir = NULL;
108         int             loops = LOOPS;
109         char            *outerloops = OUTERLOOPS;
110         char            *retries = RETRIES;
111         char            *delay = "0";
112         DIR             *datadir;
113         struct dirent   *file;
114         int             friendly = 0;
115         /* search */
116         char            *sfile = NULL;
117         char            *sreqs[MAXREQS];
118         char            *sbase[MAXREQS];
119         int             snum = 0;
120         char            *sargs[MAXARGS];
121         int             sanum;
122         char            scmd[MAXPATHLEN];
123         char            sloops[] = "18446744073709551615UL";
124         /* read */
125         char            *rfile = NULL;
126         char            *rreqs[MAXREQS];
127         int             rnum = 0;
128         char            *rargs[MAXARGS];
129         int             ranum;
130         char            rcmd[MAXPATHLEN];
131         char            rloops[] = "18446744073709551615UL";
132         /* addel */
133         char            *afiles[MAXREQS];
134         int             anum = 0;
135         char            *aargs[MAXARGS];
136         int             aanum;
137         char            acmd[MAXPATHLEN];
138         char            aloops[] = "18446744073709551615UL";
139         /* modrdn */
140         char            *mfile = NULL;
141         char            *mreqs[MAXREQS];
142         int             mnum = 0;
143         char            *margs[MAXARGS];
144         int             manum;
145         char            mcmd[MAXPATHLEN];
146         char            mloops[] = "18446744073709551615UL";
147         /* modify */
148         char            *modfile = NULL;
149         char            *modreqs[MAXREQS];
150         char            *moddn[MAXREQS];
151         int             modnum = 0;
152         char            *modargs[MAXARGS];
153         int             modanum;
154         char            modcmd[MAXPATHLEN];
155         char            modloops[] = "18446744073709551615UL";
156         /* bind */
157         char            *bfile = NULL;
158         char            *breqs[MAXREQS];
159         char            *bcreds[MAXREQS];
160         int             bnum = 0;
161         char            *bargs[MAXARGS];
162         int             banum;
163         char            bcmd[MAXPATHLEN];
164         char            bloops[] = "18446744073709551615UL";
165
166         char            *friendlyOpt = NULL;
167
168         tester_init( "slapd-tester" );
169
170         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:L:P:p:r:t:w:" )) != EOF ) {
171                 switch( i ) {
172                 case 'D':               /* slapd manager */
173                         manager = ArgDup( optarg );
174                         break;
175
176                 case 'd':               /* data directory */
177                         dirname = strdup( optarg );
178                         break;
179
180                 case 'F':
181                         friendly++;
182                         break;
183
184                 case 'H':               /* slapd uri */
185                         uri = strdup( optarg );
186                         break;
187
188                 case 'h':               /* slapd host */
189                         host = strdup( optarg );
190                         break;
191
192                 case 'j':               /* the number of parallel clients */
193                         if ( lutil_atoi( &maxkids, optarg ) != 0 ) {
194                                 usage( argv[0] );
195                         }
196                         break;
197
198                 case 'l':               /* the number of loops per client */
199                         if ( lutil_atoi( &loops, optarg ) != 0 ) {
200                                 usage( argv[0] );
201                         }
202                         break;
203
204                 case 'L':               /* the number of outerloops per client */
205                         outerloops = strdup( optarg );
206                         break;
207
208                 case 'P':               /* prog directory */
209                         progdir = strdup( optarg );
210                         break;
211
212                 case 'p':               /* the servers port number */
213                         port = strdup( optarg );
214                         break;
215
216                 case 'r':               /* the number of retries in case of error */
217                         retries = strdup( optarg );
218                         break;
219
220                 case 't':               /* the delay in seconds between each retry */
221                         delay = strdup( optarg );
222                         break;
223
224                 case 'w':               /* the managers passwd */
225                         passwd = ArgDup( optarg );
226                         break;
227
228                 default:
229                         usage( argv[0] );
230                         break;
231                 }
232         }
233
234         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
235                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
236                 usage( argv[0] );
237
238 #ifdef HAVE_WINSOCK
239         children = malloc( maxkids * sizeof(HANDLE) );
240 #endif
241         /* get the file list */
242         if ( ( datadir = opendir( dirname )) == NULL ) {
243
244                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
245                                         argv[0], dirname );
246                 exit( EXIT_FAILURE );
247
248         }
249
250         /*  look for search, read, modrdn, and add/delete files */
251         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
252
253                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
254                         sfile = get_file_name( dirname, file->d_name );
255                         continue;
256                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
257                         rfile = get_file_name( dirname, file->d_name );
258                         continue;
259                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
260                         mfile = get_file_name( dirname, file->d_name );
261                         continue;
262                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
263                         modfile = get_file_name( dirname, file->d_name );
264                         continue;
265                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
266                         && ( anum < MAXREQS )) {
267                         afiles[anum++] = get_file_name( dirname, file->d_name );
268                         continue;
269                 } else if ( !strcasecmp( file->d_name, TBINDFILE )) {
270                         bfile = get_file_name( dirname, file->d_name );
271                         continue;
272                 }
273         }
274
275         closedir( datadir );
276
277         /* look for search requests */
278         if ( sfile ) {
279                 snum = get_search_filters( sfile, sreqs, sbase );
280         }
281
282         /* look for read requests */
283         if ( rfile ) {
284                 rnum = get_read_entries( rfile, rreqs );
285         }
286
287         /* look for modrdn requests */
288         if ( mfile ) {
289                 mnum = get_read_entries( mfile, mreqs );
290         }
291
292         /* look for modify requests */
293         if ( modfile ) {
294                 modnum = get_search_filters( modfile, modreqs, moddn );
295         }
296
297         /* look for bind requests */
298         if ( bfile ) {
299                 bnum = get_search_filters( bfile, bcreds, breqs );
300         }
301
302         /* setup friendly option */
303
304         switch ( friendly ) {
305         case 0:
306                 break;
307
308         case 1:
309                 friendlyOpt = "-F";
310                 break;
311
312         default:
313                 /* NOTE: right now we don't need it more than twice */
314         case 2:
315                 friendlyOpt = "-FF";
316                 break;
317         }
318
319         snprintf( sloops, sizeof( sloops ), "%d", 10 * loops );
320         snprintf( rloops, sizeof( rloops ), "%d", 20 * loops );
321         snprintf( aloops, sizeof( aloops ), "%d", loops );
322         snprintf( mloops, sizeof( mloops ), "%d", loops );
323         snprintf( modloops, sizeof( modloops ), "%d", loops );
324         snprintf( bloops, sizeof( bloops ), "%d", 20 * loops );
325
326         /*
327          * generate the search clients
328          */
329
330         sanum = 0;
331         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
332                 progdir );
333         sargs[sanum++] = scmd;
334         if ( uri ) {
335                 sargs[sanum++] = "-H";
336                 sargs[sanum++] = uri;
337         } else {
338                 sargs[sanum++] = "-h";
339                 sargs[sanum++] = host;
340                 sargs[sanum++] = "-p";
341                 sargs[sanum++] = port;
342         }
343         sargs[sanum++] = "-D";
344         sargs[sanum++] = manager;
345         sargs[sanum++] = "-w";
346         sargs[sanum++] = passwd;
347         sargs[sanum++] = "-l";
348         sargs[sanum++] = sloops;
349         sargs[sanum++] = "-L";
350         sargs[sanum++] = outerloops;
351         sargs[sanum++] = "-r";
352         sargs[sanum++] = retries;
353         sargs[sanum++] = "-t";
354         sargs[sanum++] = delay;
355         sargs[sanum++] = "-b";
356         sargs[sanum++] = NULL;          /* will hold the search base */
357         sargs[sanum++] = "-f";
358         sargs[sanum++] = NULL;          /* will hold the search request */
359         sargs[sanum++] = NULL;
360
361         /*
362          * generate the read clients
363          */
364
365         ranum = 0;
366         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
367                 progdir );
368         rargs[ranum++] = rcmd;
369         if ( uri ) {
370                 rargs[ranum++] = "-H";
371                 rargs[ranum++] = uri;
372         } else {
373                 rargs[ranum++] = "-h";
374                 rargs[ranum++] = host;
375                 rargs[ranum++] = "-p";
376                 rargs[ranum++] = port;
377         }
378         rargs[ranum++] = "-l";
379         rargs[ranum++] = rloops;
380         rargs[ranum++] = "-L";
381         rargs[ranum++] = outerloops;
382         rargs[ranum++] = "-r";
383         rargs[ranum++] = retries;
384         rargs[ranum++] = "-t";
385         rargs[ranum++] = delay;
386         rargs[ranum++] = "-e";
387         rargs[ranum++] = NULL;          /* will hold the read entry */
388         rargs[ranum++] = NULL;
389
390         /*
391          * generate the modrdn clients
392          */
393
394         manum = 0;
395         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
396                 progdir );
397         margs[manum++] = mcmd;
398         if ( uri ) {
399                 margs[manum++] = "-H";
400                 margs[manum++] = uri;
401         } else {
402                 margs[manum++] = "-h";
403                 margs[manum++] = host;
404                 margs[manum++] = "-p";
405                 margs[manum++] = port;
406         }
407         margs[manum++] = "-D";
408         margs[manum++] = manager;
409         margs[manum++] = "-w";
410         margs[manum++] = passwd;
411         margs[manum++] = "-l";
412         margs[manum++] = mloops;
413         margs[manum++] = "-L";
414         margs[manum++] = outerloops;
415         margs[manum++] = "-r";
416         margs[manum++] = retries;
417         margs[manum++] = "-t";
418         margs[manum++] = delay;
419         if ( friendly ) {
420                 margs[manum++] = friendlyOpt;
421         }
422         margs[manum++] = "-e";
423         margs[manum++] = NULL;          /* will hold the modrdn entry */
424         margs[manum++] = NULL;
425         
426         /*
427          * generate the modify clients
428          */
429
430         modanum = 0;
431         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
432                 progdir );
433         modargs[modanum++] = modcmd;
434         if ( uri ) {
435                 modargs[modanum++] = "-H";
436                 modargs[modanum++] = uri;
437         } else {
438                 modargs[modanum++] = "-h";
439                 modargs[modanum++] = host;
440                 modargs[modanum++] = "-p";
441                 modargs[modanum++] = port;
442         }
443         modargs[modanum++] = "-D";
444         modargs[modanum++] = manager;
445         modargs[modanum++] = "-w";
446         modargs[modanum++] = passwd;
447         modargs[modanum++] = "-l";
448         modargs[modanum++] = modloops;
449         modargs[modanum++] = "-L";
450         modargs[modanum++] = outerloops;
451         modargs[modanum++] = "-r";
452         modargs[modanum++] = retries;
453         modargs[modanum++] = "-t";
454         modargs[modanum++] = delay;
455         if ( friendly ) {
456                 modargs[modanum++] = friendlyOpt;
457         }
458         modargs[modanum++] = "-e";
459         modargs[modanum++] = NULL;              /* will hold the modify entry */
460         modargs[modanum++] = "-a";;
461         modargs[modanum++] = NULL;              /* will hold the ava */
462         modargs[modanum++] = NULL;
463
464         /*
465          * generate the add/delete clients
466          */
467
468         aanum = 0;
469         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
470                 progdir );
471         aargs[aanum++] = acmd;
472         if ( uri ) {
473                 aargs[aanum++] = "-H";
474                 aargs[aanum++] = uri;
475         } else {
476                 aargs[aanum++] = "-h";
477                 aargs[aanum++] = host;
478                 aargs[aanum++] = "-p";
479                 aargs[aanum++] = port;
480         }
481         aargs[aanum++] = "-D";
482         aargs[aanum++] = manager;
483         aargs[aanum++] = "-w";
484         aargs[aanum++] = passwd;
485         aargs[aanum++] = "-l";
486         aargs[aanum++] = aloops;
487         aargs[aanum++] = "-L";
488         aargs[aanum++] = outerloops;
489         aargs[aanum++] = "-r";
490         aargs[aanum++] = retries;
491         aargs[aanum++] = "-t";
492         aargs[aanum++] = delay;
493         if ( friendly ) {
494                 aargs[aanum++] = friendlyOpt;
495         }
496         aargs[aanum++] = "-f";
497         aargs[aanum++] = NULL;          /* will hold the add data file */
498         aargs[aanum++] = NULL;
499
500         /*
501          * generate the bind clients
502          */
503
504         banum = 0;
505         snprintf( bcmd, sizeof bcmd, "%s" LDAP_DIRSEP BINDCMD,
506                 progdir );
507         bargs[banum++] = bcmd;
508         if ( uri ) {
509                 bargs[banum++] = "-H";
510                 bargs[banum++] = uri;
511         } else {
512                 bargs[banum++] = "-h";
513                 bargs[banum++] = host;
514                 bargs[banum++] = "-p";
515                 bargs[banum++] = port;
516         }
517         bargs[banum++] = "-l";
518         bargs[banum++] = bloops;
519         bargs[banum++] = "-L";
520         bargs[banum++] = outerloops;
521 #if 0
522         bargs[banum++] = "-r";
523         bargs[banum++] = retries;
524         bargs[banum++] = "-t";
525         bargs[banum++] = delay;
526 #endif
527         if ( friendly ) {
528                 bargs[banum++] = friendlyOpt;
529         }
530         bargs[banum++] = "-D";
531         bargs[banum++] = NULL;
532         bargs[banum++] = "-w";
533         bargs[banum++] = NULL;
534         bargs[banum++] = NULL;
535
536         for ( j = 0; j < MAXREQS; j++ ) {
537                 if ( j < snum ) {
538
539                         sargs[sanum - 2] = sreqs[j];
540                         sargs[sanum - 4] = sbase[j];
541                         fork_child( scmd, sargs );
542
543                 }
544
545                 if ( j < rnum ) {
546
547                         rargs[ranum - 2] = rreqs[j];
548                         fork_child( rcmd, rargs );
549
550                 }
551
552                 if ( j < mnum ) {
553
554                         margs[manum - 2] = mreqs[j];
555                         fork_child( mcmd, margs );
556
557                 }
558                 if ( j < modnum ) {
559
560                         modargs[modanum - 4] = moddn[j];
561                         modargs[modanum - 2] = modreqs[j];
562                         fork_child( modcmd, modargs );
563
564                 }
565
566                 if ( j < anum ) {
567
568                         aargs[aanum - 2] = afiles[j];
569                         fork_child( acmd, aargs );
570
571                 }
572
573                 if ( j < bnum ) {
574
575                         bargs[banum - 4] = breqs[j];
576                         bargs[banum - 2] = bcreds[j];
577                         fork_child( bcmd, bargs );
578
579                 }
580
581         }
582
583         wait4kids( -1 );
584
585         exit( EXIT_SUCCESS );
586 }
587
588 static char *
589 get_file_name( char *dirname, char *filename )
590 {
591         char buf[MAXPATHLEN];
592
593         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
594                 dirname, filename );
595         return( strdup( buf ));
596 }
597
598
599 static int
600 get_search_filters( char *filename, char *filters[], char *bases[] )
601 {
602         FILE    *fp;
603         int     filter = 0;
604
605         if ( (fp = fopen( filename, "r" )) != NULL ) {
606                 char  line[BUFSIZ];
607
608                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
609                         char *nl;
610
611                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
612                                 *nl = '\0';
613                         bases[filter] = ArgDup( line );
614                         fgets( line, BUFSIZ, fp );
615                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
616                                 *nl = '\0';
617
618                         filters[filter++] = ArgDup( line );
619
620                 }
621                 fclose( fp );
622         }
623
624         return( filter );
625 }
626
627
628 static int
629 get_read_entries( char *filename, char *entries[] )
630 {
631         FILE    *fp;
632         int     entry = 0;
633
634         if ( (fp = fopen( filename, "r" )) != NULL ) {
635                 char  line[BUFSIZ];
636
637                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
638                         char *nl;
639
640                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
641                                 *nl = '\0';
642                         entries[entry++] = ArgDup( line );
643
644                 }
645                 fclose( fp );
646         }
647
648         return( entry );
649 }
650
651 #ifndef HAVE_WINSOCK
652 static void
653 fork_child( char *prog, char **args )
654 {
655         pid_t   pid;
656
657         wait4kids( maxkids );
658
659         switch ( pid = fork() ) {
660         case 0:         /* child */
661 #ifdef HAVE_EBCDIC
662                 /* The __LIBASCII execvp only handles ASCII "prog",
663                  * we still need to translate the arg vec ourselves.
664                  */
665                 { char *arg2[MAXREQS];
666                 int i;
667
668                 for (i=0; args[i]; i++) {
669                         arg2[i] = ArgDup(args[i]);
670                         __atoe(arg2[i]);
671                 }
672                 arg2[i] = NULL;
673                 args = arg2; }
674 #endif
675                 execvp( prog, args );
676                 tester_perror( "execvp" );
677                 exit( EXIT_FAILURE );
678                 break;
679
680         case -1:        /* trouble */
681                 tester_perror( "fork" );
682                 break;
683
684         default:        /* parent */
685                 nkids++;
686                 break;
687         }
688 }
689
690 static void
691 wait4kids( int nkidval )
692 {
693         int             status;
694
695         while ( nkids >= nkidval ) {
696                 wait( &status );
697
698                 if ( WIFSTOPPED(status) ) {
699                         fprintf( stderr,
700                             "stopping: child stopped with signal %d\n",
701                             (int) WSTOPSIG(status) );
702
703                 } else if ( WIFSIGNALED(status) ) {
704                         fprintf( stderr, 
705                             "stopping: child terminated with signal %d%s\n",
706                             (int) WTERMSIG(status),
707 #ifdef WCOREDUMP
708                                 WCOREDUMP(status) ? ", core dumped" : ""
709 #else
710                                 ""
711 #endif
712                                 );
713                         exit( WEXITSTATUS(status)  );
714
715                 } else if ( WEXITSTATUS(status) != 0 ) {
716                         fprintf( stderr, 
717                             "stopping: child exited with status %d\n",
718                             (int) WEXITSTATUS(status) );
719                         exit( WEXITSTATUS(status) );
720
721                 } else {
722                         nkids--;
723                 }
724         }
725 }
726 #else
727
728 static void
729 wait4kids( int nkidval )
730 {
731         int rc, i;
732
733         while ( nkids >= nkidval ) {
734                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
735                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
736                         children[i] = children[i+1];
737                 nkids--;
738         }
739 }
740
741 static void
742 fork_child( char *prog, char **args )
743 {
744         int rc;
745
746         wait4kids( maxkids );
747
748         rc = _spawnvp( _P_NOWAIT, prog, args );
749
750         if ( rc == -1 ) {
751                 tester_perror( "_spawnvp" );
752         } else {
753                 children[nkids++] = (HANDLE)rc;
754         }
755 }
756 #endif