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