tier_roundrobin.c revision 1.1 1 /* $NetBSD: tier_roundrobin.c,v 1.1 2025/09/05 21:09:46 christos Exp $ */
2
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1998-2024 The OpenLDAP Foundation.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
11 * Public License.
12 *
13 * A copy of this license is available in the file LICENSE in the
14 * top-level directory of the distribution or, alternatively, at
15 * <http://www.OpenLDAP.org/license.html>.
16 */
17
18 #include <sys/cdefs.h>
19 __RCSID("$NetBSD: tier_roundrobin.c,v 1.1 2025/09/05 21:09:46 christos Exp $");
20
21 #include "portable.h"
22
23 #include "lload.h"
24
25 static LloadTierInit roundrobin_init;
26 static LloadTierBackendCb roundrobin_add_backend;
27 static LloadTierBackendCb roundrobin_remove_backend;
28 static LloadTierSelect roundrobin_select;
29
30 struct lload_tier_type roundrobin_tier;
31
32 static LloadTier *
33 roundrobin_init( void )
34 {
35 LloadTier *tier;
36
37 tier = ch_calloc( 1, sizeof(LloadTier) );
38
39 tier->t_type = roundrobin_tier;
40 ldap_pvt_thread_mutex_init( &tier->t_mutex );
41 LDAP_CIRCLEQ_INIT( &tier->t_backends );
42
43 return tier;
44 }
45
46 static int
47 roundrobin_add_backend( LloadTier *tier, LloadBackend *b )
48 {
49 assert( b->b_tier == tier );
50 LDAP_CIRCLEQ_INSERT_TAIL( &tier->t_backends, b, b_next );
51 if ( !tier->t_private ) {
52 tier->t_private = b;
53 }
54 tier->t_nbackends++;
55 return LDAP_SUCCESS;
56 }
57
58 static int
59 roundrobin_remove_backend( LloadTier *tier, LloadBackend *b )
60 {
61 LloadBackend *next = LDAP_CIRCLEQ_LOOP_NEXT( &tier->t_backends, b, b_next );
62
63 assert_locked( &tier->t_mutex );
64 assert_locked( &b->b_mutex );
65
66 assert( b->b_tier == tier );
67
68 LDAP_CIRCLEQ_REMOVE( &tier->t_backends, b, b_next );
69 if ( b == tier->t_private ) {
70 if ( tier->t_nbackends ) {
71 tier->t_private = next;
72 } else {
73 assert( b == next );
74 tier->t_private = NULL;
75 }
76 }
77 tier->t_nbackends--;
78 return LDAP_SUCCESS;
79 }
80
81 static int
82 roundrobin_select(
83 LloadTier *tier,
84 LloadOperation *op,
85 LloadConnection **cp,
86 int *res,
87 char **message )
88 {
89 LloadBackend *b, *first, *next;
90 int rc = 0;
91
92 checked_lock( &tier->t_mutex );
93 first = b = tier->t_private;
94 checked_unlock( &tier->t_mutex );
95
96 if ( !first ) return rc;
97
98 do {
99 int result;
100
101 checked_lock( &b->b_mutex );
102 next = LDAP_CIRCLEQ_LOOP_NEXT( &tier->t_backends, b, b_next );
103
104 result = backend_select( b, op, cp, res, message );
105 checked_unlock( &b->b_mutex );
106
107 rc |= result;
108 if ( result && *cp ) {
109 /*
110 * Round-robin step:
111 * Rotate the queue to put this backend at the end. The race here
112 * is acceptable.
113 */
114 checked_lock( &tier->t_mutex );
115 tier->t_private = next;
116 checked_unlock( &tier->t_mutex );
117 return rc;
118 }
119
120 b = next;
121 } while ( b != first );
122
123 return rc;
124 }
125
126 struct lload_tier_type roundrobin_tier = {
127 .tier_name = "roundrobin",
128
129 .tier_init = roundrobin_init,
130 .tier_startup = tier_startup,
131 .tier_reset = tier_reset,
132 .tier_destroy = tier_destroy,
133
134 .tier_oc = BER_BVC("olcBkLloadTierConfig"),
135 .tier_backend_oc = BER_BVC("olcBkLloadBackendConfig"),
136
137 .tier_add_backend = roundrobin_add_backend,
138 .tier_remove_backend = roundrobin_remove_backend,
139
140 .tier_select = roundrobin_select,
141 };
142