ldap_pvt_thread_mutex_t cs_mutex;
int cs_num;
int cs_age;
+ int cs_ref;
struct berval *cs_vals;
int *cs_sids;
-} cookie_state;
+ /* pending changes, not yet committed */
+ ldap_pvt_thread_mutex_t cs_pmutex;
+ int cs_pnum;
+ struct berval *cs_pvals;
+ int *cs_psids;
+} 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 */
struct berval si_logbase;
struct berval si_filterstr;
struct berval si_logfilterstr;
+ struct berval si_contextdn;
int si_scope;
int si_attrsonly;
char *si_anfile;
Modifications**,int, struct berval*,
struct berval *cookieCSN );
static int syncrepl_updateCookie(
- syncinfo_t *, Operation *, struct berval *,
+ syncinfo_t *, Operation *,
struct sync_cookie * );
static struct berval * slap_uuidstr_from_normalized(
struct berval *, struct berval *, void * );
*/
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];
+ e.e_name = si->si_contextdn;
+ e.e_nname = si->si_contextdn;
at[0].an_name = a.a_desc->ad_cname;
at[0].an_desc = a.a_desc;
BER_BVZERO( &at[1].an_name );
{
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;
+ if ( ldap_get_option( si->si_ld, LDAP_OPT_X_SASL_SSF, &ssf )
+ == LDAP_SUCCESS )
+ op->o_sasl_ssf = ssf;
}
op->o_ssf = ( op->o_sasl_ssf > op->o_tls_ssf )
? op->o_sasl_ssf : op->o_tls_ssf;
BerVarray csn = NULL;
void *ctx = op->o_tmpmemctx;
- op->o_req_ndn = op->o_bd->be_nsuffix[0];
+ op->o_req_ndn = si->si_contextdn;
op->o_req_dn = op->o_req_ndn;
/* try to read stored contextCSN */
si->si_syncCookie.ctxcsn, si->si_syncCookie.rid,
si->si_syncCookie.sid );
} else {
+ /* ITS#6367: recreate the cookie so it has our SID, not our peer's */
+ 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 );
/* Look for contextCSN from syncprov overlay. */
check_syncprov( op, si );
}
err = LDAP_SUCCESS;
ber_len_t len;
- struct berval *psub;
Modifications *modlist = NULL;
- int match, m;
+ int match, m, punlock = 0;
struct timeval *tout_p = NULL;
struct timeval tout = { 0, 0 };
Debug( LDAP_DEBUG_TRACE, "=>do_syncrep2 %s\n", si->si_ridtxt, 0, 0 );
- psub = &si->si_be->be_nsuffix[0];
-
slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie );
if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) {
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
ber_scanf( ber, /*"{"*/ "m}", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
slap_parse_sync_cookie( &syncCookie, NULL );
if ( syncCookie.ctxcsn ) {
int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
+ check_syncprov( op, si );
for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
- if ( si->si_cookieState->cs_sids[i] == sid &&
- ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
- si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
- ldap_controls_free( rctrls );
- rc = 0;
+ if ( si->si_cookieState->cs_sids[i] == sid ) {
+ if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
+ si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+ ldap_controls_free( rctrls );
+ rc = 0;
+ goto done;
+ }
+ break;
+ }
+ }
+ /* check pending CSNs too */
+ while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
+ if ( slapd_shutdown ) {
+ rc = -2;
goto done;
}
+ if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
+ ldap_pvt_thread_yield();
+ }
+ for ( i =0; i<si->si_cookieState->cs_pnum; i++ ) {
+ if ( si->si_cookieState->cs_psids[i] == sid ) {
+ if ( ber_bvcmp( syncCookie.ctxcsn, &si->si_cookieState->cs_pvals[i] ) <= 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s\n",
+ si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
+ ldap_controls_free( rctrls );
+ rc = 0;
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+ goto done;
+ }
+ ber_bvreplace( &si->si_cookieState->cs_pvals[i],
+ syncCookie.ctxcsn );
+ break;
+ }
+ }
+ /* 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;
}
+ punlock = 1;
}
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
rc = 0;
if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
} else switch ( rc ) {
case LDAP_ALREADY_EXISTS:
case LDAP_NO_SUCH_OBJECT:
syncstate, &syncUUID, syncCookie.ctxcsn ) ) == LDAP_SUCCESS &&
syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
}
}
+ if ( punlock );
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
ldap_controls_free( rctrls );
if ( modlist ) {
slap_mods_free( modlist, 1 );
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_REFRESHDELETES )
}
if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie );
}
if ( err == LDAP_SUCCESS
&& si->si_logstate == SYNCLOG_FALLBACK ) {
"LDAP_RES_INTERMEDIATE",
"NEW_COOKIE" );
ber_scanf( ber, "tm", &tag, &cookie );
+ Debug( LDAP_DEBUG_SYNC,
+ "do_syncrep2: %s NEW_COOKIE: %s\n",
+ si->si_ridtxt,
+ cookie.bv_val, 0);
+ if ( !BER_BVISNULL( &cookie ) ) {
+ ch_free( syncCookie.octet_str.bv_val );
+ ber_dupbv( &syncCookie.octet_str, &cookie );
+ }
+ if (!BER_BVISNULL( &syncCookie.octet_str ) ) {
+ slap_parse_sync_cookie( &syncCookie, NULL );
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
+ }
break;
case LDAP_TAG_SYNC_REFRESH_DELETE:
case LDAP_TAG_SYNC_REFRESH_PRESENT:
{
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
}
/* Defaults to TRUE */
{
ber_scanf( ber, "m", &cookie );
- Debug( LDAP_DEBUG_SYNC, "do_syncrep2: cookie=%s\n",
- BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0, 0 );
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
+ si->si_ridtxt,
+ BER_BVISNULL( &cookie ) ? "" : cookie.bv_val, 0 );
if ( !BER_BVISNULL( &cookie ) ) {
ch_free( syncCookie.octet_str.bv_val );
if ( !BER_BVISNULL( &syncCookie.octet_str ) )
{
slap_parse_sync_cookie( &syncCookie, NULL );
+ op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
compare_csns( &syncCookie_req, &syncCookie, &m );
}
}
if ( match < 0 ) {
if ( si->si_refreshPresent == 1 &&
+ si_tag != LDAP_TAG_SYNC_NEW_COOKIE &&
syncCookie_req.numcsns == syncCookie.numcsns ) {
syncrepl_del_nonpresent( op, si, NULL,
&syncCookie, m );
if ( syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, psub, &syncCookie);
+ rc = syncrepl_updateCookie( si, op, &syncCookie);
}
}
int rc = LDAP_SUCCESS;
int dostop = 0;
ber_socket_t s;
- int i, defer = 1, fail = 0;
+ int i, defer = 1, fail = 0, freeinfo = 0;
Backend *be;
- Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
-
if ( si == NULL )
return NULL;
+ if ( slapd_shutdown )
+ return NULL;
+
+ Debug( LDAP_DEBUG_TRACE, "=>do_syncrepl %s\n", si->si_ridtxt, 0, 0 );
- /* There will never be more than one instance active */
- ldap_pvt_thread_mutex_lock( &si->si_mutex );
+ /* Don't get stuck here while a pause is initiated */
+ while ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
+ if ( slapd_shutdown )
+ return NULL;
+ if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
+ ldap_pvt_thread_yield();
+ }
+
+ if ( si->si_ctype < 1 ) {
+ goto deleted;
+ }
switch( abs( si->si_type ) ) {
case LDAP_SYNC_REFRESH_ONLY:
connection_fake_init( &conn, &opbuf, ctx );
op = &opbuf.ob_op;
- /* use global malloc for now */
- op->o_tmpmemctx = NULL;
- op->o_tmpmfuncs = &ch_mfuncs;
-
op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
be = si->si_be;
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 );
+ si->si_wbe = top_be;
else
si->si_wbe = be;
} else {
si->si_wbe = be;
}
+ if ( SLAP_SYNC_SUBENTRY( si->si_wbe )) {
+ build_new_dn( &si->si_contextdn, &si->si_wbe->be_nsuffix[0],
+ (struct berval *)&slap_ldapsync_cn_bv, NULL );
+ } else {
+ si->si_contextdn = si->si_wbe->be_nsuffix[0];
+ }
}
if ( !si->si_schemachecking )
op->o_no_schema_check = 1;
goto reload;
}
+deleted:
/* We got deleted while running on cn=config */
- if ( !si->si_ctype ) {
+ if ( si->si_ctype < 1 ) {
+ if ( si->si_ctype == -1 ) {
+ si->si_ctype = 0;
+ freeinfo = 1;
+ }
if ( si->si_conn )
dostop = 1;
rc = -1;
break;
}
- if ( !si->si_ctype
+ if ( si->si_ctype < 1
|| !si->si_retrynum || si->si_retrynum[i] == RETRYNUM_TAIL ) {
if ( si->si_re ) {
ldap_pvt_runqueue_remove( &slapd_rq, rtask );
if ( rc ) {
if ( fail == RETRYNUM_TAIL ) {
Debug( LDAP_DEBUG_ANY,
- "do_syncrepl: %s quitting\n",
- si->si_ridtxt, 0, 0 );
+ "do_syncrepl: %s rc %d quitting\n",
+ si->si_ridtxt, rc, 0 );
} else if ( fail > 0 ) {
Debug( LDAP_DEBUG_ANY,
- "do_syncrepl: %s retrying (%d retries left)\n",
- si->si_ridtxt, fail, 0 );
+ "do_syncrepl: %s rc %d retrying (%d retries left)\n",
+ si->si_ridtxt, rc, fail );
} else {
Debug( LDAP_DEBUG_ANY,
- "do_syncrepl: %s retrying\n",
- si->si_ridtxt, 0, 0 );
+ "do_syncrepl: %s rc %d retrying\n",
+ si->si_ridtxt, rc, 0 );
}
}
/* Do final delete cleanup */
- if ( !si->si_ctype ) {
- cookie_state *cs = si->si_cookieState;
- syncinfo_free( si, ( !be->be_syncinfo ||
- be->be_syncinfo->si_cookieState != cs ));
+ if ( freeinfo ) {
+ syncinfo_free( si, 0 );
}
return NULL;
}
prdn = BER_BVNULL, nrdn = BER_BVNULL,
psup = BER_BVNULL, nsup = BER_BVNULL;
int rc, deleteOldRdn = 0, freeReqDn = 0;
+ int do_graduate = 0;
if ( ldap_msgtype( msg ) != LDAP_RES_SEARCH_ENTRY ) {
Debug( LDAP_DEBUG_ANY, "syncrepl_message_to_op: %s "
op->o_tag = LBER_DEFAULT;
op->o_bd = si->si_wbe;
+ if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_op: %s got empty dn",
+ si->si_ridtxt, 0, 0 );
+ return LDAP_OTHER;
+ }
+
while (( rc = ldap_get_attribute_ber( si->si_ld, msg, ber, &bv, &bvals ) )
== LDAP_SUCCESS ) {
if ( bv.bv_val == NULL )
if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
bdn = bvals[0];
- dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_op: %s "
+ "dn \"%s\" normalization failed (%d)",
+ si->si_ridtxt, bdn.bv_val, rc );
+ rc = -1;
+ ch_free( bvals );
+ goto done;
+ }
ber_dupbv( &op->o_req_dn, &dn );
ber_dupbv( &op->o_req_ndn, &ndn );
slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
&slap_schema.si_ad_entryCSN->ad_cname ) )
{
slap_queue_csn( op, bvals );
+ do_graduate = 1;
}
ch_free( bvals );
}
Debug( LDAP_DEBUG_SYNC,
"syncrepl_message_to_op: %s be_add %s (%d)\n",
si->si_ridtxt, op->o_req_dn.bv_val, rc );
+ do_graduate = 0;
}
if ( e == op->ora_e )
be_entry_release_w( op, op->ora_e );
"syncrepl_message_to_op: %s be_modify %s (%d)\n",
si->si_ridtxt, op->o_req_dn.bv_val, rc );
op->o_bd = si->si_be;
+ do_graduate = 0;
}
break;
case LDAP_REQ_MODRDN:
Debug( rc ? LDAP_DEBUG_ANY : LDAP_DEBUG_SYNC,
"syncrepl_message_to_op: %s be_modrdn %s (%d)\n",
si->si_ridtxt, op->o_req_dn.bv_val, rc );
+ do_graduate = 0;
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: %s be_delete %s (%d)\n",
si->si_ridtxt, op->o_req_dn.bv_val, rc );
+ do_graduate = 0;
break;
}
done:
- slap_graduate_commit_csn( op );
+ if ( do_graduate )
+ slap_graduate_commit_csn( op );
op->o_bd = si->si_be;
op->o_tmpfree( op->o_csn.bv_val, op->o_tmpmemctx );
BER_BVZERO( &op->o_csn );
return rc;
}
+ if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_entry: %s got empty dn",
+ si->si_ridtxt, 0, 0 );
+ return LDAP_OTHER;
+ }
+
if ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_DELETE ) {
/* NOTE: this could be done even before decoding the DN,
* although encoding errors wouldn't be detected */
return -1;
}
- dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
+ if ( rc != LDAP_SUCCESS ) {
+ /* One of the things that could happen is that the schema
+ * is not lined-up; this could result in unknown attributes.
+ * A value non conformant to the syntax should be unlikely,
+ * except when replicating between different versions
+ * of the software, or when syntax validation bugs are fixed
+ */
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_message_to_entry: "
+ "%s dn \"%s\" normalization failed (%d)",
+ si->si_ridtxt, bdn.bv_val, rc );
+ return rc;
+ }
+
ber_dupbv( &op->o_req_dn, &dn );
ber_dupbv( &op->o_req_ndn, &ndn );
slap_sl_free( ndn.bv_val, op->o_tmpmemctx );
rc = op->o_bd->be_add( op, &rs_add );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: %s be_add (%d)\n",
- si->si_ridtxt, rc, 0 );
+ "syncrepl_entry: %s be_add %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
switch ( rs_add.sr_err ) {
case LDAP_SUCCESS:
if ( op->ora_e == entry ) {
default:
Debug( LDAP_DEBUG_ANY,
- "syncrepl_entry: %s be_add failed (%d)\n",
- si->si_ridtxt, rs_add.sr_err, 0 );
+ "syncrepl_entry: %s be_add %s failed (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rs_add.sr_err );
break;
}
+ syncCSN = NULL;
op->o_bd = be;
goto done;
}
break;
}
}
+ if ( !mod->sml_numvals ) {
+ /* Drop this op */
+ *ml = mod->sml_next;
+ mod->sml_next = NULL;
+ slap_mods_free( mod, 1 );
+ }
break;
}
}
}
}
}
-
+
/* RDNs must be NUL-terminated for back-ldap */
noldp = op->orr_newrdn;
ber_dupbv_x( &op->orr_newrdn, &noldp, op->o_tmpmemctx );
slap_mods_free( op->orr_modlist, 1 );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: %s be_modrdn (%d)\n",
- si->si_ridtxt, rc, 0 );
+ "syncrepl_entry: %s be_modrdn %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
op->o_bd = be;
/* Renamed entries may still have other mods so just fallthru */
op->o_req_dn = entry->e_name;
op->o_req_ndn = entry->e_nname;
/* Use CSN on the modify */
- if ( syncCSN && !just_rename )
+ if ( just_rename )
+ syncCSN = NULL;
+ else if ( syncCSN )
slap_queue_csn( op, syncCSN );
}
if ( dni.mods ) {
slap_mods_free( op->orm_modlist, 1 );
op->orm_no_opattrs = 0;
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: %s be_modify (%d)\n",
- si->si_ridtxt, rc, 0 );
+ "syncrepl_entry: %s be_modify %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
if ( rs_modify.sr_err != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"syncrepl_entry: %s be_modify failed (%d)\n",
si->si_ridtxt, rs_modify.sr_err, 0 );
}
+ syncCSN = NULL;
op->o_bd = be;
} else if ( !dni.renamed ) {
Debug( LDAP_DEBUG_SYNC,
"syncrepl_entry: %s entry unchanged, ignored (%s)\n",
si->si_ridtxt, op->o_req_dn.bv_val, 0 );
+ if ( syncCSN ) {
+ slap_graduate_commit_csn( op );
+ syncCSN = NULL;
+ }
}
goto done;
case LDAP_SYNC_DELETE :
op->o_bd = si->si_wbe;
rc = op->o_bd->be_delete( op, &rs_delete );
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: %s be_delete (%d)\n",
- si->si_ridtxt, rc, 0 );
+ "syncrepl_entry: %s be_delete %s (%d)\n",
+ si->si_ridtxt, op->o_req_dn.bv_val, rc );
while ( rs_delete.sr_err == LDAP_SUCCESS
&& op->o_delete_glue_parent ) {
break;
}
}
+ syncCSN = NULL;
op->o_bd = be;
}
goto done;
syncrepl_updateCookie(
syncinfo_t *si,
Operation *op,
- struct berval *pdn,
struct sync_cookie *syncCookie )
{
Backend *be = op->o_bd;
cb.sc_private = si;
op->o_callback = &cb;
- op->o_req_dn = op->o_bd->be_suffix[0];
- op->o_req_ndn = op->o_bd->be_nsuffix[0];
+ op->o_req_dn = si->si_contextdn;
+ op->o_req_ndn = si->si_contextdn;
/* update contextCSN */
op->o_dont_replicate = 1;
op->orm_modlist = &mod;
op->orm_no_opattrs = 1;
rc = op->o_bd->be_modify( op, &rs_modify );
+
+ if ( rs_modify.sr_err == LDAP_NO_SUCH_OBJECT &&
+ SLAP_SYNC_SUBENTRY( op->o_bd )) {
+ const char *text;
+ char txtbuf[SLAP_TEXT_BUFLEN];
+ size_t textlen = sizeof txtbuf;
+ Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
+ rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
+ op->ora_e = e;
+ rc = op->o_bd->be_add( op, &rs_modify );
+ if ( e == op->ora_e )
+ be_entry_release_w( op, op->ora_e );
+ }
+
op->orm_no_opattrs = 0;
op->o_dont_replicate = 0;
return rc;
}
+/* Compare the attribute from the old entry to the one in the new
+ * entry. The Modifications from the new entry will either be left
+ * in place, or changed to an Add or Delete as needed.
+ */
static void
attr_cmp( Operation *op, Attribute *old, Attribute *new,
Modifications ***mret, Modifications ***mcur )
*mret = modtail;
}
+/* Generate a set of modifications to change the old entry into the
+ * new one. On input ml is a list of modifications equivalent to
+ * the new entry. It will be massaged and the result will be stored
+ * in mods.
+ */
+void syncrepl_diff_entry( Operation *op, Attribute *old, Attribute *new,
+ Modifications **mods, Modifications **ml, int is_ctx)
+{
+ Modifications **modtail = mods;
+
+ /* We assume that attributes are saved in the same order
+ * in the remote and local databases. So if we walk through
+ * the attributeDescriptions one by one they should match in
+ * lock step. If not, look for an add or delete.
+ */
+ while ( old && new )
+ {
+ /* If we've seen this before, use its mod now */
+ if ( new->a_flags & SLAP_ATTR_IXADD ) {
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ new = new->a_next;
+ continue;
+ }
+ /* Skip contextCSN */
+ if ( is_ctx && old->a_desc ==
+ slap_schema.si_ad_contextCSN ) {
+ old = old->a_next;
+ continue;
+ }
+
+ if ( old->a_desc != new->a_desc ) {
+ Modifications *mod;
+ Attribute *tmp;
+
+ /* If it's just been re-added later,
+ * remember that we've seen it.
+ */
+ tmp = attr_find( new, old->a_desc );
+ if ( tmp ) {
+ tmp->a_flags |= SLAP_ATTR_IXADD;
+ } else {
+ /* If it's a new attribute, pull it in.
+ */
+ tmp = attr_find( old, new->a_desc );
+ if ( !tmp ) {
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ new = new->a_next;
+ continue;
+ }
+ /* Delete old attr */
+ mod = ch_malloc( sizeof( Modifications ) );
+ mod->sml_op = LDAP_MOD_DELETE;
+ mod->sml_flags = 0;
+ mod->sml_desc = old->a_desc;
+ mod->sml_type = mod->sml_desc->ad_cname;
+ mod->sml_numvals = 0;
+ mod->sml_values = NULL;
+ mod->sml_nvalues = NULL;
+ *modtail = mod;
+ modtail = &mod->sml_next;
+ }
+ old = old->a_next;
+ continue;
+ }
+ /* kludge - always update modifiersName so that it
+ * stays co-located with the other mod opattrs. But only
+ * if we know there are other valid mods.
+ */
+ if ( *mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
+ old->a_desc == slap_schema.si_ad_modifyTimestamp ))
+ attr_cmp( op, NULL, new, &modtail, &ml );
+ else
+ attr_cmp( op, old, new, &modtail, &ml );
+ new = new->a_next;
+ old = old->a_next;
+ }
+ *modtail = *ml;
+ *ml = NULL;
+}
+
static int
dn_callback(
Operation* op,
* is actually newer than old entry
*/
if ( !is_entry_glue( rs->sr_entry )) {
- old = attr_find( rs->sr_entry->e_attrs,
- slap_schema.si_ad_objectClass );
old = attr_find( rs->sr_entry->e_attrs,
slap_schema.si_ad_entryCSN );
new = attr_find( dni->new_entry->e_attrs,
*/
}
- modtail = &dni->mods;
- ml = dni->modlist;
-
- /* We assume that attributes are saved in the same order
- * in the remote and local databases. So if we walk through
- * the attributeDescriptions one by one they should match in
- * lock step. If not, look for an add or delete.
- */
- for ( old = rs->sr_entry->e_attrs, new = dni->new_entry->e_attrs;
- old && new; )
- {
- /* If we've seen this before, use its mod now */
- if ( new->a_flags & SLAP_ATTR_IXADD ) {
- attr_cmp( op, NULL, new, &modtail, &ml );
- new = new->a_next;
- continue;
- }
- /* Skip contextCSN */
- if ( is_ctx && old->a_desc ==
- slap_schema.si_ad_contextCSN ) {
- old = old->a_next;
- continue;
- }
-
- if ( old->a_desc != new->a_desc ) {
- Modifications *mod;
- Attribute *tmp;
-
- /* If it's just been re-added later,
- * remember that we've seen it.
- */
- tmp = attr_find( new, old->a_desc );
- if ( tmp ) {
- tmp->a_flags |= SLAP_ATTR_IXADD;
- } else {
- /* If it's a new attribute, pull it in.
- */
- tmp = attr_find( old, new->a_desc );
- if ( !tmp ) {
- attr_cmp( op, NULL, new, &modtail, &ml );
- new = new->a_next;
- continue;
- }
- /* Delete old attr */
- mod = ch_malloc( sizeof( Modifications ) );
- mod->sml_op = LDAP_MOD_DELETE;
- mod->sml_flags = 0;
- mod->sml_desc = old->a_desc;
- mod->sml_type = mod->sml_desc->ad_cname;
- mod->sml_numvals = 0;
- mod->sml_values = NULL;
- mod->sml_nvalues = NULL;
- *modtail = mod;
- modtail = &mod->sml_next;
- }
- old = old->a_next;
- continue;
- }
- /* kludge - always update modifiersName so that it
- * stays co-located with the other mod opattrs. But only
- * if we know there are other valid mods.
- */
- if ( dni->mods && ( old->a_desc == slap_schema.si_ad_modifiersName ||
- old->a_desc == slap_schema.si_ad_modifyTimestamp ))
- attr_cmp( op, NULL, new, &modtail, &ml );
- else
- attr_cmp( op, old, new, &modtail, &ml );
- new = new->a_next;
- old = old->a_next;
- }
- *modtail = *ml;
- *ml = NULL;
+ syncrepl_diff_entry( op, rs->sr_entry->e_attrs,
+ dni->new_entry->e_attrs, &dni->mods, dni->modlist,
+ is_ctx );
}
}
} else if ( rs->sr_type == REP_RESULT ) {
{
syncinfo_t *si_next;
- if ( free_all && sie->si_cookieState ) {
- ch_free( sie->si_cookieState->cs_sids );
- ber_bvarray_free( sie->si_cookieState->cs_vals );
- ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
- ch_free( sie->si_cookieState );
- }
+ Debug( LDAP_DEBUG_TRACE, "syncinfo_free: %s\n",
+ sie->si_ridtxt, 0, 0 );
+
do {
si_next = sie->si_next;
ldap_unbind_ext( sie->si_ld, NULL, NULL );
}
- /* 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_stoptask( &slapd_rq, sie->si_re );
- ldap_pvt_runqueue_remove( &slapd_rq, sie->si_re );
+ struct re_s *re = sie->si_re;
+ sie->si_re = NULL;
+
+ ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex );
+ if ( ldap_pvt_runqueue_isrunning( &slapd_rq, re ) )
+ ldap_pvt_runqueue_stoptask( &slapd_rq, re );
+ ldap_pvt_runqueue_remove( &slapd_rq, re );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
}
-
- ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
- ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
-
+
+ ldap_pvt_thread_mutex_destroy( &sie->si_mutex );
+
bindconf_free( &sie->si_bindconf );
-
+
if ( sie->si_filterstr.bv_val ) {
ch_free( sie->si_filterstr.bv_val );
}
if ( sie->si_logbase.bv_val ) {
ch_free( sie->si_logbase.bv_val );
}
+ if ( sie->si_be && SLAP_SYNC_SUBENTRY( sie->si_be )) {
+ ch_free( sie->si_contextdn.bv_val );
+ }
if ( sie->si_attrs ) {
int i = 0;
while ( sie->si_attrs[i] != NULL ) {
}
ch_free( npe );
}
+ if ( sie->si_cookieState ) {
+ sie->si_cookieState->cs_ref--;
+ if ( !sie->si_cookieState->cs_ref ) {
+ ch_free( sie->si_cookieState->cs_sids );
+ ber_bvarray_free( sie->si_cookieState->cs_vals );
+ ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_mutex );
+ ch_free( sie->si_cookieState->cs_psids );
+ ber_bvarray_free( sie->si_cookieState->cs_pvals );
+ ldap_pvt_thread_mutex_destroy( &sie->si_cookieState->cs_pmutex );
+ ch_free( sie->si_cookieState );
+ }
+ }
ch_free( sie );
sie = si_next;
} while ( free_all && si_next );
GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
};
-static struct {
- struct berval key;
- int val;
-} scopes[] = {
- { BER_BVC("base"), LDAP_SCOPE_BASE },
- { BER_BVC("one"), LDAP_SCOPE_ONELEVEL },
- { BER_BVC("onelevel"), LDAP_SCOPE_ONELEVEL }, /* OpenLDAP extension */
- { BER_BVC("children"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("subord"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("subordinate"), LDAP_SCOPE_SUBORDINATE },
- { BER_BVC("sub"), LDAP_SCOPE_SUBTREE },
- { BER_BVC("subtree"), LDAP_SCOPE_SUBTREE }, /* OpenLDAP extension */
- { BER_BVNULL, 0 }
-};
-
static slap_verbmasks datamodes[] = {
{ BER_BVC("default"), SYNCDATA_DEFAULT },
{ BER_BVC("accesslog"), SYNCDATA_ACCESSLOG },
}
}
}
+ if ( j < 1 || si->si_retrynum_init[j-1] != RETRYNUM_FOREVER ) {
+ Debug( LDAP_DEBUG_CONFIG,
+ "%s: syncrepl will eventually stop retrying; the \"retry\" parameter should end with a '+'.\n",
+ c->log, 0, 0 );
+ }
+
si->si_retrynum_init[j] = RETRYNUM_TAIL;
si->si_retrynum[j] = RETRYNUM_TAIL;
si->si_retryinterval[j] = 0;
{
int j;
val = c->argv[ i ] + STRLENOF( SCOPESTR "=" );
- for ( j = 0; !BER_BVISNULL(&scopes[j].key); j++ ) {
- if (!strcasecmp( val, scopes[j].key.bv_val ) ) {
- si->si_scope = scopes[j].val;
- break;
- }
- }
- if ( BER_BVISNULL(&scopes[j].key) ) {
+ j = ldap_pvt_str2scope( val );
+ if ( j < 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
"unknown scope \"%s\"", val);
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
+ si->si_scope = j;
si->si_got |= GOT_SCOPE;
} else if ( !strncasecmp( c->argv[ i ], ATTRSONLYSTR,
STRLENOF( ATTRSONLYSTR ) ) )
rc = parse_syncrepl_line( c, si );
if ( rc == 0 ) {
+ LDAPURLDesc *lud;
+
/* Must be LDAPv3 because we need controls */
switch ( si->si_bindconf.sb_version ) {
case 0:
return 1;
}
+ if ( ldap_url_parse( si->si_bindconf.sb_uri.bv_val, &lud )) {
+ snprintf( c->cr_msg, sizeof( c->cr_msg ),
+ "<%s> invalid URL", c->argv[0] );
+ Debug( LDAP_DEBUG_ANY, "%s: %s %s\n",
+ c->log, c->cr_msg, si->si_bindconf.sb_uri.bv_val );
+ return 1;
+ }
+
si->si_be = c->be;
if ( slapMode & SLAP_SERVER_MODE ) {
- Listener **l = slapd_get_listeners();
int isMe = 0;
-
- /* check if URL points to current server. If so, ignore
- * this configuration. We require an exact match. Just
- * in case they really want to do this, they can vary
- * the case of the URL to allow it.
+ /* check if consumer points to current server and database.
+ * If so, ignore this configuration.
*/
- if ( l && !SLAP_DBHIDDEN( c->be ) ) {
+ if ( !SLAP_DBHIDDEN( c->be ) ) {
int i;
- for ( i=0; l[i]; i++ ) {
- if ( bvmatch( &l[i]->sl_url, &si->si_bindconf.sb_uri ) ) {
+ /* if searchbase doesn't match current DB suffix,
+ * assume it's different
+ */
+ for ( i=0; !BER_BVISNULL( &c->be->be_nsuffix[i] ); i++ ) {
+ if ( bvmatch( &si->si_base, &c->be->be_nsuffix[i] )) {
isMe = 1;
break;
}
}
+ /* if searchbase matches, see if URLs match */
+ if ( isMe && config_check_my_url( si->si_bindconf.sb_uri.bv_val,
+ lud ) == NULL )
+ isMe = 0;
}
if ( !isMe ) {
/* mirrormode still needs to see this flag in tool mode */
rc = config_sync_shadow( c ) ? -1 : 0;
}
+ ldap_free_urldesc( lud );
}
#ifdef HAVE_TLS
si->si_cookieState = c->be->be_syncinfo->si_cookieState;
- // add new syncrepl to end of list (same order as when deleting)
+ /* add new syncrepl to end of list (same order as when deleting) */
for ( sip = c->be->be_syncinfo; sip->si_next; sip = sip->si_next );
sip->si_next = si;
} else {
si->si_cookieState = ch_calloc( 1, sizeof( cookie_state ));
ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_mutex );
+ ldap_pvt_thread_mutex_init( &si->si_cookieState->cs_pmutex );
c->be->be_syncinfo = si;
}
+ si->si_cookieState->cs_ref++;
si->si_next = NULL;
static void
syncrepl_unparse( syncinfo_t *si, struct berval *bv )
{
- struct berval bc, uri;
+ struct berval bc, uri, bs;
char buf[BUFSIZ*2], *ptr;
ber_len_t len;
int i;
ptr = lutil_strcopy( ptr, si->si_logbase.bv_val );
*ptr++ = '"';
}
- for (i=0; !BER_BVISNULL(&scopes[i].key);i++) {
- if ( si->si_scope == scopes[i].val ) {
- if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + scopes[i].key.bv_len ) return;
- ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
- ptr = lutil_strcopy( ptr, scopes[i].key.bv_val );
- break;
- }
+ if ( ldap_pvt_scope2bv( si->si_scope, &bs ) == LDAP_SUCCESS ) {
+ if ( WHATSLEFT <= STRLENOF( " " SCOPESTR "=" ) + bs.bv_len ) return;
+ ptr = lutil_strcopy( ptr, " " SCOPESTR "=" );
+ ptr = lutil_strcopy( ptr, bs.bv_val );
}
if ( si->si_attrsonly ) {
if ( WHATSLEFT <= STRLENOF( " " ATTRSONLYSTR "=\"" "\"" ) ) return;
}
return 1;
} else if ( c->op == LDAP_MOD_DELETE ) {
- cookie_state *cs = NULL;
int isrunning = 0;
if ( c->be->be_syncinfo ) {
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 ) {
if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
isrunning = 1;
} else {
+ if ( si->si_conn ) {
+ /* If there's a persistent connection, it may
+ * already have a thread queued. We know it's
+ * not active, so it must be pending and we
+ * can simply cancel it now.
+ */
+ ldap_pvt_thread_pool_retract( &connection_pool,
+ si->si_re->routine, si->si_re );
+ }
ldap_pvt_thread_mutex_unlock( &si->si_mutex );
}
}
- if ( si->si_re && isrunning ) {
- si->si_ctype = 0;
+ if ( isrunning ) {
+ si->si_ctype = -1;
si->si_next = NULL;
} else {
syncinfo_free( si, 0 );
}
if ( !c->be->be_syncinfo ) {
SLAP_DBFLAGS( c->be ) &= ~SLAP_DBFLAG_SHADOW_MASK;
- if ( cs && !isrunning ) {
- ch_free( cs->cs_sids );
- ber_bvarray_free( cs->cs_vals );
- ldap_pvt_thread_mutex_destroy( &cs->cs_mutex );
- ch_free( cs );
- }
}
return 0;
}