diff --git a/servers/slapd/ldapsync.c b/servers/slapd/ldapsync.c index 59334851d7..143b10233f 100644 --- a/servers/slapd/ldapsync.c +++ b/servers/slapd/ldapsync.c @@ -35,7 +35,8 @@ slap_compose_sync_cookie( Operation *op, struct berval *cookie, BerVarray csn, - int rid ) + int rid, + int sid ) { int len, numcsn = 0; @@ -51,6 +52,9 @@ slap_compose_sync_cookie( } else { len = snprintf( cookiestr, sizeof( cookiestr ), "rid=%03d", rid ); + if ( sid >= 0 ) { + len += sprintf( cookiestr+len, ",sid=%03x", sid ); + } } ber_str2bv_x( cookiestr, len, 1, cookie, op ? op->o_tmpmemctx : NULL ); @@ -63,10 +67,17 @@ slap_compose_sync_cookie( len += csn[i].bv_len + 1; len += STRLENOF("rid=123,csn="); + if ( sid >= 0 ) + len += STRLENOF("sid=xxx,"); + cookie->bv_val = slap_sl_malloc( len, op ? op->o_tmpmemctx : NULL ); - len = sprintf( cookie->bv_val, "rid=%03d,csn=", rid ); + len = sprintf( cookie->bv_val, "rid=%03d,", rid ); ptr = cookie->bv_val + len; + if ( sid >= 0 ) { + ptr += sprintf( ptr, "sid=%03x,", sid ); + } + ptr = lutil_strcopy( ptr, "csn=" ); for ( i=0; irid = -1; + cookie->sid = -1; cookie->ctxcsn = NULL; cookie->sids = NULL; cookie->numcsns = 0; @@ -181,6 +193,17 @@ slap_parse_sync_cookie( } continue; } + if ( !strncmp( next, "sid=", STRLENOF("sid=") )) { + rid_ptr = next; + cookie->sid = strtoul( &rid_ptr[ STRLENOF( "sid=" ) ], &next, 16 ); + if ( next == rid_ptr || next > end || *next != ',' ) { + return -1; + } + if ( *next == ',' ) { + next++; + } + continue; + } if ( !strncmp( next, "csn=", STRLENOF("csn=") )) { slap_syntax_validate_func *validate; struct berval stamp; @@ -258,6 +281,7 @@ slap_init_sync_cookie_ctxcsn( cookie->ctxcsn = NULL; value_add_one( &cookie->ctxcsn, &ctxcsn ); cookie->numcsns = 1; + cookie->sid = slap_serverID; return 0; } @@ -287,6 +311,7 @@ slap_dup_sync_cookie( } new->rid = src->rid; + new->sid = src->sid; new->numcsns = src->numcsns; if ( src->numcsns ) { diff --git a/servers/slapd/overlays/syncprov.c b/servers/slapd/overlays/syncprov.c index b6b7eb45b3..8a824513c1 100644 --- a/servers/slapd/overlays/syncprov.c +++ b/servers/slapd/overlays/syncprov.c @@ -59,6 +59,7 @@ typedef struct syncops { ID s_eid; /* entryID of search base */ Operation *s_op; /* search op */ int s_rid; + int s_sid; struct berval s_filterstr; int s_flags; /* search status */ #define PS_IS_REFRESHING 0x01 @@ -769,7 +770,7 @@ syncprov_sendresp( Operation *op, opcookie *opc, syncops *so, ctrls[1] = NULL; csns[0] = opc->sctxcsn; BER_BVZERO( &csns[1] ); - slap_compose_sync_cookie( op, &cookie, csns, so->s_rid ); + slap_compose_sync_cookie( op, &cookie, csns, so->s_rid, so->s_sid ); e_uuid.e_attrs = &a_uuid; a_uuid.a_desc = slap_schema.si_ad_entryUUID; @@ -977,6 +978,12 @@ static int syncprov_qresp( opcookie *opc, syncops *so, int mode ) { syncres *sr; + int sid; + + /* Don't send changes back to their originator */ + sid = slap_parse_csn_sid( &opc->sctxcsn ); + if ( sid == so->s_sid ) + return LDAP_SUCCESS; sr = ch_malloc(sizeof(syncres) + opc->suuid.bv_len + 1 + opc->sdn.bv_len + 1 + opc->sndn.bv_len + 1 + opc->sctxcsn.bv_len + 1 ); @@ -1523,7 +1530,8 @@ syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl, if ( ndel ) { struct berval cookie; - slap_compose_sync_cookie( op, &cookie, delcsn, srs->sr_state.rid ); + slap_compose_sync_cookie( op, &cookie, delcsn, srs->sr_state.rid, + srs->sr_state.sid ); uuids[ndel].bv_val = NULL; syncprov_sendinfo( op, rs, LDAP_TAG_SYNC_ID_SET, &cookie, 0, uuids, 1 ); op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); @@ -1919,6 +1927,13 @@ syncprov_search_response( Operation *op, SlapReply *rs ) int i, sid; sid = slap_parse_csn_sid( &a->a_nvals[0] ); + /* Don't send changed entries back to the originator */ + if ( sid == srs->sr_state.sid ) { + Debug( LDAP_DEBUG_SYNC, + "Entry %s changed by peer, ignored\n", + rs->sr_entry->e_name.bv_val, 0, 0 ); + return LDAP_SUCCESS; + } /* Make sure entry is less than the snapshot'd contextCSN */ for ( i=0; iss_numcsns; i++ ) { if ( sid == ss->ss_sids[i] && ber_bvcmp( &a->a_nvals[0], @@ -1957,7 +1972,7 @@ syncprov_search_response( Operation *op, SlapReply *rs ) struct berval cookie; slap_compose_sync_cookie( op, &cookie, ss->ss_ctxcsn, - srs->sr_state.rid ); + srs->sr_state.rid, srs->sr_state.sid ); /* Is this a regular refresh? */ if ( !ss->ss_so ) { @@ -2051,6 +2066,7 @@ syncprov_op_search( Operation *op, SlapReply *rs ) *sop = so; ldap_pvt_thread_mutex_init( &sop->s_mutex ); sop->s_rid = srs->sr_state.rid; + sop->s_rid = srs->sr_state.sid; sop->s_inuse = 1; ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index d04794faf3..29d8799971 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -1016,7 +1016,7 @@ LDAP_SLAPD_V (char *) slap_known_controls[]; * ldapsync.c */ LDAP_SLAPD_F (void) slap_compose_sync_cookie LDAP_P(( - Operation *, struct berval *, BerVarray, int )); + Operation *, struct berval *, BerVarray, int, int )); LDAP_SLAPD_F (void) slap_sync_cookie_free LDAP_P(( struct sync_cookie *, int free_cookie )); LDAP_SLAPD_F (int) slap_parse_csn_sid LDAP_P(( diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 0495eb0047..f4c1cf7d1d 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1661,6 +1661,7 @@ struct sync_cookie { struct berval *ctxcsn; struct berval octet_str; int rid; + int sid; int numcsns; int *sids; LDAP_STAILQ_ENTRY(sync_cookie) sc_next; diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 154734e68f..7e72db64f4 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -520,13 +520,14 @@ do_syncrep1( } slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, - si->si_syncCookie.ctxcsn, si->si_syncCookie.rid ); + si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, + SLAP_SINGLE_SHADOW( si->si_be ) ? -1 : slap_serverID ); } else { ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex ); /* match SIDs */ if ( si->si_cookieState->cs_num > 1 && si->si_cookieAge != si->si_cookieState->cs_age ) { - int i, j; + int i, j, changed = 0; for (i=0; !BER_BVISNULL( &si->si_syncCookie.ctxcsn[i] ); i++) { /* bogus, just dup everything */ @@ -534,6 +535,7 @@ do_syncrep1( 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; jsi_cookieState->cs_num; j++) { @@ -542,9 +544,16 @@ do_syncrep1( continue; ber_bvreplace( &si->si_syncCookie.ctxcsn[i], &si->si_cookieState->cs_vals[j] ); + changed = 1; break; } } + if ( changed ) { + ch_free( si->si_syncCookie.octet_str.bv_val ); + slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str, + si->si_syncCookie.ctxcsn, si->si_syncCookie.rid, + SLAP_SINGLE_SHADOW( si->si_be ) ? -1 : slap_serverID ); + } } ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex ); } @@ -1092,6 +1101,13 @@ reload: goto reload; } + /* We got deleted while running on cn=config */ + if ( !si->si_ctype ) { + if ( si->si_conn_setup ) + dostop = 1; + rc = -1; + } + if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) { /* If we succeeded, enable the connection for further listening. * If we failed, tear down the connection and reschedule. @@ -1146,7 +1162,8 @@ reload: break; } - if ( !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) { + if ( !si->si_ctype + || !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) { ldap_pvt_runqueue_remove( &slapd_rq, rtask ); } else if ( RETRYNUM_VALID( si->si_retrynum[i] ) ) { if ( si->si_retrynum[i] > 0 ) @@ -1160,6 +1177,24 @@ reload: ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); ldap_pvt_thread_mutex_unlock( &si->si_mutex ); + /* Do final delete cleanup */ + if ( !si->si_ctype ) { + cookie_state *cs = NULL; + syncinfo_t **sip; + + cs = be->be_syncinfo->si_cookieState; + for ( sip = &be->be_syncinfo; *sip != si; sip = &(*sip)->si_next ); + *sip = si->si_next; + syncinfo_free( si ); + if ( !be->be_syncinfo ) { + SLAP_DBFLAGS( be ) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW); + if ( cs ) { + ber_bvarray_free( cs->cs_vals ); + ldap_pvt_thread_mutex_destroy( &cs->cs_mutex ); + ch_free( cs ); + } + } + } return NULL; } @@ -3836,7 +3871,18 @@ syncrepl_config( ConfigArgs *c ) si = *sip; if ( c->valx == -1 || i == c->valx ) { *sip = si->si_next; - syncinfo_free( si ); + /* If the task is currently active, we have to leave + * it running. It will exit on its own. This will only + * happen when running on the cn=config DB. + */ + if ( si->si_re && + ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re ) ) { + si->si_ctype = 0; + } else { + syncinfo_free( si ); + } + if ( i == c->valx ) + break; } else { sip = &si->si_next; }