From: Jong Hyuk Choi Date: Mon, 10 Nov 2003 02:44:25 +0000 (+0000) Subject: 1. Session history support X-Git-Tag: OPENLDAP_REL_ENG_2_1_MP~458 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=279760a4674c26b8d6b6a843c2fd20e630e3c7d6;p=openldap 1. Session history support - memory based session history to minimize sync traffic - when client is covered by a session history, then [add+delete] mode is used - when client cookie is not covered by the history because the cookie is too outdated and/or the history is truncated, [add+present] mode is used 2. Sync cookie syntax : comma separated name=value pairs - csn=yyyymmddhh:mm:ssZ#0xSSSS#r#ssssr,sid=nnn --- diff --git a/servers/slapd/Makefile.in b/servers/slapd/Makefile.in index b5b76a2ef1..2ece47608f 100644 --- a/servers/slapd/Makefile.in +++ b/servers/slapd/Makefile.in @@ -23,7 +23,7 @@ SRCS = main.c globals.c config.c daemon.c \ oidm.c starttls.c index.c sets.c referral.c root_dse.c \ sasl.c module.c mra.c mods.c sl_malloc.c limits.c \ backglue.c operational.c matchedValues.c cancel.c syncrepl.c \ - backover.c ctxcsn.c $(@PLAT@_SRCS) + backover.c ctxcsn.c ldapsync.c sessionlog.c $(@PLAT@_SRCS) OBJS = main.o globals.o config.o daemon.o \ connection.o search.o filter.o add.o cr.o \ @@ -37,7 +37,7 @@ OBJS = main.o globals.o config.o daemon.o \ oidm.o starttls.o index.o sets.o referral.o root_dse.o \ sasl.o module.o mra.o mods.o sl_malloc.o limits.o \ backglue.o operational.o matchedValues.o cancel.o syncrepl.o \ - backover.o ctxcsn.o $(@PLAT@_OBJS) + backover.o ctxcsn.o ldapsync.o sessionlog.o $(@PLAT@_OBJS) LDAP_INCDIR= ../../include -I$(srcdir)/slapi LDAP_LIBDIR= ../../libraries diff --git a/servers/slapd/back-bdb/add.c b/servers/slapd/back-bdb/add.c index c393cdf968..bb6e2aeb2e 100644 --- a/servers/slapd/back-bdb/add.c +++ b/servers/slapd/back-bdb/add.c @@ -528,7 +528,7 @@ retry: /* transaction retry */ return_results: send_ldap_result( op, rs ); - if ( rs->sr_err == LDAP_SUCCESS && !noop ) { + if ( rs->sr_err == LDAP_SUCCESS && !noop && !op->o_no_psearch ) { LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { bdb_psearch( op, rs, ps_list, op->oq_add.rs_e, LDAP_PSEARCH_BY_ADD ); } diff --git a/servers/slapd/back-bdb/back-bdb.h b/servers/slapd/back-bdb/back-bdb.h index 1a249f41e6..76e130fb88 100644 --- a/servers/slapd/back-bdb/back-bdb.h +++ b/servers/slapd/back-bdb/back-bdb.h @@ -162,6 +162,8 @@ struct bdb_info { ID bi_lastid; ldap_pvt_thread_mutex_t bi_lastid_mutex; LDAP_LIST_HEAD(pl, slap_op) bi_psearch_list; + ldap_pvt_thread_mutex_t bi_pslist_mutex; + LDAP_LIST_HEAD(se, slap_session_entry) bi_session_list; #ifdef SLAP_IDL_CACHE int bi_idl_cache_max_size; int bi_idl_cache_size; diff --git a/servers/slapd/back-bdb/config.c b/servers/slapd/back-bdb/config.c index d1bd93cd75..7fa83327ac 100644 --- a/servers/slapd/back-bdb/config.c +++ b/servers/slapd/back-bdb/config.c @@ -127,31 +127,31 @@ bdb_db_config( if( rc != LDAP_SUCCESS ) return 1; /* unique key for shared memory regions */ - } else if ( strcasecmp( argv[0], "shm_key" ) == 0 ) { - if ( argc < 2 ) { - fprintf( stderr, - "%s: line %d: missing key in \"shm_key \" line\n", - fname, lineno ); - return( 1 ); - } - bdb->bi_shm_key = atoi( argv[1] ); + } else if ( strcasecmp( argv[0], "shm_key" ) == 0 ) { + if ( argc < 2 ) { + fprintf( stderr, + "%s: line %d: missing key in \"shm_key \" line\n", + fname, lineno ); + return( 1 ); + } + bdb->bi_shm_key = atoi( argv[1] ); /* size of the cache in entries */ - } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) { - if ( argc < 2 ) { - fprintf( stderr, - "%s: line %d: missing size in \"cachesize \" line\n", - fname, lineno ); - return( 1 ); - } - bdb->bi_cache.c_maxsize = atoi( argv[1] ); + } else if ( strcasecmp( argv[0], "cachesize" ) == 0 ) { + if ( argc < 2 ) { + fprintf( stderr, + "%s: line %d: missing size in \"cachesize \" line\n", + fname, lineno ); + return( 1 ); + } + bdb->bi_cache.c_maxsize = atoi( argv[1] ); /* depth of search stack cache in units of (IDL)s */ - } else if ( strcasecmp( argv[0], "searchstack" ) == 0 ) { + } else if ( strcasecmp( argv[0], "searchstack" ) == 0 ) { if ( argc < 2 ) { fprintf( stderr, - "%s: line %d: missing depth in \"searchstack \" line\n", - fname, lineno ); + "%s: line %d: missing depth in \"searchstack \" line\n", + fname, lineno ); return( 1 ); } bdb->bi_search_stack_depth = atoi( argv[1] ); @@ -165,17 +165,82 @@ bdb_db_config( #ifdef SLAP_IDL_CACHE /* size of the IDL cache in entries */ - } else if ( strcasecmp( argv[0], "idlcachesize" ) == 0 ) { - if ( argc < 2 ) { - fprintf( stderr, - "%s: line %d: missing size in \"idlcachesize \" line\n", - fname, lineno ); - return( 1 ); - } - if ( !( slapMode & SLAP_TOOL_MODE ) ) - bdb->bi_idl_cache_max_size = atoi( argv[1] ); + } else if ( strcasecmp( argv[0], "idlcachesize" ) == 0 ) { + if ( argc < 2 ) { + fprintf( stderr, + "%s: line %d: missing size in \"idlcachesize \" line\n", + fname, lineno ); + return( 1 ); + } + if ( !( slapMode & SLAP_TOOL_MODE ) ) + bdb->bi_idl_cache_max_size = atoi( argv[1] ); #endif + } else if ( strcasecmp( argv[0], "sessionlog" ) == 0 ) { + int se_id = 0, se_size = 0; + struct slap_session_entry *sent; + if ( argc < 3 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing arguments in \"sessionlog \"" + " line.\n", fname, lineno , 0 ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing arguments in \"sessionlog \"" + " line\n", fname, lineno, 0 ); +#endif + return( 1 ); + } + + se_id = atoi( argv[1] ); + se_size = atoi( argv[2] ); + + if ( se_id < 0 || se_id > 999 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: session log id %d is out of range [0..999]\n", + fname, lineno , se_id ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: session log id %d is out of range [0..999]\n", + fname, lineno , se_id ); +#endif + return( 1 ); + } + + if ( se_size < 0 || se_size > 999 ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: session log size %d is negative\n", + fname, lineno , se_size ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: session log size %d is negative\n", + fname, lineno , se_size ); +#endif + return( 1 ); + } + + LDAP_LIST_FOREACH( sent, &bdb->bi_session_list, se_link ) { + if ( sent->se_id == se_id ) { +#ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: session %d already exists\n", + fname, lineno , se_id ); +#else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: session %d already exists\n", + fname, lineno , se_id ); +#endif + return( 1 ); + } + } + sent = (struct slap_session_entry *) ch_calloc( 1, + sizeof( struct slap_session_entry )); + sent->se_id = se_id; + sent->se_size = se_size; + LDAP_LIST_INSERT_HEAD( &bdb->bi_session_list, sent, se_link ); + /* anything else */ } else { fprintf( stderr, "%s: line %d: " diff --git a/servers/slapd/back-bdb/ctxcsn.c b/servers/slapd/back-bdb/ctxcsn.c index a2cbadfd77..6d9af8c80b 100644 --- a/servers/slapd/back-bdb/ctxcsn.c +++ b/servers/slapd/back-bdb/ctxcsn.c @@ -262,6 +262,7 @@ bdb_get_commit_csn( int num_retries = 0; int ctxcsn_added = 0; int rc; + struct sync_cookie syncCookie = { NULL, -1, NULL}; if ( op->o_sync_mode != SLAP_SYNC_NONE ) { if ( op->o_bd->be_syncinfo ) { @@ -271,7 +272,8 @@ bdb_get_commit_csn( ber_str2bv( substr, 0, 0, &bv ); build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &bv, NULL ); } else { - build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], (struct berval *)&slap_ldapsync_cn_bv, NULL ); + build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], + (struct berval *)&slap_ldapsync_cn_bv, NULL ); } ctxcsn_retry : @@ -330,7 +332,8 @@ txn_retry: return rs->sr_err; } - bdb_cache_add( bdb, suffix_ei, ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker ); + bdb_cache_add( bdb, suffix_ei, ctxcsn_e, + (struct berval *)&slap_ldapsync_cn_bv, locker ); rs->sr_err = TXN_COMMIT( ltid, 0 ); if ( rs->sr_err != 0 ) { @@ -361,14 +364,24 @@ txn_retry: if ( op->o_bd->be_syncinfo ) { csn_a = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_syncreplCookie ); + if ( csn_a ) { + struct berval cookie; + ber_dupbv( &cookie, &csn_a->a_vals[0] ); + ber_bvarray_add( &syncCookie.octet_str, &cookie ); + slap_parse_sync_cookie( &syncCookie ); + *search_context_csn = ber_dupbv( NULL, syncCookie.ctxcsn ); + slap_sync_cookie_free( &syncCookie, 0 ); + } else { + *search_context_csn = NULL; + } } else { csn_a = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN ); - } - if ( csn_a ) { - *search_context_csn = ber_dupbv( NULL, &csn_a->a_vals[0] ); - } else { - *search_context_csn = NULL; + if ( csn_a ) { + *search_context_csn = ber_dupbv( NULL, &csn_a->a_vals[0] ); + } else { + *search_context_csn = NULL; + } } } else { *search_context_csn = NULL; diff --git a/servers/slapd/back-bdb/delete.c b/servers/slapd/back-bdb/delete.c index 5872be64ec..fa25873ac7 100644 --- a/servers/slapd/back-bdb/delete.c +++ b/servers/slapd/back-bdb/delete.c @@ -540,7 +540,7 @@ retry: /* transaction retry */ return_results: send_ldap_result( op, rs ); - if ( rs->sr_err == LDAP_SUCCESS && !noop ) { + if ( rs->sr_err == LDAP_SUCCESS && !noop && !op->o_no_psearch ) { LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) { bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_DELETE ); } diff --git a/servers/slapd/back-bdb/modify.c b/servers/slapd/back-bdb/modify.c index 79455549d5..ba219deaa5 100644 --- a/servers/slapd/back-bdb/modify.c +++ b/servers/slapd/back-bdb/modify.c @@ -467,7 +467,7 @@ retry: /* transaction retry */ goto return_results; } - if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop && !op->o_no_psearch ) { LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { bdb_psearch(op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); } diff --git a/servers/slapd/back-bdb/modrdn.c b/servers/slapd/back-bdb/modrdn.c index b85d50a0af..18f14807aa 100644 --- a/servers/slapd/back-bdb/modrdn.c +++ b/servers/slapd/back-bdb/modrdn.c @@ -864,7 +864,7 @@ retry: /* transaction retry */ goto return_results; } - if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop ) { + if ( rs->sr_err == LDAP_SUCCESS && !op->o_noop && !op->o_no_psearch ) { LDAP_LIST_FOREACH ( ps_list, &bdb->bi_psearch_list, o_ps_link ) { bdb_psearch( op, rs, ps_list, e, LDAP_PSEARCH_BY_PREMODIFY ); } diff --git a/servers/slapd/back-bdb/proto-bdb.h b/servers/slapd/back-bdb/proto-bdb.h index f9e14ee560..8fb4a11698 100644 --- a/servers/slapd/back-bdb/proto-bdb.h +++ b/servers/slapd/back-bdb/proto-bdb.h @@ -548,30 +548,8 @@ int bdb_do_search( ); #define bdb_psearch(op, rs, sop, e, ps_type) bdb_do_search(op, rs, sop, e, ps_type) -#define bdb_build_sync_state_ctrl BDB_SYMBOL(build_sync_state_ctrl) -#define bdb_build_sync_done_ctrl BDB_SYMBOL(build_sync_done_ctrl) #define bdb_send_ldap_intermediate BDB_SYMBOL(send_ldap_intermediate) -int -bdb_build_sync_state_ctrl( - Operation *op, - SlapReply *rs, - Entry *e, - int entry_sync_state, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *csn ); - -int -bdb_build_sync_done_ctrl( - Operation *op, - SlapReply *rs, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *latest_entrycsn_bv ); - int bdb_send_ldap_intermediate( Operation *op, diff --git a/servers/slapd/back-bdb/search.c b/servers/slapd/back-bdb/search.c index e3cf6b03d8..0cf8f48dca 100644 --- a/servers/slapd/back-bdb/search.c +++ b/servers/slapd/back-bdb/search.c @@ -378,7 +378,6 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, AttributeName *attrs; Filter contextcsnand, contextcsnle, cookief, csnfnot, csnfeq, csnfand, csnfge; - Filter omitcsnf, omitcsnfle; AttributeAssertion aa_ge, aa_eq, aa_le; int entry_count = 0; struct berval *search_context_csn = NULL; @@ -396,19 +395,86 @@ bdb_do_search( Operation *op, SlapReply *rs, Operation *sop, u_int32_t locker = 0; DB_LOCK lock; + Operation *ps_list; + int sync_send_present_mode = 1; + int match; + MatchingRule *mr; + const char *text; + int slog_found = 0; + #ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ENTRY, "bdb_back_search\n", 0, 0, 0 ); + LDAP_LOG( OPERATION, ENTRY, "bdb_search\n", 0, 0, 0 ); #else - Debug( LDAP_DEBUG_TRACE, "=> bdb_back_search\n", + Debug( LDAP_DEBUG_TRACE, "=> bdb_search\n", 0, 0, 0); #endif attrs = sop->oq_search.rs_attrs; + if ( !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 ) { + if ( sent->se_id == sop->o_sync_state.sid ) { + sop->o_sync_slog_size = sent->se_size; + break; + } + } + } + } + /* 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 ) { + ldap_pvt_thread_mutex_lock( &bdb->bi_pslist_mutex ); LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link ); + ldap_pvt_thread_mutex_unlock( &bdb->bi_pslist_mutex ); + } else if ( !IS_PSEARCH && sop->o_sync_mode & SLAP_SYNC_REFRESH_AND_PERSIST + && sop->o_sync_slog_size >= 0 ) { + ldap_pvt_thread_mutex_lock( &bdb->bi_pslist_mutex ); + LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) { + if ( ps_list->o_sync_slog_size >= 0 ) { + if ( ps_list->o_sync_state.sid == sop->o_sync_state.sid ) { + slog_found = 1; + break; + } + } + } + + if ( slog_found ) { + if ( ps_list->o_sync_slog_omitcsn.bv_len != 0 ) { + mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering; + if ( sop->o_sync_state.ctxcsn && sop->o_sync_state.ctxcsn->bv_val != NULL ) { + value_match( &match, slap_schema.si_ad_entryCSN, mr, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + sop->o_sync_state.ctxcsn, &ps_list->o_sync_slog_omitcsn, + &text ); + } else { + match = -1; + } + if ( match >= 0 ) { + rs->sr_err = LDAP_SUCCESS; + rs->sr_rspoid = LDAP_SYNC_INFO; + rs->sr_ctrls = NULL; + bdb_send_ldap_intermediate( sop, rs, + LDAP_SYNC_STATE_MODE_DONE, NULL ); + sync_send_present_mode = 0; + } + } else { + rs->sr_err = LDAP_SUCCESS; + rs->sr_rspoid = LDAP_SYNC_INFO; + rs->sr_ctrls = NULL; + bdb_send_ldap_intermediate( sop, rs, + LDAP_SYNC_STATE_MODE_DONE, NULL ); + sync_send_present_mode = 0; + } + } else if ( sop->o_sync_slog_size >= 0 ) { + LDAP_LIST_INSERT_HEAD( &bdb->bi_psearch_list, sop, o_ps_link ); + } else { + sop->o_sync_state.sid = -1; + } + ldap_pvt_thread_mutex_unlock( &bdb->bi_pslist_mutex ); } + null_attr.an_desc = NULL; null_attr.an_oc = NULL; null_attr.an_name.bv_len = 0; @@ -670,8 +736,9 @@ dn2entry_retry: goto done; } - if ( sop->o_sync_state.bv_val && ber_bvcmp( &sop->o_sync_state, - search_context_csn ) == 0 ) + if ( sop->o_sync_mode != SLAP_SYNC_NONE && sop->o_sync_state.ctxcsn && + sop->o_sync_state.ctxcsn->bv_val && + ber_bvcmp( &sop->o_sync_state.ctxcsn[0], search_context_csn ) == 0 ) { bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock ); goto nochange; @@ -777,8 +844,6 @@ dn2entry_retry: if ( (sop->o_sync_mode & SLAP_SYNC_REFRESH) || IS_PSEARCH ) { - MatchingRule *mr; - const char *text; int match; cookief.f_choice = LDAP_FILTER_AND; @@ -792,7 +857,11 @@ dn2entry_retry: csnfeq.f_choice = LDAP_FILTER_EQUALITY; csnfeq.f_ava = &aa_eq; csnfeq.f_av_desc = slap_schema.si_ad_entryCSN; - csnfeq.f_av_value = sop->o_sync_state; + if ( sop->o_sync_state.ctxcsn != NULL ) { + csnfeq.f_av_value = *sop->o_sync_state.ctxcsn; + } else { + csnfeq.f_av_value = slap_empty_bv; + } csnfand.f_choice = LDAP_FILTER_AND; csnfand.f_and = &csnfge; @@ -801,7 +870,11 @@ dn2entry_retry: csnfge.f_choice = LDAP_FILTER_GE; csnfge.f_ava = &aa_ge; csnfge.f_av_desc = slap_schema.si_ad_entryCSN; - csnfge.f_av_value = sop->o_sync_state; + if ( sop->o_sync_state.ctxcsn != NULL ) { + csnfge.f_av_value = *sop->o_sync_state.ctxcsn; + } else { + csnfge.f_av_value = slap_empty_bv; + } if ( search_context_csn && !IS_PSEARCH ) { csnfge.f_next = &contextcsnand; @@ -817,21 +890,23 @@ dn2entry_retry: contextcsnle.f_next = sop->oq_search.rs_filter; mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering; - if ( sop->o_sync_state.bv_len != 0 ) { + if ( sop->o_sync_state.ctxcsn && + sop->o_sync_state.ctxcsn->bv_val != NULL ) { value_match( &match, slap_schema.si_ad_entryCSN, mr, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &sop->o_sync_state, search_context_csn, &text ); + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &sop->o_sync_state.ctxcsn[0], search_context_csn, + &text ); } else { match = -1; } - no_sync_state_change = !match; + no_sync_state_change = ( match >= 0 ); } else { csnfge.f_next = sop->oq_search.rs_filter; } } for ( id = bdb_idl_first( candidates, &cursor ); - id != NOID; + id != NOID && !no_sync_state_change; id = bdb_idl_next( candidates, &cursor ) ) { int scopeok = 0; @@ -1060,8 +1135,7 @@ 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 ); + 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 ) { @@ -1091,7 +1165,8 @@ id2entry_retry: if ( rs->sr_err == LDAP_COMPARE_TRUE ) { /* check size limit */ - if ( --sop->oq_search.rs_slimit == -1 ) { + if ( --sop->oq_search.rs_slimit == -1 && + sop->o_sync_slog_size == -1 ) { if (!IS_PSEARCH) { bdb_cache_return_entry_r( bdb->bi_dbenv, &bdb->bi_cache, e, &lock ); @@ -1157,49 +1232,82 @@ id2entry_retry: } else { entry_sync_state = LDAP_SYNC_ADD; } - } else if ( ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) + } else if ( ps_type == LDAP_PSEARCH_BY_SCOPEOUT ) { entry_sync_state = LDAP_SYNC_DELETE; - else { + } else { rs->sr_err = LDAP_OTHER; goto done; } - rs->sr_err = bdb_build_sync_state_ctrl( sop, - rs, e, entry_sync_state, ctrls, - num_ctrls++, 1, search_context_csn ); - if ( rs->sr_err != LDAP_SUCCESS ) goto done; - rs->sr_attrs = attrs; - rs->sr_ctrls = ctrls; - result = send_search_entry( sop, rs ); - ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); - ch_free( ctrls[--num_ctrls] ); - ctrls[num_ctrls] = NULL; - rs->sr_ctrls = NULL; - + if ( sop->o_sync_slog_size != -1 ) { + if ( entry_sync_state == LDAP_SYNC_DELETE ) { + result = slap_add_session_log( op, sop, e ); + } else { + result = 1; + } + } else { + struct berval cookie; + slap_compose_sync_cookie( sop, &cookie, + search_context_csn, + sop->o_sync_state.sid ); + 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; + rs->sr_ctrls = ctrls; + result = send_search_entry( sop, rs ); + if ( cookie.bv_val ) + ch_free( cookie.bv_val ); + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + rs->sr_ctrls = NULL; + } } else if ( ps_type == LDAP_PSEARCH_BY_PREMODIFY ) { struct psid_entry* psid_e; - psid_e = (struct psid_entry *) calloc (1, + 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 ); } else { - printf("Error !\n"); +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "bdb_search: invalid ps_type (%d) \n", + ps_type, 0, 0); +#else + Debug( LDAP_DEBUG_TRACE, + "bdb_search: invalid ps_type (%d) \n", + ps_type, 0, 0); +#endif } } else { if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) { - rs->sr_err = bdb_build_sync_state_ctrl( sop, + struct berval cookie; + slap_compose_sync_cookie( sop, &cookie, + search_context_csn, + sop->o_sync_state.sid ); + rs->sr_err = slap_build_sync_state_ctrl( sop, rs, e, entry_sync_state, ctrls, - num_ctrls++, 0, search_context_csn ); + num_ctrls++, 0, &cookie ); if ( rs->sr_err != LDAP_SUCCESS ) goto done; rs->sr_ctrls = ctrls; if ( rc_sync == LDAP_COMPARE_TRUE ) { /* ADD */ rs->sr_attrs = sop->oq_search.rs_attrs; + result = send_search_entry( sop, rs ); } else { /* PRESENT */ - rs->sr_attrs = &null_attr; + if ( sync_send_present_mode ) { + rs->sr_attrs = &null_attr; + result = send_search_entry( sop, rs ); + } else { + result = 1; + } } - result = send_search_entry( sop, rs ); + + if ( cookie.bv_val ) + ch_free( cookie.bv_val ); ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); ch_free( ctrls[--num_ctrls] ); ctrls[num_ctrls] = NULL; @@ -1260,19 +1368,54 @@ nochange: rs->sr_err = LDAP_SUCCESS; rs->sr_rspoid = LDAP_SYNC_INFO; rs->sr_ctrls = NULL; - bdb_send_ldap_intermediate( sop, rs, - LDAP_SYNC_STATE_MODE_DONE, search_context_csn ); + if ( sync_send_present_mode ) { + struct berval cookie; + slap_compose_sync_cookie( sop, &cookie, + search_context_csn, + sop->o_sync_state.sid ); + bdb_send_ldap_intermediate( sop, rs, + LDAP_SYNC_STATE_MODE_DONE, &cookie ); + if ( cookie.bv_val ) + ch_free( cookie.bv_val ); + } + + if ( !sync_send_present_mode && !no_sync_state_change ) { + int slog_found = 0; + ldap_pvt_thread_mutex_lock( &bdb->bi_pslist_mutex ); + LDAP_LIST_FOREACH( ps_list, &bdb->bi_psearch_list, o_ps_link ) { + if ( ps_list->o_sync_slog_size > 0 ) { + if ( ps_list->o_sync_state.sid == sop->o_sync_state.sid ) { + slog_found = 1; + break; + } + } + } + + if ( slog_found ) { + slap_send_session_log( op, ps_list, rs ); + } + ldap_pvt_thread_mutex_unlock( &bdb->bi_pslist_mutex ); + } - /* If changelog is supported, this is where to process it */ - if ( sop->o_sync_mode & SLAP_SYNC_PERSIST ) { /* refreshAndPersist mode */ + struct berval cookie; + slap_compose_sync_cookie( sop, &cookie, + search_context_csn, + sop->o_sync_state.sid ); bdb_send_ldap_intermediate( sop, rs, - LDAP_SYNC_LOG_MODE_DONE, search_context_csn ); + LDAP_SYNC_LOG_MODE_DONE, &cookie ); + if ( cookie.bv_val ) { + ch_free( cookie.bv_val ); + } } else { /* refreshOnly mode */ - bdb_build_sync_done_ctrl( sop, rs, ctrls, - num_ctrls++, 1, search_context_csn ); + struct berval cookie; + slap_compose_sync_cookie( sop, &cookie, + search_context_csn, + sop->o_sync_state.sid ); + slap_build_sync_done_ctrl( sop, rs, ctrls, + num_ctrls++, 1, &cookie ); rs->sr_ctrls = ctrls; rs->sr_ref = rs->sr_v2ref; rs->sr_err = (rs->sr_v2ref == NULL) ? LDAP_SUCCESS : LDAP_REFERRAL; @@ -1282,6 +1425,8 @@ nochange: } ch_free( ctrls[--num_ctrls] ); ctrls[num_ctrls] = NULL; + if ( cookie.bv_val ) + ch_free( cookie.bv_val ); } } else { rs->sr_ctrls = NULL; @@ -1588,118 +1733,6 @@ done: } #endif -int -bdb_build_sync_state_ctrl( - Operation *op, - SlapReply *rs, - Entry *e, - int entry_sync_state, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *csn) -{ - Attribute* a; - int ret; - int res; - const char *text = NULL; - - BerElementBuffer berbuf; - BerElement *ber = (BerElement *)&berbuf; - - struct berval entryuuid_bv = { 0, NULL }; - - ber_init2( ber, 0, LBER_USE_DER ); - - ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); - - for ( a = e->e_attrs; a != NULL; a = a->a_next ) { - AttributeDescription *desc = a->a_desc; - if ( desc == slap_schema.si_ad_entryUUID ) { - ber_dupbv( &entryuuid_bv, &a->a_vals[0] ); - } - } - - if ( send_cookie && csn ) { - ber_printf( ber, "{eOON}", - entry_sync_state, &entryuuid_bv, csn ); - } else { - ber_printf( ber, "{eON}", - entry_sync_state, &entryuuid_bv ); - } - - ch_free( entryuuid_bv.bv_val ); - entryuuid_bv.bv_val = NULL; - - ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; - ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; - ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); - - ber_free_buf( ber ); - - if ( ret < 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_build_sync_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_build_sync_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#endif - send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); - return ret; - } - - return LDAP_SUCCESS; -} - -int -bdb_build_sync_done_ctrl( - Operation *op, - SlapReply *rs, - LDAPControl **ctrls, - int num_ctrls, - int send_cookie, - struct berval *csn ) -{ - int ret; - BerElementBuffer berbuf; - BerElement *ber = (BerElement *)&berbuf; - - ber_init2( ber, NULL, LBER_USE_DER ); - - ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); - - if ( send_cookie && csn ) { - ber_printf( ber, "{ON}", csn ); - } else { - ber_printf( ber, "{N}" ); - } - - ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE; - ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; - ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); - - ber_free_buf( ber ); - - if ( ret < 0 ) { -#ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, RESULTS, - "bdb_build_sync_done_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_TRACE, - "bdb_build_sync_done_ctrl: ber_flatten2 failed\n", - 0, 0, 0 ); -#endif - send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); - return ret; - } - - return LDAP_SUCCESS; -} - int bdb_send_ldap_intermediate( Operation *op, diff --git a/servers/slapd/config.c b/servers/slapd/config.c index 347f3239b0..ea3d1a65f4 100644 --- a/servers/slapd/config.c +++ b/servers/slapd/config.c @@ -2797,8 +2797,9 @@ add_syncrepl( si->si_attrs[0] = NULL; si->si_type = LDAP_SYNC_REFRESH_ONLY; si->si_interval = 86400; - si->si_syncCookie.bv_val = NULL; - si->si_syncCookie.bv_len = 0; + si->si_syncCookie.ctxcsn = NULL; + si->si_syncCookie.octet_str = NULL; + si->si_syncCookie.sid = -1; si->si_manageDSAit = 0; si->si_tlimit = -1; si->si_slimit = -1; @@ -2864,7 +2865,6 @@ add_syncrepl( #define ATTRSONLYSTR "attrsonly" #define TYPESTR "type" #define INTERVALSTR "interval" -#define COOKIESTR "cookie" #define LASTMODSTR "lastmod" #define LMREQSTR "req" #define LMGENSTR "gen" @@ -3104,15 +3104,10 @@ parse_syncrepl_line( (long) si->si_interval); return 1; } - } else if ( !strncasecmp( cargv[ i ], - COOKIESTR, sizeof( COOKIESTR ) - 1 ) ) - { - val = cargv[ i ] + sizeof( COOKIESTR ); - ber_str2bv( val, 0, 1, &si->si_syncCookie ); } else if ( !strncasecmp( cargv[ i ], MANAGEDSAITSTR, sizeof( MANAGEDSAITSTR ) - 1 ) ) { - val = cargv[ i ] + sizeof( COOKIESTR ); + val = cargv[ i ] + sizeof( MANAGEDSAITSTR ); si->si_manageDSAit = atoi( val ); } else if ( !strncasecmp( cargv[ i ], SLIMITSTR, sizeof( SLIMITSTR ) - 1 ) ) diff --git a/servers/slapd/connection.c b/servers/slapd/connection.c index c8d9814ab9..1044cf4bf1 100644 --- a/servers/slapd/connection.c +++ b/servers/slapd/connection.c @@ -928,6 +928,7 @@ connection_operation( void *ctx, void *arg_v ) #endif /* SLAPD_MONITOR */ Connection *conn = op->o_conn; void *memctx = NULL; + void *memctx_null = NULL; ber_len_t memsiz; ldap_pvt_thread_mutex_lock( &num_ops_mutex ); @@ -1098,20 +1099,25 @@ operations_error: ldap_pvt_thread_mutex_lock( &conn->c_mutex ); - if ( op->o_cancel != SLAP_CANCEL_ACK && ( op->o_sync_mode & SLAP_SYNC_PERSIST ) ) { + ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx_null ); + + if ( op->o_cancel != SLAP_CANCEL_ACK && + ( op->o_sync_mode & SLAP_SYNC_PERSIST ) ) { + sl_mem_detach( ctx, memctx ); + } else if (( op->o_sync_slog_size != -1 )) { sl_mem_detach( ctx, memctx ); - goto no_co_op_free; + LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); + LDAP_STAILQ_NEXT(op, o_next) = NULL; + conn->c_n_ops_executing--; + conn->c_n_ops_completed++; + } else { + LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); + LDAP_STAILQ_NEXT(op, o_next) = NULL; + slap_op_free( op ); + conn->c_n_ops_executing--; + conn->c_n_ops_completed++; } - LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); - LDAP_STAILQ_NEXT(op, o_next) = NULL; - - conn->c_n_ops_executing--; - conn->c_n_ops_completed++; - memctx = NULL; - ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx ); - slap_op_free( op ); - no_co_op_free: switch( tag ) { diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index 8bdecdeef3..4791603165 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -1206,7 +1206,7 @@ static int parseLDAPsync ( BerElement *ber; ber_int_t mode; ber_len_t len; - struct berval cookie = { 0, NULL }; + struct slap_session_entry *se; if ( op->o_sync != SLAP_NO_CONTROL ) { rs->sr_text = "LDAP Sync control specified multiple times"; @@ -1256,22 +1256,20 @@ static int parseLDAPsync ( tag = ber_peek_tag( ber, &len ); if ( tag == LDAP_SYNC_TAG_COOKIE ) { - if (( ber_scanf( ber, /*{*/ "m}", - &cookie )) == LBER_ERROR ) { + struct berval tmp_bv; + if (( ber_scanf( ber, /*{*/ "o}", &tmp_bv )) == LBER_ERROR ) { rs->sr_text = "LDAP Sync control : cookie decoding error"; return LDAP_PROTOCOL_ERROR; } + ber_bvarray_add( &op->o_sync_state.octet_str, &tmp_bv ); + slap_parse_sync_cookie( &op->o_sync_state ); } else { if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) { rs->sr_text = "LDAP Sync control : decoding error"; return LDAP_PROTOCOL_ERROR; } - cookie.bv_len = 0; - cookie.bv_val = NULL; } - ber_dupbv( &op->o_sync_state, &cookie ); - (void) ber_free( ber, 1 ); op->o_sync_mode = (char) mode; diff --git a/servers/slapd/ctxcsn.c b/servers/slapd/ctxcsn.c index 8b0b3e8917..71c7188bd3 100644 --- a/servers/slapd/ctxcsn.c +++ b/servers/slapd/ctxcsn.c @@ -193,6 +193,7 @@ slap_get_csn( if ( manage_ctxcsn ) { pending = (struct slap_csn_entry *) ch_calloc( 1, sizeof( struct slap_csn_entry )); ldap_pvt_thread_mutex_lock( &op->o_bd->be_pcl_mutex ); + ber_dupbv( &op->o_sync_csn, csn ); pending->csn = ber_dupbv( NULL, csn ); pending->connid = op->o_connid; pending->opid = op->o_opid; diff --git a/servers/slapd/globals.c b/servers/slapd/globals.c index fdc4c823a2..1869805805 100644 --- a/servers/slapd/globals.c +++ b/servers/slapd/globals.c @@ -25,3 +25,5 @@ const struct berval slap_unknown_bv = BER_BVC("unknown"); /* normalized boolean values */ const struct berval slap_true_bv = BER_BVC("TRUE"); const struct berval slap_false_bv = BER_BVC("FALSE"); + +struct sync_cookie *slap_sync_cookie = NULL; diff --git a/servers/slapd/ldapsync.c b/servers/slapd/ldapsync.c new file mode 100644 index 0000000000..a93d8e6ba3 --- /dev/null +++ b/servers/slapd/ldapsync.c @@ -0,0 +1,377 @@ +/* $OpenLDAP$ */ +/* + * LDAP Content Sync Routines + */ +/* + * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Copyright (c) 2003 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "portable.h" + +#include + +#include +#include + +#include "ldap_pvt.h" +#include "lutil.h" +#include "slap.h" +#include "lutil_ldap.h" + +int +slap_build_sync_state_ctrl( + Operation *op, + SlapReply *rs, + Entry *e, + int entry_sync_state, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *csn) +{ + Attribute* a; + int ret; + int res; + const char *text = NULL; + + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + struct berval entryuuid_bv = { 0, NULL }; + + ber_init2( ber, 0, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + for ( a = e->e_attrs; a != NULL; a = a->a_next ) { + AttributeDescription *desc = a->a_desc; + if ( desc == slap_schema.si_ad_entryUUID ) { + ber_dupbv( &entryuuid_bv, &a->a_vals[0] ); + } + } + + if ( send_cookie && csn ) { + ber_printf( ber, "{eOON}", + entry_sync_state, &entryuuid_bv, csn ); + } else { + ber_printf( ber, "{eON}", + entry_sync_state, &entryuuid_bv ); + } + + ch_free( entryuuid_bv.bv_val ); + entryuuid_bv.bv_val = NULL; + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "slap_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + return ret; + } + + return LDAP_SUCCESS; +} + +int +slap_build_sync_done_ctrl( + Operation *op, + SlapReply *rs, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *csn ) +{ + int ret; + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + ber_init2( ber, NULL, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + if ( send_cookie && csn ) { + ber_printf( ber, "{ON}", csn ); + } else { + ber_printf( ber, "{N}" ); + } + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_DONE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "slap_build_sync_done_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_build_sync_done_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + return ret; + } + + return LDAP_SUCCESS; +} + + +int +slap_build_sync_state_ctrl_from_slog( + Operation *op, + SlapReply *rs, + struct slog_entry *slog_e, + int entry_sync_state, + LDAPControl **ctrls, + int num_ctrls, + int send_cookie, + struct berval *csn) +{ + Attribute* a; + int ret; + int res; + const char *text = NULL; + + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + + struct berval entryuuid_bv = { 0, NULL }; + + ber_init2( ber, 0, LBER_USE_DER ); + + ctrls[num_ctrls] = ch_malloc ( sizeof ( LDAPControl ) ); + + ber_dupbv( &entryuuid_bv, &slog_e->sl_uuid ); + + if ( send_cookie && csn ) { + ber_printf( ber, "{eOON}", + entry_sync_state, &entryuuid_bv, csn ); + } else { + ber_printf( ber, "{eON}", + entry_sync_state, &entryuuid_bv ); + } + + ch_free( entryuuid_bv.bv_val ); + entryuuid_bv.bv_val = NULL; + + ctrls[num_ctrls]->ldctl_oid = LDAP_CONTROL_SYNC_STATE; + ctrls[num_ctrls]->ldctl_iscritical = op->o_sync; + ret = ber_flatten2( ber, &ctrls[num_ctrls]->ldctl_value, 1 ); + + ber_free_buf( ber ); + + if ( ret < 0 ) { +#ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, RESULTS, + "slap_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#else + Debug( LDAP_DEBUG_TRACE, + "slap_build_sync_ctrl: ber_flatten2 failed\n", + 0, 0, 0 ); +#endif + send_ldap_error( op, rs, LDAP_OTHER, "internal error" ); + return ret; + } + + return LDAP_SUCCESS; +} + +void +slap_compose_sync_cookie( + Operation *op, + struct berval *cookie, + struct berval *csn, + int sid ) +{ + char cookiestr[ LDAP_LUTIL_CSNSTR_BUFSIZE + 10 ]; + + if ( csn->bv_val == NULL ) { + if ( sid == -1 ) { + cookiestr[0] = '\0'; + } else { + snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 10, + "sid=%03d", sid ); + } + } else if ( sid == -1 ) { + snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 10, + "csn=%s", csn->bv_val ); + } else { + snprintf( cookiestr, LDAP_LUTIL_CSNSTR_BUFSIZE + 10, + "csn=%s,sid=%03d", csn->bv_val, sid ); + } + ber_str2bv( cookiestr, strlen(cookiestr), 1, cookie ); +} + +void +slap_sync_cookie_free( + struct sync_cookie *cookie, + int free_cookie +) +{ + if ( cookie == NULL ) + return; + + if ( cookie->ctxcsn ) { + ber_bvarray_free( cookie->ctxcsn ); + cookie->ctxcsn = NULL; + } + + if ( cookie->octet_str ) { + ber_bvarray_free( cookie->octet_str ); + cookie->octet_str = NULL; + } + + if ( free_cookie ) { + ch_free( cookie ); + } + + return; +} + +int +slap_parse_sync_cookie( + struct sync_cookie *cookie +) +{ + char *csn_ptr; + char *csn_str; + char *sid_ptr; + char *sid_str; + char *cval; + struct berval *ctxcsn; + + if ( cookie == NULL ) + return -1; + + if (( csn_ptr = strstr( cookie->octet_str[0].bv_val, "csn=" )) != NULL ) { + csn_str = (char *) strndup( csn_ptr, LDAP_LUTIL_CSNSTR_BUFSIZE ); + if ( cval = strchr( csn_str, ',' )) { + *cval = '\0'; + } + ctxcsn = ber_str2bv( csn_str + 4, strlen(csn_str) - 4, 1, NULL ); + ch_free( csn_str ); + ber_bvarray_add( &cookie->ctxcsn, ctxcsn ); + ch_free( ctxcsn ); + } else { + cookie->ctxcsn = NULL; + } + + if (( sid_ptr = strstr( cookie->octet_str->bv_val, "sid=" )) != NULL ) { + sid_str = (char *) strndup( sid_ptr, 7 ); + if ( cval = strchr( sid_str, ',' )) { + *cval = '\0'; + } + cookie->sid = atoi( sid_str+4 ); + ch_free( sid_str ); + } else { + cookie->sid = -1; + } +} + +int +slap_init_sync_cookie_ctxcsn( + struct sync_cookie *cookie +) +{ + char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE + 4 ]; + struct berval octet_str = { 0, NULL }; + struct berval ctxcsn = { 0, NULL }; + struct berval ctxcsn_dup = { 0, NULL }; + struct berval slap_syncCookie; + + if ( cookie == NULL ) + return -1; + + octet_str.bv_len = snprintf( csnbuf, LDAP_LUTIL_CSNSTR_BUFSIZE + 4, + "csn=%4d%02d%02d%02d:%02d:%02dZ#0x%04x#%d#%04x", + 1900, 1, 1, 0, 0, 0, 0, 0, 0 ); + octet_str.bv_val = csnbuf; + build_new_dn( &slap_syncCookie, &cookie->octet_str[0], &octet_str, NULL ); + ber_bvarray_free( cookie->octet_str ); + cookie->octet_str = NULL; + ber_bvarray_add( &cookie->octet_str, &slap_syncCookie ); + + ber_dupbv( &ctxcsn, &octet_str ); + ctxcsn.bv_val += 4; + ctxcsn.bv_len -= 4; + ber_dupbv( &ctxcsn_dup, &ctxcsn ); + ch_free( ctxcsn.bv_val ); + ber_bvarray_add( &cookie->ctxcsn, &ctxcsn_dup ); + + return 0; +} + +struct sync_cookie * +slap_dup_sync_cookie( + struct sync_cookie *dst, + struct sync_cookie *src +) +{ + int i; + struct sync_cookie *new; + struct berval tmp_bv; + + if ( src == NULL ) + return NULL; + + if ( dst ) { + ber_bvarray_free( dst->ctxcsn ); + ber_bvarray_free( dst->octet_str ); + new = dst; + } else { + new = ( struct sync_cookie * ) + ch_calloc( 1, sizeof( struct sync_cookie )); + } + + new->sid = src->sid; + + if ( src->ctxcsn ) { + for ( i=0; src->ctxcsn[i].bv_val; i++ ) { + ber_dupbv( &tmp_bv, &src->ctxcsn[i] ); + ber_bvarray_add( &new->ctxcsn, &tmp_bv ); + } + } + + if ( src->octet_str ) { + for ( i=0; src->octet_str[i].bv_val; i++ ) { + ber_dupbv( &tmp_bv, &src->octet_str[i] ); + ber_bvarray_add( &new->octet_str, &tmp_bv ); + } + } + + return new; +} diff --git a/servers/slapd/main.c b/servers/slapd/main.c index 61dc82e121..c15dee8c1d 100644 --- a/servers/slapd/main.c +++ b/servers/slapd/main.c @@ -92,6 +92,7 @@ usage( char *name ) fprintf( stderr, "\t-4\t\tIPv4 only\n" "\t-6\t\tIPv6 only\n" + "\t-c cookie\tSync cookie of consumer\n" "\t-d level\tDebug level" "\n" "\t-f filename\tConfiguration file\n" #if defined(HAVE_SETUID) && defined(HAVE_SETGID) @@ -144,6 +145,8 @@ int main( int argc, char **argv ) char *serverName = NULL; int serverMode = SLAP_SERVER_MODE; + struct berval cookie = { 0, NULL }; + #ifdef CSRIMALLOC FILE *leakfile; if( ( leakfile = fopen( "slapd.leak", "w" )) == NULL ) { @@ -214,7 +217,7 @@ int main( int argc, char **argv ) #endif while ( (i = getopt( argc, argv, - "d:f:h:s:n:t" + "c:d:f:h:s:n:t" #if LDAP_PF_INET6 "46" #endif @@ -243,6 +246,16 @@ int main( int argc, char **argv ) urls = ch_strdup( optarg ); break; + case 'c': /* provide sync cookie, override if exist in replica */ + if ( slap_sync_cookie ) { + slap_sync_cookie_free( slap_sync_cookie, 1 ); + } + slap_sync_cookie = (struct sync_cookie *) ch_calloc( 1, + sizeof( struct sync_cookie )); + ber_str2bv( optarg, strlen( optarg ), 1, &cookie ); + ber_bvarray_add( &slap_sync_cookie->octet_str, &cookie ); + break; + case 'd': /* set debug level and 'do not detach' flag */ no_detach = 1; #ifdef LDAP_DEBUG diff --git a/servers/slapd/mods.c b/servers/slapd/mods.c index 02d4bcb207..1d2d9a800c 100644 --- a/servers/slapd/mods.c +++ b/servers/slapd/mods.c @@ -216,6 +216,7 @@ modify_delete_values( Attribute *a; MatchingRule *mr = mod->sm_desc->ad_type->sat_equality; char dummy = '\0'; + int match = 0; /* * If permissive is set, then the non-existence of an @@ -264,7 +265,6 @@ modify_delete_values( for ( i = 0; mod->sm_values[i].bv_val != NULL; i++ ) { int found = 0; for ( j = 0; a->a_vals[j].bv_val != NULL; j++ ) { - int match; if( mod->sm_nvalues ) { assert( a->a_nvals ); diff --git a/servers/slapd/operation.c b/servers/slapd/operation.c index c144c19cfc..ff6fbf3cc6 100644 --- a/servers/slapd/operation.c +++ b/servers/slapd/operation.c @@ -42,6 +42,8 @@ void slap_op_destroy(void) void slap_op_free( Operation *op ) { + struct berval slap_empty_bv_dup; + assert( LDAP_STAILQ_NEXT(op, o_next) == NULL ); if ( op->o_ber != NULL ) { @@ -65,9 +67,8 @@ slap_op_free( Operation *op ) ber_free( op->o_res_ber, 1 ); } #endif - if ( op->o_sync_state.bv_val != NULL ) { - free( op->o_sync_state.bv_val ); - } + + slap_sync_cookie_free( &op->o_sync_state, 0 ); { GroupAssertion *g, *n; @@ -85,7 +86,14 @@ slap_op_free( Operation *op ) } #endif /* defined( LDAP_SLAPI ) */ + if ( op->o_sync_csn.bv_val != NULL ) { + ch_free( op->o_sync_csn.bv_val ); + } + memset( op, 0, sizeof(Operation) ); + + op->o_sync_state.sid = -1; + op->o_sync_slog_size = -1; ldap_pvt_thread_mutex_lock( &slap_op_mutex ); LDAP_STAILQ_INSERT_HEAD( &slap_free_ops, op, o_next ); ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); @@ -100,6 +108,7 @@ slap_op_alloc( ) { Operation *op; + struct berval slap_empty_bv_dup; ldap_pvt_thread_mutex_lock( &slap_op_mutex ); if ((op = LDAP_STAILQ_FIRST( &slap_free_ops ))) { @@ -107,8 +116,9 @@ slap_op_alloc( } ldap_pvt_thread_mutex_unlock( &slap_op_mutex ); - if (!op) + if (!op) { op = (Operation *) ch_calloc( 1, sizeof(Operation) ); + } op->o_ber = ber; op->o_msgid = msgid; @@ -118,6 +128,11 @@ slap_op_alloc( op->o_opid = id; op->o_res_ber = NULL; + op->o_sync_state.sid = -1; + op->o_sync_slog_size = -1; + LDAP_STAILQ_FIRST( &op->o_sync_slog_list ) = NULL; + op->o_sync_slog_list.stqh_last = &LDAP_STAILQ_FIRST( &op->o_sync_slog_list ); + #if defined( LDAP_SLAPI ) if ( slapi_plugins_used ) { op->o_pb = slapi_pblock_new(); diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 9ccc36220d..3f88cf4746 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -551,6 +551,7 @@ LDAP_SLAPD_V( const struct berval ) slap_empty_bv; LDAP_SLAPD_V( const struct berval ) slap_unknown_bv; LDAP_SLAPD_V( const struct berval ) slap_true_bv; LDAP_SLAPD_V( const struct berval ) slap_false_bv; +LDAP_SLAPD_V( struct sync_cookie * ) slap_sync_cookie; /* * index.c @@ -575,6 +576,29 @@ LDAP_SLAPD_V (char *) ldap_srvtab; LDAP_SLAPD_V (int) krbv4_ldap_auth(); #endif +/* + * ldapsync.c + */ +LDAP_SLAPD_F (int) slap_build_sync_state_ctrl LDAP_P(( + 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 * )); +LDAP_SLAPD_F (int) slap_build_sync_state_ctrl_from_slog LDAP_P(( + Operation *, SlapReply *, struct slog_entry *, int, + LDAPControl **, int, int, struct berval * )); +LDAP_SLAPD_F (void) slap_compose_sync_cookie LDAP_P(( + Operation *, struct berval *, struct berval *, int )); +LDAP_SLAPD_F (void) slap_sync_cookie_free LDAP_P(( + struct sync_cookie *, int free_cookie )); +LDAP_SLAPD_F (int) slap_parse_sync_cookie LDAP_P(( + struct sync_cookie * )); +LDAP_SLAPD_F (int) slap_init_sync_cookie_ctxcsn LDAP_P(( + struct sync_cookie * )); +LDAP_SLAPD_F (struct sync_cookie *) slap_dup_sync_cookie LDAP_P(( + struct sync_cookie *, struct sync_cookie * )); + /* * limits.c */ @@ -1004,6 +1028,14 @@ LDAP_SLAPD_F (char *) scherr2str LDAP_P((int code)) LDAP_GCCATTR((const)); LDAP_SLAPD_F (int) dscompare LDAP_P(( const char *s1, const char *s2del, char delim )); +/* + * sessionlog.c + */ +LDAP_SLAPD_F (int) slap_send_session_log LDAP_P(( + Operation *, Operation *, SlapReply *)); +LDAP_SLAPD_F (int) slap_add_session_log LDAP_P(( + Operation *, Operation *, Entry * )); + /* * sl_malloc.c */ @@ -1031,6 +1063,30 @@ LDAP_SLAPD_F (SLAP_EXTOP_MAIN_FN) starttls_extop; LDAP_SLAPD_F (Filter *) str2filter LDAP_P(( const char *str )); LDAP_SLAPD_F (Filter *) str2filter_x LDAP_P(( Operation *op, const char *str )); +/* + * syncrepl.c + */ + +LDAP_SLAPD_V (struct runqueue_s) syncrepl_rq; + +LDAP_SLAPD_F (void) init_syncrepl LDAP_P((syncinfo_t *)); +LDAP_SLAPD_F (void*) do_syncrepl LDAP_P((void *, void *)); +LDAP_SLAPD_F (Entry*) syncrepl_message_to_entry LDAP_P(( + syncinfo_t *, Operation *, LDAPMessage *, + Modifications **, int )); +LDAP_SLAPD_F (int) syncrepl_entry LDAP_P(( + syncinfo_t *, Operation*, Entry*, + Modifications*,int, struct berval*, + struct sync_cookie *, int )); +LDAP_SLAPD_F (void) syncrepl_updateCookie LDAP_P(( + syncinfo_t *, Operation *, struct berval *, + struct sync_cookie * )); +LDAP_SLAPD_F (void) syncrepl_add_glue LDAP_P(( + Operation*, Entry* )); +LDAP_SLAPD_F (Entry*) slap_create_syncrepl_entry LDAP_P(( + Backend *, struct berval *, + struct berval *, struct berval * )); + /* syntax.c */ LDAP_SLAPD_F (Syntax *) syn_find LDAP_P(( const char *synname )); @@ -1183,29 +1239,6 @@ LDAP_SLAPD_F (int) do_search LDAP_P((Operation *op, SlapReply *rs)); LDAP_SLAPD_F (int) do_unbind LDAP_P((Operation *op, SlapReply *rs)); LDAP_SLAPD_F (int) do_extended LDAP_P((Operation *op, SlapReply *rs)); -/* - * syncrepl.c - */ - -LDAP_SLAPD_V (struct runqueue_s) syncrepl_rq; - -LDAP_SLAPD_F (void) init_syncrepl LDAP_P((syncinfo_t *)); -LDAP_SLAPD_F (void*) do_syncrepl LDAP_P((void *, void *)); -LDAP_SLAPD_F (Entry*) syncrepl_message_to_entry LDAP_P(( - syncinfo_t *, Operation *, LDAPMessage *, - Modifications **, int )); -LDAP_SLAPD_F (int) syncrepl_entry LDAP_P(( - syncinfo_t *, Operation*, Entry*, - Modifications*,int, struct berval*, int )); -LDAP_SLAPD_F (void) syncrepl_updateCookie LDAP_P(( - syncinfo_t *, Operation *, struct berval *, - struct berval * )); -LDAP_SLAPD_F (void) syncrepl_add_glue LDAP_P(( - Operation*, Entry* )); -LDAP_SLAPD_F (Entry*) slap_create_syncrepl_entry LDAP_P(( - Backend *, struct berval *, - struct berval *, struct berval * )); - LDAP_END_DECL #endif /* PROTO_SLAP_H */ diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 306015eea6..d46cefa709 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -423,7 +423,7 @@ static struct slap_schema_ad_map { "DESC 'syncrepl Cookie for shadow copy' " "EQUALITY octetStringMatch " "ORDERING octetStringOrderingMatch " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", NULL, SLAP_AT_HIDE, NULL, NULL, @@ -435,7 +435,7 @@ static struct slap_schema_ad_map { "DESC 'the largest committed CSN of a context' " "EQUALITY octetStringMatch " "ORDERING octetStringOrderingMatch " - "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{64} " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " "SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )", NULL, SLAP_AT_HIDE, NULL, NULL, diff --git a/servers/slapd/search.c b/servers/slapd/search.c index 39ca34f4b1..2fdd461653 100644 --- a/servers/slapd/search.c +++ b/servers/slapd/search.c @@ -401,6 +401,9 @@ return_results:; if ( ( op->o_sync_mode & SLAP_SYNC_PERSIST ) ) return rs->sr_err; + if ( ( op->o_sync_slog_size != -1 ) ) + return rs->sr_err; + if( op->o_req_dn.bv_val != NULL) sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); if( op->o_req_ndn.bv_val != NULL) sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); diff --git a/servers/slapd/sessionlog.c b/servers/slapd/sessionlog.c new file mode 100644 index 0000000000..cb759ee725 --- /dev/null +++ b/servers/slapd/sessionlog.c @@ -0,0 +1,140 @@ +/* $OpenLDAP$ */ +/* + * Session History Management Routines + */ +/* + * Copyright 2003 The OpenLDAP Foundation, All Rights Reserved. + * COPYING RESTRICTIONS APPLY, see COPYRIGHT file + */ +/* Copyright (c) 2003 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include "portable.h" + +#include + +#include +#include + +#include "ldap_pvt.h" +#include "lutil.h" +#include "slap.h" +#include "lutil_ldap.h" + +int +slap_send_session_log( + Operation *op, + Operation *sop, + SlapReply *rs +) +{ + Entry e; + AttributeName uuid_attr[2]; + LDAPControl *ctrls[SLAP_MAX_RESPONSE_CONTROLS]; + int num_ctrls = 0; + struct slog_entry *slog_e; + int result; + int match; + const char *text; + + uuid_attr[0].an_desc = NULL; + uuid_attr[0].an_oc = NULL; + uuid_attr[0].an_name.bv_len = 0; + uuid_attr[0].an_name.bv_val = NULL; + e.e_attrs = NULL; + e.e_id = 0; + e.e_name.bv_val = NULL; + e.e_name.bv_len = 0; + e.e_nname.bv_val = NULL; + e.e_nname.bv_len = 0; + + for( num_ctrls = 0; + num_ctrls < SLAP_MAX_RESPONSE_CONTROLS; + num_ctrls++ ) { + ctrls[num_ctrls] = NULL; + } + num_ctrls = 0; + + LDAP_STAILQ_FOREACH( slog_e, &sop->o_sync_slog_list, sl_link ) { + + if ( op->o_sync_state.ctxcsn->bv_val == NULL ) { + match = 1; + } else { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + op->o_sync_state.ctxcsn, &slog_e->sl_csn, &text ); + } + + if ( match < 0 ) { + rs->sr_err = slap_build_sync_state_ctrl_from_slog( op, rs, slog_e, + LDAP_SYNC_DELETE, ctrls, num_ctrls++, 0, NULL ); + + if ( rs->sr_err != LDAP_SUCCESS ) + return rs->sr_err; + + if ( e.e_name.bv_val ) + ch_free( e.e_name.bv_val ); + ber_dupbv( &e.e_name, &slog_e->sl_name ); + + rs->sr_entry = &e; + rs->sr_attrs = uuid_attr; + rs->sr_ctrls = ctrls; + result = send_search_entry( op, rs ); + ch_free( ctrls[num_ctrls-1]->ldctl_value.bv_val ); + ch_free( ctrls[--num_ctrls] ); + ctrls[num_ctrls] = NULL; + rs->sr_ctrls = NULL; + } + } +} + +int +slap_add_session_log( + Operation *op, + Operation *sop, + Entry *e +) +{ + struct slog_entry* slog_e; + Attribute *a; + + slog_e = (struct slog_entry *) ch_calloc (1, sizeof( struct slog_entry )); + a = attr_find( e->e_attrs, slap_schema.si_ad_entryUUID ); + ber_dupbv( &slog_e->sl_uuid, &a->a_vals[0] ); + ber_dupbv( &slog_e->sl_name, &e->e_name ); + ber_dupbv( &slog_e->sl_csn, &op->o_sync_csn ); + LDAP_STAILQ_INSERT_TAIL( &sop->o_sync_slog_list, slog_e, sl_link ); + sop->o_sync_slog_len++; + + while ( sop->o_sync_slog_len > sop->o_sync_slog_size ) { + slog_e = LDAP_STAILQ_FIRST( &sop->o_sync_slog_list ); + if ( sop->o_sync_slog_omitcsn.bv_val ) { + ch_free( sop->o_sync_slog_omitcsn.bv_val ); + } + ber_dupbv( &sop->o_sync_slog_omitcsn, &slog_e->sl_csn ); + LDAP_STAILQ_REMOVE_HEAD( &sop->o_sync_slog_list, sl_link ); + ch_free( slog_e->sl_uuid.bv_val ); + ch_free( slog_e->sl_name.bv_val ); + ch_free( slog_e->sl_csn.bv_val ); + ch_free( slog_e ); + sop->o_sync_slog_len--; + } + + return LDAP_SUCCESS; +} diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 4be38925d1..0b11e6e4f1 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -1293,45 +1293,57 @@ struct nonpresent_entry { LDAP_LIST_ENTRY(nonpresent_entry) npe_link; }; +struct sync_cookie { + struct berval *ctxcsn; + long sid; + struct berval *octet_str; +}; + /* * syncinfo structure for syncrepl */ typedef struct syncinfo_s { - struct slap_backend_db *si_be; - unsigned int si_id; - char *si_provideruri; - BerVarray si_provideruri_bv; -#define SYNCINFO_TLS_OFF 0 -#define SYNCINFO_TLS_ON 1 -#define SYNCINFO_TLS_CRITICAL 2 - int si_tls; - struct berval si_updatedn; - int si_bindmethod; - char *si_binddn; - char *si_passwd; - char *si_saslmech; - char *si_secprops; - char *si_realm; - char *si_authcId; - char *si_authzId; - int si_schemachecking; - Filter *si_filter; - struct berval si_filterstr; - struct berval si_base; - int si_scope; - int si_attrsonly; - char **si_attrs; - int si_type; - time_t si_interval; - struct berval si_syncCookie; - int si_manageDSAit; - int si_slimit; - int si_tlimit; - struct berval si_syncUUID_ndn; - Avlnode *si_presentlist; - int si_sync_mode; - LDAP *si_ld; - LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist; +// struct slap_conn *si_conn; + struct slap_backend_db *si_be; +// struct slap_entry *si_e; +// void *si_ctx; + unsigned int si_id; + char *si_provideruri; + BerVarray si_provideruri_bv; +#define SYNCINFO_TLS_OFF 0 +#define SYNCINFO_TLS_ON 1 +#define SYNCINFO_TLS_CRITICAL 2 + int si_tls; + struct berval si_updatedn; + int si_bindmethod; + char *si_binddn; + char *si_passwd; + char *si_saslmech; + char *si_secprops; + char *si_realm; + char *si_authcId; + char *si_authzId; + int si_schemachecking; + Filter *si_filter; + struct berval si_filterstr; + struct berval si_base; + int si_scope; + int si_attrsonly; + char **si_attrs; + int si_type; + time_t si_interval; +// struct sync_cookie *si_syncCookie; + struct sync_cookie si_syncCookie; + int si_manageDSAit; + int si_slimit; + int si_tlimit; +// struct berval *si_syncUUID; +// struct berval *si_syncUUID_ndn; + struct berval si_syncUUID_ndn; + Avlnode *si_presentlist; + int si_sync_mode; + LDAP *si_ld; + LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist; } syncinfo_t; struct slap_backend_db { @@ -1812,6 +1824,21 @@ struct psid_entry { LDAP_LIST_ENTRY(psid_entry) ps_link; }; +struct slog_entry { + struct berval sl_uuid; + struct berval sl_name; + struct berval sl_csn; + LDAP_STAILQ_ENTRY(slog_entry) sl_link; +}; + +/* session lists */ +struct slap_session_entry { + int se_id; + int se_size; + struct berval se_spec; + LDAP_LIST_ENTRY( slap_session_entry ) se_link; +}; + struct slap_csn_entry { struct berval *csn; unsigned long opid; @@ -1966,13 +1993,20 @@ typedef struct slap_op { char o_sync; char o_sync_mode; -#define SLAP_SYNC_NONE (0x0) -#define SLAP_SYNC_REFRESH (0x1) -#define SLAP_SYNC_PERSIST (0x2) -#define SLAP_SYNC_REFRESH_AND_PERSIST (0x3) - struct berval o_sync_state; +#define SLAP_SYNC_NONE (0x0) +#define SLAP_SYNC_REFRESH (0x1) +#define SLAP_SYNC_PERSIST (0x2) +#define SLAP_SYNC_REFRESH_AND_PERSIST (0x3) + struct sync_cookie o_sync_state; + struct berval o_sync_cid; + int o_sync_slog_size; + struct berval o_sync_csn; + struct berval o_sync_slog_omitcsn; + int o_sync_slog_len; + LDAP_STAILQ_HEAD(sl, slog_entry) o_sync_slog_list; int o_ps_entries; + int o_no_psearch; LDAP_LIST_ENTRY(slap_op) o_ps_link; LDAP_LIST_HEAD(pe, psid_entry) o_pm_list; diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index b17754d420..b4acf565ce 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -125,8 +125,8 @@ init_syncrepl(syncinfo_t *si) static int ldap_sync_search( syncinfo_t *si, - void *ctx, - struct berval *syncCookie ) + void *ctx +) { BerElementBuffer berbuf; BerElement *ber = (BerElement *)&berbuf; @@ -139,8 +139,10 @@ ldap_sync_search( ber_init2( ber, NULL, LBER_USE_DER ); ber_set_option( ber, LBER_OPT_BER_MEMCTX, &ctx ); - if ( syncCookie ) { - ber_printf( ber, "{eO}", abs(si->si_type), syncCookie ); + if ( si->si_syncCookie.octet_str && + si->si_syncCookie.octet_str[0].bv_val ) { + ber_printf( ber, "{eO}", abs(si->si_type), + &si->si_syncCookie.octet_str[0] ); } else { ber_printf( ber, "{e}", abs(si->si_type) ); } @@ -187,7 +189,7 @@ do_syncrep1( char syncrepl_cbuf[sizeof(CN_STR SYNCREPL_STR)]; struct berval syncrepl_cn_bv; - BerVarray syncCookie; + struct sync_cookie syncCookie = { NULL, -1, NULL }; si->si_sync_mode = LDAP_SYNC_STATE_MODE; @@ -197,11 +199,11 @@ do_syncrep1( if ( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING LDAP_LOG( OPERATION, ERR, - "do_syncrepl: ldap_initialize failed (%s)\n", + "do_syncrep1: ldap_initialize failed (%s)\n", si->si_provideruri, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "do_syncrepl: ldap_initialize failed (%s)\n", + "do_syncrep1: ldap_initialize failed (%s)\n", si->si_provideruri, 0, 0 ); #endif return rc; @@ -216,7 +218,7 @@ do_syncrep1( rc = ldap_start_tls_s( si->si_ld, NULL, NULL ); if( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "do_syncrepl: " + LDAP_LOG ( OPERATION, ERR, "do_syncrep1: " "%s: ldap_start_tls failed (%d)\n", si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning", rc, 0 ); @@ -272,11 +274,11 @@ do_syncrep1( */ if ( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "do_syncrepl: " + LDAP_LOG ( OPERATION, ERR, "do_syncrep1: " "ldap_sasl_interactive_bind_s failed (%d)\n", rc, 0, 0 ); #else - Debug( LDAP_DEBUG_ANY, "do_syncrepl: " + Debug( LDAP_DEBUG_ANY, "do_syncrep1: " "ldap_sasl_interactive_bind_s failed (%d)\n", rc, 0, 0 ); #endif @@ -292,10 +294,10 @@ do_syncrep1( rc = ldap_bind_s( si->si_ld, si->si_binddn, si->si_passwd, si->si_bindmethod ); if ( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "do_syncrepl: " + LDAP_LOG ( OPERATION, ERR, "do_syncrep1: " "ldap_bind_s failed (%d)\n", rc, 0, 0 ); #else - Debug( LDAP_DEBUG_ANY, "do_syncrepl: " + Debug( LDAP_DEBUG_ANY, "do_syncrep1: " "ldap_bind_s failed (%d)\n", rc, 0, 0 ); #endif goto done; @@ -312,24 +314,43 @@ do_syncrep1( op->o_tmpmemctx ); op->o_req_dn = op->o_req_ndn; - syncCookie = NULL; - backend_attribute( op, NULL, &op->o_req_ndn, - slap_schema.si_ad_syncreplCookie, &syncCookie ); + if ( slap_sync_cookie != NULL ) { + slap_sync_cookie_free( &si->si_syncCookie, 0 ); + slap_parse_sync_cookie( slap_sync_cookie ); + if ( slap_sync_cookie->ctxcsn == NULL || + slap_sync_cookie->ctxcsn->bv_val == NULL ) { + slap_init_sync_cookie_ctxcsn( slap_sync_cookie ); + } + slap_dup_sync_cookie( &si->si_syncCookie, slap_sync_cookie ); + slap_sync_cookie_free( slap_sync_cookie, 1 ); + slap_sync_cookie = NULL; + } + + /* use in-memory version if it exists */ + if ( si->si_syncCookie.octet_str == NULL ) { + BerVarray cookie = NULL; + struct berval cookie_bv; + backend_attribute( op, NULL, &op->o_req_ndn, + slap_schema.si_ad_syncreplCookie, &cookie ); + if ( cookie ) { + ber_dupbv( &cookie_bv, &cookie[0] ); + ber_bvarray_add( &si->si_syncCookie.octet_str, &cookie_bv ); + slap_parse_sync_cookie( &si->si_syncCookie ); + ber_bvarray_free_x( cookie, op->o_tmpmemctx ); + } + } + + rc = ldap_sync_search( si, op->o_tmpmemctx ); - rc = ldap_sync_search( si, op->o_tmpmemctx, syncCookie ); if( rc != LDAP_SUCCESS ) { #ifdef NEW_LOGGING - LDAP_LOG ( OPERATION, ERR, "do_syncrepl: " + LDAP_LOG ( OPERATION, ERR, "do_syncrep1: " "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 ); #else - Debug( LDAP_DEBUG_ANY, "do_syncrepl: " + Debug( LDAP_DEBUG_ANY, "do_syncrep1: " "ldap_search_ext: %s (%d)\n", ldap_err2string( rc ), rc, 0 ); #endif } - if ( syncCookie ) { - ber_dupbv( &si->si_syncCookie, syncCookie ); - ber_bvarray_free_x( syncCookie, op->o_tmpmemctx ); - } done: if ( rc ) { @@ -364,8 +385,9 @@ do_syncrep2( int syncstate; struct berval syncUUID = { 0, NULL }; - struct berval syncCookie = { 0, NULL }; - struct berval syncCookie_req; + struct sync_cookie syncCookie = { NULL, -1, NULL }; + struct sync_cookie syncCookie_req = { NULL, -1, NULL }; + struct berval cookie = { 0, NULL }; int rc; int err; @@ -400,7 +422,7 @@ do_syncrep2( psub = &si->si_be->be_nsuffix[0]; - syncCookie_req = si->si_syncCookie; + slap_dup_sync_cookie( &syncCookie_req, &si->si_syncCookie ); if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ){ tout_p = &tout; @@ -419,7 +441,6 @@ do_syncrep2( msg != NULL; msg = ldap_next_message( si->si_ld, msg ) ) { - syncCookie.bv_len = 0; syncCookie.bv_val = NULL; switch( ldap_msgtype( msg ) ) { case LDAP_RES_SEARCH_ENTRY: ldap_get_entry_controls( si->si_ld, msg, &rctrls ); @@ -432,13 +453,21 @@ do_syncrep2( ber_init2( ber, &rctrlp->ldctl_value, LBER_USE_DER ); ber_scanf( ber, "{em", &syncstate, &syncUUID ); if ( ber_peek_tag( ber, &len ) == LDAP_SYNC_TAG_COOKIE ) { - ber_scanf( ber, "m}", &syncCookie ); + ber_scanf( ber, "m}", &cookie ); + if ( cookie.bv_val ) { + struct berval tmp_bv; + ber_dupbv( &tmp_bv, &cookie ); + ber_bvarray_add( &syncCookie.octet_str, &tmp_bv ); + } + if ( syncCookie.octet_str && + syncCookie.octet_str[0].bv_val ) + slap_parse_sync_cookie( &syncCookie ); } entry = syncrepl_message_to_entry( si, op, msg, &modlist, syncstate ); - rc_efree = syncrepl_entry( si, op, entry, modlist, - syncstate, &syncUUID, !syncinfo_arrived ); - if ( syncCookie.bv_len ) { + rc_efree = syncrepl_entry( si, op, entry, modlist, syncstate, + &syncUUID, &syncCookie_req, !syncinfo_arrived ); + if ( syncCookie.octet_str && syncCookie.octet_str[0].bv_val ) { syncrepl_updateCookie( si, op, psub, &syncCookie ); } ldap_controls_free( rctrls ); @@ -453,10 +482,10 @@ do_syncrep2( case LDAP_RES_SEARCH_REFERENCE: #ifdef NEW_LOGGING LDAP_LOG( OPERATION, ERR, - "do_syncrepl : reference received\n", 0, 0, 0 ); + "do_syncrep2 : reference received\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "do_syncrepl : reference received\n", 0, 0, 0 ); + "do_syncrep2 : reference received\n", 0, 0, 0 ); #endif break; @@ -470,16 +499,30 @@ do_syncrep2( ber_scanf( ber, "{" /*"}"*/); if ( ber_peek_tag( ber, &len ) == LDAP_SYNC_TAG_COOKIE ) { - ber_scanf( ber, "m", &syncCookie ); + ber_scanf( ber, "m", &cookie ); + if ( cookie.bv_val ) { + struct berval tmp_bv; + ber_dupbv( &tmp_bv, &cookie ); + ber_bvarray_add( &syncCookie.octet_str, &tmp_bv); + } + if ( syncCookie.octet_str && + syncCookie.octet_str[0].bv_val ) + slap_parse_sync_cookie( &syncCookie ); } } - value_match( &match, slap_schema.si_ad_entryCSN, - slap_schema.si_ad_entryCSN->ad_type->sat_ordering, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &syncCookie_req, &syncCookie, &text ); - if ( syncCookie.bv_len && match < 0) { - syncrepl_updateCookie( si, op, - psub, &syncCookie ); + if ( syncCookie_req.ctxcsn == NULL ) { + match = -1; + } else if ( syncCookie.ctxcsn == NULL ) { + match = 1; + } else { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &syncCookie_req.ctxcsn[0], &syncCookie.ctxcsn[0], &text ); + } + if ( syncCookie.octet_str && syncCookie.octet_str->bv_val + && match < 0 ) { + syncrepl_updateCookie( si, op, psub, &syncCookie ); } if ( rctrls ) { ldap_controls_free( rctrls ); @@ -509,25 +552,31 @@ do_syncrep2( if ( ber_peek_tag( ber, &len ) == LDAP_SYNC_TAG_COOKIE ) { - ber_scanf( ber, /*"{"*/ "m}", &syncCookie ); - } else { - if ( syncstate == LDAP_SYNC_NEW_COOKIE ) { -#ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR, - "do_syncrepl : cookie required\n", 0, 0, 0 ); -#else - Debug( LDAP_DEBUG_ANY, - "do_syncrepl : cookie required\n", 0, 0, 0 ); -#endif + ber_scanf( ber, /*"{"*/ "m}", &cookie ); + if ( cookie.bv_val ) { + struct berval tmp_bv; + ber_dupbv( &tmp_bv, &cookie ); + ber_bvarray_add( &syncCookie.octet_str, &tmp_bv); } + if ( syncCookie.octet_str && + syncCookie.octet_str[0].bv_val ) + slap_parse_sync_cookie( &syncCookie ); } - value_match( &match, slap_schema.si_ad_entryCSN, - slap_schema.si_ad_entryCSN->ad_type->sat_ordering, - SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, - &syncCookie_req, &syncCookie, &text ); + if ( syncCookie_req.ctxcsn == NULL ) { + match = -1; + } else if ( syncCookie.ctxcsn == NULL ) { + match = 1; + } else { + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &syncCookie_req.ctxcsn[0], + &syncCookie.ctxcsn[0], &text ); + } - if ( syncCookie.bv_len && match < 0 ) { + if ( syncCookie.ctxcsn && syncCookie.ctxcsn[0].bv_val + && match < 0 ) { syncrepl_updateCookie( si, op, psub, &syncCookie); } @@ -545,10 +594,10 @@ do_syncrep2( { #ifdef NEW_LOGGING LDAP_LOG( OPERATION, ERR, - "do_syncrepl : unknown sync info\n", 0, 0, 0 ); + "do_syncrep2 : unknown sync info\n", 0, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "do_syncrepl : unknown sync info\n", 0, 0, 0 ); + "do_syncrep2 : unknown sync info\n", 0, 0, 0 ); #endif } @@ -557,11 +606,11 @@ do_syncrep2( break; } else { #ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR,"do_syncrepl :" + LDAP_LOG( OPERATION, ERR,"do_syncrep2 :" " unknown intermediate " "response\n", 0, 0, 0 ); #else - Debug( LDAP_DEBUG_ANY, "do_syncrepl : " + Debug( LDAP_DEBUG_ANY, "do_syncrep2 : " "unknown intermediate response (%d)\n", rc, 0, 0 ); #endif @@ -572,15 +621,20 @@ do_syncrep2( break; default: #ifdef NEW_LOGGING - LDAP_LOG( OPERATION, ERR, "do_syncrepl : " + LDAP_LOG( OPERATION, ERR, "do_syncrep2 : " "unknown message\n", 0, 0, 0 ); #else - Debug( LDAP_DEBUG_ANY, "do_syncrepl : " + Debug( LDAP_DEBUG_ANY, "do_syncrep2 : " "unknown message\n", 0, 0, 0 ); #endif break; } + if ( syncCookie.octet_str ) { + slap_sync_cookie_free( &syncCookie_req, 0 ); + slap_dup_sync_cookie( &syncCookie_req, &syncCookie ); + slap_sync_cookie_free( &syncCookie, 0 ); + } } ldap_msgfree( res ); res = NULL; @@ -594,14 +648,17 @@ do_syncrep2( #ifdef NEW_LOGGING LDAP_LOG( OPERATION, ERR, - "do_syncrepl : %s\n", errstr, 0, 0 ); + "do_syncrep2 : %s\n", errstr, 0, 0 ); #else Debug( LDAP_DEBUG_ANY, - "do_syncrepl : %s\n", errstr, 0, 0 ); + "do_syncrep2 : %s\n", errstr, 0, 0 ); #endif } done: + slap_sync_cookie_free( &syncCookie, 0 ); + slap_sync_cookie_free( &syncCookie_req, 0 ); + if ( res ) ldap_msgfree( res ); if ( rc && si->si_ld ) { @@ -672,6 +729,13 @@ do_syncrepl( op.o_conn = &conn; op.o_connid = op.o_conn->c_connid; + op.o_sync_state.ctxcsn = NULL; + op.o_sync_state.sid = -1; + op.o_sync_state.octet_str = NULL; + op.o_sync_slog_size = -1; + LDAP_STAILQ_FIRST( &op.o_sync_slog_list ) = NULL; + op.o_sync_slog_list.stqh_last = &LDAP_STAILQ_FIRST(&op.o_sync_slog_list); + /* Establish session, do search */ if ( !si->si_ld ) { first = 1; @@ -699,10 +763,6 @@ do_syncrepl( dostop = 1; } } else { - ch_free( si->si_syncCookie.bv_val ); - si->si_syncCookie.bv_val = NULL; - si->si_syncCookie.bv_len = 0; - /* Session closed due to receipt of search result */ if ( rc == -2 ) rc = 0; } } @@ -884,6 +944,7 @@ syncrepl_entry( Modifications* modlist, int syncstate, struct berval* syncUUID, + struct sync_cookie* syncCookie_req, int refresh ) { @@ -898,7 +959,7 @@ syncrepl_entry( int ret = LDAP_SUCCESS; const char *text; - if ( refresh && + if ( refresh && si->si_sync_mode == LDAP_SYNC_STATE_MODE && ( syncstate == LDAP_SYNC_PRESENT || syncstate == LDAP_SYNC_ADD )) { syncuuid_bv = ber_dupbv( NULL, syncUUID ); @@ -951,13 +1012,24 @@ syncrepl_entry( cb.sc_response = null_callback; cb.sc_private = si; - if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn.bv_val && - si->si_sync_mode != LDAP_SYNC_LOG_MODE ) + if ( rc == LDAP_SUCCESS && si->si_syncUUID_ndn.bv_val ) { + char *subseq_ptr; + + if ( syncstate != LDAP_SYNC_DELETE ) { + op->o_no_psearch = 1; + } + + ber_dupbv( &op->o_sync_csn, syncCookie_req->ctxcsn ); + subseq_ptr = strstr( op->o_sync_csn.bv_val, "#0000" ); + subseq_ptr += 4; + *subseq_ptr = '1'; + op->o_req_dn = si->si_syncUUID_ndn; op->o_req_ndn = si->si_syncUUID_ndn; op->o_tag = LDAP_REQ_DELETE; rc = be->be_delete( op, &rs ); + op->o_no_psearch = 0; } switch ( syncstate ) { @@ -1032,15 +1104,7 @@ syncrepl_entry( } case LDAP_SYNC_DELETE : - if ( si->si_sync_mode == LDAP_SYNC_LOG_MODE ) { - if ( si->si_syncUUID_ndn.bv_val ) { - op->o_req_dn = si->si_syncUUID_ndn; - op->o_req_ndn = si->si_syncUUID_ndn; - op->o_tag = LDAP_REQ_DELETE; - rc = be->be_delete( op, &rs ); - } - } - /* Already deleted otherwise */ + /* Already deleted */ ret = 1; goto done; @@ -1289,7 +1353,7 @@ syncrepl_updateCookie( syncinfo_t *si, Operation *op, struct berval *pdn, - struct berval *syncCookie + struct sync_cookie *syncCookie ) { Backend *be = op->o_bd; @@ -1313,6 +1377,9 @@ syncrepl_updateCookie( slap_callback cb; SlapReply rs = {REP_RESULT}; + slap_sync_cookie_free( &si->si_syncCookie, 0 ); + slap_dup_sync_cookie( &si->si_syncCookie, syncCookie ); + mod = (Modifications *) ch_calloc( 1, sizeof( Modifications )); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_desc = slap_schema.si_ad_objectClass; @@ -1335,7 +1402,7 @@ syncrepl_updateCookie( modtail = &mod->sml_next; if ( scbva[0].bv_val ) ch_free( scbva[0].bv_val ); - ber_dupbv( &scbva[0], syncCookie ); + ber_dupbv( &scbva[0], &si->si_syncCookie.octet_str[0] ); mod = (Modifications *) ch_calloc( 1, sizeof( Modifications )); mod->sml_op = LDAP_MOD_REPLACE; mod->sml_desc = slap_schema.si_ad_syncreplCookie; diff --git a/servers/slapd/tools/Makefile.in b/servers/slapd/tools/Makefile.in index 8934eac54c..8f71829cff 100644 --- a/servers/slapd/tools/Makefile.in +++ b/servers/slapd/tools/Makefile.in @@ -46,7 +46,8 @@ SLAPD_OBJS = ../globals.o ../config.o ../ch_malloc.o ../cr.o ../backend.o \ ../init.o ../controls.o ../kerberos.o ../passwd.o \ ../index.o ../extended.o ../starttls.o ../sets.o ../mra.o \ ../referral.o ../backglue.o ../oidm.o ../mods.o ../operation.o \ - ../cancel.o ../sl_malloc.o ../backover.o ../ctxcsn.o ../syncrepl.o + ../cancel.o ../sl_malloc.o ../backover.o ../ctxcsn.o ../syncrepl.o \ + ../ldapsync.o ../sessionlog.o SLAPOBJS = $(SLAPD_OBJS) slapcommon.o mimic.o diff --git a/tests/data/slapd-syncrepl-master.conf b/tests/data/slapd-syncrepl-master.conf index bb51cdd1dd..7e2fa3406e 100644 --- a/tests/data/slapd-syncrepl-master.conf +++ b/tests/data/slapd-syncrepl-master.conf @@ -28,3 +28,5 @@ rootpw secret #ldbm#index cn,sn,uid pres,eq,sub #bdb#index objectClass eq #bdb#index cn,sn,uid pres,eq,sub + +sessionlog 1 100 diff --git a/tests/data/slapd-syncrepl-slave-refresh1.conf b/tests/data/slapd-syncrepl-slave-refresh1.conf index d1aa086f60..15543497ab 100644 --- a/tests/data/slapd-syncrepl-slave-refresh1.conf +++ b/tests/data/slapd-syncrepl-slave-refresh1.conf @@ -29,6 +29,8 @@ rootpw secret #bdb#index objectClass eq #bdb#index cn,sn,uid pres,eq,sub +sessionlog 1 100 + # Don't change syncrepl spec yet syncrepl id=1 provider=ldap://localhost:9011