diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 960b4a99af14f0c608dd4c8a1932ff1ba614d9b2..2d5dd98866506ac487c9f68b1f0b08a8fde64c2d 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -501,6 +501,103 @@ ldap_sync_search( return rc; } +static int +merge_state( syncinfo_t *si ) +{ + int i, j = 0, k, numcsns = 0, alloc = 0, changed = 0; + BerVarray new_ctxcsn = si->si_syncCookie.ctxcsn; + int *new_sids = NULL; + + /* Count and set up sids */ + for ( i=0; i < si->si_cookieState->cs_num; i++ ) { + if ( si->si_cookieState->cs_sids[i] == -1 ) { + continue; + } + + for ( ; j < si->si_syncCookie.numcsns && + si->si_syncCookie.sids[j] == -1; + j++ ) + alloc = 1; /* Just skip over them */ + + for ( ; j < si->si_syncCookie.numcsns && + si->si_syncCookie.sids[j] < si->si_cookieState->cs_sids[i]; + j++ ) { + if ( si->si_syncCookie.sids[j] != -1 ) { + new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) ); + new_sids[numcsns++] = si->si_syncCookie.sids[j]; + } + } + + if ( j < si->si_syncCookie.numcsns && + si->si_syncCookie.sids[j] == si->si_cookieState->cs_sids[i] ) j++; + + new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) ); + new_sids[numcsns++] = si->si_cookieState->cs_sids[i]; + } + + for ( ; j < si->si_syncCookie.numcsns; j++ ) { + if ( si->si_syncCookie.sids[j] != -1 ) { + new_sids = ch_realloc( new_sids, (numcsns+1)*sizeof(int) ); + new_sids[numcsns++] = si->si_syncCookie.sids[j]; + } + } + + if ( alloc || numcsns != si->si_syncCookie.numcsns ) { + /* Short circuit allocations if we don't need to start over */ + alloc = 1; + new_ctxcsn = ch_calloc( numcsns + 1, sizeof( BerValue ) ); + } + + i = j = 0; + for ( k=0; k < numcsns; k++ ) { + while ( i < si->si_cookieState->cs_num && + si->si_cookieState->cs_sids[i] < new_sids[k] ) + i++; + + while ( j < si->si_syncCookie.numcsns && + si->si_syncCookie.sids[j] < new_sids[k] ) + j++; + + if ( j < si->si_syncCookie.numcsns && + si->si_cookieState->cs_sids[i] == si->si_syncCookie.sids[j] ) { + assert( si->si_cookieState->cs_sids[i] == new_sids[k] ); + if ( !bvmatch( &si->si_syncCookie.ctxcsn[j], + &si->si_cookieState->cs_vals[i] )) { + ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] ); + changed = 1; + } else if ( alloc ) { + ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] ); + } + i++; + j++; + } else if ( si->si_cookieState->cs_sids[i] == new_sids[k] ) { + changed = 1; + ber_bvreplace( &new_ctxcsn[k], &si->si_cookieState->cs_vals[i] ); + i++; + } else { + if ( alloc ) { + ber_dupbv( &new_ctxcsn[k], &si->si_syncCookie.ctxcsn[j] ); + } + j++; + } + } + assert( i == si->si_cookieState->cs_num ); + assert( j == si->si_syncCookie.numcsns ); + + si->si_syncCookie.numcsns = numcsns; + if ( alloc ) { + changed = 1; + ch_free( si->si_syncCookie.sids ); + si->si_syncCookie.sids = new_sids; + + ber_bvarray_free( si->si_syncCookie.ctxcsn ); + si->si_syncCookie.ctxcsn = new_ctxcsn; + } else { + ch_free( new_sids ); + } + return changed; +} + static int check_syncprov( Operation *op, @@ -571,29 +668,8 @@ check_syncprov( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, si->si_cookieState->cs_vals, NULL ); changed = 1; - } else { - for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) { - /* bogus, just dup everything */ - if ( si->si_syncCookie.sids[i] == -1 ) { - ber_bvarray_free( si->si_syncCookie.ctxcsn ); - ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn, - si->si_cookieState->cs_vals, NULL ); - changed = 1; - break; - } - for (j=0; j<si->si_cookieState->cs_num; j++) { - if ( si->si_syncCookie.sids[i] != - si->si_cookieState->cs_sids[j] ) - continue; - if ( bvmatch( &si->si_syncCookie.ctxcsn[i], - &si->si_cookieState->cs_vals[j] )) - break; - ber_bvreplace( &si->si_syncCookie.ctxcsn[i], - &si->si_cookieState->cs_vals[j] ); - changed = 1; - break; - } - } + } else if ( merge_state( si ) ) { + changed = 1; } } if ( changed ) {