attrs, op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto cleanup;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
done:;
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
return rs->sr_err;
}
#define META_ANONYMOUS 2
#endif
- time_t msc_create_time;
- time_t msc_time;
-
struct metainfo_t *msc_info;
} metasingleconn_t;
typedef struct metaconn_t {
struct slap_conn *mc_conn;
- ldap_pvt_thread_mutex_t mc_mutex;
unsigned mc_refcnt;
- int mc_tainted;
+
+ time_t mc_create_time;
+ time_t mc_time;
struct berval mc_local_ndn;
/* NOTE: msc_mscflags is used to recycle the #define
unsigned mt_flags;
int mt_version;
time_t mt_network_timeout;
- time_t mt_conn_ttl;
- time_t mt_idle_timeout;
struct timeval mt_bind_timeout;
#define META_BIND_TIMEOUT LDAP_BACK_RESULT_UTIMEOUT
time_t mt_timeout[ LDAP_BACK_OP_LAST ];
ldap_back_send_t sendok );
extern void
-meta_back_release_conn(
+meta_back_release_conn_lock(
Operation *op,
- metaconn_t *mc );
+ metaconn_t *mc,
+ int dolock );
+#define meta_back_release_conn(op, mc) meta_back_release_conn_lock( (op), (mc), 1 )
extern int
-meta_back_retry_lock(
+meta_back_retry(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
+ metaconn_t **mcp,
int candidate,
- ldap_back_send_t sendok,
- int dolock );
-#define meta_back_retry(op, rs, mc, candidate, sendok) \
- meta_back_retry_lock((op), (rs), (mc), (candidate), (sendok), 1)
+ ldap_back_send_t sendok );
extern void
meta_back_conn_free(
const void *c2 );
extern int
-meta_back_dnconn_cmp(
+meta_back_conndn_cmp(
const void *c1,
const void *c2 );
extern int
-meta_back_dnconn_dup(
+meta_back_conndn_dup(
void *c1,
void *c2 );
}
if ( !dn_match( &op->o_req_ndn, &mc->mc_local_ndn ) ) {
+ metaconn_t *tmpmc;
int lerr;
/* wait for all other ops to release the connection */
}
assert( mc->mc_refcnt == 1 );
- mc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_dnconn_cmp );
- assert( mc != NULL );
+ tmpmc = avl_delete( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
+ meta_back_conndn_cmp );
+ assert( tmpmc == mc );
ber_bvreplace( &mc->mc_local_ndn, &op->o_req_ndn );
lerr = avl_insert( &mi->mi_conninfo.lai_tree, (caddr_t)mc,
- meta_back_dnconn_cmp, meta_back_dnconn_dup );
+ meta_back_conndn_cmp, meta_back_conndn_dup );
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
if ( lerr == -1 ) {
for ( i = 0; i < mi->mi_ntargets; ++i ) {
rc = slap_map_api2result( rs );
if ( rs->sr_err == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- rc = meta_back_retry( op, rs, mc, candidate, LDAP_BACK_DONTSEND );
+ rc = meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_DONTSEND );
if ( rc ) {
if ( nretries > 0 ) {
nretries--;
ldap_pvt_thread_yield();
goto rebind;
}
+ goto return_results;
}
break;
rc = slap_map_api2result( rs );
if ( rc == LDAP_UNAVAILABLE && nretries != META_RETRY_NEVER ) {
- /* NOTE: we do not use meta_back_retry() here
- * to avoid circular loops; mc_mutex is set
- * by the caller */
if ( dolock ) {
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
}
LDAP_BACK_PCONN_ID( mc->mc_conn ),
isroot ? " (isroot)" : "" );
- ldap_pvt_thread_mutex_lock( &mc->mc_mutex );
-
/*
* all the targets are bound as pseudoroot
*/
if ( rc == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry_lock( op, rs, mc, i, LDAP_BACK_DONTSEND, 0 ) ) {
+ if ( meta_back_retry( op, rs, &mc, i, sendok ) ) {
goto retry;
}
+ return 0;
}
snprintf( buf, sizeof( buf ),
}
done:;
- ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
-
Debug( LDAP_DEBUG_TRACE,
"%s meta_back_dobind: conn=%ld bound=%d\n",
op->o_log_prefix, LDAP_BACK_PCONN_ID( mc->mc_conn ), bound );
mi->mi_targets[ i ].mt_flags = mi->mi_flags;
mi->mi_targets[ i ].mt_version = mi->mi_version;
mi->mi_targets[ i ].mt_network_timeout = mi->mi_network_timeout;
- mi->mi_targets[ i ].mt_conn_ttl = mi->mi_conn_ttl;
- mi->mi_targets[ i ].mt_idle_timeout = mi->mi_idle_timeout;
mi->mi_targets[ i ].mt_bind_timeout = mi->mi_bind_timeout;
for ( c = 0; c < LDAP_BACK_OP_LAST; c++ ) {
mi->mi_targets[ i ].mt_timeout[ c ] = mi->mi_timeout[ c ];
/* idle timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "idle-timeout" ) == 0 ) {
unsigned long t;
- time_t *tp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_idle_timeout
- : &mi->mi_idle_timeout;
switch ( argc ) {
case 1:
}
- *tp = (time_t)t;
+ mi->mi_idle_timeout = (time_t)t;
/* conn ttl */
} else if ( strcasecmp( argv[ 0 ], "conn-ttl" ) == 0 ) {
unsigned long t;
- time_t *tp = mi->mi_ntargets ?
- &mi->mi_targets[ mi->mi_ntargets - 1 ].mt_conn_ttl
- : &mi->mi_conn_ttl;
switch ( argc ) {
case 1:
}
- *tp = (time_t)t;
+ mi->mi_conn_ttl = (time_t)t;
/* bind timeout when connecting to ldap servers */
} else if ( strcasecmp( argv[ 0 ], "bind-timeout" ) == 0 ) {
#define PRINT_CONNTREE 0
/*
- * meta_back_dnconn_cmp
+ * meta_back_conndn_cmp
*
* compares two struct metaconn based on the value of the conn pointer
* and of the local DN; used by avl stuff
*/
int
-meta_back_dnconn_cmp(
+meta_back_conndn_cmp(
const void *c1,
const void *c2 )
{
return rc;
}
+/*
+ * meta_back_conndnmc_cmp
+ *
+ * compares two struct metaconn based on the value of the conn pointer,
+ * the local DN and the struct pointer; used by avl stuff
+ */
+static int
+meta_back_conndnmc_cmp(
+ const void *c1,
+ const void *c2 )
+{
+ metaconn_t *mc1 = ( metaconn_t * )c1;
+ metaconn_t *mc2 = ( metaconn_t * )c2;
+ int rc;
+
+ /* If local DNs don't match, it is definitely not a match */
+ /* For shared sessions, conn is NULL. Only explicitly
+ * bound sessions will have non-NULL conn.
+ */
+ rc = SLAP_PTRCMP( mc1->mc_conn, mc2->mc_conn );
+ if ( rc == 0 ) {
+ rc = ber_bvcmp( &mc1->mc_local_ndn, &mc2->mc_local_ndn );
+ if ( rc == 0 ) {
+ rc = SLAP_PTRCMP( mc1, mc2 );
+ }
+ }
+
+ return rc;
+}
+
/*
* meta_back_conn_cmp
*
}
/*
- * meta_back_dnconn_dup
+ * meta_back_conndn_dup
*
* returns -1 in case a duplicate struct metaconn has been inserted;
* used by avl stuff
*/
int
-meta_back_dnconn_dup(
+meta_back_conndn_dup(
void *c1,
void *c2 )
{
BER_BVZERO( &mc->mc_local_ndn );
mc->msc_mscflags = 0;
mc->mc_authz_target = META_BOUND_NONE;
- ldap_pvt_thread_mutex_init( &mc->mc_mutex );
mc->mc_refcnt = 1;
- mc->mc_tainted = 0;
return mc;
}
* Already init'ed
*/
if ( msc->msc_ld != NULL ) {
- int doreturn = 1;
-
- if ( ( mt->mt_idle_timeout != 0 && op->o_time > msc->msc_time + mt->mt_idle_timeout )
- || ( mt->mt_conn_ttl != 0 && op->o_time > msc->msc_create_time + mt->mt_conn_ttl ) )
- {
- Debug( LDAP_DEBUG_TRACE,
- "%s meta_back_init_one_conn[%d]: idle timeout/ttl.\n",
- op->o_log_prefix, candidate, 0 );
- if ( meta_back_retry( op, rs, mc, candidate, sendok ) ) {
- return rs->sr_err;
- }
-
- doreturn = 0;
- }
-
- if ( mt->mt_idle_timeout != 0 ) {
- msc->msc_time = op->o_time;
- }
-
- if ( doreturn ) {
- return rs->sr_err = LDAP_SUCCESS;
- }
+ return rs->sr_err = LDAP_SUCCESS;
}
/*
*/
( void )rewrite_session_init( mt->mt_rwmap.rwm_rw, op->o_conn );
- if ( mt->mt_idle_timeout ) {
- msc->msc_time = op->o_time;
- }
-
- if ( mt->mt_conn_ttl ) {
- msc->msc_create_time = op->o_time;
- }
-
} else {
rs->sr_err = slap_map_api2result( rs );
if ( sendok & LDAP_BACK_SENDERR ) {
}
/*
- * meta_back_retry_lock
+ * meta_back_retry
*
* Retries one connection
*/
int
-meta_back_retry_lock(
+meta_back_retry(
Operation *op,
SlapReply *rs,
- metaconn_t *mc,
+ metaconn_t **mcp,
int candidate,
- ldap_back_send_t sendok,
- int dolock )
+ ldap_back_send_t sendok )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
metatarget_t *mt = &mi->mi_targets[ candidate ];
int rc = LDAP_UNAVAILABLE;
+ metaconn_t *mc = *mcp;
metasingleconn_t *msc = &mc->mc_conns[ candidate ];
-retry_lock:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
assert( mc->mc_refcnt > 0 );
-
if ( mc->mc_refcnt == 1 ) {
char buf[ SLAP_TEXT_BUFLEN ];
- while ( dolock && ldap_pvt_thread_mutex_trylock( &mc->mc_mutex ) ) {
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- ldap_pvt_thread_yield();
- goto retry_lock;
- }
-
snprintf( buf, sizeof( buf ),
"retrying URI=\"%s\" DN=\"%s\"",
mt->mt_uri,
}
}
- if ( dolock ) {
- ldap_pvt_thread_mutex_unlock( &mc->mc_mutex );
- }
- }
+ } else {
+ meta_back_release_conn_lock( op, mc, 0 );
+ *mcp = NULL;
- if ( rc != LDAP_SUCCESS ) {
- mc->mc_tainted = 1;
+ if ( sendok ) {
+ rs->sr_err = LDAP_UNAVAILABLE;
+ rs->sr_text = "unable to retry";
+ send_ldap_result( op, rs );
+ }
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
meta_op_type op_type = META_OP_REQUIRE_SINGLE;
- int parent = 0,
- newparent = 0;
+ enum {
+ META_DNTYPE_ENTRY,
+ META_DNTYPE_PARENT,
+ META_DNTYPE_NEWPARENT
+ } dn_type = META_DNTYPE_ENTRY;
struct berval ndn = op->o_req_ndn,
pndn;
retry_lock:
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
- (caddr_t)&mc_curr, meta_back_dnconn_cmp );
+ (caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc ) {
- if ( mc->mc_tainted ) {
- rs->sr_err = LDAP_UNAVAILABLE;
- rs->sr_text = "remote server unavailable";
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
- return NULL;
+ if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+ || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ {
+ /* don't let anyone else use this expired connection */
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ (caddr_t)mc, meta_back_conndnmc_cmp );
+
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_getconn: mc=%p conn=%ld expired.\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
}
-
+
/* Don't reuse connections while they're still binding */
if ( LDAP_BACK_CONN_BINDING( mc ) ) {
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
ldap_pvt_thread_yield();
goto retry_lock;
}
+
mc->mc_refcnt++;
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
case LDAP_REQ_ADD:
/* if we go to selection, the entry must not exist,
* and we must be able to resolve the parent */
- parent = 1;
+ dn_type = META_DNTYPE_PARENT;
dnParent( &ndn, &pndn );
break;
/* if nnewSuperior is not NULL, it must resolve
* to the same candidate as the req_ndn */
if ( op->orr_nnewSup ) {
- newparent = 1;
+ dn_type = META_DNTYPE_NEWPARENT;
}
break;
if ( i == META_TARGET_NONE ) {
i = meta_back_get_candidate( op, rs, &ndn );
- if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && parent ) {
+ if ( rs->sr_err == LDAP_NO_SUCH_OBJECT && dn_type == META_DNTYPE_PARENT ) {
i = meta_back_get_candidate( op, rs, &pndn );
}
}
}
- if ( newparent && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
+ if ( dn_type == META_DNTYPE_NEWPARENT && meta_back_get_candidate( op, rs, op->orr_nnewSup ) != i )
{
if ( mc != NULL ) {
meta_back_release_conn( op, mc );
* the reason is that the connection might have been
* created by meta_back_get_candidate() */
if ( !( sendok & LDAP_BACK_BINDING ) ) {
+retry_lock2:;
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
mc = (metaconn_t *)avl_find( mi->mi_conninfo.lai_tree,
- (caddr_t)&mc_curr, meta_back_dnconn_cmp );
+ (caddr_t)&mc_curr, meta_back_conndn_cmp );
if ( mc != NULL ) {
+ /* Don't reuse connections while they're still binding */
+ if ( LDAP_BACK_CONN_BINDING( mc ) ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
+ ldap_pvt_thread_yield();
+ goto retry_lock2;
+ }
+
mc->mc_refcnt++;
}
ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
rs->sr_err = LDAP_SUCCESS;
rs->sr_text = NULL;
+ /* touch the timestamp */
+ if ( mi->mi_idle_timeout != 0 ) {
+ mc->mc_time = op->o_time;
+ }
+
if ( new_conn ) {
+ if ( mi->mi_conn_ttl ) {
+ mc->mc_create_time = op->o_time;
+ }
+
/*
* Inserts the newly created metaconn in the avl tree
*/
ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
err = avl_insert( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
- meta_back_dnconn_cmp, meta_back_dnconn_dup );
+ meta_back_conndn_cmp, meta_back_conndn_dup );
#if PRINT_CONNTREE > 0
myprint( mi->mi_conninfo.lai_tree );
}
void
-meta_back_release_conn(
+meta_back_release_conn_lock(
Operation *op,
- metaconn_t *mc )
+ metaconn_t *mc,
+ int dolock )
{
metainfo_t *mi = ( metainfo_t * )op->o_bd->be_private;
assert( mc != NULL );
- ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_lock( &mi->mi_conninfo.lai_mutex );
+ }
assert( mc->mc_refcnt > 0 );
mc->mc_refcnt--;
LDAP_BACK_CONN_BINDING_CLEAR( mc );
- if ( mc->mc_refcnt == 0 && mc->mc_tainted ) {
- (void)avl_delete( &mi->mi_conninfo.lai_tree, ( caddr_t )mc,
- meta_back_dnconn_cmp );
- meta_back_conn_free( mc );
+ if ( ( mi->mi_conn_ttl != 0 && op->o_time > mc->mc_create_time + mi->mi_conn_ttl )
+ || ( mi->mi_idle_timeout != 0 && op->o_time > mc->mc_time + mi->mi_idle_timeout ) )
+ {
+ Debug( LDAP_DEBUG_TRACE, "%s meta_back_release_conn: mc=%p conn=%ld expired.\n",
+ op->o_log_prefix, (void *)mc, LDAP_BACK_PCONN_ID( mc->mc_conn ) );
+ (void)avl_delete( &mi->mi_conninfo.lai_tree,
+ ( caddr_t )mc, meta_back_conndnmc_cmp );
+ if ( mc->mc_refcnt == 0 ) {
+ meta_back_conn_free( mc );
+ }
+ }
+ if ( dolock ) {
+ ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
- ldap_pvt_thread_mutex_unlock( &mi->mi_conninfo.lai_mutex );
}
mdn.bv_val, op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto cleanup;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
done:;
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
return rs->sr_err;
}
(void)meta_clear_one_candidate( &mc->mc_conns[ i ] );
}
- ldap_pvt_thread_mutex_destroy( &mc->mc_mutex );
free( mc );
}
modv, op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto done;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
cleanup:;
+ if ( maperr ) {
+ rc = meta_back_op_result( mc, op, rs, candidate );
+
+ } else {
+ send_ldap_result( op, rs );
+ }
+
+done:;
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
free( mods );
free( modv );
- if ( maperr ) {
- rc = meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
}
- meta_back_release_conn( op, mc );
-
return rs->sr_err;
}
op->o_ctrls, NULL, &msgid );
if ( rs->sr_err == LDAP_UNAVAILABLE && do_retry ) {
do_retry = 0;
- if ( meta_back_retry( op, rs, mc, candidate, LDAP_BACK_SENDERR ) ) {
+ if ( meta_back_retry( op, rs, &mc, candidate, LDAP_BACK_SENDERR ) ) {
goto retry;
}
+ goto done;
} else if ( rs->sr_err == LDAP_SUCCESS ) {
struct timeval tv, *tvp = NULL;
}
cleanup:;
+ if ( maperr ) {
+ meta_back_op_result( mc, op, rs, candidate );
+
+ } else {
+ send_ldap_result( op, rs );
+ }
+
+done:;
if ( mdn.bv_val != op->o_req_dn.bv_val ) {
free( mdn.bv_val );
BER_BVZERO( &mdn );
BER_BVZERO( &mnewSuperior );
}
- if ( maperr ) {
- meta_back_op_result( mc, op, rs, candidate );
-
- } else {
- send_ldap_result( op, rs );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
}
- meta_back_release_conn( op, mc );
-
return rs->sr_err;
}
if ( candidates[ i ].sr_type == REP_INTERMEDIATE ) {
candidates[ i ].sr_type = REP_RESULT;
- if ( meta_back_retry( op, rs, mc, i, LDAP_BACK_DONTSEND ) ) {
+ if ( meta_back_retry( op, rs, &mc, i, LDAP_BACK_DONTSEND ) ) {
switch ( meta_back_search_start( op, rs, &dc, msc, i, candidates ) )
{
case META_SEARCH_CANDIDATE:
goto finish;
}
}
+
+ savepriv = op->o_private;
+ op->o_private = (void *)i;
+ send_ldap_result( op, rs );
+ op->o_private = savepriv;
+ goto finish;
}
/*
}
}
- meta_back_release_conn( op, mc );
+ if ( mc ) {
+ meta_back_release_conn( op, mc );
+ }
return rs->sr_err;
}