From 4efd705cc338951cc3b75653b5ec106b96237d93 Mon Sep 17 00:00:00 2001 From: Jong Hyuk Choi Date: Sat, 9 Oct 2004 09:26:16 +0000 Subject: [PATCH] syncrepl consistency patch --- include/ldap_log.h | 1 + servers/slapd/back-bdb/delete.c | 11 + servers/slapd/back-bdb/search.c | 369 ++++++++++++++++++++++++++++---- servers/slapd/proto-slap.h | 4 +- servers/slapd/slap.h | 19 ++ servers/slapd/syncrepl.c | 100 ++++++++- 6 files changed, 446 insertions(+), 58 deletions(-) diff --git a/include/ldap_log.h b/include/ldap_log.h index d053bdf78d..299e25f24a 100644 --- a/include/ldap_log.h +++ b/include/ldap_log.h @@ -96,6 +96,7 @@ LDAP_BEGIN_DECL #define LDAP_DEBUG_PARSE 0x0800 #define LDAP_DEBUG_CACHE 0x1000 #define LDAP_DEBUG_INDEX 0x2000 +#define LDAP_DEBUG_SYNC 0x4000 #define LDAP_DEBUG_NONE 0x8000 #define LDAP_DEBUG_ANY -1 diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index 80dfedaa74..be55bf1a94 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -366,6 +366,17 @@ retry: /* transaction retry */ goto return_results; } + ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock ); + LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) { + rc = bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREDELETE ); + if ( rc ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_delete: persistent search failed (%d,%d)\n", + rc, rs->sr_err, 0 ); + } + } + ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock ); + /* delete from dn2id */ rs->sr_err = bdb_dn2id_delete( op, lt2, eip, e ); if ( rs->sr_err != 0 ) { diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index 39f84b4e0c..be4c526df6 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -45,6 +45,9 @@ static void send_paged_response( ID *lastid, int tentries ); +static int bdb_pfid_cmp( const void *v_id1, const void *v_id2 ); +static ID* bdb_id_dup( Operation *op, ID *id ); + /* Dereference aliases for a single alias entry. Return the final * dereferenced entry on success, NULL on any failure. */ @@ -306,6 +309,7 @@ sameido: #define IS_BDB_REPLACE(type) (( type == LDAP_PSEARCH_BY_DELETE ) || \ ( type == LDAP_PSEARCH_BY_SCOPEOUT )) #define IS_PSEARCH (op != sop) +#define IS_POST_SEARCH ( op->ors_post_search_id != NOID ) static Operation * bdb_drop_psearch( Operation *op, ber_int_t msgid ) @@ -369,19 +373,170 @@ bdb_cancel( Operation *op, SlapReply *rs ) int bdb_search( Operation *op, SlapReply *rs ) { - return bdb_do_search( op, rs, op, NULL, 0 ); + int rc; + struct pc_entry *pce = NULL; + struct pc_entry *tmp_pce = NULL; + Entry ps_e = {0}; + Attribute *a; + + ps_e.e_private = NULL; + ldap_pvt_thread_mutex_init( &op->o_pcmutex ); + LDAP_TAILQ_INIT( &op->o_ps_pre_candidates ); + LDAP_TAILQ_INIT( &op->o_ps_post_candidates ); + + op->ors_post_search_id = NOID; + rc = bdb_do_search( op, rs, op, NULL, 0 ); + + ldap_pvt_thread_mutex_lock( &op->o_pcmutex ); + pce = LDAP_TAILQ_FIRST( &op->o_ps_post_candidates ); + ldap_pvt_thread_mutex_unlock( &op->o_pcmutex ); + + while ( rc == LDAP_SUCCESS && pce && + op->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) { + + ps_e.e_id = op->ors_post_search_id = pce->pc_id; + if ( op->o_sync_csn.bv_val ) { + ch_free( op->o_sync_csn.bv_val ); + op->o_sync_csn.bv_val = NULL; + } + ber_dupbv( &op->o_sync_csn, &pce->pc_csn ); + ber_dupbv( &ps_e.e_name, &pce->pc_ename ); + ber_dupbv( &ps_e.e_nname, &pce->pc_enname ); + a = ch_calloc( 1, sizeof( Attribute )); + a->a_desc = slap_schema.si_ad_entryUUID; + a->a_vals = ch_calloc( 2, sizeof( struct berval )); + ber_dupbv( &a->a_vals[0], &pce->pc_entryUUID ); + a->a_nvals = a->a_vals; + a->a_next = NULL; + ps_e.e_attrs = a; + + rc = bdb_do_search( op, rs, op, &ps_e, 0 ); + + tmp_pce = pce; + ldap_pvt_thread_mutex_lock( &op->o_pcmutex ); + pce = LDAP_TAILQ_NEXT( pce, pc_link ); + LDAP_TAILQ_REMOVE( &op->o_ps_post_candidates, tmp_pce, pc_link ); + ldap_pvt_thread_mutex_unlock( &op->o_pcmutex ); + + ch_free( tmp_pce->pc_csn.bv_val ); + ch_free( tmp_pce->pc_entryUUID.bv_val ); + ch_free( tmp_pce->pc_ename.bv_val ); + ch_free( tmp_pce->pc_enname.bv_val ); + ch_free( tmp_pce ); + entry_clean( &ps_e ); + } + return rc; } int bdb_psearch( Operation *op, SlapReply *rs, Operation *sop, Entry *ps_e, int ps_type ) { int rc; + struct pc_entry *pce = NULL; + struct pc_entry *p = NULL; - sop->o_private = op->o_private; - rc = bdb_do_search( op, rs, sop, ps_e, ps_type ); - sop->o_private = NULL; + op->ors_post_search_id = NOID; - return rc; + switch (ps_type) { + case LDAP_PSEARCH_BY_PREMODIFY: + case LDAP_PSEARCH_BY_PREDELETE: + + if ( sop->o_refresh_in_progress ) { + pce = (struct pc_entry *) ch_calloc( 1, sizeof( struct pc_entry )); + pce->pc_id = ps_e->e_id; + ldap_pvt_thread_mutex_lock( &sop->o_pcmutex ); + if ( LDAP_TAILQ_EMPTY( &sop->o_ps_pre_candidates )) { + LDAP_TAILQ_INSERT_HEAD( &sop->o_ps_pre_candidates, pce, pc_link ); + } else { + LDAP_TAILQ_FOREACH( p, &sop->o_ps_pre_candidates, pc_link ) { + if ( p->pc_id > pce->pc_id ) + break; + } + + if ( p ) { + LDAP_TAILQ_INSERT_BEFORE( p, pce, pc_link ); + } else { + LDAP_TAILQ_INSERT_TAIL( + &sop->o_ps_pre_candidates, + pce, pc_link ); + } + } + ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex ); + } else { + rc = bdb_do_search( op, rs, sop, ps_e, ps_type ); + return rc; + } + + /* Wait until refresh search send the entry */ + while ( !pce->pc_sent ) { + if ( sop->o_refresh_in_progress ) { + ldap_pvt_thread_yield(); + } else { + break; + } + } + + if ( !sop->o_refresh_in_progress && !pce->pc_sent ) { + /* refresh ended without processing pce */ + /* need to perform psearch for ps_e */ + ldap_pvt_thread_mutex_lock( &sop->o_pcmutex ); + LDAP_TAILQ_REMOVE( &sop->o_ps_pre_candidates, pce, pc_link ); + ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex ); + ch_free( pce ); + rc = bdb_do_search( op, rs, sop, ps_e, ps_type ); + return rc; + } else { + /* the pce entry was sent in the refresh phase */ + if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) { + struct psid_entry* psid_e; + psid_e = (struct psid_entry *) ch_calloc(1, + sizeof(struct psid_entry)); + psid_e->ps_op = sop; + LDAP_LIST_INSERT_HEAD( &op->o_pm_list, psid_e, ps_link ); + } + + ldap_pvt_thread_mutex_lock( &sop->o_pcmutex ); + LDAP_TAILQ_REMOVE( &sop->o_ps_pre_candidates, pce, pc_link ); + ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex ); + ch_free( pce ); + return LDAP_SUCCESS; + } + break; + case LDAP_PSEARCH_BY_DELETE: + case LDAP_PSEARCH_BY_SCOPEOUT: + case LDAP_PSEARCH_BY_ADD: + case LDAP_PSEARCH_BY_MODIFY: + ldap_pvt_thread_mutex_lock( &op->o_pcmutex ); + if ( sop->o_refresh_in_progress || + !LDAP_TAILQ_EMPTY( &sop->o_ps_post_candidates )) { + pce = (struct pc_entry *) ch_calloc( 1, sizeof( struct pc_entry )); + pce->pc_id = ps_e->e_id; +// pce->ps_type = ps_type; + ber_dupbv( &pce->pc_csn, &op->o_sync_csn ); + if ( ps_type == LDAP_PSEARCH_BY_DELETE ) { + Attribute *a; + for ( a = ps_e->e_attrs; a != NULL; a = a->a_next ) { + AttributeDescription *desc = a->a_desc; + if ( desc == slap_schema.si_ad_entryUUID ) { + ber_dupbv( &pce->pc_entryUUID, &a->a_nvals[0] ); + } + } + } + ber_dupbv( &pce->pc_ename, &ps_e->e_name ); + ber_dupbv( &pce->pc_enname, &ps_e->e_nname ); + LDAP_TAILQ_INSERT_TAIL( &sop->o_ps_post_candidates, pce, pc_link ); + ldap_pvt_thread_mutex_unlock( &op->o_pcmutex ); + } else { + ldap_pvt_thread_mutex_unlock( &op->o_pcmutex ); + rc = bdb_do_search( op, rs, sop, ps_e, ps_type ); + return rc; + } + break; + default: + Debug( LDAP_DEBUG_TRACE, "do_psearch: invalid psearch type\n", + 0, 0, 0 ); + return LDAP_OTHER; + } } /* For persistent searches, op is the currently executing operation, @@ -428,6 +583,7 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, const char *text; int slog_found = 0; + struct pc_entry *pce = NULL; BerVarray syncUUID_set = NULL; int syncUUID_set_cnt = 0; @@ -439,7 +595,8 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, opinfo = (struct bdb_op_info *) op->o_private; - if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) { + if ( !IS_POST_SEARCH && !IS_PSEARCH && + sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST ) { struct slap_session_entry *sent; if ( sop->o_sync_state.sid >= 0 ) { LDAP_LIST_FOREACH( sent, &bdb->bi_session_list, se_link ) { @@ -452,14 +609,16 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, } /* psearch needs to be registered before refresh begins */ - /* psearch and refresh transmission is serialized in send_ldap_ber() */ - if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_PERSIST ) { + if ( !IS_POST_SEARCH && !IS_PSEARCH && + sop->o_sync_mode & SLAP_SYNC_PERSIST ) { + sop->o_refresh_in_progress = 1; ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock ); LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link ); ldap_pvt_thread_rdwr_wunlock( &bdb->bi_pslist_rwlock ); - } else if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST - && sop->o_sync_slog_size >= 0 ) + } else if ( !IS_POST_SEARCH && !IS_PSEARCH && + sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST + && sop->o_sync_slog_size >= 0 ) { ldap_pvt_thread_rdwr_wlock( &bdb->bi_pslist_rwlock ); LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) { @@ -545,6 +704,14 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, } } + if ( IS_POST_SEARCH ) { + cursor = 0; + candidates[0] = 1; + candidates[1] = op->ors_post_search_id; + search_context_csn = ber_dupbv( NULL, &op->o_sync_csn ); + goto loop_start; + } + if ( sop->o_req_ndn.bv_len == 0 ) { /* DIT root special case */ ei_root.bei_e = &e_root; @@ -876,13 +1043,64 @@ dn2entry_retry: } } +loop_start: + for ( id = bdb_idl_first( candidates, &cursor ); - id != NOID && !no_sync_state_change; + id != NOID && !no_sync_state_change; id = bdb_idl_next( candidates, &cursor ) ) { int scopeok = 0; + ID* idhole = NULL; loop_begin: + + if ( !IS_POST_SEARCH ) { + idhole = (ID*) avl_find( sop->o_psearch_finished, + (caddr_t)&id, bdb_pfid_cmp ); + if ( idhole ) { + avl_delete( &sop->o_psearch_finished, + (caddr_t)idhole, bdb_pfid_cmp ); + sop->o_tmpfree( idhole, sop->o_tmpmemctx ); + goto loop_continue; + } + + if ( sop->o_refresh_in_progress ) { + ldap_pvt_thread_mutex_lock( &sop->o_pcmutex ); + pce = LDAP_TAILQ_FIRST( &sop->o_ps_pre_candidates ); + while ( pce && pce->pc_sent ) { + pce = LDAP_TAILQ_NEXT( pce, pc_link ); + } + ldap_pvt_thread_mutex_unlock( &sop->o_pcmutex ); + if ( pce ) { + ID pos; + if ( BDB_IDL_IS_RANGE( candidates ) ) { + if ( pce->pc_id >= candidates[1] && + pce->pc_id <= candidates[2] && + pce->pc_id > cursor-1 ) { + id = pce->pc_id; + cursor--; + avl_insert( &sop->o_psearch_finished, + (caddr_t)bdb_id_dup( sop, &pce->pc_id ), + bdb_pfid_cmp, avl_dup_error ); + } else { + pce->pc_sent = 1; + } + } else { + pos = bdb_idl_search(candidates, pce->pc_id); + if ( pos > cursor-1 && pos <= candidates[0] ) { + id = pce->pc_id; + cursor--; + avl_insert( &sop->o_psearch_finished, + (caddr_t)bdb_id_dup( sop, &pce->pc_id ), + bdb_pfid_cmp, avl_dup_error ); + } else { + pce->pc_sent = 1; + } + } + } + } + } + /* check for abandon */ if ( sop->o_abandon ) { if ( sop != op ) { @@ -937,7 +1155,11 @@ id2entry_retry: } if ( e == NULL ) { - if( !BDB_IDL_IS_RANGE(candidates) ) { + if ( IS_POST_SEARCH ) { + /* send LDAP_SYNC_DELETE */ + rs->sr_entry = e = ps_e; + goto post_search_no_entry; + } else if( !BDB_IDL_IS_RANGE(candidates) ) { /* only complain for non-range IDLs */ Debug( LDAP_DEBUG_TRACE, "bdb_search: candidate %ld not found\n", @@ -1049,7 +1271,7 @@ id2entry_retry: #endif /* Not in scope, ignore it */ - if ( !scopeok ) { + if ( !IS_POST_SEARCH && !scopeok ) { Debug( LDAP_DEBUG_TRACE, "bdb_search: %ld scope not okay\n", (long) id, 0, 0 ); @@ -1091,29 +1313,39 @@ id2entry_retry: } } else { - if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - rc_sync = test_filter( sop, rs->sr_entry, &cookief ); - rs->sr_err = test_filter( sop, rs->sr_entry, &contextcsnand ); - if ( rs->sr_err == LDAP_COMPARE_TRUE ) { - if ( rc_sync == LDAP_COMPARE_TRUE ) { - if ( no_sync_state_change ) { - Debug( LDAP_DEBUG_TRACE, - "bdb_search: error in context csn management\n", - 0, 0, 0 ); - } - entry_sync_state = LDAP_SYNC_ADD; + if ( !IS_POST_SEARCH ) { + if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { + rc_sync = test_filter( sop, rs->sr_entry, &cookief ); + rs->sr_err = test_filter( sop, rs->sr_entry, + &contextcsnand ); + if ( rs->sr_err == LDAP_COMPARE_TRUE ) { + if ( rc_sync == LDAP_COMPARE_TRUE ) { + if ( no_sync_state_change ) { + Debug( LDAP_DEBUG_TRACE, + "bdb_search: " + "error in context csn management\n", + 0, 0, 0 ); + } + entry_sync_state = LDAP_SYNC_ADD; - } else { - if ( no_sync_state_change ) { - goto loop_continue; + } else { + if ( no_sync_state_change ) { + goto loop_continue; + } + entry_sync_state = LDAP_SYNC_PRESENT; } - entry_sync_state = LDAP_SYNC_PRESENT; } + } else { + rs->sr_err = test_filter( sop, + rs->sr_entry, sop->oq_search.rs_filter ); } - } else { - rs->sr_err = test_filter( sop, - rs->sr_entry, sop->oq_search.rs_filter ); + if ( scopeok ) { + rs->sr_err = test_filter( sop, + rs->sr_entry, sop->oq_search.rs_filter ); + } else { + rs->sr_err = LDAP_COMPARE_TRUE; + } } } @@ -1147,16 +1379,17 @@ id2entry_retry: /* safe default */ int result = -1; - if (IS_PSEARCH) { + if (IS_PSEARCH || IS_POST_SEARCH) { int premodify_found = 0; - int entry_sync_state; - if ( ps_type == LDAP_PSEARCH_BY_ADD || + if ( IS_POST_SEARCH || + ps_type == LDAP_PSEARCH_BY_ADD || ps_type == LDAP_PSEARCH_BY_DELETE || ps_type == LDAP_PSEARCH_BY_MODIFY || ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) { - if ( ps_type == LDAP_PSEARCH_BY_MODIFY ) { + if ( !IS_POST_SEARCH && + ps_type == LDAP_PSEARCH_BY_MODIFY ) { struct psid_entry* psid_e; LDAP_LIST_FOREACH( psid_e, &op->o_pm_list, ps_link) @@ -1170,7 +1403,14 @@ id2entry_retry: if (psid_e != NULL) free (psid_e); } - if ( ps_type == LDAP_PSEARCH_BY_ADD ) { + if ( IS_POST_SEARCH ) { + if ( scopeok ) { + entry_sync_state = LDAP_SYNC_ADD; + } else { +post_search_no_entry: + entry_sync_state = LDAP_SYNC_DELETE; + } + } else if ( ps_type == LDAP_PSEARCH_BY_ADD ) { entry_sync_state = LDAP_SYNC_ADD; } else if ( ps_type == LDAP_PSEARCH_BY_DELETE ) { entry_sync_state = LDAP_SYNC_DELETE; @@ -1199,11 +1439,16 @@ id2entry_retry: search_context_csn, sop->o_sync_state.sid, sop->o_sync_state.rid ); - rs->sr_err = slap_build_sync_state_ctrl( sop, - rs, e, entry_sync_state, ctrls, + rs->sr_err = slap_build_sync_state_ctrl( + sop, rs, e, entry_sync_state, ctrls, num_ctrls++, 1, &cookie ); if ( rs->sr_err != LDAP_SUCCESS ) goto done; - rs->sr_attrs = attrs; + if (!(IS_POST_SEARCH && + entry_sync_state == LDAP_SYNC_DELETE)) { + rs->sr_attrs = attrs; + } else { + rs->sr_attrs = NULL; + } rs->sr_operational_attrs = NULL; rs->sr_ctrls = ctrls; rs->sr_flags = 0; @@ -1235,8 +1480,8 @@ id2entry_retry: } else { if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */ - rs->sr_err = slap_build_sync_state_ctrl( sop, - rs, e, entry_sync_state, ctrls, + rs->sr_err = slap_build_sync_state_ctrl( + sop, rs, e, entry_sync_state, ctrls, num_ctrls++, 0, NULL ); if ( rs->sr_err != LDAP_SUCCESS ) goto done; rs->sr_ctrls = ctrls; @@ -1321,15 +1566,24 @@ loop_continue: if( e != NULL ) { /* free reader lock */ if (!IS_PSEARCH) { - bdb_cache_return_entry_r( bdb->bi_dbenv, - &bdb->bi_cache, e , &lock ); - if ( sop->o_nocaching ) { - bdb_cache_delete_entry( bdb, ei, locker, &lock ); + if (!(IS_POST_SEARCH && + entry_sync_state == LDAP_SYNC_DELETE)) { + bdb_cache_return_entry_r( bdb->bi_dbenv, + &bdb->bi_cache, e , &lock ); + if ( sop->o_nocaching ) { + bdb_cache_delete_entry( bdb, ei, locker, &lock ); + } } } e = NULL; rs->sr_entry = NULL; } + + if ( sop->o_refresh_in_progress ) { + if ( pce ) { + pce->pc_sent = 1; + } + } ldap_pvt_thread_yield(); } @@ -1345,7 +1599,7 @@ loop_continue: } nochange: - if (!IS_PSEARCH) { + if (!IS_PSEARCH && !IS_POST_SEARCH) { if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { if ( sop->o_sync_mode & SLAP_SYNC_PERSIST ) { struct berval cookie; @@ -1458,9 +1712,17 @@ nochange: } } + if ( sop->o_refresh_in_progress ) { + sop->o_refresh_in_progress = 0; + } + rs->sr_err = LDAP_SUCCESS; done: + if ( sop->o_psearch_finished ) { + avl_free( sop->o_psearch_finished, ch_free ); + } + if( !IS_PSEARCH && e != NULL ) { /* free reader lock */ bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); @@ -1849,3 +2111,18 @@ done: (void) ber_free_buf( ber ); } +static int +bdb_pfid_cmp( const void *v_id1, const void *v_id2 ) +{ + const ID *p1 = v_id1, *p2 = v_id2; + return *p1 - *p2; +} + +static ID* +bdb_id_dup( Operation *op, ID *id ) +{ + ID *new; + new = ch_malloc( sizeof(ID) ); + *new = *id; + return new; +} diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 244d4ccd86..c1b316d8fc 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -694,8 +694,8 @@ LDAP_SLAPD_V (int) krbv4_ldap_auth(); * ldapsync.c */ LDAP_SLAPD_F (int) slap_build_sync_state_ctrl LDAP_P(( - Operation *, SlapReply *, Entry *, int, LDAPControl **, - int, int, struct berval * )); + Operation *, SlapReply *, Entry *, int, + LDAPControl **, int, int, struct berval * )); LDAP_SLAPD_F (int) slap_build_sync_done_ctrl LDAP_P(( Operation *, SlapReply *, LDAPControl **, int, int, struct berval *, int )); diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 6b762c6bbc..5d7b4f91e8 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1662,6 +1662,7 @@ typedef struct req_search_s { AttributeName *rs_attrs; Filter *rs_filter; struct berval rs_filterstr; + int rs_post_search_id; } req_search_s; typedef struct req_compare_s { @@ -1998,6 +1999,7 @@ typedef struct slap_paged_state { #define LDAP_PSEARCH_BY_PREMODIFY 0x03 #define LDAP_PSEARCH_BY_MODIFY 0x04 #define LDAP_PSEARCH_BY_SCOPEOUT 0x05 +#define LDAP_PSEARCH_BY_PREDELETE 0x06 struct psid_entry { struct slap_op *ps_op; @@ -2029,6 +2031,16 @@ struct slap_csn_entry { LDAP_TAILQ_ENTRY (slap_csn_entry) ce_csn_link; }; +struct pc_entry { + ID pc_id; + int pc_sent; + struct berval pc_csn; + struct berval pc_entryUUID; + struct berval pc_ename; + struct berval pc_enname; + LDAP_TAILQ_ENTRY( pc_entry ) pc_link; +}; + /* * Caches the result of a backend_group check for ACL evaluation */ @@ -2101,6 +2113,7 @@ typedef struct slap_op { #define ors_attrs oq_search.rs_attrs #define ors_filter oq_search.rs_filter #define ors_filterstr oq_search.rs_filterstr +#define ors_post_search_id oq_search.rs_post_search_id #define orr_newrdn oq_modrdn.rs_newrdn #define orr_nnewrdn oq_modrdn.rs_nnewrdn @@ -2202,6 +2215,12 @@ typedef struct slap_op { LDAP_LIST_ENTRY(slap_op) o_ps_link; LDAP_LIST_HEAD(pe, psid_entry) o_pm_list; + int o_refresh_in_progress; + LDAP_TAILQ_HEAD(pc_pre, pc_entry) o_ps_pre_candidates; + LDAP_TAILQ_HEAD(pc_post, pc_entry) o_ps_post_candidates; + Avlnode *o_psearch_finished; + ldap_pvt_thread_mutex_t o_pcmutex; + AuthorizationInformation o_authz; BerElement *o_ber; /* ber of the request */ diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index 2389fcb1b5..a043f13f8f 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -48,6 +48,9 @@ static int dn_callback( struct slap_op *, struct slap_rep * ); static int nonpresent_callback( struct slap_op *, struct slap_rep * ); static int null_callback( struct slap_op *, struct slap_rep * ); +static int si_refreshDelete = 0; +static int si_refreshPresent = 0; + static AttributeDescription *sync_descs[4]; struct runqueue_s syncrepl_rq; @@ -588,7 +591,7 @@ do_syncrep2( ldap_get_entry_controls( si->si_ld, msg, &rctrls ); /* we can't work without the control */ if ( !rctrls ) { - Debug( LDAP_DEBUG_ANY, "do_syncrep2 : " + Debug( LDAP_DEBUG_ANY, "do_syncrep2: " "got search entry without " "control\n", 0, 0, 0 ); rc = -1; @@ -632,10 +635,12 @@ do_syncrep2( case LDAP_RES_SEARCH_REFERENCE: Debug( LDAP_DEBUG_ANY, - "do_syncrep2 : reference received\n", 0, 0, 0 ); + "do_syncrep2: reference received error\n", 0, 0, 0 ); break; case LDAP_RES_SEARCH_RESULT: + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: LDAP_RES_SEARCH_RESULT\n", 0, 0, 0 ); ldap_parse_result( si->si_ld, msg, &err, NULL, NULL, NULL, &rctrls, 0 ); if ( rctrls ) { @@ -703,18 +708,31 @@ do_syncrep2( rc = ldap_parse_intermediate( si->si_ld, msg, &retoid, &retdata, NULL, 0 ); if ( !rc && !strcmp( retoid, LDAP_SYNC_INFO ) ) { - int si_refreshDelete = 0; - int si_refreshPresent = 0; ber_init2( ber, retdata, LBER_USE_DER ); switch ( si_tag = ber_peek_tag( ber, &len )) { ber_tag_t tag; case LDAP_TAG_SYNC_NEW_COOKIE: + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: %s - %s%s\n", + "LDAP_RES_INTERMEDIATE", + "NEW_COOKIE", "\n" ); ber_scanf( ber, "tm", &tag, &cookie ); break; case LDAP_TAG_SYNC_REFRESH_DELETE: + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: %s - %s%s\n", + "LDAP_RES_INTERMEDIATE", + "REFRESH_DELETE\n", "\n" ); si_refreshDelete = 1; case LDAP_TAG_SYNC_REFRESH_PRESENT: + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: %s - %s%s\n", + "LDAP_RES_INTERMEDIATE", + si_tag == LDAP_TAG_SYNC_REFRESH_PRESENT ? + "REFRESH_PRESENT" : "REFRESH_DELETE", + "\n" ); + si_refreshDelete = 1; si_refreshPresent = 1; ber_scanf( ber, "t{" /*"}"*/, &tag ); if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) @@ -740,6 +758,11 @@ do_syncrep2( ber_scanf( ber, /*"{"*/ "}" ); break; case LDAP_TAG_SYNC_ID_SET: + Debug( LDAP_DEBUG_SYNC, + "do_syncrep2: %s - %s%s\n", + "LDAP_RES_INTERMEDIATE", + "SYNC_ID_SET", + "\n" ); ber_scanf( ber, "t{" /*"}"*/, &tag ); if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) @@ -775,8 +798,8 @@ do_syncrep2( slap_sl_free( syncUUIDs, op->o_tmpmemctx ); break; default: - Debug( LDAP_DEBUG_ANY, - "do_syncrep2 : unknown syncinfo tag (%ld)\n", + Debug( LDAP_DEBUG_ANY, + "do_syncrep2 : unknown syncinfo tag (%ld)\n", (long) si_tag, 0, 0 ); ldap_memfree( retoid ); ber_bvfree( retdata ); @@ -919,6 +942,8 @@ do_syncrepl( /* Establish session, do search */ if ( !si->si_ld ) { first = 1; + si_refreshDelete = 0; + si_refreshPresent = 0; rc = do_syncrep1( &op, si ); } @@ -1170,10 +1195,42 @@ syncrepl_entry( struct berval org_ndn = BER_BVNULL; int org_managedsait; + Debug( LDAP_DEBUG_SYNC, "%s: %s", + "syncrepl_entry", + "LDAP_RES_SEARCH_ENTRY", 0 ); + switch( syncstate ) { + case LDAP_SYNC_PRESENT: + Debug( LDAP_DEBUG_SYNC, "%s: %s", + "syncrepl_entry", + "LDAP_SYNC_PRESENT", "\n" ); + break; + case LDAP_SYNC_ADD: + Debug( LDAP_DEBUG_SYNC, "%s: %s", + "syncrepl_entry", + "LDAP_SYNC_ADD", "\n" ); + break; + case LDAP_SYNC_DELETE: + Debug( LDAP_DEBUG_SYNC, "%s: %s", + "syncrepl_entry", + "LDAP_SYNC_DELETE", "\n" ); + break; + case LDAP_SYNC_MODIFY: + Debug( LDAP_DEBUG_SYNC, "%s: %s", + "syncrepl_entry", + "LDAP_SYNC_MODIFY", "\n" ); + break; + default: + Debug( LDAP_DEBUG_ANY, "%s: %s", + "syncrepl_entry", + "UNKNONW syncstate", "\n" ); + } + if (( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) { - syncuuid_bv = ber_dupbv( NULL, syncUUID ); - avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv, - syncuuid_cmp, avl_dup_error ); + if ( !si_refreshPresent ) { + syncuuid_bv = ber_dupbv( NULL, syncUUID ); + avl_insert( &si->si_presentlist, (caddr_t) syncuuid_bv, + syncuuid_cmp, avl_dup_error ); + } } if ( syncstate == LDAP_SYNC_PRESENT ) { @@ -1222,6 +1279,9 @@ syncrepl_entry( if ( limits_check( op, &rs_search ) == 0 ) { rc = be->be_search( op, &rs_search ); + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s (%d)\n", + "be_search", rc, 0 ); } if ( !BER_BVISNULL( &op->ors_filterstr ) ) { @@ -1231,7 +1291,18 @@ syncrepl_entry( cb.sc_response = null_callback; cb.sc_private = si; - if ( rs_search.sr_err == LDAP_SUCCESS && !BER_BVISNULL( &si->si_syncUUID_ndn ) ) + if ( entry && entry->e_name.bv_val ) { + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s\n", + entry->e_name.bv_val, 0, 0 ); + } else { + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s\n", + si->si_syncUUID_ndn.bv_val, 0, 0 ); + } + + if ( rs_search.sr_err == LDAP_SUCCESS && + !BER_BVISNULL( &si->si_syncUUID_ndn )) { char *subseq_ptr; @@ -1250,6 +1321,9 @@ syncrepl_entry( op->o_req_ndn = si->si_syncUUID_ndn; op->o_tag = LDAP_REQ_DELETE; rc = be->be_delete( op, &rs_delete ); + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s (%d)\n", + "be_delete", rc, 0 ); org_req_dn = op->o_req_dn; org_req_ndn = op->o_req_ndn; @@ -1303,6 +1377,9 @@ syncrepl_entry( op->o_req_ndn = entry->e_nname; rc = be->be_add( op, &rs_add ); + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s (%d)\n", + "be_add", rc, 0 ); if ( rs_add.sr_err != LDAP_SUCCESS ) { if ( rs_add.sr_err == LDAP_ALREADY_EXISTS && @@ -1330,6 +1407,9 @@ syncrepl_entry( op->o_req_ndn = entry->e_nname; rc = be->be_modify( op, &rs_modify ); + Debug( LDAP_DEBUG_SYNC, + "syncrepl_entry: %s (%d)\n", + "be_modify", rc, 0 ); if ( rs_modify.sr_err != LDAP_SUCCESS ) { Debug( LDAP_DEBUG_ANY, "syncrepl_entry : be_modify failed (%d)\n", -- 2.39.5