1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Ruslan Ermilov
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevstatic char *ngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd,
14e18a033bSKonstantin Ananyev    void *conf);
15e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone,
16e18a033bSKonstantin Ananyev    void *data);
17e18a033bSKonstantin Ananyevstatic ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers(
18e18a033bSKonstantin Ananyev    ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf);
19e18a033bSKonstantin Ananyev
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_upstream_zone_commands[] = {
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyev    { ngx_string("zone"),
24e18a033bSKonstantin Ananyev      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
25e18a033bSKonstantin Ananyev      ngx_http_upstream_zone,
26e18a033bSKonstantin Ananyev      0,
27e18a033bSKonstantin Ananyev      0,
28e18a033bSKonstantin Ananyev      NULL },
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyev      ngx_null_command
31e18a033bSKonstantin Ananyev};
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_upstream_zone_module_ctx = {
35e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
36e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
37e18a033bSKonstantin Ananyev
38e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
39e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
42e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
43e18a033bSKonstantin Ananyev
44e18a033bSKonstantin Ananyev    NULL,                                  /* create location configuration */
45e18a033bSKonstantin Ananyev    NULL                                   /* merge location configuration */
46e18a033bSKonstantin Ananyev};
47e18a033bSKonstantin Ananyev
48e18a033bSKonstantin Ananyev
49e18a033bSKonstantin Ananyevngx_module_t  ngx_http_upstream_zone_module = {
50e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
51e18a033bSKonstantin Ananyev    &ngx_http_upstream_zone_module_ctx,    /* module context */
52e18a033bSKonstantin Ananyev    ngx_http_upstream_zone_commands,       /* module directives */
53e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
54e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
55e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
56e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
57e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
58e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
59e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
60e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
61e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
62e18a033bSKonstantin Ananyev};
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyev
65e18a033bSKonstantin Ananyevstatic char *
66e18a033bSKonstantin Ananyevngx_http_upstream_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
67e18a033bSKonstantin Ananyev{
68e18a033bSKonstantin Ananyev    ssize_t                         size;
69e18a033bSKonstantin Ananyev    ngx_str_t                      *value;
70e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t   *uscf;
71e18a033bSKonstantin Ananyev    ngx_http_upstream_main_conf_t  *umcf;
72e18a033bSKonstantin Ananyev
73e18a033bSKonstantin Ananyev    uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
74e18a033bSKonstantin Ananyev    umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
75e18a033bSKonstantin Ananyev
76e18a033bSKonstantin Ananyev    value = cf->args->elts;
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev    if (!value[1].len) {
79e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
80e18a033bSKonstantin Ananyev                           "invalid zone name \"%V\"", &value[1]);
81e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
82e18a033bSKonstantin Ananyev    }
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    if (cf->args->nelts == 3) {
85e18a033bSKonstantin Ananyev        size = ngx_parse_size(&value[2]);
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev        if (size == NGX_ERROR) {
88e18a033bSKonstantin Ananyev            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
89e18a033bSKonstantin Ananyev                               "invalid zone size \"%V\"", &value[2]);
90e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
91e18a033bSKonstantin Ananyev        }
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev        if (size < (ssize_t) (8 * ngx_pagesize)) {
94e18a033bSKonstantin Ananyev            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
95e18a033bSKonstantin Ananyev                               "zone \"%V\" is too small", &value[1]);
96e18a033bSKonstantin Ananyev            return NGX_CONF_ERROR;
97e18a033bSKonstantin Ananyev        }
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev    } else {
100e18a033bSKonstantin Ananyev        size = 0;
101e18a033bSKonstantin Ananyev    }
102e18a033bSKonstantin Ananyev
103e18a033bSKonstantin Ananyev    uscf->shm_zone = ngx_shared_memory_add(cf, &value[1], size,
104e18a033bSKonstantin Ananyev                                           &ngx_http_upstream_module);
105e18a033bSKonstantin Ananyev    if (uscf->shm_zone == NULL) {
106e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
107e18a033bSKonstantin Ananyev    }
108e18a033bSKonstantin Ananyev
109e18a033bSKonstantin Ananyev    uscf->shm_zone->init = ngx_http_upstream_init_zone;
110e18a033bSKonstantin Ananyev    uscf->shm_zone->data = umcf;
111e18a033bSKonstantin Ananyev
112e18a033bSKonstantin Ananyev    uscf->shm_zone->noreuse = 1;
113e18a033bSKonstantin Ananyev
114e18a033bSKonstantin Ananyev    return NGX_CONF_OK;
115e18a033bSKonstantin Ananyev}
116e18a033bSKonstantin Ananyev
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyevstatic ngx_int_t
119e18a033bSKonstantin Ananyevngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data)
120e18a033bSKonstantin Ananyev{
121e18a033bSKonstantin Ananyev    size_t                          len;
122e18a033bSKonstantin Ananyev    ngx_uint_t                      i;
123e18a033bSKonstantin Ananyev    ngx_slab_pool_t                *shpool;
124e18a033bSKonstantin Ananyev    ngx_http_upstream_rr_peers_t   *peers, **peersp;
125e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
126e18a033bSKonstantin Ananyev    ngx_http_upstream_main_conf_t  *umcf;
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev    shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
129e18a033bSKonstantin Ananyev    umcf = shm_zone->data;
130e18a033bSKonstantin Ananyev    uscfp = umcf->upstreams.elts;
131e18a033bSKonstantin Ananyev
132e18a033bSKonstantin Ananyev    if (shm_zone->shm.exists) {
133e18a033bSKonstantin Ananyev        peers = shpool->data;
134e18a033bSKonstantin Ananyev
135e18a033bSKonstantin Ananyev        for (i = 0; i < umcf->upstreams.nelts; i++) {
136e18a033bSKonstantin Ananyev            uscf = uscfp[i];
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev            if (uscf->shm_zone != shm_zone) {
139e18a033bSKonstantin Ananyev                continue;
140e18a033bSKonstantin Ananyev            }
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev            uscf->peer.data = peers;
143e18a033bSKonstantin Ananyev            peers = peers->zone_next;
144e18a033bSKonstantin Ananyev        }
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev        return NGX_OK;
147e18a033bSKonstantin Ananyev    }
148e18a033bSKonstantin Ananyev
149e18a033bSKonstantin Ananyev    len = sizeof(" in upstream zone \"\"") + shm_zone->shm.name.len;
150e18a033bSKonstantin Ananyev
151e18a033bSKonstantin Ananyev    shpool->log_ctx = ngx_slab_alloc(shpool, len);
152e18a033bSKonstantin Ananyev    if (shpool->log_ctx == NULL) {
153e18a033bSKonstantin Ananyev        return NGX_ERROR;
154e18a033bSKonstantin Ananyev    }
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev    ngx_sprintf(shpool->log_ctx, " in upstream zone \"%V\"%Z",
157e18a033bSKonstantin Ananyev                &shm_zone->shm.name);
158e18a033bSKonstantin Ananyev
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    /* copy peers to shared memory */
161e18a033bSKonstantin Ananyev
162e18a033bSKonstantin Ananyev    peersp = (ngx_http_upstream_rr_peers_t **) (void *) &shpool->data;
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    for (i = 0; i < umcf->upstreams.nelts; i++) {
165e18a033bSKonstantin Ananyev        uscf = uscfp[i];
166e18a033bSKonstantin Ananyev
167e18a033bSKonstantin Ananyev        if (uscf->shm_zone != shm_zone) {
168e18a033bSKonstantin Ananyev            continue;
169e18a033bSKonstantin Ananyev        }
170e18a033bSKonstantin Ananyev
171e18a033bSKonstantin Ananyev        peers = ngx_http_upstream_zone_copy_peers(shpool, uscf);
172e18a033bSKonstantin Ananyev        if (peers == NULL) {
173e18a033bSKonstantin Ananyev            return NGX_ERROR;
174e18a033bSKonstantin Ananyev        }
175e18a033bSKonstantin Ananyev
176e18a033bSKonstantin Ananyev        *peersp = peers;
177e18a033bSKonstantin Ananyev        peersp = &peers->zone_next;
178e18a033bSKonstantin Ananyev    }
179e18a033bSKonstantin Ananyev
180e18a033bSKonstantin Ananyev    return NGX_OK;
181e18a033bSKonstantin Ananyev}
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyevstatic ngx_http_upstream_rr_peers_t *
185e18a033bSKonstantin Ananyevngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool,
186e18a033bSKonstantin Ananyev    ngx_http_upstream_srv_conf_t *uscf)
187e18a033bSKonstantin Ananyev{
188e18a033bSKonstantin Ananyev    ngx_http_upstream_rr_peer_t   *peer, **peerp;
189e18a033bSKonstantin Ananyev    ngx_http_upstream_rr_peers_t  *peers, *backup;
190e18a033bSKonstantin Ananyev
191e18a033bSKonstantin Ananyev    peers = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t));
192e18a033bSKonstantin Ananyev    if (peers == NULL) {
193e18a033bSKonstantin Ananyev        return NULL;
194e18a033bSKonstantin Ananyev    }
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyev    ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t));
197e18a033bSKonstantin Ananyev
198e18a033bSKonstantin Ananyev    peers->shpool = shpool;
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev    for (peerp = &peers->peer; *peerp; peerp = &peer->next) {
201e18a033bSKonstantin Ananyev        /* pool is unlocked */
202e18a033bSKonstantin Ananyev        peer = ngx_slab_calloc_locked(shpool,
203e18a033bSKonstantin Ananyev                                      sizeof(ngx_http_upstream_rr_peer_t));
204e18a033bSKonstantin Ananyev        if (peer == NULL) {
205e18a033bSKonstantin Ananyev            return NULL;
206e18a033bSKonstantin Ananyev        }
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev        ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t));
209e18a033bSKonstantin Ananyev
210e18a033bSKonstantin Ananyev        *peerp = peer;
211e18a033bSKonstantin Ananyev    }
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    if (peers->next == NULL) {
214e18a033bSKonstantin Ananyev        goto done;
215e18a033bSKonstantin Ananyev    }
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    backup = ngx_slab_alloc(shpool, sizeof(ngx_http_upstream_rr_peers_t));
218e18a033bSKonstantin Ananyev    if (backup == NULL) {
219e18a033bSKonstantin Ananyev        return NULL;
220e18a033bSKonstantin Ananyev    }
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev    ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t));
223e18a033bSKonstantin Ananyev
224e18a033bSKonstantin Ananyev    backup->shpool = shpool;
225e18a033bSKonstantin Ananyev
226e18a033bSKonstantin Ananyev    for (peerp = &backup->peer; *peerp; peerp = &peer->next) {
227e18a033bSKonstantin Ananyev        /* pool is unlocked */
228e18a033bSKonstantin Ananyev        peer = ngx_slab_calloc_locked(shpool,
229e18a033bSKonstantin Ananyev                                      sizeof(ngx_http_upstream_rr_peer_t));
230e18a033bSKonstantin Ananyev        if (peer == NULL) {
231e18a033bSKonstantin Ananyev            return NULL;
232e18a033bSKonstantin Ananyev        }
233e18a033bSKonstantin Ananyev
234e18a033bSKonstantin Ananyev        ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t));
235e18a033bSKonstantin Ananyev
236e18a033bSKonstantin Ananyev        *peerp = peer;
237e18a033bSKonstantin Ananyev    }
238e18a033bSKonstantin Ananyev
239e18a033bSKonstantin Ananyev    peers->next = backup;
240e18a033bSKonstantin Ananyev
241e18a033bSKonstantin Ananyevdone:
242e18a033bSKonstantin Ananyev
243e18a033bSKonstantin Ananyev    uscf->peer.data = peers;
244e18a033bSKonstantin Ananyev
245e18a033bSKonstantin Ananyev    return peers;
246e18a033bSKonstantin Ananyev}
247