xref: /unit/src/nxt_upstream_round_robin.c (revision 1440:d1ad3857769c)
10Sigor@sysoev.ru 
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru  * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru  * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru  */
60Sigor@sysoev.ru 
7*1440Sigor@sysoev.ru #include <math.h>
81394Sigor@sysoev.ru #include <nxt_router.h>
91394Sigor@sysoev.ru #include <nxt_http.h>
101394Sigor@sysoev.ru #include <nxt_upstream.h>
111394Sigor@sysoev.ru 
121394Sigor@sysoev.ru 
131394Sigor@sysoev.ru struct nxt_upstream_round_robin_server_s {
141394Sigor@sysoev.ru     nxt_sockaddr_t                     *sockaddr;
151394Sigor@sysoev.ru 
161394Sigor@sysoev.ru     int32_t                            current_weight;
171394Sigor@sysoev.ru     int32_t                            effective_weight;
181394Sigor@sysoev.ru     int32_t                            weight;
191394Sigor@sysoev.ru 
201394Sigor@sysoev.ru     uint8_t                            protocol;
211394Sigor@sysoev.ru };
221394Sigor@sysoev.ru 
231394Sigor@sysoev.ru 
241394Sigor@sysoev.ru struct nxt_upstream_round_robin_s {
251394Sigor@sysoev.ru     uint32_t                           items;
261394Sigor@sysoev.ru     nxt_upstream_round_robin_server_t  server[0];
271394Sigor@sysoev.ru };
281394Sigor@sysoev.ru 
291394Sigor@sysoev.ru 
301394Sigor@sysoev.ru static nxt_upstream_t *nxt_upstream_round_robin_joint_create(
311394Sigor@sysoev.ru     nxt_router_temp_conf_t *tmcf, nxt_upstream_t *upstream);
321394Sigor@sysoev.ru static void nxt_upstream_round_robin_server_get(nxt_task_t *task,
331394Sigor@sysoev.ru     nxt_upstream_server_t *us);
341394Sigor@sysoev.ru 
351394Sigor@sysoev.ru 
361394Sigor@sysoev.ru static const nxt_upstream_server_proto_t  nxt_upstream_round_robin_proto = {
371394Sigor@sysoev.ru     .joint_create = nxt_upstream_round_robin_joint_create,
381394Sigor@sysoev.ru     .get          = nxt_upstream_round_robin_server_get,
391394Sigor@sysoev.ru };
401394Sigor@sysoev.ru 
411394Sigor@sysoev.ru 
421394Sigor@sysoev.ru nxt_int_t
nxt_upstream_round_robin_create(nxt_task_t * task,nxt_router_temp_conf_t * tmcf,nxt_conf_value_t * upstream_conf,nxt_upstream_t * upstream)431394Sigor@sysoev.ru nxt_upstream_round_robin_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
441394Sigor@sysoev.ru     nxt_conf_value_t *upstream_conf, nxt_upstream_t *upstream)
451394Sigor@sysoev.ru {
46*1440Sigor@sysoev.ru     double                      total, k, w;
471394Sigor@sysoev.ru     size_t                      size;
48*1440Sigor@sysoev.ru     uint32_t                    i, n, next, wt;
491394Sigor@sysoev.ru     nxt_mp_t                    *mp;
501394Sigor@sysoev.ru     nxt_str_t                   name;
511394Sigor@sysoev.ru     nxt_sockaddr_t              *sa;
52*1440Sigor@sysoev.ru     nxt_conf_value_t            *servers_conf, *srvcf, *wtcf;
531394Sigor@sysoev.ru     nxt_upstream_round_robin_t  *urr;
541394Sigor@sysoev.ru 
551394Sigor@sysoev.ru     static nxt_str_t  servers = nxt_string("servers");
56*1440Sigor@sysoev.ru     static nxt_str_t  weight = nxt_string("weight");
571394Sigor@sysoev.ru 
581394Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
591394Sigor@sysoev.ru 
601394Sigor@sysoev.ru     servers_conf = nxt_conf_get_object_member(upstream_conf, &servers, NULL);
611394Sigor@sysoev.ru     n = nxt_conf_object_members_count(servers_conf);
621394Sigor@sysoev.ru 
63*1440Sigor@sysoev.ru     total = 0.0;
64*1440Sigor@sysoev.ru     next = 0;
65*1440Sigor@sysoev.ru 
66*1440Sigor@sysoev.ru     for (i = 0; i < n; i++) {
67*1440Sigor@sysoev.ru         srvcf = nxt_conf_next_object_member(servers_conf, &name, &next);
68*1440Sigor@sysoev.ru         wtcf = nxt_conf_get_object_member(srvcf, &weight, NULL);
69*1440Sigor@sysoev.ru         w = (wtcf != NULL) ? nxt_conf_get_number(wtcf) : 1;
70*1440Sigor@sysoev.ru         total += w;
71*1440Sigor@sysoev.ru     }
72*1440Sigor@sysoev.ru 
73*1440Sigor@sysoev.ru     /*
74*1440Sigor@sysoev.ru      * This prevents overflow of int32_t
75*1440Sigor@sysoev.ru      * in nxt_upstream_round_robin_server_get().
76*1440Sigor@sysoev.ru      */
77*1440Sigor@sysoev.ru     k = (total == 0) ? 0 : (NXT_INT32_T_MAX / 2) / total;
78*1440Sigor@sysoev.ru 
79*1440Sigor@sysoev.ru     if (isinf(k)) {
80*1440Sigor@sysoev.ru         k = 1;
81*1440Sigor@sysoev.ru     }
82*1440Sigor@sysoev.ru 
831394Sigor@sysoev.ru     size = sizeof(nxt_upstream_round_robin_t)
841394Sigor@sysoev.ru            + n * sizeof(nxt_upstream_round_robin_server_t);
851394Sigor@sysoev.ru 
861394Sigor@sysoev.ru     urr = nxt_mp_zalloc(mp, size);
871394Sigor@sysoev.ru     if (nxt_slow_path(urr == NULL)) {
881394Sigor@sysoev.ru         return NXT_ERROR;
891394Sigor@sysoev.ru     }
901394Sigor@sysoev.ru 
911394Sigor@sysoev.ru     urr->items = n;
921394Sigor@sysoev.ru     next = 0;
931394Sigor@sysoev.ru 
941394Sigor@sysoev.ru     for (i = 0; i < n; i++) {
951394Sigor@sysoev.ru         srvcf = nxt_conf_next_object_member(servers_conf, &name, &next);
961394Sigor@sysoev.ru 
971394Sigor@sysoev.ru         sa = nxt_sockaddr_parse(mp, &name);
981394Sigor@sysoev.ru         if (nxt_slow_path(sa == NULL)) {
991394Sigor@sysoev.ru             return NXT_ERROR;
1001394Sigor@sysoev.ru         }
1011394Sigor@sysoev.ru 
1021394Sigor@sysoev.ru         sa->type = SOCK_STREAM;
1031394Sigor@sysoev.ru 
1041394Sigor@sysoev.ru         urr->server[i].sockaddr = sa;
1051394Sigor@sysoev.ru         urr->server[i].protocol = NXT_HTTP_PROTO_H1;
1061394Sigor@sysoev.ru 
107*1440Sigor@sysoev.ru         wtcf = nxt_conf_get_object_member(srvcf, &weight, NULL);
108*1440Sigor@sysoev.ru         w = (wtcf != NULL) ? k * nxt_conf_get_number(wtcf) : k;
109*1440Sigor@sysoev.ru         wt = (w > 1 || w == 0) ? round(w) : 1;
1101394Sigor@sysoev.ru 
111*1440Sigor@sysoev.ru         urr->server[i].weight = wt;
112*1440Sigor@sysoev.ru         urr->server[i].effective_weight = wt;
1131394Sigor@sysoev.ru     }
1141394Sigor@sysoev.ru 
1151394Sigor@sysoev.ru     upstream->proto = &nxt_upstream_round_robin_proto;
1161394Sigor@sysoev.ru     upstream->type.round_robin = urr;
1171394Sigor@sysoev.ru 
1181394Sigor@sysoev.ru     return NXT_OK;
1191394Sigor@sysoev.ru }
1201394Sigor@sysoev.ru 
1211394Sigor@sysoev.ru 
1221394Sigor@sysoev.ru static nxt_upstream_t *
nxt_upstream_round_robin_joint_create(nxt_router_temp_conf_t * tmcf,nxt_upstream_t * upstream)1231394Sigor@sysoev.ru nxt_upstream_round_robin_joint_create(nxt_router_temp_conf_t *tmcf,
1241394Sigor@sysoev.ru     nxt_upstream_t *upstream)
1251394Sigor@sysoev.ru {
1261394Sigor@sysoev.ru     size_t                      size;
1271394Sigor@sysoev.ru     uint32_t                    i, n;
1281394Sigor@sysoev.ru     nxt_mp_t                    *mp;
1291394Sigor@sysoev.ru     nxt_upstream_t              *u;
1301394Sigor@sysoev.ru     nxt_upstream_round_robin_t  *urr, *urrcf;
1311394Sigor@sysoev.ru 
1321394Sigor@sysoev.ru     mp = tmcf->router_conf->mem_pool;
1331394Sigor@sysoev.ru 
1341394Sigor@sysoev.ru     u = nxt_mp_alloc(mp, sizeof(nxt_upstream_t));
1351394Sigor@sysoev.ru     if (nxt_slow_path(u == NULL)) {
1361394Sigor@sysoev.ru         return NULL;
1371394Sigor@sysoev.ru     }
1381394Sigor@sysoev.ru 
1391394Sigor@sysoev.ru     *u = *upstream;
1401394Sigor@sysoev.ru 
1411394Sigor@sysoev.ru     urrcf = upstream->type.round_robin;
1421394Sigor@sysoev.ru 
1431394Sigor@sysoev.ru     size = sizeof(nxt_upstream_round_robin_t)
1441394Sigor@sysoev.ru            + urrcf->items * sizeof(nxt_upstream_round_robin_server_t);
1451394Sigor@sysoev.ru 
1461394Sigor@sysoev.ru     urr = nxt_mp_alloc(mp, size);
1471394Sigor@sysoev.ru     if (nxt_slow_path(urr == NULL)) {
1481394Sigor@sysoev.ru         return NULL;
1491394Sigor@sysoev.ru     }
1501394Sigor@sysoev.ru 
1511394Sigor@sysoev.ru     u->type.round_robin = urr;
1521394Sigor@sysoev.ru 
1531394Sigor@sysoev.ru     n = urrcf->items;
1541394Sigor@sysoev.ru     urr->items = n;
1551394Sigor@sysoev.ru 
1561394Sigor@sysoev.ru     for (i = 0; i < n; i++) {
1571394Sigor@sysoev.ru         urr->server[i] = urrcf->server[i];
1581394Sigor@sysoev.ru     }
1591394Sigor@sysoev.ru 
1601394Sigor@sysoev.ru     return u;
1611394Sigor@sysoev.ru }
1621394Sigor@sysoev.ru 
1631394Sigor@sysoev.ru 
1641394Sigor@sysoev.ru static void
nxt_upstream_round_robin_server_get(nxt_task_t * task,nxt_upstream_server_t * us)1651394Sigor@sysoev.ru nxt_upstream_round_robin_server_get(nxt_task_t *task, nxt_upstream_server_t *us)
1661394Sigor@sysoev.ru {
1671394Sigor@sysoev.ru     int32_t                            total;
1681394Sigor@sysoev.ru     uint32_t                           i, n;
1691394Sigor@sysoev.ru     nxt_upstream_round_robin_t         *round_robin;
1701394Sigor@sysoev.ru     nxt_upstream_round_robin_server_t  *s, *best;
1711394Sigor@sysoev.ru 
1721394Sigor@sysoev.ru     best = NULL;
1731394Sigor@sysoev.ru     total = 0;
1741394Sigor@sysoev.ru 
1751394Sigor@sysoev.ru     round_robin = us->upstream->type.round_robin;
1761394Sigor@sysoev.ru 
1771394Sigor@sysoev.ru     s = round_robin->server;
1781394Sigor@sysoev.ru     n = round_robin->items;
1791394Sigor@sysoev.ru 
1801394Sigor@sysoev.ru     for (i = 0; i < n; i++) {
1811394Sigor@sysoev.ru 
1821394Sigor@sysoev.ru         s[i].current_weight += s[i].effective_weight;
1831394Sigor@sysoev.ru         total += s[i].effective_weight;
1841394Sigor@sysoev.ru 
1851394Sigor@sysoev.ru         if (s[i].effective_weight < s[i].weight) {
1861394Sigor@sysoev.ru             s[i].effective_weight++;
1871394Sigor@sysoev.ru         }
1881394Sigor@sysoev.ru 
1891394Sigor@sysoev.ru         if (best == NULL || s[i].current_weight > best->current_weight) {
1901394Sigor@sysoev.ru             best = &s[i];
1911394Sigor@sysoev.ru         }
1921394Sigor@sysoev.ru     }
1931394Sigor@sysoev.ru 
194*1440Sigor@sysoev.ru     if (best == NULL || total == 0) {
1951394Sigor@sysoev.ru         us->state->error(task, us);
1961394Sigor@sysoev.ru         return;
1971394Sigor@sysoev.ru     }
1981394Sigor@sysoev.ru 
1991394Sigor@sysoev.ru     best->current_weight -= total;
2001394Sigor@sysoev.ru     us->sockaddr = best->sockaddr;
2011394Sigor@sysoev.ru     us->protocol = best->protocol;
2021394Sigor@sysoev.ru     us->server.round_robin = best;
2031394Sigor@sysoev.ru 
2041394Sigor@sysoev.ru     us->state->ready(task, us);
2051394Sigor@sysoev.ru }
206