struct slog_entry *se_next;
struct berval se_uuid;
struct berval se_csn;
+ int se_sid;
ber_tag_t se_tag;
} slog_entry;
/* The main state for this overlay */
typedef struct syncprov_info_t {
syncops *si_ops;
- struct berval si_ctxcsn; /* ldapsync context */
+ BerVarray si_ctxcsn; /* ldapsync context */
+ int *si_sids;
+ int si_numcsns;
int si_chkops; /* checkpointing info */
int si_chktime;
int si_numops; /* number of ops since last checkpoint */
ldap_pvt_thread_mutex_t si_csn_mutex;
ldap_pvt_thread_mutex_t si_ops_mutex;
ldap_pvt_thread_mutex_t si_mods_mutex;
- char si_ctxcsnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
} syncprov_info_t;
typedef struct opcookie {
sync_control *srs = NULL;
struct slap_limits_set fc_limits;
int i, rc = LDAP_SUCCESS, findcsn_retry = 1;
+ int maxid = 0;
if ( mode != FIND_MAXCSN ) {
srs = op->o_controls[slap_cids.sc_LDAPsync];
-
- if ( srs->sr_state.ctxcsn.bv_len >= LDAP_LUTIL_CSNSTR_BUFSIZE ) {
- return LDAP_OTHER;
- }
}
fop = *op;
cf.f_ava = &eq;
cf.f_av_desc = slap_schema.si_ad_entryCSN;
+ BER_BVZERO( &cf.f_av_value );
cf.f_next = NULL;
fop.o_callback = &cb;
switch( mode ) {
case FIND_MAXCSN:
cf.f_choice = LDAP_FILTER_GE;
- cf.f_av_value = si->si_ctxcsn;
+ cf.f_av_value = si->si_ctxcsn[0];
+ /* If there are multiple CSNs, use the largest */
+ for ( i=1; i<si->si_numcsns; i++) {
+ if ( ber_bvcmp( &cf.f_av_value, &si->si_ctxcsn[i] ) < 0 ) {
+ cf.f_av_value = si->si_ctxcsn[i];
+ maxid = i;
+ }
+ }
fop.ors_filterstr.bv_len = sprintf( buf, "(entryCSN>=%s)",
cf.f_av_value.bv_val );
fop.ors_attrsonly = 0;
fop.ors_slimit = SLAP_NO_LIMIT;
cb.sc_private = &maxcsn;
cb.sc_response = findmax_cb;
- strcpy( cbuf, si->si_ctxcsn.bv_val );
+ strcpy( cbuf, cf.f_av_value.bv_val );
maxcsn.bv_val = cbuf;
- maxcsn.bv_len = si->si_ctxcsn.bv_len;
+ maxcsn.bv_len = cf.f_av_value.bv_len;
break;
case FIND_CSN:
- cf.f_av_value = srs->sr_state.ctxcsn;
+ if ( BER_BVISEMPTY( &cf.f_av_value )) {
+ cf.f_av_value = srs->sr_state.ctxcsn[0];
+ /* If there are multiple CSNs, use the smallest */
+ for ( i=1; i<srs->sr_state.numcsns; i++ ) {
+ if ( ber_bvcmp( &cf.f_av_value, &srs->sr_state.ctxcsn[i] )
+ > 0 ) {
+ cf.f_av_value = srs->sr_state.ctxcsn[i];
+ }
+ }
+ }
/* Look for exact match the first time */
if ( findcsn_retry ) {
cf.f_choice = LDAP_FILTER_EQUALITY;
switch( mode ) {
case FIND_MAXCSN:
- strcpy( si->si_ctxcsnbuf, maxcsn.bv_val );
- si->si_ctxcsn.bv_len = maxcsn.bv_len;
+ if ( ber_bvcmp( &si->si_ctxcsn[maxid], &maxcsn )) {
+ ber_bvreplace( &si->si_ctxcsn[maxid], &maxcsn );
+ si->si_numops++; /* ensure a checkpoint */
+ }
break;
case FIND_CSN:
/* If matching CSN was not found, invalidate the context. */
SlapReply rs = { REP_SEARCH };
LDAPControl *ctrls[2];
- struct berval cookie;
+ struct berval cookie, csns[2];
Entry e_uuid = {0};
Attribute a_uuid = {0};
return SLAPD_ABANDON;
ctrls[1] = NULL;
- slap_compose_sync_cookie( op, &cookie, &opc->sctxcsn, so->s_rid );
+ csns[0] = opc->sctxcsn;
+ BER_BVZERO( &csns[1] );
+ slap_compose_sync_cookie( op, &cookie, csns, so->s_rid );
e_uuid.e_attrs = &a_uuid;
a_uuid.a_desc = slap_schema.si_ad_entryUUID;
}
static void
-syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on,
- struct berval *csn )
+syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on )
{
+ syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private;
Modifications mod;
Operation opm;
SlapReply rsm = { 0 };
- struct berval bv[2];
slap_callback cb = {0};
- /* If ctxcsn is empty, delete it */
- if ( BER_BVISEMPTY( csn )) {
- mod.sml_values = NULL;
- } else {
- mod.sml_values = bv;
- bv[1].bv_val = NULL;
- bv[0] = *csn;
- }
+ mod.sml_values = si->si_ctxcsn;
mod.sml_nvalues = NULL;
mod.sml_desc = slap_schema.si_ad_contextCSN;
mod.sml_op = LDAP_MOD_REPLACE;
opm.o_tag = LDAP_REQ_MODIFY;
opm.o_callback = &cb;
opm.orm_modlist = &mod;
+ opm.orm_no_opattrs = 1;
opm.o_req_dn = op->o_bd->be_suffix[0];
opm.o_req_ndn = op->o_bd->be_nsuffix[0];
opm.o_bd->bd_info = on->on_info->oi_orig;
opm.o_managedsait = SLAP_CONTROL_NONCRITICAL;
- SLAP_DBFLAGS( opm.o_bd ) |= SLAP_DBFLAG_NOLASTMOD;
opm.o_bd->be_modify( &opm, &rsm );
- SLAP_DBFLAGS( opm.o_bd ) ^= SLAP_DBFLAG_NOLASTMOD;
if ( mod.sml_next != NULL ) {
slap_mods_free( mod.sml_next, 1 );
}
AC_MEMCPY( se->se_csn.bv_val, op->o_csn.bv_val, op->o_csn.bv_len );
se->se_csn.bv_val[op->o_csn.bv_len] = '\0';
se->se_csn.bv_len = op->o_csn.bv_len;
+ se->se_sid = slap_parse_csn_sid( &se->se_csn );
ldap_pvt_thread_mutex_lock( &sl->sl_mutex );
if ( sl->sl_head ) {
/* enter with sl->sl_mutex locked, release before returning */
static void
syncprov_playlog( Operation *op, SlapReply *rs, sessionlog *sl,
- sync_control *srs, struct berval *ctxcsn )
+ sync_control *srs, BerVarray ctxcsn, int numcsns, int *sids )
{
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
slog_entry *se;
int i, j, ndel, num, nmods, mmods;
char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
BerVarray uuids;
- struct berval delcsn;
+ struct berval delcsn[2];
if ( !sl->sl_num ) {
ldap_pvt_thread_mutex_unlock( &sl->sl_mutex );
num * UUID_LEN, op->o_tmpmemctx );
uuids[0].bv_val = (char *)(uuids + num + 1);
- delcsn.bv_len = 0;
- delcsn.bv_val = cbuf;
+ delcsn[0].bv_len = 0;
+ delcsn[0].bv_val = cbuf;
+ BER_BVZERO(&delcsn[1]);
/* Make a copy of the relevant UUIDs. Put the Deletes up front
* and everything else at the end. Do this first so we can
* unlock the list mutex.
*/
- Debug( LDAP_DEBUG_SYNC, "srs csn %s\n", srs-> sr_state.ctxcsn.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "srs csn %s\n",
+ srs->sr_state.ctxcsn[0].bv_val, 0, 0 );
for ( se=sl->sl_head; se; se=se->se_next ) {
- Debug( LDAP_DEBUG_SYNC, "log csn %s\n", se-> se_csn.bv_val,
-0, 0 );
- ndel = ber_bvcmp( &se->se_csn, &srs->sr_state.ctxcsn );
- if ( ndel <= 0 ) {
- Debug( LDAP_DEBUG_SYNC, "cmp %d, too old\n", ndel,
-0, 0 );
- continue;
- }
- ndel = ber_bvcmp( &se->se_csn, ctxcsn );
- if ( ndel > 0 ) {
- Debug( LDAP_DEBUG_SYNC, "cmp %d, too new\n", ndel,
-0, 0 );
- break;
- }
+ int k;
+ Debug( LDAP_DEBUG_SYNC, "log csn %s\n", se->se_csn.bv_val, 0, 0 );
+ ndel = 1;
+ for ( k=0; k<srs->sr_state.numcsns; k++ ) {
+ if ( se->se_sid == srs->sr_state.sids[k] ) {
+ ndel = ber_bvcmp( &se->se_csn, &srs->sr_state.ctxcsn[k] );
+ break;
+ }
+ }
+ if ( ndel <= 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "cmp %d, too old\n", ndel, 0, 0 );
+ continue;
+ }
+ ndel = 0;
+ for ( k=0; k<numcsns; k++ ) {
+ if ( se->se_sid == sids[k] ) {
+ ndel = ber_bvcmp( &se->se_csn, &ctxcsn[k] );
+ break;
+ }
+ }
+ if ( ndel > 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "cmp %d, too new\n", ndel, 0, 0 );
+ break;
+ }
if ( se->se_tag == LDAP_REQ_DELETE ) {
j = i;
i++;
AC_MEMCPY( cbuf, se->se_csn.bv_val, se->se_csn.bv_len );
- delcsn.bv_len = se->se_csn.bv_len;
- delcsn.bv_val[delcsn.bv_len] = '\0';
+ delcsn[0].bv_len = se->se_csn.bv_len;
+ delcsn[0].bv_val[delcsn[0].bv_len] = '\0';
} else {
nmods++;
j = num - nmods;
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 );
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 );
ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
slap_get_commit_csn( op, &maxcsn );
if ( !BER_BVISNULL( &maxcsn ) ) {
+ int i, sid;
strcpy( cbuf, maxcsn.bv_val );
- if ( ber_bvcmp( &maxcsn, &si->si_ctxcsn ) > 0 ) {
- strcpy( si->si_ctxcsnbuf, cbuf );
- si->si_ctxcsn.bv_len = maxcsn.bv_len;
+ sid = slap_parse_csn_sid( &maxcsn );
+ for ( i=0; i<si->si_numcsns; i++ ) {
+ if ( sid == si->si_sids[i] ) {
+ if ( ber_bvcmp( &maxcsn, &si->si_ctxcsn[i] ) > 0 ) {
+ ber_bvreplace( &si->si_ctxcsn[i], &maxcsn );
+ }
+ break;
+ }
+ }
+ /* It's a new SID for us */
+ if ( i == si->si_numcsns ) {
+ value_add_one( &si->si_ctxcsn, &maxcsn );
+ si->si_numcsns++;
+ si->si_sids = ch_realloc( si->si_sids, si->si_numcsns *
+ sizeof(int));
+ si->si_sids[i] = sid;
}
}
opc->sctxcsn.bv_val = cbuf;
if ( do_check ) {
- syncprov_checkpoint( op, rs, on, &opc->sctxcsn );
+ syncprov_checkpoint( op, rs, on );
}
/* Handle any persistent searches */
{
Entry e = {0};
Attribute a = {0};
- struct berval bv[2];
e.e_name = op->o_bd->be_suffix[0];
e.e_nname = op->o_bd->be_nsuffix[0];
-
- BER_BVZERO( &bv[1] );
- bv[0] = si->si_ctxcsn;
+ e.e_attrs = &a;
a.a_desc = slap_schema.si_ad_contextCSN;
- a.a_vals = bv;
- a.a_nvals = a.a_vals;
ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
+ a.a_vals = si->si_ctxcsn;
+ a.a_nvals = a.a_vals;
+
rs->sr_err = access_allowed( op, &e, op->oq_compare.rs_ava->aa_desc,
&op->oq_compare.rs_ava->aa_value, ACL_COMPARE, NULL );
if ( ! rs->sr_err ) {
typedef struct searchstate {
slap_overinst *ss_on;
syncops *ss_so;
+ BerVarray ss_ctxcsn;
+ int *ss_sids;
+ int ss_numcsns;
int ss_present;
- struct berval ss_ctxcsn;
- char ss_csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
} searchstate;
static int
a = attr_find( rs->sr_operational_attrs, slap_schema.si_ad_entryCSN );
}
if ( a ) {
+ int i, sid;
+ sid = slap_parse_csn_sid( &a->a_nvals[0] );
+
/* Make sure entry is less than the snapshot'd contextCSN */
- if ( ber_bvcmp( &a->a_nvals[0], &ss->ss_ctxcsn ) > 0 ) {
- Debug( LDAP_DEBUG_SYNC, "Entry %s CSN %s greater than snapshot %s\n",
- rs->sr_entry->e_name.bv_val,
- a->a_nvals[0].bv_val,
- ss->ss_ctxcsn.bv_val );
- return LDAP_SUCCESS;
+ for ( i=0; i<ss->ss_numcsns; i++ ) {
+ if ( sid == ss->ss_sids[i] && ber_bvcmp( &a->a_nvals[0],
+ &ss->ss_ctxcsn[i] ) > 0 ) {
+ Debug( LDAP_DEBUG_SYNC,
+ "Entry %s CSN %s greater than snapshot %s\n",
+ rs->sr_entry->e_name.bv_val,
+ a->a_nvals[0].bv_val,
+ ss->ss_ctxcsn[i].bv_val );
+ return LDAP_SUCCESS;
+ }
}
- /* Don't send the ctx entry twice */
- if ( !BER_BVISNULL( &srs->sr_state.ctxcsn ) &&
- bvmatch( &a->a_nvals[0], &srs->sr_state.ctxcsn ) ) {
- Debug( LDAP_DEBUG_SYNC, "Entry %s CSN %s matches ctx %s\n",
- rs->sr_entry->e_name.bv_val,
- a->a_nvals[0].bv_val,
- srs->sr_state.ctxcsn.bv_val );
- return LDAP_SUCCESS;
+ /* Don't send old entries twice */
+ if ( srs->sr_state.ctxcsn ) {
+ for ( i=0; i<srs->sr_state.numcsns; i++ ) {
+ if ( sid == srs->sr_state.sids[i] &&
+ ber_bvcmp( &a->a_nvals[0],
+ &srs->sr_state.ctxcsn[i] )<= 0 ) {
+ Debug( LDAP_DEBUG_SYNC,
+ "Entry %s CSN %s older or equal to ctx %s\n",
+ rs->sr_entry->e_name.bv_val,
+ a->a_nvals[0].bv_val,
+ srs->sr_state.ctxcsn[i].bv_val );
+ return LDAP_SUCCESS;
+ }
+ }
}
}
rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2,
} else if ( rs->sr_type == REP_RESULT && rs->sr_err == LDAP_SUCCESS ) {
struct berval cookie;
- slap_compose_sync_cookie( op, &cookie, &ss->ss_ctxcsn,
+ slap_compose_sync_cookie( op, &cookie, ss->ss_ctxcsn,
srs->sr_state.rid );
/* Is this a regular refresh? */
syncops *sop = NULL;
searchstate *ss;
sync_control *srs;
- struct berval ctxcsn;
- char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
+ BerVarray ctxcsn;
+ int i, *sids, numcsns;
+ struct berval mincsn;
if ( !(op->o_sync_mode & SLAP_SYNC_REFRESH) ) return SLAP_CB_CONTINUE;
/* snapshot the ctxcsn */
ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
- strcpy( csnbuf, si->si_ctxcsnbuf );
- ctxcsn.bv_len = si->si_ctxcsn.bv_len;
+ ber_bvarray_dup_x( &ctxcsn, si->si_ctxcsn, op->o_tmpmemctx );
+ numcsns = si->si_numcsns;
+ sids = op->o_tmpalloc( numcsns * sizeof(int), op->o_tmpmemctx );
+ for ( i=0; i<numcsns; i++ )
+ sids[i] = si->si_sids[i];
ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex );
- ctxcsn.bv_val = csnbuf;
/* If we have a cookie, handle the PRESENT lookups */
- if ( !BER_BVISNULL( &srs->sr_state.ctxcsn )) {
+ if ( srs->sr_state.ctxcsn ) {
sessionlog *sl;
+ int i, j;
- /* The cookie was validated when it was parsed, just use it */
+ /* If there are SIDs we don't recognize in the cookie, drop them */
+ for (i=0; i<srs->sr_state.numcsns; ) {
+ for (j=0; j<numcsns; j++) {
+ if ( srs->sr_state.sids[i] == sids[j] ) {
+ break;
+ }
+ }
+ /* not found */
+ if ( j == numcsns ) {
+ struct berval tmp = srs->sr_state.ctxcsn[i];
+ j = srs->sr_state.numcsns - 1;
+ srs->sr_state.ctxcsn[i] = srs->sr_state.ctxcsn[j];
+ tmp.bv_len = 0;
+ srs->sr_state.ctxcsn[j] = tmp;
+ srs->sr_state.numcsns = j;
+ srs->sr_state.sids[i] = srs->sr_state.sids[j];
+ continue;
+ }
+ i++;
+ }
- /* If just Refreshing and nothing has changed, shortcut it */
- if ( bvmatch( &srs->sr_state.ctxcsn, &ctxcsn )) {
- nochange = 1;
- if ( !(op->o_sync_mode & SLAP_SYNC_PERSIST) ) {
- LDAPControl *ctrls[2];
+ /* Find the smallest CSN */
+ mincsn = srs->sr_state.ctxcsn[0];
+ for ( i=1; i<srs->sr_state.numcsns; i++ ) {
+ if ( ber_bvcmp( &mincsn, &srs->sr_state.ctxcsn[i] ) > 0 )
+ mincsn = srs->sr_state.ctxcsn[i];
+ }
- ctrls[0] = NULL;
- ctrls[1] = NULL;
- syncprov_done_ctrl( op, rs, ctrls, 0, 0,
- NULL, LDAP_SYNC_REFRESH_DELETES );
- rs->sr_ctrls = ctrls;
- rs->sr_err = LDAP_SUCCESS;
- send_ldap_result( op, rs );
- rs->sr_ctrls = NULL;
- return rs->sr_err;
+ /* If nothing has changed, shortcut it */
+ if ( srs->sr_state.numcsns == numcsns ) {
+ int i, j, changed = 0;
+ for ( i=0; i<srs->sr_state.numcsns; i++ ) {
+ for ( j=0; j<numcsns; j++ ) {
+ if ( srs->sr_state.sids[i] != sids[j] )
+ continue;
+ if ( !bvmatch( &srs->sr_state.ctxcsn[i], &ctxcsn[j] ))
+ changed = 1;
+ break;
+ }
+ if ( changed )
+ break;
+ }
+ if ( !changed ) {
+ nochange = 1;
+ if ( !(op->o_sync_mode & SLAP_SYNC_PERSIST) ) {
+ LDAPControl *ctrls[2];
+
+ ctrls[0] = NULL;
+ ctrls[1] = NULL;
+ syncprov_done_ctrl( op, rs, ctrls, 0, 0,
+ NULL, LDAP_SYNC_REFRESH_DELETES );
+ rs->sr_ctrls = ctrls;
+ rs->sr_err = LDAP_SUCCESS;
+ send_ldap_result( op, rs );
+ rs->sr_ctrls = NULL;
+ return rs->sr_err;
+ }
+ goto shortcut;
}
- goto shortcut;
}
/* Do we have a sessionlog for this search? */
sl=si->si_logs;
/* Are there any log entries, and is the consumer state
* present in the session log?
*/
- if ( sl->sl_num > 0 && ber_bvcmp( &srs->sr_state.ctxcsn, &sl->sl_mincsn ) >= 0 ) {
+ if ( sl->sl_num > 0 && ber_bvcmp( &mincsn, &sl->sl_mincsn ) >= 0 ) {
do_present = 0;
/* mutex is unlocked in playlog */
- syncprov_playlog( op, rs, sl, srs, &ctxcsn );
+ syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids );
} else {
ldap_pvt_thread_mutex_unlock( &sl->sl_mutex );
}
#ifdef LDAP_COMP_MATCH
fava->f_ava->aa_cf = NULL;
#endif
- ber_dupbv_x( &fava->f_ava->aa_value, &srs->sr_state.ctxcsn, op->o_tmpmemctx );
+ ber_dupbv_x( &fava->f_ava->aa_value, &mincsn, op->o_tmpmemctx );
fava->f_next = op->ors_filter;
op->ors_filter = fand;
filter2bv_x( op, op->ors_filter, &op->ors_filterstr );
ss->ss_on = on;
ss->ss_so = sop;
ss->ss_present = do_present;
- ss->ss_ctxcsn.bv_len = ctxcsn.bv_len;
- ss->ss_ctxcsn.bv_val = ss->ss_csnbuf;
- strcpy( ss->ss_ctxcsn.bv_val, ctxcsn.bv_val );
+ ss->ss_ctxcsn = ctxcsn;
+ ss->ss_numcsns = numcsns;
+ ss->ss_sids = sids;
cb->sc_response = syncprov_search_response;
cb->sc_cleanup = syncprov_search_cleanup;
cb->sc_private = ss;
cb->sc_next = op->o_callback;
op->o_callback = cb;
-#if 0 /* I don't think we need to shortcircuit back-bdb any more */
- op->o_sync_mode &= SLAP_CONTROL_MASK;
-#endif
-
/* If this is a persistent search and no changes were reported during
* the refresh phase, just invoke the response callback to transition
* us into persist phase
break;
}
- if ( !a ) {
- for ( ap = &rs->sr_operational_attrs; *ap; ap=&(*ap)->a_next );
+ ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
+ if ( si->si_ctxcsn ) {
+ if ( !a ) {
+ for ( ap = &rs->sr_operational_attrs; *ap;
+ ap=&(*ap)->a_next );
- a = attr_alloc( slap_schema.si_ad_contextCSN );
- a->a_vals = ch_malloc( 2 * sizeof(struct berval));
- a->a_vals[1].bv_val = NULL;
- a->a_nvals = a->a_vals;
- *ap = a;
- }
+ a = attr_alloc( slap_schema.si_ad_contextCSN );
+ *ap = a;
+ }
- ldap_pvt_thread_mutex_lock( &si->si_csn_mutex );
- if ( !ap ) {
- strcpy( a->a_vals[0].bv_val, si->si_ctxcsnbuf );
- } else {
- ber_dupbv( &a->a_vals[0], &si->si_ctxcsn );
+ if ( !ap ) {
+ if ( !rs->sr_flags & REP_ENTRY_MODIFIABLE ) {
+ rs->sr_entry = entry_dup( rs->sr_entry );
+ rs->sr_flags |=
+ REP_ENTRY_MODIFIABLE|REP_ENTRY_MUSTBEFREED;
+ a = attr_find( rs->sr_entry->e_attrs,
+ slap_schema.si_ad_contextCSN );
+ }
+ free( a->a_vals );
+ }
+ ber_bvarray_dup_x( &a->a_vals, si->si_ctxcsn, NULL );
+ a->a_nvals = a->a_vals;
}
ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex );
}
Connection conn = { 0 };
OperationBuffer opbuf = { 0 };
- char ctxcsnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE];
Operation *op = (Operation *) &opbuf;
Entry *e;
Attribute *a;
op->o_dn = be->be_rootdn;
op->o_ndn = be->be_rootndn;
- ctxcsnbuf[0] = '\0';
-
op->o_bd->bd_info = on->on_info->oi_orig;
rc = be_entry_get_rw( op, be->be_nsuffix, NULL,
slap_schema.si_ad_contextCSN, 0, &e );
a = attr_find( e->e_attrs, slap_schema.si_ad_contextCSN );
if ( a ) {
- si->si_ctxcsn.bv_len = a->a_nvals[0].bv_len;
- if ( si->si_ctxcsn.bv_len >= sizeof(si->si_ctxcsnbuf ))
- si->si_ctxcsn.bv_len = sizeof(si->si_ctxcsnbuf)-1;
- strncpy( si->si_ctxcsnbuf, a->a_nvals[0].bv_val,
- si->si_ctxcsn.bv_len );
- si->si_ctxcsnbuf[si->si_ctxcsn.bv_len] = '\0';
- strcpy( ctxcsnbuf, si->si_ctxcsnbuf );
+ int i;
+ ber_bvarray_dup_x( &si->si_ctxcsn, a->a_vals, NULL );
+ for ( i=0; !BER_BVISEMPTY( &a->a_vals[i] ); i++ );
+ si->si_numcsns = i;
+ si->si_sids = slap_parse_csn_sids( si->si_ctxcsn, i );
}
be_entry_release_rw( op, e, 0 );
- if ( !BER_BVISEMPTY( &si->si_ctxcsn ) ) {
+ if ( si->si_ctxcsn ) {
op->o_bd->bd_info = (BackendInfo *)on;
op->o_req_dn = be->be_suffix[0];
op->o_req_ndn = be->be_nsuffix[0];
}
}
- if ( BER_BVISEMPTY( &si->si_ctxcsn ) ) {
- if ( SLAP_SYNC_SHADOW( op->o_bd )) {
- /* If we're also a consumer, and we didn't get a contextCSN,
+ /* Didn't find a contextCSN, should we generate one? */
+ if ( !si->si_ctxcsn ) {
+ char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ];
+ struct berval csn;
+
+ if ( SLAP_SYNC_SHADOW( op->o_bd ) && SLAP_SINGLE_SHADOW( op->o_bd )) {
+ /* If we're also a consumer, and we're not multimaster,
* then don't generate anything, wait for our provider to send it
* to us.
*/
goto out;
}
- si->si_ctxcsn.bv_len = sizeof( si->si_ctxcsnbuf );
- slap_get_csn( op, &si->si_ctxcsn, 0 );
- }
+ csn.bv_val = csnbuf;
+ csn.bv_len = sizeof( csnbuf );
+ slap_get_csn( op, &csn, 0 );
+ value_add_one( &si->si_ctxcsn, &csn );
+ si->si_numcsns = 1;
+ si->si_sids = ch_malloc( sizeof(int) );
+ si->si_sids[0] = slap_serverID;
- /* If our ctxcsn is different from what was read from the root
- * entry, make sure we do a checkpoint on close
- */
- if ( strcmp( si->si_ctxcsnbuf, ctxcsnbuf )) {
+ /* make sure we do a checkpoint on close */
si->si_numops++;
}
op->o_bd = be;
op->o_dn = be->be_rootdn;
op->o_ndn = be->be_rootndn;
- syncprov_checkpoint( op, &rs, on, &si->si_ctxcsn );
+ syncprov_checkpoint( op, &rs, on );
}
return 0;
ldap_pvt_thread_mutex_init( &si->si_csn_mutex );
ldap_pvt_thread_mutex_init( &si->si_ops_mutex );
ldap_pvt_thread_mutex_init( &si->si_mods_mutex );
- si->si_ctxcsn.bv_val = si->si_ctxcsnbuf;
csn_anlist[0].an_desc = slap_schema.si_ad_entryCSN;
csn_anlist[0].an_name = slap_schema.si_ad_entryCSN->ad_cname;
LDAP_LIST_ENTRY(nonpresent_entry) npe_link;
};
+typedef struct cookie_state {
+ ldap_pvt_thread_mutex_t cs_mutex;
+ int cs_num;
+ int cs_age;
+ struct berval *cs_vals;
+ int *cs_sids;
+} cookie_state;
+
#define SYNCDATA_DEFAULT 0 /* entries are plain LDAP entries */
#define SYNCDATA_ACCESSLOG 1 /* entries are accesslog format */
#define SYNCDATA_CHANGELOG 2 /* entries are changelog format */
#define RETRYNUM_FINITE(n) ((n) > RETRYNUM_FOREVER) /* not forever */
typedef struct syncinfo_s {
+ struct syncinfo_s *si_next;
struct slap_backend_db *si_be;
struct re_s *si_re;
- long si_rid;
+ int si_rid;
+ char si_ridtxt[8];
slap_bindconf si_bindconf;
struct berval si_base;
struct berval si_logbase;
int *si_retrynum_init;
int *si_retrynum;
struct sync_cookie si_syncCookie;
+ cookie_state *si_cookieState;
+ int si_cookieAge;
int si_manageDSAit;
int si_slimit;
int si_tlimit;
static int syncrepl_entry(
syncinfo_t *, Operation*, Entry*,
Modifications**,int, struct berval*,
- struct sync_cookie *,
- struct berval * );
+ struct sync_cookie * );
static int syncrepl_updateCookie(
syncinfo_t *, Operation *, struct berval *,
struct sync_cookie * );
/* If we're using a log but we have no state, then fallback to
* normal mode for a full refresh.
*/
- if ( si->si_syncdata && BER_BVISEMPTY( &si->si_syncCookie.ctxcsn ) ) {
+ if ( si->si_syncdata && !si->si_syncCookie.numcsns ) {
si->si_logstate = SYNCLOG_FALLBACK;
}
int cmdline_cookie_found = 0;
struct sync_cookie *sc = NULL;
- struct berval *psub;
#ifdef HAVE_TLS
void *ssl;
#endif
- psub = &si->si_be->be_nsuffix[0];
-
rc = slap_client_connect( &si->si_ld, &si->si_bindconf );
if ( rc != LDAP_SUCCESS ) {
goto done;
if ( BER_BVISNULL( &si->si_syncCookie.octet_str ) ) {
- /* get contextCSN shadow replica from database */
- BerVarray csn = NULL;
-
- assert( si->si_rid < 1000 );
- op->o_req_ndn = op->o_bd->be_nsuffix[0];
- op->o_req_dn = op->o_req_ndn;
+ int i;
- /* try to read stored contextCSN */
- backend_attribute( op, NULL, &op->o_req_ndn,
- slap_schema.si_ad_contextCSN, &csn, ACL_READ );
- if ( csn ) {
- ch_free( si->si_syncCookie.ctxcsn.bv_val );
- ber_dupbv( &si->si_syncCookie.ctxcsn, csn );
- ber_bvarray_free_x( csn, op->o_tmpmemctx );
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ if ( !si->si_cookieState->cs_num ) {
+ /* get contextCSN shadow replica from database */
+ BerVarray csn = NULL;
+ void *ctx = op->o_tmpmemctx;
+
+ 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 );
+ }
+ }
+ if ( si->si_cookieState->cs_num ) {
+ ber_bvarray_free( si->si_syncCookie.ctxcsn );
+ if ( ber_bvarray_dup_x( &si->si_syncCookie.ctxcsn,
+ si->si_cookieState->cs_vals, NULL )) {
+ rc = LDAP_NO_MEMORY;
+ goto done;
+ }
+ si->si_syncCookie.numcsns = si->si_cookieState->cs_num;
+ si->si_syncCookie.sids = ch_malloc( si->si_cookieState->cs_num *
+ sizeof(int) );
+ for ( i=0; i<si->si_syncCookie.numcsns; i++ )
+ si->si_syncCookie.sids[i] = si->si_cookieState->cs_sids[i];
}
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
si->si_syncCookie.rid = si->si_rid;
/* ctxcsn wasn't parsed yet, do it now */
slap_parse_sync_cookie( sc, op->o_tmpmemctx );
- if ( BER_BVISNULL( &sc->ctxcsn ) ) {
+ if ( !sc->ctxcsn ) {
/* if cmdline cookie does not have ctxcsn */
/* component, set it to an initial value */
slap_init_sync_cookie_ctxcsn( sc );
}
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 );
+ } 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;
+
+ 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 );
+ break;
+ }
+ for (j=0; j<si->si_cookieState->cs_num; j++) {
+ if ( si->si_syncCookie.sids[i] !=
+ si->si_cookieState->cs_sids[j] )
+ continue;
+ ber_bvreplace( &si->si_syncCookie.ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] );
+ break;
+ }
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
}
rc = ldap_sync_search( si, op->o_tmpmemctx );
if( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY, "do_syncrep1: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s "
"ldap_search_ext: %s (%d)\n",
- si->si_rid, ldap_err2string( rc ), rc );
+ si->si_ridtxt, ldap_err2string( rc ), rc );
}
done:
return rc;
}
+static int
+compare_csns( struct sync_cookie *sc1, struct sync_cookie *sc2, int *which )
+{
+ int i, j, match = 0;
+ const char *text;
+
+ *which = 0;
+
+ for (i=0; !BER_BVISNULL( &sc1->ctxcsn[i] ); i++) {
+ for (j=0; !BER_BVISNULL( &sc2->ctxcsn[j] ); j++) {
+ if ( sc1->sids[i] != sc2->sids[j] )
+ continue;
+ value_match( &match, slap_schema.si_ad_entryCSN,
+ slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
+ SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
+ &sc1->ctxcsn[i], &sc2->ctxcsn[i], &text );
+ if ( match < 0 ) {
+ *which = j;
+ return match;
+ }
+ break;
+ }
+ }
+ return match;
+}
+
static int
do_syncrep2(
Operation *op,
int syncstate;
struct berval syncUUID = BER_BVNULL;
- struct sync_cookie syncCookie = { BER_BVNULL };
- struct sync_cookie syncCookie_req = { BER_BVNULL };
+ struct sync_cookie syncCookie = { NULL };
+ struct sync_cookie syncCookie_req = { NULL };
struct berval cookie = BER_BVNULL;
int rc, err;
struct berval *psub;
Modifications *modlist = NULL;
- const char *text;
- int match;
+ int match, m;
struct timeval *tout_p = NULL;
struct timeval tout = { 0, 0 };
ber_init2( ber, NULL, LBER_USE_DER );
ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
- Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 rid %03ld\n", si->si_rid, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
psub = &si->si_be->be_nsuffix[0];
rctrlp = ldap_find_control( LDAP_CONTROL_SYNC_STATE, rctrls );
}
if ( rctrlp == NULL ) {
- Debug( LDAP_DEBUG_ANY, "do_syncrep2: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
"got search entry without "
- "Sync State control\n", si->si_rid, 0, 0 );
+ "Sync State control\n", si->si_ridtxt, 0, 0 );
rc = -1;
goto done;
}
/* FIXME: what if syncUUID is NULL or empty?
* (happens with back-sql...) */
if ( BER_BVISEMPTY( &syncUUID ) ) {
- Debug( LDAP_DEBUG_ANY, "do_syncrep2: rid %03ld "
- "got empty syncUUID\n", si->si_rid, 0, 0 );
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+ "got empty syncUUID\n", si->si_ridtxt, 0, 0 );
ldap_controls_free( rctrls );
rc = -1;
goto done;
if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
modlist = NULL;
if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
- !BER_BVISNULL( &syncCookie.ctxcsn ) )
+ syncCookie.ctxcsn )
{
rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
}
&modlist, &entry, syncstate ) ) == LDAP_SUCCESS )
{
if ( ( rc = syncrepl_entry( si, op, entry, &modlist,
- syncstate, &syncUUID, &syncCookie_req,
- &syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
- !BER_BVISNULL( &syncCookie.ctxcsn ) )
+ syncstate, &syncUUID, &syncCookie_req ) ) == LDAP_SUCCESS &&
+ syncCookie.ctxcsn )
{
rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
}
case LDAP_RES_SEARCH_REFERENCE:
Debug( LDAP_DEBUG_ANY,
- "do_syncrep2: rid %03ld reference received error\n",
- si->si_rid, 0, 0 );
+ "do_syncrep2: %s reference received error\n",
+ si->si_ridtxt, 0, 0 );
break;
case LDAP_RES_SEARCH_RESULT:
Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: rid %03ld LDAP_RES_SEARCH_RESULT\n",
- si->si_rid, 0, 0 );
+ "do_syncrep2: %s LDAP_RES_SEARCH_RESULT\n",
+ si->si_ridtxt, 0, 0 );
ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL,
&rctrls, 0 );
#ifdef LDAP_X_SYNC_REFRESH_REQUIRED
}
ber_scanf( ber, /*"{"*/ "}" );
}
- if ( BER_BVISNULL( &syncCookie_req.ctxcsn ) ) {
+ if ( !syncCookie_req.ctxcsn ) {
match = -1;
- } else if ( BER_BVISNULL( &syncCookie.ctxcsn ) ) {
+ } else if ( !syncCookie.ctxcsn ) {
match = 1;
} else {
- value_match( &match, slap_schema.si_ad_entryCSN,
- slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
- SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
- &syncCookie_req.ctxcsn, &syncCookie.ctxcsn,
- &text );
+ match = compare_csns( &syncCookie_req, &syncCookie, &m );
}
if ( rctrls ) {
ldap_controls_free( rctrls );
if ( refreshDeletes == 0 && match < 0 &&
err == LDAP_SUCCESS )
{
- syncrepl_del_nonpresent( op, si, NULL, &syncCookie.ctxcsn );
+ syncrepl_del_nonpresent( op, si, NULL,
+ &syncCookie.ctxcsn[m] );
} else {
avl_free( si->si_presentlist, avl_ber_bvfree );
si->si_presentlist = NULL;
}
}
- if ( !BER_BVISNULL( &syncCookie.ctxcsn ) &&
- match < 0 && err == LDAP_SUCCESS )
+ if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
{
rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
}
ber_tag_t tag;
case LDAP_TAG_SYNC_NEW_COOKIE:
Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: rid %03ld %s - %s\n",
- si->si_rid,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
"LDAP_RES_INTERMEDIATE",
"NEW_COOKIE" );
ber_scanf( ber, "tm", &tag, &cookie );
case LDAP_TAG_SYNC_REFRESH_DELETE:
case LDAP_TAG_SYNC_REFRESH_PRESENT:
Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: rid %03ld %s - %s\n",
- si->si_rid,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
"LDAP_RES_INTERMEDIATE",
si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ?
"REFRESH_PRESENT" : "REFRESH_DELETE" );
break;
case LDAP_TAG_SYNC_ID_SET:
Debug( LDAP_DEBUG_SYNC,
- "do_syncrep2: rid %03ld %s - %s\n",
- si->si_rid,
+ "do_syncrep2: %s %s - %s\n",
+ si->si_ridtxt,
"LDAP_RES_INTERMEDIATE",
"SYNC_ID_SET" );
ber_scanf( ber, "t{" /*"}"*/, &tag );
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
+ compare_csns( &syncCookie_req, &syncCookie, &m );
}
}
if ( ber_peek_tag( ber, &len ) ==
ber_scanf( ber, /*"{"*/ "}" );
if ( refreshDeletes ) {
syncrepl_del_nonpresent( op, si, syncUUIDs,
- &syncCookie.ctxcsn );
+ &syncCookie.ctxcsn[m] );
ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
} else {
int i;
break;
default:
Debug( LDAP_DEBUG_ANY,
- "do_syncrep2: rid %03ld unknown syncinfo tag (%ld)\n",
- si->si_rid, (long) si_tag, 0 );
+ "do_syncrep2: %s unknown syncinfo tag (%ld)\n",
+ si->si_ridtxt, (long) si_tag, 0 );
ldap_memfree( retoid );
ber_bvfree( retdata );
continue;
}
- if ( BER_BVISNULL( &syncCookie_req.ctxcsn ) ) {
+ if ( !syncCookie_req.ctxcsn ) {
match = -1;
- } else if ( BER_BVISNULL( &syncCookie.ctxcsn ) ) {
+ } else if ( !syncCookie.ctxcsn ) {
match = 1;
} else {
- value_match( &match, slap_schema.si_ad_entryCSN,
- slap_schema.si_ad_entryCSN->ad_type->sat_ordering,
- SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
- &syncCookie_req.ctxcsn,
- &syncCookie.ctxcsn, &text );
+ match = compare_csns( &syncCookie_req, &syncCookie, &m );
}
if ( match < 0 ) {
if ( si->si_refreshPresent == 1 ) {
- syncrepl_del_nonpresent( op, si, NULL, &syncCookie.ctxcsn );
+ syncrepl_del_nonpresent( op, si, NULL,
+ &syncCookie.ctxcsn[m] );
}
- if ( !BER_BVISNULL( &syncCookie.ctxcsn ) )
+ if ( syncCookie.ctxcsn )
{
rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
}
break;
} else {
- Debug( LDAP_DEBUG_ANY, "do_syncrep2: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
"unknown intermediate response (%d)\n",
- si->si_rid, rc, 0 );
+ si->si_ridtxt, rc, 0 );
ldap_memfree( retoid );
ber_bvfree( retdata );
break;
break;
default:
- Debug( LDAP_DEBUG_ANY, "do_syncrep2: rid %03ld "
- "unknown message\n", si->si_rid, 0, 0 );
+ Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
+ "unknown message\n", si->si_ridtxt, 0, 0 );
break;
}
errstr = ldap_err2string( rc );
Debug( LDAP_DEBUG_ANY,
- "do_syncrep2: rid %03ld %s\n", si->si_rid, errstr, 0 );
+ "do_syncrep2: %s %s\n", si->si_ridtxt, errstr, 0 );
}
done:
int i, defer = 1;
Backend *be;
- Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl rid %03ld\n", si->si_rid, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
if ( si == NULL )
return NULL;
int rc, deleteOldRdn = 0, freeReqDn = 0;
if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
"Message type should be entry (%d)",
- si->si_rid, ldap_msgtype( msg ), 0 );
+ si->si_ridtxt, ldap_msgtype( msg ), 0 );
return -1;
}
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
- "syncrepl_message_to_op: rid %03ld dn get failed (%d)",
- si->si_rid, rc, 0 );
+ "syncrepl_message_to_op: %s dn get failed (%d)",
+ si->si_ridtxt, rc, 0 );
return rc;
}
int i = verb_to_mask( bvals[0].bv_val, modops );
if ( i < 0 ) {
Debug( LDAP_DEBUG_ANY,
- "syncrepl_message_to_op: rid %03ld unknown op %s",
- si->si_rid, bvals[0].bv_val, 0 );
+ "syncrepl_message_to_op: %s unknown op %s",
+ si->si_ridtxt, bvals[0].bv_val, 0 );
ch_free( bvals );
rc = -1;
goto done;
rc = slap_mods_check( op, modlist, &text, txtbuf, textlen, NULL );
if ( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
"mods check (%s)\n",
- si->si_rid, text, 0 );
+ si->si_ridtxt, text, 0 );
goto done;
}
freeReqDn = 0;
rc = slap_mods2entry( modlist, &op->ora_e, 1, 0, &text, txtbuf, textlen);
if( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
"mods2entry (%s)\n",
- si->si_rid, text, 0 );
+ si->si_ridtxt, text, 0 );
} else {
rc = op->o_bd->be_add( op, &rs );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_message_to_op: rid %03ld be_add %s (%d)\n",
- si->si_rid, op->o_req_dn.bv_val, rc );
+ "syncrepl_message_to_op: %s be_add %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
}
if ( e == op->ora_e )
be_entry_release_w( op, op->ora_e );
op->orm_modlist = modlist;
rc = op->o_bd->be_modify( op, &rs );
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
- "syncrepl_message_to_op: rid %03ld be_modify %s (%d)\n",
- si->si_rid, op->o_req_dn.bv_val, rc );
+ "syncrepl_message_to_op: %s be_modify %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
}
break;
case LDAP_REQ_MODRDN:
rc = op->o_bd->be_modrdn( op, &rs );
slap_mods_free( op->orr_modlist, 1 );
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
- "syncrepl_message_to_op: rid %03ld be_modrdn %s (%d)\n",
- si->si_rid, op->o_req_dn.bv_val, rc );
+ "syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
break;
case LDAP_REQ_DELETE:
rc = op->o_bd->be_delete( op, &rs );
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
- "syncrepl_message_to_op: rid %03ld be_delete %s (%d)\n",
- si->si_rid, op->o_req_dn.bv_val, rc );
+ "syncrepl_message_to_op: %s be_delete %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
break;
}
done:
*modlist = NULL;
if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: rid %03ld "
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s "
"Message type should be entry (%d)",
- si->si_rid, ldap_msgtype( msg ), 0 );
+ si->si_ridtxt, ldap_msgtype( msg ), 0 );
return -1;
}
rc = ldap_get_dn_ber( si->si_ld, msg, &ber, &bdn );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
- "syncrepl_message_to_entry: rid %03ld dn get failed (%d)",
- si->si_rid, rc, 0 );
+ "syncrepl_message_to_entry: %s dn get failed (%d)",
+ si->si_ridtxt, rc, 0 );
return rc;
}
}
if ( *modlist == NULL ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: rid %03ld no attributes\n",
- si->si_rid, 0, 0 );
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s no attributes\n",
+ si->si_ridtxt, 0, 0 );
rc = -1;
goto done;
}
rc = slap_mods_check( op, *modlist, &text, txtbuf, textlen, NULL );
if ( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: rid %03ld mods check (%s)\n",
- si->si_rid, text, 0 );
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods check (%s)\n",
+ si->si_ridtxt, text, 0 );
goto done;
}
rc = slap_mods2entry( *modlist, &e, 1, 1, &text, txtbuf, textlen);
if( rc != LDAP_SUCCESS ) {
- Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: rid %03ld mods2entry (%s)\n",
- si->si_rid, text, 0 );
+ Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_entry: %s mods2entry (%s)\n",
+ si->si_ridtxt, text, 0 );
}
done:
Modifications** modlist,
int syncstate,
struct berval* syncUUID,
- struct sync_cookie* syncCookie_req,
- struct berval* syncCSN )
+ struct sync_cookie* syncCookie_req )
{
Backend *be = op->o_bd;
slap_callback cb = { NULL, NULL, NULL, NULL };
switch( syncstate ) {
case LDAP_SYNC_PRESENT:
- Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: rid %03ld %s\n",
- si->si_rid,
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
+ si->si_ridtxt,
"LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_PRESENT)", 0 );
break;
case LDAP_SYNC_ADD:
- Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: rid %03ld %s\n",
- si->si_rid,
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
+ si->si_ridtxt,
"LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_ADD)", 0 );
break;
case LDAP_SYNC_DELETE:
- Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: rid %03ld %s\n",
- si->si_rid,
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
+ si->si_ridtxt,
"LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_DELETE)", 0 );
break;
case LDAP_SYNC_MODIFY:
- Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: rid %03ld %s\n",
- si->si_rid,
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s %s\n",
+ si->si_ridtxt,
"LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_MODIFY)", 0 );
break;
default:
- Debug( LDAP_DEBUG_ANY, "syncrepl_entry: rid %03ld %s\n",
- si->si_rid,
+ Debug( LDAP_DEBUG_ANY, "syncrepl_entry: %s %s\n",
+ si->si_ridtxt,
"LDAP_RES_SEARCH_ENTRY(UNKNOWN syncstate)", 0 );
}
ava.aa_value = *syncUUID;
if ( syncuuid_bv ) {
- Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: rid %03ld inserted UUID %s\n",
- si->si_rid, syncUUID_strrep.bv_val, 0 );
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s inserted UUID %s\n",
+ si->si_ridtxt, syncUUID_strrep.bv_val, 0 );
}
op->ors_filter = &f;
if ( limits_check( op, &rs_search ) == 0 ) {
rc = be->be_search( op, &rs_search );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld be_search (%d)\n",
- si->si_rid, rc, 0 );
+ "syncrepl_entry: %s be_search (%d)\n",
+ si->si_ridtxt, rc, 0 );
}
if ( !BER_BVISNULL( &op->ors_filterstr ) ) {
if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld %s\n",
- si->si_rid, entry->e_name.bv_val, 0 );
+ "syncrepl_entry: %s %s\n",
+ si->si_ridtxt, entry->e_name.bv_val, 0 );
} else {
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld %s\n",
- si->si_rid, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
+ "syncrepl_entry: %s %s\n",
+ si->si_ridtxt, dni.dn.bv_val ? dni.dn.bv_val : "(null)", 0 );
}
/* Don't save the contextCSN on the inooming context entry,
rc = be->be_add( op, &rs_add );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld be_add (%d)\n",
- si->si_rid, rc, 0 );
+ "syncrepl_entry: %s be_add (%d)\n",
+ si->si_ridtxt, rc, 0 );
switch ( rs_add.sr_err ) {
case LDAP_SUCCESS:
if ( op->ora_e == entry ) {
default:
Debug( LDAP_DEBUG_ANY,
- "syncrepl_entry: rid %03ld be_add failed (%d)\n",
- si->si_rid, rs_add.sr_err, 0 );
+ "syncrepl_entry: %s be_add failed (%d)\n",
+ si->si_ridtxt, rs_add.sr_err, 0 );
break;
}
goto done;
slap_mods_free( op->orr_modlist, 1 );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld be_modrdn (%d)\n",
- si->si_rid, rc, 0 );
+ "syncrepl_entry: %s be_modrdn (%d)\n",
+ si->si_ridtxt, rc, 0 );
goto done;
}
if ( dni.mods ) {
rc = be->be_modify( op, &rs_modify );
slap_mods_free( op->orm_modlist, 1 );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld be_modify (%d)\n",
- si->si_rid, rc, 0 );
+ "syncrepl_entry: %s be_modify (%d)\n",
+ si->si_ridtxt, rc, 0 );
if ( rs_modify.sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
- "syncrepl_entry: rid %03ld be_modify failed (%d)\n",
- si->si_rid, rs_modify.sr_err, 0 );
+ "syncrepl_entry: %s be_modify failed (%d)\n",
+ si->si_ridtxt, rs_modify.sr_err, 0 );
}
} else {
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld entry unchanged, ignored (%s)\n",
- si->si_rid, op->o_req_dn.bv_val, 0 );
+ "syncrepl_entry: %s entry unchanged, ignored (%s)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, 0 );
}
goto done;
case LDAP_SYNC_DELETE :
op->o_tag = LDAP_REQ_DELETE;
rc = be->be_delete( op, &rs_delete );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: rid %03ld be_delete (%d)\n",
- si->si_rid, rc, 0 );
+ "syncrepl_entry: %s be_delete (%d)\n",
+ si->si_ridtxt, rc, 0 );
while ( rs_delete.sr_err == LDAP_SUCCESS
&& op->o_delete_glue_parent ) {
default :
Debug( LDAP_DEBUG_ANY,
- "syncrepl_entry: rid %03ld unknown syncstate\n", si->si_rid, 0, 0 );
+ "syncrepl_entry: %s unknown syncstate\n", si->si_ridtxt, 0, 0 );
goto done;
}
if ( cookiecsn && !BER_BVISNULL( cookiecsn ) ) {
csn = *cookiecsn;
} else {
- csn = si->si_syncCookie.ctxcsn;
+ csn = si->si_syncCookie.ctxcsn[0];
}
slap_queue_csn( op, &csn );
op->o_req_ndn = *np_prev->npe_nname;
rc = op->o_bd->be_delete( op, &rs_delete );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_del_nonpresent: rid %03ld be_delete %s (%d)\n",
- si->si_rid, op->o_req_dn.bv_val, rc );
+ "syncrepl_del_nonpresent: %s be_delete %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
if ( rs_delete.sr_err == LDAP_NOT_ALLOWED_ON_NONLEAF ) {
Modifications mod1, mod2;
struct sync_cookie *syncCookie )
{
Backend *be = op->o_bd;
- Modifications mod = { { 0 } };
- struct berval vals[ 2 ];
+ Modifications mod[2];
+ struct berval first = BER_BVNULL;
- int rc, flags;
+ int rc, i, j;
slap_callback cb = { NULL };
SlapReply rs_modify = {REP_RESULT};
- mod.sml_op = LDAP_MOD_REPLACE;
- mod.sml_desc = slap_schema.si_ad_contextCSN;
- mod.sml_type = mod.sml_desc->ad_cname;
- mod.sml_values = vals;
- vals[0] = syncCookie->ctxcsn;
- BER_BVZERO( &vals[1] );
-
- slap_queue_csn( op, &syncCookie->ctxcsn );
+ 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_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_next = NULL;
+
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+
+ 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] )
+ continue;
+ if ( ber_bvcmp( &syncCookie->ctxcsn[i],
+ &si->si_cookieState->cs_vals[j] ) > 0 ) {
+ ber_bvarray_add_x( &mod[0].sml_values,
+ &si->si_cookieState->cs_vals[j], op->o_tmpmemctx );
+ ber_bvarray_add_x( &mod[1].sml_values,
+ &syncCookie->ctxcsn[i], op->o_tmpmemctx );
+ if ( BER_BVISNULL( &first ))
+ 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 );
+ if ( BER_BVISNULL( &first ))
+ first = syncCookie->ctxcsn[i];
+ }
+ }
+ slap_queue_csn( op, &first );
op->o_tag = LDAP_REQ_MODIFY;
- assert( si->si_rid < 1000 );
-
cb.sc_response = null_callback;
cb.sc_private = si;
/* update contextCSN */
op->o_msgid = SLAP_SYNC_UPDATE_MSGID;
- op->orm_modlist = &mod;
- flags = SLAP_DBFLAGS( op->o_bd );
- SLAP_DBFLAGS( op->o_bd ) |= SLAP_DBFLAG_NOLASTMOD;
+
+ if ( mod[0].sml_values )
+ op->orm_modlist = mod;
+ else
+ op->orm_modlist = &mod[1];
+
+ op->orm_no_opattrs = 1;
rc = be->be_modify( op, &rs_modify );
- SLAP_DBFLAGS( op->o_bd ) = flags;
op->o_msgid = 0;
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
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 );
+ 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 );
+ }
+
+ si->si_cookieState->cs_age++;
+ si->si_cookieAge = si->si_cookieState->cs_age;
} else {
Debug( LDAP_DEBUG_ANY,
- "syncrepl_updateCookie: rid %03ld be_modify failed (%d)\n",
- si->si_rid, rs_modify.sr_err, 0 );
+ "syncrepl_updateCookie: %s be_modify failed (%d)\n",
+ si->si_ridtxt, rs_modify.sr_err, 0 );
}
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
slap_graduate_commit_csn( op );
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 );
+ 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 );
return rc;
}
} else if ( rs->sr_type == REP_SEARCH ) {
if ( !( si->si_refreshDelete & NP_DELETE_ONE ) ) {
- char buf[sizeof("000 not")];
+ char buf[sizeof("rid=000 not")];
a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
}
if ( slap_debug & LDAP_DEBUG_SYNC ) {
- sprintf( buf, "%03ld %s", si->si_rid,
+ sprintf( buf, "%s %s", si->si_ridtxt,
present_uuid ? "got" : "not" );
}
- Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: rid %s UUID %s, dn %s\n",
+ Debug( LDAP_DEBUG_SYNC, "nonpresent_callback: %s UUID %s, dn %s\n",
buf, a ? a->a_vals[0].bv_val : "<missing>", rs->sr_entry->e_name.bv_val );
if ( a == NULL ) return 0;
return -1;
}
si->si_rid = tmp;
+ sprintf( si->si_ridtxt, IDSTR "=%03d", si->si_rid );
gots |= GOT_ID;
} else if ( !strncasecmp( c->argv[ i ], PROVIDERSTR "=",
STRLENOF( PROVIDERSTR "=" ) ) )
init_syncrepl( si );
si->si_re = ldap_pvt_runqueue_insert( &slapd_rq,
si->si_interval, do_syncrepl, si, "do_syncrepl",
- c->be->be_suffix[0].bv_val );
+ si->si_ridtxt );
if ( si->si_re )
rc = config_sync_shadow( c ) ? -1 : 0;
else
if ( !si->si_schemachecking ) {
SLAP_DBFLAGS(c->be) |= SLAP_DBFLAG_NO_SCHEMA_CHECK;
}
+ if ( c->be->be_syncinfo ) {
+ si->si_cookieState = c->be->be_syncinfo->si_cookieState;
+ } else {
+ si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
+ ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
+ }
+ si->si_next = c->be->be_syncinfo;
c->be->be_syncinfo = si;
return 0;
}
if (c->op == SLAP_CONFIG_EMIT) {
if ( c->be->be_syncinfo ) {
struct berval bv;
- syncrepl_unparse( c->be->be_syncinfo, &bv );
- ber_bvarray_add( &c->rvalue_vals, &bv );
+ syncinfo_t *si;
+
+ for ( si = c->be->be_syncinfo; si; si=si->si_next ) {
+ syncrepl_unparse( si, &bv );
+ ber_bvarray_add( &c->rvalue_vals, &bv );
+ }
return 0;
}
return 1;
} else if ( c->op == LDAP_MOD_DELETE ) {
+ cookie_state *cs = NULL;
if ( c->be->be_syncinfo ) {
- syncinfo_free( c->be->be_syncinfo );
- c->be->be_syncinfo = NULL;
+ syncinfo_t *si, **sip;
+ int i;
+
+ cs = c->be->be_syncinfo->si_cookieState;
+ for ( sip = &c->be->be_syncinfo, i=0; *sip; i++ ) {
+ si = *sip;
+ if ( c->valx == -1 || i == c->valx ) {
+ *sip = si->si_next;
+ syncinfo_free( si );
+ } else {
+ sip = &si->si_next;
+ }
+ }
+ }
+ if ( !c->be->be_syncinfo ) {
+ SLAP_DBFLAGS( c->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 );
+ }
}
- SLAP_DBFLAGS( c->be ) &= ~(SLAP_DBFLAG_SHADOW|SLAP_DBFLAG_SYNC_SHADOW);
return 0;
}
- if ( SLAP_SHADOW( c->be ) ) {
+ if ( SLAP_SLURP_SHADOW( c->be ) ) {
Debug(LDAP_DEBUG_ANY, "%s: "
"syncrepl: database already shadowed.\n",
c->log, 0, 0);