version 1.155, 2006/08/15 07:25:42
|
version 1.165, 2007/01/02 19:01:14
|
Line 1
|
Line 1
|
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.154 2006/07/28 00:40:38 hyc Exp $ */ |
/* $OpenLDAP: pkg/ldap/servers/slapd/overlays/syncprov.c,v 1.164 2006/12/02 09:42:42 ando Exp $ */ |
/* syncprov.c - syncrepl provider */ |
/* syncprov.c - syncrepl provider */ |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
/* This work is part of OpenLDAP Software <http://www.openldap.org/>. |
* |
* |
* Copyright 2004-2006 The OpenLDAP Foundation. |
* Copyright 2004-2007 The OpenLDAP Foundation. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
Line 65 typedef struct syncops {
|
Line 65 typedef struct syncops {
|
#define PS_IS_DETACHED 0x02 |
#define PS_IS_DETACHED 0x02 |
#define PS_WROTE_BASE 0x04 |
#define PS_WROTE_BASE 0x04 |
#define PS_FIND_BASE 0x08 |
#define PS_FIND_BASE 0x08 |
|
#define PS_FIX_FILTER 0x10 |
|
|
int s_inuse; /* reference count */ |
int s_inuse; /* reference count */ |
struct syncres *s_res; |
struct syncres *s_res; |
Line 773 syncprov_sendresp( Operation *op, opcook
|
Line 774 syncprov_sendresp( Operation *op, opcook
|
rs.sr_flags = REP_ENTRY_MUSTRELEASE; |
rs.sr_flags = REP_ENTRY_MUSTRELEASE; |
if ( opc->sreference ) { |
if ( opc->sreference ) { |
rs.sr_ref = get_entry_referrals( op, rs.sr_entry ); |
rs.sr_ref = get_entry_referrals( op, rs.sr_entry ); |
send_search_reference( op, &rs ); |
rs.sr_err = send_search_reference( op, &rs ); |
ber_bvarray_free( rs.sr_ref ); |
ber_bvarray_free( rs.sr_ref ); |
if ( !rs.sr_entry ) |
if ( !rs.sr_entry ) |
*e = NULL; |
*e = NULL; |
Line 785 syncprov_sendresp( Operation *op, opcook
|
Line 786 syncprov_sendresp( Operation *op, opcook
|
if ( rs.sr_entry->e_private ) |
if ( rs.sr_entry->e_private ) |
rs.sr_flags = REP_ENTRY_MUSTRELEASE; |
rs.sr_flags = REP_ENTRY_MUSTRELEASE; |
rs.sr_attrs = op->ors_attrs; |
rs.sr_attrs = op->ors_attrs; |
send_search_entry( op, &rs ); |
rs.sr_err = send_search_entry( op, &rs ); |
if ( !rs.sr_entry ) |
if ( !rs.sr_entry ) |
*e = NULL; |
*e = NULL; |
break; |
break; |
Line 797 syncprov_sendresp( Operation *op, opcook
|
Line 798 syncprov_sendresp( Operation *op, opcook
|
if ( opc->sreference ) { |
if ( opc->sreference ) { |
struct berval bv = BER_BVNULL; |
struct berval bv = BER_BVNULL; |
rs.sr_ref = &bv; |
rs.sr_ref = &bv; |
send_search_reference( op, &rs ); |
rs.sr_err = send_search_reference( op, &rs ); |
} else { |
} else { |
send_search_entry( op, &rs ); |
rs.sr_err = send_search_entry( op, &rs ); |
} |
} |
break; |
break; |
default: |
default: |
Line 877 syncprov_qtask( void *ctx, void *arg )
|
Line 878 syncprov_qtask( void *ctx, void *arg )
|
OperationBuffer opbuf; |
OperationBuffer opbuf; |
Operation *op; |
Operation *op; |
BackendDB be; |
BackendDB be; |
|
int rc; |
|
|
op = (Operation *) &opbuf; |
op = (Operation *) &opbuf; |
*op = *so->s_op; |
*op = *so->s_op; |
Line 897 syncprov_qtask( void *ctx, void *arg )
|
Line 899 syncprov_qtask( void *ctx, void *arg )
|
op->o_private = NULL; |
op->o_private = NULL; |
op->o_callback = NULL; |
op->o_callback = NULL; |
|
|
(void)syncprov_qplay( op, on, so ); |
rc = syncprov_qplay( op, on, so ); |
|
|
/* decrement use count... */ |
/* decrement use count... */ |
syncprov_free_syncop( so ); |
syncprov_free_syncop( so ); |
|
|
/* wait until we get explicitly scheduled again */ |
/* wait until we get explicitly scheduled again */ |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
ldap_pvt_runqueue_stoptask( &slapd_rq, so->s_qtask ); |
ldap_pvt_runqueue_stoptask( &slapd_rq, rtask ); |
ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 1 ); |
if ( rc == 0 ) { |
|
ldap_pvt_runqueue_resched( &slapd_rq, rtask, 1 ); |
|
} else { |
|
/* bail out on any error */ |
|
ldap_pvt_runqueue_remove( &slapd_rq, rtask ); |
|
} |
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
|
|
#if 0 /* FIXME: connection_close isn't exported from slapd. |
|
* should it be? |
|
*/ |
|
if ( rc ) { |
|
ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); |
|
if ( connection_state_closing( op->o_conn )) { |
|
connection_close( op->o_conn ); |
|
} |
|
ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); |
|
} |
|
#endif |
return NULL; |
return NULL; |
} |
} |
|
|
|
/* Start the task to play back queued psearch responses */ |
|
static void |
|
syncprov_qstart( syncops *so ) |
|
{ |
|
int wake=0; |
|
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
|
if ( !so->s_qtask ) { |
|
so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, |
|
syncprov_qtask, so, "syncprov_qtask", |
|
so->s_op->o_conn->c_peer_name.bv_val ); |
|
++so->s_inuse; |
|
wake = 1; |
|
} else { |
|
if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) && |
|
!so->s_qtask->next_sched.tv_sec ) { |
|
so->s_qtask->interval.tv_sec = 0; |
|
ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 ); |
|
so->s_qtask->interval.tv_sec = RUNQ_INTERVAL; |
|
++so->s_inuse; |
|
wake = 1; |
|
} |
|
} |
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
if ( wake ) |
|
slap_wake_listener(); |
|
} |
|
|
/* Queue a persistent search response */ |
/* Queue a persistent search response */ |
static int |
static int |
syncprov_qresp( opcookie *opc, syncops *so, int mode ) |
syncprov_qresp( opcookie *opc, syncops *so, int mode ) |
Line 949 syncprov_qresp( opcookie *opc, syncops *
|
Line 994 syncprov_qresp( opcookie *opc, syncops *
|
so->s_flags |= PS_FIND_BASE; |
so->s_flags |= PS_FIND_BASE; |
} |
} |
if ( so->s_flags & PS_IS_DETACHED ) { |
if ( so->s_flags & PS_IS_DETACHED ) { |
int wake=0; |
syncprov_qstart( so ); |
ldap_pvt_thread_mutex_lock( &slapd_rq.rq_mutex ); |
|
if ( !so->s_qtask ) { |
|
so->s_qtask = ldap_pvt_runqueue_insert( &slapd_rq, RUNQ_INTERVAL, |
|
syncprov_qtask, so, "syncprov_qtask", |
|
so->s_op->o_conn->c_peer_name.bv_val ); |
|
++so->s_inuse; |
|
wake = 1; |
|
} else { |
|
if (!ldap_pvt_runqueue_isrunning( &slapd_rq, so->s_qtask ) && |
|
!so->s_qtask->next_sched.tv_sec ) { |
|
so->s_qtask->interval.tv_sec = 0; |
|
ldap_pvt_runqueue_resched( &slapd_rq, so->s_qtask, 0 ); |
|
so->s_qtask->interval.tv_sec = RUNQ_INTERVAL; |
|
++so->s_inuse; |
|
wake = 1; |
|
} |
|
} |
|
ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex ); |
|
if ( wake ) |
|
slap_wake_listener(); |
|
} |
} |
ldap_pvt_thread_mutex_unlock( &so->s_mutex ); |
ldap_pvt_thread_mutex_unlock( &so->s_mutex ); |
return LDAP_SUCCESS; |
return LDAP_SUCCESS; |
Line 1235 syncprov_op_cleanup( Operation *op, Slap
|
Line 1260 syncprov_op_cleanup( Operation *op, Slap
|
} |
} |
|
|
static void |
static void |
syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on ) |
syncprov_checkpoint( Operation *op, SlapReply *rs, slap_overinst *on, |
|
struct berval *csn ) |
{ |
{ |
syncprov_info_t *si = on->on_bi.bi_private; |
|
Modifications mod; |
Modifications mod; |
Operation opm; |
Operation opm; |
SlapReply rsm = { 0 }; |
SlapReply rsm = { 0 }; |
Line 1245 syncprov_checkpoint( Operation *op, Slap
|
Line 1270 syncprov_checkpoint( Operation *op, Slap
|
slap_callback cb = {0}; |
slap_callback cb = {0}; |
|
|
/* If ctxcsn is empty, delete it */ |
/* If ctxcsn is empty, delete it */ |
if ( BER_BVISEMPTY( &si->si_ctxcsn )) { |
if ( BER_BVISEMPTY( csn )) { |
mod.sml_values = NULL; |
mod.sml_values = NULL; |
} else { |
} else { |
mod.sml_values = bv; |
mod.sml_values = bv; |
bv[1].bv_val = NULL; |
bv[1].bv_val = NULL; |
bv[0] = si->si_ctxcsn; |
bv[0] = *csn; |
} |
} |
mod.sml_nvalues = NULL; |
mod.sml_nvalues = NULL; |
mod.sml_desc = slap_schema.si_ad_contextCSN; |
mod.sml_desc = slap_schema.si_ad_contextCSN; |
Line 1485 syncprov_op_response( Operation *op, Sla
|
Line 1510 syncprov_op_response( Operation *op, Sla
|
{ |
{ |
struct berval maxcsn = BER_BVNULL; |
struct berval maxcsn = BER_BVNULL; |
char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; |
char cbuf[LDAP_LUTIL_CSNSTR_BUFSIZE]; |
|
int do_check = 0; |
|
|
/* Update our context CSN */ |
/* Update our context CSN */ |
cbuf[0] = '\0'; |
cbuf[0] = '\0'; |
Line 1507 syncprov_op_response( Operation *op, Sla
|
Line 1533 syncprov_op_response( Operation *op, Sla
|
|
|
si->si_numops++; |
si->si_numops++; |
if ( si->si_chkops || si->si_chktime ) { |
if ( si->si_chkops || si->si_chktime ) { |
int do_check=0; |
|
if ( si->si_chkops && si->si_numops >= si->si_chkops ) { |
if ( si->si_chkops && si->si_numops >= si->si_chkops ) { |
do_check = 1; |
do_check = 1; |
si->si_numops = 0; |
si->si_numops = 0; |
Line 1517 syncprov_op_response( Operation *op, Sla
|
Line 1542 syncprov_op_response( Operation *op, Sla
|
do_check = 1; |
do_check = 1; |
si->si_chklast = op->o_time; |
si->si_chklast = op->o_time; |
} |
} |
if ( do_check ) { |
|
syncprov_checkpoint( op, rs, on ); |
|
} |
|
} |
} |
ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex ); |
ldap_pvt_thread_mutex_unlock( &si->si_csn_mutex ); |
|
|
opc->sctxcsn.bv_len = maxcsn.bv_len; |
opc->sctxcsn.bv_len = maxcsn.bv_len; |
opc->sctxcsn.bv_val = cbuf; |
opc->sctxcsn.bv_val = cbuf; |
|
|
|
if ( do_check ) { |
|
syncprov_checkpoint( op, rs, on, &opc->sctxcsn ); |
|
} |
|
|
/* Handle any persistent searches */ |
/* Handle any persistent searches */ |
if ( si->si_ops ) { |
if ( si->si_ops ) { |
switch(op->o_tag) { |
switch(op->o_tag) { |
Line 1785 syncprov_detach_op( Operation *op, synco
|
Line 1811 syncprov_detach_op( Operation *op, synco
|
op2->ors_filterstr.bv_val = ptr; |
op2->ors_filterstr.bv_val = ptr; |
strcpy( ptr, so->s_filterstr.bv_val ); |
strcpy( ptr, so->s_filterstr.bv_val ); |
op2->ors_filterstr.bv_len = so->s_filterstr.bv_len; |
op2->ors_filterstr.bv_len = so->s_filterstr.bv_len; |
op2->ors_filter = filter_dup( op->ors_filter, NULL ); |
|
|
/* Skip the AND/GE clause that we stuck on in front */ |
|
if ( so->s_flags & PS_FIX_FILTER ) { |
|
op2->ors_filter = op->ors_filter->f_and->f_next; |
|
so->s_flags ^= PS_FIX_FILTER; |
|
} else { |
|
op2->ors_filter = op->ors_filter; |
|
} |
|
op2->ors_filter = filter_dup( op2->ors_filter, NULL ); |
so->s_op = op2; |
so->s_op = op2; |
|
|
/* Copy any cached group ACLs individually */ |
/* Copy any cached group ACLs individually */ |
Line 1877 syncprov_search_response( Operation *op,
|
Line 1911 syncprov_search_response( Operation *op,
|
op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); |
op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); |
} else { |
} else { |
/* It's RefreshAndPersist, transition to Persist phase */ |
/* It's RefreshAndPersist, transition to Persist phase */ |
syncprov_sendinfo( op, rs, ( ss->ss_present && rs->sr_nentries ) ? |
syncprov_sendinfo( op, rs, ss->ss_present ? |
LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE, |
LDAP_TAG_SYNC_REFRESH_PRESENT : LDAP_TAG_SYNC_REFRESH_DELETE, |
&cookie, 1, NULL, 0 ); |
&cookie, 1, NULL, 0 ); |
op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); |
op->o_tmpfree( cookie.bv_val, op->o_tmpmemctx ); |
Line 1889 syncprov_search_response( Operation *op,
|
Line 1923 syncprov_search_response( Operation *op,
|
ss->ss_so->s_flags ^= PS_IS_REFRESHING; |
ss->ss_so->s_flags ^= PS_IS_REFRESHING; |
|
|
syncprov_detach_op( op, ss->ss_so, on ); |
syncprov_detach_op( op, ss->ss_so, on ); |
|
|
|
/* If there are queued responses, fire them off */ |
|
if ( ss->ss_so->s_res ) |
|
syncprov_qstart( ss->ss_so ); |
ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); |
ldap_pvt_thread_mutex_unlock( &ss->ss_so->s_mutex ); |
|
|
return LDAP_SUCCESS; |
return LDAP_SUCCESS; |
Line 1996 syncprov_op_search( Operation *op, SlapR
|
Line 2034 syncprov_op_search( Operation *op, SlapR
|
sl=si->si_logs; |
sl=si->si_logs; |
if ( sl ) { |
if ( sl ) { |
ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); |
ldap_pvt_thread_mutex_lock( &sl->sl_mutex ); |
if ( ber_bvcmp( &srs->sr_state.ctxcsn, &sl->sl_mincsn ) >= 0 ) { |
/* Are there any log entries, and is the consumer state |
|
* present in the session log? |
|
*/ |
|
if ( sl->sl_num > 0 && ber_bvcmp( &srs->sr_state.ctxcsn, &sl->sl_mincsn ) >= 0 ) { |
do_present = 0; |
do_present = 0; |
/* mutex is unlocked in playlog */ |
/* mutex is unlocked in playlog */ |
syncprov_playlog( op, rs, sl, srs, &ctxcsn ); |
syncprov_playlog( op, rs, sl, srs, &ctxcsn ); |
Line 2050 shortcut:
|
Line 2091 shortcut:
|
fava->f_next = op->ors_filter; |
fava->f_next = op->ors_filter; |
op->ors_filter = fand; |
op->ors_filter = fand; |
filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); |
filter2bv_x( op, op->ors_filter, &op->ors_filterstr ); |
|
if ( sop ) |
|
sop->s_flags |= PS_FIX_FILTER; |
} |
} |
|
|
/* Let our callback add needed info to returned entries */ |
/* Let our callback add needed info to returned entries */ |
Line 2107 syncprov_operational(
|
Line 2150 syncprov_operational(
|
if ( !a ) { |
if ( !a ) { |
for ( ap = &rs->sr_operational_attrs; *ap; ap=&(*ap)->a_next ); |
for ( ap = &rs->sr_operational_attrs; *ap; ap=&(*ap)->a_next ); |
|
|
a = ch_malloc( sizeof(Attribute)); |
a = attr_alloc( slap_schema.si_ad_contextCSN ); |
a->a_desc = slap_schema.si_ad_contextCSN; |
|
a->a_vals = ch_malloc( 2 * sizeof(struct berval)); |
a->a_vals = ch_malloc( 2 * sizeof(struct berval)); |
a->a_vals[1].bv_val = NULL; |
a->a_vals[1].bv_val = NULL; |
a->a_nvals = a->a_vals; |
a->a_nvals = a->a_vals; |
a->a_next = NULL; |
|
a->a_flags = 0; |
|
*ap = a; |
*ap = a; |
} |
} |
|
|
Line 2241 sp_cf_gen(ConfigArgs *c)
|
Line 2281 sp_cf_gen(ConfigArgs *c)
|
switch ( c->type ) { |
switch ( c->type ) { |
case SP_CHKPT: |
case SP_CHKPT: |
if ( lutil_atoi( &si->si_chkops, c->argv[1] ) != 0 ) { |
if ( lutil_atoi( &si->si_chkops, c->argv[1] ) != 0 ) { |
sprintf( c->msg, "%s unable to parse checkpoint ops # \"%s\"", |
snprintf( c->msg, sizeof( c->msg ), "%s unable to parse checkpoint ops # \"%s\"", |
c->argv[0], c->argv[1] ); |
c->argv[0], c->argv[1] ); |
Debug( LDAP_DEBUG_CONFIG, "%s: %s\n", c->log, c->msg, 0 ); |
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, |
|
"%s: %s\n", c->log, c->msg, 0 ); |
return ARG_BAD_CONF; |
return ARG_BAD_CONF; |
} |
} |
if ( si->si_chkops <= 0 ) { |
if ( si->si_chkops <= 0 ) { |
sprintf( c->msg, "%s invalid checkpoint ops # \"%d\"", |
snprintf( c->msg, sizeof( c->msg ), "%s invalid checkpoint ops # \"%d\"", |
c->argv[0], si->si_chkops ); |
c->argv[0], si->si_chkops ); |
Debug( LDAP_DEBUG_CONFIG, "%s: %s\n", c->log, c->msg, 0 ); |
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, |
|
"%s: %s\n", c->log, c->msg, 0 ); |
return ARG_BAD_CONF; |
return ARG_BAD_CONF; |
} |
} |
if ( lutil_atoi( &si->si_chktime, c->argv[2] ) != 0 ) { |
if ( lutil_atoi( &si->si_chktime, c->argv[2] ) != 0 ) { |
sprintf( c->msg, "%s unable to parse checkpoint time \"%s\"", |
snprintf( c->msg, sizeof( c->msg ), "%s unable to parse checkpoint time \"%s\"", |
c->argv[0], c->argv[1] ); |
c->argv[0], c->argv[1] ); |
Debug( LDAP_DEBUG_CONFIG, "%s: %s\n", c->log, c->msg, 0 ); |
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, |
|
"%s: %s\n", c->log, c->msg, 0 ); |
return ARG_BAD_CONF; |
return ARG_BAD_CONF; |
} |
} |
if ( si->si_chktime <= 0 ) { |
if ( si->si_chktime <= 0 ) { |
sprintf( c->msg, "%s invalid checkpoint time \"%d\"", |
snprintf( c->msg, sizeof( c->msg ), "%s invalid checkpoint time \"%d\"", |
c->argv[0], si->si_chkops ); |
c->argv[0], si->si_chkops ); |
Debug( LDAP_DEBUG_CONFIG, "%s: %s\n", c->log, c->msg, 0 ); |
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, |
|
"%s: %s\n", c->log, c->msg, 0 ); |
return ARG_BAD_CONF; |
return ARG_BAD_CONF; |
} |
} |
si->si_chktime *= 60; |
si->si_chktime *= 60; |
Line 2271 sp_cf_gen(ConfigArgs *c)
|
Line 2315 sp_cf_gen(ConfigArgs *c)
|
int size = c->value_int; |
int size = c->value_int; |
|
|
if ( size < 0 ) { |
if ( size < 0 ) { |
sprintf( c->msg, "%s size %d is negative", |
snprintf( c->msg, sizeof( c->msg ), "%s size %d is negative", |
c->argv[0], size ); |
c->argv[0], size ); |
Debug( LDAP_DEBUG_CONFIG, "%s: %s\n", c->log, c->msg, 0 ); |
Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE, |
|
"%s: %s\n", c->log, c->msg, 0 ); |
return ARG_BAD_CONF; |
return ARG_BAD_CONF; |
} |
} |
sl = si->si_logs; |
sl = si->si_logs; |
Line 2433 syncprov_db_close(
|
Line 2478 syncprov_db_close(
|
op->o_bd = be; |
op->o_bd = be; |
op->o_dn = be->be_rootdn; |
op->o_dn = be->be_rootdn; |
op->o_ndn = be->be_rootndn; |
op->o_ndn = be->be_rootndn; |
syncprov_checkpoint( op, &rs, on ); |
syncprov_checkpoint( op, &rs, on, &si->si_ctxcsn ); |
ldap_pvt_thread_pool_context_reset( thrctx ); |
ldap_pvt_thread_pool_context_reset( thrctx ); |
} |
} |
|
|
Line 2448 syncprov_db_init(
|
Line 2493 syncprov_db_init(
|
slap_overinst *on = (slap_overinst *)be->bd_info; |
slap_overinst *on = (slap_overinst *)be->bd_info; |
syncprov_info_t *si; |
syncprov_info_t *si; |
|
|
|
if ( SLAP_ISGLOBALOVERLAY( be ) ) { |
|
Debug( LDAP_DEBUG_ANY, |
|
"syncprov must be instantiated within a database.\n", |
|
0, 0, 0 ); |
|
return 1; |
|
} |
|
|
si = ch_calloc(1, sizeof(syncprov_info_t)); |
si = ch_calloc(1, sizeof(syncprov_info_t)); |
on->on_bi.bi_private = si; |
on->on_bi.bi_private = si; |
ldap_pvt_thread_mutex_init( &si->si_csn_mutex ); |
ldap_pvt_thread_mutex_init( &si->si_csn_mutex ); |