]> git.sur5r.net Git - openldap/blob - tests/progs/slapd-tester.c
allow a friendly behavior of write stress testers...
[openldap] / tests / progs / slapd-tester.c
1 /* $OpenLDAP$ */
2 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
3  *
4  * Copyright 1999-2005 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
37
38 #define SEARCHCMD               "slapd-search"
39 #define READCMD                 "slapd-read"
40 #define ADDCMD                  "slapd-addel"
41 #define MODRDNCMD               "slapd-modrdn"
42 #define MODIFYCMD               "slapd-modify"
43 #define MAXARGS                 100
44 #define MAXREQS                 5000
45 #define LOOPS                   "100"
46 #define RETRIES                 "0"
47
48 #define TSEARCHFILE             "do_search.0"
49 #define TREADFILE               "do_read.0"
50 #define TADDFILE                "do_add."
51 #define TMODRDNFILE             "do_modrdn.0"
52 #define TMODIFYFILE             "do_modify.0"
53
54 static char *get_file_name( char *dirname, char *filename );
55 static int  get_search_filters( char *filename, char *filters[], char *bases[] );
56 static int  get_read_entries( char *filename, char *entries[] );
57 static void fork_child( char *prog, char **args );
58 static void     wait4kids( int nkidval );
59
60 static int      maxkids = 20;
61 static int      nkids;
62
63 #ifdef HAVE_WINSOCK
64 static HANDLE   *children;
65 static char argbuf[BUFSIZ];
66 #define ArgDup(x) strdup(strcat(strcat(strcpy(argbuf,"\""),x),"\""))
67 #else
68 #define ArgDup(x) strdup(x)
69 #endif
70
71 static void
72 usage( char *name )
73 {
74         fprintf( stderr,
75                 "usage: %s "
76                 "-H <uri> | ([-h <host>] -p <port>) "
77                 "-D <manager> "
78                 "-w <passwd> "
79                 "-d <datadir> "
80                 "[-j <maxchild>] "
81                 "[-l <loops>] "
82                 "-P <progdir> "
83                 "[-r <maxretries>] "
84                 "[-t <delay>] "
85                 "[-F]\n",
86                 name );
87         exit( EXIT_FAILURE );
88 }
89
90 int
91 main( int argc, char **argv )
92 {
93         int             i, j;
94         char            *uri = NULL;
95         char            *host = "localhost";
96         char            *port = NULL;
97         char            *manager = NULL;
98         char            *passwd = NULL;
99         char            *dirname = NULL;
100         char            *progdir = NULL;
101         char            *loops = LOOPS;
102         char            *retries = RETRIES;
103         char            *delay = "0";
104         DIR                     *datadir;
105         struct dirent   *file;
106         char            *sfile = NULL;
107         char            *sreqs[MAXREQS];
108         char            *sbase[MAXREQS];
109         int         snum = 0;
110         char            *rfile = NULL;
111         char            *rreqs[MAXREQS];
112         int         rnum = 0;
113         char            *afiles[MAXREQS];
114         int         anum = 0;
115         char            *mfile = NULL;
116         char            *mreqs[MAXREQS];
117         int             mnum = 0;
118         char            *sargs[MAXARGS];
119         int                     sanum;
120         char            scmd[MAXPATHLEN];
121         char            *rargs[MAXARGS];
122         int                     ranum;
123         char            rcmd[MAXPATHLEN];
124         char            *aargs[MAXARGS];
125         int                     aanum;
126         char            acmd[MAXPATHLEN];
127         char            *margs[MAXARGS];
128         int             manum;
129         char            mcmd[MAXPATHLEN];
130         char            *modargs[MAXARGS];
131         int             modanum;
132         char            modcmd[MAXPATHLEN];
133         char            *modfile = NULL;
134         char            *modreqs[MAXREQS];
135         char            *moddn[MAXREQS];
136         int             modnum = 0;
137         int             friendly = 0;
138
139         while ( (i = getopt( argc, argv, "D:d:FH:h:j:l:P:p:r:t:w:" )) != EOF ) {
140                 switch( i ) {
141                 case 'D':               /* slapd manager */
142                         manager = ArgDup( optarg );
143                         break;
144
145                 case 'd':               /* data directory */
146                         dirname = strdup( optarg );
147                         break;
148
149                 case 'F':
150                         friendly++;
151                         break;
152
153                 case 'H':               /* slapd uri */
154                         uri = strdup( optarg );
155                         break;
156
157                 case 'h':               /* slapd host */
158                         host = strdup( optarg );
159                         break;
160
161                 case 'j':               /* the number of parallel clients */
162                         maxkids = atoi( optarg );
163                         break;
164
165                 case 'l':               /* the number of loops per client */
166                         loops = strdup( optarg );
167                         break;
168
169                 case 'P':               /* prog directory */
170                         progdir = strdup( optarg );
171                         break;
172
173                 case 'p':               /* the servers port number */
174                         port = strdup( optarg );
175                         break;
176
177                 case 'r':               /* the number of retries in case of error */
178                         retries = strdup( optarg );
179                         break;
180
181                 case 't':               /* the delay in seconds between each retry */
182                         delay = strdup( optarg );
183                         break;
184
185                 case 'w':               /* the managers passwd */
186                         passwd = ArgDup( optarg );
187                         break;
188
189                 default:
190                         usage( argv[0] );
191                         break;
192                 }
193         }
194
195         if (( dirname == NULL ) || ( port == NULL && uri == NULL ) ||
196                         ( manager == NULL ) || ( passwd == NULL ) || ( progdir == NULL ))
197                 usage( argv[0] );
198
199 #ifdef HAVE_WINSOCK
200         children = malloc( maxkids * sizeof(HANDLE) );
201 #endif
202         /* get the file list */
203         if ( ( datadir = opendir( dirname )) == NULL ) {
204
205                 fprintf( stderr, "%s: couldn't open data directory \"%s\".\n",
206                                         argv[0], dirname );
207                 exit( EXIT_FAILURE );
208
209         }
210
211         /*  look for search, read, modrdn, and add/delete files */
212         for ( file = readdir( datadir ); file; file = readdir( datadir )) {
213
214                 if ( !strcasecmp( file->d_name, TSEARCHFILE )) {
215                         sfile = get_file_name( dirname, file->d_name );
216                         continue;
217                 } else if ( !strcasecmp( file->d_name, TREADFILE )) {
218                         rfile = get_file_name( dirname, file->d_name );
219                         continue;
220                 } else if ( !strcasecmp( file->d_name, TMODRDNFILE )) {
221                         mfile = get_file_name( dirname, file->d_name );
222                         continue;
223                 } else if ( !strcasecmp( file->d_name, TMODIFYFILE )) {
224                         modfile = get_file_name( dirname, file->d_name );
225                         continue;
226                 } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE ))
227                         && ( anum < MAXREQS )) {
228                         afiles[anum++] = get_file_name( dirname, file->d_name );
229                         continue;
230                 }
231         }
232
233         closedir( datadir );
234
235         /* look for search requests */
236         if ( sfile ) {
237                 snum = get_search_filters( sfile, sreqs, sbase );
238         }
239
240         /* look for read requests */
241         if ( rfile ) {
242                 rnum = get_read_entries( rfile, rreqs );
243         }
244
245         /* look for modrdn requests */
246         if ( mfile ) {
247                 mnum = get_read_entries( mfile, mreqs );
248         }
249         /* look for modify requests */
250         if ( modfile ) {
251                 modnum = get_search_filters( modfile, modreqs, moddn );
252         }
253
254         /*
255          * generate the search clients
256          */
257
258         sanum = 0;
259         snprintf( scmd, sizeof scmd, "%s" LDAP_DIRSEP SEARCHCMD,
260                 progdir );
261         sargs[sanum++] = scmd;
262         if ( uri ) {
263                 sargs[sanum++] = "-H";
264                 sargs[sanum++] = uri;
265         } else {
266                 sargs[sanum++] = "-h";
267                 sargs[sanum++] = host;
268                 sargs[sanum++] = "-p";
269                 sargs[sanum++] = port;
270         }
271         sargs[sanum++] = "-D";
272         sargs[sanum++] = manager;
273         sargs[sanum++] = "-w";
274         sargs[sanum++] = passwd;
275         sargs[sanum++] = "-l";
276         sargs[sanum++] = loops;
277         sargs[sanum++] = "-r";
278         sargs[sanum++] = retries;
279         sargs[sanum++] = "-t";
280         sargs[sanum++] = delay;
281         sargs[sanum++] = "-b";
282         sargs[sanum++] = NULL;          /* will hold the search base */
283         sargs[sanum++] = "-f";
284         sargs[sanum++] = NULL;          /* will hold the search request */
285         sargs[sanum++] = NULL;
286
287         /*
288          * generate the read clients
289          */
290
291         ranum = 0;
292         snprintf( rcmd, sizeof rcmd, "%s" LDAP_DIRSEP READCMD,
293                 progdir );
294         rargs[ranum++] = rcmd;
295         if ( uri ) {
296                 rargs[ranum++] = "-H";
297                 rargs[ranum++] = uri;
298         } else {
299                 rargs[ranum++] = "-h";
300                 rargs[ranum++] = host;
301                 rargs[ranum++] = "-p";
302                 rargs[ranum++] = port;
303         }
304         rargs[ranum++] = "-l";
305         rargs[ranum++] = loops;
306         rargs[ranum++] = "-r";
307         rargs[ranum++] = retries;
308         rargs[ranum++] = "-t";
309         rargs[ranum++] = delay;
310         rargs[ranum++] = "-e";
311         rargs[ranum++] = NULL;          /* will hold the read entry */
312         rargs[ranum++] = NULL;
313
314         /*
315          * generate the modrdn clients
316          */
317
318         manum = 0;
319         snprintf( mcmd, sizeof mcmd, "%s" LDAP_DIRSEP MODRDNCMD,
320                 progdir );
321         margs[manum++] = mcmd;
322         if ( uri ) {
323                 margs[manum++] = "-H";
324                 margs[manum++] = uri;
325         } else {
326                 margs[manum++] = "-h";
327                 margs[manum++] = host;
328                 margs[manum++] = "-p";
329                 margs[manum++] = port;
330         }
331         margs[manum++] = "-D";
332         margs[manum++] = manager;
333         margs[manum++] = "-w";
334         margs[manum++] = passwd;
335         margs[manum++] = "-l";
336         margs[manum++] = loops;
337         margs[manum++] = "-r";
338         margs[manum++] = retries;
339         margs[manum++] = "-t";
340         margs[manum++] = delay;
341         if ( friendly ) {
342                 margs[manum++] = "-F";
343         }
344         margs[manum++] = "-e";
345         margs[manum++] = NULL;          /* will hold the modrdn entry */
346         margs[manum++] = NULL;
347         
348         /*
349          * generate the modify clients
350          */
351
352         modanum = 0;
353         snprintf( modcmd, sizeof modcmd, "%s" LDAP_DIRSEP MODIFYCMD,
354                 progdir );
355         modargs[modanum++] = modcmd;
356         if ( uri ) {
357                 modargs[modanum++] = "-H";
358                 modargs[modanum++] = uri;
359         } else {
360                 modargs[modanum++] = "-h";
361                 modargs[modanum++] = host;
362                 modargs[modanum++] = "-p";
363                 modargs[modanum++] = port;
364         }
365         modargs[modanum++] = "-D";
366         modargs[modanum++] = manager;
367         modargs[modanum++] = "-w";
368         modargs[modanum++] = passwd;
369         modargs[modanum++] = "-l";
370         modargs[modanum++] = loops;
371         modargs[modanum++] = "-r";
372         modargs[modanum++] = retries;
373         modargs[modanum++] = "-t";
374         modargs[modanum++] = delay;
375         if ( friendly ) {
376                 modargs[modanum++] = "-F";
377         }
378         modargs[modanum++] = "-e";
379         modargs[modanum++] = NULL;              /* will hold the modify entry */
380         modargs[modanum++] = "-a";;
381         modargs[modanum++] = NULL;              /* will hold the ava */
382         modargs[modanum++] = NULL;
383
384         /*
385          * generate the add/delete clients
386          */
387
388         aanum = 0;
389         snprintf( acmd, sizeof acmd, "%s" LDAP_DIRSEP ADDCMD,
390                 progdir );
391         aargs[aanum++] = acmd;
392         if ( uri ) {
393                 aargs[aanum++] = "-H";
394                 aargs[aanum++] = uri;
395         } else {
396                 aargs[aanum++] = "-h";
397                 aargs[aanum++] = host;
398                 aargs[aanum++] = "-p";
399                 aargs[aanum++] = port;
400         }
401         aargs[aanum++] = "-D";
402         aargs[aanum++] = manager;
403         aargs[aanum++] = "-w";
404         aargs[aanum++] = passwd;
405         aargs[aanum++] = "-l";
406         aargs[aanum++] = loops;
407         aargs[aanum++] = "-r";
408         aargs[aanum++] = retries;
409         aargs[aanum++] = "-t";
410         aargs[aanum++] = delay;
411         if ( friendly ) {
412                 aargs[aanum++] = "-F";
413         }
414         aargs[aanum++] = "-f";
415         aargs[aanum++] = NULL;          /* will hold the add data file */
416         aargs[aanum++] = NULL;
417
418         for ( j = 0; j < MAXREQS; j++ ) {
419
420                 if ( j < snum ) {
421
422                         sargs[sanum - 2] = sreqs[j];
423                         sargs[sanum - 4] = sbase[j];
424                         fork_child( scmd, sargs );
425
426                 }
427
428                 if ( j < rnum ) {
429
430                         rargs[ranum - 2] = rreqs[j];
431                         fork_child( rcmd, rargs );
432
433                 }
434
435                 if ( j < mnum ) {
436
437                         margs[manum - 2] = mreqs[j];
438                         fork_child( mcmd, margs );
439
440                 }
441                 if ( j < modnum ) {
442
443                         modargs[modanum - 4] = moddn[j];
444                         modargs[modanum - 2] = modreqs[j];
445                         fork_child( modcmd, modargs );
446
447                 }
448
449                 if ( j < anum ) {
450
451                         aargs[aanum - 2] = afiles[j];
452                         fork_child( acmd, aargs );
453
454                 }
455
456         }
457
458         wait4kids( -1 );
459
460         exit( EXIT_SUCCESS );
461 }
462
463 static char *
464 get_file_name( char *dirname, char *filename )
465 {
466         char buf[MAXPATHLEN];
467
468         snprintf( buf, sizeof buf, "%s" LDAP_DIRSEP "%s",
469                 dirname, filename );
470         return( strdup( buf ));
471 }
472
473
474 static int
475 get_search_filters( char *filename, char *filters[], char *bases[] )
476 {
477         FILE    *fp;
478         int     filter = 0;
479
480         if ( (fp = fopen( filename, "r" )) != NULL ) {
481                 char  line[BUFSIZ];
482
483                 while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
484                         char *nl;
485
486                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
487                                 *nl = '\0';
488                         bases[filter] = ArgDup( line );
489                         fgets( line, BUFSIZ, fp );
490                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
491                                 *nl = '\0';
492
493                         filters[filter++] = ArgDup( line );
494
495                 }
496                 fclose( fp );
497         }
498
499         return( filter );
500 }
501
502
503 static int
504 get_read_entries( char *filename, char *entries[] )
505 {
506         FILE    *fp;
507         int     entry = 0;
508
509         if ( (fp = fopen( filename, "r" )) != NULL ) {
510                 char  line[BUFSIZ];
511
512                 while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) {
513                         char *nl;
514
515                         if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' )))
516                                 *nl = '\0';
517                         entries[entry++] = ArgDup( line );
518
519                 }
520                 fclose( fp );
521         }
522
523         return( entry );
524 }
525
526 #ifndef HAVE_WINSOCK
527 static void
528 fork_child( char *prog, char **args )
529 {
530         pid_t   pid;
531
532         wait4kids( maxkids );
533
534         switch ( pid = fork() ) {
535         case 0:         /* child */
536 #ifdef HAVE_EBCDIC
537                 /* The __LIBASCII execvp only handles ASCII "prog",
538                  * we still need to translate the arg vec ourselves.
539                  */
540                 { char *arg2[MAXREQS];
541                 int i;
542
543                 for (i=0; args[i]; i++) {
544                         arg2[i] = ArgDup(args[i]);
545                         __atoe(arg2[i]);
546                 }
547                 arg2[i] = NULL;
548                 args = arg2; }
549 #endif
550                 execvp( prog, args );
551                 fprintf( stderr, "%s: ", prog );
552                 perror( "execv" );
553                 exit( EXIT_FAILURE );
554                 break;
555
556         case -1:        /* trouble */
557                 fprintf( stderr, "Could not fork to run %s\n", prog );
558                 perror( "fork" );
559                 break;
560
561         default:        /* parent */
562                 nkids++;
563                 break;
564         }
565 }
566
567 static void
568 wait4kids( int nkidval )
569 {
570         int             status;
571
572         while ( nkids >= nkidval ) {
573                 wait( &status );
574
575                 if ( WIFSTOPPED(status) ) {
576                         fprintf( stderr,
577                             "stopping: child stopped with signal %d\n",
578                             (int) WSTOPSIG(status) );
579
580                 } else if ( WIFSIGNALED(status) ) {
581                         fprintf( stderr, 
582                             "stopping: child terminated with signal %d%s\n",
583                             (int) WTERMSIG(status),
584 #ifdef WCOREDUMP
585                                 WCOREDUMP(status) ? ", core dumped" : ""
586 #else
587                                 ""
588 #endif
589                                 );
590                         exit( WEXITSTATUS(status)  );
591
592                 } else if ( WEXITSTATUS(status) != 0 ) {
593                         fprintf( stderr, 
594                             "stopping: child exited with status %d\n",
595                             (int) WEXITSTATUS(status) );
596                         exit( WEXITSTATUS(status) );
597
598                 } else {
599                         nkids--;
600                 }
601         }
602 }
603 #else
604
605 static void
606 wait4kids( int nkidval )
607 {
608         int rc, i;
609
610         while ( nkids >= nkidval ) {
611                 rc = WaitForMultipleObjects( nkids, children, FALSE, INFINITE );
612                 for ( i=rc - WAIT_OBJECT_0; i<nkids-1; i++)
613                         children[i] = children[i+1];
614                 nkids--;
615         }
616 }
617
618 static void
619 fork_child( char *prog, char **args )
620 {
621         int rc;
622
623         wait4kids( maxkids );
624
625         rc = _spawnvp( _P_NOWAIT, prog, args );
626
627         if ( rc == -1 ) {
628                 fprintf( stderr, "%s: ", prog );
629                 perror("spawnvp");
630         } else {
631                 children[nkids++] = (HANDLE)rc;
632         }
633 }
634 #endif