From bf2b88f0fc81b3c87bdd387d7f9d91d7affb6a6d Mon Sep 17 00:00:00 2001 From: Howard Chu Date: Wed, 23 Sep 2020 14:58:37 +0100 Subject: [PATCH] ITS#9354 cleanup watcher After initial contact, don't exit if a server goes down. Also, don't wait forever for responses, use a timeout and mention when a timeout occurs. Simplify csn/sid handling, we know the max we expect so just allocate the space in advance and keep a fixed sid to slot mapping. --- tests/progs/slapd-common.c | 4 +- tests/progs/slapd-common.h | 1 + tests/progs/slapd-watcher.c | 598 ++++++++++++++++++++---------------- 3 files changed, 345 insertions(+), 258 deletions(-) diff --git a/tests/progs/slapd-common.c b/tests/progs/slapd-common.c index 535cd5fb1b..42701ac0d4 100644 --- a/tests/progs/slapd-common.c +++ b/tests/progs/slapd-common.c @@ -554,7 +554,9 @@ retry:; } } ldap_unbind_ext( ld, NULL, NULL ); - exit( EXIT_FAILURE ); + ld = NULL; + if ( !( flags & TESTER_INIT_NOEXIT )) + exit( EXIT_FAILURE ); } } diff --git a/tests/progs/slapd-common.h b/tests/progs/slapd-common.h index 33d2b3e965..8a0b5de709 100644 --- a/tests/progs/slapd-common.h +++ b/tests/progs/slapd-common.h @@ -66,6 +66,7 @@ struct tester_conn_args { }; #define TESTER_INIT_ONLY (1 << 0) +#define TESTER_INIT_NOEXIT (1 << 1) #define TESTER_COMMON_OPTS "CD:d:H:h:L:l:i:O:p:R:U:X:Y:r:t:w:x" #define TESTER_COMMON_HELP \ "[-C] " \ diff --git a/tests/progs/slapd-watcher.c b/tests/progs/slapd-watcher.c index 0f0ec37bf3..d1b0d8c532 100644 --- a/tests/progs/slapd-watcher.c +++ b/tests/progs/slapd-watcher.c @@ -40,14 +40,21 @@ #include "slapd-common.h" +#define SLAP_SYNC_SID_MAX 4095 + #define HAS_MONITOR 1 #define HAS_BASE 2 #define HAS_ENTRIES 4 #define HAS_SREPL 8 +#define HAS_ALL (HAS_MONITOR|HAS_BASE|HAS_ENTRIES|HAS_SREPL) + + +#define WAS_LATE 0x100 +#define WAS_DOWN 0x200 #define MONFILTER "(objectClass=monitorOperation)" -#define SLAP_SYNC_SID_MAX 4095 +static const char *default_monfilter = MONFILTER; typedef enum { SLAP_OP_BIND = 0, @@ -87,8 +94,6 @@ typedef struct counters { } counters; typedef struct csns { - int num; - int *sids; struct berval *vals; struct timeval *tvs; } csns; @@ -107,6 +112,8 @@ typedef struct server { int sid; struct berval monitorbase; char *monitorfilter; + time_t late; + time_t down; counters c_prev; counters c_curr; csns csn_prev; @@ -166,6 +173,26 @@ void deltat(time_t *tt) static char *clearscreen = "\033[H\033[2J"; +void rotate_stats( server *sv ) +{ + if ( sv->flags & HAS_MONITOR ) + sv->c_prev = sv->c_curr; + if ( sv->flags & HAS_BASE ) { + int i; + + for (i=0; icsn_curr.vals[i].bv_len ) { + ber_bvreplace(&sv->csn_prev.vals[i], + &sv->csn_curr.vals[i]); + sv->csn_prev.tvs[i] = sv->csn_curr.tvs[i]; + } else { + if ( sv->csn_prev.vals[i].bv_val ) + sv->csn_prev.vals[i].bv_val[0] = '\0'; + } + } + } +} + void display() { int i, j; @@ -180,9 +207,19 @@ void display() printf("\n"); for (i=0; i servers[i].times[j].maxlag) - servers[i].times[j].maxlag = deltatt; - } else { - servers[i].times[j].lag = 0; - printf(", sync'd"); - } - if (servers[i].times[j].maxlag) { - printf(", max delta "); - deltat( &servers[i].times[j].maxlag ); - } - } - } + if (i != j) { + if (ber_bvcmp(&servers[i].csn_curr.vals[j], + &servers[j].csn_curr.vals[j])) { + struct timeval delta; + int ahead = 0; + time_t deltatt; + delta.tv_sec = servers[j].csn_curr.tvs[j].tv_sec - + servers[i].csn_curr.tvs[j].tv_sec; + delta.tv_usec = servers[j].csn_curr.tvs[j].tv_usec - + servers[i].csn_curr.tvs[j].tv_usec; + if (delta.tv_usec < 0) { + delta.tv_usec += 1000000; + delta.tv_sec--; } + if (delta.tv_sec < 0) { + delta.tv_sec = -delta.tv_sec; + ahead = 1; + } + deltatt = delta.tv_sec; + if (ahead) + printf(", ahead "); + else + printf(", behind "); + deltat( &deltatt ); + servers[i].times[j].lag = deltatt; + if (deltatt > servers[i].times[j].maxlag) + servers[i].times[j].maxlag = deltatt; + } else { + servers[i].times[j].lag = 0; + printf(", sync'd"); + } + if (servers[i].times[j].maxlag) { + printf(", max delta "); + deltat( &servers[i].times[j].maxlag ); } } printf("\n"); } - if ( servers[i].csn_prev.num != servers[i].csn_curr.num ) { - servers[i].csn_prev.sids = realloc(servers[i].csn_prev.sids, - servers[i].csn_curr.num * sizeof(int)); - servers[i].csn_prev.vals = realloc(servers[i].csn_prev.vals, - servers[i].csn_curr.num * sizeof(struct berval)); - servers[i].csn_prev.tvs = realloc(servers[i].csn_prev.tvs, - servers[i].csn_curr.num * sizeof(struct timeval)); - for (j=servers[i].csn_prev.num; j < servers[i].csn_curr.num; j++) { - BER_BVZERO( &servers[i].csn_prev.vals[j] ); - } - servers[i].csn_prev.num = servers[i].csn_curr.num; - for (j=0; jnum != i ) { - int j; - c->vals = realloc( c->vals, i*sizeof(struct berval)); - c->sids = realloc( c->sids, i*sizeof(int)); - c->tvs = realloc( c->tvs, i*sizeof(struct timeval)); - for (j=c->num; jvals[j] ); - } - } - c->num = i; - for (i=0; inum; i++) { + /* clear old values if any */ + for (i=0; ivals[i].bv_val ) + c->vals[i].bv_val[0] = '\0'; + + for (i=0; bvs[i].bv_val; i++) { struct lutil_tm tm; struct lutil_timet tt; - ber_bvreplace( &c->vals[i], &bvs[i] ); - c->sids[i] = slap_parse_csn_sid( &bvs[i] ); - lutil_parsetime(c->vals[i].bv_val, &tm); - c->tvs[i].tv_usec = tm.tm_usec; - lutil_tm2time( &tm, &tt ); - c->tvs[i].tv_sec = tt.tt_sec; + int sid = slap_parse_csn_sid( &bvs[i] ); + for (j=0; jvals[j], &bvs[i] ); + lutil_parsetime(bvs[i].bv_val, &tm); + c->tvs[j].tv_usec = tm.tm_usec; + lutil_tm2time( &tm, &tt ); + c->tvs[j].tv_sec = tt.tt_sec; + } } } +int +setup_server( struct tester_conn_args *config, server *sv, int first ) +{ + config->uri = sv->url; + tester_init_ld( &sv->ld, config, first ? 0 : TESTER_INIT_NOEXIT ); + if ( !sv->ld ) + return -1; + + sv->flags &= ~HAS_ALL; + { + char *attrs[] = { at_namingContexts.bv_val, at_monitorOpCompleted.bv_val, + at_olmMDBEntries.bv_val, NULL }; + LDAPMessage *res = NULL, *e = NULL; + BerElement *ber = NULL; + LDAP *ld = sv->ld; + struct berval dn, bv, *bvals, **bvp = &bvals; + int j, rc; + + rc = ldap_search_ext_s( ld, "cn=monitor", LDAP_SCOPE_SUBTREE, monfilter, + attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); + switch(rc) { + case LDAP_SIZELIMIT_EXCEEDED: + case LDAP_TIMELIMIT_EXCEEDED: + case LDAP_SUCCESS: + gettimeofday( &sv->c_curr.time, 0 ); + sv->flags |= HAS_MONITOR; + for ( e = ldap_first_entry( ld, res ); e; e = ldap_next_entry( ld, e )) { + ldap_get_dn_ber( ld, e, &ber, &dn ); + if ( !strncasecmp( dn.bv_val, "cn=Database", sizeof("cn=Database")-1 ) || + !strncasecmp( dn.bv_val, "cn=Frontend", sizeof("cn=Frontend")-1 )) { + int matched = 0; + for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { + if ( bv.bv_val == NULL ) break; + if (!ber_bvcmp( &bv, &at_namingContexts ) && bvals ) { + for (j=0; bvals[j].bv_val; j++) { + if ( !ber_bvstrcasecmp( &base, &bvals[j] )) { + matched = 1; + break; + } + } + if (!matched) { + ber_memfree( bvals ); + bvals = NULL; + break; + } + } + if (!ber_bvcmp( &bv, &at_olmMDBEntries )) { + ber_bvreplace( &sv->monitorbase, &dn ); + sv->flags |= HAS_ENTRIES; + sv->c_curr.entries = strtoul( bvals[0].bv_val, NULL, 0 ); + } + ber_memfree( bvals ); + bvals = NULL; + } + } else if (!strncasecmp( dn.bv_val, opnames[0].rdn.bv_val, + opnames[0].rdn.bv_len )) { + get_counters( ld, e, ber, &sv->c_curr ); + break; + } + if ( ber ) + ber_free( ber, 0 ); + } + break; + + case LDAP_NO_SUCH_OBJECT: + /* no cn=monitor */ + break; + + default: + tester_ldap_error( ld, "ldap_search_ext_s(cn=Monitor)", sv->url ); + if ( first ) + exit( EXIT_FAILURE ); + } + ldap_msgfree( res ); + + if ( base.bv_val ) { + char *attr2[] = { at_contextCSN.bv_val, NULL }; + rc = ldap_search_ext_s( ld, base.bv_val, LDAP_SCOPE_BASE, "(objectClass=*)", + attr2, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); + switch(rc) { + case LDAP_SUCCESS: + e = ldap_first_entry( ld, res ); + if ( e ) { + sv->flags |= HAS_BASE; + ldap_get_dn_ber( ld, e, &ber, &dn ); + for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); + rc == LDAP_SUCCESS; + rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { + int done = 0; + if ( bv.bv_val == NULL ) break; + if ( bvals ) { + if ( !ber_bvcmp( &bv, &at_contextCSN )) { + get_csns( &sv->csn_curr, bvals ); + done = 1; + } + ber_memfree( bvals ); + bvals = NULL; + if ( done ) + break; + } + } + } + ldap_msgfree( res ); + break; + + default: + tester_ldap_error( ld, "ldap_search_ext_s(baseDN)", sv->url ); + if ( first ) + exit( EXIT_FAILURE ); + } + } + } + + if ( sv->monitorfilter != default_monfilter ) + free( sv->monitorfilter ); + if ( sv->flags & HAS_ENTRIES ) { + int len = sv->monitorbase.bv_len + sizeof("(|(entryDN=)" MONFILTER ")"); + char *ptr = malloc(len); + sprintf(ptr, "(|(entryDN=%s)" MONFILTER ")", sv->monitorbase.bv_val ); + sv->monitorfilter = ptr; + } else if ( sv->flags & HAS_MONITOR ) { + sv->monitorfilter = (char *)default_monfilter; + } + if ( first ) + rotate_stats( sv ); +} + int main( int argc, char **argv ) { int i, rc, *msg1, *msg2; char **sids = NULL; struct tester_conn_args *config; + int first = 1; config = tester_init( "slapd-watcher", TESTER_TESTER ); config->authmethod = LDAP_AUTH_SIMPLE; @@ -485,183 +630,107 @@ main( int argc, char **argv ) } for ( i = 0; i < numservers; i++ ) { - int version = LDAP_VERSION3; servers[i].url = argv[i]; - config->uri = argv[i]; - tester_init_ld( &servers[i].ld, config, 0 ); - servers[i].flags = 0; - { - char *attrs[] = { at_namingContexts.bv_val, at_monitorOpCompleted.bv_val, - at_olmMDBEntries.bv_val, NULL }; - LDAPMessage *res = NULL, *e = NULL; - BerElement *ber = NULL; - LDAP *ld = servers[i].ld; - struct berval dn, bv, *bvals, **bvp = &bvals; - int j; - - rc = ldap_search_ext_s( ld, "cn=monitor", LDAP_SCOPE_SUBTREE, monfilter, - attrs, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); - switch(rc) { - case LDAP_SIZELIMIT_EXCEEDED: - case LDAP_TIMELIMIT_EXCEEDED: - case LDAP_SUCCESS: - gettimeofday( &servers[i].c_curr.time, 0 ); - servers[i].flags |= HAS_MONITOR; - for ( e = ldap_first_entry( ld, res ); e; e = ldap_next_entry( ld, e )) { - ldap_get_dn_ber( ld, e, &ber, &dn ); - if ( !strncasecmp( dn.bv_val, "cn=Database", sizeof("cn=Database")-1 ) || - !strncasecmp( dn.bv_val, "cn=Frontend", sizeof("cn=Frontend")-1 )) { - int matched = 0; - for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); - rc == LDAP_SUCCESS; - rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { - if ( bv.bv_val == NULL ) break; - if (!ber_bvcmp( &bv, &at_namingContexts ) && bvals ) { - for (j=0; bvals[j].bv_val; j++) { - if ( !ber_bvstrcasecmp( &base, &bvals[j] )) { - matched = 1; - break; - } - } - if (!matched) { - ber_memfree( bvals ); - bvals = NULL; - break; - } - } - if (!ber_bvcmp( &bv, &at_olmMDBEntries )) { - ber_dupbv( &servers[i].monitorbase, &dn ); - servers[i].flags |= HAS_ENTRIES; - servers[i].c_curr.entries = strtoul( bvals[0].bv_val, NULL, 0 ); - } - ber_memfree( bvals ); - bvals = NULL; - } - } else if (!strncasecmp( dn.bv_val, opnames[0].rdn.bv_val, - opnames[0].rdn.bv_len )) { - get_counters( ld, e, ber, &servers[i].c_curr ); - break; - } - if ( ber ) - ber_free( ber, 0 ); - } - break; - - case LDAP_NO_SUCH_OBJECT: - /* no cn=monitor */ - break; - - default: - tester_ldap_error( ld, "ldap_search_ext_s(cn=Monitor)", NULL ); - exit( EXIT_FAILURE ); - } - ldap_msgfree( res ); - if ( base.bv_val ) { - char *attr2[] = { at_contextCSN.bv_val, NULL }; - rc = ldap_search_ext_s( ld, base.bv_val, LDAP_SCOPE_BASE, "(objectClass=*)", - attr2, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &res ); - switch(rc) { - case LDAP_SUCCESS: - e = ldap_first_entry( ld, res ); - if ( e ) { - servers[i].flags |= HAS_BASE; - ldap_get_dn_ber( ld, e, &ber, &dn ); - for ( rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp ); - rc == LDAP_SUCCESS; - rc = ldap_get_attribute_ber( ld, e, ber, &bv, bvp )) { - int done = 0; - if ( bv.bv_val == NULL ) break; - if ( bvals ) { - if ( !ber_bvcmp( &bv, &at_contextCSN )) { - get_csns( &servers[i].csn_curr, bvals ); - done = 1; - } - ber_memfree( bvals ); - bvals = NULL; - if ( done ) - break; - } - } - } - ldap_msgfree( res ); - break; - - default: - tester_ldap_error( ld, "ldap_search_ext_s(baseDN)", NULL ); - exit( EXIT_FAILURE ); - } - } - } - } - - for (i=0; i