version 1.9, 2004/11/24 16:07:14
|
version 1.10, 2004/11/24 19:34:28
|
Line 64 typedef struct opcookie {
|
Line 64 typedef struct opcookie {
|
} opcookie; |
} opcookie; |
|
|
typedef struct fbase_cookie { |
typedef struct fbase_cookie { |
struct berval *fdn; |
struct berval *fdn; /* DN of a modified entry, for scope testing */ |
syncops *fss; |
syncops *fss; /* persistent search we're testing against */ |
int fbase; |
int fbase; /* if TRUE we found the search base and it's still valid */ |
int fsuffix; |
int fscope; /* if TRUE then fdn is within the psearch scope */ |
} fbase_cookie; |
} fbase_cookie; |
|
|
static AttributeName csn_anlist[2]; |
static AttributeName csn_anlist[2]; |
static AttributeName uuid_anlist[2]; |
static AttributeName uuid_anlist[2]; |
|
|
static int |
/* syncprov_findbase: |
dn_avl_cmp( const void *c1, const void *c2 ) |
* finds the true DN of the base of a search (with alias dereferencing) and |
{ |
* checks to make sure the base entry doesn't get replaced with a different |
struct berval *bv1 = (struct berval *)c1; |
* entry (e.g., swapping trees via ModDN, or retargeting an alias). If a |
struct berval *bv2 = (struct berval *)c2; |
* change is detected, any persistent search on this base must be terminated / |
int rc = bv1->bv_len - bv2->bv_len; |
* reloaded. |
|
* On the first call, we just save the DN and entryID. On subsequent calls |
if ( rc ) return rc; |
* we compare the DN and entryID with the saved values. |
return ber_bvcmp( bv1, bv2 ); |
*/ |
} |
|
|
|
static int |
static int |
findbase_cb( Operation *op, SlapReply *rs ) |
findbase_cb( Operation *op, SlapReply *rs ) |
{ |
{ |
Line 99 findbase_cb( Operation *op, SlapReply *r
|
Line 97 findbase_cb( Operation *op, SlapReply *r
|
fc->fbase = 1; |
fc->fbase = 1; |
fc->fss->s_eid = rs->sr_entry->e_id; |
fc->fss->s_eid = rs->sr_entry->e_id; |
ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname ); |
ber_dupbv( &fc->fss->s_base, &rs->sr_entry->e_nname ); |
|
|
} else if ( rs->sr_entry->e_id == fc->fss->s_eid && |
} else if ( rs->sr_entry->e_id == fc->fss->s_eid && |
dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) { |
dn_match( &rs->sr_entry->e_nname, &fc->fss->s_base )) { |
|
|
|
/* OK, the DN is the same and the entryID is the same. Now |
|
* see if the fdn resides in the scope. |
|
*/ |
fc->fbase = 1; |
fc->fbase = 1; |
fc->fsuffix = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname ); |
switch ( fc->fss->s_op->ors_scope ) { |
|
case LDAP_SCOPE_BASE: |
|
fc->fscope = dn_match( fc->fdn, &rs->sr_entry->e_nname ); |
|
break; |
|
case LDAP_SCOPE_ONELEVEL: { |
|
struct berval pdn; |
|
dnParent( fc->fdn, &pdn ); |
|
fc->fscope = dn_match( &pdn, &rs->sr_entry->e_nname ); |
|
break; } |
|
case LDAP_SCOPE_SUBTREE: |
|
fc->fscope = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname ); |
|
break; |
|
#ifdef LDAP_SCOPE_SUBORDINATE |
|
case LDAP_SCOPE_SUBORDINATE: |
|
fc->fscope = dnIsSuffix( fc->fdn, &rs->sr_entry->e_nname ) && |
|
!dn_match( fc->fdn, &rs->sr_entry->e_nname ); |
|
break; |
|
#endif |
|
} |
} |
} |
} |
} |
return LDAP_SUCCESS; |
return LDAP_SUCCESS; |
} |
} |
|
|
static int |
static int |
syncprov_findbase( Operation *op, syncops *ss, fbase_cookie *fc ) |
syncprov_findbase( Operation *op, fbase_cookie *fc ) |
{ |
{ |
opcookie *opc = op->o_callback->sc_private; |
opcookie *opc = op->o_callback->sc_private; |
slap_overinst *on = opc->son; |
slap_overinst *on = opc->son; |
Line 129 syncprov_findbase( Operation *op, syncop
|
Line 150 syncprov_findbase( Operation *op, syncop
|
fop.o_callback = &cb; |
fop.o_callback = &cb; |
fop.o_tag = LDAP_REQ_SEARCH; |
fop.o_tag = LDAP_REQ_SEARCH; |
fop.ors_scope = LDAP_SCOPE_BASE; |
fop.ors_scope = LDAP_SCOPE_BASE; |
fop.ors_deref = ss->s_op->ors_deref; |
fop.ors_deref = fc->fss->s_op->ors_deref; |
fop.ors_slimit = 1; |
fop.ors_slimit = 1; |
fop.ors_tlimit = SLAP_NO_LIMIT; |
fop.ors_tlimit = SLAP_NO_LIMIT; |
fop.ors_attrs = slap_anlist_no_attrs; |
fop.ors_attrs = slap_anlist_no_attrs; |
fop.ors_attrsonly = 1; |
fop.ors_attrsonly = 1; |
fop.ors_filter = ss->s_op->ors_filter; |
fop.ors_filter = fc->fss->s_op->ors_filter; |
fop.ors_filterstr = ss->s_op->ors_filterstr; |
fop.ors_filterstr = fc->fss->s_op->ors_filterstr; |
|
|
fop.o_req_ndn = ss->s_op->o_req_ndn; |
fop.o_req_ndn = fc->fss->s_op->o_req_ndn; |
|
|
fop.o_bd->bd_info = on->on_info->oi_orig; |
fop.o_bd->bd_info = on->on_info->oi_orig; |
rc = fop.o_bd->be_search( &fop, &frs ); |
rc = fop.o_bd->be_search( &fop, &frs ); |
Line 151 syncprov_findbase( Operation *op, syncop
|
Line 172 syncprov_findbase( Operation *op, syncop
|
return LDAP_NO_SUCH_OBJECT; |
return LDAP_NO_SUCH_OBJECT; |
} |
} |
|
|
|
/* syncprov_findcsn: |
|
* This function has three different purposes, but they all use a search |
|
* that filters on entryCSN so they're combined here. |
|
* 1: when the current contextCSN is unknown (i.e., at server start time) |
|
* and a syncrepl search has arrived with a cookie, we search for all entries |
|
* with CSN >= the cookie CSN, and store the maximum as our contextCSN. Also, |
|
* we expect to find the cookie CSN in the search results, and note if we did |
|
* or not. If not, we assume the cookie is stale. (This may be too restrictive, |
|
* notice case 2.) |
|
* |
|
* 2: when the current contextCSN is known and we have a sync cookie, we search |
|
* for one entry with CSN <= the cookie CSN. (Used to search for =.) If an |
|
* entry is found, the cookie CSN is valid, otherwise it is stale. Case 1 is |
|
* considered a special case of case 2, and both are generally called the |
|
* "find CSN" task. |
|
* |
|
* 3: during a refresh phase, we search for all entries with CSN <= the cookie |
|
* CSN, and generate Present records for them. We always collect this result |
|
* in SyncID sets, even if there's only one match. |
|
*/ |
#define FIND_CSN 1 |
#define FIND_CSN 1 |
#define FIND_PRESENT 2 |
#define FIND_PRESENT 2 |
|
|
Line 165 findcsn_cb( Operation *op, SlapReply *rs
|
Line 206 findcsn_cb( Operation *op, SlapReply *rs
|
slap_callback *sc = op->o_callback; |
slap_callback *sc = op->o_callback; |
|
|
if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { |
if ( rs->sr_type == REP_SEARCH && rs->sr_err == LDAP_SUCCESS ) { |
|
/* If the private pointer is set, it points to an fcsn_cookie |
|
* and we want to record the maxcsn and match state. |
|
*/ |
if ( sc->sc_private ) { |
if ( sc->sc_private ) { |
int i; |
int i; |
fcsn_cookie *fc = sc->sc_private; |
fcsn_cookie *fc = sc->sc_private; |
Line 178 findcsn_cb( Operation *op, SlapReply *rs
|
Line 222 findcsn_cb( Operation *op, SlapReply *rs
|
strcpy(fc->maxcsn.bv_val, a->a_vals[0].bv_val ); |
strcpy(fc->maxcsn.bv_val, a->a_vals[0].bv_val ); |
} |
} |
} else { |
} else { |
|
/* Otherwise, if the private pointer is not set, we just |
|
* want to know if any entry matched the filter. |
|
*/ |
sc->sc_private = (void *)1; |
sc->sc_private = (void *)1; |
} |
} |
} |
} |
return LDAP_SUCCESS; |
return LDAP_SUCCESS; |
} |
} |
|
|
|
/* Build a list of entryUUIDs for sending in a SyncID set */ |
|
|
typedef struct fpres_cookie { |
typedef struct fpres_cookie { |
int num; |
int num; |
BerVarray uuids; |
BerVarray uuids; |
Line 197 findpres_cb( Operation *op, SlapReply *r
|
Line 246 findpres_cb( Operation *op, SlapReply *r
|
int ret = SLAP_CB_CONTINUE; |
int ret = SLAP_CB_CONTINUE; |
|
|
if ( rs->sr_type == REP_SEARCH ) { |
if ( rs->sr_type == REP_SEARCH ) { |
Debug(LDAP_DEBUG_TRACE, "present %s\n", rs->sr_entry->e_name.bv_val, 0, 0); |
|
ret = slap_build_syncUUID_set( op, &pc->uuids, rs->sr_entry ); |
ret = slap_build_syncUUID_set( op, &pc->uuids, rs->sr_entry ); |
if ( ret > 0 ) { |
if ( ret > 0 ) { |
pc->num++; |
pc->num++; |
Line 281 syncprov_findcsn( Operation *op, int mod
|
Line 329 syncprov_findcsn( Operation *op, int mod
|
fop.ors_attrs = slap_anlist_no_attrs; |
fop.ors_attrs = slap_anlist_no_attrs; |
fop.ors_slimit = 1; |
fop.ors_slimit = 1; |
cb.sc_private = NULL; |
cb.sc_private = NULL; |
fbuf.bv_len = sprintf( buf, "(entryCSN=%s)", op->o_sync_state.ctxcsn->bv_val ); |
fbuf.bv_len = sprintf( buf, "(entryCSN<=%s)", op->o_sync_state.ctxcsn->bv_val ); |
} |
} |
cb.sc_response = findcsn_cb; |
cb.sc_response = findcsn_cb; |
|
|
Line 290 syncprov_findcsn( Operation *op, int mod
|
Line 338 syncprov_findcsn( Operation *op, int mod
|
fop.ors_attrsonly = 0; |
fop.ors_attrsonly = 0; |
fop.ors_attrs = uuid_anlist; |
fop.ors_attrs = uuid_anlist; |
fop.ors_slimit = SLAP_NO_LIMIT; |
fop.ors_slimit = SLAP_NO_LIMIT; |
|
/* We want pure entries, not referrals */ |
|
fop.o_managedsait = SLAP_CONTROL_CRITICAL; |
cb.sc_private = &pcookie; |
cb.sc_private = &pcookie; |
cb.sc_response = findpres_cb; |
cb.sc_response = findpres_cb; |
pcookie.num = 0; |
pcookie.num = 0; |
Line 440 syncprov_matchops( Operation *op, opcook
|
Line 490 syncprov_matchops( Operation *op, opcook
|
/* validate base */ |
/* validate base */ |
fc.fss = ss; |
fc.fss = ss; |
fc.fbase = 0; |
fc.fbase = 0; |
fc.fsuffix = 0; |
fc.fscope = 0; |
rc = syncprov_findbase( op, ss, &fc ); |
rc = syncprov_findbase( op, &fc ); |
if ( rc != LDAP_SUCCESS ) continue; |
if ( rc != LDAP_SUCCESS ) continue; |
|
|
/* If we're sending results now, look for this op in old matches */ |
/* If we're sending results now, look for this op in old matches */ |
Line 459 syncprov_matchops( Operation *op, opcook
|
Line 509 syncprov_matchops( Operation *op, opcook
|
} |
} |
|
|
/* check if current o_req_dn is in scope and matches filter */ |
/* check if current o_req_dn is in scope and matches filter */ |
if ( fc.fsuffix && test_filter( op, e, ss->s_filter ) == |
if ( fc.fscope && test_filter( op, e, ss->s_filter ) == |
LDAP_COMPARE_TRUE ) { |
LDAP_COMPARE_TRUE ) { |
if ( saveit ) { |
if ( saveit ) { |
sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx ); |
sm = op->o_tmpalloc( sizeof(syncmatches), op->o_tmpmemctx ); |
Line 757 syncprov_op_search( Operation *op, SlapR
|
Line 807 syncprov_op_search( Operation *op, SlapR
|
opc.son = on; |
opc.son = on; |
cb = op->o_callback; |
cb = op->o_callback; |
op->o_callback = ≻ |
op->o_callback = ≻ |
rs->sr_err = syncprov_findbase( op, &so, &fc ); |
rs->sr_err = syncprov_findbase( op, &fc ); |
op->o_callback = cb; |
op->o_callback = cb; |
|
|
if ( rs->sr_err != LDAP_SUCCESS ) { |
if ( rs->sr_err != LDAP_SUCCESS ) { |
Line 815 syncprov_op_search( Operation *op, SlapR
|
Line 865 syncprov_op_search( Operation *op, SlapR
|
} |
} |
} |
} |
|
|
|
/* If we didn't get a cookie and we don't know our contextcsn, try to |
|
* find it anyway. |
|
*/ |
if ( !gotstate && !si->si_gotcsn ) { |
if ( !gotstate && !si->si_gotcsn ) { |
struct berval bv = BER_BVC("1"), *old; |
struct berval bv = BER_BVC("1"), *old; |
|
|
Line 824 syncprov_op_search( Operation *op, SlapR
|
Line 877 syncprov_op_search( Operation *op, SlapR
|
op->o_sync_state.ctxcsn = old; |
op->o_sync_state.ctxcsn = old; |
} |
} |
|
|
/* Append CSN range to search filter */ |
/* Append CSN range to search filter, save original filter |
|
* for persistent search evaluation |
|
*/ |
if ( sop ) { |
if ( sop ) { |
sop->s_filter = op->ors_filter; |
sop->s_filter = op->ors_filter; |
} |
} |
Line 863 shortcut:
|
Line 918 shortcut:
|
cb->sc_next = op->o_callback; |
cb->sc_next = op->o_callback; |
op->o_callback = cb; |
op->o_callback = cb; |
|
|
op->o_sync_mode = 0; /* Don't let back-bdb see this */ |
/* FIXME: temporary hack to make sure back-bdb's native Psearch handling |
|
* doesn't get invoked. We can skip this after the back-bdb code is |
|
* removed, and also delete ss->ss_done. |
|
*/ |
|
op->o_sync_mode = 0; |
|
|
/* If this is a persistent search and no changes were reported during |
/* If this is a persistent search and no changes were reported during |
* the refresh phase, just invoke the response callback to transition |
* the refresh phase, just invoke the response callback to transition |
Line 878 shortcut:
|
Line 937 shortcut:
|
return SLAP_CB_CONTINUE; |
return SLAP_CB_CONTINUE; |
} |
} |
|
|
#if 0 |
|
static int |
|
syncprov_response( Operation *op, SlapReply *rs ) |
|
{ |
|
slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; |
|
syncprov_info_t *si = (syncprov_info_t *)on->on_bi.bi_private; |
|
|
|
if ( rs->sr_err == LDAP_SUCCESS ) { |
|
if ( op->o_tag == LDAP_REQ_SEARCH ) { |
|
/* handle transition from refresh to persist */ |
|
if ( op->o_sync_mode == SLAP_SYNC_REFRESH_AND_PERSIST ) { |
|
} |
|
|
|
/* If we're checkpointing */ |
|
} else if ( si->si_chkops || si->si_chktime )) { |
|
int do_check = 0; |
|
|
|
switch ( op->o_tag ) { |
|
case LDAP_REQ_EXTENDED: |
|
{ int i, doit = 0; |
|
|
|
/* if not PASSWD_MODIFY, break */ |
|
for ( i=0; write_exop[i]; i++ ) |
|
{ |
|
if ( !ber_bvcmp( write_exop[i], &op->oq_extended.rs_reqoid )) |
|
{ |
|
doit = 1; |
|
break; |
|
} |
|
} |
|
if ( !doit ) break; |
|
} |
|
/* else fallthru */ |
|
case LDAP_REQ_ADD: |
|
case LDAP_REQ_MODIFY: |
|
case LDAP_REQ_MODRDN: |
|
case LDAP_REQ_DELETE: |
|
ldap_pvt_thread_mutex_lock( &si->si_chk_mutex ); |
|
if ( si->si_chkops ) |
|
{ |
|
si->si_numops++; |
|
if ( si->si_numops >= si->si_chkops ) |
|
{ |
|
do_check = 1; |
|
si->si_numops = 0; |
|
} |
|
} |
|
if ( si->si_chktime ) |
|
{ |
|
if ( op->o_time - si->si_chklast >= si->si_chktime ) |
|
{ |
|
do_check = 1; |
|
si->si_chklast = op->o_time; |
|
} |
|
} |
|
ldap_pvt_thread_mutex_unlock( &si->si_chk_mutex ); |
|
if ( do_check ) |
|
{ |
|
/* write cn=ldapsync to underlying db */ |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
/* Release this DN */ |
|
if ( op->o_tag == LDAP_REQ_MODIFY ) { |
|
ldap_pvt_thread_mutex_lock( &si->si_mod_mutex ); |
|
avl_delete( &si->si_mods, &op->o_req_ndn, dn_avl_cmp ); |
|
ldap_pvt_thread_mutex_unlock( &si->si_mod_mutex ); |
|
} |
|
return SLAP_CB_CONTINUE; |
|
} |
|
#endif |
|
|
|
static int |
static int |
syncprov_db_config( |
syncprov_db_config( |
BackendDB *be, |
BackendDB *be, |