From 39f0066db488364aefb67164e8d4671b487835e1 Mon Sep 17 00:00:00 2001 From: Kurt Spanier Date: Mon, 15 Feb 1999 10:49:20 +0000 Subject: [PATCH] Addition of a new Concurrency Test fro testing slapd performance and correctness of locking schemas in backends. In back-bdb2 open NEXTID during startup and close at shutdown. --- doc/devel/todo | 2 +- servers/slapd/back-bdb2/back-bdb2.h | 9 +- servers/slapd/back-bdb2/index.c | 27 +-- servers/slapd/back-bdb2/init.c | 2 - servers/slapd/back-bdb2/nextid.c | 42 ++-- servers/slapd/back-bdb2/startup.c | 2 +- servers/slapd/back-bdb2/txn.c | 70 +++++- tests/Makefile.in | 33 ++- tests/data/do_add.1 | 26 ++ tests/data/do_read.0 | 5 + tests/data/do_search.0 | 5 + tests/data/slapd-bdb2-master.conf | 1 + tests/scripts/defines.sh | 1 + tests/scripts/test008-concurrency | 68 ++++++ tests/slapd-addel.c | 276 ++++++++++++++++++++++ tests/slapd-read.c | 117 +++++++++ tests/slapd-search.c | 122 ++++++++++ tests/slapd-tester.c | 352 ++++++++++++++++++++++++++++ 18 files changed, 1103 insertions(+), 57 deletions(-) create mode 100644 tests/data/do_add.1 create mode 100644 tests/data/do_read.0 create mode 100644 tests/data/do_search.0 create mode 100755 tests/scripts/test008-concurrency create mode 100644 tests/slapd-addel.c create mode 100644 tests/slapd-read.c create mode 100644 tests/slapd-search.c create mode 100644 tests/slapd-tester.c diff --git a/doc/devel/todo b/doc/devel/todo index c1781181d1..3a8e7e057a 100644 --- a/doc/devel/todo +++ b/doc/devel/todo @@ -32,7 +32,7 @@ Modify -lldap to be session-level multithreaded Port slapd (incl back-ldbm & tools) to NT MajorLDAP - Design and implement an LDAP-enabled mailing list manager Slapd-DB2 - Design and implement a backend to take full advantage - of the latest DB2 features. + of the latest DB2 features . Medium projects diff --git a/servers/slapd/back-bdb2/back-bdb2.h b/servers/slapd/back-bdb2/back-bdb2.h index f3c0ec0d68..126c2fb6ce 100644 --- a/servers/slapd/back-bdb2/back-bdb2.h +++ b/servers/slapd/back-bdb2/back-bdb2.h @@ -90,7 +90,6 @@ struct dbcache { int dbc_refcnt; int dbc_maxids; int dbc_maxindirect; - time_t dbc_lastref; long dbc_blksize; char *dbc_name; LDBM dbc_db; @@ -146,6 +145,11 @@ typedef struct _bdb2_txn_head { #define BDB2_DB_ID2CHILDREN_FILE 3 #define BDB2_DB_OC_IDX_FILE 4 + /* a file pointer for the NEXTID file + (must be opened appropriately at backend + entry and closed on leave */ + FILE *nextidFP; + /* is the default attribute index set to non-none */ int withDefIDX; #define BDB2_WITH_DEF_IDX 1 @@ -187,9 +191,6 @@ struct ldbminfo { Avlnode *li_attrs; int li_dbcachesize; int li_dbcachewsync; - struct dbcache li_dbcache[MAXDBCACHE]; - ldap_pvt_thread_mutex_t li_dbcache_mutex; - ldap_pvt_thread_cond_t li_dbcache_cv; /* a list of all files of the database */ BDB2_TXN_HEAD li_txn_head; diff --git a/servers/slapd/back-bdb2/index.c b/servers/slapd/back-bdb2/index.c index 4344606632..6cd9d31cf7 100644 --- a/servers/slapd/back-bdb2/index.c +++ b/servers/slapd/back-bdb2/index.c @@ -128,26 +128,26 @@ bdb2i_index_read( realval = val; tmpval = NULL; if ( prefix != UNKNOWN_PREFIX ) { - unsigned int len = strlen( val ); + unsigned int len = strlen( val ); - if ( (len + 2) < sizeof(buf) ) { + if ( (len + 2) < sizeof(buf) ) { realval = buf; } else { /* value + prefix + null */ tmpval = (char *) ch_malloc( len + 2 ); realval = tmpval; } - realval[0] = prefix; - strcpy( &realval[1], val ); + realval[0] = prefix; + strcpy( &realval[1], val ); } key.dptr = realval; key.dsize = strlen( realval ) + 1; idl = bdb2i_idl_fetch( be, db, key ); - if ( tmpval != NULL ) { - free( tmpval ); - } + if ( tmpval != NULL ) { + free( tmpval ); + } bdb2i_cache_close( be, db ); @@ -168,7 +168,6 @@ add_value( { int rc; Datum key; - ID_BLOCK *idl = NULL; char *tmpval = NULL; char *realval = val; char buf[BUFSIZ]; @@ -180,17 +179,17 @@ add_value( Debug( LDAP_DEBUG_TRACE, "=> add_value( \"%c%s\" )\n", prefix, val, 0 ); if ( prefix != UNKNOWN_PREFIX ) { - unsigned int len = strlen( val ); + unsigned int len = strlen( val ); - if ( (len + 2) < sizeof(buf) ) { + if ( (len + 2) < sizeof(buf) ) { realval = buf; } else { /* value + prefix + null */ tmpval = (char *) ch_malloc( len + 2 ); realval = tmpval; } - realval[0] = prefix; - strcpy( &realval[1], val ); + realval[0] = prefix; + strcpy( &realval[1], val ); } key.dptr = realval; @@ -202,10 +201,6 @@ add_value( free( tmpval ); } - if( idl != NULL ) { - bdb2i_idl_free( idl ); - } - ldap_pvt_thread_yield(); /* Debug( LDAP_DEBUG_TRACE, "<= add_value %d\n", rc, 0, 0 ); */ diff --git a/servers/slapd/back-bdb2/init.c b/servers/slapd/back-bdb2/init.c index eaa557f9de..5f0c8cd3d1 100644 --- a/servers/slapd/back-bdb2/init.c +++ b/servers/slapd/back-bdb2/init.c @@ -177,8 +177,6 @@ bdb2i_back_db_init_internal( ldap_pvt_thread_mutex_init( &li->li_add_mutex ); ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex ); ldap_pvt_thread_mutex_init( &li->li_nextid_mutex ); - ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex ); - ldap_pvt_thread_cond_init( &li->li_dbcache_cv ); /* initialize the TP file head */ if ( bdb2i_txn_head_init( &li->li_txn_head ) != 0 ) diff --git a/servers/slapd/back-bdb2/nextid.c b/servers/slapd/back-bdb2/nextid.c index 711603a46c..129221e31e 100644 --- a/servers/slapd/back-bdb2/nextid.c +++ b/servers/slapd/back-bdb2/nextid.c @@ -13,32 +13,29 @@ #include "slap.h" #include "back-bdb2.h" +/* XXX the separate handling of the NEXTID file is in contrast to TP */ +/* the NEXTID file is beeing opened during database start-up */ static ID next_id_read( BackendDB *be ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; + BDB2_TXN_HEAD *head = &li->li_txn_head; + FILE* fp = head->nextidFP; ID id; char buf[20]; - char* file = li->li_nextid_file; - FILE* fp; - if ( (fp = fopen( file, "r" )) == NULL ) { - Debug( LDAP_DEBUG_ANY, - "next_id_read: could not open \"%s\"\n", - file, 0, 0 ); - return NOID; - } + /* set the file pointer to the beginnig of the file */ + rewind( fp ); + /* read the nextid */ if ( fgets( buf, sizeof(buf), fp ) == NULL ) { Debug( LDAP_DEBUG_ANY, "next_id_read: could not fgets nextid from \"%s\"\n", - file, 0, 0 ); - fclose( fp ); + li->li_nextid_file, 0, 0 ); return NOID; } id = atol( buf ); - fclose( fp ); if(id < 1) { Debug( LDAP_DEBUG_ANY, @@ -50,31 +47,30 @@ next_id_read( BackendDB *be ) return id; } +/* XXX the separate handling of the NEXTID file is in contrast to TP */ +/* the NEXTID file is beeing opened during database start-up */ static int next_id_write( BackendDB *be, ID id ) { struct ldbminfo *li = (struct ldbminfo *) be->be_private; + BDB2_TXN_HEAD *head = &li->li_txn_head; + FILE* fp = head->nextidFP; char buf[20]; - char* file = li->li_nextid_file; - FILE* fp; - int rc; - - if ( (fp = fopen( file, "w" )) == NULL ) { - Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): could not open \"%s\"\n", - id, file, 0 ); - return -1; - } + int rc = 0; - rc = 0; + /* set the file pointer to the beginnig of the file */ + rewind( fp ); + /* write the nextid */ if ( fprintf( fp, "%ld\n", id ) == EOF ) { Debug( LDAP_DEBUG_ANY, "next_id_write(%ld): cannot fprintf\n", id, 0, 0 ); rc = -1; } - if( fclose( fp ) != 0 ) { - Debug( LDAP_DEBUG_ANY, "next_id_write %ld: cannot fclose\n", + /* if forced flushing of files is in effect, do so */ + if( li->li_dbcachewsync && ( fflush( fp ) != 0 )) { + Debug( LDAP_DEBUG_ANY, "next_id_write %ld: cannot fflush\n", id, 0, 0 ); rc = -1; } diff --git a/servers/slapd/back-bdb2/startup.c b/servers/slapd/back-bdb2/startup.c index 07a4b8d7d9..024d3e238c 100644 --- a/servers/slapd/back-bdb2/startup.c +++ b/servers/slapd/back-bdb2/startup.c @@ -19,7 +19,7 @@ static void remove_old_locks( char *home ); static void bdb2i_db_errcall( char *prefix, char *message ) { - Debug( LDAP_DEBUG_ANY, "dbd2_db_errcall(): %s %s", prefix, message, 0 ); + Debug( LDAP_DEBUG_ANY, "bdb2_db_errcall(): %s %s", prefix, message, 0 ); } diff --git a/servers/slapd/back-bdb2/txn.c b/servers/slapd/back-bdb2/txn.c index 493dfa87fc..9dc238c4f7 100644 --- a/servers/slapd/back-bdb2/txn.c +++ b/servers/slapd/back-bdb2/txn.c @@ -39,16 +39,10 @@ bdb2i_txn_head_init( BDB2_TXN_HEAD *head ) static void bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo ) { - time_t curtime; struct stat st; char buf[MAXPATHLEN]; - ldap_pvt_thread_mutex_lock( ¤ttime_mutex ); - curtime = currenttime; - ldap_pvt_thread_mutex_unlock( ¤ttime_mutex ); - fileinfo->dbc_refcnt = 1; - fileinfo->dbc_lastref = curtime; sprintf( buf, "%s%s%s", li->li_directory, DEFAULT_DIRSEP, fileinfo->dbc_name ); @@ -66,6 +60,14 @@ bdb2i_init_db_file_cache( struct ldbminfo *li, BDB2_TXN_FILES *fileinfo ) } +/* create a DB file cache entry for a specified index attribute + (if not already done); the function is called during config + file read for all index'ed attributes; if "default" index with + a non-none selection is given, this is remembered for run-time + extension of the list of index files; the function is also + called before add or modify operations to check for putative + new "default" index files; at that time, files are also opened +*/ void bdb2i_txn_attr_config( struct ldbminfo *li, @@ -158,11 +160,45 @@ bdb2i_txn_attr_config( } +/* open the NEXTID file for read/write; if it does not exist, + create it (access to the file must be preceeded by a rewind) +*/ +static int +bdb2i_open_nextid( struct ldbminfo *li ) +{ + BDB2_TXN_HEAD *head = &li->li_txn_head; + FILE *fp = NULL; + char *file = li->li_nextid_file; + + /* try to open the file for read and write */ + if ((( fp = fopen( file, "r+" )) == NULL ) && + (( fp = fopen( file, "w+" )) == NULL )) { + + Debug( LDAP_DEBUG_ANY, + "bdb2i_open_nextid: could not open \"%s\"\n", + file, 0, 0 ); + return( -1 ); + + } + + /* the file is open for read/write */ + head->nextidFP = fp; + + return( 0 ); +} + + +/* open all DB during startup of the backend (necessary due to TP) + additional files may be opened during slapd life-time due to + default indexes (must be configured in slapd.conf; + see bdb2i_txn_attr_config) +*/ int bdb2i_txn_open_files( struct ldbminfo *li ) { BDB2_TXN_HEAD *head = &li->li_txn_head; BDB2_TXN_FILES *dbFile; + int rc; for ( dbFile = head->dbFiles; dbFile; dbFile = dbFile->next ) { char fileName[MAXPATHLEN]; @@ -179,7 +215,7 @@ bdb2i_txn_open_files( struct ldbminfo *li ) Debug( LDAP_DEBUG_ANY, "bdb2i_txn_open_files(): couldn't open file \"%s\" -- FATAL.\n", dbFile->dbc_name, 0, 0 ); - return( 1 ); + return( -1 ); } @@ -191,10 +227,22 @@ bdb2i_txn_open_files( struct ldbminfo *li ) } - return 0; + rc = bdb2i_open_nextid( li ); + + return rc; } +/* close the NEXTID file */ +static void +bdb2i_close_nextid( BDB2_TXN_HEAD *head ) +{ + fclose( head->nextidFP ); + head->nextidFP = NULL; +} + + +/* close all DB files during shutdown of the backend */ void bdb2i_txn_close_files( BackendDB *be ) { @@ -207,9 +255,15 @@ bdb2i_txn_close_files( BackendDB *be ) ldbm_close( dbFile->dbc_db ); } + + bdb2i_close_nextid( head ); + } +/* get the db_cache structure associated with a specified + DB file (replaces the on-the-fly opening of files in cache_open() +*/ BDB2_TXN_FILES * bdb2i_get_db_file_cache( struct ldbminfo *li, char *name ) { diff --git a/tests/Makefile.in b/tests/Makefile.in index aea2c7481b..b0626ca9d6 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -4,7 +4,32 @@ ## tests Makefile.in for OpenLDAP BUILD_BDB2 = @BUILD_BDB2@ -bdb2-local: FORCE +SRC = slapd-tester.c slapd-search.c +PROGRAMS = slapd-tester slapd-search slapd-read slapd-addel + +LDAP_INCDIR= ../include +LDAP_LIBDIR= ../libraries + +XLIBS = -lldap_r -llber -llutil + +build-tools: FORCE + $(MAKE) $(MFLAGS) load-tools + +load-tools: $(PROGRAMS) + +slapd-tester: slapd-tester.o + $(LTLINK) -o $@ slapd-tester.o + +slapd-search: slapd-search.o $(LDAP_LIBLBER_DEPEND) $(LDAP_LIBLDAP_DEPEND) + $(LTLINK) -o $@ slapd-search.o $(LDAP_LIBPATH) $(XLIBS) + +slapd-read: slapd-read.o $(LDAP_LIBLBER_DEPEND) $(LDAP_LIBLDAP_DEPEND) + $(LTLINK) -o $@ slapd-read.o $(LDAP_LIBPATH) $(XLIBS) + +slapd-addel: slapd-addel.o $(LDAP_LIBLBER_DEPEND) $(LDAP_LIBLDAP_DEPEND) + $(LTLINK) -o $@ slapd-addel.o $(LDAP_LIBPATH) $(XLIBS) + +bdb2-local: build-tools FORCE @if test "$(BUILD_BDB2)" = "yes" ; then \ $(LN_S) $(srcdir)/data . ; \ echo "Initiating LDAP tests..." ; \ @@ -14,7 +39,7 @@ bdb2-local: FORCE echo "run configure with --enable-bdb2" ; \ fi -all-local: FORCE +all-local: build-tools FORCE @-$(LN_S) $(srcdir)/data . @echo "Initiating LDAP tests..."; \ $(MKDIR) test-db test-repl ; \ @@ -22,8 +47,12 @@ all-local: FORCE clean-local: FORCE $(RM) test-db/[!C]* test-repl/[!C]* *core + $(RM) $(PROGRAMS) + $(RM) *.o veryclean-local: FORCE @-$(RM) data $(RM) -r test-db test-repl + $(RM) $(PROGRAMS) + $(RM) *.o diff --git a/tests/data/do_add.1 b/tests/data/do_add.1 new file mode 100644 index 0000000000..8a57d95c91 --- /dev/null +++ b/tests/data/do_add.1 @@ -0,0 +1,26 @@ +cn=James A Jones 2, ou=Alumni Association, ou=People, o=University of Michigan, c=US +objectclass: top +objectclass: person +objectclass: organizationalPerson +objectclass: newPilotPerson +objectclass: umichPerson +cn: James A Jones 2 +cn: James Jones +cn: Jim Jones +sn: Jones +postaladdress: Alumni Association $ 111 Maple St $ Ann Arbor, MI 48109 +seealso: cn=All Staff, ou=Groups, o=University of Michigan, c=US +uid: jaj +krbname: jaj@umich.edu +userpassword: jaj +nobatchupdates: TRUE +onvacation: FALSE +homepostaladdress: 3882 Beverly Rd. $ Ann Arbor, MI 48105 +homephone: +1 313 555 4772 +multilinedescription: Outstanding +title: Mad Cow Researcher, UM Alumni Association +pager: +1 313 555 3923 +mail: jaj@mail.alumni.umich.edu +facsimiletelephonenumber: +1 313 555 4332 +telephonenumber: +1 313 555 0895 + diff --git a/tests/data/do_read.0 b/tests/data/do_read.0 new file mode 100644 index 0000000000..25dc6761dd --- /dev/null +++ b/tests/data/do_read.0 @@ -0,0 +1,5 @@ +cn=Barbara Jensen, ou=Information Technology Division, ou=People, o=University of Michigan, c=US +cn=ITD Staff,ou=Groups,o=University of Michigan,c=US +ou=Groups, o=University of Michigan, c=US +ou=Alumni Association, ou=People, o=University of Michigan, c=US +cn=James A Jones 1, ou=Alumni Association, ou=People, o=University of Michigan, c=US diff --git a/tests/data/do_search.0 b/tests/data/do_search.0 new file mode 100644 index 0000000000..6e9cd1f3fa --- /dev/null +++ b/tests/data/do_search.0 @@ -0,0 +1,5 @@ +cn=Barbara Jensen +cn=Bjorn Jensen +cn=James A Jones 1 +cn=Bjorn Jensen +cn=Alumni Assoc Staff diff --git a/tests/data/slapd-bdb2-master.conf b/tests/data/slapd-bdb2-master.conf index 53e6a91f2d..2dad68bfc0 100644 --- a/tests/data/slapd-bdb2-master.conf +++ b/tests/data/slapd-bdb2-master.conf @@ -13,6 +13,7 @@ argsfile ./test-db/slapd.args backend bdb2 home ./test-db +mpoolsize 2100000 database bdb2 cachesize 4 diff --git a/tests/scripts/defines.sh b/tests/scripts/defines.sh index 50c8497c45..b77c8f47a1 100755 --- a/tests/scripts/defines.sh +++ b/tests/scripts/defines.sh @@ -31,6 +31,7 @@ SLURPD=../servers/slurpd/slurpd LDAPSEARCH=../clients/tools/ldapsearch LDAPMODIFY=../clients/tools/ldapmodify LDAPADD=../clients/tools/ldapadd +SLAPDTESTER=slapd-tester LVL=5 PORT=9009 SLAVEPORT=9010 diff --git a/tests/scripts/test008-concurrency b/tests/scripts/test008-concurrency new file mode 100755 index 0000000000..815cdaf79e --- /dev/null +++ b/tests/scripts/test008-concurrency @@ -0,0 +1,68 @@ +#!/bin/sh + +if [ $# -eq 0 ]; then + SRCDIR="." +else + SRCDIR=$1; shift +fi +if [ $# -eq 1 ]; then + BDB2=$1; shift +fi + +echo "running defines.sh $SRCDIR $BDB2" + +. $SRCDIR/scripts/defines.sh $SRCDIR $BDB2 + +echo "Datadir is $DATADIR" + +echo "Cleaning up in $DBDIR..." + +rm -f $DBDIR/[!C]* + +echo "Running ldif2ldbm to build slapd database..." +$LDIF2LDBM -f $CONF -i $LDIF -e ../servers/slapd/tools +RC=$? +if [ $RC != 0 ]; then + echo "ldif2ldbm failed!" + exit $RC +fi + +echo "Starting slapd on TCP/IP port $PORT..." +$SLAPD -f $CONF -p $PORT -d $LVL $TIMING > $MASTERLOG 2>&1 & +PID=$! + +echo "Waiting 5 seconds for slapd to start..." +sleep 5 + +echo "Using tester for concurrent server access..." +$SLAPDTESTER -b "$BASEDN" -d "$DATADIR" -h localhost -p $PORT -D "$MANAGERDN" -w $PASSWD -l 100 +RC=$? + +if [ $RC != 0 ]; then + echo "slapd-tester failed!" + exit $RC +fi + +echo "Using ldapsearch to retrieve all the entries..." +$LDAPSEARCH -L -S "" -b "$BASEDN" -h localhost -p $PORT \ + 'objectClass=*' > $SEARCHOUT 2>&1 +RC=$? + +kill -HUP $PID + +if [ $RC != 0 ]; then + echo "ldapsearch failed!" + exit $RC +fi + +echo "Comparing retrieved entries to LDIF file used to create database" +cmp $SEARCHOUT $LDIF +if [ $? != 0 ]; then + echo "comparison failed - database was not created correctly" + exit 1 +fi + +echo ">>>>> Test succeeded" + + +exit 0 diff --git a/tests/slapd-addel.c b/tests/slapd-addel.c new file mode 100644 index 0000000000..a6c7238378 --- /dev/null +++ b/tests/slapd-addel.c @@ -0,0 +1,276 @@ +#include "portable.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "lber.h" +#include "ldap.h" + +#define LOOPS 100 + +static char * +get_add_entry( char *filename, LDAPMod ***mods ); + +static void +do_addel( char *host, int port, char *manager, char *passwd, + char *dn, LDAPMod **attrs, int maxloop ); + +static void +usage( char *name ) +{ + fprintf( stderr, "usage: %s [-h ] -p port -D -w -f [-l ]\n", + name ); + exit( 1 ); +} + +int +main( int argc, char **argv ) +{ + int i, j; + char *host = "localhost"; + int port = -1; + char *manager = NULL; + char *passwd = NULL; + char *filename = NULL; + char *entry = NULL; + int loops = LOOPS; + LDAPMod **attrs = NULL; + + while ( (i = getopt( argc, argv, "h:p:D:w:f:l:" )) != EOF ) { + switch( i ) { + case 'h': /* the servers host */ + host = strdup( optarg ); + break; + + case 'p': /* the servers port */ + port = atoi( optarg ); + break; + + case 'D': /* the servers manager */ + manager = strdup( optarg ); + break; + + case 'w': /* the server managers password */ + passwd = strdup( optarg ); + break; + + case 'f': /* file with entry search request */ + filename = strdup( optarg ); + break; + + case 'l': /* the number of loops */ + loops = atoi( optarg ); + break; + + default: + usage( argv[0] ); + break; + } + } + + if (( filename == NULL ) || ( port == -1 ) || + ( manager == NULL ) || ( passwd == NULL )) + usage( argv[0] ); + + entry = get_add_entry( filename, &attrs ); + if (( entry == NULL ) || ( *entry == '\0' )) { + + fprintf( stderr, "%s: invalid entry DN in file \"%s\".\n", + argv[0], filename ); + exit( 1 ); + + } + + if (( attrs == NULL ) || ( *attrs == '\0' )) { + + fprintf( stderr, "%s: invalid attrs in file \"%s\".\n", + argv[0], filename ); + exit( 1 ); + + } + + do_addel( host, port, manager, passwd, entry, attrs, loops ); + + exit( 0 ); +} + + +#define safe_realloc( ptr, size ) ( ptr == NULL ? malloc( size ) : \ + realloc( ptr, size )) + + +static void +addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen ) +{ + LDAPMod **pmods; + int i, j; + struct berval *bvp; + + pmods = *pmodsp; + modop |= LDAP_MOD_BVALUES; + + i = 0; + if ( pmods != NULL ) { + for ( ; pmods[ i ] != NULL; ++i ) { + if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 && + pmods[ i ]->mod_op == modop ) { + break; + } + } + } + + if ( pmods == NULL || pmods[ i ] == NULL ) { + if (( pmods = (LDAPMod **)safe_realloc( pmods, (i + 2) * + sizeof( LDAPMod * ))) == NULL ) { + perror( "safe_realloc" ); + exit( 1 ); + } + *pmodsp = pmods; + pmods[ i + 1 ] = NULL; + if (( pmods[ i ] = (LDAPMod *)calloc( 1, sizeof( LDAPMod ))) + == NULL ) { + perror( "calloc" ); + exit( 1 ); + } + pmods[ i ]->mod_op = modop; + if (( pmods[ i ]->mod_type = strdup( attr )) == NULL ) { + perror( "strdup" ); + exit( 1 ); + } + } + + if ( value != NULL ) { + j = 0; + if ( pmods[ i ]->mod_bvalues != NULL ) { + for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) { + ; + } + } + if (( pmods[ i ]->mod_bvalues = + (struct berval **)safe_realloc( pmods[ i ]->mod_bvalues, + (j + 2) * sizeof( struct berval * ))) == NULL ) { + perror( "safe_realloc" ); + exit( 1 ); + } + pmods[ i ]->mod_bvalues[ j + 1 ] = NULL; + if (( bvp = (struct berval *)malloc( sizeof( struct berval ))) + == NULL ) { + perror( "malloc" ); + exit( 1 ); + } + pmods[ i ]->mod_bvalues[ j ] = bvp; + + bvp->bv_len = vlen; + if (( bvp->bv_val = (char *)malloc( vlen + 1 )) == NULL ) { + perror( "malloc" ); + exit( 1 ); + } + SAFEMEMCPY( bvp->bv_val, value, vlen ); + bvp->bv_val[ vlen ] = '\0'; + } +} + + +static char * +get_add_entry( char *filename, LDAPMod ***mods ) +{ + FILE *fp; + char *entry = NULL; + + if ( fp = fopen( filename, "r" )) { + char line[BUFSIZ]; + + if ( fgets( line, BUFSIZ, fp )) { + char *nl; + + if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) + *nl = '\0'; + entry = strdup( line ); + + } + + while ( fgets( line, BUFSIZ, fp )) { + char *nl; + char *value; + + if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) + *nl = '\0'; + + if ( *line == '\0' ) break; + if ( !( value = strchr( line, ':' ))) break; + + *value++ = '\0'; + while ( *value && isblank( *value )) value++; + + addmodifyop( mods, LDAP_MOD_ADD, line, value, strlen( value )); + + } + fclose( fp ); + } + + return( entry ); +} + + +static void +do_addel( + char *host, + int port, + char *manager, + char *passwd, + char *entry, + LDAPMod **attrs, + int maxloop +) +{ + LDAP *ld; + int i; + + if (( ld = ldap_init( host, port )) == NULL ) { + perror( "ldap_init" ); + exit( 1 ); + } + + if ( ldap_bind_s( ld, manager, passwd, LDAP_AUTH_SIMPLE ) + != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_bind" ); + exit( 1 ); + } + + + fprintf( stderr, "Add/Delete(%d): entry=\"%s\".\n", maxloop, entry ); + + for ( i = 0; i < maxloop; i++ ) { + + /* add the entry */ + if ( ldap_add_s( ld, entry, attrs ) != LDAP_SUCCESS ) { + + ldap_perror( ld, "ldap_add" ); + break; + + } + + /* wait a second for the add to really complete */ + sleep( 1 ); + + /* now delete the entry again */ + if ( ldap_delete_s( ld, entry ) != LDAP_SUCCESS ) { + + ldap_perror( ld, "ldap_delete" ); + break; + + } + + } + + ldap_unbind( ld ); +} + + diff --git a/tests/slapd-read.c b/tests/slapd-read.c new file mode 100644 index 0000000000..da7c9df22c --- /dev/null +++ b/tests/slapd-read.c @@ -0,0 +1,117 @@ +#include "portable.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "lber.h" +#include "ldap.h" + +#define LOOPS 100 + +static void +do_read( char *host, int port, char *entry, int maxloop ); + +static void +usage( char *name ) +{ + fprintf( stderr, "usage: %s [-h ] -p port -e [-l ]\n", + name ); + exit( 1 ); +} + +int +main( int argc, char **argv ) +{ + int i, j; + char *host = "localhost"; + int port = -1; + char *entry = NULL; + int loops = LOOPS; + + while ( (i = getopt( argc, argv, "h:p:e:l:" )) != EOF ) { + switch( i ) { + case 'h': /* the servers host */ + host = strdup( optarg ); + break; + + case 'p': /* the servers port */ + port = atoi( optarg ); + break; + + case 'e': /* file with entry search request */ + entry = strdup( optarg ); + break; + + case 'l': /* the number of loops */ + loops = atoi( optarg ); + break; + + default: + usage( argv[0] ); + break; + } + } + + if (( entry == NULL ) || ( port == -1 )) + usage( argv[0] ); + + if ( *entry == '\0' ) { + + fprintf( stderr, "%s: invalid EMPTY entry DN.\n", + argv[0] ); + exit( 1 ); + + } + + do_read( host, port, entry, loops ); + + exit( 0 ); +} + + +static void +do_read( char *host, int port, char *entry, int maxloop ) +{ + LDAP *ld; + int i; + char *attrs[] = { "cn", "sn", NULL }; + char *filter = "(objectclass=*)"; + + if (( ld = ldap_init( host, port )) == NULL ) { + perror( "ldap_init" ); + exit( 1 ); + } + + if ( ldap_bind_s( ld, NULL, NULL, LDAP_AUTH_SIMPLE ) != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_bind" ); + exit( 1 ); + } + + + fprintf( stderr, "Read(%d): entry=\"%s\".\n", maxloop, entry ); + + for ( i = 0; i < maxloop; i++ ) { + LDAPMessage *res; + + if ( ldap_search_s( ld, entry, LDAP_SCOPE_BASE, + filter, attrs, 0, &res ) != LDAP_SUCCESS ) { + + ldap_perror( ld, "ldap_read" ); + break; + + } + + ldap_msgfree( res ); + } + + ldap_unbind( ld ); +} + + diff --git a/tests/slapd-search.c b/tests/slapd-search.c new file mode 100644 index 0000000000..559e3bca2b --- /dev/null +++ b/tests/slapd-search.c @@ -0,0 +1,122 @@ +#include "portable.h" + +#include + +#include +#include +#include +#include +#include + +#include + +#include "lber.h" +#include "ldap.h" + +#define LOOPS 100 + +static void +do_search( char *host, int port, char *sbase, char *filter, int maxloop ); + +static void +usage( char *name ) +{ + fprintf( stderr, "usage: %s [-h ] -p port -b -f [-l ]\n", + name ); + exit( 1 ); +} + +int +main( int argc, char **argv ) +{ + int i, j; + char *host = "localhost"; + int port = -1; + char *sbase = NULL; + char *filter = NULL; + int loops = LOOPS; + + while ( (i = getopt( argc, argv, "h:p:b:f:l:" )) != EOF ) { + switch( i ) { + case 'h': /* the servers host */ + host = strdup( optarg ); + break; + + case 'p': /* the servers port */ + port = atoi( optarg ); + break; + + case 'b': /* file with search base */ + sbase = strdup( optarg ); + break; + + case 'f': /* the search request */ + filter = strdup( optarg ); + break; + + case 'l': /* number of loops */ + loops = atoi( optarg ); + break; + + default: + usage( argv[0] ); + break; + } + } + + if (( sbase == NULL ) || ( filter == NULL ) || ( port == -1 )) + usage( argv[0] ); + + if ( *filter == '\0' ) { + + fprintf( stderr, "%s: invalid EMPTY search filter.\n", + argv[0] ); + exit( 1 ); + + } + + do_search( host, port, sbase, filter, loops ); + + exit( 0 ); +} + + +static void +do_search( char *host, int port, char *sbase, char *filter, int maxloop ) +{ + LDAP *ld; + int i; + char *attrs[] = { "cn", "sn", NULL }; + + if (( ld = ldap_init( host, port )) == NULL ) { + perror( "ldap_init" ); + exit( 1 ); + } + + if ( ldap_bind_s( ld, NULL, NULL, LDAP_AUTH_SIMPLE ) != LDAP_SUCCESS ) { + ldap_perror( ld, "ldap_bind" ); + exit( 1 ); + } + + + fprintf( stderr, "Search(%d): base=\"%s\", filter=\"%s\".\n", + maxloop, sbase, filter ); + + for ( i = 0; i < maxloop; i++ ) { + LDAPMessage *res; + + if ( ldap_search_s( ld, sbase, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, &res ) != LDAP_SUCCESS ) { + + ldap_perror( ld, "ldap_search" ); + break; + + } + + ldap_msgfree( res ); + } + + ldap_unbind( ld ); +} + + diff --git a/tests/slapd-tester.c b/tests/slapd-tester.c new file mode 100644 index 0000000000..5bf9d4ed20 --- /dev/null +++ b/tests/slapd-tester.c @@ -0,0 +1,352 @@ +#include "portable.h" + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "ldapconfig.h" + + +#define SEARCHCMD "slapd-search" +#define READCMD "slapd-read" +#define ADDCMD "slapd-addel" +#define MAXARGS 100 +#define MAXREQS 20 +#define LOOPS "100" + +#define TSEARCHFILE "do_search.0" +#define TREADFILE "do_read.0" +#define TADDFILE "do_add." + +static char *get_file_name( char *dirname, char *filename ); +static int get_search_filters( char *filename, char *filters[] ); +static int get_read_entries( char *filename, char *entries[] ); +static void fork_child( char *prog, char *args[] ); +static void wait4kids( int nkidval ); + +static int maxkids = 20; +static int nkids; + +static void +usage( char *name ) +{ + fprintf( stderr, "usage: %s [-h ] -p -D -w -d -b [-j ] [-l ]\n", name ); + exit( 1 ); +} + +int +main( int argc, char **argv ) +{ + int i, j; + char *host = "localhost"; + char *port = NULL; + char *manager = NULL; + char *passwd = NULL; + char *dirname = NULL; + char *sbase = NULL; + char *loops = LOOPS; + DIR *datadir; + struct dirent *file; + char *sfile = NULL; + char *sreqs[MAXREQS]; + int snum = 0; + char *rfile = NULL; + char *rreqs[MAXREQS]; + int rnum = 0; + char *afiles[MAXREQS]; + int anum = 0; + char *sargs[MAXARGS]; + int sanum; + char scmd[MAXPATHLEN]; + char *rargs[MAXARGS]; + int ranum; + char rcmd[MAXPATHLEN]; + char *aargs[MAXARGS]; + int aanum; + char acmd[MAXPATHLEN]; + + while ( (i = getopt( argc, argv, "h:p:D:w:b:d:j:l:" )) != EOF ) { + switch( i ) { + case 'h': /* slapd host */ + host = strdup( optarg ); + break; + + case 'p': /* the servers port number */ + port = strdup( optarg ); + break; + + case 'D': /* slapd manager */ + manager = strdup( optarg ); + break; + + case 'w': /* the managers passwd */ + passwd = strdup( optarg ); + break; + + case 'b': /* the base DN */ + sbase = strdup( optarg ); + break; + + case 'd': /* data directory */ + dirname = strdup( optarg ); + break; + + case 'j': /* the number of parallel clients */ + maxkids = atoi( optarg ); + break; + + case 'l': /* the number of loops per client */ + loops = strdup( optarg ); + break; + + default: + usage( argv[0] ); + break; + } + } + + if (( dirname == NULL ) || ( sbase == NULL ) || ( port == NULL ) || + ( manager == NULL ) || ( passwd == NULL )) + usage( argv[0] ); + + /* get the file list */ + if ( ( datadir = opendir( dirname )) == NULL ) { + + fprintf( stderr, "%s: couldn't open data directory \"%s\".\n", + argv[0], dirname ); + exit( 1 ); + + } + + /* look for search, read, and add/delete files */ + for ( file = readdir( datadir ); file; file = readdir( datadir )) { + + if ( !strcasecmp( file->d_name, TSEARCHFILE )) { + sfile = get_file_name( dirname, file->d_name ); + continue; + } else if ( !strcasecmp( file->d_name, TREADFILE )) { + rfile = get_file_name( dirname, file->d_name ); + continue; + } else if ( !strncasecmp( file->d_name, TADDFILE, strlen( TADDFILE )) + && ( anum < MAXREQS )) { + afiles[anum++] = get_file_name( dirname, file->d_name ); + continue; + } + } + + /* look for search requests */ + if ( sfile ) { + snum = get_search_filters( sfile, sreqs ); + } + + /* look for read requests */ + if ( rfile ) { + rnum = get_read_entries( rfile, rreqs ); + } + + /* + * generate the search clients + */ + + sanum = 0; + sprintf( scmd, "%s", SEARCHCMD ); + sargs[sanum++] = scmd; + sargs[sanum++] = "-h"; + sargs[sanum++] = host; + sargs[sanum++] = "-p"; + sargs[sanum++] = port; + sargs[sanum++] = "-b"; + sargs[sanum++] = sbase; + sargs[sanum++] = "-l"; + sargs[sanum++] = loops; + sargs[sanum++] = "-f"; + sargs[sanum++] = NULL; /* will hold the search request */ + sargs[sanum++] = NULL; + + /* + * generate the read clients + */ + + ranum = 0; + sprintf( rcmd, "%s", READCMD ); + rargs[ranum++] = rcmd; + rargs[ranum++] = "-h"; + rargs[ranum++] = host; + rargs[ranum++] = "-p"; + rargs[ranum++] = port; + rargs[ranum++] = "-l"; + rargs[ranum++] = loops; + rargs[ranum++] = "-e"; + rargs[ranum++] = NULL; /* will hold the read entry */ + rargs[ranum++] = NULL; + + /* + * generate the add/delete clients + */ + + aanum = 0; + sprintf( acmd, "%s", ADDCMD ); + aargs[aanum++] = acmd; + aargs[aanum++] = "-h"; + aargs[aanum++] = host; + aargs[aanum++] = "-p"; + aargs[aanum++] = port; + aargs[aanum++] = "-D"; + aargs[aanum++] = manager; + aargs[aanum++] = "-w"; + aargs[aanum++] = passwd; + aargs[aanum++] = "-l"; + aargs[aanum++] = loops; + aargs[aanum++] = "-f"; + aargs[aanum++] = NULL; /* will hold the add data file */ + aargs[aanum++] = NULL; + + for ( j = 0; j < MAXREQS; j++ ) { + + if ( j < snum ) { + + sargs[sanum - 2] = sreqs[j]; + fork_child( scmd, sargs ); + + } + + if ( j < rnum ) { + + rargs[ranum - 2] = rreqs[j]; + fork_child( rcmd, rargs ); + + } + + if ( j < anum ) { + + aargs[aanum - 2] = afiles[j]; + fork_child( acmd, aargs ); + + } + + } + + wait4kids( -1 ); + + exit( 0 ); +} + +static char * +get_file_name( char *dirname, char *filename ) +{ + char buf[MAXPATHLEN]; + + sprintf( buf, "%s%s%s", dirname, DEFAULT_DIRSEP, filename ); + return( strdup( buf )); +} + + +static int +get_search_filters( char *filename, char *filters[] ) +{ + FILE *fp; + int filter = 0; + + if ( fp = fopen( filename, "r" )) { + char line[BUFSIZ]; + + while (( filter < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) { + char *nl; + + if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) + *nl = '\0'; + filters[filter++] = strdup( line ); + + } + fclose( fp ); + } + + return( filter ); +} + + +static int +get_read_entries( char *filename, char *entries[] ) +{ + FILE *fp; + int entry = 0; + + if ( fp = fopen( filename, "r" )) { + char line[BUFSIZ]; + + while (( entry < MAXREQS ) && ( fgets( line, BUFSIZ, fp ))) { + char *nl; + + if (( nl = strchr( line, '\r' )) || ( nl = strchr( line, '\n' ))) + *nl = '\0'; + entries[entry++] = strdup( line ); + + } + fclose( fp ); + } + + return( entry ); +} + + +static void +fork_child( char *prog, char *args[] ) +{ + int status, pid; + + wait4kids( maxkids ); + + switch ( pid = fork() ) { + case 0: /* child */ + execvp( prog, args ); + fprintf( stderr, "%s: ", prog ); + perror( "execv" ); + exit( -1 ); + break; + + case -1: /* trouble */ + fprintf( stderr, "Could not fork to run %s\n", prog ); + perror( "fork" ); + break; + + default: /* parent */ + nkids++; + break; + } +} + +static void +wait4kids( int nkidval ) +{ + int status; + unsigned char *p; + + while ( nkids >= nkidval ) { + wait( &status ); + p = (unsigned char *) &status; + if ( p[sizeof(int) - 1] == 0177 ) { + fprintf( stderr, + "stopping: child stopped with signal %d\n", + p[sizeof(int) - 2] ); + } else if ( p[sizeof(int) - 1] != 0 ) { + fprintf( stderr, + "stopping: child terminated with signal %d\n", + p[sizeof(int) - 1] ); + exit( p[sizeof(int) - 1] ); + } else if ( p[sizeof(int) - 2] != 0 ) { + fprintf( stderr, + "stopping: child exited with status %d\n", + p[sizeof(int) - 2] ); + exit( p[sizeof(int) - 2] ); + } else { + nkids--; + } + } +} -- 2.39.5