/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software .
*
* Copyright 1998-2022 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
* .
*/
#include "portable.h"
#include "lload.h"
lload_t_head tiers;
int
tier_startup( LloadTier *tier )
{
LloadBackend *b;
LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) {
checked_lock( &b->b_mutex );
if ( !b->b_retry_event ) {
b->b_retry_event = evtimer_new( daemon_base, backend_connect, b );
if ( !b->b_retry_event ) {
Debug( LDAP_DEBUG_ANY, "tier_startup: "
"%s failed to allocate retry event\n",
tier->t_type.tier_name );
return -1;
}
}
backend_retry( b );
checked_unlock( &b->b_mutex );
}
return LDAP_SUCCESS;
}
int
tier_reset( LloadTier *tier, int shutdown )
{
LloadBackend *b;
LDAP_CIRCLEQ_FOREACH ( b, &tier->t_backends, b_next ) {
epoch_t epoch = epoch_join();
checked_lock( &b->b_mutex );
if ( shutdown ) {
b->b_numconns = b->b_numbindconns = 0;
}
backend_reset( b, 1 );
backend_retry( b );
checked_unlock( &b->b_mutex );
epoch_leave( epoch );
}
return LDAP_SUCCESS;
}
int
tier_destroy( LloadTier *tier )
{
while ( !LDAP_CIRCLEQ_EMPTY( &tier->t_backends ) ) {
LloadBackend *b = LDAP_CIRCLEQ_FIRST( &tier->t_backends );
epoch_t epoch = epoch_join();
lload_backend_destroy( b );
epoch_leave( epoch );
}
#ifdef BALANCER_MODULE
if ( tier->t_monitor ) {
/* FIXME: implement proper subsys shutdown in back-monitor or make
* backend just an entry, not a subsys */
if ( slapd_shutdown ) {
/* Just drop backlink, back-monitor will call mss_destroy later */
assert( tier->t_monitor->mss_private == tier );
tier->t_monitor->mss_private = NULL;
} else {
BackendDB *be;
struct berval monitordn = BER_BVC("cn=monitor");
int rc;
be = select_backend( &monitordn, 0 );
rc = tier->t_monitor->mss_destroy( be, tier->t_monitor );
assert( rc == LDAP_SUCCESS );
}
}
#endif /* BALANCER_MODULE */
ch_free( tier->t_name.bv_val );
ch_free( tier );
return LDAP_SUCCESS;
}
void
lload_tiers_destroy( void )
{
while ( !LDAP_STAILQ_EMPTY( &tiers ) ) {
LloadTier *tier = LDAP_STAILQ_FIRST( &tiers );
LDAP_STAILQ_REMOVE_HEAD( &tiers, t_next );
tier->t_type.tier_destroy( tier );
}
}
void
lload_tiers_shutdown( void )
{
lload_tiers_reset( 1 );
}
void
lload_tiers_reset( int shutdown )
{
LloadTier *tier;
LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) {
tier->t_type.tier_reset( tier, shutdown );
}
}
void
lload_tiers_update( evutil_socket_t s, short what, void *arg )
{
LloadTier *tier;
LDAP_STAILQ_FOREACH ( tier, &tiers, t_next ) {
if ( tier->t_type.tier_update ) {
tier->t_type.tier_update( tier );
}
}
}
extern struct lload_tier_type roundrobin_tier;
extern struct lload_tier_type weighted_tier;
extern struct lload_tier_type bestof_tier;
struct {
char *name;
struct lload_tier_type *type;
} tier_types[] = {
{ "roundrobin", &roundrobin_tier },
{ "weighted", &weighted_tier },
{ "bestof", &bestof_tier },
{ NULL }
};
struct lload_tier_type *
lload_tier_find( char *name )
{
int i;
for ( i = 0; tier_types[i].name; i++ ) {
if ( !strcasecmp( name, tier_types[i].name ) ) {
return tier_types[i].type;
}
}
return NULL;
}