/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2003-2009 The OpenLDAP Foundation.
+ * Copyright 2003-2010 The OpenLDAP Foundation.
* Portions Copyright 2003 by IBM Corporation.
* Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
* All rights reserved.
struct berval si_base;
struct berval si_logbase;
struct berval si_filterstr;
+ Filter *si_filter;
struct berval si_logfilterstr;
struct berval si_contextdn;
int si_scope;
struct sync_cookie * );
static struct berval * slap_uuidstr_from_normalized(
struct berval *, struct berval *, void * );
+static int syncrepl_add_glue_ancestors(
+ Operation* op, Entry *e );
/* callback functions */
static int dn_callback( Operation *, SlapReply * );
Modifications *modlist = NULL;
- int match, m, punlock = 0;
+ int match, m, punlock = -1;
struct timeval *tout_p = NULL;
struct timeval tout = { 0, 0 };
ldap_get_entry_controls( si->si_ld, msg, &rctrls );
/* we can't work without the control */
if ( rctrls ) {
- LDAPControl **next;
+ LDAPControl **next = NULL;
/* NOTE: make sure we use the right one;
* a better approach would be to run thru
* the whole list and take care of all */
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",
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s\n",
si->si_ridtxt, syncCookie.ctxcsn->bv_val, 0 );
ldap_controls_free( rctrls );
rc = 0;
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;
+ punlock = i;
}
op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
rc = syncrepl_updateCookie( si, op, &syncCookie );
}
}
- if ( punlock );
+ if ( punlock >= 0 ) {
+ /* on failure, revert pending CSN */
+ if ( rc != LDAP_SUCCESS ) {
+ int i;
+ for ( i = 0; i<si->si_cookieState->cs_num; i++ ) {
+ if ( si->si_cookieState->cs_sids[i] == si->si_cookieState->cs_psids[punlock] ) {
+ ber_bvreplace( &si->si_cookieState->cs_pvals[punlock],
+ &si->si_cookieState->cs_vals[i] );
+ break;
+ }
+ }
+ if ( i == si->si_cookieState->cs_num )
+ si->si_cookieState->cs_pvals[punlock].bv_val[0] = '\0';
+ }
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
+ }
ldap_controls_free( rctrls );
if ( modlist ) {
slap_mods_free( modlist, 1 );
si->si_ridtxt, err, ldap_err2string( err ) );
}
if ( rctrls ) {
- LDAPControl **next;
+ LDAPControl **next = NULL;
/* NOTE: make sure we use the right one;
* a better approach would be to run thru
* the whole list and take care of all */
connection_fake_init( &conn, &opbuf, ctx );
op = &opbuf.ob_op;
/* o_connids must be unique for slap_graduate_commit_csn */
- op->o_connid = -1000 - si->si_rid;
+ op->o_connid = SLAPD_SYNC_RID2SYNCCONN(si->si_rid);
op->o_managedsait = SLAP_CONTROL_NONCRITICAL;
be = si->si_be;
si->si_refreshDelete = 0;
si->si_refreshPresent = 0;
+ if ( si->si_presentlist ) {
+ avl_free( si->si_presentlist, ch_free );
+ si->si_presentlist = NULL;
+ }
+
/* use main DB when retrieving contextCSN */
op->o_bd = si->si_wbe;
op->o_dn = op->o_bd->be_rootdn;
{ BER_BVNULL, 0 }
};
-static Modifications *
+static int
syncrepl_accesslog_mods(
syncinfo_t *si,
- struct berval *vals
+ struct berval *vals,
+ struct Modifications **modres
)
{
char *colon;
struct berval bv, bv2;
short op;
Modifications *mod = NULL, *modlist = NULL, **modtail;
- int i;
+ int i, rc = 0;
modtail = &modlist;
bv.bv_len = colon - bv.bv_val;
if ( slap_bv2ad( &bv, &ad, &text ) ) {
/* Invalid */
- continue;
+ Debug( LDAP_DEBUG_ANY, "syncrepl_accesslog_mods: %s "
+ "Invalid attribute %s, %s\n",
+ si->si_ridtxt, bv.bv_val, text );
+ slap_mods_free( modlist, 1 );
+ modlist = NULL;
+ rc = -1;
+ break;
}
/* Ignore dynamically generated attrs */
mod->sml_numvals++;
}
}
- return modlist;
+ *modres = modlist;
+ return rc;
}
-static Modifications *
+static int
syncrepl_changelog_mods(
syncinfo_t *si,
- struct berval *vals
+ struct berval *vals,
+ struct Modifications **modres
)
{
- return NULL; /* FIXME */
+ return -1; /* FIXME */
}
static int
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_mod ) ) {
/* Parse attribute into modlist */
if ( si->si_syncdata == SYNCDATA_ACCESSLOG ) {
- modlist = syncrepl_accesslog_mods( si, bvals );
+ rc = syncrepl_accesslog_mods( si, bvals, &modlist );
} else {
- modlist = syncrepl_changelog_mods( si, bvals );
+ rc = syncrepl_changelog_mods( si, bvals, &modlist );
}
+ if ( rc ) goto done;
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newRdn ) ) {
rdn = bvals[0];
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_delRdn ) ) {
mod->sml_next = m2;
}
op->o_bd = si->si_wbe;
+retry_modrdn:;
rc = op->o_bd->be_modrdn( op, &rs_modify );
+
+ /* 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 )) {
+ Operation op2 = *op;
+ rc = syncrepl_add_glue_ancestors( &op2, entry );
+ if ( rc == LDAP_SUCCESS ) {
+ goto retry_modrdn;
+ }
+ }
+
op->o_tmpfree( op->orr_nnewrdn.bv_val, op->o_tmpmemctx );
op->o_tmpfree( op->orr_newrdn.bv_val, op->o_tmpmemctx );
op->ors_tlimit = SLAP_NO_LIMIT;
op->ors_limit = NULL;
op->ors_attrsonly = 0;
- op->ors_filter = str2filter_x( op, si->si_filterstr.bv_val );
+ op->ors_filter = filter_dup( si->si_filter, op->o_tmpmemctx );
/* In multimaster, updates can continue to arrive while
* we're searching. Limit the search result to entries
* older than our newest cookie CSN.
return;
}
-int
-syncrepl_add_glue(
+static int
+syncrepl_add_glue_ancestors(
Operation* op,
Entry *e )
{
Backend *be = op->o_bd;
slap_callback cb = { NULL };
Attribute *a;
- int rc;
+ int rc = LDAP_SUCCESS;
int suffrdns;
int i;
struct berval dn = BER_BVNULL;
ndn.bv_len = e->e_nname.bv_len - (ndn.bv_val - e->e_nname.bv_val);
}
+ return rc;
+}
+
+int
+syncrepl_add_glue(
+ Operation* op,
+ Entry *e )
+{
+ slap_callback cb = { NULL };
+ int rc;
+ Backend *be = op->o_bd;
+ SlapReply rs_add = {REP_RESULT};
+
+ rc = syncrepl_add_glue_ancestors( op, e );
+ switch ( rc ) {
+ case LDAP_SUCCESS:
+ case LDAP_ALREADY_EXISTS:
+ break;
+
+ default:
+ return rc;
+ }
+
+ op->o_tag = LDAP_REQ_ADD;
+ op->o_callback = &cb;
+ cb.sc_response = null_callback;
+ cb.sc_private = NULL;
+
op->o_req_dn = e->e_name;
op->o_req_ndn = e->e_nname;
op->ora_e = e;
* Also use replace op if attr has no equality matching rule.
* (ITS#5781)
*/
- if ( nn && no < o &&
+ if ( ( nn || ( no > 0 && no < o ) ) &&
( old->a_desc == slap_schema.si_ad_objectClass ||
- !old->a_desc->ad_type->sat_equality ))
+ !old->a_desc->ad_type->sat_equality ) )
+ {
no = o;
+ }
i = j;
/* all old values were deleted, just use the replace op */
if ( sie->si_filterstr.bv_val ) {
ch_free( sie->si_filterstr.bv_val );
}
+ if ( sie->si_filter ) {
+ filter_free( sie->si_filter );
+ }
if ( sie->si_logfilterstr.bv_val ) {
ch_free( sie->si_logfilterstr.bv_val );
}
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
- if ( tmp > SLAP_SYNC_SID_MAX || tmp < 0 ) {
+ if ( tmp > SLAP_SYNC_RID_MAX || tmp < 0 ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error: parse_syncrepl_line: "
- "syncrepl id %d is out of range [0..4095]", tmp );
+ "syncrepl id %d is out of range [0..%d]", tmp, SLAP_SYNC_RID_MAX );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
{
val = c->argv[ i ] + STRLENOF( PROVIDERSTR "=" );
ber_str2bv( val, 0, 1, &si->si_bindconf.sb_uri );
+#ifdef HAVE_TLS
+ if ( ldap_is_ldaps_url( val ))
+ si->si_bindconf.sb_tls_do_init = 1;
+#endif
si->si_got |= GOT_PROVIDER;
} else if ( !strncasecmp( c->argv[ i ], SCHEMASTR "=",
STRLENOF( SCHEMASTR "=" ) ) )
}
}
+ si->si_filter = str2filter( si->si_filterstr.bv_val );
+ if ( si->si_filter == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse filter=\"%s\"\n",
+ si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_filterstr.bv_val );
+ return 1;
+ }
+
return 0;
}
return 1;
} else {
Debug( LDAP_DEBUG_CONFIG,
- "Config: ** successfully added syncrepl \"%s\"\n",
+ "Config: ** successfully added syncrepl %s \"%s\"\n",
+ si->si_ridtxt,
BER_BVISNULL( &si->si_bindconf.sb_uri ) ?
- "(null)" : si->si_bindconf.sb_uri.bv_val, 0, 0 );
+ "(null)" : si->si_bindconf.sb_uri.bv_val, 0 );
if ( c->be->be_syncinfo ) {
syncinfo_t *sip;
si->si_bindconf.sb_version = LDAP_VERSION3;
ptr = buf;
- assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_SID_MAX );
+ assert( si->si_rid >= 0 && si->si_rid <= SLAP_SYNC_RID_MAX );
len = snprintf( ptr, WHATSLEFT, IDSTR "=%03d " PROVIDERSTR "=%s",
si->si_rid, si->si_bindconf.sb_uri.bv_val );
if ( len >= sizeof( buf ) ) return;
si = *sip;
if ( c->valx == -1 || i == c->valx ) {
*sip = si->si_next;
+ si->si_ctype = -1;
+ si->si_next = NULL;
/* 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 ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
isrunning = 1;
} else {
+ /* There is no active thread, but we must still
+ * ensure that no thread is (or will be) queued
+ * while we removes the task.
+ */
+ struct re_s *re = si->si_re;
+ si->si_re = NULL;
+
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 );
+ connection_client_stop( si->si_conn );
+ si->si_conn = 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 );
+ isrunning = 1;
}
+ ldap_pvt_runqueue_remove( &slapd_rq, re );
+ ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
+
+ if ( ldap_pvt_thread_pool_retract( &connection_pool,
+ re->routine, re ) > 0 )
+ isrunning = 0;
+
ldap_pvt_thread_mutex_unlock( &si->si_mutex );
}
}
- if ( isrunning ) {
- si->si_ctype = -1;
- si->si_next = NULL;
- } else {
+ if ( !isrunning ) {
syncinfo_free( si, 0 );
}
if ( i == c->valx )