Commit 52d05420 authored by Ondřej Kuzník's avatar Ondřej Kuzník
Browse files

ITS#8125 WIP

parent 26bb312b
......@@ -152,6 +152,7 @@ typedef struct syncprov_info_t {
int si_active; /* True if there are active mods */
int si_dirty; /* True if the context is dirty, i.e changes
* have been made without updating the csn. */
int si_refresh; /* True if our DB is being refreshed */
time_t si_chklast; /* time of last checkpoint */
Avlnode *si_mods; /* entries being modified */
sessionlog *si_logs;
......@@ -960,6 +961,21 @@ syncprov_qplay( Operation *op, syncops *so )
syncres *sr;
int rc = 0;
ldap_pvt_thread_rdwr_rlock( &so->s_si->si_csn_rwlock );
if ( so->s_si->si_refresh ) {
/* Cancel this persistent search if in the middle of a refresh */
ldap_pvt_thread_rdwr_runlock( &so->s_si->si_csn_rwlock );
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 %s "
"stopping existing persist session\n",
so->s_op->o_log_prefix );
/* FIXME: We should have cancelled all searches when we foudn out? */
assert( 0 );
/* Acquire mutex for caller */
ldap_pvt_thread_mutex_lock( &so->s_mutex );
return 1;
}
ldap_pvt_thread_rdwr_runlock( &so->s_si->si_csn_rwlock );
do {
ldap_pvt_thread_mutex_lock( &so->s_mutex );
sr = so->s_res;
......@@ -1965,6 +1981,56 @@ syncprov_op_response( Operation *op, SlapReply *rs )
slap_overinst *on = opc->son;
syncprov_info_t *si = on->on_bi.bi_private;
syncmatches *sm;
int was_refreshing;
ldap_pvt_thread_mutex_lock( &op->o_bd->be_pcl_mutex );
ldap_pvt_thread_rdwr_wlock( &si->si_csn_rwlock );
was_refreshing = si->si_refresh;
si->si_refresh = op->o_bd->be_refreshing;
ldap_pvt_thread_mutex_unlock( &op->o_bd->be_pcl_mutex );
if ( si->si_refresh != was_refreshing ) {
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 changed to %d\n",
si->si_refresh );
}
if ( si->si_refresh && !was_refreshing ) {
syncops *so, **sop = &si->si_ops;
int gonext;
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex );
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock );
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 "
"DB refresh detected, %s (%s)\n",
*sop ? "checking persist ops for reset" : "no operations to reset",
op->o_bd->be_suffix[0].bv_val );
for ( so = *sop; so; sop = gonext ? &(*sop)->s_next : sop, so = *sop ) {
SlapReply rs2 = {REP_RESULT};
gonext = 1;
/* Only cancel if already in persist */
if ( so->s_flags & PS_IS_REFRESHING ) {
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 %s "
"still in refresh\n",
so->s_op->o_log_prefix );
continue;
}
gonext = 0;
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 %s "
"stopping persist session\n",
so->s_op->o_log_prefix );
rs2.sr_err = LDAP_BUSY;
rs2.sr_text = "its8125 Our database has gone into refresh, please retry later";
send_ldap_result( so->s_op, &rs2 );
if ( so->s_flags & PS_TASK_QUEUED )
ldap_pvt_thread_pool_retract( so->s_pool_cookie );
if ( !syncprov_drop_psearch( so, 1 ) )
so->s_si = NULL;
}
si->si_ops = NULL;
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex );
} else {
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock );
}
if ( rs->sr_err == LDAP_SUCCESS )
{
......@@ -2555,6 +2621,7 @@ syncprov_search_response( Operation *op, SlapReply *rs )
* Note: refresh never gets here if there were no changes
*/
if ( !ss->ss_so ) {
bailout:
rs->sr_ctrls = op->o_tmpalloc( sizeof(LDAPControl *)*2,
op->o_tmpmemctx );
rs->sr_ctrls[1] = NULL;
......@@ -2564,6 +2631,20 @@ syncprov_search_response( Operation *op, SlapReply *rs )
LDAP_SYNC_REFRESH_DELETES );
op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx );
} else {
ldap_pvt_thread_rdwr_rlock( &si->si_csn_rwlock );
if ( si->si_refresh ) {
/* ITS#8125 Our DB is being refreshed, we can't support persist
* sessions safely while that's the case */
ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock );
Debug( LDAP_DEBUG_SYNC, "syncprov_op_response: its8125 %s "
"stopping session just after refresh\n",
ss->ss_so->s_op->o_log_prefix );
syncprov_free_syncop( ss->ss_so, FS_LOCK|FS_UNLINK );
rs->sr_text = "its8125 Provider is refreshing from another source";
goto bailout;
}
ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock );
/* It's RefreshAndPersist, transition to Persist phase */
syncprov_sendinfo( op, rs, ( ss->ss_flags & SS_PRESENT ) ?
LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE,
......
......@@ -1984,6 +1984,7 @@ struct BackendDB {
struct be_pcl *be_pending_csn_list;
ldap_pvt_thread_mutex_t be_pcl_mutex;
struct syncinfo_s *be_syncinfo; /* For syncrepl */
int be_refreshing;
void *be_pb; /* Netscape plugin */
struct ConfigOCs *be_cf_ocs;
......
......@@ -1099,8 +1099,16 @@ do_syncrep2(
/* The notification control is only sent during persist phase */
rctrlp = ldap_control_find( LDAP_CONTROL_PERSIST_ENTRY_CHANGE_NOTICE, rctrls, &next );
if ( rctrlp ) {
if ( !si->si_refreshDone )
if ( !si->si_refreshDone ) {
si->si_refreshDone = 1;
/* TODO: could we have actually tainted the DB
* in DSEE mode? */
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
si->si_be->be_refreshing = 0;
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s its8125 finished refresh\n",
si->si_ridtxt );
}
if ( si->si_refreshDone )
syncrepl_dsee_update( si, op );
}
......@@ -1286,10 +1294,6 @@ logerr:
bdn.bv_val[bdn.bv_len] = '\0';
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync on (%s), switching to REFRESH\n",
si->si_ridtxt, bdn.bv_val );
if (si->si_strict_refresh) {
slap_suspend_listeners();
connections_drop();
}
break;
default:
break;
......@@ -1354,10 +1358,6 @@ logerr:
si->si_logstate = SYNCLOG_FALLBACK;
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s delta-sync lost sync, switching to REFRESH\n",
si->si_ridtxt );
if (si->si_strict_refresh) {
slap_suspend_listeners();
connections_drop();
}
}
rc = err;
goto done;
......@@ -1373,6 +1373,11 @@ logerr:
if ( si->si_logstate == SYNCLOG_FALLBACK ) {
si->si_logstate = SYNCLOG_LOGGING;
si->si_refreshDone = 1;
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
si->si_be->be_refreshing = 0;
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s its8125 finished refresh\n",
si->si_ridtxt );
rc = LDAP_SYNC_REFRESH_REQUIRED;
} else {
rc = -2;
......@@ -1474,6 +1479,11 @@ logerr:
&& si->si_logstate == SYNCLOG_FALLBACK ) {
si->si_logstate = SYNCLOG_LOGGING;
si->si_refreshDone = 1;
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
si->si_be->be_refreshing = 0;
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
Debug( LDAP_DEBUG_SYNC, "do_syncrep2: %s its8125 finished refresh\n",
si->si_ridtxt );
rc = LDAP_SYNC_REFRESH_REQUIRED;
slap_resume_listeners();
} else {
......@@ -1554,7 +1564,10 @@ logerr:
}
ber_scanf( ber, /*"{"*/ "}" );
if ( si->si_refreshDone ) {
Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s finished refresh\n",
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
si->si_be->be_refreshing = 0;
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
Debug( LDAP_DEBUG_SYNC, "do_syncrep1: %s its8125 finished refresh\n",
si->si_ridtxt );
}
if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST &&
......@@ -3698,10 +3711,35 @@ syncrepl_entry(
dninfo dni = {0};
int retry = 1;
int freecsn = 1;
int refreshing = 1;
Debug( LDAP_DEBUG_SYNC,
"syncrepl_entry: %s LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) csn=%s tid %x\n",
si->si_ridtxt, syncrepl_state2str( syncstate ), syncCSN ? syncCSN->bv_val : "(none)", op->o_tid );
si->si_ridtxt, syncrepl_state2str( syncstate ),
syncCSN ? syncCSN->bv_val : "(none)", op->o_tid );
if ( !syncCSN || BER_BVISNULL(syncCSN) ) {
/*
* ITS#8125: A provider is trying to effect a refresh now, make sure
* syncprov can find out.
*/
if ( si->si_refreshDone ) {
/*
* syncprov will always try to send a cookie with a CSN if possible
* during persist phase, either this isn't OpenLDAP or something
* has gone wrong. Either way we aren't safe to serve a
* refreshAndPersist session correctly until a future refresh.
*/
Debug( LDAP_DEBUG_ANY, "syncrepl_entry: %s "
"LDAP_RES_SEARCH_ENTRY(LDAP_SYNC_%s) csn-less entry received during "
"persist! Tainting database immediately so we don't propagate this.\n",
si->si_ridtxt, syncrepl_state2str( syncstate ) );
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
si->si_be->be_refreshing = 1;
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
}
refreshing = 1;
}
if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD ) ) {
if ( !si->si_refreshPresent && !si->si_refreshDone ) {
......@@ -3710,6 +3748,7 @@ syncrepl_entry(
}
if ( syncstate == LDAP_SYNC_PRESENT ) {
/* ITS#8125 TODO: Deal with presentlist */
return 0;
} else if ( syncstate != LDAP_SYNC_DELETE ) {
if ( entry == NULL ) {
......@@ -3839,6 +3878,14 @@ syncrepl_entry(
}
}
retry_add:;
ldap_pvt_thread_mutex_lock( &si->si_be->be_pcl_mutex );
if ( !si->si_be->be_refreshing ) {
Debug( LDAP_DEBUG_SYNC, "syncrepl_entry: %s its8125 "
"detected an ongoing refresh, tainting database\n",
si->si_ridtxt );
si->si_be->be_refreshing = 1;
}
ldap_pvt_thread_mutex_unlock( &si->si_be->be_pcl_mutex );
if ( BER_BVISNULL( &dni.dn ) ) {
SlapReply rs_add = {REP_RESULT};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment