/* $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" 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, };