Commit 660617ae authored by Jong Hyuk Choi's avatar Jong Hyuk Choi
Browse files

Context CSN patch (1)

- currenty works for refreshOnly mode of LDAP Sync
- Context CSN for add / modify is implemented
- code for delete / modrdn / refreshAndPersist will be soon committed
parent 2583276a
......@@ -361,7 +361,7 @@ struct { \
#define LDAP_TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define LDAP_TAILQ_FOREACH(var, head, field) \
for (var = LDAP_TAILQ_FIRST(head); var; var = TAILQ_NEXT(var, field))
for (var = LDAP_TAILQ_FIRST(head); var; var = LDAP_TAILQ_NEXT(var, field))
#define LDAP_TAILQ_FOREACH_REVERSE(var, head, type, field) \
for ((var) = LDAP_TAILQ_LAST((head), type, field); \
......
......@@ -23,7 +23,7 @@ SRCS = main.c globals.c config.c daemon.c \
oidm.c starttls.c index.c sets.c referral.c root_dse.c \
sasl.c module.c mra.c mods.c sl_malloc.c limits.c \
backglue.c operational.c matchedValues.c cancel.c syncrepl.c \
backover.c $(@PLAT@_SRCS)
backover.c ctxcsn.c $(@PLAT@_SRCS)
OBJS = main.o globals.o config.o daemon.o \
connection.o search.o filter.o add.o cr.o \
......@@ -37,7 +37,7 @@ OBJS = main.o globals.o config.o daemon.o \
oidm.o starttls.o index.o sets.o referral.o root_dse.o \
sasl.o module.o mra.o mods.o sl_malloc.o limits.o \
backglue.o operational.o matchedValues.o cancel.o syncrepl.o \
backover.o $(@PLAT@_OBJS)
backover.o ctxcsn.o $(@PLAT@_OBJS)
LDAP_INCDIR= ../../include -I$(srcdir)/slapi
LDAP_LIBDIR= ../../libraries
......
......@@ -375,6 +375,11 @@ do_add( Operation *op, SlapReply *rs )
#endif /* LDAP_SLAPI */
done:
#ifdef LDAP_SYNC
graduate_commit_csn( op );
#endif
if( modlist != NULL ) {
slap_mods_free( modlist );
}
......
......@@ -37,6 +37,17 @@ bdb_add(Operation *op, SlapReply *rs )
#ifdef LDAP_SYNC
Operation* ps_list;
struct berval *max_committed_csn = NULL;
EntryInfo *suffix_ei = NULL;
EntryInfo *ctxcsn_ei = NULL;
Entry *ctxcsn_e = NULL;
DB_LOCK suffix_lock;
DB_LOCK ctxcsn_lock;
struct berval ctxcsn_rdn = { 0, NULL };
struct berval ctxcsn_ndn = { 0, NULL };
int rc, ret;
int ctxcsn_added = 0;
ID ctxcsn_id;
#endif
#ifdef NEW_LOGGING
......@@ -74,14 +85,31 @@ bdb_add(Operation *op, SlapReply *rs )
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_add: next_id failed (%d)\n",
rs->sr_err, 0, 0 );
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#endif
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
#ifdef LDAP_SYNC
if ( be_issuffix( op->o_bd, &op->oq_add.rs_e->e_nname ) ) {
rs->sr_err = bdb_next_id( op->o_bd, NULL, &ctxcsn_id );
if( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#endif
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
}
#endif
if( 0 ) {
retry: /* transaction retry */
if( p ) {
......@@ -467,7 +495,136 @@ retry: /* transaction retry */
goto return_results;
}
if( op->o_noop ) {
#ifdef LDAP_SYNC
ber_str2bv( "cn=ldapsync", strlen("cn=ldapsync"), 0, &ctxcsn_rdn );
build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &ctxcsn_rdn );
rc = bdb_dn2entry( op, ltid, &ctxcsn_ndn, &ctxcsn_ei,
0, locker, &ctxcsn_lock );
if ( ctxcsn_ei ) {
ctxcsn_e = ctxcsn_ei->bei_e;
bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, ctxcsn_ei, 1, 0, &ctxcsn_lock );
}
max_committed_csn = commit_csn( op );
ctxcsn_added = 0;
if ( max_committed_csn == NULL )
goto txn_end;
switch( rc ) {
case 0:
if ( !ctxcsn_e ) {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn not present";
goto return_results;
} else {
attr_delete( &ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN );
attr_merge_normalize_one( ctxcsn_e, slap_schema.si_ad_contextCSN,
max_committed_csn, NULL );
ret = bdb_id2entry_update( op->o_bd, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = ret;
rs->sr_text = "context csn update failed";
goto return_results;
}
ret = bdb_index_entry_add( op, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn indexing failed";
goto return_results;
}
}
break;
case DB_NOTFOUND:
if ( !be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
rc = bdb_dn2entry( op, ltid, &op->o_bd->be_nsuffix[0], &suffix_ei,
0, locker, &suffix_lock );
} else {
suffix_ei = ei;
}
ctxcsn_e = create_context_csn_entry( op->o_bd, max_committed_csn );
ctxcsn_e->e_id = ctxcsn_id;
ctxcsn_added = 1;
ret = bdb_dn2id_add( op, ltid, suffix_ei, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
case DB_KEYEXIST :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn exists before contex prefix does";
goto return_results;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn store failed";
goto return_results;
}
ret = bdb_id2entry_add( op->o_bd, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn store failed";
goto return_results;
}
ret = bdb_index_entry_add( op, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn indexing failed";
goto return_results;
}
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto rewind;
case LDAP_BUSY:
rs->sr_err = rc;
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
goto txn_end;
rewind :
rewind_commit_csn( op );
goto retry;
txn_end:
#endif
if ( op->o_noop ) {
if (( rs->sr_err=TXN_ABORT( ltid )) != 0 ) {
rs->sr_text = "txn_abort (no-op) failed";
} else {
......@@ -486,6 +643,9 @@ retry: /* transaction retry */
} else {
struct berval nrdn;
#ifdef LDAP_SYNC
struct berval ctx_nrdn;
#endif
if (pdn.bv_len) {
nrdn.bv_val = op->ora_e->e_nname.bv_val;
......@@ -494,7 +654,15 @@ retry: /* transaction retry */
nrdn = op->ora_e->e_nname;
}
bdb_cache_add(bdb, ei, op->oq_add.rs_e, &nrdn, locker );
bdb_cache_add( bdb, ei, op->oq_add.rs_e, &nrdn, locker );
#ifdef LDAP_SYNC
if ( ctxcsn_added ) {
ctx_nrdn.bv_val = "cn=ldapsync";
ctx_nrdn.bv_len = strlen( ctx_nrdn.bv_val );
bdb_cache_add( bdb, suffix_ei, ctxcsn_e, &ctx_nrdn, locker );
}
#endif
if(( rs->sr_err=TXN_COMMIT( ltid, 0 )) != 0 ) {
rs->sr_text = "txn_commit failed";
......@@ -555,4 +723,3 @@ done:
return ( ( rs->sr_err == LDAP_SUCCESS ) ? noop : rs->sr_err );
}
......@@ -34,7 +34,11 @@ bdb_cache_entryinfo_new( )
}
/* Atomically release and reacquire a lock */
#if LDAP_SYNC
int
#else
static int
#endif
bdb_cache_entry_db_relock(
DB_ENV *env,
u_int32_t locker,
......
......@@ -331,6 +331,17 @@ bdb_modify( Operation *op, SlapReply *rs )
#ifdef LDAP_SYNC
Operation* ps_list;
struct psid_entry *pm_list, *pm_prev;
struct berval *max_committed_csn = NULL;
EntryInfo *suffix_ei = NULL;
EntryInfo *ctxcsn_ei = NULL;
Entry *ctxcsn_e = NULL;
DB_LOCK suffix_lock;
DB_LOCK ctxcsn_lock;
struct berval ctxcsn_rdn = { 0, NULL };
struct berval ctxcsn_ndn = { 0, NULL };
int rc, ret;
int ctxcsn_added = 0;
ID ctxcsn_id;
#endif
#ifdef NEW_LOGGING
......@@ -571,6 +582,150 @@ retry: /* transaction retry */
goto return_results;
}
#ifdef LDAP_SYNC
ber_str2bv( "cn=ldapsync", strlen("cn=ldapsync"), 0, &ctxcsn_rdn );
build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &ctxcsn_rdn );
rc = bdb_dn2entry( op, ltid, &ctxcsn_ndn, &ctxcsn_ei,
0, locker, &ctxcsn_lock );
if ( ctxcsn_ei ) {
ctxcsn_e = ctxcsn_ei->bei_e;
bdb_cache_entry_db_relock( bdb->bi_dbenv, locker, ctxcsn_ei, 1, 0, &ctxcsn_lock );
}
max_committed_csn = commit_csn( op );
if ( max_committed_csn == NULL )
goto txn_end;
ctxcsn_added = 0;
switch( rc ) {
case 0:
if ( !ctxcsn_e ) {
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn not present";
goto return_results;
} else {
attr_delete( &ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN );
attr_merge_normalize_one( ctxcsn_e, slap_schema.si_ad_contextCSN,
max_committed_csn, NULL );
ret = bdb_id2entry_update( op->o_bd, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = ret;
rs->sr_text = "context csn update failed";
goto return_results;
}
ret = bdb_index_entry_add( op, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn indexing failed";
goto return_results;
}
}
break;
case DB_NOTFOUND:
if ( !be_issuffix( op->o_bd, &op->ora_e->e_nname ) ) {
rc = bdb_dn2entry( op, ltid, &op->o_bd->be_nsuffix[0], &suffix_ei,
0, locker, &suffix_lock );
} else {
suffix_ei = ei;
}
/* This serializes add. But this case is very rare : only once. */
rs->sr_err = bdb_next_id( op->o_bd, NULL, &ctxcsn_id );
if ( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#else
Debug( LDAP_DEBUG_TRACE,
"bdb_add: next_id failed (%d)\n", rs->sr_err, 0, 0 );
#endif
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
ctxcsn_e = create_context_csn_entry( op->o_bd, max_committed_csn );
ctxcsn_e->e_id = ctxcsn_id;
ctxcsn_added = 1;
ret = bdb_dn2id_add( op, ltid, suffix_ei, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
case DB_KEYEXIST :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn exists before contex prefix does";
goto return_results;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn store failed";
goto return_results;
}
ret = bdb_id2entry_add( op->o_bd, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn store failed";
goto return_results;
}
ret = bdb_index_entry_add( op, ltid, ctxcsn_e );
switch ( ret ) {
case 0 :
break;
case DB_LOCK_DEADLOCK :
case DB_LOCK_NOTGRANTED :
goto rewind;
default :
rs->sr_err = LDAP_OTHER;
rs->sr_text = "context csn indexing failed";
goto return_results;
}
break;
case DB_LOCK_DEADLOCK:
case DB_LOCK_NOTGRANTED:
goto rewind;
case LDAP_BUSY:
rs->sr_err = rc;
rs->sr_text = "ldap server busy";
goto return_results;
default:
rs->sr_err = LDAP_OTHER;
rs->sr_text = "internal error";
goto return_results;
}
goto txn_end;
rewind :
rewind_commit_csn( op );
goto retry;
txn_end:
#endif
if( op->o_noop ) {
if ( ( rs->sr_err = TXN_ABORT( ltid ) ) != 0 ) {
rs->sr_text = "txn_abort (no-op) failed";
......@@ -579,12 +734,26 @@ retry: /* transaction retry */
rs->sr_err = LDAP_SUCCESS;
}
} else {
#ifdef LDAP_SYNC
struct berval ctx_nrdn;
EntryInfo *ctx_ei;
#endif
bdb_cache_modify( e, dummy.e_attrs, bdb->bi_dbenv, locker, &lock );
#ifdef LDAP_SYNC
if ( ctxcsn_added ) {
ctx_nrdn.bv_val = "cn=ldapsync";
ctx_nrdn.bv_len = strlen( ctx_nrdn.bv_val );
bdb_cache_add( bdb, suffix_ei, ctxcsn_e, &ctx_nrdn, locker );
}
#endif
rs->sr_err = TXN_COMMIT( ltid, 0 );
}
ltid = NULL;
op->o_private = NULL;
if( rs->sr_err != 0 ) {
#ifdef NEW_LOGGING
LDAP_LOG ( OPERATION, ERR,
......
......@@ -468,6 +468,16 @@ void bdb_cache_delete_cleanup(
);
void bdb_cache_release_all( Cache *cache );
#ifdef LDAP_SYNC
int bdb_cache_entry_db_relock(
DB_ENV *env,
u_int32_t locker,
EntryInfo *ei,
int rw,
int tryOnly,
DB_LOCK *lock );
#endif
#ifdef BDB_REUSE_LOCKERS
#define bdb_locker_id BDB_SYMBOL(locker_id)
......@@ -515,13 +525,13 @@ int bdb_do_search(
int
bdb_build_sync_state_ctrl(
Operation *op,
SlapReply *rs,
SlapReply *rs,
Entry *e,
int entry_sync_state,
LDAPControl **ctrls,
int num_ctrls,
int send_cookie,
struct berval *latest_entrycsn_bv );
struct berval *csn );
int
bdb_build_sync_done_ctrl(
......
......@@ -380,13 +380,20 @@ int bdb_search( Operation *op, SlapReply *rs )
AttributeName *attrs;
#ifdef LDAP_SYNC
Filter cookief, csnfnot, csnfeq, csnfand, csnfge, omitcsnf, omitcsnfle;
Filter contextcsnand, contextcsnle, cookief, csnfnot, csnfeq, csnfand, csnfge;
Filter omitcsnf, omitcsnfle;
AttributeAssertion aa_ge, aa_eq, aa_le;
int entry_count = 0;
struct berval *search_context_csn = NULL;
struct berval ctxcsn_rdn = { 0, NULL };
struct berval ctxcsn_ndn = { 0, NULL };
EntryInfo *ctxcsn_ei;
Entry *ctxcsn_e;
DB_LOCK ctxcsn_lock;
Attribute *csn_a;
#if 0
struct berval entrycsn_bv = { 0, NULL };
#endif
struct berval latest_entrycsn_bv = { 0, NULL };
LDAPControl *ctrls[SLAP_SEARCH_MAX_CTRLS];
int num_ctrls = 0;
AttributeName uuid_attr[2];
......@@ -679,6 +686,32 @@ dn2entry_retry:
}
e = NULL;
#ifdef LDAP_SYNC
if ( sop->o_sync_mode != SLAP_SYNC_NONE ) {
ber_str2bv( "cn=ldapsync", strlen("cn=ldapsync"), 0, &ctxcsn_rdn );
build_new_dn( &ctxcsn_ndn, &op->o_bd->be_nsuffix[0], &ctxcsn_rdn );
bdb_dn2entry( op, NULL, &ctxcsn_ndn, &ctxcsn_ei, 0, locker, &ctxcsn_lock );
if ( ctxcsn_ei ) {
ctxcsn_e = ctxcsn_ei->bei_e;
}
if ( ctxcsn_e ) {
csn_a = attr_find( ctxcsn_e->e_attrs, slap_schema.si_ad_contextCSN );
if ( csn_a ) {
search_context_csn = ber_dupbv( NULL, &csn_a->a_vals[0] );
} else {
search_context_csn = NULL;
}
} else {
search_context_csn = NULL;
}
bdb_cache_entry_db_unlock( bdb->bi_dbenv, &ctxcsn_lock );
}
#endif
/* select candidates */
if ( sop->oq_search.rs_scope == LDAP_SCOPE_BASE ) {
rs->sr_err = base_candidate( op->o_bd, &base, candidates );
......@@ -800,7 +833,27 @@ dn2entry_retry:
csnfge.f_ava = &aa_ge;
csnfge.f_av_desc = slap_schema.si_ad_entryCSN;
csnfge.f_av_value = sop->o_sync_state;
csnfge.f_next = sop->oq_search.rs_filter;
if ( search_context_csn ) {
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;
} else {
csnfge.f_next = sop->oq_search.rs_filter;
}
if ( search_context_csn && search_context_csn->bv_val )
printf("search_context_csn = %s\n", search_context_csn->bv_val );
else
printf("search_context_csn = NULL\n");
}
#endif
......@@ -1038,7 +1091,7 @@ id2entry_retry:
if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
rc_sync = test_filter( sop, rs->sr_entry, &cookief );
rs->sr_err = test_filter( sop,
rs->sr_entry, sop->oq_search.rs_filter );
rs->sr_entry, &contextcsnand );
if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
if ( rc_sync == LDAP_COMPARE_TRUE ) {
entry_sync_state = LDAP_SYNC_ADD;
......@@ -1134,7 +1187,7 @@ id2entry_retry:
if ( sop->o_ps_protocol == LDAP_SYNC ) {
rs->sr_err = bdb_build_sync_state_ctrl( sop,
rs, e, entry_sync_state, ctrls,
num_ctrls++, 1, &latest_entrycsn_bv );
num_ctrls++, 1, search_context_csn );
if ( rs->sr_err != LDAP_SUCCESS ) goto done;
rs->sr_attrs = attrs;
rs->sr_ctrls = ctrls;
......@@ -1164,7 +1217,7 @@ id2entry_retry:
if ( sop->o_sync_mode & SLAP_SYNC_REFRESH ) {
rs->sr_err = bdb_build_sync_state_ctrl( sop,
rs, e, entry_sync_state, ctrls,
num_ctrls++, 0, &latest_entrycsn_bv );
num_ctrls++, 0, search_context_csn );
if ( rs->sr_err != LDAP_SUCCESS ) goto done;
rs->sr_ctrls = ctrls;
......@@ -1234,18 +1287,18 @@ loop_continue: