diff options
Diffstat (limited to '')
-rw-r--r-- | servers/lloadd/tier_roundrobin.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/servers/lloadd/tier_roundrobin.c b/servers/lloadd/tier_roundrobin.c new file mode 100644 index 0000000..d299fb9 --- /dev/null +++ b/servers/lloadd/tier_roundrobin.c @@ -0,0 +1,136 @@ +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software <http://www.openldap.org/>. + * + * 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 + * <http://www.OpenLDAP.org/license.html>. + */ + +#include "portable.h" + +#include "lload.h" + +static LloadTierInit roundrobin_init; +static LloadTierBackendCb roundrobin_add_backend; +static LloadTierBackendCb roundrobin_remove_backend; +static LloadTierSelect roundrobin_select; + +struct lload_tier_type roundrobin_tier; + +static LloadTier * +roundrobin_init( void ) +{ + LloadTier *tier; + + tier = ch_calloc( 1, sizeof(LloadTier) ); + + tier->t_type = roundrobin_tier; + ldap_pvt_thread_mutex_init( &tier->t_mutex ); + LDAP_CIRCLEQ_INIT( &tier->t_backends ); + + return tier; +} + +static int +roundrobin_add_backend( LloadTier *tier, LloadBackend *b ) +{ + assert( b->b_tier == tier ); + LDAP_CIRCLEQ_INSERT_TAIL( &tier->t_backends, b, b_next ); + if ( !tier->t_private ) { + tier->t_private = b; + } + tier->t_nbackends++; + return LDAP_SUCCESS; +} + +static int +roundrobin_remove_backend( LloadTier *tier, LloadBackend *b ) +{ + LloadBackend *next = LDAP_CIRCLEQ_LOOP_NEXT( &tier->t_backends, b, b_next ); + + assert_locked( &tier->t_mutex ); + assert_locked( &b->b_mutex ); + + assert( b->b_tier == tier ); + + LDAP_CIRCLEQ_REMOVE( &tier->t_backends, b, b_next ); + if ( b == tier->t_private ) { + if ( tier->t_nbackends ) { + tier->t_private = next; + } else { + assert( b == next ); + tier->t_private = NULL; + } + } + tier->t_nbackends--; + return LDAP_SUCCESS; +} + +static int +roundrobin_select( + LloadTier *tier, + LloadOperation *op, + LloadConnection **cp, + int *res, + char **message ) +{ + LloadBackend *b, *first, *next; + int rc = 0; + + checked_lock( &tier->t_mutex ); + first = b = tier->t_private; + checked_unlock( &tier->t_mutex ); + + if ( !first ) return rc; + + do { + int result; + + checked_lock( &b->b_mutex ); + next = LDAP_CIRCLEQ_LOOP_NEXT( &tier->t_backends, b, b_next ); + + result = backend_select( b, op, cp, res, message ); + checked_unlock( &b->b_mutex ); + + rc |= result; + if ( result && *cp ) { + /* + * Round-robin step: + * Rotate the queue to put this backend at the end. The race here + * is acceptable. + */ + checked_lock( &tier->t_mutex ); + tier->t_private = next; + checked_unlock( &tier->t_mutex ); + return rc; + } + + b = next; + } while ( b != first ); + + return rc; +} + +struct lload_tier_type roundrobin_tier = { + .tier_name = "roundrobin", + + .tier_init = roundrobin_init, + .tier_startup = tier_startup, + .tier_reset = tier_reset, + .tier_destroy = tier_destroy, + + .tier_oc = BER_BVC("olcBkLloadTierConfig"), + .tier_backend_oc = BER_BVC("olcBkLloadBackendConfig"), + + .tier_add_backend = roundrobin_add_backend, + .tier_remove_backend = roundrobin_remove_backend, + + .tier_select = roundrobin_select, +}; |