diff --git a/libraries/libldap_r/rq.c b/libraries/libldap_r/rq.c index b028054e33..194d16db8e 100644 --- a/libraries/libldap_r/rq.c +++ b/libraries/libldap_r/rq.c @@ -66,12 +66,11 @@ ldap_pvt_runqueue_remove( break; } - assert ( e == entry ); - - LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext ); + if ( e == entry ) { + LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext ); + } LDAP_FREE( entry ); - } struct re_s* @@ -148,7 +147,7 @@ ldap_pvt_runqueue_resched( LDAP_STAILQ_REMOVE( &rq->task_list, entry, re_s, tnext ); - if ( entry->interval.tv_sec && !defer ) { + if ( !defer ) { entry->next_sched.tv_sec = time( NULL ) + entry->interval.tv_sec; } else { entry->next_sched.tv_sec = 0; diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 7aceee21eb..b91b0979df 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -3028,6 +3028,9 @@ add_syncrepl( si->si_attrs[0] = NULL; si->si_type = LDAP_SYNC_REFRESH_ONLY; si->si_interval = 86400; + si->si_retryinterval = 0; + si->si_retrynum_init = 0; + si->si_retrynum = 0; si->si_syncCookie.ctxcsn = NULL; si->si_syncCookie.octet_str = NULL; si->si_syncCookie.sid = -1; @@ -3144,6 +3147,8 @@ add_syncrepl( #define SLIMITSTR "sizelimit" #define TLIMITSTR "timelimit" +#define RETRYSTR "retry" + #define GOT_ID 0x0001 #define GOT_PROVIDER 0x0002 #define GOT_METHOD 0x0004 @@ -3383,6 +3388,53 @@ parse_syncrepl_line( (long) si->si_interval); return 1; } + } else if ( !strncasecmp( cargv[ i ], + RETRYSTR, sizeof( RETRYSTR ) - 1 ) ) + { + char *str; + char **retry_list; + int j, k, n; + + val = cargv[ i ] + sizeof( RETRYSTR ); + retry_list = (char **) ch_calloc( 1, sizeof( char * )); + retry_list[0] = NULL; + + str2clist( &retry_list, val, " ,\t" ); + + for ( k = 0; retry_list && retry_list[k]; k++ ) ; + n = k / 2; + if ( k % 2 ) { + fprintf( stderr, + "Error: incomplete syncrepl retry list\n" ); + for ( k = 0; retry_list && retry_list[k]; k++ ) { + ch_free( retry_list[k] ); + } + ch_free( retry_list ); + exit( EXIT_FAILURE ); + } + si->si_retryinterval = (time_t *) ch_calloc( n + 1, sizeof( time_t )); + si->si_retrynum = (int *) ch_calloc( n + 1, sizeof( int )); + si->si_retrynum_init = (int *) ch_calloc( n + 1, sizeof( int )); + for ( j = 0; j < n; j++ ) { + si->si_retryinterval[j] = atoi( retry_list[j*2] ); + if ( *retry_list[j*2+1] == '+' ) { + si->si_retrynum_init[j] = -1; + si->si_retrynum[j] = -1; + j++; + break; + } else { + si->si_retrynum_init[j] = atoi( retry_list[j*2+1] ); + si->si_retrynum[j] = atoi( retry_list[j*2+1] ); + } + } + si->si_retrynum_init[j] = -2; + si->si_retrynum[j] = -2; + si->si_retryinterval[j] = 0; + + for ( k = 0; retry_list && retry_list[k]; k++ ) { + ch_free( retry_list[k] ); + } + ch_free( retry_list ); } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR, sizeof( MANAGEDSAITSTR ) - 1 ) ) { diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 293c3cb79c..e0330c07bb 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1407,6 +1407,9 @@ typedef struct syncinfo_s { char **si_attrs; int si_type; time_t si_interval; + time_t *si_retryinterval; + int *si_retrynum_init; + int *si_retrynum; struct sync_cookie si_syncCookie; int si_manageDSAit; int si_slimit; diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 5309636963..42a3456b89 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -823,6 +823,7 @@ do_syncrepl( int first = 0; int dostop = 0; ber_socket_t s; + int i, defer = 1; #ifdef NEW_LOGGING LDAP_LOG ( OPERATION, DETAIL1, "do_syncrepl\n", 0, 0, 0 ); @@ -885,7 +886,7 @@ do_syncrepl( arg ); } else { connection_client_enable( s ); - } + } } else if ( !first ) { dostop = 1; } @@ -901,25 +902,45 @@ do_syncrepl( * 4) for Persist and Success, reschedule to defer */ ldap_pvt_thread_mutex_lock( &syncrepl_rq.rq_mutex ); + if ( ldap_pvt_runqueue_isrunning( &syncrepl_rq, rtask )) { ldap_pvt_runqueue_stoptask( &syncrepl_rq, rtask ); } - if ( dostop ) { - connection_client_stop( s ); - } - - if ( rc && rc != LDAP_SERVER_DOWN ) { - ldap_pvt_runqueue_remove( &syncrepl_rq, rtask ); - } else { - if ( rc == LDAP_SERVER_DOWN || - si->si_type == LDAP_SYNC_REFRESH_ONLY ) { - rc = 0; - } else { - rc = 1; + if ( rc == LDAP_SUCCESS ) { + if ( dostop ) { + connection_client_stop( s ); + } + if ( si->si_type == LDAP_SYNC_REFRESH_ONLY ) { + defer = 0; + } + rtask->interval.tv_sec = si->si_interval; + ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, defer ); + if ( si->si_retrynum ) { + for ( i = 0; si->si_retrynum_init[i] != -2; i++ ) { + si->si_retrynum[i] = si->si_retrynum_init[i]; + } + si->si_retrynum[i] = -2; + } + } else { + for ( i = 0; si->si_retrynum && si->si_retrynum[i] <= 0; i++ ) { + if ( si->si_retrynum[i] == -1 || si->si_retrynum[i] == -2 ) + break; + } + + if ( !si->si_retrynum || si->si_retrynum[i] == -2 ) { + if ( dostop ) { + connection_client_stop( s ); + } + ldap_pvt_runqueue_remove( &syncrepl_rq, rtask ); + } else if ( si->si_retrynum[i] >= -1 ) { + if ( si->si_retrynum[i] > 0 ) + si->si_retrynum[i]--; + rtask->interval.tv_sec = si->si_retryinterval[i]; + ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, 0 ); } - ldap_pvt_runqueue_resched( &syncrepl_rq, rtask, rc ); } + ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex ); return NULL;