diff -cNr openldap-2.2.30.org/build/version.var openldap-2.2.30/build/version.var *** openldap-2.2.30.org/build/version.var 2005-11-19 02:57:23.000000000 +0900 --- openldap-2.2.30/build/version.var 2006-10-11 11:28:08.000000000 +0900 *************** *** 15,21 **** ol_package=OpenLDAP ol_major=2 ol_minor=2 ! ol_patch=30 ol_api_inc=20230 ol_api_current=7 ol_api_revision=23 --- 15,21 ---- ol_package=OpenLDAP ol_major=2 ol_minor=2 ! ol_patch=30sb2 ol_api_inc=20230 ol_api_current=7 ol_api_revision=23 diff -cNr openldap-2.2.30.org/include/ldap.h openldap-2.2.30/include/ldap.h *** openldap-2.2.30.org/include/ldap.h 2005-08-13 04:28:56.000000000 +0900 --- openldap-2.2.30/include/ldap.h 2006-10-11 11:28:08.000000000 +0900 *************** *** 198,203 **** --- 198,206 ---- char ldctl_iscritical; /* criticality */ } LDAPControl; + #define LDAP_SYNCBACKUP 1 + #define LDAP_SYNCBACKUP_TEST 1 + /* LDAP Controls */ /* standard track controls */ #define LDAP_CONTROL_MANAGEDSAIT "2.16.840.1.113730.3.4.2" /* RFC 3296 */ *************** *** 215,220 **** --- 218,227 ---- #define LDAP_CONTROL_PROXY_AUTHZ "2.16.840.1.113730.3.4.18" #define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.334810.2.3" + #ifdef LDAP_SYNCBACKUP + #define LDAP_CONTROL_CONTEXTCSN "1.3.6.1.4.1.4203.666.7.5" + #endif + /* various works in progress */ #define LDAP_CONTROL_NOOP "1.3.6.1.4.1.4203.666.5.2" *************** *** 271,276 **** --- 278,287 ---- #define LDAP_EXOP_X_WHO_AM_I "1.3.6.1.4.1.4203.1.11.3" #define LDAP_EXOP_X_CANCEL "1.3.6.1.4.1.4203.666.6.3" + #ifdef LDAP_SYNCBACKUP + #define LDAP_EXOP_X_NOOP "1.3.6.1.4.1.4203.666.7.3" + #define LDAP_EXOP_X_START_SYNC "1.3.6.1.4.1.4203.666.7.4" + #endif /* LDAP Features */ #define LDAP_FEATURE_ALL_OP_ATTRS "1.3.6.1.4.1.4203.1.5.1" /* RFC 3673 */ diff -cNr openldap-2.2.30.org/servers/slapd/Makefile.in openldap-2.2.30/servers/slapd/Makefile.in *** openldap-2.2.30.org/servers/slapd/Makefile.in 2005-01-21 02:01:05.000000000 +0900 --- openldap-2.2.30/servers/slapd/Makefile.in 2006-10-11 11:28:08.000000000 +0900 *************** *** 38,43 **** --- 38,44 ---- backover.c ctxcsn.c ldapsync.c sessionlog.c \ slapadd.c slapcat.c slapcommon.c slapdn.c slapindex.c \ slappasswd.c slaptest.c \ + syncbackup.c startsync.c \ $(@PLAT@_SRCS) OBJS = main.o globals.o config.o daemon.o \ *************** *** 55,60 **** --- 56,62 ---- backover.o ctxcsn.o ldapsync.o sessionlog.o \ slapadd.o slapcat.o slapcommon.o slapdn.o slapindex.o \ slappasswd.o slaptest.o \ + syncbackup.o startsync.o \ $(@PLAT@_OBJS) LDAP_INCDIR= ../../include -I$(srcdir)/slapi diff -cNr openldap-2.2.30.org/servers/slapd/add.c openldap-2.2.30/servers/slapd/add.c *** openldap-2.2.30.org/servers/slapd/add.c 2005-01-21 02:01:06.000000000 +0900 --- openldap-2.2.30/servers/slapd/add.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 33,38 **** --- 33,42 ---- #include "ldap_pvt.h" #include "slap.h" + #ifdef LDAP_SYNCBACKUP + #include "lutil.h" + #endif + #ifdef LDAP_SLAPI #include "slapi/slapi.h" *************** *** 254,261 **** --- 258,269 ---- /* do the update here */ int repl_user = be_isupdate( op ); #ifndef SLAPD_MULTIMASTER + #ifdef LDAP_SYNCBACKUP + if ( !SLAP_SHADOW(op->o_bd) || ( SLAP_BACKUP_SHADOW(op->o_bd) && op->o_ctxcsn != SLAP_NO_CONTROL ) || repl_user ) + #else if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif + #endif { int update = op->o_bd->be_update_ndn.bv_len; char textbuf[SLAP_TEXT_BUFLEN]; *************** *** 285,291 **** goto done; } } ! rs->sr_err = slap_mods2entry( modlist, &e, repl_user, 0, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { --- 293,306 ---- goto done; } } ! #ifdef LDAP_SYNCBACKUP ! if ( SLAP_BACKUP_SHADOW(op->o_bd) ) { ! struct berval csn = { 0, NULL }; ! char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; ! ! slap_get_csn ( op, csnbuf, sizeof(csnbuf), &csn, 1 ); ! } ! #endif rs->sr_err = slap_mods2entry( modlist, &e, repl_user, 0, &rs->sr_text, textbuf, textlen ); if( rs->sr_err != LDAP_SUCCESS ) { *************** *** 309,315 **** op->ora_e = e; #ifdef SLAPD_MULTIMASTER ! if ( !repl_user ) #endif { cb.sc_next = op->o_callback; --- 324,334 ---- op->ora_e = e; #ifdef SLAPD_MULTIMASTER ! if ( !repl_user ! #ifdef LDAP_SYNCBACKUP ! || !SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) #endif { cb.sc_next = op->o_callback; diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/add.c openldap-2.2.30/servers/slapd/back-bdb/add.c *** openldap-2.2.30.org/servers/slapd/back-bdb/add.c 2005-01-21 02:01:10.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/add.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 42,47 **** --- 42,50 ---- DB_LOCK lock; int num_retries = 0; + #ifdef LDAP_SYNCBACKUP + int did_syncbackup = 0; + #endif Operation* ps_list; int rc; *************** *** 346,351 **** --- 349,368 ---- goto return_results; } + #ifdef LDAP_SYNCBACKUP + /* FIXME: + * Because of unknown reason, if this fail + * after bdb_index_entry_add(), bdb_idl_insert_key() will + * sometimes fail by DB->cusror failure. + * */ + if( ! did_syncbackup ) { + rs->sr_err = syncbackup(op, rs, ei->bei_e); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + did_syncbackup = 1; + } + #endif /* attribute indexes */ rs->sr_err = bdb_index_entry_add( op, lt2, op->oq_add.rs_e ); if ( rs->sr_err != LDAP_SUCCESS ) { *************** *** 362,374 **** --- 379,396 ---- rs->sr_text = "index generation failed"; goto return_results; } + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; goto return_results; } + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ) { + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker ); switch ( rc ) { *************** *** 420,426 **** --- 442,452 ---- suffix_ei = BEI(e); } + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ){ + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif if ( ctxcsn_added ) { bdb_cache_add( bdb, suffix_ei, ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker ); diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/ctxcsn.c openldap-2.2.30/servers/slapd/back-bdb/ctxcsn.c *** openldap-2.2.30.org/servers/slapd/back-bdb/ctxcsn.c 2005-04-27 01:29:23.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/ctxcsn.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 236,242 **** u_int32_t ctxcsn_locker = 0; if ( op->o_sync_mode != SLAP_SYNC_NONE && ! !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { char substr[67]; struct berval ctxcsn_ndn = BER_BVNULL; struct berval bv; --- 236,246 ---- u_int32_t ctxcsn_locker = 0; if ( op->o_sync_mode != SLAP_SYNC_NONE && ! !LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) ! #ifdef LDAP_SYNCBACKUP ! && !SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) { char substr[67]; struct berval ctxcsn_ndn = BER_BVNULL; struct berval bv; *************** *** 306,312 **** } } } else if ( op->o_sync_mode != SLAP_SYNC_NONE && ! LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { provider_ctxcsn_retry : rs->sr_err = bdb_dn2entry( op, NULL, &op->o_bd->be_context_csn, &ctxcsn_ei, --- 310,320 ---- } } } else if ( op->o_sync_mode != SLAP_SYNC_NONE && ! ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) ! #ifdef LDAP_SYNCBACKUP ! || SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! )) { provider_ctxcsn_retry : rs->sr_err = bdb_dn2entry( op, NULL, &op->o_bd->be_context_csn, &ctxcsn_ei, diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/delete.c openldap-2.2.30/servers/slapd/back-bdb/delete.c *** openldap-2.2.30.org/servers/slapd/back-bdb/delete.c 2005-01-21 02:01:11.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/delete.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 42,47 **** --- 42,50 ---- DB_LOCK lock, plock; int num_retries = 0; + #ifdef LDAP_SYNCBACKUP + int did_syncbackup = 0; + #endif Operation* ps_list; int rc; *************** *** 451,456 **** --- 454,469 ---- p = NULL; } + #ifdef LDAP_SYNCBACKUP + if( ! did_syncbackup ) { + rs->sr_err = syncbackup(op, rs, ei->bei_e); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + did_syncbackup = 1; + } + #endif + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; *************** *** 469,475 **** --- 482,492 ---- if ( !dn_match( &ctxcsn_ndn, &op->o_req_ndn ) && !be_issuffix( op->o_bd, &op->o_req_ndn ) && + #ifdef LDAP_SYNCBACKUP + ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL )) { + #else LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker ); switch ( rc ) { *************** *** 496,502 **** --- 513,523 ---- goto retry; } + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ) { + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif if ( ctxcsn_added ) { bdb_cache_add( bdb, suffix_ei, ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker ); diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/init.c openldap-2.2.30/servers/slapd/back-bdb/init.c *** openldap-2.2.30.org/servers/slapd/back-bdb/init.c 2005-07-29 00:03:17.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/init.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 586,591 **** --- 586,594 ---- LDAP_CONTROL_SUBENTRIES, #endif LDAP_CONTROL_VALUESRETURNFILTER, + #ifdef LDAP_SYNCBACKUP + LDAP_CONTROL_CONTEXTCSN, + #endif #ifdef LDAP_CONTROL_X_PERMISSIVE_MODIFY LDAP_CONTROL_X_PERMISSIVE_MODIFY, #endif diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/modify.c openldap-2.2.30/servers/slapd/back-bdb/modify.c *** openldap-2.2.30.org/servers/slapd/back-bdb/modify.c 2005-01-21 02:01:11.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/modify.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 277,282 **** --- 277,285 ---- DB_LOCK lock; int num_retries = 0; + #ifdef LDAP_SYNCBACKUP + int did_syncbackup = 0; + #endif LDAPControl **preread_ctrl = NULL; LDAPControl **postread_ctrl = NULL; *************** *** 525,537 **** --- 528,554 ---- goto return_results; } + #ifdef LDAP_SYNCBACKUP + if( ! did_syncbackup ) { + rs->sr_err = syncbackup(op, rs, ei->bei_e); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + did_syncbackup = 1; + } + #endif + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; goto return_results; } + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ) { + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker ); switch ( rc ) { *************** *** 574,580 **** --- 591,601 ---- } dummy.e_attrs = NULL; + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ){ + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif if ( ctxcsn_added ) { bdb_cache_add( bdb, suffix_ei, ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker ); diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/modrdn.c openldap-2.2.30/servers/slapd/back-bdb/modrdn.c *** openldap-2.2.30.org/servers/slapd/back-bdb/modrdn.c 2005-09-28 22:40:52.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/modrdn.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 58,63 **** --- 58,66 ---- DB_LOCK lock, plock, nplock; int num_retries = 0; + #ifdef LDAP_SYNCBACKUP + int did_syncbackup = 0; + #endif LDAPControl **preread_ctrl = NULL; LDAPControl **postread_ctrl = NULL; *************** *** 740,752 **** --- 743,769 ---- p = NULL; } + #ifdef LDAP_SYNCBACKUP + if( ! did_syncbackup ) { + rs->sr_err = syncbackup(op, rs, ei->bei_e); + if ( rs->sr_err != LDAP_SUCCESS ) { + goto return_results; + } + did_syncbackup = 1; + } + #endif + if ( TXN_COMMIT( lt2, 0 ) != 0 ) { rs->sr_err = LDAP_OTHER; rs->sr_text = "txn_commit(2) failed"; goto return_results; } + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ) { + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif rc = bdb_csn_commit( op, rs, ltid, ei, &suffix_ei, &ctxcsn_e, &ctxcsn_added, locker ); switch ( rc ) { *************** *** 792,798 **** --- 809,819 ---- new_dn.bv_val = NULL; new_ndn.bv_val = NULL; + #ifdef LDAP_SYNCBACKUP + if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo ) || op->o_ctxcsn != SLAP_NO_CONTROL ){ + #else if ( LDAP_STAILQ_EMPTY( &op->o_bd->be_syncinfo )) { + #endif if ( ctxcsn_added ) { bdb_cache_add( bdb, suffix_ei, ctxcsn_e, (struct berval *)&slap_ldapsync_cn_bv, locker ); diff -cNr openldap-2.2.30.org/servers/slapd/back-bdb/search.c openldap-2.2.30/servers/slapd/back-bdb/search.c *** openldap-2.2.30.org/servers/slapd/back-bdb/search.c 2005-01-21 02:01:11.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-bdb/search.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 338,343 **** --- 338,348 ---- { Operation *ps; void *saved_tmpmemctx; + #ifdef LDAP_SYNCBACKUP + int rc = LDAP_UNAVAILABLE; + + rc = syncbackup_abandon( op, rs ); + #endif ps = bdb_drop_psearch( op, op->oq_abandon.rs_msgid, (op->o_tag != LDAP_REQ_ABANDON) ); if ( ps ) { *************** *** 376,382 **** --- 381,391 ---- return LDAP_SUCCESS; } + #ifdef LDAP_SYNCBACKUP + return rc; + #else return LDAP_UNAVAILABLE; + #endif } int bdb_search( Operation *op, SlapReply *rs ) *************** *** 866,879 **** csnfge.f_next = &contextcsnand; contextcsnand.f_choice = LDAP_FILTER_AND; contextcsnand.f_and = &contextcsnle; contextcsnand.f_next = NULL; ! contextcsnle.f_choice = LDAP_FILTER_LE; contextcsnle.f_ava = &aa_le; contextcsnle.f_av_desc = slap_schema.si_ad_entryCSN; contextcsnle.f_av_value = *search_context_csn; contextcsnle.f_next = sop->oq_search.rs_filter; mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering; if ( sop->o_sync_state.ctxcsn && --- 875,894 ---- csnfge.f_next = &contextcsnand; contextcsnand.f_choice = LDAP_FILTER_AND; + #ifdef LDAP_SYNCBACKUP + /* FIXME: ad-hoc: limit by LE causes DN to be deleted by modify operation in refresh time */ + contextcsnand.f_and = sop->oq_search.rs_filter; + contextcsnand.f_next = NULL; + #else contextcsnand.f_and = &contextcsnle; contextcsnand.f_next = NULL; ! contextcsnle.f_choice = LDAP_FILTER_LE; contextcsnle.f_ava = &aa_le; contextcsnle.f_av_desc = slap_schema.si_ad_entryCSN; contextcsnle.f_av_value = *search_context_csn; contextcsnle.f_next = sop->oq_search.rs_filter; + #endif mr = slap_schema.si_ad_entryCSN->ad_type->sat_ordering; if ( sop->o_sync_state.ctxcsn && diff -cNr openldap-2.2.30.org/servers/slapd/back-monitor/backend.c openldap-2.2.30/servers/slapd/back-monitor/backend.c *** openldap-2.2.30.org/servers/slapd/back-monitor/backend.c 2005-04-22 05:16:51.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-monitor/backend.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 138,144 **** attr_merge_normalize_one( e, mi->mi_ad_seeAlso, &dn, NULL ); } ! mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); e->e_private = ( void * )mp; mp->mp_next = e_tmp; --- 138,144 ---- attr_merge_normalize_one( e, mi->mi_ad_seeAlso, &dn, NULL ); } ! mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); e->e_private = ( void * )mp; mp->mp_next = e_tmp; diff -cNr openldap-2.2.30.org/servers/slapd/back-monitor/database.c openldap-2.2.30/servers/slapd/back-monitor/database.c *** openldap-2.2.30.org/servers/slapd/back-monitor/database.c 2005-01-21 02:01:14.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-monitor/database.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 36,41 **** --- 36,48 ---- #include "../back-ldap/back-ldap.h" #endif /* defined(SLAPD_LDAP) */ + #ifdef LDAP_SYNCBACKUP + static Entry * + monitor_syncbackup_init( struct monitorinfo *mi, int i ); + static int + monitor_syncbackup_update( struct monitorinfo *mi, int backendID, int syncbackupID, Entry *e ); + #endif + int monitor_subsys_database_init( BackendDB *be *************** *** 225,230 **** --- 232,241 ---- monitor_back_add_plugin( be, e ); #endif /* defined(LDAP_SLAPI) */ + #ifdef LDAP_SYNCBACKUP + mp->mp_children = monitor_syncbackup_init( mi, i ); + #endif + e_tmp = e; } *************** *** 289,291 **** --- 300,459 ---- return rc; } #endif /* defined(LDAP_SLAPI) */ + + #ifdef LDAP_SYNCBACKUP + + int + monitor_subsys_backend_update( + Operation *op, + Entry *e + ) + { + struct monitorinfo *mi = (struct monitorinfo *)op->o_bd->be_private; + + assert( op ); + assert( mi ); + assert( e ); + + if ( strncasecmp( e->e_ndn, "cn=syncbackup", + sizeof("cn=syncbackup")-1 ) == 0 ) { + + int backendID, syncbackupID; + + sscanf( e->e_ndn, "cn=syncbackup %d,cn=backend %d,", + &syncbackupID, &backendID ); + + monitor_syncbackup_update( mi, backendID, syncbackupID, e ); + } + + return 0; + } + + static void + monitor_syncbackup_monitorinfo( + char *buf, + size_t size, + syncbackupinfo_t *info, + int syncbackupID + ) + { + + snprintf( buf, size, "syncid=%s state=%d csn=%s", + info->sbi_backups[syncbackupID]->sb_syncid, + info->sbi_backups[syncbackupID]->sb_state, + (info->sbi_backups[syncbackupID]->sb_age)?((info->sbi_backups[syncbackupID]->sb_age->ev_csn)?info->sbi_backups[syncbackupID]->sb_age->ev_csn:info->sbi_init_cookie->bv_val):"none" + ); + + } + + static Entry * + monitor_syncbackup_init( struct monitorinfo *mi, int i ) + { + Entry *e, *e_tmp; + BackendDB *be = &backendDB[i]; + int j; + struct monitorentrypriv *mp; + + if ( !be ) return NULL; + if ( !be->be_syncbackupinfo ) return NULL; + + e_tmp = NULL; + + for ( j = be->be_syncbackupinfo->sbi_num_max_backups; j--; ) { + char buf[ BACKMONITOR_BUFSIZE ]; + + snprintf( buf, sizeof( buf ), + "dn: cn=Syncbackup %d,cn=Backend %d,%s\n" + "objectClass: %s\n" + "structuralObjectClass: %s\n" + "cn: Syncbackup %d\n" + "monitoredInfo:\n" + "createTimestamp: %s\n" + "modifyTimestamp: %s\n", + j, + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_dn.bv_val, + mi->mi_oc_monitoredObject->soc_cname.bv_val, + mi->mi_oc_monitoredObject->soc_cname.bv_val, + j, + mi->mi_startTime.bv_val, + mi->mi_startTime.bv_val ); + + e = str2entry( buf ); + if ( e == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, CRIT, + "monitor_subsys_backend_init: " + "unable to create entry 'cn=Syncbackup %d,cn=Backend %d,%s'\n", + j, i, monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val ); + #else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: " + "unable to create entry 'cn=Syncbackup %d, cn=Backend %d,%s'\n", + j, + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val + ); + #endif + return NULL; + } + + mp = ( struct monitorentrypriv * )ch_calloc( sizeof( struct monitorentrypriv ), 1 ); + e->e_private = ( void * )mp; + mp->mp_next = e_tmp; + mp->mp_children = NULL; + mp->mp_info = &monitor_subsys[SLAPD_MONITOR_BACKEND]; + mp->mp_flags = monitor_subsys[SLAPD_MONITOR_BACKEND].mss_flags + | MONITOR_F_SUB; + + if ( monitor_cache_add( mi, e ) ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, CRIT, + "monitor_subsys_backend_init: " + "unable to add entry 'cn=Syncbackup %d,cn=Backend %d,%s'\n", + j, i, monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val ); + #else + Debug( LDAP_DEBUG_ANY, + "monitor_subsys_backend_init: " + "unable to add entry 'cn=Syncbackup %d,cn=Backend %d,%s'\n", + j, + i, + monitor_subsys[SLAPD_MONITOR_BACKEND].mss_ndn.bv_val + ); + #endif + return NULL; + } + + e_tmp = e; + } + + return e_tmp; + } + + + static int + monitor_syncbackup_update( + struct monitorinfo *mi, + int backendID, + int syncbackupID, + Entry *e + ) + { + char buf[ BACKMONITOR_BUFSIZE ]; + Attribute *a; + syncbackupinfo_t *info = backendDB[backendID].be_syncbackupinfo; + + assert ( info ); + + a = attr_find( e->e_attrs, mi->mi_ad_monitoredInfo ); + assert( a != NULL ); + + monitor_syncbackup_monitorinfo( buf, sizeof( buf ), info, syncbackupID ); + free( a->a_vals[ 0 ].bv_val ); + ber_str2bv( buf, 0, 1, &a->a_vals[ 0 ] ); + + return 0; + } + + #endif + diff -cNr openldap-2.2.30.org/servers/slapd/back-monitor/init.c openldap-2.2.30/servers/slapd/back-monitor/init.c *** openldap-2.2.30.org/servers/slapd/back-monitor/init.c 2005-01-21 02:01:15.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-monitor/init.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 61,67 **** --- 61,71 ---- BER_BVNULL, BER_BVNULL, BER_BVNULL, MONITOR_F_PERSISTENT_CH, monitor_subsys_backend_init, + #ifdef LDAP_SYNCBACKUP + monitor_subsys_backend_update, + #else NULL, /* update */ + #endif NULL, /* create */ NULL /* modify */ }, { diff -cNr openldap-2.2.30.org/servers/slapd/back-monitor/proto-back-monitor.h openldap-2.2.30/servers/slapd/back-monitor/proto-back-monitor.h *** openldap-2.2.30.org/servers/slapd/back-monitor/proto-back-monitor.h 2005-01-21 02:01:15.000000000 +0900 --- openldap-2.2.30/servers/slapd/back-monitor/proto-back-monitor.h 2006-10-11 11:28:08.000000000 +0900 *************** *** 36,41 **** --- 36,44 ---- * backends */ int monitor_subsys_backend_init LDAP_P(( BackendDB *be )); + #ifdef LDAP_SYNCBACKUP + int monitor_subsys_backend_update LDAP_P(( Operation *op, Entry *e )); + #endif /* * databases diff -cNr openldap-2.2.30.org/servers/slapd/backend.c openldap-2.2.30/servers/slapd/backend.c *** openldap-2.2.30.org/servers/slapd/backend.c 2005-01-21 02:01:06.000000000 +0900 --- openldap-2.2.30/servers/slapd/backend.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 329,334 **** --- 329,338 ---- int i; int rc = 0; + #ifdef LDAP_SYNCBACKUP + init_syncbackup(); + #endif + if( ! ( nBackendDB > 0 ) ) { /* no databases */ #ifdef NEW_LOGGING *************** *** 390,395 **** --- 394,404 ---- LDAP_STAILQ_INIT( &syncrepl_rq.task_list ); LDAP_STAILQ_INIT( &syncrepl_rq.run_list ); + #ifdef LDAP_SYNCBACKUP + ldap_pvt_thread_mutex_init( &health_rq.rq_mutex ); + LDAP_STAILQ_INIT( &health_rq.task_list ); + LDAP_STAILQ_INIT( &health_rq.run_list ); + #endif /* open each backend database */ for( i = 0; i < nBackendDB; i++ ) { if ( backendDB[i].be_suffix == NULL ) { *************** *** 413,418 **** --- 422,436 ---- if ( rc ) return rc; + #ifdef LDAP_SYNCBACKUP + if ( backendDB[i].be_syncbackupinfo != NULL ) { + bootsync(&backendDB[i]); + ldap_pvt_thread_mutex_lock( &health_rq.rq_mutex ); + ldap_pvt_runqueue_insert( &health_rq, 1, backup_healthcheck, (void *)&backendDB[i] ); + ldap_pvt_thread_mutex_unlock( &health_rq.rq_mutex ); + } + #endif + if ( !LDAP_STAILQ_EMPTY( &backendDB[i].be_syncinfo )) { syncinfo_t *si; *************** *** 543,548 **** --- 561,571 ---- if ( bd->be_rootpw.bv_val ) free( bd->be_rootpw.bv_val ); if ( bd->be_context_csn.bv_val ) free( bd->be_context_csn.bv_val ); acl_destroy( bd->be_acl, global_acl ); + #ifdef LDAP_SYNCBACKUP + if ( bd->be_syncbackupinfo ) { + syncbackupinfo_destroy ( bd->be_syncbackupinfo ); + } + #endif } free( backendDB ); *************** *** 626,631 **** --- 649,658 ---- ldap_pvt_thread_mutex_init( be->be_pcl_mutexp ); LDAP_STAILQ_INIT( &be->be_syncinfo ); + #ifdef LDAP_SYNCBACKUP + be->be_syncbackupinfo = NULL; + be->be_weaksync = 0; + #endif /* assign a default depth limit for alias deref */ be->be_max_deref_depth = SLAPD_DEFAULT_MAXDEREFDEPTH; diff -cNr openldap-2.2.30.org/servers/slapd/config.c openldap-2.2.30/servers/slapd/config.c *** openldap-2.2.30.org/servers/slapd/config.c 2005-06-09 06:36:45.000000000 +0900 --- openldap-2.2.30/servers/slapd/config.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 106,111 **** --- 106,117 ---- static int add_syncrepl LDAP_P(( Backend *, char **, int )); static int parse_syncrepl_line LDAP_P(( char **, int, syncinfo_t *)); + #ifdef LDAP_SYNCBACKUP + static int add_syncbackup LDAP_P(( Backend *, char **, int )); + static int parse_syncbackup_line LDAP_P(( char **, int, syncinfo_t *)); + static int add_syncreplica LDAP_P(( Backend *, char **, int )); + static int parse_replica_line LDAP_P(( char **, int, Ri *)); + #endif int read_config( const char *fname, int depth ) *************** *** 1894,1899 **** --- 1900,1998 ---- SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_SYNC_SHADOW ); + #ifdef LDAP_SYNCBACKUP + } else if ( strcasecmp( cargv[0], "weaksync" ) == 0) { + if ( be == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, INFO, + "%s: line %d: weaksync line must appear inside " + "a database definition.\n", fname, lineno, 0); + #else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: weaksync line must appear inside " + "a database definition.\n", fname, lineno, 0); + #endif + return 1; + } else { + if ( cargc < 2 ) { + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing on|off in \"weaksync \" line\n", + fname, lineno, 0 ); + return( 1 ); + } + if ( strcasecmp( cargv[1], "off" ) == 0 ) { + be->be_weaksync = 0; + } else { + be->be_weaksync = 1; + } + } + } else if ( strcasecmp( cargv[0], "syncbackup" ) == 0 ) { + if ( be == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, INFO, + "%s: line %d: syncbackup line must appear inside " + "a database definition.\n", fname, lineno, 0); + #else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: syncbackup line must appear inside " + "a database definition.\n", fname, lineno, 0); + #endif + return 1; + } else if ( add_syncbackup( be, cargv, cargc )) { + return 1; + } + + SLAP_DBFLAGS(be) |= ( SLAP_DBFLAG_SHADOW | SLAP_DBFLAG_BACKUP_SHADOW ); + } else if ( strcasecmp( cargv[0], "syncdn" ) == 0 ) { + if ( cargc < 2 ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: missing dn in \"syncdn \"" + " line.\n", fname, lineno , 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: missing dn in \"syncdn \" line\n", + fname, lineno, 0 ); + #endif + + return( 1 ); + } + if ( be == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, INFO, + "%s: line %d: syncdn line must appear inside " + "a database definition\n", + fname, lineno , 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: syncdn line must appear inside " + "a database definition\n", + fname, lineno, 0 ); + #endif + return 1; + + } else { + struct berval dn; + + dn.bv_val = cargv[1]; + dn.bv_len = strlen( cargv[1] ); + + rc = dnNormalize( 0, NULL, NULL, &dn, &be->be_sync_ndn, NULL ); + if( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, CRIT, + "%s: line %d: syncdn DN is invalid.\n", + fname, lineno , 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "%s: line %d: syncdn DN is invalid\n", + fname, lineno, 0 ); + #endif + return 1; + } + } + #endif + /* list of replicas of the data in this backend (master only) */ } else if ( strcasecmp( cargv[0], "replica" ) == 0 ) { if ( cargc < 2 ) { *************** *** 1923,1929 **** } else { int nr = -1; ! for ( i = 1; i < cargc; i++ ) { if ( strncasecmp( cargv[i], "host=", 5 ) == 0 ) { --- 2022,2036 ---- } else { int nr = -1; ! #ifdef LDAP_SYNCBACKUP ! for ( i = 1; i < cargc; i++ ) { ! if ( strncasecmp( cargv[i], "syncid=", 7 ) == 0 ) { ! add_syncreplica( be, cargv, cargc ); ! break; ! } ! } ! if ( i == cargc ) { ! #endif for ( i = 1; i < cargc; i++ ) { if ( strncasecmp( cargv[i], "host=", 5 ) == 0 ) { *************** *** 2064,2069 **** --- 2171,2179 ---- } } } + #ifdef LDAP_SYNCBACKUP + } + #endif } } else if ( strcasecmp( cargv[0], "replicationInterval" ) == 0 ) { *************** *** 2971,2976 **** --- 3081,3090 ---- si->si_manageDSAit = 0; si->si_tlimit = 0; si->si_slimit = 0; + #ifdef LDAP_SYNCBACKUP + si->si_replType = SYNC_REPLICA; + si->si_state = SYNC_HEALTH_STATE_NONE; + #endif si->si_presentlist = NULL; LDAP_LIST_INIT( &si->si_nonpresentlist ); *************** *** 3026,3032 **** #define OLDAUTHCSTR "bindprincipal" #define AUTHCSTR "authcID" #define AUTHZSTR "authzID" ! #define SRVTABSTR "srvtab" #define SASLMECHSTR "saslmech" #define REALMSTR "realm" #define SECPROPSSTR "secprops" --- 3140,3146 ---- #define OLDAUTHCSTR "bindprincipal" #define AUTHCSTR "authcID" #define AUTHZSTR "authzID" ! #define SRVTABSTR "srvtab" #define SASLMECHSTR "saslmech" #define REALMSTR "realm" #define SECPROPSSTR "secprops" *************** *** 3049,3054 **** --- 3163,3172 ---- #define MANAGEDSAITSTR "manageDSAit" #define SLIMITSTR "sizelimit" #define TLIMITSTR "timelimit" + #ifdef LDAP_SYNCBACKUP + #define SYNCIDSTR "syncid" + #define CHECKINTVLSTR "checkinterval" + #endif #define RETRYSTR "retry" *************** *** 3378,3383 **** --- 3496,3926 ---- return 0; } + #ifdef LDAP_SYNCBACKUP + static int + add_syncbackup( + Backend *be, + char **cargv, + int cargc + ) + { + syncinfo_t *si; + + if ( be->be_suffix[1].bv_val ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, ERR, + "add_syncbackup: only one suffix allowed\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "add_syncbackup: only one suffix allowed\n", 0, 0, 0 ); + #endif + return 1; + } + + if ( !LDAP_STAILQ_EMPTY( &be->be_syncinfo )) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, INFO, + "add_syncbackup: multiple syncrepl lines in a database " + "definition are yet to be supported.\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "add_syncbackup: multiple syncrepl lines in a database " + "definition are yet to be supported.\n", 0, 0, 0 ); + #endif + return 1; + } + + si = (syncinfo_t *) ch_calloc( 1, sizeof( syncinfo_t ) ); + + if ( si == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, ERR, "out of memory in add_syncbackup\n", 0, 0,0 ); + #else + Debug( LDAP_DEBUG_ANY, "out of memory in add_syncbackup\n", 0, 0, 0 ); + #endif + exit( EXIT_FAILURE ); + } + + si->si_rid = 0; + si->si_tls = SYNCINFO_TLS_OFF; + if ( be->be_rootndn.bv_val ) { + ber_dupbv( &si->si_updatedn, &be->be_rootndn ); + } else { + fprintf( stderr, "set rootdn line before syncbackup line\n" ); + free( si ); + return 1; + } + si->si_bindmethod = LDAP_AUTH_SIMPLE; + si->si_schemachecking = 0; + ber_str2bv( "(objectclass=*)", sizeof("(objectclass=*)")-1, 1, + &si->si_filterstr ); + if ( be->be_suffix && be->be_suffix[0].bv_val ) { + ber_dupbv( &si->si_base, &be->be_suffix[0] ); + } else { + fprintf( stderr, "set suffix line before syncbackup line\n" ); + free( si ); + return 1; + } + si->si_scope = LDAP_SCOPE_SUBTREE; + si->si_attrsonly = 0; + si->si_attrs = (char **) ch_calloc( 1, sizeof( char * )); + si->si_attrs[0] = NULL; + si->si_exattrs = (char **) ch_calloc( 1, sizeof( char * )); + si->si_exattrs[0] = NULL; + si->si_type = LDAP_SYNC_REFRESH_ONLY; + si->si_interval = 10; + si->si_retryinterval = (time_t *) ch_calloc( 2, sizeof( time_t )); + si->si_retryinterval[0] = 10; + si->si_retryinterval[1] = -2; + si->si_retrynum_init = (int *) ch_calloc( 2, sizeof( int )); + si->si_retrynum_init[0] = -1; + si->si_retrynum_init[1] = -2; + si->si_retrynum = (int *) ch_calloc( 2, sizeof( int )); + si->si_retrynum[0] = -1; + si->si_retrynum[1] = -2; + 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; + si->si_state = SYNC_HEALTH_STATE_NONE; + si->si_replType = SYNC_BACKUP; + + si->si_presentlist = NULL; + LDAP_LIST_INIT( &si->si_nonpresentlist ); + + if ( parse_syncbackup_line( cargv, cargc, si ) < 0 ) { + /* Something bad happened - back out */ + #ifdef NEW_LOGGING + LDAP_LOG( CONFIG, ERR, "failed to add syncinfo\n", 0, 0,0 ); + #else + Debug( LDAP_DEBUG_ANY, "failed to add syncinfo\n", 0, 0, 0 ); + #endif + free( si ); + return 1; + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( CONFIG, RESULTS, + "add_syncbackup: Config: ** successfully added syncbackup \"%s%d\"\n", + si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 ); + #else + Debug( LDAP_DEBUG_CONFIG, + "Config: ** successfully added syncbackup \"%s:%d\"\n", + si->si_provideruri == NULL ? "(null)" : si->si_provideruri, 0, 0 ); + #endif + si->si_be = be; + LDAP_STAILQ_INSERT_TAIL( &be->be_syncinfo, si, si_next ); + return 0; + } + } + + + static int + parse_syncbackup_line( + char **cargv, + int cargc, + syncinfo_t *si + ) + { + int gots = 0; + int i; + char *hp, *val; + + for ( i = 1; i < cargc; i++ ) { + if ( !strncasecmp( cargv[ i ], PROVIDERSTR, + sizeof( PROVIDERSTR ) - 1 )) { + val = cargv[ i ] + sizeof( PROVIDERSTR ); + if ( validate_global_referral( val ) ) { + fprintf( stderr, "Error: parse_syncbackup_line: " + "invalid URL (%s)\n", val ); + return -1; + } + + si->si_provideruri = ch_strdup( val ); + si->si_provideruri_bv = (BerVarray) ch_calloc( 2, sizeof( struct berval )); + ber_str2bv( si->si_provideruri, strlen( si->si_provideruri ), 1, &si->si_provideruri_bv[0] ); + si->si_provideruri_bv[1].bv_len = 0; + si->si_provideruri_bv[1].bv_val = NULL; + gots |= GOT_PROVIDER; + } else if ( !strncasecmp( cargv[ i ], STARTTLSSTR, + sizeof(STARTTLSSTR) - 1 ) ) + { + val = cargv[ i ] + sizeof( STARTTLSSTR ); + if( !strcasecmp( val, CRITICALSTR ) ) { + si->si_tls = SYNCINFO_TLS_CRITICAL; + } else { + si->si_tls = SYNCINFO_TLS_ON; + } + } else if ( !strncasecmp( cargv[ i ], + BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( BINDDNSTR ); + si->si_binddn = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR, + sizeof( BINDMETHSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( BINDMETHSTR ); + if ( !strcasecmp( val, SIMPLESTR )) { + si->si_bindmethod = LDAP_AUTH_SIMPLE; + gots |= GOT_METHOD; + } else if ( !strcasecmp( val, SASLSTR )) { + si->si_bindmethod = LDAP_AUTH_SASL; + gots |= GOT_METHOD; + } else { + si->si_bindmethod = -1; + } + } else if ( !strncasecmp( cargv[ i ], + SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SASLMECHSTR ); + si->si_saslmech = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + CREDSTR, sizeof( CREDSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( CREDSTR ); + si->si_passwd = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SECPROPSSTR ); + si->si_secprops = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + REALMSTR, sizeof( REALMSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( REALMSTR ); + si->si_realm = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( AUTHCSTR ); + si->si_authcId = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) { + /* Old authcID is provided for some backwards compatibility */ + val = cargv[ i ] + sizeof( OLDAUTHCSTR ); + si->si_authcId = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( AUTHZSTR ); + si->si_authzId = ch_strdup( val ); + } else if ( !strncasecmp( cargv[ i ], + SYNCIDSTR, sizeof( SYNCIDSTR ) -1 )) { + val = cargv[ i ] + sizeof( SYNCIDSTR ); + si->si_syncid = ch_strdup( val ); + gots |= GOT_ID; + } else if ( !strncasecmp( cargv[ i ], + CHECKINTVLSTR, sizeof( CHECKINTVLSTR ) -1 )) { + val = cargv[ i ] + sizeof( CHECKINTVLSTR ); + si->si_interval = atoi( val ); + if ( si->si_interval <= 0 ) { + fprintf( stderr, "Error: parse_syncbackup_line: " + "checkinterval must be larger than 0\n" ); + return -1; + } + } else { + fprintf( stderr, "Error: parse_syncbackup_line: " + "unknown keyword \"%s\"\n", cargv[ i ] ); + } + } + + #if 0 + if ( si->bindmethod == LDAP_AUTH_SASL) { + if ((gots & GOT_MECH) == 0) { + fprintf( stderr, "Error: \"syncbackup\" line needs SASLmech flag " + "in slapd config file\n" ); + return -1; + } + } + + gots |= GOT_MECH; + #endif + + if ( gots != GOT_ALL ) { + fprintf( stderr, "Error: Malformed \"syncbackup\" line in slapd config file " ); + return -1; + } + + return 0; + } + + static int + add_syncreplica( + Backend *be, + char **cargv, + int cargc + ) + { + int nr, rc, i; + Ri *ri; + syncbackupinfo_t *info; + // syncbackup_table_t *tbl; + // syncbackup_history_t *history; + + if ( be->be_suffix[1].bv_val ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, ERR, + "add_syncbackup: only one suffix allowed\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "add_syncbackup: only one suffix allowed\n", 0, 0, 0 ); + #endif + return 1; + } + + if ( be->be_syncbackupinfo == NULL ) { + be->be_syncbackupinfo = syncbackupinfo_new( be ); + info = be->be_syncbackupinfo; + } + + info = be->be_syncbackupinfo; + + nr = ++info->sbi_num_max_backups; + info->sbi_backups = + (syncbackup_t **)ch_realloc(info->sbi_backups, nr * sizeof(syncbackup_t *)); + + if ( info->sbi_backups == NULL ) { + fprintf( stderr, "out of memory, add_syncreplica\n" ); + exit( EXIT_FAILURE ); + } + + ri = (Ri *)ch_malloc(sizeof(Ri)); + memset( ri, 0, sizeof(Ri) ); + if ( parse_replica_line( cargv, cargc, ri) < 0 ) { + /* Something bad happened - back out */ + fprintf( stderr, + "Warning: failed to add replica \"%s:%d - ignoring replica\n", + ri->ri_hostname == NULL ? + "(null)" : ri->ri_hostname, + ri->ri_port ); + free (ri); + info->sbi_num_max_backups--; + } else { + info->sbi_backups[nr-1] = syncbackup_new ( ri ); + info->sbi_backups[nr-1]->sb_sbi = info; + + #ifdef NEW_LOGGING + LDAP_LOG ( CONFIG, RESULTS, + "add_syncreplica: Config: ** successfully added replica \"%s%d\"\n", + ri->ri_hostname == NULL ? + "(null)" : ri->ri_hostname, + ri->ri_port, 0 ); + #else + Debug( LDAP_DEBUG_CONFIG, + "Config: ** successfully added replica \"%s:%d\"\n", + ri->ri_hostname == NULL ? + "(null)" : ri->ri_hostname, + ri->ri_port, 0 ); + #endif + } + + return 0; + } + + static int + parse_replica_line( + char **cargv, + int cargc, + Ri *ri + ) + { + int gots = 0; + int i; + char *hp, *val; + + for ( i = 1; i < cargc; i++ ) { + if ( !strncasecmp( cargv[ i ], HOSTSTR, sizeof( HOSTSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( HOSTSTR ); /* '\0' string terminator accounts for '=' */ + if (( hp = strchr( val, ':' )) != NULL ) { + *hp = '\0'; + hp++; + ri->ri_port = atoi( hp ); + } + if ( ri->ri_port <= 0 ) { + ri->ri_port = 0; + } + ri->ri_hostname = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], ATTRSTR, sizeof( ATTRSTR ) - 1 ) ) { + /* ignore it */ ; + } else if ( !strncasecmp( cargv[ i ], SUFFIXSTR, sizeof( SUFFIXSTR ) - 1 ) ) { + /* ignore it */ ; + } else if ( !strncasecmp( cargv[ i ], TLSSTR, sizeof( TLSSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( TLSSTR ); + if( !strcasecmp( val, CRITICALSTR ) ) { + ri->ri_tls = TLS_CRITICAL; + } else { + ri->ri_tls = TLS_ON; + } + } else if ( !strncasecmp( cargv[ i ], BINDDNSTR, sizeof( BINDDNSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( BINDDNSTR ); + ri->ri_bind_dn = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], BINDMETHSTR, sizeof( BINDMETHSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( BINDMETHSTR ); + if ( !strcasecmp( val, KERBEROSSTR )) { + fprintf( stderr, "Error: a bind method of \"kerberos\" was\n" ); + fprintf( stderr, "specified in the slapd configuration file.\n" ); + fprintf( stderr, "slurpd no longer supports Kerberos.\n" ); + exit( EXIT_FAILURE ); + } else if ( !strcasecmp( val, SIMPLESTR )) { + ri->ri_bind_method = LDAP_AUTH_SIMPLE; + gots |= GOT_METHOD; + } else if ( !strcasecmp( val, SASLSTR )) { + ri->ri_bind_method = LDAP_AUTH_SASL; + gots |= GOT_METHOD; + } else { + ri->ri_bind_method = -1; + } + } else if ( !strncasecmp( cargv[ i ], SASLMECHSTR, sizeof( SASLMECHSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SASLMECHSTR ); + ri->ri_saslmech = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], CREDSTR, sizeof( CREDSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( CREDSTR ); + ri->ri_password = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], SECPROPSSTR, sizeof( SECPROPSSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SECPROPSSTR ); + ri->ri_secprops = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], REALMSTR, sizeof( REALMSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( REALMSTR ); + ri->ri_realm = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], AUTHCSTR, sizeof( AUTHCSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( AUTHCSTR ); + ri->ri_authcId = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], OLDAUTHCSTR, sizeof( OLDAUTHCSTR ) - 1 ) ) { + /* Old authcID is provided for some backwards compatibility */ + val = cargv[ i ] + sizeof( OLDAUTHCSTR ); + ri->ri_authcId = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], AUTHZSTR, sizeof( AUTHZSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( AUTHZSTR ); + ri->ri_authzId = strdup( val ); + } else if ( !strncasecmp( cargv[ i ], SRVTABSTR, sizeof( SRVTABSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SRVTABSTR ); + if ( ri->ri_srvtab != NULL ) { + free( ri->ri_srvtab ); + } + ri->ri_srvtab = strdup( val ); + } else if ( ! strncasecmp ( cargv[ i ], "syncid=", sizeof( SYNCIDSTR ) - 1 ) ) { + val = cargv[ i ] + sizeof( SYNCIDSTR ); + ri->ri_syncid = ch_strdup( val ); + } else { + fprintf( stderr, + "Error: parse_replica_line: unknown keyword \"%s\"\n", + cargv[ i ] ); + } + } + + #if 0 + if ( ri->ri_bind_method == AUTH_SASL) { + if ((gots & GOT_MECH) == 0) { + fprintf( stderr, "Error: \"replica\" line needs SASLmech flag in " ); + fprintf( stderr, "slapd config file, line %d\n", lineno ); + return -1; + } + } + else if ( gots != GOT_ALL ) { + fprintf( stderr, "Error: Malformed \"replica\" line in slapd " ); + fprintf( stderr, "config file, line %d\n", lineno ); + return -1; + } + #endif + + return 0; + } + + #endif + char ** str2clist( char ***out, char *in, const char *brkstr ) { diff -cNr openldap-2.2.30.org/servers/slapd/connection.c openldap-2.2.30/servers/slapd/connection.c *** openldap-2.2.30.org/servers/slapd/connection.c 2005-11-16 08:05:34.000000000 +0900 --- openldap-2.2.30/servers/slapd/connection.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 1094,1099 **** --- 1094,1120 ---- assert( 0 ); } + #ifdef LDAP_SYNCBACKUP + if ( op->o_ctxcsn ) { + syncinfo_t *si; + if ( !LDAP_STAILQ_EMPTY ( &op->o_bd->be_syncinfo )) { + LDAP_STAILQ_FOREACH( si, &op->o_bd->be_syncinfo, si_next ) { + if( si->si_replType == SYNC_BACKUP && si->si_state == SYNC_HEALTH_STATE_IDLE ) { + #ifdef NEW_LOGGING + LDAP_LOG( CONNECTION, DETAIL1, + "connection_operation: master sends an event for %s\n", si->si_syncid, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "connection_operation: master sends an event for %s\n", si->si_syncid, 0, 0 ); + #endif + si->si_state = SYNC_HEALTH_STATE_CONNECT; + break; + } + } + } + } + #endif + operations_error: if( rc == SLAPD_DISCONNECT ) tag = LBER_ERROR; *************** *** 1164,1169 **** --- 1185,1202 ---- conn->c_n_ops_executing--; conn->c_n_ops_completed++; + #ifdef LDAP_SYNCBACKUP + } else if ( ( op->o_tag == LDAP_REQ_EXTENDED && !strcmp(op->oq_extended.rs_reqoid.bv_val, LDAP_EXOP_X_START_SYNC)) ) { + 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++; + if( rc == SLAPD_ABANDON ) { + sl_mem_detach( ctx, memctx ); + } else { + slap_op_free( op ); + } + #endif } else { LDAP_STAILQ_REMOVE( &conn->c_ops, op, slap_op, o_next); LDAP_STAILQ_NEXT(op, o_next) = NULL; diff -cNr openldap-2.2.30.org/servers/slapd/controls.c openldap-2.2.30/servers/slapd/controls.c *** openldap-2.2.30.org/servers/slapd/controls.c 2005-08-13 04:28:56.000000000 +0900 --- openldap-2.2.30/servers/slapd/controls.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 42,47 **** --- 42,51 ---- #endif static SLAP_CTRL_PARSE_FN parseLDAPsync; + #ifdef LDAP_SYNCBACKUP + static SLAP_CTRL_PARSE_FN parseContextCSN; + #endif + #undef sc_mask /* avoid conflict with Irix 6.5 */ const struct berval slap_pre_read_bv = BER_BVC(LDAP_CONTROL_PRE_READ); *************** *** 130,135 **** --- 134,144 ---- { LDAP_CONTROL_PROXY_AUTHZ, SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops, parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + #ifdef LDAP_SYNCBACKUP + { LDAP_CONTROL_CONTEXTCSN, + SLAP_CTRL_ADD|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME|SLAP_CTRL_DELETE, NULL, + parseContextCSN, LDAP_SLIST_ENTRY_INITIALIZER(next) }, + #endif { NULL, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) } }; *************** *** 1407,1409 **** --- 1416,1468 ---- return LDAP_SUCCESS; } + + #ifdef LDAP_SYNCBACKUP + static int parseContextCSN ( + Operation *op, + SlapReply *rs, + LDAPControl *ctrl ) + { + BerElement *ber; + struct berval ctxcsn = { 0, NULL }; + + if ( op->o_ctxcsn != SLAP_NO_CONTROL ) { + rs->sr_text = "contextCSN control specified multiple times"; + return LDAP_PROTOCOL_ERROR; + } + + if ( ctrl->ldctl_value.bv_len == 0 ) { + rs->sr_text = "contextCSN control value is empty (or absent)"; + return LDAP_PROTOCOL_ERROR; + } + + /* Parse the control value + * contextCSNValue ::= SEQUENCE { + * contextCSNValue ::= SEQUENCE { + * cookie contextCSN + * } + */ + + ber = ber_init( &ctrl->ldctl_value ); + if( ber == NULL ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + if (( ber_scanf( ber, /*{*/ "{m}", &ctxcsn )) == LBER_ERROR ) { + rs->sr_text = "contextCSN control : contextCSN decoding error"; + (void) ber_free( ber, 1 ); + return LDAP_PROTOCOL_ERROR; + } + + ber_dupbv( &op->o_ctxcsn_bv, &ctxcsn ); + + (void) ber_free( ber, 1 ); + + op->o_ctxcsn = ctrl->ldctl_iscritical + ? SLAP_CRITICAL_CONTROL + : SLAP_NONCRITICAL_CONTROL; + + return LDAP_SUCCESS; + } + #endif diff -cNr openldap-2.2.30.org/servers/slapd/ctxcsn.c openldap-2.2.30/servers/slapd/ctxcsn.c *** openldap-2.2.30.org/servers/slapd/ctxcsn.c 2005-01-21 02:01:06.000000000 +0900 --- openldap-2.2.30/servers/slapd/ctxcsn.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 95,100 **** --- 95,106 ---- } } + #ifdef LDAP_SYNCBACKUP + if ( op->o_bd->be_syncbackupinfo ) { + ldap_pvt_thread_mutex_unlock(&op->o_bd->be_syncbackupinfo->sbi_syncbackup_mutex); + } + #endif + ldap_pvt_thread_mutex_unlock( op->o_bd->be_pcl_mutexp ); return; *************** *** 154,162 **** --- 160,190 ---- if ( csn == NULL ) return LDAP_OTHER; + #ifdef LDAP_SYNCBACKUP + + if ( op->o_bd->be_syncbackupinfo ) { + ldap_pvt_thread_mutex_lock(&op->o_bd->be_syncbackupinfo->sbi_syncbackup_mutex); + } + + if ( op->o_ctxcsn != SLAP_NO_CONTROL ) { + if ( op->o_ctxcsn_bv.bv_len >= len ) { + return LDAP_OTHER; + } + strncpy( csnbuf, op->o_ctxcsn_bv.bv_val, len ); + csn->bv_len = strlen( csnbuf ); + } else { + #endif csn->bv_len = lutil_csnstr( csnbuf, len, 0, 0 ); + #ifdef LDAP_SYNCBACKUP + } + #endif csn->bv_val = csnbuf; + #ifdef LDAP_SYNCBACKUP + if ( op->o_ctxcsn == SLAP_NO_CONTROL ) + ber_dupbv( &op->o_ctxcsn_bv, csn ); + #endif + if ( manage_ctxcsn ) { pending = (struct slap_csn_entry *) ch_calloc( 1, sizeof( struct slap_csn_entry )); diff -cNr openldap-2.2.30.org/servers/slapd/daemon.c openldap-2.2.30/servers/slapd/daemon.c *** openldap-2.2.30.org/servers/slapd/daemon.c 2005-07-07 11:23:47.000000000 +0900 --- openldap-2.2.30/servers/slapd/daemon.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 1281,1286 **** --- 1281,1289 ---- struct timeval *tvp; struct timeval *cat; + #ifdef LDAP_SYNCBACKUP + struct timeval *cat2; + #endif time_t tdelta = 1; struct re_s* rtask; now = slap_get_time(); *************** *** 1382,1388 **** rtask = ldap_pvt_runqueue_next_sched( &syncrepl_rq, &cat ); } ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex ); ! if ( cat && cat->tv_sec ) { time_t diff = difftime( cat->tv_sec, now ); if ( diff == 0 ) --- 1385,1416 ---- rtask = ldap_pvt_runqueue_next_sched( &syncrepl_rq, &cat ); } ldap_pvt_thread_mutex_unlock( &syncrepl_rq.rq_mutex ); ! ! #ifdef LDAP_SYNCBACKUP ! ldap_pvt_thread_mutex_lock( &health_rq.rq_mutex ); ! rtask = ldap_pvt_runqueue_next_sched( &health_rq, &cat2 ); ! while ( cat2 && cat2->tv_sec && cat2->tv_sec <= now ) { ! if ( ldap_pvt_runqueue_isrunning( &health_rq, rtask )) { ! ldap_pvt_runqueue_resched( &health_rq, rtask, 0 ); ! } ! else { ! ldap_pvt_runqueue_runtask( &health_rq, rtask ); ! ldap_pvt_runqueue_resched( &health_rq, rtask, 0 ); ! ldap_pvt_thread_mutex_unlock( &health_rq.rq_mutex ); ! ldap_pvt_thread_pool_submit( &connection_pool, ! rtask->routine, (void *) rtask ); ! ldap_pvt_thread_mutex_lock( &health_rq.rq_mutex ); ! } ! rtask = ldap_pvt_runqueue_next_sched( &health_rq, &cat2 ); ! } ! ldap_pvt_thread_mutex_unlock( &health_rq.rq_mutex ); ! ! if ( cat2 ) { ! if ( !cat || cat2->tv_sec < cat->tv_sec ) ! cat = cat2; ! } ! #endif ! if ( cat && cat->tv_sec ) { time_t diff = difftime( cat->tv_sec, now ); if ( diff == 0 ) diff -cNr openldap-2.2.30.org/servers/slapd/delete.c openldap-2.2.30/servers/slapd/delete.c *** openldap-2.2.30.org/servers/slapd/delete.c 2005-01-21 02:01:07.000000000 +0900 --- openldap-2.2.30/servers/slapd/delete.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 207,226 **** /* do the update here */ int repl_user = be_isupdate( op ); #ifndef SLAPD_MULTIMASTER if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif { slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; ! if ( !repl_user ) { struct berval csn = BER_BVNULL; char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; slap_get_csn( op, csnbuf, sizeof(csnbuf), &csn, 1 ); } #ifdef SLAPD_MULTIMASTER ! if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ) #endif { cb.sc_next = op->o_callback; --- 207,239 ---- /* do the update here */ int repl_user = be_isupdate( op ); #ifndef SLAPD_MULTIMASTER + #ifdef LDAP_SYNCBACKUP + if ( !SLAP_SHADOW(op->o_bd) || + ( SLAP_BACKUP_SHADOW(op->o_bd) && op->o_ctxcsn != SLAP_NO_CONTROL ) || repl_user ) + #else if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif + #endif { slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; ! if ( !repl_user ! #ifdef LDAP_SYNCBACKUP ! || SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) { struct berval csn = BER_BVNULL; char csnbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; slap_get_csn( op, csnbuf, sizeof(csnbuf), &csn, 1 ); } #ifdef SLAPD_MULTIMASTER ! if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ! #ifdef LDAP_SYNCBACKUP ! || !SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) #endif { cb.sc_next = op->o_callback; diff -cNr openldap-2.2.30.org/servers/slapd/extended.c openldap-2.2.30/servers/slapd/extended.c *** openldap-2.2.30.org/servers/slapd/extended.c 2005-01-21 02:01:08.000000000 +0900 --- openldap-2.2.30/servers/slapd/extended.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 69,74 **** --- 69,77 ---- const struct berval slap_EXOP_WHOAMI = BER_BVC(LDAP_EXOP_X_WHO_AM_I); const struct berval slap_EXOP_MODIFY_PASSWD = BER_BVC(LDAP_EXOP_MODIFY_PASSWD); const struct berval slap_EXOP_START_TLS = BER_BVC(LDAP_EXOP_START_TLS); + #ifdef LDAP_SYNCBACKUP + const struct berval slap_EXOP_START_SYNC = BER_BVC(LDAP_EXOP_X_START_SYNC); + #endif static struct { const struct berval *oid; *************** *** 81,86 **** --- 84,92 ---- #ifdef HAVE_TLS { &slap_EXOP_START_TLS, 0, starttls_extop }, #endif + #ifdef LDAP_SYNCBACKUP + { &slap_EXOP_START_SYNC, 0, startsync_extop }, + #endif { NULL, 0, NULL } }; diff -cNr openldap-2.2.30.org/servers/slapd/modify.c openldap-2.2.30/servers/slapd/modify.c *** openldap-2.2.30.org/servers/slapd/modify.c 2005-01-21 02:01:08.000000000 +0900 --- openldap-2.2.30/servers/slapd/modify.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 462,469 **** --- 462,474 ---- * because it accepts each modify request */ #ifndef SLAPD_MULTIMASTER + #ifdef LDAP_SYNCBACKUP + if ( !SLAP_SHADOW(op->o_bd) || + ( SLAP_BACKUP_SHADOW(op->o_bd) && op->o_ctxcsn != SLAP_NO_CONTROL ) || repl_user ) + #else if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif + #endif { int update = op->o_bd->be_update_ndn.bv_len; char textbuf[SLAP_TEXT_BUFLEN]; *************** *** 494,502 **** } } op->orm_modlist = modlist; #ifdef SLAPD_MULTIMASTER ! if ( !repl_user ) #endif { /* but we log only the ones not from a replicator user */ --- 499,518 ---- } } + #ifdef LDAP_SYNCBACKUP + if ( SLAP_BACKUP_SHADOW(op->o_bd) ) { + struct berval csn = { 0, NULL }; + char csnbuf[ LDAP_LUTIL_CSNSTR_BUFSIZE ]; + slap_get_csn ( op, csnbuf, sizeof(csnbuf), &csn, 1 ); + } + #endif op->orm_modlist = modlist; #ifdef SLAPD_MULTIMASTER ! if ( !repl_user ! #ifdef LDAP_SYNCBACKUP ! || !SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) #endif { /* but we log only the ones not from a replicator user */ diff -cNr openldap-2.2.30.org/servers/slapd/modrdn.c openldap-2.2.30/servers/slapd/modrdn.c *** openldap-2.2.30.org/servers/slapd/modrdn.c 2005-01-21 02:01:08.000000000 +0900 --- openldap-2.2.30/servers/slapd/modrdn.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 364,376 **** /* do the update here */ int repl_user = be_isupdate( op ); #ifndef SLAPD_MULTIMASTER if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif { slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; op->orr_deleteoldrdn = deloldrdn; #ifdef SLAPD_MULTIMASTER ! if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ) #endif { cb.sc_next = op->o_callback; --- 364,385 ---- /* do the update here */ int repl_user = be_isupdate( op ); #ifndef SLAPD_MULTIMASTER + #ifdef LDAP_SYNCBACKUP + if ( !SLAP_SHADOW(op->o_bd) || + ( SLAP_BACKUP_SHADOW(op->o_bd) && op->o_ctxcsn != SLAP_NO_CONTROL ) || repl_user ) + #else if ( !SLAP_SHADOW(op->o_bd) || repl_user ) #endif + #endif { slap_callback cb = { NULL, slap_replog_cb, NULL, NULL }; op->orr_deleteoldrdn = deloldrdn; #ifdef SLAPD_MULTIMASTER ! if ( !op->o_bd->be_update_ndn.bv_len || !repl_user ! #ifdef LDAP_SYNCBACKUP ! || !SLAP_BACKUP_SHADOW(op->o_bd) ! #endif ! ) #endif { cb.sc_next = op->o_callback; *************** *** 621,627 **** --- 630,642 ---- done: + #ifdef LDAP_SYNCBACKUP + if ( rs->sr_err == LDAP_SUCCESS && ( !repl_user + || SLAP_BACKUP_SHADOW(op->o_bd) ) + ) { + #else if ( rs->sr_err == LDAP_SUCCESS && !repl_user ) { + #endif char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof textbuf; diff -cNr openldap-2.2.30.org/servers/slapd/operation.c openldap-2.2.30/servers/slapd/operation.c *** openldap-2.2.30.org/servers/slapd/operation.c 2005-01-21 02:01:08.000000000 +0900 --- openldap-2.2.30/servers/slapd/operation.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 89,94 **** --- 89,100 ---- slap_sync_cookie_free( &op->o_sync_state, 0 ); + #ifdef LDAP_SYNCBACKUP + if ( op->o_ctxcsn_bv.bv_val != NULL ) { + free ( op->o_ctxcsn_bv.bv_val ); + } + #endif + { GroupAssertion *g, *n; for (g = op->o_groups; g; g=n) { *************** *** 161,165 **** --- 167,175 ---- } #endif /* defined( LDAP_SLAPI ) */ + #if LDAP_SYNCBACKUP + op->o_backup = 1; + #endif + return( op ); } diff -cNr openldap-2.2.30.org/servers/slapd/passwd.c openldap-2.2.30/servers/slapd/passwd.c *** openldap-2.2.30.org/servers/slapd/passwd.c 2005-03-15 04:34:31.000000000 +0900 --- openldap-2.2.30/servers/slapd/passwd.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 205,210 **** --- 205,213 ---- if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_err = op->o_bd->be_modify( op, rs ); } + #ifdef LDAP_SYNCBACKUP + slap_graduate_commit_csn( op ); + #endif if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_rspdata = rsp; } else if ( rsp ) { diff -cNr openldap-2.2.30.org/servers/slapd/proto-slap.h openldap-2.2.30/servers/slapd/proto-slap.h *** openldap-2.2.30.org/servers/slapd/proto-slap.h 2005-01-21 02:01:09.000000000 +0900 --- openldap-2.2.30/servers/slapd/proto-slap.h 2006-10-11 11:28:08.000000000 +0900 *************** *** 1305,1310 **** --- 1305,1331 ---- LDAP_SLAPD_F (int) do_unbind LDAP_P((Operation *op, SlapReply *rs)); LDAP_SLAPD_F (int) do_extended LDAP_P((Operation *op, SlapReply *rs)); + #ifdef LDAP_SYNCBACKUP + + LDAP_SLAPD_V (struct runqueue_s) health_rq; + + LDAP_SLAPD_F (int) syncbackup LDAP_P((Operation *op, SlapReply *rs, Entry *e)); + LDAP_SLAPD_F (int) syncbackup_abandon LDAP_P((Operation *op, SlapReply *rs)); + LDAP_SLAPD_F (int) syncbackup_get_id LDAP_P((BackendDB *be, char *syncid)); + LDAP_SLAPD_F (int) attach_backup LDAP_P((BackendDB *db, int id, char *csn, Operation *op, syncbackup_backup_event_func )); + LDAP_SLAPD_F (int) detach_backup LDAP_P((BackendDB *db, int id)); + LDAP_SLAPD_F (SLAP_EXTOP_MAIN_FN) startsync_extop; + LDAP_SLAPD_F (SLAP_EXTOP_MAIN_FN) noop_extop; + LDAP_SLAPD_F (syncbackup_t *) syncbackup_new LDAP_P((Ri *ri)); + LDAP_SLAPD_F (void) syncbackup_destroy LDAP_P((syncbackup_t *bak)); + LDAP_SLAPD_F (syncbackupinfo_t *) syncbackupinfo_new (BackendDB *be); + LDAP_SLAPD_F (void) syncbackupinfo_destroy LDAP_P((syncbackupinfo_t *info)); + LDAP_SLAPD_F (int) healthcheck LDAP_P((LDAP *ld)); + + LDAP_SLAPD_F (void*) backup_healthcheck LDAP_P((void *, void *)); + + #endif + LDAP_END_DECL #endif /* PROTO_SLAP_H */ diff -cNr openldap-2.2.30.org/servers/slapd/slap.h openldap-2.2.30/servers/slapd/slap.h *** openldap-2.2.30.org/servers/slapd/slap.h 2005-03-15 02:58:02.000000000 +0900 --- openldap-2.2.30/servers/slapd/slap.h 2006-10-11 11:28:08.000000000 +0900 *************** *** 1413,1420 **** --- 1413,1577 ---- LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist; LDAP_STAILQ_ENTRY( syncinfo_s ) si_next; ldap_pvt_thread_mutex_t si_mutex; + #ifdef LDAP_SYNCBACKUP + # define SYNC_REPLICA 0 + # define SYNC_BACKUP 1 + # define SYNC_BOOTSYNC 2 + int si_replType; + char *si_syncid; + int si_state; + #endif + } syncinfo_t; + #ifdef LDAP_SYNCBACKUP + + /* Synchronized backup macros */ + # define SYNCBACKUP_DEBUG(msg...) \ + fprintf(stderr, "SYNCBACKUP_DEBUG: " msg, ## msg) + + # define SYNC_HEALTH_TIMEOUT 10 + + # define SYNCBACKUP_STATE_NONE 0 + # define SYNCBACKUP_STATE_CONNECT 1 + # define SYNCBACKUP_STATE_BIND 2 + + # define SYNC_HEALTH_STATE_NONE 0 + # define SYNC_HEALTH_STATE_CONNECT 1 + # define SYNC_HEALTH_STATE_IDLE 2 + + # define SYNC_STATUS_NONE 0 + # define SYNC_NO_SUCH_COOKIE 1 + # define SYNC_ERROR 2 + # define SYNC_SERVER_FAILURE 3 + + # define SLAPD_ATTACH_NOCOOKIE 1 + # define SLAPD_ATTACH_BADCOOKIE 2 + # define SLAPD_ATTACH_ALREADY 3 + + # include "../servers/slurpd/slurp.h" + # ifdef ldap_debug + # undef ldap_debug + # define ldap_debug slap_debug + # endif + + typedef struct extended_s { + char *reqoid; + struct berval *reqdata; + } + extended_t; + + typedef struct rename_s { + char *olddn; + char *newrdn; + char *newSup; + int deleteoldrdn; + } + rename_t; + + typedef struct addmod_s { + char *entrydn; + LDAPMod **mods; + } + addmod_t; + + typedef struct event_s { + unsigned long ev_id; + + int ev_tag; + long ev_time; + char *ev_csn; + + LDAPControl **ev_ctrls; + + unsigned long ev_connid; + unsigned long ev_opid; + + Entry *ev_entry; + union ev_u { + addmod_t *addmod; + char *deldn; + rename_t *rename; + extended_t *ex; + } ev; + LDAP_STAILQ_ENTRY(event_s) ev_next; + } + event_t; + + struct syncbackup_s; + + typedef int syncbackup_backup_event_func LDAP_P(( + struct syncbackup_s *b, + int rc, + char *err, + int severity)); + + struct syncbackupinfo_s; + + typedef struct syncbackup_s { + struct syncbackupinfo_s *sb_sbi; /* sbi for this sb */ + + char *sb_syncid; /* syncid information */ + + int sb_state; /* status of sb */ + + LDAP *sb_ld; /* LDAP descripter */ + int sb_msgid; /* msgid which this sb's handling */ + long sb_time; /* time when the msgid's operation started */ + + # define SYNCBACKUP_ERROR_NORMAL 0 + # define SYNCBACKUP_ERROR_CRITICAL 1 + char sb_criterr; /* flag for critical situation */ + + ldap_pvt_thread_mutex_t sb_join_mutex; /* join protection */ + + syncbackup_backup_event_func *sb_cb; /* call back */ + + unsigned long sb_opid; /* opeartion id to make syncbackup start */ + unsigned long sb_connid; /* connection id to make syncbackup start */ + struct slap_op *sb_op; /* operation to make syncbackup start */ + + struct ri *sb_ri; /* syncreplica information */ + + event_t *sb_age; /* age of this backup */ + } + syncbackup_t; + + typedef struct syncbackupinfo_s { + BackendDB *sbi_bd; /* backend DB for this sbi */ + + ldap_pvt_thread_mutex_t sbi_syncbackup_mutex; /* sbi protection */ + + ber_int_t sbi_num_max_backups; /* maximum syncbackup servers */ + ber_int_t sbi_num_backups; /* active backup servers */ + ber_int_t sbi_num_sync_backups; /* synchronized backup servers */ + ldap_pvt_thread_mutex_t sbi_num_sync_backups_mutex; + ber_int_t sbi_num_atleast_result; /* at least backup */ + + struct berval *sbi_init_cookie; /* init cookie value */ + + ldap_pvt_thread_mutex_t sbi_num_backups_mutex; /* num_backup protection */ + ldap_pvt_thread_cond_t sbi_backup_avail_cv; /* backup avail */ + ldap_pvt_thread_mutex_t sbi_backup_avail_mutex; /* backup avail protection */ + + /* modification history */ + struct syncbackup_history_s { + LDAP_STAILQ_HEAD(h_e, event_s) queue; /* history queue */ + unsigned long top; /* queue top location */ + unsigned long bottom; /* queue bottom location */ + } + sbi_history; + + syncbackup_t **sbi_backups; /* each backup info */ + + ldap_pvt_thread_pool_t sbi_follow_pool; /* follow thread */ + ldap_pvt_thread_mutex_t sbi_follow_mutex; /* follow thread protection */ + + ldap_pvt_thread_pool_t sbi_health_pool; /* health check thread */ + } + syncbackupinfo_t; + #endif + LDAP_TAILQ_HEAD( be_pcl, slap_csn_entry ); struct slap_backend_db { *************** *** 1482,1487 **** --- 1639,1647 ---- #define SLAP_DBFLAG_SHADOW 0x8000U /* a shadow */ #define SLAP_DBFLAG_SYNC_SHADOW 0x1000U /* a sync shadow */ #define SLAP_DBFLAG_SLURP_SHADOW 0x2000U /* a slurp shadow */ + #ifdef LDAP_SYNCBACKUP + #define SLAP_DBFLAG_BACKUP_SHADOW 0x4000U /* a backup shadow */ + #endif slap_mask_t be_flags; #define SLAP_DBFLAGS(be) ((be)->be_flags) #define SLAP_NOLASTMOD(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_NOLASTMOD) *************** *** 1497,1503 **** #define SLAP_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SHADOW) #define SLAP_SYNC_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SYNC_SHADOW) #define SLAP_SLURP_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SLURP_SHADOW) ! slap_mask_t be_restrictops; /* restriction operations */ #define SLAP_RESTRICT_OP_ADD 0x0001U #define SLAP_RESTRICT_OP_BIND 0x0002U --- 1657,1665 ---- #define SLAP_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SHADOW) #define SLAP_SYNC_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SYNC_SHADOW) #define SLAP_SLURP_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_SLURP_SHADOW) ! #ifdef LDAP_SYNCBACKUP ! #define SLAP_BACKUP_SHADOW(be) (SLAP_DBFLAGS(be) & SLAP_DBFLAG_BACKUP_SHADOW) ! #endif slap_mask_t be_restrictops; /* restriction operations */ #define SLAP_RESTRICT_OP_ADD 0x0001U #define SLAP_RESTRICT_OP_BIND 0x0002U *************** *** 1561,1566 **** --- 1723,1731 ---- struct slap_replica_info **be_replica; /* replicas of this backend (in master) */ char *be_replogfile; /* replication log file (in master) */ struct berval be_update_ndn; /* allowed to make changes (in replicas) */ + #ifdef LDAP_SYNCBACKUP + struct berval be_sync_ndn; /* allowed to do syncbackup */ + #endif BerVarray be_update_refs; /* where to refer modifying clients to */ struct be_pcl *be_pending_csn_list; ldap_pvt_thread_mutex_t be_pcl_mutex; *************** *** 1568,1574 **** struct berval be_context_csn; ldap_pvt_thread_mutex_t be_context_csn_mutex; LDAP_STAILQ_HEAD( be_si, syncinfo_s ) be_syncinfo; /* For syncrepl */ ! char *be_realm; void *be_pb; /* Netscape plugin */ --- 1733,1742 ---- struct berval be_context_csn; ldap_pvt_thread_mutex_t be_context_csn_mutex; LDAP_STAILQ_HEAD( be_si, syncinfo_s ) be_syncinfo; /* For syncrepl */ ! #ifdef LDAP_SYNCBACKUP ! syncbackupinfo_t *be_syncbackupinfo; /* For syncbackup */ ! int be_weaksync; /* weaksync flag */ ! #endif char *be_realm; void *be_pb; /* Netscape plugin */ *************** *** 2160,2165 **** --- 2328,2339 ---- int o_nocaching; int o_delete_glue_parent; + #ifdef LDAP_SYNCBACKUP + char o_ctxcsn; /* contextCSN control flag */ + struct berval o_ctxcsn_bv; /* contextCSN control value */ + char o_backup; /* propagation handle flag */ + #endif + #ifdef LDAP_SLAPI void *o_pb; /* NS-SLAPI plugin */ void *o_extensions; /* NS-SLAPI plugin */ diff -cNr openldap-2.2.30.org/servers/slapd/startsync.c openldap-2.2.30/servers/slapd/startsync.c *** openldap-2.2.30.org/servers/slapd/startsync.c 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/servers/slapd/startsync.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,351 ---- + /* $OpenLDAP:$ */ + /* + * startSYNC extended operation + */ + /* + * Copyright 2003, VA Linux Systems Japan, K.K, All rights reserved. + * This software is not subject to any license of VA Linux Systems + * Japan, K.K. + * + * This is free software; you can redistribute and use it + * under the same terms as OpenLDAP itself. + * + * Written by Kaoru Sekiguchi and Masato Taruishi. + * + */ + + #include "portable.h" + #include "slap.h" + + #ifdef LDAP_SYNCBACKUP + + static syncbackup_backup_event_func send_sync_error; + static void send_ldap_syncresponse( Operation *op, SlapReply *rs, int status ); + + static struct berval * + slap_sync_return( int status ) + { + struct berval *bv = NULL; + char berbuf[LBER_ELEMENT_SIZEOF]; + /* opaque structure, size unknown but smaller than berbuf */ + BerElement *ber = (BerElement *)berbuf; + + ber_init_w_nullc( ber, LBER_USE_DER ); + + if (ber_printf(ber, "{eN}", status) < 0) { + ber_free_buf( ber ); + + return NULL; + } + + (void) ber_flatten( ber, &bv ); + + ber_free_buf( ber ); + + return bv; + } + + static int + send_sync_error( + syncbackup_t *bak, + int rc, + char *errmsg, + int severity + ) + { + Operation *op = bak->sb_op; + SlapReply rs = { REP_EXTENDED }; + void *saved_tmpmemctx = NULL; + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "=>send_sync_error\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "=>send_sync_error\n", 0, 0, 0 ); + #endif + + if ( op->o_abandon != 1 ) + { + rs.sr_err = rc; + rs.sr_text = errmsg; + send_ldap_syncresponse( bak->sb_op, &rs, severity ); + + if ( severity == SYNC_ERROR ) { + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu STARTSYNC SYNCERROR id=\"%s\" err=%d txt=%s\n", + op->o_conn->c_connid, op->o_opid, + bak->sb_syncid, + rc, + rs.sr_text ); + } else { + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu STARTSYNC SERVERFAIL id=\"%s\" err=%d txt=%s\n", + op->o_conn->c_connid, op->o_opid, + bak->sb_syncid, + rc, + rs.sr_text ); + } + + } + + if ( op->o_savmemctx ) { + saved_tmpmemctx = op->o_savmemctx; + } + + slap_op_free( op ); + + if ( saved_tmpmemctx ) { + sl_mem_destroy( NULL, saved_tmpmemctx ); + } + + return 0; + + } + + int startsync_extop( + Operation *op, + SlapReply *rs ) + { + BerElement *ber; + int i, rc; + ber_len_t len; + char *syncid; + struct berval cookie = { 0, NULL }; + BackendDB *bd; + void *memctx_null = NULL; + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "=>startsync\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "=>startsync\n", 0, 0, 0 ); + #endif + + + if ( op->o_tmpmemctx ) { + op->o_savmemctx = op->o_tmpmemctx; + op->o_tmpmemctx = NULL; + op->o_tmpmfuncs = &ch_mfuncs; + ber_set_option( op->o_ber, LBER_OPT_BER_MEMCTX, &memctx_null ); + } + + rs->sr_rspoid = ch_strdup(LDAP_EXOP_X_START_SYNC); + + if (rs->sr_rspoid == NULL) { + rs->sr_text = "internal error"; + rs->sr_rspdata = slap_sync_return(SYNC_SERVER_FAILURE); + + return LDAP_OTHER; + } + + if ( op->ore_reqdata == NULL ) { + rs->sr_text = "no synchronization information"; + + return LDAP_PROTOCOL_ERROR; + } + + bd = select_backend(&op->o_ndn, 0, 1); + if ( bd == NULL ) { + rs->sr_text = "no such backend to the specified binddn"; + + return LDAP_INSUFFICIENT_ACCESS; + } + + if ( !dn_match( &op->o_ndn, &bd->be_sync_ndn ) ) { + rs->sr_text = "don't allow syncbackup"; + + return LDAP_INSUFFICIENT_ACCESS; + } + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "startsync: \"%s\" is allowed syncbackup\n", + op->o_ndn.bv_val, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "startsync: \"%s\" is allowed syncbackup\n", + op->o_ndn.bv_val, 0, 0 ); + #endif + + ber = ber_init( op->ore_reqdata ); + if ( ber == NULL ) { + rs->sr_text = "internal error"; + rs->sr_rspdata = slap_sync_return(SYNC_SERVER_FAILURE); + + return LDAP_OTHER; + } + + if ( ber_scanf( ber, "{a", &syncid) == LBER_ERROR ) { + rs->sr_text = "parse failed"; + (void) ber_free( ber, 1 ); + + rc = LDAP_PROTOCOL_ERROR; + + goto done; + } + + if ( ber_peek_tag( ber, &len ) == LDAP_TAG_SYNC_COOKIE ) { + if ( ber_scanf( ber, "o}", &cookie ) == LBER_ERROR ) { + rs->sr_text = "parse failed"; + (void) ber_free( ber, 1 ); + + rc = LDAP_PROTOCOL_ERROR; + + goto done; + } + } + + (void) ber_free( ber, 1 ); + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu STARTSYNC id=\"%s\" cookie=\"%s\" dn=\"%s\"\n", + op->o_conn->c_connid, op->o_opid, syncid, cookie.bv_len ? cookie.bv_val : "(null)", op->o_ndn.bv_val ); + + + i = syncbackup_get_id( bd, syncid ); + + if ( i < 0 ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "startsync: syncid \"%s\" is incorrect\n", + syncid, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "startsync: syncid \"%s\" is incorrect\n", + syncid, 0, 0 ); + #endif + rs->sr_text = "incorrect syncid"; + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu RESULT err=%d text=%s\n", + op->o_conn->c_connid, op->o_opid, LDAP_INVALID_CREDENTIALS, rs->sr_text, 0 ); + + rc = LDAP_INVALID_CREDENTIALS; + + goto done; + } + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "startsync: received correct syncid \"%s\"\n", + syncid, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "startsync: received correct syncid \"%s\"\n", + syncid, 0, 0 ); + #endif + + rc = attach_backup(bd, i, cookie.bv_val, op, send_sync_error ); + + switch ( rc ) { + case LDAP_SUCCESS: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, ERR, "syncid=%s, backup server attached\n", + syncid, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "syncid=%s, backup server attached\n", + syncid, 0, 0 ); + #endif + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu STARTSYNC ATTACH id=\"%s\"\n", + op->o_conn->c_connid, op->o_opid, syncid, 0, 0 ); + rs->sr_text = "synchronization start"; + rs->sr_err = LDAP_SUCCESS; + send_ldap_intermediate( op, rs ); + + /* + * FIXME: ad-hoc return value to make this operation + * persistent. + */ + rc = SLAPD_ABANDON; + + goto done; + + case SLAPD_ATTACH_NOCOOKIE: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "startsync: syncid=%s cookie=%s, cookie is old\n", + syncid, cookie.bv_val, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "startsync: syncid=%s, cookie is old\n", + syncid, cookie.bv_val, 0 ); + #endif + + rs->sr_text = "cookie is old"; + rs->sr_rspdata = slap_sync_return(SYNC_NO_SUCH_COOKIE); + + rc = LDAP_OTHER; + + break; + + case SLAPD_ATTACH_BADCOOKIE: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "startsync: syncid=%s cookie=%s, cookie is incorrect\n", + syncid, cookie.bv_val, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "startsync: syncid=%s, cookie is incorrect\n", + syncid, cookie.bv_val, 0 ); + #endif + rs->sr_text = "cookie is incorrect"; + + rc = LDAP_OPERATIONS_ERROR; + + break; + + case SLAPD_ATTACH_ALREADY: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "startsync: syncid=%s, synchronization already started\n", + syncid, cookie.bv_val, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "startsync: syncid=%s, synchronization already started\n", + syncid, cookie.bv_val, 0 ); + #endif + rs->sr_text = "synchronization already started"; + rc = LDAP_OPERATIONS_ERROR; + + break; + + default: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, ERR, "startsync: attach_backup failed\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "startsync: attach_backup failed\n", + 0, 0, 0 ); + #endif + rs->sr_text = "internal error"; + rs->sr_rspdata = slap_sync_return(SYNC_SERVER_FAILURE); + + rc = LDAP_OTHER; + + break; + + } + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu RESULT err=%d text=%s\n", + op->o_conn->c_connid, op->o_opid, rc, rs->sr_text, 0 ); + + done: + if ( syncid != NULL ) + ber_memfree( syncid ); + + if ( cookie.bv_val != NULL ) + ber_memfree( cookie.bv_val ); + + return rc; + } + + static void + send_ldap_syncresponse( Operation *op, SlapReply *rs, int status ) + { + rs->sr_rspoid = strdup(LDAP_EXOP_X_START_SYNC); + if ( status != SYNC_STATUS_NONE ) + rs->sr_rspdata = slap_sync_return(status); + + send_ldap_extended( op, rs ); + + return; + } + #endif diff -cNr openldap-2.2.30.org/servers/slapd/syncbackup.c openldap-2.2.30/servers/slapd/syncbackup.c *** openldap-2.2.30.org/servers/slapd/syncbackup.c 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/servers/slapd/syncbackup.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,2972 ---- + /* $OpenLDAP:$ */ + /* + * Synchronized Backup Engine + */ + /* + * Copyright 2003, VA Linux Systems Japan, K.K, All rights reserved. + * This software is not subject to any license of VA Linux Systems + * Japan, K.K. + * + * This is free software; you can redistribute and use it + * under the same terms as OpenLDAP itself. + * + * Written by Masato Taruishi and Kaoru Sekiguchi. + * + */ + + #include "portable.h" + #include "slap.h" + + #ifdef LDAP_SYNCBACKUP + + #include + #include + #include + #include "ldap_pvt.h" + #include "lutil.h" + #include "lutil_ldap.h" + #include "ldap_rq.h" + + /* events too many threshold */ + #define EVENTS_THRESHOLD 100 + /* events hold time in second */ + #define EVENTS_HOLDTIME 3 * 60 + + #define SYNCBACKUP_EVENT_INIT(head) \ + do { (head)->top = 0; (head)->bottom = 0; \ + LDAP_STAILQ_INIT( &(head)->queue ); } while(0) + + #define SYNCBACKUP_EVENT_MAX(head) \ + ((unsigned long)-1) + + #define SYNCBACKUP_EVENT_SIZE(head) \ + (SYNCBACKUP_EVENT_LATENCY(head, LDAP_STAILQ_FIRST(head)->ev_id)+1) + + #define SYNCBACKUP_EVENT_FULL(head) \ + ( SYNCBACKUP_EVENT_SIZE(head) == SYNCBACKUP_EVENT_MAX(head) - 1 ) + + #define SYNCBACKUP_EVENT_LATENCY(head, loc) \ + ((LDAP_STAILQ_LAST(head, event_s, ev_next)->ev_id>=(loc))? \ + (LDAP_STAILQ_LAST(head, event_s, ev_next)->ev_id-(loc)): \ + LDAP_STAILQ_LAST(head, event_s, ev_next)->ev_id+ \ + (SYNCBACKUP_EVENT_MAX(head)-(loc)) \ + ) + + /* + * + * sbi_history_t +-------(t)----------(b)----------+ + * + * +-- (sync point) + * [1] +-O | + * [2] +---O | + * [3] +------O + * [4] +-----O| + * [5] +------O + * + * syncbackup + * + * 1) Waits for the number of synchronized backups to become bigger than + * the specified value (default 1). + * + * 1-1) For backup servers whose latency is 1 and which has already sent + * a message, check whether its message result is completed. + * - If true, increment its age. + * + * 1-2) call follow thread and sleep until follow thread wakes myself + * (follow_thread should make unsynchronized backups follow) + * + * + * 2) For synchronized backup servers, propagates an operation + * asynchronously. + * + * 3) Waits for the specified number ( default 1 ) of results. + * + * 4) Registers the operation to queue. + * + * 5) Increments the server's age. + * + * follow_thread_t + * + * follow thread is a thread such as + * + * 1) to make unsynchorinized backups follow. + * 2) to make not-bound backups bind. + * + */ + + #define WAITLIMIT 30 + + /* Prototypes */ + + /* follow thread */ + static ldap_pvt_thread_start_t follow; + struct runqueue_s health_rq; + + /* backup history management */ + static event_t *alloc_event( syncbackupinfo_t *info); + static int history_backup_latency( BackendDB *be, int id ); + static int history_push_event( BackendDB *be, int id, event_t *ev ); + static int history_pop_event( BackendDB *be, event_t **ev ); + static int history_process_event( syncbackup_t *b, event_t *ev ); + static void history_gc( BackendDB *be, int max, int min ); + static int consider_history_gc( syncbackupinfo_t *info); + + /* backup management */ + static int cookiecmp( struct berval *c1, struct berval *c2 ); + static int backup_init( syncbackup_t *b ); + static int backup_bind( syncbackup_t *b ); + static int backup_result( BackendDB *be, int id, int *waittime, int errorstat ); + static int backup_recovery( BackendDB *be, int id, int err ); + static int backup_close( syncbackup_t *b ); + static int backup_call_cb( syncbackupinfo_t *info, int id, int rc, char *err, int severity ); + static int is_backup_op_avail( syncbackupinfo_t *info, int id ); + static int is_backup_avail( syncbackupinfo_t *info, int id ); + static int is_sync_backup( syncbackupinfo_t *info, int id ); + + /* propagation management/operation */ + static int join_syncbackup(Operation *op, SlapReply *rs, int num_backups); + static int wait_sync_result(Operation *op, SlapReply *rs, int num_backups, event_t *ev); + static void build_event(event_t *ev, int ev_tag, Entry *entry, char *csn, int connid, int opid, LDAPControl **ctrls, void *ev_u); + static void event_free( event_t *ev ); + static int build_backup_ctrls(LDAPControl ***ctrlsp, Operation *op); + static void backup_ctrls_free(LDAPControl **ctrls); + static addmod_t *build_add_event_u( Operation *op, LDAPMod **mods ); + static rename_t *build_rename_event_u( Operation *op ); + static extended_t *build_extended_event_u( Operation *op ); + static void build_addmod_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls, int ev_tag, LDAPMod **mods); + static void build_add_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls, LDAPMod **mods); + static void build_modify_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls, LDAPMod **mods); + static void build_delete_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls); + static void build_rename_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls); + static void build_extended_event(event_t *ev, Entry *entry, Operation *op, LDAPControl **ctrls); + + /* general functions */ + int slap_entry2ldapmods(Entry *e, LDAPMod ***mods); + int slap_mods2ldapmods(Modifications *modlist, LDAPMod ***mods); + void slap_print_ldapmods(LDAPMod **mods); + void slap_ldapmods_free(LDAPMod **mods); + + /* bootsync */ + static int replica2syncinfo(Ri *ri, syncinfo_t *si); + + /* Static variables */ + + static LDAP_STAILQ_HEAD(s_fe, event_s) free_events; + static ldap_pvt_thread_mutex_t free_events_mutex; + + /** + * Initializes syncbackup engine. + * + */ + void + init_syncbackup() + { + LDAP_STAILQ_INIT( &free_events ); + ldap_pvt_thread_mutex_init( &free_events_mutex ); + } + + /** + * Creates a new syncbackup information. + * + * @return new syncbackupinfo_t + */ + syncbackupinfo_t * + syncbackupinfo_new( BackendDB *be ) + { + syncbackupinfo_t *info; + + info = (syncbackupinfo_t *)ch_malloc(sizeof(syncbackupinfo_t)); + info->sbi_init_cookie = NULL; + info->sbi_num_atleast_result = 1; + info->sbi_num_max_backups= 0; + info->sbi_num_backups= 0; + ldap_pvt_thread_mutex_init( &info->sbi_num_backups_mutex ); + + ldap_pvt_thread_cond_init(&info->sbi_backup_avail_cv); + ldap_pvt_thread_mutex_init(&info->sbi_backup_avail_mutex); + + SYNCBACKUP_EVENT_INIT ( &info->sbi_history ); + info->sbi_bd = be; + + info->sbi_num_sync_backups = 0; + ldap_pvt_thread_mutex_init( &info->sbi_num_sync_backups_mutex ); + ldap_pvt_thread_mutex_init( &info->sbi_syncbackup_mutex ); + info->sbi_backups = NULL; + + info->sbi_history.bottom = 0; + info->sbi_history.top = 0; + + ldap_pvt_thread_pool_init( &info->sbi_follow_pool, 1, 0 ); + ldap_pvt_thread_mutex_init( &info->sbi_follow_mutex ); + + be->be_syncbackupinfo = info; + + + history_push_event( be, -1, alloc_event( info ) ); + + return info; + } + + /** + * Destroys the specified syncbackup information. + * + * @param info syncbackup information to be destroyed. + */ + void + syncbackupinfo_destroy(syncbackupinfo_t *info) + { + ldap_pvt_thread_mutex_destroy ( &info->sbi_syncbackup_mutex ); + ldap_pvt_thread_mutex_destroy ( &info->sbi_num_sync_backups_mutex ); + ldap_pvt_thread_mutex_destroy ( &info->sbi_backup_avail_mutex ); + ldap_pvt_thread_cond_destroy ( &info->sbi_backup_avail_cv ); + + ldap_pvt_thread_mutex_destroy( &info->sbi_num_backups_mutex ); + ldap_pvt_thread_pool_destroy( &info->sbi_follow_pool, 1 ); + ldap_pvt_thread_mutex_destroy( &info->sbi_follow_mutex ); + + ch_free ( info->sbi_backups ); + ch_free ( info ); + } + + /** + * Creates a new backup server from the specified replica information. + * + * @param replica information + * @return new backup server + */ + syncbackup_t * + syncbackup_new( Ri *ri ) + { + syncbackup_t *bak; + + bak = (syncbackup_t *)ch_malloc(sizeof(syncbackup_t)); + memset ( bak, 0, sizeof(syncbackup_t) ); + + ldap_pvt_thread_mutex_init( &bak->sb_join_mutex ); + bak->sb_syncid = ri->ri_syncid; + bak->sb_ri = ri; + bak->sb_state = SYNCBACKUP_STATE_NONE; + + return bak; + } + + /** + * Destorys the specified backup server. + * + * @param bak backup server to be destroyed + */ + void + syncbackup_destroy( syncbackup_t *bak ) + { + ldap_pvt_thread_mutex_destroy( &bak->sb_join_mutex ); + ch_free( bak ); + } + + /** + * Abandons the syncbackup which is started by the specified operation. + * + * @param op operation to be abandoned + * @param rs reply information + * @return LDAP_SUCCESS if the backup is successfully abandoned + * @return LDAP_UNAVAILABLE if no backup is found for the specified operation + */ + int + syncbackup_abandon(Operation *op, SlapReply *rs) + { + int i; + syncbackupinfo_t *info = op->o_bd->be_syncbackupinfo; + + if ( info == NULL ) + return LDAP_UNAVAILABLE; + + for( i=0; i < info->sbi_num_max_backups; i++ ) { + if ( is_backup_avail( info, i ) && + info->sbi_backups[i]->sb_op->o_msgid == op->o_msgid ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup_abandon: id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "syncbackup_abandon: id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + detach_backup( op->o_bd, i); + return LDAP_SUCCESS; + } + } + + return LDAP_UNAVAILABLE; + } + + /** + * Detaches the specified backup server. + * + * @param be backend db + * @param id id number of the backup to be detached + * @return 0 + */ + int + detach_backup( + BackendDB *be, + int id + ) + { + + syncbackupinfo_t *info = be->be_syncbackupinfo; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "detach_backup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>detach_backup\n", 0, 0, 0); + #endif + + ldap_pvt_thread_mutex_lock(&info->sbi_num_sync_backups_mutex); + if ( is_sync_backup( info, id ) ) { + info->sbi_num_sync_backups--; + } + info->sbi_backups[id]->sb_age = NULL; + ldap_pvt_thread_mutex_unlock(&info->sbi_num_sync_backups_mutex); + + backup_close ( info->sbi_backups[id] ); + + ldap_pvt_thread_mutex_lock(&info->sbi_num_backups_mutex); + info->sbi_num_backups--; + ldap_pvt_thread_mutex_unlock(&info->sbi_num_backups_mutex); + + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu DETACH id=%s\n", + info->sbi_backups[id]->sb_connid, + info->sbi_backups[id]->sb_opid, + info->sbi_backups[id]->sb_syncid, 0, 0 ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "detached: %s\n", info->sbi_backups[id]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "detached: %s\n", info->sbi_backups[id]->sb_syncid, 0, 0); + #endif + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "detach_backup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=detach_backup\n", 0, 0, 0); + #endif + + return 0; + } + + /** + * Returns the id number of the specified syncid. + * + * @param be backend db + * @param syncid syncid of the backup + * @return id number of the specified syncid + * @return -1 if no such backup server, which has the specified syncid, found + */ + int + syncbackup_get_id( + BackendDB *be, + char *syncid + ) + { + int i; + syncbackupinfo_t *info = be->be_syncbackupinfo; + + for( i=0; i < info->sbi_num_max_backups; i++ ) { + if ( !strcmp( syncid, info->sbi_backups[i]->sb_syncid ) ) { + return i; + } + } + + return -1; + } + + /** + * Attaches the specified backup server at the designated location + * of the specified csn with the specified operation. The specified + * operation is used to manage the backup server to be attached. For + * example, when the backup server fail, its reason will be sent to the + * operation as its response. When these events are happened, the specified + * callback function will be invoked. In addition, the sync management + * connection may send an abandon operation for the operation in order to + * abandon the syncbackup to the backup server. + * + * @param be backend db + * @param id id number of the backup to be attached + * @param csn ChangeSequenseNumber which the backup will be attached + * @param op operation which attaces the backup + * @param cb callback function to be called when an event of the + * backup is happened. + * + * @return LDAP_SUCCESS if the backup is successfully attached + * @return SLAPD_ATTACH_BADCOOKIE if the backup sends a csn though + * the master doesn't have any csn, or if the backup sends + * a future csn than the latest csn which the master manages. + * @return SLAPD_ATTACH_ALREADY if the specified backup has been already + * attached. + * @return SLAPD_ATTACH_NOCOOKIE if the backup sends a csn which the + * master has abandoned. + */ + int + attach_backup( + BackendDB *be, + int id, + char *csn, + Operation *op, + syncbackup_backup_event_func *cb + ) + { + int rc; + event_t *bottom, *top, *age; + char *retoid = NULL; + syncbackupinfo_t *info = be->be_syncbackupinfo; + struct berval csn_bv = { (csn)?strlen(csn):0, csn } ; + struct berval csnq_bv = { 0, NULL }; + char *csnq; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>attach_backup\n", 0, 0, 0); + #endif + + if( info->sbi_backups[id]->sb_age != NULL ) { + rc = healthcheck( info->sbi_backups[id]->sb_ld ); + if ( rc == LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, + "attach_backup: backup[%d] already attached: %d.\n", + id, info->sbi_backups[id]->sb_age, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + " attach_backup: backup[%d] already attached: %d.\n", + id, info->sbi_backups[id]->sb_age, 0); + #endif + return SLAPD_ATTACH_ALREADY; + } + + backup_call_cb( info, id, rc, "health-check error", SYNC_SERVER_FAILURE ); + detach_backup( be, id ); + } + + top = LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ); + bottom = LDAP_STAILQ_FIRST( &info->sbi_history.queue ); + + age = top; + + if ( csn == NULL ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: no cookie sent\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: no cookie sent\n", 0, 0, 0); + #endif + if ( info->sbi_init_cookie == NULL && LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next )->ev_id == 0) { + goto attach; + } + return SLAPD_ATTACH_BADCOOKIE; + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: csn=%s\n", csn, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: csn=%s\n", csn, 0, 0); + #endif + + if ( LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next )->ev_id == 0 ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: empty history\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: empty history\n", 0, 0, 0); + #endif + if( info->sbi_init_cookie == NULL ) { + return SLAPD_ATTACH_BADCOOKIE; + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: init cookie: %s\n", info->sbi_init_cookie->bv_val, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: init cookie: %s\n", info->sbi_init_cookie->bv_val, 0, 0); + #endif + + if ( cookiecmp( &csn_bv, info->sbi_init_cookie ) == 0 ) + { + goto attach; + } + + return SLAPD_ATTACH_NOCOOKIE; + } + + csnq = top->ev_csn; + if ( csnq != NULL ) { + ber_str2bv( csnq, strlen( csnq ), 0, &csnq_bv ); + if ( cookiecmp(&csnq_bv, &csn_bv) < 0 ) + return SLAPD_ATTACH_BADCOOKIE; + } + + while( top != bottom ) { + csnq = bottom->ev_csn; + if( csnq != NULL) { + ber_str2bv( csnq, strlen( csnq ), 0, &csnq_bv ); + if( cookiecmp(&csn_bv, &csnq_bv) == 0) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: match: bottom: %d, top: %d\n", bottom, top, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: match: bottom: %d, top: %d\n", bottom, top, 0); + #endif + age = bottom; + if( LDAP_STAILQ_NEXT( bottom, ev_next )->ev_csn == NULL) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: NULL csn found\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: NULL csn found\n", 0, 0, 0); + #endif + return SLAPD_ATTACH_NOCOOKIE; + } + + goto attach; + + } + } + bottom = LDAP_STAILQ_NEXT( bottom, ev_next ); + } + csnq = bottom->ev_csn; + + if( csnq != NULL ) { + ber_str2bv( csnq, strlen( csnq ), 0, &csnq_bv ); + if( cookiecmp(&csn_bv, &csnq_bv) == 0) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach_backup: match: bottom: %d, top: %d\n", bottom, top, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: match: bottom: %d, top: %d\n", bottom, top, 0); + #endif + age = bottom; + goto attach; + } + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "attach_backup: no such cookie from id=%s: %s\n", info->sbi_backups[id]->sb_syncid, csn, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach_backup: no such cookie from id=%s: %s\n", info->sbi_backups[id]->sb_syncid, csn, 0); + #endif + + return SLAPD_ATTACH_NOCOOKIE; + + attach: + + if ( backup_init ( info->sbi_backups[id] ) < 0 ) { + return -1; + } + + info->sbi_backups[id]->sb_age = age; + info->sbi_backups[id]->sb_op = op; + info->sbi_backups[id]->sb_opid = op->o_opid; + info->sbi_backups[id]->sb_connid = op->o_conn->c_connid; + info->sbi_backups[id]->sb_cb = cb; + ldap_pvt_thread_mutex_lock(&info->sbi_num_backups_mutex); + info->sbi_num_backups++; + ldap_pvt_thread_mutex_unlock( &info->sbi_num_backups_mutex ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "attach %s success\n", info->sbi_bacups[id]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "attach %s success\n", info->sbi_backups[id]->sb_syncid, 0, 0); + #endif + + #ifndef NO_THREADS + ldap_pvt_thread_mutex_lock( &info->sbi_follow_mutex ); + if ( ldap_pvt_thread_pool_backload( &info->sbi_follow_pool ) == 0 ) + ldap_pvt_thread_pool_submit( &info->sbi_follow_pool, follow, be ); + ldap_pvt_thread_mutex_unlock( &info->sbi_follow_mutex ); + #endif + + return LDAP_SUCCESS; + + } + + /** + * Propagates an operation to backups which is up-to-date and returns + * whether the operation is successfully backed up or not. + * + * @param op reference to operation + * @param rs reference to slap_reply + * @param entry reference to Entry + * @return LDAP_SUCCESS if propagation success + * @return LDAP_XXX otherwise + */ + int + syncbackup( + Operation *op, + SlapReply *rs, + Entry *entry + ) + { + struct slap_csn_entry *csne = NULL; + int i, rc, num_rc = 0; + LDAPMod **mods; + BackendDB *be = op->o_bd; + syncbackupinfo_t *info = be->be_syncbackupinfo; + event_t *ev; + LDAPControl **ctrls; + int *msgidp; + int atleast; + + if( info == NULL || op->o_backup == 0 ) { + return LDAP_SUCCESS; + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>syncbackup\n", 0, 0, 0); + #endif + + i = 0; + while( SYNCBACKUP_EVENT_FULL( &info->sbi_history.queue )) { + ldap_pvt_thread_sleep( ++i ); + if ( op->o_time + WAITLIMIT < slap_get_time() ) { + rs->sr_text = "too busy to make backup servers follow"; + return LDAP_BUSY; + } + } + + atleast = 0; + for ( i = 0; i < info->sbi_num_max_backups; i++ ) { + if ( info->sbi_backups[i]->sb_age == NULL ) continue; + if ( history_backup_latency( be, i ) > EVENTS_THRESHOLD ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup: id=%s delayed: %d\n", info->sbi_backups[i]->sb_syncid, history_backup_latency( be, i ), 0); + #else + Debug ( LDAP_DEBUG_TRACE, "syncbackup: id=%s delayed: %d\n", info->sbi_backups[i]->sb_syncid, history_backup_latency( be, i ), 0); + #endif + } else { + atleast++; + } + if ( atleast == info->sbi_num_atleast_result) break; + } + + if ( atleast < info->sbi_num_atleast_result ) { + if ( be->be_weaksync ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup: weaksync\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "syncbackup: weaksync\n", 0, 0, 0); + #endif + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "syncbackup: not enough backup servers registered\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "syncbackup: not enough backup servers registered\n", 0, 0, 0); + #endif + rs->sr_text = "not enough backup servers registered"; + return LDAP_BUSY; + } + } + + if (( rc = join_syncbackup(op, rs, atleast) ) != LDAP_SUCCESS ) { + return rc; + } + + assert( info->sbi_num_sync_backups >= atleast ); + + /* create contextCSN control */ + if ( build_backup_ctrls(&ctrls, op) < 0 ) { + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + ev = alloc_event( info ); + + /* create propagation event */ + switch ( op->o_tag ) { + case LDAP_REQ_ADD: + slap_entry2ldapmods(op->ora_e, &mods); + slap_print_ldapmods(mods); + build_add_event ( ev, entry, op, ctrls, mods ); + break; + + case LDAP_REQ_MODIFY: + slap_mods2ldapmods(op->orm_modlist, &mods); + slap_print_ldapmods(mods); + build_modify_event ( ev, entry, op, ctrls, mods ); + break; + + case LDAP_REQ_DELETE: + build_delete_event( ev, entry, op, ctrls ); + break; + + case LDAP_REQ_MODRDN: + build_rename_event ( ev, entry, op, ctrls ); + break; + + case LDAP_REQ_EXTENDED: + build_extended_event ( ev, entry, op, ctrls ); + break; + + default: + assert( 0 ); + } + + /* propagates the event */ + for(i=0; isbi_num_max_backups; i++) { + + if( !is_sync_backup( info, i ) ) { + continue; + } + + msgidp = &info->sbi_backups[i]->sb_msgid; + + rc = history_process_event( info->sbi_backups[i], ev ); + if ( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "syncbackup: propagation failed. id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "syncbackup: propagation failed. id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + backup_call_cb( info, i, rc, "propagation failed", SYNC_ERROR ); + detach_backup( be, i ); + continue; + } + + num_rc++; + + info->sbi_backups[i]->sb_time = slap_get_time(); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup: propagation done id=%s, msgid(%d) latest_time(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, 0 ); + #else + Debug ( LDAP_DEBUG_TRACE, "syncbackup: propagation done id=%s, msgid(%d) latest_time(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, info->sbi_backups[i]->sb_time ); + #endif + } + + /* if all propagation failed... */ + if ( atleast != 0 && num_rc == 0 ) { + switch( op->o_tag ) { + case LDAP_REQ_ADD: + case LDAP_REQ_MODIFY: + slap_ldapmods_free(mods); + break; + } + event_free( ev ); + rs->sr_text = "internal error"; + return LDAP_OTHER; + } + + /* wait for results */ + if (( rc = wait_sync_result(op, rs, atleast, ev)) != LDAP_SUCCESS ) { + event_free ( ev ); + return rc; + } + + #ifdef NO_THREADS + ldap_pvt_thread_mutex_lock( &info->sbi_follow_mutex ); + if ( ldap_pvt_thread_pool_backload( &info->sbi_follow_pool ) == 0 ) + ldap_pvt_thread_pool_submit( &info->sbi_follow_pool, follow, be ); + ldap_pvt_thread_mutex_unlock( &info->sbi_follow_mutex ); + #endif + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "syncbackup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=syncbackup\n", 0, 0, 0); + #endif + + return LDAP_SUCCESS; + } + + /* history management functions */ + + static int + history_process_event( + syncbackup_t *b, + event_t *ev + ) + { + int rc; + LDAP *ld = b->sb_ld; + int *msgidp = &b->sb_msgid; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "history_process_event\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>history_process_event\n", 0, 0, 0); + #endif + + switch(ev->ev_tag) { + case LDAP_REQ_ADD: + slap_print_ldapmods( ev->ev.addmod->mods ); + if((rc = ldap_add_ext(ld, ev->ev.addmod->entrydn, ev->ev.addmod->mods, ev->ev_ctrls, NULL, msgidp)) != LDAP_SUCCESS) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_add_ext: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_add_ext: %s\n", ldap_err2string( rc ), 0, 0); + #endif + } + break; + + case LDAP_REQ_MODIFY: + slap_print_ldapmods( ev->ev.addmod->mods); + if((rc = ldap_modify_ext(ld, ev->ev.addmod->entrydn, ev->ev.addmod->mods, ev->ev_ctrls, NULL, msgidp)) != LDAP_SUCCESS) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_modify_ext: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_modify_ext: %s\n", ldap_err2string( rc ), 0, 0); + #endif + } + break; + + case LDAP_REQ_DELETE: + if((rc = ldap_delete_ext(ld, ev->ev.deldn, ev->ev_ctrls, NULL, msgidp)) != LDAP_SUCCESS) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_delete_ext: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_delete_ext: %s\n", ldap_err2string( rc ), 0, 0); + #endif + } + break; + + case LDAP_REQ_MODRDN: + if((rc = ldap_rename(ld, ev->ev.rename->olddn, ev->ev.rename->newrdn, ev->ev.rename->newSup, ev->ev.rename->deleteoldrdn, ev->ev_ctrls, NULL, msgidp)) != LDAP_SUCCESS) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_rename: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_rename: %s\n", ldap_err2string( rc ), 0, 0); + #endif + } + break; + + case LDAP_REQ_EXTENDED: + if(( rc = ldap_extended_operation(ld, ev->ev.ex->reqoid, ev->ev.ex->reqdata, ev->ev_ctrls, NULL, msgidp)) != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_extended_operation: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_extended_operation: %s\n", ldap_err2string( rc ), 0, 0); + #endif + } + break; + + default: + assert( 0 ); + } + + return rc; + } + + static int + backup_result( + BackendDB *be, + int id, + int *waittime, + int errorstat + ) + { + + int rc, err; + event_t *age; + char *errstr = NULL; + struct timeval tv; + LDAPMessage *res = NULL; + + long otime; + syncbackupinfo_t *info = be->be_syncbackupinfo; + LDAP *ld = info->sbi_backups[id]->sb_ld; + int msgid = info->sbi_backups[id]->sb_msgid; + + tv.tv_sec = (*waittime) / 1000000; + tv.tv_usec = (*waittime) % 1000000; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_result\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>backup_result\n", 0, 0, 0); + #endif + + rc = ldap_result(ld, msgid, 0, &tv, &res); + otime = info->sbi_backups[id]->sb_time; + + if ( rc < 0 ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "ldap_result: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "ldap_result: %s\n", ldap_err2string( rc ), 0, 0); + #endif + backup_call_cb ( info, id, rc, "result failed", errorstat ); + detach_backup( be, id ); + + goto done; + + } else if ( rc == 0 ){ + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_result: ldap_result timeout id=%s, start(%ld), now(%ld)\n", info->sbi_backups[id]->sb_syncid, time, slap_get_time()); + #else + Debug ( LDAP_DEBUG_TRACE, "backup_result: ldap_result timeout id=%s, start(%ld), now(%ld)\n", info->sbi_backups[id]->sb_syncid, otime, slap_get_time()); + #endif + if ( (*waittime) < 1000000 ) { + (*waittime) *= 3; + (*waittime)++; + } + + goto done; + + } else { + rc = ldap_parse_result(ld, res, &err, NULL, &errstr, NULL, NULL, 0); + if ( rc ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup_result: ldap_parse_result failed (%d)\n", rc, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "backup_result: ldap_parse_result failed (%d)\n", rc, 0, 0); + #endif + backup_call_cb( info, id, rc, "internal error", errorstat ); + detach_backup( be, id ); + rc = -1; + + goto done; + } + + if( err == LDAP_SUCCESS ) { + (*waittime) /= 2; + + info->sbi_backups[id]->sb_msgid = 0; + + if ( info->sbi_backups[id]->sb_age != LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ) ) { + /* increment age if it's not in sync */ + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_result: increment age id=%s ev=%d latency=%d\n", info->sbi_backups[id]->sb_syncid, info->sbi_backups[id]->sb_age->ev_id, history_backup_latency( be, id ) ); + #else + Debug ( LDAP_DEBUG_TRACE, "backup_result: increment age id=%s ev=%d latency=%d\n", info->sbi_backups[id]->sb_syncid, info->sbi_backups[id]->sb_age->ev_id, history_backup_latency(be, id) ); + #endif + + info->sbi_backups[id]->sb_age = LDAP_STAILQ_NEXT( info->sbi_backups[id]->sb_age, ev_next ); + age = info->sbi_backups[id]->sb_age; + + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu BACKUP latency=%d backup=\"%s\"\n", age->ev_connid, age->ev_opid, history_backup_latency( be, id ), info->sbi_backups[id]->sb_syncid, 0 ); + + if ( age == LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next )) { + ldap_pvt_thread_mutex_lock(&info->sbi_num_sync_backups_mutex); + info->sbi_num_sync_backups++; + ldap_pvt_thread_mutex_unlock(&info->sbi_num_sync_backups_mutex); + ldap_pvt_thread_mutex_lock(&info->sbi_backup_avail_mutex); + ldap_pvt_thread_cond_signal( &info->sbi_backup_avail_cv ); + ldap_pvt_thread_mutex_unlock(&info->sbi_backup_avail_mutex); + } + + } + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_result: err from id=%s \"%s, %s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(err), errstr ); + #else + Debug ( LDAP_DEBUG_TRACE, "backup_result: err from id=%s \"%s, %s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(err), errstr ); + #endif + if( backup_recovery( be, id, err ) != LDAP_SUCCESS ) { + backup_call_cb( info, id, err, errstr, SYNC_ERROR ); + detach_backup( be, id ); + rc = 2; + } else { + rc = 0; + } + + goto done; + + } + } + + rc = 1; + done: + if ( res ) ldap_msgfree( res ); + + if ( errstr != NULL ) + ldap_memfree( errstr ); + + return rc; + } + + static int + backup_recovery( + BackendDB *be, + int id, + int err + ) + { + int rc = err; + syncbackupinfo_t *info = be->be_syncbackupinfo; + LDAPMod **mods; + event_t *ev = LDAP_STAILQ_NEXT( info->sbi_backups[id]->sb_age, ev_next ); + event_t ev_next; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_recovery\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>backup_recovery\n", 0, 0, 0); + #endif + + switch( err ) { + + case LDAP_NO_SUCH_OBJECT: + slap_entry2ldapmods( ev->ev_entry, &mods); + rc = ldap_add_ext_s(info->sbi_backups[id]->sb_ld, ev->ev_entry->e_nname.bv_val, mods, ev->ev_ctrls, NULL); + slap_ldapmods_free ( mods ); + if( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup recovery failed: id=%s \"%s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(rc), 0 ); + #else + Debug ( LDAP_DEBUG_ANY, "backup_recovery failed: id=%s \"%s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(rc), 0 ); + #endif + goto done; + } + + break; + + default: + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "unknown recovery situation: id=%s \"%s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(rc), 0 ); + #else + Debug ( LDAP_DEBUG_ANY, "unknown recovery situation: id=%s \"%s\"\n", info->sbi_backups[id]->sb_syncid, ldap_err2string(err), 0 ); + #endif + goto done; + } + + recovery: + + Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu RECOVERY latency=%d backup=\"%s\"\n", ev->ev_connid, ev->ev_opid, history_backup_latency( be, id ), info->sbi_backups[id]->sb_syncid, 0 ); + + retry: + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup retry: id=%s\n", info->sbi_backups[id]->sb_syncid, 0, 0 ); + #else + Debug ( LDAP_DEBUG_TRACE, "backup_retry: id=%s\n", info->sbi_backups[id]->sb_syncid, 0, 0 ); + #endif + info->sbi_backups[id]->sb_msgid = -1; + + done: + + return rc; + } + + static int + consider_history_gc( + syncbackupinfo_t *info + ) + { + int num_gc; + event_t *ev; + + if ( ( num_gc = SYNCBACKUP_EVENT_SIZE( &info->sbi_history.queue ) ) > 1 ) { + + if ( info->sbi_num_max_backups== info->sbi_num_backups) { + return 1; + } + + LDAP_STAILQ_FOREACH( ev, &info->sbi_history.queue, ev_next ) { + if ( ev->ev_time < slap_get_time() - ( EVENTS_HOLDTIME )) { + num_gc--; + } else { + return num_gc; + } + + } + + } + + return 1; + } + + static void * + follow(void *ctx, void *arg_v) + { + int i, latency, f, rc, num_gc; + event_t *age; + long otime, stime, stime1; + static int waittime = 30; + BackendDB *be = arg_v; + syncbackupinfo_t *info = be->be_syncbackupinfo; + Operation *op; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>follow\n", 0, 0, 0); + #endif + + stime = slap_get_time(); + + do { + f = 0; + for(i=0; isbi_num_max_backups; i++) { + if( info->sbi_backups[i]->sb_age != NULL ) { + if(info->sbi_backups[i]->sb_state == SYNCBACKUP_STATE_CONNECT) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: binding (%d)\n", i, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: binding (%d)\n", i, 0, 0 ); + #endif + if(( rc = backup_bind(info->sbi_backups[i])) == LDAP_SUCCESS ) { + info->sbi_backups[i]->sb_state = SYNCBACKUP_STATE_BIND; + if ( is_sync_backup ( info, i )) { + ldap_pvt_thread_mutex_lock(&info->sbi_num_sync_backups_mutex); + info->sbi_num_sync_backups++; + ldap_pvt_thread_mutex_unlock(&info->sbi_num_sync_backups_mutex); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: sync id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: sync id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + ldap_pvt_thread_mutex_lock(&info->sbi_backup_avail_mutex); + ldap_pvt_thread_cond_signal( &info->sbi_backup_avail_cv ); + ldap_pvt_thread_mutex_unlock(&info->sbi_backup_avail_mutex); + } + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: id=%s bounded\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: id=%s is succesfully bound\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + op = info->sbi_backups[i]->sb_op; + Statslog( LDAP_DEBUG_STATS, + "conn=%lu op=%lu BACKUP BIND backup=\"%s\" latency=%d\n", + op->o_conn->c_connid, op->o_opid, + info->sbi_backups[i]->sb_syncid, + history_backup_latency( be, i), + 0 ); + } else { + backup_call_cb ( info, i, rc, "bind error", SYNC_ERROR ); + detach_backup( be, i ); + continue; + } + } + + latency = history_backup_latency(be, i); + if( latency > 0 ) { + ldap_pvt_thread_mutex_lock(&info->sbi_backups[i]->sb_join_mutex); + age = info->sbi_backups[i]->sb_age; + if( info->sbi_backups[i]->sb_msgid > 0 ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: retrieving previous operation of id=%s, msgid(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: retrieving previous operation of id=%s, msgid(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, 0); + #endif + rc = backup_result( be, i, &waittime, SYNC_SERVER_FAILURE ) ; + if ( rc > 0 ) { + f++; + } else if ( rc == 0 ) { + f++; + otime = info->sbi_backups[i]->sb_time; + if ( otime < slap_get_time() - WAITLIMIT ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "follow: id=%s: following timeout\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "follow: id=%s: following timeout\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + backup_call_cb ( info, i, LDAP_BUSY, "following timeout", SYNC_STATUS_NONE ); + detach_backup( be, i ); + } + } else { + if ( latency == 1 ) { + info->sbi_backups[i]->sb_criterr = 1; + } + } + + } else { + event_t *ev; + ev = LDAP_STAILQ_NEXT( age, ev_next ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: following id=%s, (latency: %d), (ev: %d)\n", info->sbi_backups[i]->sb_syncid, latency, ev->ev_id ); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: following id=%s, (latency: %d), (ev: %d)\n", info->sbi_backups[i]->sb_syncid, latency, ev->ev_id); + #endif + if(( rc = history_process_event( info->sbi_backups[i], ev )) != LDAP_SUCCESS ) + { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "follow: processing error of id=%s,\n", info->sbi_backups[i]->sb_syncid, 0, 0 ); + #else + Debug ( LDAP_DEBUG_ANY, "follow: processing error of id=%s,\n", info->sbi_backups[i]->sb_syncid, 0, 0 ); + #endif + backup_call_cb ( info, i, rc, "following error", SYNC_SERVER_FAILURE ); + detach_backup( be, i ); + } else { + info->sbi_backups[i]->sb_time = slap_get_time(); + f++; + } + } + ldap_pvt_thread_mutex_unlock(&info->sbi_backups[i]->sb_join_mutex); + } + } + } + + stime1 = slap_get_time(); + if ( stime != stime1 ) { + ldap_pvt_thread_mutex_lock(&info->sbi_backup_avail_mutex); + ldap_pvt_thread_cond_signal( &info->sbi_backup_avail_cv ); + ldap_pvt_thread_mutex_unlock(&info->sbi_backup_avail_mutex); + stime = stime1; + } + + } while(f > 0 && ! slapd_shutdown ); + + #ifndef NO_THREADS + ldap_pvt_thread_mutex_lock(&info->sbi_backup_avail_mutex); + ldap_pvt_thread_cond_signal( &info->sbi_backup_avail_cv ); + ldap_pvt_thread_mutex_unlock(&info->sbi_backup_avail_mutex); + #endif + + num_gc = consider_history_gc( info ); + + if ( num_gc > 0 ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: cleaning events\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: cleaning events\n", 0, 0, 0); + #endif + history_gc ( be, 1, num_gc ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow: %d events left\n", SYNCBACKUP_EVENT_SIZE( &info->sbi_history.queue ), 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "follow: %d events left\n", SYNCBACKUP_EVENT_SIZE( &info->sbi_history.queue ), 0, 0); + #endif + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "follow\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=follow\n", 0, 0, 0); + #endif + + return NULL; + } + + + /* caller must lock this function. */ + static void + history_gc(BackendDB *be, int max, int min) + { + syncbackupinfo_t *info = be->be_syncbackupinfo; + int size = SYNCBACKUP_EVENT_SIZE( &info->sbi_history.queue ); + int i, l; + event_t *ev; + + if ( size > max ) { + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "history_gc\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>history_gc\n", 0, 0, 0); + #endif + + for ( i = 0; i < info->sbi_num_max_backups; i++ ) { + if ( info->sbi_backups[i]->sb_age == NULL ) continue; + l = history_backup_latency( be, i ); + if ( l > min ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "history_gc: id=%s delayed: %d\n", info->sbi_backups[i]->sb_syncid, l, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "history_gc: id=%s delayed: %d\n", info->sbi_backups[i]->sb_syncid, l, 0); + #endif + min = l; + } + } + + for ( i = 0; i < size - min; i++ ) { + history_pop_event( be, &ev ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "history_gc: gc ev=%lu\n", ev->ev_id, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "history_gc: gc ev=%lu\n", ev->ev_id, 0, 0); + #endif + event_free ( ev ); + } + } + + } + + static int + history_backup_latency( + BackendDB *be, + int id + ) + { + syncbackupinfo_t *info = be->be_syncbackupinfo; + int latency; + + assert ( info->sbi_backups[id]->sb_age != NULL ); + + ldap_pvt_thread_mutex_lock(&info->sbi_num_sync_backups_mutex); + latency = SYNCBACKUP_EVENT_LATENCY( &info->sbi_history.queue, info->sbi_backups[id]->sb_age->ev_id ); + ldap_pvt_thread_mutex_unlock(&info->sbi_num_sync_backups_mutex); + + return latency; + } + + static event_t * + alloc_event( + syncbackupinfo_t *info + ) + { + event_t *ev; + + ldap_pvt_thread_mutex_lock( &free_events_mutex ); + if ( LDAP_STAILQ_EMPTY( &free_events ) ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "alloc_event: allocating memory\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "alloc_event: allocating memory\n", 0, 0, 0); + #endif + ev = (event_t *)ch_malloc(sizeof(event_t)); + memset( ev, 0, sizeof( event_t )); + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "alloc_event: reuse allocated memory\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "alloc_event: reuse allocated memory\n", 0, 0, 0); + #endif + ev = LDAP_STAILQ_FIRST( &free_events ); + LDAP_STAILQ_REMOVE_HEAD( &free_events, ev_next ); + } + ldap_pvt_thread_mutex_unlock( &free_events_mutex ); + + return ev; + } + + static void + build_event( + event_t *ev, + int ev_tag, + Entry *entry, + char *csn, + int connid, + int opid, + LDAPControl **ctrls, + void *ev_u + ) + { + + ev->ev_tag = ev_tag; + ev->ev_csn = ch_strdup( csn ); + + switch(ev_tag) { + case LDAP_REQ_ADD: + case LDAP_REQ_MODIFY: + ev->ev.addmod = (addmod_t *)ev_u; + break; + + case LDAP_REQ_DELETE: + ev->ev.deldn = ch_strdup((char *)ev_u); + + break; + + case LDAP_REQ_MODRDN: + ev->ev.rename = (rename_t *)ev_u; + break; + + case LDAP_REQ_EXTENDED: + ev->ev.ex = (extended_t *)ev_u; + break; + + default: + assert( 0 ); + + } + + ev->ev_ctrls = ctrls; + ev->ev_connid = connid; + ev->ev_opid = opid; + ev->ev_time = slap_get_time(); + if( entry ) + ev->ev_entry = entry_dup( entry ); + } + + static void + event_free(event_t *ev) + { + if ( ev->ev_csn != NULL ) { + free ( ev->ev_csn ); + } + + if ( ev->ev_entry != NULL ) { + entry_free( ev->ev_entry ); + } + + switch(ev->ev_tag) { + case LDAP_REQ_ADD: + case LDAP_REQ_MODIFY: + ch_free ( ev->ev.addmod->entrydn ); + slap_ldapmods_free ( ev->ev.addmod->mods ); + ch_free( ev->ev.addmod ); + break; + + case LDAP_REQ_DELETE: + ch_free ( ev->ev.deldn ); + break; + + case LDAP_REQ_MODRDN: + ch_free ( ev->ev.rename->olddn ); + ch_free ( ev->ev.rename->newrdn ); + if ( ev->ev.rename->newSup ) ch_free ( ev->ev.rename->newSup ); + ch_free ( ev->ev.rename ); + break; + + case LDAP_REQ_EXTENDED: + ch_free ( ev->ev.ex->reqoid ); + ber_bvfree( ev->ev.ex->reqdata ); + ch_free ( ev->ev.ex ); + break; + + case 0: + break; + + default: + assert( 0 ); + + } + + backup_ctrls_free( ev->ev_ctrls ); + memset( ev, 0, sizeof(event_t)); + + ldap_pvt_thread_mutex_lock( &free_events_mutex ); + LDAP_STAILQ_INSERT_HEAD( &free_events, ev, ev_next ); + ldap_pvt_thread_mutex_unlock( &free_events_mutex ); + } + + static int + history_push_event( + BackendDB *be, + int id, + event_t *ev + ) + { + syncbackupinfo_t *info = be->be_syncbackupinfo; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "history_push_event\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>history_push_event\n", 0, 0, 0); + #endif + + ldap_pvt_thread_mutex_lock(&info->sbi_num_sync_backups_mutex); + + ev->ev_id = info->sbi_history.top++; + LDAP_STAILQ_INSERT_TAIL ( &info->sbi_history.queue, ev, ev_next ); + + if ( id >= 0 ) { + info->sbi_backups[id]->sb_age = LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ); + info->sbi_num_sync_backups = 1; + } else { + info->sbi_num_sync_backups = 0; + } + + ldap_pvt_thread_mutex_unlock(&info->sbi_num_sync_backups_mutex); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "history_push_event: csn %s, ev_id:%d\n", (ev->ev_csn)?ev->ev_csn:"(null)", ev->ev_id, 0 ); + #else + Debug ( LDAP_DEBUG_TRACE, "history_push_event: csn %s, ev_id:%d\n", (ev->ev_csn)?ev->ev_csn:"(null)", ev->ev_id, 0 ); + #endif + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "history_push_event\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=history_push_event\n", 0, 0, 0); + #endif + + return 0; + } + + static int + history_pop_event( + BackendDB *be, + event_t **ev + ) + { + event_t *top, *bottom; + syncbackupinfo_t *info = be->be_syncbackupinfo; + + assert( !LDAP_STAILQ_EMPTY( &info->sbi_history.queue ) ); + + top = LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ); + bottom = LDAP_STAILQ_FIRST( &info->sbi_history.queue ); + + assert( bottom->ev_id == info->sbi_history.bottom ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL, "history_pop_event: b:%d, t:%d\n", bottom->ev_id , top->ev_id, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "history_pop_event: b:%d, t:%d\n", bottom->ev_id, top->ev_id, 0); + #endif + + (*ev) = bottom; + LDAP_STAILQ_REMOVE_HEAD( &info->sbi_history.queue, ev_next ); + info->sbi_history.bottom++; + + assert( !LDAP_STAILQ_EMPTY( &info->sbi_history.queue ) ); + + return 0; + } + + static int + cookiecmp(struct berval *c1, struct berval *c2) + { + int match; + const char *text; + + value_match( &match, slap_schema.si_ad_entryCSN, + slap_schema.si_ad_entryCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + c1, c2, &text); + + return match; + } + + static int + is_backup_avail( + syncbackupinfo_t *info, + int id + ) + { + if ( info->sbi_backups[id]->sb_state == SYNCBACKUP_STATE_BIND ) + { + return 1; + + } + + return 0; + } + + static int + is_backup_op_avail( + syncbackupinfo_t *info, + int id + ) + { + syncbackup_t *bak = info->sbi_backups[id]; + Operation *op = bak->sb_op; + Connection *c = op->o_conn; + + if ( op->o_opid == bak->sb_opid && + c->c_connid == bak->sb_connid ) + { + return 1; + } + + return 0; + + } + + static int + backup_init ( syncbackup_t *bak ) + { + + Ri *ri = bak->sb_ri; + static int protocol = LDAP_VERSION3; + + bak->sb_msgid = 0; + bak->sb_criterr = 0; + bak->sb_op = NULL; + bak->sb_syncid = ri->ri_syncid; + + if((bak->sb_ld=ldap_init(ri->ri_hostname, ri->ri_port)) == NULL) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "Could not initialize: id=%s err=%s\n", bak->sb_syncid, strerror(errno), 0); + #else + Debug ( LDAP_DEBUG_ANY, "Could not initialize: id=%s err=%s\n", bak->sb_syncid, strerror(errno), 0); + #endif + return -1; + } + + if((ldap_set_option(bak->sb_ld, LDAP_OPT_PROTOCOL_VERSION, &protocol)) + != LDAP_OPT_SUCCESS) + { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "Could not set protocol version\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "Could not set protocol version\n", 0, 0, 0); + #endif + return -1; + } + + bak->sb_state = SYNCBACKUP_STATE_CONNECT; + + return 0; + + } + + static int + backup_bind(syncbackup_t *bak) + { + int rc; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_bind\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>backup_bind\n", 0, 0, 0); + #endif + + assert( bak != NULL ); + assert( bak->sb_ri != NULL ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_bind: binding %s, %s\n", bak->sb_ri->ri_bind_dn, bak->sb_ri->ri_password, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "backup_bind: binding %s, %s\n", bak->sb_ri->ri_bind_dn, bak->sb_ri->ri_password, 0); + #endif + if( bak->sb_ri->ri_tls ) { + rc = ldap_start_tls_s( bak->sb_ld, NULL, NULL ); + if( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup_bind: " + "%s: ldap_start_tls failed (%d)\n", + bak->sb_ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning", + rc, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "%s: ldap_start_tls failed (%d)\n", + bak->sb_ri->ri_tls == TLS_CRITICAL ? "Error" : "Warning", + rc, 0 ); + #endif + if( bak->sb_ri->ri_tls == TLS_CRITICAL ) + return rc; + } + + } + + if ( bak->sb_ri->ri_bind_method == LDAP_AUTH_SASL ) { + #ifdef HAVE_CYRUS_SASL + void *defaults; + + if ( bak->sb_ri->ri_secprops != NULL ) { + rc = ldap_set_option( bak->sb_ld, + LDAP_OPT_X_SASL_SECPROPS, bak->sb_ri->ri_secprops); + + if( rc != LDAP_OPT_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup_bind: Error: " + "ldap_set_option(%s,SECPROPS,\"%s\") failed!\n", + bak->sb_syncid, bak->sb_ri->ri_secprops, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "Error: ldap_set_option " + "(%s,SECPROPS,\"%s\") failed!\n", + bak->sb_syncid, bak->sb_ri->ri_secprops, NULL ); + #endif + return rc; + + } + } + + defaults = lutil_sasl_defaults( bak->sb_ld, + bak->sb_ri->ri_saslmech, + bak->sb_ri->ri_realm, + bak->sb_ri->ri_authcId, + bak->sb_ri->ri_password, + bak->sb_ri->ri_authzId ); + + rc = ldap_sasl_interactive_bind_s( bak->sb_ld, + bak->sb_ri->ri_bind_dn, + bak->sb_ri->ri_saslmech, + NULL, NULL, + LDAP_SASL_QUIET, + lutil_sasl_interact, + defaults ); + + if ( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup_bind: " + "ldap_sasl_interactive_bind_s failed (%d)\n", + rc, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "backup_bind: " + "ldap_sasl_interactive_bind_s failed (%d)\n", + rc, 0, 0 ); + #endif + return rc; + } + #else + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "not compiled with SASL support\n", 0, 0, 0); + #else + Debug( LDAP_DEBUG_ANY, "not compiled with SASL support\n", 0, 0, 0); + #endif + return LDAP_OTHER; + #endif + } else { + if(( rc = ldap_simple_bind_s(bak->sb_ld, bak->sb_ri->ri_bind_dn, bak->sb_ri->ri_password)) != LDAP_SUCCESS) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "backup_bind: ldap_simple_bind: %s\n", ldap_err2string( rc ), 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "backup_bind: ldap_simple_bind: %s\n", ldap_err2string( rc ), 0, 0); + #endif + return rc; + } + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_bind\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=backup_bind\n", 0, 0, 0); + #endif + return 0; + } + + static int + backup_close ( syncbackup_t *bak ) + { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_close\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>backup_close\n", 0, 0, 0); + #endif + ldap_unbind ( bak->sb_ld ); + bak->sb_state = SYNCBACKUP_STATE_NONE; + bak->sb_op = NULL; + bak->sb_cb = NULL; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_close\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=backup_close\n", 0, 0, 0); + #endif + + return 0; + } + + static int + backup_call_cb( + syncbackupinfo_t *info, + int id, + int rc, + char *errstr, + int severity + ) + { + syncbackup_t *bak = info->sbi_backups[id]; + + if ( !is_backup_op_avail( info, id ) ) { + bak->sb_op->o_abandon = 1; + } + + if ( bak->sb_cb ) return (bak->sb_cb)(bak, rc, errstr, severity ); + else return 0; + + } + + static int + is_sync_backup( + syncbackupinfo_t *info, + int id + ) + { + event_t *s_ev; + + s_ev = LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ); + return ( s_ev == info->sbi_backups[id]->sb_age && info->sbi_backups[id]->sb_state == SYNCBACKUP_STATE_BIND ); + } + + + /* propagation management functions */ + + static int + wait_sync_result( + Operation *op, + SlapReply *rs, + int num_backups, + event_t *ev + ) + { + int num_rc = 0, i, rc, j, waittime; + BackendDB *be = op->o_bd; + syncbackupinfo_t *info = be->be_syncbackupinfo; + long tlimit = ev->ev_time + WAITLIMIT; + event_t *sync_point; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "wait_sync_result\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>wait_sync_result: dn: %s, id: %d, tlimit: %d\n", op->o_req_dn.bv_val, op->o_opid, tlimit); + #endif + + for(waittime=30; num_rc < num_backups; ) { + sync_point = LDAP_STAILQ_LAST( &info->sbi_history.queue, event_s, ev_next ); + for(i=0; isbi_num_max_backups; i++) { + + if( info->sbi_backups[i]->sb_state != SYNCBACKUP_STATE_BIND ) + continue; + + if( info->sbi_backups[i]->sb_age != sync_point ) + continue; + + ldap_pvt_thread_mutex_lock(&info->sbi_backups[i]->sb_join_mutex); + if ( info->sbi_backups[i]->sb_msgid > 0 ) + { + rc = backup_result( be, i, &waittime, SYNC_ERROR ); + if ( rc == 1 ) { + if ( num_rc == 0 ) { + history_push_event( be, i, ev ); + Statslog ( LDAP_DEBUG_STATS, "conn=%lu op=%lu BACKUP latency=%d backup=\"%s\"\n", ev->ev_connid, ev->ev_opid, history_backup_latency( be, i ), info->sbi_backups[i]->sb_syncid, 0 ); + } + + num_rc = info->sbi_num_sync_backups; + + } else if ( rc == -1 ) { + info->sbi_backups[i]->sb_criterr = 1; + } else if ( slap_get_time() >= tlimit ) { + backup_call_cb( info, i, LDAP_OTHER, "backup timeout", SYNC_ERROR ); + detach_backup( be, i ); + info->sbi_backups[i]->sb_criterr = 1; + } + + } else { + if(( rc = history_process_event(info->sbi_backups[i], ev )) != LDAP_SUCCESS ) { + backup_call_cb ( info, i, rc, "propagation error", SYNC_SERVER_FAILURE ); + detach_backup( be, i ); + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "wait_sync_result: processing late sync id=%s, msgid(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "wait_sync_result: processing late sync id=%s, msgid(%d)\n", info->sbi_backups[i]->sb_syncid, info->sbi_backups[i]->sb_msgid, 0); + #endif + info->sbi_backups[i]->sb_time = slap_get_time(); + } + + } + ldap_pvt_thread_mutex_unlock(&info->sbi_backups[i]->sb_join_mutex); + + } + + if( (info->sbi_num_backups== num_rc ) && + ( num_rc < num_backups ) ) + { + if ( !num_rc && ! be->be_weaksync ) { + j = 0; + i = 0; + for(; i < info->sbi_num_max_backups; i++ ) { + if ( ! info->sbi_backups[i]->sb_criterr ) + break; + + j = 1; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "unknown backup state: id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "unknown backup state: id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + } + + if ( j == 1 ) { + #ifdef SYNCBACKUP_STRICTCONSISTENCY + exit( EXIT_FAILURE ); + #else + rs->sr_text = "unknown backup state"; + return LDAP_OTHER; + } else { + rs->sr_text = "backup server error"; + return LDAP_BUSY; + #endif + } + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "can't fetch %d success results, num=%d\n", num_backups, num_rc, 0); + #else + Debug ( LDAP_DEBUG_ANY, "can't fetch %d success results, num=%d\n", num_backups, num_rc, 0); + #endif + rs->sr_text = "not enough backup servers available"; + break; + + } + + } + + if ( num_rc != info->sbi_num_backups|| + SYNCBACKUP_EVENT_SIZE( &info->sbi_history.queue ) > EVENTS_THRESHOLD ) { + ldap_pvt_thread_mutex_lock( &info->sbi_follow_mutex ); + if ( ldap_pvt_thread_pool_backload( &info->sbi_follow_pool ) == 0 ) + ldap_pvt_thread_pool_submit(&info->sbi_follow_pool, follow, be); + ldap_pvt_thread_mutex_unlock( &info->sbi_follow_mutex ); + } + + if( num_backups == 0 ) { + history_push_event(be, -1, ev); + Statslog ( LDAP_DEBUG_STATS, "conn=%lu op=%lu BACKUP DELAYED dn=\"%s\"\n", op->o_conn->c_connid, op->o_opid, op->o_req_dn.bv_val, 0, 0); + } + + return LDAP_SUCCESS; + } + + static int + join_syncbackup( + Operation *op, + SlapReply *rs, + int num_backups + ) + { + BackendDB *be = op->o_bd; + syncbackupinfo_t *info = be->be_syncbackupinfo; + int waittime, i, rc; + long tlimit = op->o_time + WAITLIMIT; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>join_syncbackup\n", 0, 0, 0); + #endif + + #ifdef NO_THREADS + if(info->sbi_num_backups== 0) { + ldap_pvt_thread_mutex_lock( &info->sbi_follow_mutex ); + if ( ldap_pvt_thread_pool_backload( &info->sbi_follow_pool ) == 0 ) + ldap_pvt_thread_pool_submit( &info->sbi_follow_pool, follow, be ); + ldap_pvt_thread_mutex_unlock( &info->sbi_follow_mutex ); + } + #endif + + waittime = 30; + do { + + #define SYNCBACKUP_JOIN_AS_FAST_AS_POSSIBLE 1 + #ifdef SYNCBACKUP_JOIN_AS_FAST_AS_POSSIBLE + if ( info->sbi_num_sync_backups >= num_backups ) { + break; + } + #endif + if(info->sbi_num_backups== 0) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup: no backup activated\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "join_syncbackup: no backup activated\n", 0, 0, 0); + #endif + rs->sr_text = "no backup activated"; + return LDAP_BUSY; + } + + for(i=0; isbi_num_max_backups; i++) { + if( info->sbi_backups[i]->sb_state == SYNCBACKUP_STATE_NONE ) { + continue; + } + + if ( ! is_backup_avail( info, i ) ) + continue; + + if ( history_backup_latency( be, i ) != 1) + continue; + + ldap_pvt_thread_mutex_lock(&info->sbi_backups[i]->sb_join_mutex); + if ( info->sbi_backups[i]->sb_msgid > 0 ) + { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup: retrieving result of id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "join_syncbackup: retrieving result of id=%s\n", info->sbi_backups[i]->sb_syncid, 0, 0); + #endif + rc = backup_result( be, i, &waittime, SYNC_ERROR ); + } + ldap_pvt_thread_mutex_unlock(&info->sbi_backups[i]->sb_join_mutex); + } + + if ( info->sbi_num_sync_backups >= num_backups ) { + break; + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup: no backup followed, calling follow thread\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "join_syncbackup: no backup followed, calling follow thread\n", 0, 0, 0); + #endif + + ldap_pvt_thread_mutex_lock( &info->sbi_follow_mutex ); + if ( ldap_pvt_thread_pool_backload( &info->sbi_follow_pool ) == 0 ) + ldap_pvt_thread_pool_submit( &info->sbi_follow_pool, follow, be ); + ldap_pvt_thread_mutex_unlock( &info->sbi_follow_mutex ); + + ldap_pvt_thread_mutex_lock( &info->sbi_backup_avail_mutex ); + ldap_pvt_thread_cond_wait( &info->sbi_backup_avail_cv, &info->sbi_backup_avail_mutex ); + ldap_pvt_thread_mutex_unlock( &info->sbi_backup_avail_mutex ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup: got signal from follow thread\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "join_syncbackup: got signal from follow thread\n", 0, 0, 0); + #endif + if ( slap_get_time() >= tlimit ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "join_syncbackup: timeout\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "join_syncbackup: timeout\n", 0, 0, 0); + #endif + rs->sr_text = "timeout to join backup servers"; + return LDAP_BUSY; + } + + } while ( 1 ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "join_syncbackup: sync_state: ", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "join_syncbackup: sync_state: ", 0, 0, 0); + #endif + for(i=0; i < info->sbi_num_max_backups; i++) { + if ( is_backup_avail ( info, i ) ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "(%2x)", history_backup_latency(be, i), 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "(%2x)", history_backup_latency(be, i), 0, 0); + #endif + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "(XXX)", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "(XXX)", 0, 0, 0); + #endif + } + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "\n", 0, 0, 0); + #endif + + return LDAP_SUCCESS; + } + + static int + build_backup_ctrls( + LDAPControl ***ctrlsp, + Operation *op + ) + { + int i; + struct berval *ctxcsn_bvalp; + BerElement *ctxcsn_ber; + int no_csn = 1; + LDAPControl ctxcsn_ctrl = { LDAP_CONTROL_CONTEXTCSN, { 0, NULL }, 1 }; + + /* + * don't create contextCSN control when the operation is an + * extended operation. + */ + if ( op->o_tag == LDAP_REQ_EXTENDED ) { + no_csn = 0; + } + + if ( op->o_ctrls == NULL ) { + *ctrlsp = (LDAPControl **)ch_malloc(sizeof(LDAPControl *) * 2); + i = 0; + } else { + for ( i=0; op->o_ctrls[i] != NULL; i++ ) { + if ( ! strcmp( op->o_ctrls[i]->ldctl_oid, LDAP_CONTROL_CONTEXTCSN )) { + no_csn = 0; + } + + } + + *ctrlsp = (LDAPControl **)ch_malloc(sizeof(LDAPControl *) * (i+no_csn+1) ); + for ( i=0; op->o_ctrls[i] != NULL; i++ ) { + (*ctrlsp)[i] = ldap_control_dup ( op->o_ctrls[i] ); + } + } + + if ( no_csn ) { + ctxcsn_ber = ber_alloc_t( LBER_USE_DER ); + ber_set_option( ctxcsn_ber, LBER_OPT_BER_MEMCTX, NULL ); + + ber_printf( ctxcsn_ber, "{O}", &op->o_ctxcsn_bv ); + if ( ber_flatten ( ctxcsn_ber, &ctxcsn_bvalp ) == LBER_ERROR ) { + ber_free ( ctxcsn_ber, 1 ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "build_backup_ctrls: contextCSN encoding error\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_ANY, "build_backup_ctrls: contextCSN encoding error\n", 0, 0, 0); + #endif + (*ctrlsp)[i] = NULL; + ldap_controls_free(*ctrlsp); + ber_free ( ctxcsn_ber, 1 ); + ch_free( *ctrlsp ); + + return -1; + } + ber_free ( ctxcsn_ber, 1 ); + + if ( ber_dupbv( &ctxcsn_ctrl.ldctl_value, ctxcsn_bvalp ) == NULL ) { + (*ctrlsp)[i] = NULL; + ldap_controls_free(*ctrlsp); + ber_bvfree( ctxcsn_bvalp ); + ch_free( *ctrlsp ); + + return -1; + } + (*ctrlsp)[i] = ldap_control_dup ( &ctxcsn_ctrl ); + ber_bvfree( ctxcsn_bvalp ); + ch_free( ctxcsn_ctrl.ldctl_value.bv_val ); + + i++; + } + + (*ctrlsp)[i] = NULL; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "build_backup_ctrls: %d ctrls\n", i, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "build_backup_ctrls: %d ctrls\n", i, 0, 0); + #endif + + + return 0; + } + + static void + backup_ctrls_free( LDAPControl **ctrls ) + { + ldap_controls_free ( ctrls ); + } + + static addmod_t * + build_add_event_u( Operation *op, LDAPMod **mods ) + { + addmod_t *add; + + add = (addmod_t *)ch_malloc(sizeof(addmod_t)); + memset( add, 0, sizeof(addmod_t)); + add->entrydn = ch_strdup(op->o_req_dn.bv_val); + add->mods = mods; + return add; + } + + static rename_t * + build_rename_event_u( Operation *op ) + { + rename_t *rename = (rename_t *)ch_malloc(sizeof(rename_t)); + rename->olddn = ch_strdup(op->o_req_dn.bv_val); + rename->newrdn = ch_strdup(op->orr_newrdn.bv_val); + + if ( op->orr_newSup ) { + rename->newSup = ch_strdup( op->orr_newSup->bv_val ); + } else { + rename->newSup = NULL; + } + rename->deleteoldrdn = op->orr_deleteoldrdn; + + return rename; + } + + static extended_t * + build_extended_event_u( Operation *op ) + { + extended_t *ex = (extended_t *)ch_malloc(sizeof(extended_t)); + ex->reqoid = ch_strdup(op->oq_extended.rs_reqoid.bv_val); + ex->reqdata = ber_dupbv( NULL, op->oq_extended.rs_reqdata ); + + return ex; + } + + static void + build_addmod_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls, + int ev_tag, + LDAPMod **mods + ) + { + addmod_t *ev_u; + + ev_u = build_add_event_u ( op, mods ); + build_event( ev, ev_tag, entry, op->o_ctxcsn_bv.bv_val, + op->o_conn->c_connid, op->o_opid, ctrls, ev_u ); + + } + + static void + build_add_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls, + LDAPMod **mods + ) + { + build_addmod_event ( ev, entry, op, ctrls, LDAP_REQ_ADD, mods ); + } + + static void + build_modify_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls, + LDAPMod **mods + ) + { + build_addmod_event ( ev, entry, op, ctrls, LDAP_REQ_MODIFY, mods ); + } + + static void + build_delete_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls + ) + { + build_event( ev, LDAP_REQ_DELETE, entry, op->o_ctxcsn_bv.bv_val, + op->o_conn->c_connid, op->o_opid, ctrls, + op->o_req_dn.bv_val ); + } + + static void + build_rename_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls + ) + { + rename_t *ev_u; + + ev_u = build_rename_event_u ( op ); + build_event ( ev, LDAP_REQ_MODRDN, entry, op->o_ctxcsn_bv.bv_val, + op->o_conn->c_connid, op->o_opid, ctrls, ev_u ); + } + + static void + build_extended_event( + event_t *ev, + Entry *entry, + Operation *op, + LDAPControl **ctrls + ) + { + extended_t *ev_u; + + ev_u = build_extended_event_u ( op ); + build_event ( ev, LDAP_REQ_EXTENDED, entry, "", + op->o_conn->c_connid, op->o_opid, ctrls, ev_u ); + + } + + /* client side startSYNC extendend operation functions */ + + int + ldap_start_sync( + LDAP* ld, + int *msgidp, + char *syncid, + struct berval *cookie + ) + { + int rc; + struct berval bv = {0, NULL}; + BerElement *ber = NULL; + + ber = ber_alloc_t( LBER_USE_DER ); + + if( ber == NULL ) { + return -1; + } + + ber_printf( ber, "{s", syncid ); + + if ( cookie != NULL ) { + ber_printf( ber, "O", cookie ); + } + + ber_printf( ber, "N}" ); + + rc = ber_flatten2( ber, &bv, 0 ); + + if( rc < 0 ) { + ber_free( ber, 1 ); + return -1; + } + + rc = ldap_extended_operation( ld, + LDAP_EXOP_X_START_SYNC, &bv, + NULL, NULL, msgidp ); + + ber_free( ber, 1 ); + + return rc; + } + + void * + backup_healthcheck( void *ctx, void *arg ) + { + int id, rc; + struct re_s *rtask = arg; + BackendDB *be = (BackendDB *) rtask->arg; + syncbackupinfo_t *info = (syncbackupinfo_t *) be->be_syncbackupinfo; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_healthcheck\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "=>backup_helathcheck\n", 0, 0, 0 ); + #endif + + for( id=0; id < info->sbi_num_max_backups; id++ ) { + + if ( info->sbi_backups[id]->sb_state == SYNCBACKUP_STATE_NONE ) { + continue; + } + + rc = healthcheck( info->sbi_backups[id]->sb_ld ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "health: id=%d, err=%d\n", id, rc, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "helath: id=%d, err=%d\n", id, rc, 0 ); + #endif + if( rc != LDAP_SUCCESS ) { + backup_call_cb( info, id, rc, "health-check error", SYNC_SERVER_FAILURE ); + detach_backup( be, id ); + } + } + + ldap_pvt_thread_mutex_lock( &health_rq.rq_mutex ); + + if ( ldap_pvt_runqueue_isrunning( &health_rq, rtask )) { + ldap_pvt_runqueue_stoptask( &health_rq, rtask ); + } + + rtask->interval.tv_sec = 10; + ldap_pvt_runqueue_resched( &health_rq, rtask, 0 ); + ldap_pvt_thread_mutex_unlock( &health_rq.rq_mutex ); + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "backup_healthcheck\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "<=backup_helathcheck\n", 0, 0, 0 ); + #endif + + } + + int + healthcheck( + LDAP *ld + ) + { + int version, rc = 0; + LDAPMessage *res; + + struct timeval tout = { SYNC_HEALTH_TIMEOUT, 0 }; + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "healthcheck =>\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "healthcheck =>\n", 0, 0, 0 ); + #endif + rc = ldap_search_st( ld, "", LDAP_SCOPE_BASE, + "(objectclass=*)", NULL, 1, &tout, &res ); + + if ( rc != LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "healthcheck: Error \"%s\"\n", + ldap_err2strin(rc), 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "healthcheck: Error \"%s\"\n", + ldap_err2string(rc), 0, 0 ); + #endif + } + + if ( res ) ldap_msgfree( res ); + + if ( rc == LDAP_SUCCESS ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "healthcheck: connected\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "healthcheck: connected\n", 0, 0, 0 ); + #endif + } else { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "healthcheck: disconnected\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "healthcheck: disconnected\n", 0, 0, 0 ); + #endif + } + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "<=healthcheck\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "<=healthcheck\n", 0, 0, 0 ); + #endif + + return rc; + } + + int + do_syncbackup1( + syncinfo_t *si + ) + { + int msgid, rc; + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "do_syncbackup1=>\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "do_syncbackup1=>\n", 0, 0, 0 ); + #endif + + rc = ldap_start_sync( si->si_ld, &msgid, si->si_syncid, si->si_syncCookie.ctxcsn ); + + if ( rc ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: startsync failed\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: startsync failed\n", 0, 0, 0 ); + #endif + + } + + return rc; + } + + int + do_syncbackup2( + syncinfo_t *si + ) + { + int rc, err, status; + LDAPMessage *res = NULL; + LDAPMessage *msg = NULL; + struct berval bv = {0, NULL}; + BerElement *ber = NULL; + char *errstr = NULL; + char *retoid = NULL; + struct berval *retdata = NULL; + + struct timeval tout = { 0, 0 }; + + if ( slapd_shutdown ) { + rc = -2; + goto done; + } + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "do_syncbackup2=>\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "do_syncbackup2=>\n", 0, 0, 0 ); + #endif + + #ifndef NO_THREADS + if ( si->si_state == SYNC_HEALTH_STATE_NONE ) + tout.tv_sec = SYNC_HEALTH_TIMEOUT; + #endif + + while ( ( rc = ldap_result( si->si_ld, LDAP_RES_ANY, LDAP_MSG_ONE, &tout, &res )) > 0 ) { + if ( slapd_shutdown ) { + rc = -2; + goto done; + } + for( msg = ldap_first_message( si->si_ld, res ); + msg != NULL; + msg = ldap_next_message( si->si_ld, msg ) ) + { + switch( ldap_msgtype( msg ) ) { + case LDAP_RES_INTERMEDIATE: + rc = ldap_parse_intermediate( si->si_ld, msg, &retoid, NULL, NULL, 0 ); + if ( rc ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "do_syncbackup: " + "ldap_parse_intermediate failed (%d)\n", + rc, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "do_syncbackup: " + "ldap_parse_intermediate failed (%d)\n", + rc, 0, 0 ); + #endif + rc = -2; + break; + } + + if (!rc && retoid != NULL && !strcmp( retoid, LDAP_EXOP_X_START_SYNC )) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "synchronized with master server\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "synchronized with master server\n", + 0, 0, 0 ); + #endif + si->si_state = SYNC_HEALTH_STATE_CONNECT; + } else { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: unknown intermediate message\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: unknown intermediate message\n", + 0, 0, 0 ); + rc = -2; + #endif + } + + break; + + case LDAP_RES_EXTENDED: + rc = ldap_parse_result( si->si_ld, msg, &err, NULL, &errstr, NULL, NULL, 0 ); + if ( rc ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "do_syncbackup: " + "ldap_parse_result failed (%d)\n", + rc, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "do_syncbackup: " + "ldap_parse_result failed (%d)\n", + rc, 0, 0 ); + #endif + rc = -2; + break; + } + + rc = ldap_parse_extended_result( si->si_ld, msg, &retoid, &retdata, 0 ); + if ( rc ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, ERR, "do_syncbackup: " + "ldap_parse_extended_result failed (%d)\n", + rc, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, "do_syncbackup: " + "ldap_parse_extended_result failed (%d)\n", + rc, 0, 0 ); + #endif + rc = -2; + break; + } + + if (!rc && retoid != NULL && !strcmp(retoid, LDAP_EXOP_X_START_SYNC)) { + if ( retdata != NULL ) { + ber = ber_init( retdata ); + if ( ber == NULL ) { + rc = LDAP_NO_MEMORY; + break; + } + if ( ber_scanf( ber, "{e}", &status ) == LBER_ERROR ) { + rc = -2; + ber_free( ber, 1 ); + break; + } + + ber_free( ber, 1 ); + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: receive status=%d\n", + status, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: receive status=%d\n", + status, 0, 0 ); + #endif + switch ( status ) { + case SYNC_ERROR: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "do_syncbackup: sync error, %s\n", + errstr, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "do_syncbackup: sync error, %s\n", + errstr, 0, 0 ); + #endif + rc = err; + break; + + case SYNC_NO_SUCH_COOKIE: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: no such cookie \"%s\"\n", + si->syncCookie ? si->syncCookie->bv_val : "(null)", 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: no such cookie \"%s\"\n", + si->si_syncCookie.ctxcsn ? si->si_syncCookie.ctxcsn->bv_val : "(null)", 0, 0 ); + #endif + rc = -2; + break; + + case SYNC_SERVER_FAILURE: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "do_syncbackup: server failure, %s\n", + errstr, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "do_syncbackup: server failure, %s\n", + errstr, 0, 0 ); + #endif + rc = -2; + break; + default: + rc = -2; + } + } else if ( err == LDAP_SUCCESS ){ + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: synchronization is done\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: synchronization is done\n", + 0, 0, 0 ); + #endif + rc = -2; + } else if ( err == LDAP_BUSY ){ + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: master server is busy\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: master server is busy\n", + 0, 0, 0 ); + #endif + rc = -2; + } else { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, INFO, + "do_syncbackup: received error \"%s, %s\"\n", + ldap_err2strin(err), errstr, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "do_syncbackup: received error \"%s, %s\"\n", + ldap_err2string(err), errstr, 0 ); + #endif + rc = err; + } + } else { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: unknown extended response\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: unknown extended response\n", + 0, 0, 0 ); + #endif + rc = -2; + } + + break; + + default: + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup: unknown message\n", + 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup: unknown message\n", + 0, 0, 0 ); + #endif + rc = 0; + } + + if ( errstr != NULL ) { + ldap_memfree( errstr ); + errstr = NULL; + } + if ( retoid != NULL ) { + ldap_memfree( retoid ); + retoid = NULL; + } + if ( retdata != NULL ) { + ber_bvfree( retdata ); + retdata = NULL; + } + if ( rc ) + goto done; + } + } + + if ( rc == -1 ) { + const char *errstr; + + ldap_get_option( si->si_ld, LDAP_OPT_ERROR_NUMBER, &rc ); + errstr = ldap_err2string( rc ); + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, ERR, + "do_syncbackup2 : %s\n", errstr, 0, 0 ); + #else + Debug( LDAP_DEBUG_ANY, + "do_syncbackup2 : %s\n", errstr, 0, 0 ); + #endif + } + + done: + if ( res ) ldap_msgfree( res ); + + if ( !rc && si->si_state == SYNC_HEALTH_STATE_IDLE ) { + if ( healthcheck( si->si_ld ) ) { + rc = -2; + } + } + + if ( !rc && si->si_state == SYNC_HEALTH_STATE_CONNECT ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, + "do_syncbackup2: non-idle state.\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, + "do_syncbackup2: non-idle state.\n", 0, 0, 0 ); + #endif + si->si_state = SYNC_HEALTH_STATE_IDLE; + } + + if ( rc && si->si_ld ) { + si->si_state = SYNC_HEALTH_STATE_NONE; + ldap_unbind( si->si_ld ); + si->si_ld = NULL; + } + + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "<=do_syncbackup2\n", 0, 0, 0 ); + #else + Debug( LDAP_DEBUG_TRACE, "<=do_syncbackup2\n", 0, 0, 0 ); + #endif + + return rc; + } + + + /* boot-time synchronization functions for master server */ + + void + bootsync(BackendDB *be) + { + int i, j; + syncbackupinfo_t *info = be->be_syncbackupinfo; + syncinfo_t *si; + + /* + * we use thread to invoke do_syncrepl because there is + * no another way to use syncrepl easily + */ + ldap_pvt_thread_pool_t boot_syncrepl_pool; + struct re_s rtask; + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "bootsync\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "=>bootsync\n", 0, 0, 0); + #endif + + if (info == NULL) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "bootsync: no backup \n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "bootsync: no backup\n", 0, 0, 0); + #endif + return; + } + + for ( i=0; i < info->sbi_num_max_backups; i++ ) { + si = (syncinfo_t *)ch_malloc(sizeof(syncinfo_t)); + memset(si, 0, sizeof(syncinfo_t)); + replica2syncinfo(info->sbi_backups[i]->sb_ri, si); + ber_dupbv( &si->si_base, &be->be_suffix[0] ); + si->si_be = be; + ber_dupbv( &si->si_updatedn, &be->be_rootndn ); + + rtask.arg = si; + + ldap_pvt_thread_pool_init(&boot_syncrepl_pool, 1, 0); + ldap_pvt_thread_pool_submit(&boot_syncrepl_pool, do_syncrepl, &rtask); + ldap_pvt_thread_pool_destroy(&boot_syncrepl_pool, 1 ); + + syncinfo_free( si ); + } + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "bootsync\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "<=bootsync\n", 0, 0, 0); + #endif + + } + + static int + replica2syncinfo( + Ri *ri, + syncinfo_t *si + ) + { + int len; + + assert( ri->ri_port < 65536 ); + + len = strlen("ldap://:") + strlen(ri->ri_hostname) + strlen("65535"); + si->si_provideruri = (char *)ch_malloc(len + 1); + + sprintf(si->si_provideruri, "ldap://%s:%d", ri->ri_hostname, ri->ri_port); + if( ri->ri_bind_dn ) si->si_binddn = ch_strdup( ri->ri_bind_dn ); + if( ri->ri_password ) si->si_passwd = ch_strdup( ri->ri_password ); + if( ri->ri_syncid ) si->si_syncid = ch_strdup( ri->ri_syncid ); + + si->si_tls = ri->ri_tls; + + si->si_bindmethod = ri->ri_bind_method; + if( ri->ri_saslmech ) si->si_saslmech = ch_strdup( ri->ri_saslmech ); + if( ri->ri_secprops ) si->si_secprops = ch_strdup( ri->ri_secprops ); + if( ri->ri_realm ) si->si_realm = ch_strdup( ri->ri_realm ); + if( ri->ri_authcId ) si->si_authcId = ch_strdup( ri->ri_authcId ); + if( ri->ri_authzId ) si->si_authzId = ch_strdup( ri->ri_authzId ); + + si->si_rid = 0; + ber_str2bv( "(objectclass=*)", sizeof("(objectclass=*)")-1, 1, + &si->si_filterstr ); + si->si_scope = LDAP_SCOPE_SUBTREE; + si->si_attrsonly = 0; + si->si_attrs = (char **) ch_calloc( 1, sizeof( char * )); + si->si_attrs[0] = NULL; + si->si_exattrs = (char **) ch_calloc( 1, sizeof( char * )); + si->si_exattrs[0] = NULL; + si->si_type = LDAP_SYNC_REFRESH_ONLY; + si->si_interval = 10; + 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; + si->si_state = SYNC_HEALTH_STATE_NONE; + si->si_replType = SYNC_BOOTSYNC; + + si->si_presentlist = NULL; + LDAP_LIST_INIT( &si->si_nonpresentlist ); + + init_syncrepl( si ); + + return 0; + } + + /* general functions */ + + int + slap_entry2ldapmods( + Entry *e, + LDAPMod ***mods + ) + { + Attribute *a; + LDAPMod *mod; + int num_e = 0, num_a; + int i, j; + struct berval **bervary; + struct berval *bval; + + for(num_e = 0, a = e->e_attrs; a != NULL; a = a->a_next) num_e++; + + *mods = (LDAPMod **)ch_malloc(sizeof(LDAPMod *)*(num_e+1)); + for(i=0, a = e->e_attrs; ia_next, i++) { + mod = (LDAPMod *)ch_malloc(sizeof(LDAPMod)); + mod->mod_op = LDAP_MOD_BVALUES; + mod->mod_type = *a->a_desc->ad_type->sat_names; + for(num_a = 0, j =0; a->a_vals[j].bv_val != NULL; j++) num_a++; + bervary = (struct berval **)ch_malloc(sizeof(struct berval)*(num_a+1)); + for(j=0; ja_vals[j] ); + bervary[j] = bval; + } + bervary[num_a] = NULL; + mod->mod_bvalues = bervary; + (*mods)[i] = mod; + + } + (*mods)[num_e] = NULL; + return 0; + } + + int + slap_mods2ldapmods( + Modifications *modlist, + LDAPMod ***mods) + { + int num_ml, num_val; + int i, j; + Modifications *ml; + LDAPMod *mod; + + for(num_ml = 0, ml = modlist; ml != NULL; ml = ml->sml_next) num_ml++; + + *mods = (LDAPMod **)ch_malloc(sizeof(LDAPMod *)*(num_ml+1)); + for(i=0, ml = modlist; ml != NULL; ml = ml->sml_next, i++) { + mod = (LDAPMod *)ch_malloc(sizeof(LDAPMod)); + mod->mod_op = ml->sml_op | LDAP_MOD_BVALUES; + mod->mod_type = ml->sml_desc->ad_cname.bv_val; + if (ml->sml_values != NULL) { + for(num_val=0, j=0; ml->sml_values[j].bv_val != NULL; j++) num_val++; + mod->mod_bvalues = (struct berval **)ch_malloc(sizeof(struct berval *)*(num_val+1)); + for(j=0; jmod_bvalues[j] = (struct berval *)ch_malloc(sizeof(struct berval)); + ber_dupbv( mod->mod_bvalues[j], &ml->sml_values[j] ); + } + mod->mod_bvalues[num_val] = NULL; + } else { + mod->mod_bvalues = NULL; + } + (*mods)[i] = mod; + } + (*mods)[num_ml] = NULL; + return 0; + } + + void + slap_print_event( event_t *ev ) + { + + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, "Event: %id, csn=%s\n", ev->ev_id, ev->ev_csn, 0); + #else + Debug ( LDAP_DEBUG_TRACE, "Event: id=%d, csn=%s\n", ev->ev_id, ev->ev_csn, 0); + #endif + + } + + void + slap_print_ldapmods(LDAPMod **mods) + { + int i, j; + + for(i=0; mods[i] != NULL; i++) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, " Op: %p, Type: %s\n", (void *)mods[i]->mod_op, mods[i]->mod_type, 0); + #else + Debug ( LDAP_DEBUG_TRACE, " Op: %p, Type: %s\n", (void *)mods[i]->mod_op, mods[i]->mod_type, 0); + #endif + if(mods[i]->mod_bvalues != NULL) { + for(j=0; mods[i]->mod_bvalues[j] != NULL; j++) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, " %s: (0x%p) %s\n", mods[i]->mod_type, (void *)mods[i]->mod_bvalues[j]->bv_val, mods[i]->mod_bvalues[j]->bv_val); + #else + Debug ( LDAP_DEBUG_TRACE, " %s: (0x%p) %s\n", mods[i]->mod_type, (void *)mods[i]->mod_bvalues[j]->bv_val, mods[i]->mod_bvalues[j]->bv_val); + #endif + } + } + } + + } + + void + slap_ldapmods_free(LDAPMod **mods) + { + int i, j; + + for(i=0; mods[i] != NULL; i++) { + if(mods[i]->mod_bvalues != NULL) { + for(j=0; mods[i]->mod_bvalues[j] != NULL; j++) { + ch_free(mods[i]->mod_bvalues[j]->bv_val); + ch_free(mods[i]->mod_bvalues[j]); + } + ch_free(mods[i]->mod_bvalues); + ch_free(mods[i]); + } + } + + ch_free(mods); + } + + #endif /* LDAP_SYNCBACKUP */ diff -cNr openldap-2.2.30.org/servers/slapd/syncrepl.c openldap-2.2.30/servers/slapd/syncrepl.c *** openldap-2.2.30.org/servers/slapd/syncrepl.c 2005-06-23 05:44:22.000000000 +0900 --- openldap-2.2.30/servers/slapd/syncrepl.c 2006-10-11 11:35:47.000000000 +0900 *************** *** 249,254 **** --- 249,259 ---- si->si_tls == SYNCINFO_TLS_CRITICAL ? "Error" : "Warning", rc, 0 ); #endif + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BOOTSYNC ) + goto get_cookie; + #endif + if( si->si_tls == SYNCINFO_TLS_CRITICAL ) goto done; } } *************** *** 271,276 **** --- 276,286 ---- "(%s,SECPROPS,\"%s\") failed!\n", si->si_provideruri, si->si_secprops, 0 ); #endif + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BOOTSYNC ) + goto get_cookie; + #endif + goto done; } } *************** *** 311,317 **** { rc = LDAP_SERVER_DOWN; } ! goto done; } #else /* HAVE_CYRUS_SASL */ --- 321,330 ---- { rc = LDAP_SERVER_DOWN; } ! #ifdef LDAP_SYNCBACKUP ! if ( si->si_replType == SYNC_BOOTSYNC ) ! goto get_cookie; ! #endif goto done; } #else /* HAVE_CYRUS_SASL */ *************** *** 331,336 **** --- 344,353 ---- Debug( LDAP_DEBUG_ANY, "do_syncrep1: " "ldap_bind_s failed (%d)\n", rc, 0, 0 ); #endif + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BOOTSYNC ) + goto get_cookie; + #endif goto done; } } *************** *** 351,357 **** ? op->o_sasl_ssf : op->o_tls_ssf; /* get syncrepl cookie of shadow replica from subentry */ ! assert( si->si_rid < 1000 ); syncrepl_cn_bv.bv_val = syncrepl_cbuf; syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf), --- 368,376 ---- ? op->o_sasl_ssf : op->o_tls_ssf; /* get syncrepl cookie of shadow replica from subentry */ ! #ifdef LDAP_SYNCBACKUP ! get_cookie: ! #endif assert( si->si_rid < 1000 ); syncrepl_cn_bv.bv_val = syncrepl_cbuf; syncrepl_cn_bv.bv_len = snprintf(syncrepl_cbuf, sizeof(syncrepl_cbuf), *************** *** 439,444 **** --- 458,548 ---- } } + #ifdef LDAP_SYNCBACKUP + /* FIXME: parse sc value correctly? */ + if ( ( ! cmdline_cookie_found ) && + ( si->si_replType == SYNC_BACKUP || si->si_replType == SYNC_BOOTSYNC ) ) + { + BerVarray ctxcsn = NULL; + struct berval ctxcsn_bv = BER_BVNULL; + struct berval ctxcsn_ndn = BER_BVNULL; + BackendDB *be = si->si_be; + int match; + const char *text; + + if ( si->si_syncCookie.ctxcsn ) { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "syncCookie is \"%s\"\n", + si->si_syncCookie.ctxcsn[0].bv_val, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + "syncCookie is \"%s\"\n", + si->si_syncCookie.ctxcsn[0].bv_val, 0, 0); + #endif + } + + build_new_dn( &ctxcsn_ndn, psub, + (struct berval *)&slap_ldapsync_cn_bv, op->o_tmpmemctx ); + /* try to read stored contextCSN */ + backend_attribute( op, NULL, &ctxcsn_ndn, + slap_schema.si_ad_contextCSN, &ctxcsn, ACL_READ ); + + if ( ctxcsn ) { + ber_dupbv( &ctxcsn_bv, &ctxcsn[0] ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "contextCSN is \"%s\"\n", + ctxcsn_bv.bv_val, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + "contextCSN is \"%s\"\n", + ctxcsn_bv.bv_val, 0, 0); + #endif + + if ( si->si_syncCookie.ctxcsn == NULL ) { + match = -1; + } else { + value_match( &match, slap_schema.si_ad_contextCSN, + slap_schema.si_ad_contextCSN->ad_type->sat_ordering, + SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX, + &si->si_syncCookie.ctxcsn[0], &ctxcsn_bv, &text ); + } + if ( match < 0 ) { + struct berval newcookie = BER_BVNULL; + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "use contextCSN for syncCookie\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + "use contextCSN for syncCookie\n", 0, 0, 0); + #endif + + slap_compose_sync_cookie( NULL, &newcookie, + &ctxcsn_bv, si->si_syncCookie.sid, si->si_syncCookie.rid ); + slap_sync_cookie_free( &si->si_syncCookie, 0 ); + ber_bvarray_add( &si->si_syncCookie.octet_str, &newcookie ); + slap_parse_sync_cookie( &si->si_syncCookie ); + } + + ber_bvarray_free_x ( ctxcsn, op->o_tmpmemctx ); + ch_free( ctxcsn_bv.bv_val ); + ch_free( ctxcsn_ndn.bv_val ); + } else { + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "contextCSN is not found\n", 0, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + "contextCSN is not found\n", 0, 0, 0); + #endif + } + } + + if ( rc && si->si_replType == SYNC_BOOTSYNC ) + return -1; + #endif + rc = ldap_sync_search( si, op->o_tmpmemctx ); if( rc != LDAP_SUCCESS ) { *************** *** 654,659 **** --- 758,769 ---- si->si_presentlist = NULL; } } + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BACKUP ) { + rc = 0; + goto done; + } + #endif rc = -2; goto done; break; *************** *** 916,922 **** --- 1026,1046 ---- if ( rc == LDAP_SUCCESS ) { ldap_get_option( si->si_ld, LDAP_OPT_DESC, &s ); + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType != SYNC_BACKUP ) { + rc = do_syncrep2( &op, si ); + } else { + if ( first ) { + rc = do_syncrep2( &op, si ); + if ( rc == LDAP_SUCCESS ) + rc = do_syncbackup1( si ); + } + if ( rc == LDAP_SUCCESS ) + rc = do_syncbackup2( si ); + } + #else rc = do_syncrep2( &op, si ); + #endif if ( abs(si->si_type) == LDAP_SYNC_REFRESH_AND_PERSIST ) { /* If we succeeded, enable the connection for further listening. *************** *** 931,941 **** --- 1055,1097 ---- } else if ( !first ) { dostop = 1; } + #ifdef LDAP_SYNCBACKUP + } else if ( si->si_replType == SYNC_BACKUP ) { + if ( rc == LDAP_SERVER_DOWN || rc == -2 ) { + #ifdef NEW_LOGGING + LDAP_LOG( OPERATION, DETAIL1, "do_syncrepl: syncbackup retry\n", 0, 0,0 ); + #else + Debug( LDAP_DEBUG_TRACE, "do_syncrepl: syncbackup retry\n", 0, 0, 0 ); + #endif + if ( rc == -2 ) rc = 0; + } + #endif } else { if ( rc == -2 ) rc = 0; } } + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BOOTSYNC ) { + BackendDB *be = si->si_be; + + if ( si->si_syncCookie.ctxcsn ) { + if ( be->be_syncbackupinfo->sbi_init_cookie != NULL ) + ber_bvfree( be->be_syncbackupinfo->sbi_init_cookie ); + be->be_syncbackupinfo->sbi_init_cookie = ber_dupbv( NULL, &si->si_syncCookie.ctxcsn[0] ); + #ifdef NEW_LOGGING + LDAP_LOG ( OPERATION, DETAIL1, + "init_cookie: %s\n", be->be_syncbackupinfo->sbi_init_cookie->bv_val, 0, 0); + #else + Debug ( LDAP_DEBUG_TRACE, + "init_cookie: %s\n", be->be_syncbackupinfo->sbi_init_cookie->bv_val, 0, 0); + #endif + } + slap_sync_cookie_free( &si->si_syncCookie, 0 ); + + return NULL; + } + #endif /* At this point, we have 4 cases: * 1) for any hard failure, give up and remove this task * 2) for ServerDown, reschedule this task to run *************** *** 1915,1922 **** --- 2071,2092 ---- mlnext = mod; op->o_tag = LDAP_REQ_ADD; + #ifdef LDAP_SYNCBACKUP + op->o_backup = 0; + + if ( si->si_replType == SYNC_BACKUP || si->si_replType == SYNC_BOOTSYNC ) { + op->o_ctxcsn = SLAP_CRITICAL_CONTROL; + ber_dupbv( &op->o_ctxcsn_bv, syncCookie->ctxcsn ); + + rc = slap_mods_opattrs( op, modlist, modtail, + &text, txtbuf, textlen, 1 ); + } else { + #endif rc = slap_mods_opattrs( op, modlist, modtail, &text, txtbuf, textlen, 0 ); + #ifdef LDAP_SYNCBACKUP + } + #endif for ( ml = modlist; ml != NULL; ml = ml->sml_next ) { ml->sml_op = LDAP_MOD_REPLACE; *************** *** 2041,2046 **** --- 2211,2225 ---- mlnext->sml_next = NULL; } + #ifdef LDAP_SYNCBACKUP + if ( si->si_replType == SYNC_BACKUP || si->si_replType == SYNC_BOOTSYNC ) { + slap_graduate_commit_csn( op ); + + if ( op->o_ctxcsn_bv.bv_val != NULL ) + ber_bvfree( &op->o_ctxcsn_bv ); + } + #endif + for (ml = modlist ; ml != NULL; ml = mlnext ) { mlnext = ml->sml_next; free( ml ); diff -cNr openldap-2.2.30.org/servers/slurpd/config.c openldap-2.2.30/servers/slurpd/config.c *** openldap-2.2.30.org/servers/slurpd/config.c 2005-01-21 02:01:19.000000000 +0900 --- openldap-2.2.30/servers/slurpd/config.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 411,416 **** --- 411,419 ---- ) { int nr; + #ifdef LDAP_SYNCBACKUP + int rc; + #endif nr = ++sglob->num_replicas; sglob->replicas = (Ri **) ch_realloc( sglob->replicas, *************** *** 425,432 **** --- 428,440 ---- fprintf( stderr, "out of memory, Ri_init\n" ); exit( EXIT_FAILURE ); } + #ifdef LDAP_SYNCBACKUP + rc = parse_replica_line( cargv, cargc, sglob->replicas[ nr -1] ); + if ( rc < 0 ) { + #else if ( parse_replica_line( cargv, cargc, sglob->replicas[ nr - 1] ) < 0 ) { + #endif /* Something bad happened - back out */ fprintf( stderr, "Warning: failed to add replica \"%s:%d - ignoring replica\n", *************** *** 435,440 **** --- 443,454 ---- sglob->replicas[ nr - 1 ]->ri_port ); sglob->replicas[ nr - 1] = NULL; sglob->num_replicas--; + #ifdef LDAP_SYNCBACKUP + } else if ( rc > 0 ) { + /* sync=yes - ignore this replica */ + sglob->replicas[ nr - 1] = NULL; + sglob->num_replicas--; + #endif } else { #ifdef NEW_LOGGING LDAP_LOG ( CONFIG, RESULTS, *************** *** 622,627 **** --- 636,646 ---- free( ri->ri_srvtab ); } ri->ri_srvtab = strdup( val ); + #ifdef LDAP_SYNCBACKUP + } else if ( !strncasecmp( cargv[ i ], + SYNCIDSTR, sizeof( SYNCIDSTR ) - 1 ) ) { + return 1; + #endif } else { fprintf( stderr, "Error: parse_replica_line: unknown keyword \"%s\"\n", diff -cNr openldap-2.2.30.org/servers/slurpd/re.c openldap-2.2.30/servers/slurpd/re.c *** openldap-2.2.30.org/servers/slurpd/re.c 2005-01-21 02:01:19.000000000 +0900 --- openldap-2.2.30/servers/slurpd/re.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 46,55 **** --- 46,64 ---- #include #include "../slapd/slap.h" + #ifdef LDAP_SYNCBACKUP + #undef ldap_debug + #define ldap_debug slurp_debug + #endif #include "slurp.h" #include "globals.h" + #ifdef LDAP_SYNCBACKUP + #undef ldap_debug + #define ldap_debug slurp_debug + #endif + /* Forward references */ static Rh *get_repl_hosts LDAP_P(( char *, int *, char ** )); static int gettype LDAP_P(( char * )); diff -cNr openldap-2.2.30.org/servers/slurpd/sanity.c openldap-2.2.30/servers/slurpd/sanity.c *** openldap-2.2.30.org/servers/slurpd/sanity.c 2005-01-21 02:01:19.000000000 +0900 --- openldap-2.2.30/servers/slurpd/sanity.c 2006-10-11 11:28:08.000000000 +0900 *************** *** 82,90 **** --- 82,96 ---- /* * Are there any replicas listed in the slapd config file? */ + #ifdef LDAP_SYNCBACKUP + if ( sglob->num_replicas == 0 ) { + fprintf( stderr, "No replicas for slurpd in slapd.conf file \"%s\"!\n", + sglob->slapd_configfile ); + #else if ( sglob->replicas == NULL ) { fprintf( stderr, "No replicas in slapd.conf file \"%s\"!\n", sglob->slapd_configfile ); + #endif err++; } diff -cNr openldap-2.2.30.org/servers/slurpd/slurp.h openldap-2.2.30/servers/slurpd/slurp.h *** openldap-2.2.30.org/servers/slurpd/slurp.h 2005-01-21 02:01:19.000000000 +0900 --- openldap-2.2.30/servers/slurpd/slurp.h 2006-10-11 11:28:08.000000000 +0900 *************** *** 155,160 **** --- 155,163 ---- #define STARTTLSSTR "starttls" #define TLSSTR "tls" #define CRITICALSTR "critical" + #ifdef LDAP_SYNCBACKUP + #define SYNCIDSTR "syncid" + #endif #define REPLICA_SLEEP_TIME ( 10 ) *************** *** 240,245 **** --- 243,251 ---- unsigned long ri_seq; /* seq number of last repl */ ldap_pvt_thread_t ri_tid; /* ID of thread for this replica */ + #ifdef LDAP_SYNCBACKUP + char *ri_syncid; /* syncid value for syncbackup */ + #endif /* Member functions */ int (*ri_process) LDAP_P(( Ri * )); /* process the next repl entry */ diff -cNr openldap-2.2.30.org/tests/data/slapd-syncbackup-master.conf openldap-2.2.30/tests/data/slapd-syncbackup-master.conf *** openldap-2.2.30.org/tests/data/slapd-syncbackup-master.conf 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/tests/data/slapd-syncbackup-master.conf 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,47 ---- + # $OpenLDAP: pkg/ldap/tests/data/slapd-repl-master.conf,v 1.27 2003/04/30 01:04:18 hyc Exp $ + # + # master slapd config -- for testing of replication + # + ucdata-path ./ucdata + include ./schema/core.schema + include ./schema/cosine.schema + include ./schema/inetorgperson.schema + include ./schema/openldap.schema + include ./schema/nis.schema + # + pidfile ./testrun/slapd.1.pid + argsfile ./testrun/slapd.1.args + + modulepath ../servers/slapd/back-@BACKEND@/ + @MODULELOAD@ + + ####################################################################### + # ldbm database definitions + ####################################################################### + + database @BACKEND@ + #ldbm#cachesize 0 + suffix "o=University of Michigan,c=US" + directory ./testrun/db.1.a + rootdn "cn=Manager,o=University of Michigan,c=US" + rootpw secret + #ldbm#index objectClass eq + #ldbm#index cn,sn,uid pres,eq,sub + #bdb#index objectClass eq + #bdb#index cn,sn,uid pres,eq,sub + + #weaksync on + + syncdn "cn=Manager,o=University of Michigan,c=US" + + replica host=localhost:9012 + binddn="cn=Replica,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + syncid=hoge + + replica host=localhost:9013 + binddn="cn=Replica,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + syncid=hige diff -cNr openldap-2.2.30.org/tests/data/slapd-syncbackup-master2.conf openldap-2.2.30/tests/data/slapd-syncbackup-master2.conf *** openldap-2.2.30.org/tests/data/slapd-syncbackup-master2.conf 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/tests/data/slapd-syncbackup-master2.conf 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,45 ---- + # $OpenLDAP: pkg/ldap/tests/data/slapd-repl-master.conf,v 1.27 2003/04/30 01:04:18 hyc Exp $ + # + # master slapd config -- for testing of replication + # + ucdata-path ./ucdata + include ./schema/core.schema + include ./schema/cosine.schema + include ./schema/inetorgperson.schema + include ./schema/openldap.schema + include ./schema/nis.schema + # + pidfile ./testrun/slapd.1.pid + argsfile ./testrun/slapd.1.args + + modulepath ../servers/slapd/back-@BACKEND@/ + @MODULELOAD@ + + ####################################################################### + # ldbm database definitions + ####################################################################### + + database @BACKEND@ + #ldbm#cachesize 0 + suffix "o=University of Michigan,c=US" + directory ./testrun/db.2.a + rootdn "cn=Manager,o=University of Michigan,c=US" + rootpw secret + #ldbm#index objectClass eq + #ldbm#index cn,sn,uid pres,eq,sub + #bdb#index objectClass eq + #bdb#index cn,sn,uid pres,eq,sub + + syncdn "cn=Manager,o=University of Michigan,c=US" + + replica host=localhost:9012 + binddn="cn=Replica,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + syncid=moge + + replica host=localhost:9013 + binddn="cn=Replica,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + syncid=hige diff -cNr openldap-2.2.30.org/tests/data/slapd-syncbackup-slave1.conf openldap-2.2.30/tests/data/slapd-syncbackup-slave1.conf *** openldap-2.2.30.org/tests/data/slapd-syncbackup-slave1.conf 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/tests/data/slapd-syncbackup-slave1.conf 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,42 ---- + # $OpenLDAP: pkg/ldap/tests/data/slapd-syncrepl-slave-persist.conf,v 1.1 2003/05/20 17:58:11 jongchoi Exp $ + # + # slave slapd config -- for testing of SYNC replication + # + ucdata-path ./ucdata + include ./schema/core.schema + include ./schema/cosine.schema + include ./schema/inetorgperson.schema + include ./schema/openldap.schema + include ./schema/nis.schema + # + pidfile ./testrun/slapd.2.pid + argsfile ./testrun/slapd.2.args + + modulepath ../servers/slapd/back-@BACKEND@/ + @MODULELOAD@ + + ####################################################################### + # ldbm database definitions + ####################################################################### + + database @BACKEND@ + #ldbm#cachesize 0 + suffix "o=University of Michigan,c=US" + directory ./testrun/db.2.a + rootdn "cn=Replica,o=University of Michigan,c=US" + rootpw secret + updatedn "cn=Replica,o=University of Michigan,c=US" + updateref "ldap://localhost:9009" + #ldbm#index objectClass eq + #ldbm#index cn,sn,uid pres,eq,sub + #bdb#index objectClass eq + #bdb#index cn,sn,uid pres,eq,sub + + # Don't change syncrepl spec yet + syncbackup syncid=hoge + provider=ldap://localhost:9011 + binddn="cn=Manager,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + checkinterval=10 + diff -cNr openldap-2.2.30.org/tests/data/slapd-syncbackup-slave2.conf openldap-2.2.30/tests/data/slapd-syncbackup-slave2.conf *** openldap-2.2.30.org/tests/data/slapd-syncbackup-slave2.conf 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/tests/data/slapd-syncbackup-slave2.conf 2006-10-11 11:28:08.000000000 +0900 *************** *** 0 **** --- 1,42 ---- + # $OpenLDAP: pkg/ldap/tests/data/slapd-repl-slave.conf,v 1.31 2003/04/30 01:04:18 hyc Exp $ + # + # slave slapd config -- for testing of replication + # + ucdata-path ./ucdata + include ./schema/core.schema + include ./schema/cosine.schema + include ./schema/inetorgperson.schema + include ./schema/openldap.schema + include ./schema/nis.schema + # + pidfile ./testrun/slapd.3.pid + argsfile ./testrun/slapd.3.args + + modulepath ../servers/slapd/back-@BACKEND@/ + @MODULELOAD@ + + ####################################################################### + # ldbm database definitions + ####################################################################### + + database @BACKEND@ + #ldbm#cachesize 0 + suffix "o=University of Michigan,c=US" + directory ./testrun/db.3.a + rootdn "cn=Replica,o=University of Michigan,c=US" + rootpw secret + updatedn "cn=Replica,o=University of Michigan,c=US" + updateref "ldap://localhost:9009" + #ldbm#index objectClass eq + #ldbm#index cn,sn,uid pres,eq,sub + #bdb#index objectClass eq + #bdb#index cn,sn,uid pres,eq,sub + + # Don't change syncrepl spec yet + syncbackup syncid=hige + provider=ldap://localhost:9011 + binddn="cn=Manager,o=University of Michigan,c=US" + bindmethod=simple + credentials=secret + checkinterval=10 + diff -cNr openldap-2.2.30.org/tests/run openldap-2.2.30/tests/run *** openldap-2.2.30.org/tests/run 1970-01-01 09:00:00.000000000 +0900 --- openldap-2.2.30/tests/run 2006-10-11 12:51:01.000000000 +0900 *************** *** 0 **** --- 1,161 ---- + #!/bin/sh + # $OpenLDAP: pkg/ldap/tests/run.in,v 1.13.2.5 2005/01/20 17:01:19 kurt Exp $ + ## This work is part of OpenLDAP Software . + ## + ## Copyright 1998-2005 The OpenLDAP Foundation. + ## All rights reserved. + ## + ## Redistribution and use in source and binary forms, with or without + ## modification, are permitted only as authorized by the OpenLDAP + ## Public License. + ## + ## A copy of this license is available in the file LICENSE in the + ## top-level directory of the distribution or, alternatively, at + ## . + + USAGE="$0 [-b ] [-c] [-k] [-p] [-u] [-w]