/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2003-2014 The OpenLDAP Foundation.
+ * Copyright 2003-2018 The OpenLDAP Foundation.
* Portions Copyright 2003 by IBM Corporation.
* Portions Copyright 2003-2008 by Howard Chu, Symas Corporation.
* All rights reserved.
#define SUFFIXM_CTX "<suffix massage>"
#endif
+#define UUIDLEN 16
+
struct nonpresent_entry {
struct berval *npe_name;
struct berval *npe_nname;
typedef struct cookie_state {
ldap_pvt_thread_mutex_t cs_mutex;
+ ldap_pvt_thread_cond_t cs_cond;
struct berval *cs_vals;
int *cs_sids;
int cs_num;
int cs_age;
int cs_ref;
+ int cs_updating;
/* pending changes, not yet committed */
ldap_pvt_thread_mutex_t cs_pmutex;
struct berval si_base;
struct berval si_logbase;
struct berval si_filterstr;
- Filter *si_filter;
struct berval si_logfilterstr;
+ Filter *si_filter;
+ Filter *si_logfilter;
struct berval si_contextdn;
int si_scope;
int si_attrsonly;
int si_refreshDelete;
int si_refreshPresent;
int si_refreshDone;
+ int si_refreshCount;
+ time_t si_refreshBeg;
+ time_t si_refreshEnd;
+ OpExtra *si_refreshTxn;
int si_syncdata;
int si_logstate;
+ int si_lazyCommit;
int si_got;
int si_strict_refresh; /* stop listening during fallback refresh */
int si_too_old;
} syncinfo_t;
static int syncuuid_cmp( const void *, const void * );
-static int avl_presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
+static int presentlist_insert( syncinfo_t* si, struct berval *syncUUID );
+static void presentlist_delete( Avlnode **av, struct berval *syncUUID );
+static char *presentlist_find( Avlnode *av, struct berval *syncUUID );
+static int presentlist_free( Avlnode *av );
static void syncrepl_del_nonpresent( Operation *, syncinfo_t *, BerVarray, struct sync_cookie *, int );
static int syncrepl_message_to_op(
syncinfo_t *, Operation *, LDAPMessage * );
struct berval *cookieCSN );
static int syncrepl_updateCookie(
syncinfo_t *, Operation *,
- struct sync_cookie * );
+ struct sync_cookie *, int save );
static struct berval * slap_uuidstr_from_normalized(
struct berval *, struct berval *, void * );
static int syncrepl_add_glue_ancestors(
/* callback functions */
static int dn_callback( Operation *, SlapReply * );
static int nonpresent_callback( Operation *, SlapReply * );
-static int null_callback( Operation *, SlapReply * );
static AttributeDescription *sync_descs[4];
struct berval ls_newRdn;
struct berval ls_delRdn;
struct berval ls_newSup;
+ struct berval ls_controls;
} logschema;
static logschema changelog_sc = {
BER_BVC("changes"),
BER_BVC("newRDN"),
BER_BVC("deleteOldRDN"),
- BER_BVC("newSuperior")
+ BER_BVC("newSuperior"),
+ BER_BVC("controls")
};
static logschema accesslog_sc = {
BER_BVC("reqMod"),
BER_BVC("reqNewRDN"),
BER_BVC("reqDeleteOldRDN"),
- BER_BVC("reqNewSuperior")
+ BER_BVC("reqNewSuperior"),
+ BER_BVC("reqControls")
};
static const char *
int rc;
int rhint;
char *base;
- char **attrs, *lattrs[8];
+ char **attrs, *lattrs[9];
char *filter;
int attrsonly;
int scope;
lattrs[3] = ls->ls_newRdn.bv_val;
lattrs[4] = ls->ls_delRdn.bv_val;
lattrs[5] = ls->ls_newSup.bv_val;
- lattrs[6] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
- lattrs[7] = NULL;
+ lattrs[6] = ls->ls_controls.bv_val;
+ lattrs[7] = slap_schema.si_ad_entryCSN->ad_cname.bv_val;
+ lattrs[8] = NULL;
rhint = 0;
base = si->si_logbase.bv_val;
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
}
+ 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 );
}
si->si_refreshDone = 0;
+ si->si_refreshBeg = slap_get_time();
+ si->si_refreshCount = 0;
+ si->si_refreshTxn = NULL;
+ Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s starting refresh\n",
+ si->si_ridtxt, 0, 0 );
rc = ldap_sync_search( si, op->o_tmpmemctx );
}
/* FIXME: what if syncUUID is NULL or empty?
* (happens with back-sql...) */
- if ( BER_BVISEMPTY( &syncUUID[0] ) ) {
+ if ( syncUUID[0].bv_len != UUIDLEN ) {
bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_ANY, "do_syncrep2: %s "
- "got empty syncUUID with LDAP_SYNC_%s (%s)\n",
+ "got empty or invalid syncUUID with LDAP_SYNC_%s (%s)\n",
si->si_ridtxt,
syncrepl_state2str( syncstate ), bdn.bv_val );
ldap_controls_free( rctrls );
}
punlock = -1;
if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) {
- ber_scanf( ber, /*"{"*/ "m}", &cookie );
+ if ( ber_scanf( ber, /*"{"*/ "m}", &cookie ) != LBER_ERROR ) {
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s cookie=%s\n",
si->si_ridtxt,
if ( syncCookie.ctxcsn ) {
int i, sid = slap_parse_csn_sid( syncCookie.ctxcsn );
check_syncprov( op, si );
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+#ifdef CHATTY_SYNCLOG
+ Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN for sid %d: %s\n",
+ si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
+#endif
/* new SID */
if ( sid < si->si_cookieState->cs_sids[i] )
break;
bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN too old, ignoring %s (%s)\n",
si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
+ si->si_too_old = 1;
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
ldap_controls_free( rctrls );
rc = 0;
- si->si_too_old = 1;
goto done;
}
si->si_too_old = 0;
break;
}
}
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+
/* check pending CSNs too */
while ( ldap_pvt_thread_mutex_trylock( &si->si_cookieState->cs_pmutex )) {
if ( slapd_shutdown ) {
if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool ))
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 ) {
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s CSN pending, ignoring %s (%s)\n",
si->si_ridtxt, syncCookie.ctxcsn->bv_val, bdn.bv_val );
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],
}
op->o_controls[slap_cids.sc_LDAPsync] = &syncCookie;
}
+ }
}
rc = 0;
if ( si->si_syncdata && si->si_logstate == SYNCLOG_LOGGING ) {
if ( ( rc = syncrepl_message_to_op( si, op, msg ) ) == LDAP_SUCCESS &&
syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
} 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, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie, 0 );
}
}
if ( punlock >= 0 ) {
/* on failure, revert pending CSN */
if ( rc != LDAP_SUCCESS ) {
int i;
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
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],
}
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_mutex );
}
ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_pmutex );
}
{
syncrepl_del_nonpresent( op, si, NULL,
&syncCookie, m );
- } else {
- avl_free( si->si_presentlist, ch_free );
+ } else if ( si->si_presentlist ) {
+ presentlist_free( si->si_presentlist );
si->si_presentlist = NULL;
}
}
if ( syncCookie.ctxcsn && match < 0 && err == LDAP_SUCCESS )
{
- rc = syncrepl_updateCookie( si, op, &syncCookie );
+ rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
}
+ if ( si->si_refreshCount ) {
+ LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+ op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+ si->si_refreshCount = 0;
+ si->si_refreshTxn = NULL;
+ }
+ si->si_refreshEnd = slap_get_time();
if ( err == LDAP_SUCCESS
&& si->si_logstate == SYNCLOG_FALLBACK ) {
si->si_logstate = SYNCLOG_LOGGING;
{
si->si_refreshDone = 1;
}
+ if ( si->si_refreshDone ) {
+ if ( si->si_refreshCount ) {
+ LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+ op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+ si->si_refreshCount = 0;
+ si->si_refreshTxn = NULL;
+ }
+ si->si_refreshEnd = slap_get_time();
+ Debug( LDAP_DEBUG_ANY, "do_syncrep1: %s finished refresh\n",
+ si->si_ridtxt, 0, 0 );
+ }
ber_scanf( ber, /*"{"*/ "}" );
if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
si->si_refreshDone )
ber_scanf( ber, "b", &refreshDeletes );
}
syncUUIDs = NULL;
- ber_scanf( ber, "[W]", &syncUUIDs );
+ rc = ber_scanf( ber, "[W]", &syncUUIDs );
ber_scanf( ber, /*"{"*/ "}" );
- if ( refreshDeletes ) {
- syncrepl_del_nonpresent( op, si, syncUUIDs,
- &syncCookie, m );
- ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
- } else {
- int i;
- for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
- (void)avl_presentlist_insert( si, &syncUUIDs[i] );
- slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+ if ( rc != LBER_ERROR ) {
+ if ( refreshDeletes ) {
+ syncrepl_del_nonpresent( op, si, syncUUIDs,
+ &syncCookie, m );
+ ber_bvarray_free_x( syncUUIDs, op->o_tmpmemctx );
+ } else {
+ int i;
+ for ( i = 0; !BER_BVISNULL( &syncUUIDs[i] ); i++ ) {
+ (void)presentlist_insert( si, &syncUUIDs[i] );
+ slap_sl_free( syncUUIDs[i].bv_val, op->o_tmpmemctx );
+ }
+ slap_sl_free( syncUUIDs, op->o_tmpmemctx );
}
- slap_sl_free( syncUUIDs, op->o_tmpmemctx );
}
+ rc = 0;
slap_sync_cookie_free( &syncCookie, 0 );
break;
default:
if ( syncCookie.ctxcsn )
{
- rc = syncrepl_updateCookie( si, op, &syncCookie);
+ rc = syncrepl_updateCookie( si, op, &syncCookie, 1 );
+ }
+ if ( si->si_presentlist ) {
+ presentlist_free( si->si_presentlist );
+ si->si_presentlist = NULL;
}
}
if ( ldap_pvt_thread_pool_pausing( &connection_pool )) {
slap_sync_cookie_free( &syncCookie, 0 );
slap_sync_cookie_free( &syncCookie_req, 0 );
+ if ( si->si_refreshCount ) {
+ LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+ op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+ si->si_refreshCount = 0;
+ si->si_refreshTxn = NULL;
+ }
return SYNC_PAUSED;
}
}
si->si_refreshPresent = 0;
if ( si->si_presentlist ) {
- avl_free( si->si_presentlist, ch_free );
+ presentlist_free( si->si_presentlist );
si->si_presentlist = NULL;
}
if ( !colon ) {
/* Invalid */
continue;
+ } else if ( colon == bv.bv_val ) {
+ /* ITS#6545: An empty attribute signals that a new mod
+ * is about to start */
+ mod = NULL;
+ continue;
}
bv.bv_len = colon - bv.bv_val;
if ( !mod )
return SLAP_CB_CONTINUE;
+ {
+ int i, sid;
+ sid = slap_parse_csn_sid( &mod->sml_nvalues[0] );
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ for ( i =0; i<si->si_cookieState->cs_num; i++ ) {
+#ifdef CHATTY_SYNCLOG
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s CSN for sid %d: %s\n",
+ si->si_ridtxt, i, si->si_cookieState->cs_vals[i].bv_val );
+#endif
+ /* new SID */
+ if ( sid < si->si_cookieState->cs_sids[i] )
+ break;
+ if ( si->si_cookieState->cs_sids[i] == sid ) {
+ if ( ber_bvcmp( &mod->sml_nvalues[0], &si->si_cookieState->cs_vals[i] ) <= 0 ) {
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_op_modify: %s entryCSN too old, ignoring %s (%s)\n",
+ si->si_ridtxt, mod->sml_nvalues[0].bv_val, op->o_req_dn.bv_val );
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ slap_graduate_commit_csn( op );
+ /* tell accesslog this was a failure */
+ rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
+ return LDAP_SUCCESS;
+ }
+ }
+ }
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+ }
+
rc = overlay_entry_get_ov( op, &op->o_req_ndn, NULL, NULL, 0, &e, on );
if ( rc == 0 ) {
Attribute *a;
overlay_entry_release_ov( op, e, 0, on );
}
/* equal? Should never happen */
- if ( match == 0 )
+ if ( match == 0 ) {
+ slap_graduate_commit_csn( op );
+ /* tell accesslog this was a failure */
+ rs->sr_err = LDAP_TYPE_OR_VALUE_EXISTS;
return LDAP_SUCCESS;
+ }
/* mod is older: resolve conflicts...
* 1. Save/copy original modlist. Split Replace to Del/Add.
if ( match < 0 ) {
Operation op2 = *op;
AttributeName an[2];
- const char *text;
struct berval bv;
- char *ptr;
- Modifications *ml;
- int size, rc;
+ int size;
SlapReply rs1 = {0};
resolve_ctxt rx;
slap_callback cb = { NULL, syncrepl_resolve_cb, NULL, NULL };
+ Filter lf[3] = {0};
+ AttributeAssertion aa[2] = {0};
rx.rx_si = si;
rx.rx_mods = newlist;
op2.ors_filterstr.bv_len = sprintf(op2.ors_filterstr.bv_val,
"(&(entryCSN>=%s)(reqDN=%s)%s)",
bv.bv_val, op->o_req_ndn.bv_val, si->si_logfilterstr.bv_val );
- op2.ors_filter = str2filter_x( op, op2.ors_filterstr.bv_val );
+
+ lf[0].f_choice = LDAP_FILTER_AND;
+ lf[0].f_and = lf+1;
+ lf[1].f_choice = LDAP_FILTER_GE;
+ lf[1].f_ava = aa;
+ lf[1].f_av_desc = slap_schema.si_ad_entryCSN;
+ lf[1].f_av_value = bv;
+ lf[1].f_next = lf+2;
+ lf[2].f_choice = LDAP_FILTER_EQUALITY;
+ lf[2].f_ava = aa+1;
+ lf[2].f_av_desc = ad_reqDN;
+ lf[2].f_av_value = op->o_req_ndn;
+ lf[2].f_next = si->si_logfilter;
+
+ op2.ors_filter = lf;
op2.o_callback = &cb;
op2.o_bd = select_backend( &op2.o_req_ndn, 1 );
sc->sc_private = mx;
sc->sc_next = op->o_callback;
sc->sc_cleanup = NULL;
+ sc->sc_writewait = NULL;
op->o_callback = sc;
op->orm_no_opattrs = 1;
mx->mx_orig = op->orm_modlist;
return SLAP_CB_CONTINUE;
}
+static int
+syncrepl_null_callback(
+ Operation *op,
+ SlapReply *rs )
+{
+ /* If we're not the last callback in the chain, move to the end */
+ if ( op->o_callback->sc_next ) {
+ slap_callback **sc, *s1;
+ s1 = op->o_callback;
+ op->o_callback = op->o_callback->sc_next;
+ for ( sc = &op->o_callback; *sc; sc = &(*sc)->sc_next ) ;
+ *sc = s1;
+ s1->sc_next = NULL;
+ return SLAP_CB_CONTINUE;
+ }
+ if ( rs->sr_err != LDAP_SUCCESS &&
+ rs->sr_err != LDAP_REFERRAL &&
+ rs->sr_err != LDAP_ALREADY_EXISTS &&
+ rs->sr_err != LDAP_NO_SUCH_OBJECT &&
+ rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
+ {
+ Debug( LDAP_DEBUG_ANY,
+ "syncrepl_null_callback : error code 0x%x\n",
+ rs->sr_err, 0, 0 );
+ }
+ return LDAP_SUCCESS;
+}
+
static int
syncrepl_message_to_op(
syncinfo_t *si,
Modifications *modlist = NULL;
logschema *ls;
SlapReply rs = { REP_RESULT };
- slap_callback cb = { NULL, null_callback, NULL, NULL };
+ slap_callback cb = { NULL, syncrepl_null_callback, NULL, NULL };
const char *text;
char txtbuf[SLAP_TEXT_BUFLEN];
}
} else if ( !ber_bvstrcasecmp( &bv, &ls->ls_newSup ) ) {
sup = bvals[0];
+ } else if ( !ber_bvstrcasecmp( &bv, &ls->ls_controls ) ) {
+ int i;
+ struct berval rel_ctrl_bv;
+
+ (void)ber_str2bv( "{" LDAP_CONTROL_RELAX, 0, 0, &rel_ctrl_bv );
+ for ( i = 0; bvals[i].bv_val; i++ ) {
+ struct berval cbv, tmp;
+
+ ber_bvchr_post( &cbv, &bvals[i], '}' );
+ ber_bvchr_post( &tmp, &cbv, '{' );
+ ber_bvchr_pre( &cbv, &tmp, ' ' );
+ if ( cbv.bv_len == tmp.bv_len ) /* control w/o value */
+ ber_bvchr_pre( &cbv, &tmp, '}' );
+ if ( !ber_bvcmp( &cbv, &rel_ctrl_bv ) )
+ op->o_relax = SLAP_CONTROL_CRITICAL;
+ }
} else if ( !ber_bvstrcasecmp( &bv,
&slap_schema.si_ad_entryCSN->ad_cname ) )
{
op->o_callback = &cb;
slap_op_time( &op->o_time, &op->o_tincr );
+ Debug( LDAP_DEBUG_SYNC, "syncrepl_message_to_op: %s tid %x\n",
+ si->si_ridtxt, op->o_tid, 0 );
+
switch( op->o_tag ) {
case LDAP_REQ_ADD:
case LDAP_REQ_MODIFY:
AttributeDescription *newDesc; /* for renames */
} dninfo;
+#define HASHUUID 1
+
/* return 1 if inserted, 0 otherwise */
static int
-avl_presentlist_insert(
+presentlist_insert(
syncinfo_t* si,
struct berval *syncUUID )
{
- struct berval *syncuuid_bv = ch_malloc( sizeof( struct berval ) + syncUUID->bv_len + 1 );
+ char *val;
+
+#ifdef HASHUUID
+ Avlnode **av;
+ unsigned short s;
+
+ if ( !si->si_presentlist )
+ si->si_presentlist = ch_calloc(65536, sizeof( Avlnode * ));
+
+ av = (Avlnode **)si->si_presentlist;
- syncuuid_bv->bv_len = syncUUID->bv_len;
- syncuuid_bv->bv_val = (char *)&syncuuid_bv[1];
- AC_MEMCPY( syncuuid_bv->bv_val, syncUUID->bv_val, syncUUID->bv_len );
- syncuuid_bv->bv_val[ syncuuid_bv->bv_len ] = '\0';
+ val = ch_malloc(UUIDLEN-2);
+ memcpy(&s, syncUUID->bv_val, 2);
+ memcpy(val, syncUUID->bv_val+2, UUIDLEN-2);
- if ( avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv,
+ if ( avl_insert( &av[s], val,
syncuuid_cmp, avl_dup_error ) )
{
- ch_free( syncuuid_bv );
+ ch_free( val );
return 0;
}
+#else
+ val = ch_malloc(UUIDLEN);
+
+ AC_MEMCPY( val, syncUUID->bv_val, UUIDLEN );
+
+ if ( avl_insert( &si->si_presentlist, val,
+ syncuuid_cmp, avl_dup_error ) )
+ {
+ ch_free( val );
+ return 0;
+ }
+#endif
return 1;
}
+static char *
+presentlist_find(
+ Avlnode *av,
+ struct berval *val )
+{
+#ifdef HASHUUID
+ Avlnode **a2 = (Avlnode **)av;
+ unsigned short s;
+
+ if (!av)
+ return NULL;
+
+ memcpy(&s, val->bv_val, 2);
+ return avl_find( a2[s], val->bv_val+2, syncuuid_cmp );
+#else
+ return avl_find( av, val->bv_val, syncuuid_cmp );
+#endif
+}
+
+static int
+presentlist_free( Avlnode *av )
+{
+#ifdef HASHUUID
+ Avlnode **a2 = (Avlnode **)av;
+ int i, count = 0;
+
+ if ( av ) {
+ for (i=0; i<65536; i++) {
+ if (a2[i])
+ count += avl_free( a2[i], ch_free );
+ }
+ ch_free( av );
+ }
+ return count;
+#else
+ return avl_free( av, ch_free );
+#endif
+}
+
+static void
+presentlist_delete(
+ Avlnode **av,
+ struct berval *val )
+{
+#ifdef HASHUUID
+ Avlnode **a2 = *(Avlnode ***)av;
+ unsigned short s;
+
+ memcpy(&s, val->bv_val, 2);
+ avl_delete( &a2[s], val->bv_val+2, syncuuid_cmp );
+#else
+ avl_delete( av, val->bv_val, syncuuid_cmp );
+#endif
+}
+
static int
syncrepl_entry(
syncinfo_t* si,
int freecsn = 1;
Debug( LDAP_DEBUG_SYNC,
- "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s)\n",
- si->si_ridtxt, syncrepl_state2str( syncstate ), 0 );
+ "syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) tid %x\n",
+ si->si_ridtxt, syncrepl_state2str( syncstate ), op->o_tid );
if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
if ( !si->si_refreshPresent && !si->si_refreshDone ) {
- syncuuid_inserted = avl_presentlist_insert( si, syncUUID );
+ syncuuid_inserted = presentlist_insert( si, syncUUID );
}
}
slap_sl_free( op->ors_filterstr.bv_val, op->o_tmpmemctx );
}
- cb.sc_response = null_callback;
+ cb.sc_response = syncrepl_null_callback;
cb.sc_private = si;
if ( entry && !BER_BVISNULL( &entry->e_name ) ) {
slap_queue_csn( op, syncCSN );
}
+ if ( !si->si_refreshDone ) {
+ if ( si->si_lazyCommit )
+ op->o_lazyCommit = SLAP_CONTROL_NONCRITICAL;
+ if ( si->si_refreshCount == 500 ) {
+ LDAP_SLIST_REMOVE( &op->o_extra, si->si_refreshTxn, OpExtra, oe_next );
+ op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_COMMIT, &si->si_refreshTxn );
+ si->si_refreshCount = 0;
+ si->si_refreshTxn = NULL;
+ }
+ if ( op->o_bd->bd_info->bi_op_txn ) {
+ if ( !si->si_refreshCount ) {
+ op->o_bd->bd_info->bi_op_txn( op, SLAP_TXN_BEGIN, &si->si_refreshTxn );
+ }
+ si->si_refreshCount++;
+ }
+ }
+
slap_op_time( &op->o_time, &op->o_tincr );
switch ( syncstate ) {
case LDAP_SYNC_ADD:
/* Something's wrong, start over */
ber_bvarray_free( si->si_syncCookie.ctxcsn );
si->si_syncCookie.ctxcsn = NULL;
+ entry_free( entry );
ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
ber_bvarray_free( si->si_cookieState->cs_vals );
ch_free( si->si_cookieState->cs_sids );
op->o_delete_glue_parent = 0;
if ( !be_issuffix( be, &op->o_req_ndn ) ) {
slap_callback cb = { NULL };
- cb.sc_response = slap_null_cb;
+ cb.sc_response = syncrepl_null_callback;
dnParent( &op->o_req_ndn, &pdn );
op->o_req_dn = pdn;
op->o_req_ndn = pdn;
np_list = LDAP_LIST_NEXT( np_list, npe_link );
op->o_tag = LDAP_REQ_DELETE;
op->o_callback = &cb;
- cb.sc_response = null_callback;
+ cb.sc_response = syncrepl_null_callback;
cb.sc_private = si;
op->o_req_dn = *np_prev->npe_name;
op->o_req_ndn = *np_prev->npe_nname;
op->o_delete_glue_parent = 0;
if ( !be_issuffix( be, &op->o_req_ndn ) ) {
slap_callback cb = { NULL };
- cb.sc_response = slap_null_cb;
+ cb.sc_response = syncrepl_null_callback;
dnParent( &op->o_req_ndn, &pdn );
op->o_req_dn = pdn;
op->o_req_ndn = pdn;
op->o_tag = LDAP_REQ_ADD;
op->o_callback = &cb;
- cb.sc_response = null_callback;
+ cb.sc_response = syncrepl_null_callback;
cb.sc_private = NULL;
dn = e->e_name;
op->o_tag = LDAP_REQ_ADD;
op->o_callback = &cb;
- cb.sc_response = null_callback;
+ cb.sc_response = syncrepl_null_callback;
cb.sc_private = NULL;
op->o_req_dn = e->e_name;
syncrepl_updateCookie(
syncinfo_t *si,
Operation *op,
- struct sync_cookie *syncCookie )
+ struct sync_cookie *syncCookie,
+ int save )
{
Backend *be = op->o_bd;
Modifications mod;
mod.sml_next = NULL;
ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
+ while ( si->si_cookieState->cs_updating )
+ ldap_pvt_thread_cond_wait( &si->si_cookieState->cs_cond, &si->si_cookieState->cs_mutex );
#ifdef CHECK_CSN
for ( i=0; i<syncCookie->numcsns; i++ ) {
ch_free( sc.sids );
return 0;
}
+
+ si->si_cookieState->cs_updating = 1;
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+
op->o_bd = si->si_wbe;
slap_queue_csn( op, &first );
op->o_tag = LDAP_REQ_MODIFY;
- cb.sc_response = null_callback;
+ cb.sc_response = syncrepl_null_callback;
cb.sc_private = si;
op->o_callback = &cb;
op->o_req_ndn = si->si_contextdn;
/* update contextCSN */
- op->o_dont_replicate = 1;
+ op->o_dont_replicate = !save;
+
+ /* avoid timestamp collisions */
+ if ( save )
+ slap_op_time( &op->o_time, &op->o_tincr );
mod.sml_numvals = sc.numcsns;
mod.sml_values = sc.ctxcsn;
Entry *e = slap_create_context_csn_entry( op->o_bd, NULL );
rs_reinit( &rs_modify, REP_RESULT );
rc = slap_mods2entry( &mod, &e, 0, 1, &text, txtbuf, textlen);
+ slap_queue_csn( op, &first );
+ op->o_tag = LDAP_REQ_ADD;
op->ora_e = e;
rc = op->o_bd->be_add( op, &rs_modify );
if ( e == op->ora_e )
op->orm_no_opattrs = 0;
op->o_dont_replicate = 0;
+ ldap_pvt_thread_mutex_lock( &si->si_cookieState->cs_mutex );
if ( rs_modify.sr_err == LDAP_SUCCESS ) {
slap_sync_cookie_free( &si->si_syncCookie, 0 );
ch_free( sc.sids );
ber_bvarray_free( sc.ctxcsn );
}
- ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
-
- op->o_bd = be;
- 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 );
#ifdef CHECK_CSN
for ( i=0; i<si->si_cookieState->cs_num; i++ ) {
}
#endif
+ si->si_cookieState->cs_updating = 0;
+ ldap_pvt_thread_cond_broadcast( &si->si_cookieState->cs_cond );
+ ldap_pvt_thread_mutex_unlock( &si->si_cookieState->cs_mutex );
+
+ op->o_bd = be;
+ 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 );
+
return rc;
}
syncinfo_t *si = op->o_callback->sc_private;
Attribute *a;
int count = 0;
- struct berval* present_uuid = NULL;
+ char *present_uuid = NULL;
struct nonpresent_entry *np_entry;
if ( rs->sr_type == REP_RESULT ) {
- count = avl_free( si->si_presentlist, ch_free );
+ count = presentlist_free( si->si_presentlist );
si->si_presentlist = NULL;
} else if ( rs->sr_type == REP_SEARCH ) {
a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID );
if ( a ) {
- present_uuid = avl_find( si->si_presentlist, &a->a_nvals[0],
- syncuuid_cmp );
+ present_uuid = presentlist_find( si->si_presentlist, &a->a_nvals[0] );
}
if ( LogTest( LDAP_DEBUG_SYNC ) ) {
LDAP_LIST_INSERT_HEAD( &si->si_nonpresentlist, np_entry, npe_link );
} else {
- avl_delete( &si->si_presentlist,
- &a->a_nvals[0], syncuuid_cmp );
+ presentlist_delete( &si->si_presentlist, &a->a_nvals[0] );
ch_free( present_uuid );
}
}
return LDAP_SUCCESS;
}
-static int
-null_callback(
- Operation* op,
- SlapReply* rs )
-{
- if ( rs->sr_err != LDAP_SUCCESS &&
- rs->sr_err != LDAP_REFERRAL &&
- rs->sr_err != LDAP_ALREADY_EXISTS &&
- rs->sr_err != LDAP_NO_SUCH_OBJECT &&
- rs->sr_err != LDAP_NOT_ALLOWED_ON_NONLEAF )
- {
- Debug( LDAP_DEBUG_ANY,
- "null_callback : error code 0x%x\n",
- rs->sr_err, 0, 0 );
- }
- return LDAP_SUCCESS;
-}
-
static struct berval *
slap_uuidstr_from_normalized(
struct berval* uuidstr,
static int
syncuuid_cmp( const void* v_uuid1, const void* v_uuid2 )
{
- const struct berval *uuid1 = v_uuid1;
- const struct berval *uuid2 = v_uuid2;
- int rc = uuid1->bv_len - uuid2->bv_len;
- if ( rc ) return rc;
- return ( memcmp( uuid1->bv_val, uuid2->bv_val, uuid1->bv_len ) );
+#ifdef HASHUUID
+ return ( memcmp( v_uuid1, v_uuid2, UUIDLEN-2 ));
+#else
+ return ( memcmp( v_uuid1, v_uuid2, UUIDLEN ));
+#endif
}
void
if ( sie->si_logfilterstr.bv_val ) {
ch_free( sie->si_logfilterstr.bv_val );
}
+ if ( sie->si_logfilter ) {
+ filter_free( sie->si_logfilter );
+ }
if ( sie->si_base.bv_val ) {
ch_free( sie->si_base.bv_val );
}
}
slap_sync_cookie_free( &sie->si_syncCookie, 0 );
if ( sie->si_presentlist ) {
- avl_free( sie->si_presentlist, ch_free );
+ presentlist_free( sie->si_presentlist );
}
while ( !LDAP_LIST_EMPTY( &sie->si_nonpresentlist ) ) {
struct nonpresent_entry* npe;
if ( !sie->si_cookieState->cs_ref ) {
ch_free( sie->si_cookieState->cs_sids );
ber_bvarray_free( sie->si_cookieState->cs_vals );
+ ldap_pvt_thread_cond_destroy( &sie->si_cookieState->cs_cond );
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 );
#define LOGFILTERSTR "logfilter"
#define SUFFIXMSTR "suffixmassage"
#define STRICT_REFRESH "strictrefresh"
+#define LAZY_COMMIT "lazycommit"
/* FIXME: undocumented */
#define EXATTRSSTR "exattrs"
STRLENOF( STRICT_REFRESH ) ) )
{
si->si_strict_refresh = 1;
+ } else if ( !strncasecmp( c->argv[ i ], LAZY_COMMIT,
+ STRLENOF( LAZY_COMMIT ) ) )
+ {
+ si->si_lazyCommit = 1;
} else if ( !bindconf_parse( c->argv[i], &si->si_bindconf ) ) {
si->si_got |= GOT_BINDCONF;
} else {
return 1;
}
+ if ( si->si_got & GOT_LOGFILTER ) {
+ si->si_logfilter = str2filter( si->si_logfilterstr.bv_val );
+ if ( si->si_logfilter == NULL ) {
+ Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": unable to parse logfilter=\"%s\"\n",
+ si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", si->si_logfilterstr.bv_val );
+ return 1;
+ }
+ }
+
return 0;
}
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 );
+ ldap_pvt_thread_cond_init( &si->si_cookieState->cs_cond );
c->be->be_syncinfo = si;
}
ptr = lutil_strcopy( ptr, bc.bv_val );
}
}
+
+ if ( si->si_lazyCommit ) {
+ ptr = lutil_strcopy( ptr, " " LAZY_COMMIT );
+ }
+
bc.bv_len = ptr - buf;
bc.bv_val = buf;
ber_dupbv( bv, &bc );
* happen when running on the cn=config DB.
*/
if ( si->si_re ) {
- if ( ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
+ if ( si->si_be == c->be || ldap_pvt_thread_mutex_trylock( &si->si_mutex )) {
isrunning = 1;
} else {
/* There is no active thread, but we must still
ldap_pvt_runqueue_stoptask( &slapd_rq, re );
isrunning = 1;
}
- if ( ldap_pvt_thread_pool_retract( &connection_pool,
- re->routine, re ) > 0 )
+ if ( ldap_pvt_thread_pool_retract( re->pool_cookie ) > 0 )
isrunning = 0;
ldap_pvt_runqueue_remove( &slapd_rq, re );