static int syncuuid_cmp( const void *, const void * );
static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
-static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct berval * );
+static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
static int syncrepl_message_to_op(
syncinfo_t *, Operation *, LDAPMessage * );
static int syncrepl_message_to_entry(
}
static int
-ask_syncprov( Operation *op, syncinfo_t *si, Attribute *a )
+check_syncprov(
+ Operation *op,
+ syncinfo_t *si )
{
AttributeName at[2];
+ Attribute a = {0};
Entry e = {0};
SlapReply rs = {0};
+ int i, j, changed = 0;
/* Look for contextCSN from syncprov overlay. If
* there's no overlay, this will be a no-op. That means
* allowed, and all changes will already be reflected in
* the cookieState.
*/
- a->a_desc = slap_schema.si_ad_contextCSN;
- e.e_attrs = a;
- e.e_name = si->si_wbe->be_suffix[0];
- e.e_nname = si->si_wbe->be_nsuffix[0];
+ a.a_desc = slap_schema.si_ad_contextCSN;
+ e.e_attrs = &a;
+ e.e_name = op->o_bd->be_suffix[0];
+ e.e_nname = op->o_bd->be_nsuffix[0];
+ at[0].an_name = a.a_desc->ad_cname;
+ at[0].an_desc = a.a_desc;
+ BER_BVZERO( &at[1].an_name );
rs.sr_entry = &e;
rs.sr_flags = REP_ENTRY_MODIFIABLE;
- at[0].an_name = a->a_desc->ad_cname;
- at[0].an_desc = a->a_desc;
- BER_BVZERO( &at[1].an_name );
+ rs.sr_attrs = at;
op->o_req_dn = e.e_name;
op->o_req_ndn = e.e_nname;
- return backend_operational( op, &rs );
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ i = backend_operational( op, &rs );
+ if ( i == LDAP_SUCCESS && a.a_nvals ) {
+ int num = a.a_numvals;
+ /* check for differences */
+ if ( num != si->si_cookieState->cs_num ) {
+ changed = 1;
+ } else {
+ for ( i=0; i<num; i++ ) {
+ if ( ber_bvcmp( &a.a_nvals[i],
+ &si->si_cookieState->cs_vals[i] )) {
+ changed = 1;
+ break;
+ }
+ }
+ }
+ if ( changed ) {
+ ber_bvarray_free( si->si_cookieState->cs_vals );
+ ch_free( si->si_cookieState->cs_sids );
+ si->si_cookieState->cs_num = num;
+ si->si_cookieState->cs_vals = a.a_nvals;
+ si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_nvals,
+ num, NULL );
+ si->si_cookieState->cs_age++;
+ } else {
+ ber_bvarray_free( a.a_nvals );
+ }
+ ber_bvarray_free( a.a_vals );
+ }
+ /* See if the cookieState has changed due to anything outside
+ * this particular consumer. That includes other consumers in
+ * the same context, or local changes detected above.
+ */
+ if ( si->si_cookieState->cs_num > 0 && si->si_cookieAge !=
+ si->si_cookieState->cs_age ) {
+ if ( !si->si_syncCookie.numcsns ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ 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;
+ }
+ }
+ }
+ }
+ if ( changed ) {
+ si->si_cookieAge = si->si_cookieState->cs_age;
+ 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,
+ si->si_syncCookie.sid );
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ return changed;
}
static int
op->o_tls_ssf = ldap_pvt_tls_get_strength( ssl );
}
#endif /* HAVE_TLS */
- ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &op->o_sasl_ssf );
+ {
+ ber_len_t ssf; /* ITS#5403, 3864 LDAP_OPT_X_SASL_SSF probably ought
+ to use sasl_ssf_t but currently uses ber_len_t */
+ ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf );
+ op->o_sasl_ssf = ssf;
+ }
op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
? op->o_sasl_ssf : op->o_tls_ssf;
ldap_set_option( si->si_ld, LDAP_OPT_TIMELIMIT, &si->si_tlimit );
+ rc = LDAP_DEREF_NEVER; /* actually could allow DEREF_FINDING */
+ ldap_set_option( si->si_ld, LDAP_OPT_DEREF, &rc );
+
si->si_syncCookie.rid = si->si_rid;
- si->si_syncCookie.sid = SLAP_SINGLE_SHADOW( si->si_be ) ? -1 :
- slap_serverID;
+
+ /* whenever there are multiple data sources possible, advertise sid */
+ si->si_syncCookie.sid = ( SLAP_MULTIMASTER( si->si_be ) || si->si_be != si->si_wbe ) ?
+ slap_serverID : -1;
/* We've just started up, or the remote server hasn't sent us
* any meaningful state.
ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
if ( !si->si_cookieState->cs_num ) {
/* get contextCSN shadow replica from database */
- Attribute a = {0};
+ BerVarray csn = NULL;
void *ctx = op->o_tmpmemctx;
- rc = ask_syncprov( op, si, &a );
- if ( rc || !a.a_vals ) {
- /* try to read stored contextCSN */
- op->o_tmpmemctx = NULL;
- backend_attribute( op, NULL, &op->o_req_ndn,
- slap_schema.si_ad_contextCSN, &a.a_vals, ACL_READ );
- op->o_tmpmemctx = ctx;
- if ( a.a_vals ) {
- for (i=0; !BER_BVISNULL( &a.a_vals[i] ); i++);
- a.a_numvals = i;
- }
- }
- if ( a.a_vals ) {
- si->si_cookieState->cs_vals = a.a_vals;
- si->si_cookieState->cs_num = a.a_numvals;
- si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_vals, a.a_numvals, NULL );
+ op->o_req_ndn = op->o_bd->be_nsuffix[0];
+ op->o_req_dn = op->o_req_ndn;
+
+ /* try to read stored contextCSN */
+ op->o_tmpmemctx = NULL;
+ backend_attribute( op, NULL, &op->o_req_ndn,
+ slap_schema.si_ad_contextCSN, &csn, ACL_READ );
+ op->o_tmpmemctx = ctx;
+ if ( csn ) {
+ si->si_cookieState->cs_vals = csn;
+ for (i=0; !BER_BVISNULL( &csn[i] ); i++);
+ si->si_cookieState->cs_num = i;
+ si->si_cookieState->cs_sids = slap_parse_csn_sids( csn, i, NULL );
}
}
if ( si->si_cookieState->cs_num ) {
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
} else {
- Attribute a = {0};
- int i, j, changed = 0;
-
- /* Look for contextCSN from syncprov overlay. If
- * there's no overlay, this will be a no-op. That means
- * this is a pure consumer, so local changes will not be
- * allowed, and all changes will already be reflected in
- * the cookieState.
- */
- ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
- rc = ask_syncprov( op, si, &a );
- if ( rc == LDAP_SUCCESS && a.a_vals ) {
- int num = a.a_numvals;
- /* check for differences */
- if ( num != si->si_cookieState->cs_num ) {
- changed = 1;
- } else {
- for ( i=0; i<num; i++ ) {
- if ( ber_bvcmp( &a.a_vals[i],
- &si->si_cookieState->cs_vals[i] )) {
- changed =1;
- break;
- }
- }
- }
- if ( changed ) {
- ber_bvarray_free( si->si_cookieState->cs_vals );
- ch_free( si->si_cookieState->cs_sids );
- si->si_cookieState->cs_num = num;
- si->si_cookieState->cs_vals = a.a_vals;
- si->si_cookieState->cs_sids = slap_parse_csn_sids( a.a_vals,
- num, NULL );
- si->si_cookieState->cs_age++;
- } else {
- ber_bvarray_free( a.a_vals );
- }
- changed = 0;
- }
- /* See if the cookieState has changed due to anything outside
- * this particular consumer. That includes other consumers in
- * the same context, or local changes detected above.
- */
- if ( si->si_cookieState->cs_num > 1 && si->si_cookieAge !=
- si->si_cookieState->cs_age ) {
-
- 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;
- }
- }
- 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,
- si->si_syncCookie.sid );
- }
- }
- ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ /* Look for contextCSN from syncprov overlay. */
+ check_syncprov( op, si );
}
si->si_refreshDone = 0;
return -1;
}
- for (i=0; !BER_BVISNULL( &sc1->ctxcsn[i] ); i++) {
- for (j=0; !BER_BVISNULL( &sc2->ctxcsn[j] ); j++) {
+ for (j=0; j<sc2->numcsns; j++) {
+ for (i=0; i<sc1->numcsns; i++) {
if ( sc1->sids[i] != sc2->sids[j] )
continue;
value_match( &match, slap_schema.si_ad_entryCSN,
}
break;
}
+ if ( i == sc1->numcsns ) {
+ /* sc2 has a sid sc1 lacks */
+ *which = j;
+ return -1;
+ }
}
return match;
}
syncCookie.ctxcsn )
{
rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
- } else if ( rc == LDAP_NO_SUCH_OBJECT ) {
- rc = LDAP_SYNC_REFRESH_REQUIRED;
- si->si_logstate = SYNCLOG_FALLBACK;
- ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+ } else switch ( rc ) {
+ case LDAP_ALREADY_EXISTS:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ rc = LDAP_SYNC_REFRESH_REQUIRED;
+ si->si_logstate = SYNCLOG_FALLBACK;
+ ldap_abandon_ext( si->si_ld, si->si_msgid, NULL, NULL );
+ break;
+ default:
+ break;
}
} else if ( ( rc = syncrepl_message_to_entry( si, op, msg,
&modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
rc = err;
goto done;
}
+ if ( err ) {
+ Debug( LDAP_DEBUG_ANY,
+ "do_syncrep2: %s LDAP_RES_SEARCH_RESULT (%d) %s\n",
+ si->si_ridtxt, err, ldap_err2string( err ) );
+ }
if ( rctrls ) {
rctrlp = *rctrls;
ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER );
}
ber_scanf( ber, /*"{"*/ "}" );
}
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+ }
if ( !syncCookie.ctxcsn ) {
match = 1;
} else if ( !syncCookie_req.ctxcsn ) {
* 2) on err policy : stop service, stop sync, retry
*/
if ( refreshDeletes == 0 && match < 0 &&
- err == LDAP_SUCCESS )
+ err == LDAP_SUCCESS &&
+ syncCookie_req.numcsns == syncCookie.numcsns )
{
syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
} else {
avl_free( si->si_presentlist, ch_free );
si->si_presentlist = NULL;
ber_scanf( ber, /*"{"*/ "}" );
if ( refreshDeletes ) {
syncrepl_del_nonpresent( op, si, syncUUIDs,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
} else {
int i;
continue;
}
+ if ( SLAP_MULTIMASTER( op->o_bd ) && check_syncprov( op, si )) {
+ slap_sync_cookie_free( &syncCookie_req, 0 );
+ slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
+ }
if ( !syncCookie.ctxcsn ) {
match = 1;
} else if ( !syncCookie_req.ctxcsn ) {
}
if ( match < 0 ) {
- if ( si->si_refreshPresent == 1 ) {
+ if ( si->si_refreshPresent == 1 &&
+ syncCookie_req.numcsns == syncCookie.numcsns ) {
syncrepl_del_nonpresent( op, si, NULL,
- &syncCookie.ctxcsn[m] );
+ &syncCookie, m );
}
if ( syncCookie.ctxcsn )
OperationBuffer opbuf;
Operation *op;
int rc = LDAP_SUCCESS;
- int dostop = 0;
+ int dostop = 0, do_setup = 0;
ber_socket_t s;
int i, defer = 1, fail = 0;
Backend *be;
if ( si == NULL )
return NULL;
- /* Don't wait around if there's a previous session still running */
- if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex ))
- return NULL;
+ /* There will never be more than one instance active */
+ ldap_pvt_thread_mutex_lock( &si->si_mutex );
switch( abs( si->si_type ) ) {
case LDAP_SYNC_REFRESH_ONLY:
op->o_tmpmfuncs = &ch_mfuncs;
op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
- op->o_bd = be = si->si_be;
- op->o_dn = op->o_bd->be_rootdn;
- op->o_ndn = op->o_bd->be_rootndn;
- if ( !si->si_schemachecking )
- op->o_no_schema_check = 1;
-
- /* If we're glued, send writes through the glue parent */
+ be = si->si_be;
+
+ /* Coordinate contextCSN updates with any syncprov overlays
+ * in use. This may be complicated by the use of the glue
+ * overlay.
+ *
+ * Typically there is a single syncprov mastering the entire
+ * glued tree. In that case, our contextCSN updates should
+ * go to the master DB. But if there is no syncprov on the
+ * master DB, then nothing special is needed here.
+ *
+ * Alternatively, there may be individual syncprov overlays
+ * on each glued branch. In that case, each syncprov only
+ * knows about changes within its own branch. And so our
+ * contextCSN updates should only go to the local DB.
+ */
if ( !si->si_wbe ) {
- if ( SLAP_GLUE_SUBORDINATE( be )) {
- si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ if ( SLAP_GLUE_SUBORDINATE( be ) && !overlay_is_inst( be, "syncprov" )) {
+ BackendDB * top_be = select_backend( &be->be_nsuffix[0], 1 );
+ if ( overlay_is_inst( top_be, "syncprov" ))
+ si->si_wbe = select_backend( &be->be_nsuffix[0], 1 );
+ else
+ si->si_wbe = be;
} else {
si->si_wbe = be;
}
}
+ if ( !si->si_schemachecking )
+ op->o_no_schema_check = 1;
/* Establish session, do search */
if ( !si->si_ld ) {
si->si_refreshDelete = 0;
si->si_refreshPresent = 0;
+
+ /* use main DB when retrieving contextCSN */
+ op->o_bd = si->si_wbe;
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
rc = do_syncrep1( op, si );
}
if ( rc == LDAP_SUCCESS ) {
ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s );
+ /* use current DB */
+ op->o_bd = be;
+ op->o_dn = op->o_bd->be_rootdn;
+ op->o_ndn = op->o_bd->be_rootndn;
rc = do_syncrep2( op, si );
if ( rc == LDAP_SYNC_REFRESH_REQUIRED ) {
rc = ldap_sync_search( si, op->o_tmpmemctx );
if ( rc == LDAP_SUCCESS ) {
if ( si->si_conn ) {
connection_client_enable( si->si_conn );
+ goto success;
} else {
- si->si_conn = connection_client_setup( s, do_syncrepl, arg );
+ do_setup = 1;
}
} else if ( si->si_conn ) {
dostop = 1;
}
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ if ( do_setup )
+ si->si_conn = connection_client_setup( s, do_syncrepl, arg );
+
+success:
ldap_pvt_thread_mutex_unlock( &si->si_mutex );
if ( rc ) {
Operation *op,
syncinfo_t *si,
BerVarray uuids,
- struct berval *cookiecsn )
+ struct sync_cookie *sc,
+ int m )
{
Backend* be = op->o_bd;
slap_callback cb = { NULL };
}
si->si_refreshDelete ^= NP_DELETE_ONE;
} else {
+ Filter *cf, *of;
+
memset( &an[0], 0, 2 * sizeof( AttributeName ) );
an[0].an_name = slap_schema.si_ad_entryUUID->ad_cname;
an[0].an_desc = slap_schema.si_ad_entryUUID;
op->ors_slimit = SLAP_NO_LIMIT;
op->ors_attrsonly = 0;
op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
- op->ors_filterstr = si->si_filterstr;
+ /* In multimaster, updates can continue to arrive while
+ * we're searching. Limit the search result to entries
+ * older than all of our cookie CSNs.
+ */
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ Filter *f;
+ int i;
+ cf = op->o_tmpalloc( (sc->numcsns+1) * sizeof(Filter) +
+ sc->numcsns * sizeof(AttributeAssertion), op->o_tmpmemctx );
+ f = cf;
+ f->f_choice = LDAP_FILTER_AND;
+ f->f_next = NULL;
+ f->f_and = f+1;
+ of = f->f_and;
+ for ( i=0; i<sc->numcsns; i++ ) {
+ f = of;
+ f->f_choice = LDAP_FILTER_LE;
+ f->f_ava = (AttributeAssertion *)(f+1);
+ f->f_av_desc = slap_schema.si_ad_entryCSN;
+ f->f_av_value = sc->ctxcsn[i];
+ f->f_next = (Filter *)(f->f_ava+1);
+ of = f->f_next;
+ }
+ f->f_next = op->ors_filter;
+ of = op->ors_filter;
+ op->ors_filter = cf;
+ filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
+ } else {
+ cf = NULL;
+ op->ors_filterstr = si->si_filterstr;
+ }
op->o_nocaching = 1;
if ( limits_check( op, &rs_search ) == 0 ) {
rc = be->be_search( op, &rs_search );
}
+ if ( SLAP_MULTIMASTER( op->o_bd )) {
+ op->o_tmpfree( cf, op->o_tmpmemctx );
+ op->ors_filter = of;
+ }
if ( op->ors_filter ) filter_free_x( op, op->ors_filter );
+
}
op->o_nocaching = 0;
if ( !LDAP_LIST_EMPTY( &si->si_nonpresentlist ) ) {
- if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
- csn = *cookiecsn;
+ if ( sc->ctxcsn && !BER_BVISNULL( &sc->ctxcsn[m] ) ) {
+ csn = sc->ctxcsn[m];
} else {
csn = si->si_syncCookie.ctxcsn[0];
}
struct sync_cookie *syncCookie )
{
Backend *be = op->o_bd;
- Modifications mod[2];
+ Modifications mod;
struct berval first = BER_BVNULL;
int rc, i, j, len;
slap_callback cb = { NULL };
SlapReply rs_modify = {REP_RESULT};
- mod[0].sml_op = LDAP_MOD_DELETE;
- mod[0].sml_desc = slap_schema.si_ad_contextCSN;
- mod[0].sml_type = mod[0].sml_desc->ad_cname;
- mod[0].sml_values = NULL;
- mod[0].sml_nvalues = NULL;
- mod[0].sml_numvals = 0;
- mod[0].sml_next = &mod[1];
-
- mod[1].sml_op = LDAP_MOD_ADD;
- mod[1].sml_desc = slap_schema.si_ad_contextCSN;
- mod[1].sml_type = mod[0].sml_desc->ad_cname;
- mod[1].sml_values = NULL;
- mod[1].sml_nvalues = NULL;
- mod[1].sml_numvals = 0;
- mod[1].sml_next = NULL;
+ mod.sml_op = LDAP_MOD_REPLACE;
+ mod.sml_desc = slap_schema.si_ad_contextCSN;
+ mod.sml_type = mod.sml_desc->ad_cname;
+ mod.sml_flags = SLAP_MOD_INTERNAL;
+ mod.sml_nvalues = NULL;
+ mod.sml_next = NULL;
ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ /* clone the cookieState CSNs so we can Replace the whole thing */
+ mod.sml_numvals = si->si_cookieState->cs_num;
+ mod.sml_values = op->o_tmpalloc(( mod.sml_numvals+1 )*sizeof(struct berval), op->o_tmpmemctx );
+ for ( i=0; i<mod.sml_numvals; i++ )
+ mod.sml_values[i] = si->si_cookieState->cs_vals[i];
+ BER_BVZERO( &mod.sml_values[i] );
+
+ /* find any CSNs in the syncCookie that are newer than the cookieState */
for ( i=0; i<syncCookie->numcsns; i++ ) {
for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
if ( syncCookie->sids[i] != si->si_cookieState->cs_sids[j] )
len = si->si_cookieState->cs_vals[j].bv_len;
if ( memcmp( syncCookie->ctxcsn[i].bv_val,
si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
- ber_bvarray_add_x( &mod[0].sml_values,
- &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
- mod[0].sml_numvals++;
- ber_bvarray_add_x( &mod[1].sml_values,
- &syncCookie->ctxcsn[i], op->o_tmpmemctx );
- mod[1].sml_numvals++;
- if ( BER_BVISNULL( &first ))
+ mod.sml_values[j] = syncCookie->ctxcsn[i];
+ if ( BER_BVISNULL( &first ) ) {
+ first = syncCookie->ctxcsn[i];
+
+ } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+ {
first = syncCookie->ctxcsn[i];
+ }
}
break;
}
/* there was no match for this SID, it's a new CSN */
if ( j == si->si_cookieState->cs_num ) {
- ber_bvarray_add_x( &mod[1].sml_values,
- &syncCookie->ctxcsn[i], op->o_tmpmemctx );
- mod[1].sml_numvals++;
- if ( BER_BVISNULL( &first ))
+ mod.sml_values = op->o_tmprealloc( mod.sml_values,
+ ( mod.sml_numvals+2 )*sizeof(struct berval), op->o_tmpmemctx );
+ mod.sml_values[mod.sml_numvals++] = syncCookie->ctxcsn[i];
+ BER_BVZERO( &mod.sml_values[mod.sml_numvals] );
+ if ( BER_BVISNULL( &first ) ) {
+ first = syncCookie->ctxcsn[i];
+ } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
+ {
first = syncCookie->ctxcsn[i];
+ }
}
}
/* Should never happen, ITS#5065 */
if ( BER_BVISNULL( &first )) {
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
return 0;
}
op->o_bd = si->si_wbe;
/* update contextCSN */
op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
- if ( mod[0].sml_values )
- op->orm_modlist = mod;
- else
- op->orm_modlist = &mod[1];
-
+ op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
op->orm_no_opattrs = 0;
slap_sync_cookie_free( &si->si_syncCookie, 0 );
slap_dup_sync_cookie( &si->si_syncCookie, syncCookie );
/* If we replaced any old values */
- if ( mod[0].sml_values ) {
- for ( i=0; !BER_BVISNULL( &mod[0].sml_values[i] ); i++ ) {
- for ( j=0; j<si->si_cookieState->cs_num; j++ ) {
- if ( mod[0].sml_values[i].bv_val !=
- si->si_cookieState->cs_vals[j].bv_val )
- continue;
- ber_bvreplace( &si->si_cookieState->cs_vals[j],
- &mod[1].sml_values[i] );
- break;
- }
- }
- } else {
- /* Else we just added */
- si->si_cookieState->cs_num += syncCookie->numcsns;
- value_add( &si->si_cookieState->cs_vals, syncCookie->ctxcsn );
+ for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
+ if ( mod.sml_values[i].bv_val != si->si_cookieState->cs_vals[i].bv_val )
+ ber_bvreplace( &si->si_cookieState->cs_vals[i],
+ &mod.sml_values[i] );
+ }
+ /* Handle any added values */
+ if ( i < mod.sml_numvals ) {
+ si->si_cookieState->cs_num = mod.sml_numvals;
+ value_add( &si->si_cookieState->cs_vals, &mod.sml_values[i] );
free( si->si_cookieState->cs_sids );
si->si_cookieState->cs_sids = slap_parse_csn_sids(
si->si_cookieState->cs_vals, si->si_cookieState->cs_num, NULL );
op->o_bd = be;
op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &op->o_csn );
- if ( mod[1].sml_next ) slap_mods_free( mod[1].sml_next, 1 );
- op->o_tmpfree( mod[1].sml_values, op->o_tmpmemctx );
- op->o_tmpfree( mod[0].sml_values, op->o_tmpmemctx );
+ if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
+ op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
return rc;
}
}
}
+ /* Don't delete/add an objectClass, always use the replace op.
+ * Modify would fail if provider has replaced entry with a new,
+ * and the new explicitly includes a superior of a class that was
+ * only included implicitly in the old entry. Ref ITS#5517.
+ */
+ if ( nn && no < o && old->a_desc == slap_schema.si_ad_objectClass )
+ no = o;
+
i = j;
/* all old values were deleted, just use the replace op */
if ( no == o ) {
}
/* re-fetch it, in case it was already removed */
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
sie->si_re = ldap_pvt_runqueue_find( &slapd_rq, do_syncrepl, sie );
if ( sie->si_re ) {
if ( ldap_pvt_runqueue_isrunning( &slapd_rq, sie->si_re ) )
ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re );
}
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
bindconf_free( &sie->si_bindconf );
if ( !isMe ) {
init_syncrepl( si );
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
si->si_interval, do_syncrepl, si, "do_syncrepl",
si->si_ridtxt );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
if ( si->si_re )
rc = config_sync_shadow( c ) ? -1 : 0;
else
for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
si = *sip;
if ( c->valx == -1 || i == c->valx ) {
+ int isrunning = 0;
*sip = si->si_next;
/* 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 ) ) {
+ if ( si->si_re ) {
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ isrunning = ldap_pvt_runqueue_isrunning( &slapd_rq, si->si_re );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+ }
+ if ( si->si_re && isrunning ) {
si->si_ctype = 0;
} else {
syncinfo_free( si, 0 );