typedef struct cookie_state {
ldap_pvt_thread_mutex_t cs_mutex;
+ struct berval *cs_vals;
+ int *cs_sids;
int cs_num;
int cs_age;
int cs_ref;
- struct berval *cs_vals;
- int *cs_sids;
-
+
/* pending changes, not yet committed */
ldap_pvt_thread_mutex_t cs_pmutex;
- int cs_pnum;
struct berval *cs_pvals;
int *cs_psids;
+ int cs_pnum;
} cookie_state;
#define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */
slap_compose_sync_cookie( NULL, &si->si_syncCookie.octet_str,
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
+ slap_parse_sync_cookie( &si->si_syncCookie, NULL );
}
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
return changed;
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 );
+ slap_sort_csn_sids( csn, si->si_cookieState->cs_sids, i, NULL );
}
}
if ( si->si_cookieState->cs_num ) {
slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
- if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
+ if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST && si->si_refreshDone ) {
tout_p = &tout;
} else {
tout_p = NULL;
int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
check_syncprov( op, si );
for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+ /* new SID */
+ if ( sid < si->si_cookieState->cs_sids[i] )
+ break;
if ( si->si_cookieState->cs_sids[i] == sid ) {
if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
bdn.bv_val[bdn.bv_len] = '\0';
ldap_pvt_thread_yield();
}
for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
+ if ( sid < si->si_cookieState->cs_psids[i] )
+ break;
if ( si->si_cookieState->cs_psids[i] == sid ) {
if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
bdn.bv_val[bdn.bv_len] = '\0';
}
}
/* new SID, add it */
- if ( i == si->si_cookieState->cs_pnum ) {
- value_add( &si->si_cookieState->cs_pvals, syncCookie.ctxcsn );
- si->si_cookieState->cs_pnum++;
- si->si_cookieState->cs_psids = ch_realloc( si->si_cookieState->cs_psids, si->si_cookieState->cs_pnum * sizeof(int));
- si->si_cookieState->cs_psids[i] = sid;
+ if ( i == si->si_cookieState->cs_pnum ||
+ sid != si->si_cookieState->cs_psids[i] ) {
+ slap_insert_csn_sids(
+ (struct sync_cookie *)&si->si_cookieState->cs_pvals,
+ i, sid, syncCookie.ctxcsn );
}
assert( punlock < 0 );
punlock = i;
si->si_refreshDone = 1;
}
ber_scanf( ber, /*"{"*/ "}" );
+ if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
+ si->si_refreshDone )
+ tout_p = &tout;
break;
case LDAP_TAG_SYNC_ID_SET:
Debug( LDAP_DEBUG_SYNC,
/* Copy the original modlist, split Replace ops into Delete/Add,
* and drop mod opattrs since this modification is in the past.
*/
-static Modifications *mods_dup( Operation *op, Modifications *modlist )
+static Modifications *mods_dup( Operation *op, Modifications *modlist, int match )
{
Modifications *mod, *modnew = NULL, *modtail = NULL;
int size;
for ( ; modlist; modlist = modlist->sml_next ) {
- if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
- modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
- modlist->sml_desc == slap_schema.si_ad_entryCSN )
- continue;
- if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
- mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
- mod->sml_desc = modlist->sml_desc;
- mod->sml_values = NULL;
- mod->sml_nvalues = NULL;
- mod->sml_op = LDAP_MOD_DELETE;
- mod->sml_numvals = 0;
- mod->sml_flags = 0;
- if ( !modnew )
- modnew = mod;
- if ( modtail )
- modtail->sml_next = mod;
- modtail = mod;
+ /* older ops */
+ if ( match < 0 ) {
+ if ( modlist->sml_desc == slap_schema.si_ad_modifiersName ||
+ modlist->sml_desc == slap_schema.si_ad_modifyTimestamp ||
+ modlist->sml_desc == slap_schema.si_ad_entryCSN )
+ continue;
+ if ( modlist->sml_op == LDAP_MOD_REPLACE ) {
+ mod = op->o_tmpalloc( sizeof(Modifications), op->o_tmpmemctx );
+ mod->sml_desc = modlist->sml_desc;
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
+ mod->sml_op = LDAP_MOD_DELETE;
+ mod->sml_numvals = 0;
+ mod->sml_flags = 0;
+ if ( !modnew )
+ modnew = mod;
+ if ( modtail )
+ modtail->sml_next = mod;
+ modtail = mod;
+ }
}
if ( modlist->sml_numvals ) {
size = (modlist->sml_numvals+1) * sizeof(struct berval);
mod->sml_values = (BerVarray)(mod+1);
for (i=0; i<mod->sml_numvals; i++)
mod->sml_values[i] = modlist->sml_values[i];
+ BER_BVZERO(&mod->sml_values[i]);
if ( modlist->sml_nvalues ) {
mod->sml_nvalues = mod->sml_values + mod->sml_numvals + 1;
for (i=0; i<mod->sml_numvals; i++)
mod->sml_nvalues[i] = modlist->sml_nvalues[i];
+ BER_BVZERO(&mod->sml_nvalues[i]);
+ } else {
+ mod->sml_nvalues = NULL;
}
+ } else {
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
}
- if ( modlist->sml_op == LDAP_MOD_REPLACE )
+ if ( match < 0 && modlist->sml_op == LDAP_MOD_REPLACE )
mod->sml_op = LDAP_MOD_ADD;
else
mod->sml_op = modlist->sml_op;
if ( m1->sml_nvalues )
m1->sml_nvalues[k] = m1->sml_nvalues[k+1];
}
+ BER_BVZERO(&m1->sml_values[k]);
+ if ( m1->sml_nvalues ) {
+ BER_BVZERO(&m1->sml_nvalues[k]);
+ }
m1->sml_numvals--;
i--;
}
modify_ctxt *mx = sc->sc_private;
Modifications *ml;
- op->o_callback = sc->sc_next;
- op->o_tmpfree( sc, op->o_tmpmemctx );
-
op->orm_no_opattrs = 0;
op->orm_modlist = mx->mx_orig;
for ( ml = mx->mx_free; ml; ml = mx->mx_free ) {
mx->mx_free = ml->sml_next;
op->o_tmpfree( ml, op->o_tmpmemctx );
}
+ op->o_callback = sc->sc_next;
+ op->o_tmpfree( sc, op->o_tmpmemctx );
return SLAP_CB_CONTINUE;
}
&mod->sml_nvalues[0], &a->a_nvals[0], &text );
overlay_entry_release_ov( op, e, 0, on );
}
- /* mod is newer, let it go */
- if ( match > 0 ) {
- for ( mod = op->orm_modlist; mod; mod=mod->sml_next ) {
- if ( mod->sml_op == LDAP_MOD_DELETE )
- mod->sml_op = SLAP_MOD_SOFTDEL;
- }
- return SLAP_CB_CONTINUE;
- }
/* equal? Should never happen */
if ( match == 0 )
return LDAP_SUCCESS;
*
* 4. Swap original modlist back in response callback so
* that accesslog logs the original mod.
+ *
+ * Even if the mod is newer, other out-of-order changes may
+ * have been committed, forcing us to tweak the modlist:
+ * 1. Save/copy original modlist.
+ * 2. Change deletes to soft deletes.
+ * 3. Change Adds of single-valued attrs to Replace.
*/
- newlist = mods_dup( op, op->orm_modlist );
+ newlist = mods_dup( op, op->orm_modlist, match );
- {
+ /* mod is older */
+ if ( match < 0 ) {
Operation op2 = *op;
AttributeName an[2];
const char *text;
- slap_callback cb;
struct berval bv;
char *ptr;
+ Modifications *ml;
int size, rc;
SlapReply rs1 = {0};
resolve_ctxt rx = { si, newlist };
+ slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, &rx };
op2.o_tag = LDAP_REQ_SEARCH;
op2.ors_scope = LDAP_SCOPE_SUBTREE;
op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
op2.o_callback = &cb;
- cb.sc_response = syncrepl_resolve_cb;
- cb.sc_private = ℞
op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
op2.o_bd->be_search( &op2, &rs1 );
newlist = rx.rx_mods;
sc->sc_response = syncrepl_modify_cb;
sc->sc_private = mx;
sc->sc_next = op->o_callback;
+ sc->sc_cleanup = NULL;
op->o_callback = sc;
op->orm_no_opattrs = 1;
mx->mx_orig = op->orm_modlist;
ml->sml_flags = 0;
ml->sml_op = SLAP_MOD_SOFTDEL;
}
+ else if ( ml->sml_op == LDAP_MOD_DELETE )
+ ml->sml_op = SLAP_MOD_SOFTDEL;
+ else if ( ml->sml_op == LDAP_MOD_ADD &&
+ ml->sml_desc->ad_type->sat_atype.at_single_value )
+ ml->sml_op = LDAP_MOD_REPLACE;
}
op->orm_modlist = newlist;
op->o_csn = mod->sml_nvalues[0];
rc = op->o_bd->be_modify( op, &rs );
if ( SLAP_MULTIMASTER( op->o_bd )) {
LDAP_SLIST_REMOVE( &op->o_extra, &oes.oe, OpExtra, oe_next );
+ BER_BVZERO( &op->o_csn );
}
modlist = op->orm_modlist;
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
/* NOTE: noSuchObject should result because the new superior
* has not been added yet (ITS#6472) */
- if ( rc == LDAP_NO_SUCH_OBJECT && !BER_BVISNULL( op->orr_nnewSup )) {
+ if ( rc == LDAP_NO_SUCH_OBJECT && op->orr_nnewSup != NULL ) {
Operation op2 = *op;
rc = syncrepl_add_glue_ancestors( &op2, entry );
if ( rc == LDAP_SUCCESS ) {
Backend *be = op->o_bd;
Modifications mod;
struct berval first = BER_BVNULL;
+ struct sync_cookie sc;
#ifdef CHECK_CSN
Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax;
#endif
#endif
/* 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] );
+ sc.numcsns = si->si_cookieState->cs_num;
+ if ( sc.numcsns ) {
+ ber_bvarray_dup_x( &sc.ctxcsn, si->si_cookieState->cs_vals, NULL );
+ sc.sids = ch_malloc( sc.numcsns * sizeof(int));
+ for ( i=0; i<sc.numcsns; i++ )
+ sc.sids[i] = si->si_cookieState->cs_sids[i];
+ } else {
+ sc.ctxcsn = NULL;
+ sc.sids = NULL;
+ }
/* 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] )
+ for ( j=0; j<sc.numcsns; j++ ) {
+ if ( syncCookie->sids[i] < sc.sids[j] )
+ break;
+ if ( syncCookie->sids[i] != sc.sids[j] )
continue;
len = syncCookie->ctxcsn[i].bv_len;
- if ( len > si->si_cookieState->cs_vals[j].bv_len )
- len = si->si_cookieState->cs_vals[j].bv_len;
+ if ( len > sc.ctxcsn[j].bv_len )
+ len = sc.ctxcsn[j].bv_len;
if ( memcmp( syncCookie->ctxcsn[i].bv_val,
- si->si_cookieState->cs_vals[j].bv_val, len ) > 0 ) {
- mod.sml_values[j] = syncCookie->ctxcsn[i];
+ sc.ctxcsn[j].bv_val, len ) > 0 ) {
+ ber_bvreplace( &sc.ctxcsn[j], &syncCookie->ctxcsn[i] );
changed = 1;
- if ( BER_BVISNULL( &first ) ) {
- first = syncCookie->ctxcsn[i];
-
- } else if ( memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 )
- {
+ if ( BER_BVISNULL( &first ) ||
+ 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 ) {
- 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 )
- {
+ if ( j == sc.numcsns ||
+ syncCookie->sids[i] != sc.sids[j] ) {
+ slap_insert_csn_sids( &sc, j, syncCookie->sids[i],
+ &syncCookie->ctxcsn[i] );
+ if ( BER_BVISNULL( &first ) ||
+ memcmp( syncCookie->ctxcsn[i].bv_val, first.bv_val, first.bv_len ) > 0 ) {
first = syncCookie->ctxcsn[i];
}
changed = 1;
/* Should never happen, ITS#5065 */
if ( BER_BVISNULL( &first ) || !changed ) {
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
- op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
+ ber_bvarray_free( sc.ctxcsn );
+ ch_free( sc.sids );
return 0;
}
op->o_bd = si->si_wbe;
/* update contextCSN */
op->o_dont_replicate = 1;
+ mod.sml_numvals = sc.numcsns;
+ mod.sml_values = sc.ctxcsn;
+
op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
slap_sync_cookie_free( &si->si_syncCookie, 0 );
- /* If we replaced any old values */
- 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 );
- }
+ ber_bvarray_free( si->si_cookieState->cs_vals );
+ ch_free( si->si_cookieState->cs_sids );
+ si->si_cookieState->cs_vals = sc.ctxcsn;
+ si->si_cookieState->cs_sids = sc.sids;
+ si->si_cookieState->cs_num = sc.numcsns;
/* Don't just dup the provider's cookie, recreate it */
si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
Debug( LDAP_DEBUG_ANY,
"syncrepl_updateCookie: %s be_modify failed (%d)\n",
si->si_ridtxt, rs_modify.sr_err, 0 );
+ ch_free( sc.sids );
+ ber_bvarray_free( sc.ctxcsn );
}
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &op->o_csn );
if ( mod.sml_next ) slap_mods_free( mod.sml_next, 1 );
- op->o_tmpfree( mod.sml_values, op->o_tmpmemctx );
#ifdef CHECK_CSN
for ( i=0; i<si->si_cookieState->cs_num; i++ ) {