version 1.147.2.81, 2011/01/04 17:23:13
|
version 1.306, 2009/11/23 21:13:42
|
Line 1
|
Line 1
|
/* $OpenLDAP$ */ |
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.305 2009/11/22 16:43:48 hyc Exp $ */ |
/* syncprov.c - syncrepl provider */ |
/* syncprov.c - syncrepl provider */ |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
* |
* |
* Copyright 2004-2010 The OpenLDAP Foundation. |
* Copyright 2004-2009 The OpenLDAP Foundation. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
Line 113 typedef struct slog_entry {
|
Line 113 typedef struct slog_entry {
|
} slog_entry; |
} slog_entry; |
|
|
typedef struct sessionlog { |
typedef struct sessionlog { |
|
struct berval sl_mincsn; |
int sl_num; |
int sl_num; |
int sl_size; |
int sl_size; |
slog_entry *sl_head; |
slog_entry *sl_head; |
Line 132 typedef struct syncprov_info_t {
|
Line 133 typedef struct syncprov_info_t {
|
int si_numops; /* number of ops since last checkpoint */ |
int si_numops; /* number of ops since last checkpoint */ |
int si_nopres; /* Skip present phase */ |
int si_nopres; /* Skip present phase */ |
int si_usehint; /* use reload hint */ |
int si_usehint; /* use reload hint */ |
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. */ |
|
time_t si_chklast; /* time of last checkpoint */ |
time_t si_chklast; /* time of last checkpoint */ |
Avlnode *si_mods; /* entries being modified */ |
Avlnode *si_mods; /* entries being modified */ |
sessionlog *si_logs; |
sessionlog *si_logs; |
Line 933 syncprov_qplay( Operation *op, syncops *
|
Line 931 syncprov_qplay( Operation *op, syncops *
|
ldap_pvt_thread_mutex_unlock( &so->s_mutex ); |
ldap_pvt_thread_mutex_unlock( &so->s_mutex ); |
|
|
if ( sr->s_mode == LDAP_SYNC_NEW_COOKIE ) { |
if ( sr->s_mode == LDAP_SYNC_NEW_COOKIE ) { |
SlapReply rs = { REP_INTERMEDIATE }; |
SlapReply rs = { REP_INTERMEDIATE }; |
|
|
rc = syncprov_sendinfo( op, &rs, LDAP_TAG_SYNC_NEW_COOKIE, |
rc = syncprov_sendinfo( op, &rs, LDAP_TAG_SYNC_NEW_COOKIE, |
&sr->s_csn, 0, NULL, 0 ); |
&sr->s_csn, 0, NULL, 0 ); |
} else { |
} else { |
opc.sdn = sr->s_dn; |
opc.sdn = sr->s_dn; |
Line 947 syncprov_qplay( Operation *op, syncops *
|
Line 945 syncprov_qplay( Operation *op, syncops *
|
|
|
rc = syncprov_sendresp( op, &opc, so, sr->s_mode ); |
rc = syncprov_sendresp( op, &opc, so, sr->s_mode ); |
|
|
} |
if ( opc.se ) { |
if ( sr->s_e ) { |
if ( !dec_mutexint( opc.se->e_private )) { |
if ( !dec_mutexint( sr->s_e->e_private )) { |
opc.se->e_private = NULL; |
sr->s_e->e_private = NULL; |
entry_free ( opc.se ); |
entry_free ( sr->s_e ); |
} |
} |
} |
} |
} |
|
|
Line 1295 syncprov_matchops( Operation *op, opcook
|
Line 1293 syncprov_matchops( Operation *op, opcook
|
} |
} |
|
|
if ( fc.fscope ) { |
if ( fc.fscope ) { |
ldap_pvt_thread_mutex_lock( &ss->s_mutex ); |
|
op2 = *ss->s_op; |
op2 = *ss->s_op; |
oh = *op->o_hdr; |
oh = *op->o_hdr; |
oh.oh_conn = ss->s_op->o_conn; |
oh.oh_conn = ss->s_op->o_conn; |
Line 1304 syncprov_matchops( Operation *op, opcook
|
Line 1301 syncprov_matchops( Operation *op, opcook
|
op2.o_hdr = &oh; |
op2.o_hdr = &oh; |
op2.o_extra = op->o_extra; |
op2.o_extra = op->o_extra; |
op2.o_callback = NULL; |
op2.o_callback = NULL; |
if (ss->s_flags & PS_FIX_FILTER) { |
rc = test_filter( &op2, e, ss->s_op->ors_filter ); |
/* Skip the AND/GE clause that we stuck on in front. We |
|
would lose deletes/mods that happen during the refresh |
|
phase otherwise (ITS#6555) */ |
|
op2.ors_filter = ss->s_op->ors_filter->f_and->f_next; |
|
} |
|
ldap_pvt_thread_mutex_unlock( &ss->s_mutex ); |
|
rc = test_filter( &op2, e, op2.ors_filter ); |
|
} |
} |
|
|
Debug( LDAP_DEBUG_TRACE, "syncprov_matchops: sid %03x fscope %d rc %d\n", |
Debug( LDAP_DEBUG_TRACE, "syncprov_matchops: sid %03x fscope %d rc %d\n", |
Line 1378 syncprov_op_cleanup( Operation *op, Slap
|
Line 1368 syncprov_op_cleanup( Operation *op, Slap
|
syncmatches *sm, *snext; |
syncmatches *sm, *snext; |
modtarget *mt, mtdummy; |
modtarget *mt, mtdummy; |
|
|
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
|
if ( si->si_active ) |
|
si->si_active--; |
|
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
|
|
|
for (sm = opc->smatches; sm; sm=snext) { |
for (sm = opc->smatches; sm; sm=snext) { |
snext = sm->sm_next; |
snext = sm->sm_next; |
syncprov_free_syncop( sm->sm_op ); |
syncprov_free_syncop( sm->sm_op ); |
Line 1428 syncprov_checkpoint( Operation *op, Slap
|
Line 1413 syncprov_checkpoint( Operation *op, Slap
|
SlapReply rsm = { 0 }; |
SlapReply rsm = { 0 }; |
slap_callback cb = {0}; |
slap_callback cb = {0}; |
BackendDB be; |
BackendDB be; |
BackendInfo *bi; |
|
|
|
#ifdef CHECK_CSN |
#ifdef CHECK_CSN |
Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; |
Syntax *syn = slap_schema.si_ad_contextCSN->ad_type->sat_syntax; |
Line 1458 syncprov_checkpoint( Operation *op, Slap
|
Line 1442 syncprov_checkpoint( Operation *op, Slap
|
} |
} |
opm.o_req_dn = si->si_contextdn; |
opm.o_req_dn = si->si_contextdn; |
opm.o_req_ndn = si->si_contextdn; |
opm.o_req_ndn = si->si_contextdn; |
bi = opm.o_bd->bd_info; |
|
opm.o_bd->bd_info = on->on_info->oi_orig; |
opm.o_bd->bd_info = on->on_info->oi_orig; |
opm.o_managedsait = SLAP_CONTROL_NONCRITICAL; |
opm.o_managedsait = SLAP_CONTROL_NONCRITICAL; |
opm.o_no_schema_check = 1; |
opm.o_no_schema_check = 1; |
Line 1476 syncprov_checkpoint( Operation *op, Slap
|
Line 1459 syncprov_checkpoint( Operation *op, Slap
|
if ( e == opm.ora_e ) |
if ( e == opm.ora_e ) |
be_entry_release_w( &opm, opm.ora_e ); |
be_entry_release_w( &opm, opm.ora_e ); |
} |
} |
opm.o_bd->bd_info = bi; |
|
|
|
if ( mod.sml_next != NULL ) { |
if ( mod.sml_next != NULL ) { |
slap_mods_free( mod.sml_next, 1 ); |
slap_mods_free( mod.sml_next, 1 ); |
Line 1499 syncprov_add_slog( Operation *op )
|
Line 1481 syncprov_add_slog( Operation *op )
|
|
|
sl = si->si_logs; |
sl = si->si_logs; |
{ |
{ |
if ( BER_BVISEMPTY( &op->o_csn ) ) { |
|
/* During the syncrepl refresh phase we can receive operations |
|
* without a csn. We cannot reliably determine the consumers |
|
* state with respect to such operations, so we ignore them and |
|
* wipe out anything in the log if we see them. |
|
*/ |
|
ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); |
|
while ( se = sl->sl_head ) { |
|
sl->sl_head = se->se_next; |
|
ch_free( se ); |
|
} |
|
sl->sl_tail = NULL; |
|
sl->sl_num = 0; |
|
ldap_pvt_thread_mutex_unlock( &sl->sl_mutex ); |
|
return; |
|
} |
|
|
|
/* Allocate a record. UUIDs are not NUL-terminated. */ |
/* Allocate a record. UUIDs are not NUL-terminated. */ |
se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + |
se = ch_malloc( sizeof( slog_entry ) + opc->suuid.bv_len + |
op->o_csn.bv_len + 1 ); |
op->o_csn.bv_len + 1 ); |
Line 1534 syncprov_add_slog( Operation *op )
|
Line 1499 syncprov_add_slog( Operation *op )
|
|
|
ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); |
ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); |
if ( sl->sl_head ) { |
if ( sl->sl_head ) { |
/* Keep the list in csn order. */ |
sl->sl_tail->se_next = se; |
if ( ber_bvcmp( &sl->sl_tail->se_csn, &se->se_csn ) <= 0 ) { |
|
sl->sl_tail->se_next = se; |
|
sl->sl_tail = se; |
|
} else { |
|
slog_entry **sep; |
|
|
|
for ( sep = &sl->sl_head; *sep; sep = &(*sep)->se_next ) { |
|
if ( ber_bvcmp( &se->se_csn, &(*sep)->se_csn ) < 0 ) { |
|
se->se_next = *sep; |
|
*sep = se; |
|
break; |
|
} |
|
} |
|
} |
|
} else { |
} else { |
sl->sl_head = se; |
sl->sl_head = se; |
sl->sl_tail = se; |
|
} |
} |
|
sl->sl_tail = se; |
sl->sl_num++; |
sl->sl_num++; |
while ( sl->sl_num > sl->sl_size ) { |
while ( sl->sl_num > sl->sl_size ) { |
se = sl->sl_head; |
se = sl->sl_head; |
sl->sl_head = se->se_next; |
sl->sl_head = se->se_next; |
|
strcpy( sl->sl_mincsn.bv_val, se->se_csn.bv_val ); |
|
sl->sl_mincsn.bv_len = se->se_csn.bv_len; |
ch_free( se ); |
ch_free( se ); |
sl->sl_num--; |
sl->sl_num--; |
} |
} |
Line 1842 syncprov_op_response( Operation *op, Sla
|
Line 1795 syncprov_op_response( Operation *op, Sla
|
csn_changed = 1; |
csn_changed = 1; |
} |
} |
} |
} |
if ( csn_changed ) |
|
si->si_dirty = 0; |
|
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
|
|
if ( csn_changed ) { |
if ( csn_changed ) { |
syncops *ss; |
|
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
for ( ss = si->si_ops; ss; ss = ss->s_next ) { |
have_psearches = ( si->si_ops != NULL ); |
if ( ss->s_op->o_abandon ) |
|
continue; |
|
/* Send the updated csn to all syncrepl consumers, |
|
* including the server from which it originated. |
|
* The syncrepl consumer and syncprov provider on |
|
* the originating server may be configured to store |
|
* their csn values in different entries. |
|
*/ |
|
syncprov_qresp( opc, ss, LDAP_SYNC_NEW_COOKIE ); |
|
} |
|
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
|
|
|
if ( have_psearches ) { |
|
for ( sm = opc->smatches; sm; sm=sm->sm_next ) { |
|
if ( sm->sm_op->s_op->o_abandon ) |
|
continue; |
|
syncprov_qresp( opc, sm->sm_op, LDAP_SYNC_NEW_COOKIE ); |
|
} |
|
} |
} |
} |
} else { |
} else { |
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
Line 1890 syncprov_op_response( Operation *op, Sla
|
Line 1838 syncprov_op_response( Operation *op, Sla
|
} |
} |
} |
} |
} |
} |
si->si_dirty = !csn_changed; |
|
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
ldap_pvt_thread_rdwr_wunlock( &si->si_csn_rwlock ); |
|
|
if ( do_check ) { |
if ( do_check ) { |
Line 2018 syncprov_op_mod( Operation *op, SlapRepl
|
Line 1965 syncprov_op_mod( Operation *op, SlapRepl
|
|
|
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
have_psearches = ( si->si_ops != NULL ); |
have_psearches = ( si->si_ops != NULL ); |
si->si_active++; |
|
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
|
|
cbsize = sizeof(slap_callback) + sizeof(opcookie) + |
cbsize = sizeof(slap_callback) + sizeof(opcookie) + |
Line 2409 syncprov_op_search( Operation *op, SlapR
|
Line 2355 syncprov_op_search( Operation *op, SlapR
|
BerVarray ctxcsn; |
BerVarray ctxcsn; |
int i, *sids, numcsns; |
int i, *sids, numcsns; |
struct berval mincsn; |
struct berval mincsn; |
int dirty = 0; |
|
|
|
if ( !(op->o_sync_mode & SLAP_SYNC_REFRESH) ) return SLAP_CB_CONTINUE; |
if ( !(op->o_sync_mode & SLAP_SYNC_REFRESH) ) return SLAP_CB_CONTINUE; |
|
|
Line 2454 syncprov_op_search( Operation *op, SlapR
|
Line 2399 syncprov_op_search( Operation *op, SlapR
|
sop->s_inuse = 1; |
sop->s_inuse = 1; |
|
|
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
while ( si->si_active ) { |
|
/* Wait for active mods to finish before proceeding, as they |
|
* may already have inspected the si_ops list looking for |
|
* consumers to replicate the change to. Using the log |
|
* doesn't help, as we may finish playing it before the |
|
* active mods gets added to it. |
|
*/ |
|
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
|
if ( slapd_shutdown ) |
|
return SLAPD_ABANDON; |
|
if ( !ldap_pvt_thread_pool_pausecheck( &connection_pool )) |
|
ldap_pvt_thread_yield(); |
|
ldap_pvt_thread_mutex_lock( &si->si_ops_mutex ); |
|
} |
|
sop->s_next = si->si_ops; |
sop->s_next = si->si_ops; |
si->si_ops = sop; |
si->si_ops = sop; |
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
ldap_pvt_thread_mutex_unlock( &si->si_ops_mutex ); |
Line 2485 syncprov_op_search( Operation *op, SlapR
|
Line 2416 syncprov_op_search( Operation *op, SlapR
|
ctxcsn = NULL; |
ctxcsn = NULL; |
sids = NULL; |
sids = NULL; |
} |
} |
dirty = si->si_dirty; |
|
ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); |
ldap_pvt_thread_rdwr_runlock( &si->si_csn_rwlock ); |
|
|
/* If we have a cookie, handle the PRESENT lookups */ |
/* If we have a cookie, handle the PRESENT lookups */ |
Line 2542 syncprov_op_search( Operation *op, SlapR
|
Line 2472 syncprov_op_search( Operation *op, SlapR
|
if ( newer < 0 ) |
if ( newer < 0 ) |
changed = SS_CHANGED; |
changed = SS_CHANGED; |
else if ( newer > 0 ) { |
else if ( newer > 0 ) { |
/* our state is older, complain to consumer */ |
/* our state is older, tell consumer nothing */ |
rs->sr_err = LDAP_UNWILLING_TO_PERFORM; |
rs->sr_err = LDAP_SUCCESS; |
rs->sr_text = "consumer state is newer than provider!"; |
|
bailout: |
bailout: |
if ( sop ) { |
if ( sop ) { |
syncops **sp = &si->si_ops; |
syncops **sp = &si->si_ops; |
Line 2565 bailout:
|
Line 2494 bailout:
|
if ( changed ) |
if ( changed ) |
break; |
break; |
} |
} |
if ( !changed && !dirty ) { |
if ( !changed ) { |
do_present = 0; |
do_present = 0; |
no_change: if ( !(op->o_sync_mode & SLAP_SYNC_PERSIST) ) { |
no_change: if ( !(op->o_sync_mode & SLAP_SYNC_PERSIST) ) { |
LDAPControl *ctrls[2]; |
LDAPControl *ctrls[2]; |
Line 2593 no_change: if ( !(op->o_sync_mode & SLA
|
Line 2522 no_change: if ( !(op->o_sync_mode & SLA
|
/* Are there any log entries, and is the consumer state |
/* Are there any log entries, and is the consumer state |
* present in the session log? |
* present in the session log? |
*/ |
*/ |
if ( sl->sl_num > 0 && ber_bvcmp( &mincsn, &sl->sl_head->se_csn ) >= 0 ) { |
if ( sl->sl_num > 0 && ber_bvcmp( &mincsn, &sl->sl_mincsn ) >= 0 ) { |
do_present = 0; |
do_present = 0; |
/* mutex is unlocked in playlog */ |
/* mutex is unlocked in playlog */ |
syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids ); |
syncprov_playlog( op, rs, sl, srs, ctxcsn, numcsns, sids ); |
Line 2632 no_change: if ( !(op->o_sync_mode & SLA
|
Line 2561 no_change: if ( !(op->o_sync_mode & SLA
|
ber_bvarray_free_x( ctxcsn, op->o_tmpmemctx ); |
ber_bvarray_free_x( ctxcsn, op->o_tmpmemctx ); |
if ( sids ) |
if ( sids ) |
op->o_tmpfree( sids, op->o_tmpmemctx ); |
op->o_tmpfree( sids, op->o_tmpmemctx ); |
goto bailout; |
send_ldap_result( op, rs ); |
|
return rs->sr_err; |
} |
} |
} |
} |
} else { |
} else { |
Line 2649 shortcut:
|
Line 2579 shortcut:
|
} |
} |
|
|
/* If something changed, find the changes */ |
/* If something changed, find the changes */ |
if ( gotstate && ( changed || dirty ) ) { |
if ( gotstate && changed ) { |
Filter *fand, *fava; |
Filter *fand, *fava; |
|
|
fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); |
fand = op->o_tmpalloc( sizeof(Filter), op->o_tmpmemctx ); |
Line 2665 shortcut:
|
Line 2595 shortcut:
|
#endif |
#endif |
ber_dupbv_x( &fava->f_ava->aa_value, &mincsn, op->o_tmpmemctx ); |
ber_dupbv_x( &fava->f_ava->aa_value, &mincsn, op->o_tmpmemctx ); |
fava->f_next = op->ors_filter; |
fava->f_next = op->ors_filter; |
if ( sop ) |
|
ldap_pvt_thread_mutex_lock( &sop->s_mutex ); |
|
op->ors_filter = fand; |
op->ors_filter = fand; |
filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); |
filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); |
if ( sop ) { |
if ( sop ) |
sop->s_flags |= PS_FIX_FILTER; |
sop->s_flags |= PS_FIX_FILTER; |
ldap_pvt_thread_mutex_unlock( &sop->s_mutex ); |
|
} |
|
} |
} |
|
|
/* Let our callback add needed info to returned entries */ |
/* Let our callback add needed info to returned entries */ |
Line 2694 shortcut:
|
Line 2620 shortcut:
|
* the refresh phase, just invoke the response callback to transition |
* the refresh phase, just invoke the response callback to transition |
* us into persist phase |
* us into persist phase |
*/ |
*/ |
if ( !changed && !dirty ) { |
if ( !changed ) { |
rs->sr_err = LDAP_SUCCESS; |
rs->sr_err = LDAP_SUCCESS; |
rs->sr_nentries = 0; |
rs->sr_nentries = 0; |
send_ldap_result( op, rs ); |
send_ldap_result( op, rs ); |
Line 2935 sp_cf_gen(ConfigArgs *c)
|
Line 2861 sp_cf_gen(ConfigArgs *c)
|
} |
} |
sl = si->si_logs; |
sl = si->si_logs; |
if ( !sl ) { |
if ( !sl ) { |
sl = ch_malloc( sizeof( sessionlog ) ); |
sl = ch_malloc( sizeof( sessionlog ) + LDAP_PVT_CSNSTR_BUFSIZE ); |
|
sl->sl_mincsn.bv_val = (char *)(sl+1); |
|
sl->sl_mincsn.bv_len = 0; |
sl->sl_num = 0; |
sl->sl_num = 0; |
sl->sl_head = sl->sl_tail = NULL; |
sl->sl_head = sl->sl_tail = NULL; |
ldap_pvt_thread_mutex_init( &sl->sl_mutex ); |
ldap_pvt_thread_mutex_init( &sl->sl_mutex ); |