Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Overhaul memory management

The shared memory segments are now tracked via an rbtree with proper
lifetime management (via refcounting). Starting with this commit,
nginx survives a continuous reload-every-1s cycle while serving
requests all the time.
  • Loading branch information...
commit 0256ed490fc1a9ba6741d682e667933f1a7ba548 1 parent 0d90163
Grzegorz Nosek authored

Showing 1 changed file with 240 additions and 19 deletions. Show diff stats Hide diff stats

  1. +240 19 ngx_http_upstream_fair_module.c
259 ngx_http_upstream_fair_module.c
@@ -31,9 +31,19 @@ typedef struct {
31 31
32 32
33 33 typedef struct {
34   - ngx_http_upstream_fair_shared_t *shared;
  34 + ngx_rbtree_node_t node;
  35 + ngx_cycle_t *cycle;
  36 + void *peers; /* forms a unique cookie together with cycle */
  37 + ngx_int_t refcount; /* accessed only under shmtx_lock */
  38 + ngx_http_upstream_fair_shared_t stats[1];
  39 +} ngx_http_upstream_fair_shm_block_t;
  40 +
  41 +
  42 +typedef struct {
  43 + ngx_cycle_t *cycle;
  44 + ngx_http_upstream_fair_shm_block_t *shared;
35 45 ngx_http_upstream_rr_peers_t *rrp;
36   - ngx_uint_t current;
  46 + ngx_uint_t current;
37 47 } ngx_http_upstream_fair_peers_t;
38 48
39 49
@@ -41,10 +51,10 @@ typedef struct {
41 51
42 52
43 53 typedef struct {
44   - ngx_http_upstream_rr_peer_data_t rrpd;
45   - ngx_http_upstream_fair_shared_t *shared;
46   - ngx_http_upstream_fair_peers_t *peer_data;
47   - ngx_uint_t current;
  54 + ngx_http_upstream_rr_peer_data_t rrpd;
  55 + ngx_http_upstream_fair_shared_t *shared;
  56 + ngx_http_upstream_fair_peers_t *peer_data;
  57 + ngx_uint_t current;
48 58 } ngx_http_upstream_fair_peer_data_t;
49 59
50 60
@@ -106,11 +116,124 @@ ngx_module_t ngx_http_upstream_fair_module = {
106 116
107 117
108 118 static ngx_shm_zone_t * ngx_http_upstream_fair_shm_zone;
  119 +static ngx_rbtree_t * ngx_http_upstream_fair_rbtree;
  120 +
  121 +static int
  122 +ngx_http_upstream_fair_compare_rbtree_node(const ngx_rbtree_node_t *v_left,
  123 + const ngx_rbtree_node_t *v_right)
  124 +{
  125 + ngx_http_upstream_fair_shm_block_t *left, *right;
  126 +
  127 + left = (ngx_http_upstream_fair_shm_block_t *) v_left;
  128 + right = (ngx_http_upstream_fair_shm_block_t *) v_right;
  129 +
  130 + if (left->cycle < right->cycle) {
  131 + return -1;
  132 + } else if (left->cycle > right->cycle) {
  133 + return 1;
  134 + } else { /* left->cycle == right->cycle */
  135 + if (left->peers < right->peers) {
  136 + return -1;
  137 + } else if (left->peers > right->peers) {
  138 + return 1;
  139 + } else {
  140 + return 0;
  141 + }
  142 + }
  143 +}
  144 +
  145 +static void
  146 +ngx_rbtree_generic_insert(ngx_rbtree_node_t *temp,
  147 + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel,
  148 + int (*compare)(const ngx_rbtree_node_t *left, const ngx_rbtree_node_t *right))
  149 +{
  150 + for ( ;; ) {
  151 + if (node->key < temp->key) {
  152 +
  153 + if (temp->left == sentinel) {
  154 + temp->left = node;
  155 + break;
  156 + }
  157 +
  158 + temp = temp->left;
  159 +
  160 + } else if (node->key > temp->key) {
  161 +
  162 + if (temp->right == sentinel) {
  163 + temp->right = node;
  164 + break;
  165 + }
  166 +
  167 + temp = temp->right;
  168 +
  169 + } else { /* node->key == temp->key */
  170 + if (compare(node, temp) < 0) {
  171 +
  172 + if (temp->left == sentinel) {
  173 + temp->left = node;
  174 + break;
  175 + }
  176 +
  177 + temp = temp->left;
  178 +
  179 + } else {
  180 +
  181 + if (temp->right == sentinel) {
  182 + temp->right = node;
  183 + break;
  184 + }
  185 +
  186 + temp = temp->right;
  187 + }
  188 + }
  189 + }
  190 +
  191 + node->parent = temp;
  192 + node->left = sentinel;
  193 + node->right = sentinel;
  194 + ngx_rbt_red(node);
  195 +}
  196 +
  197 +
  198 +static void
  199 +ngx_http_upstream_fair_rbtree_insert(ngx_rbtree_node_t *temp,
  200 + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) {
  201 +
  202 + ngx_rbtree_generic_insert(temp, node, sentinel,
  203 + ngx_http_upstream_fair_compare_rbtree_node);
  204 +}
109 205
110 206
111 207 static ngx_int_t
112 208 ngx_http_upstream_fair_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data)
113 209 {
  210 + ngx_slab_pool_t *shpool;
  211 + ngx_rbtree_t *tree;
  212 + ngx_rbtree_node_t *sentinel;
  213 +
  214 + if (data) {
  215 + shm_zone->data = data;
  216 + return NGX_OK;
  217 + }
  218 +
  219 + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
  220 + tree = ngx_slab_alloc(shpool, sizeof *tree);
  221 + if (tree == NULL) {
  222 + return NGX_ERROR;
  223 + }
  224 +
  225 + sentinel = ngx_slab_alloc(shpool, sizeof *sentinel);
  226 + if (sentinel == NULL) {
  227 + return NGX_ERROR;
  228 + }
  229 +
  230 + ngx_rbtree_sentinel_init(sentinel);
  231 + tree->root = sentinel;
  232 + tree->sentinel = sentinel;
  233 + tree->insert = ngx_http_upstream_fair_rbtree_insert;
  234 + shm_zone->data = tree;
  235 + ngx_http_upstream_fair_rbtree = tree;
  236 +
114 237 return NGX_OK;
115 238 }
116 239
@@ -166,6 +289,7 @@ ngx_http_upstream_init_fair(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
166 289 }
167 290 ngx_http_upstream_fair_shm_zone->init = ngx_http_upstream_fair_init_shm_zone;
168 291
  292 + peers->cycle = cf->cycle;
169 293 peers->shared = NULL;
170 294 peers->current = n - 1;
171 295
@@ -464,6 +588,114 @@ ngx_http_upstream_free_fair_peer(ngx_peer_connection_t *pc, void *data,
464 588 }
465 589 }
466 590
  591 +/*
  592 + * walk through the rbtree, removing old entries and looking for
  593 + * a matching one -- compared by (cycle, peers) pair
  594 + *
  595 + * no attempt at optimisation is made, for two reasons:
  596 + * - the tree will be quite small, anyway
  597 + * - being called once per worker startup per upstream block,
  598 + * this code isn't really the hot path
  599 + */
  600 +static ngx_http_upstream_fair_shm_block_t *
  601 +ngx_http_upstream_fair_walk_shm(
  602 + ngx_slab_pool_t *shpool,
  603 + ngx_rbtree_node_t *node,
  604 + ngx_rbtree_node_t *sentinel,
  605 + ngx_cycle_t *cycle, void *peers)
  606 +{
  607 + ngx_http_upstream_fair_shm_block_t *uf_node;
  608 + ngx_http_upstream_fair_shm_block_t *found_node = NULL;
  609 + ngx_http_upstream_fair_shm_block_t *tmp_node;
  610 +
  611 + if (node == sentinel || !node) {
  612 + return NULL;
  613 + }
  614 +
  615 + /* visit left node */
  616 + if (node->left != sentinel && node->left) {
  617 + tmp_node = ngx_http_upstream_fair_walk_shm(shpool, node->left,
  618 + sentinel, cycle, peers);
  619 + if (tmp_node) {
  620 + found_node = tmp_node;
  621 + }
  622 + }
  623 +
  624 + /* visit current node */
  625 + uf_node = (ngx_http_upstream_fair_shm_block_t *) node;
  626 + if (uf_node->cycle != cycle) {
  627 + if (--uf_node->refcount == 0) {
  628 + ngx_rbtree_delete(ngx_http_upstream_fair_rbtree, node);
  629 + ngx_slab_free_locked(shpool, node);
  630 + }
  631 + } else if (uf_node->peers == peers) {
  632 + found_node = uf_node;
  633 + }
  634 +
  635 + /* visit right node */
  636 + if (node->right != sentinel && node->right) {
  637 + tmp_node = ngx_http_upstream_fair_walk_shm(shpool, node->right,
  638 + sentinel, cycle, peers);
  639 + if (tmp_node) {
  640 + found_node = tmp_node;
  641 + }
  642 + }
  643 +
  644 + return found_node;
  645 +}
  646 +
  647 +static ngx_int_t
  648 +ngx_http_upstream_fair_shm_alloc(ngx_http_upstream_fair_peers_t *usfp)
  649 +{
  650 + ngx_slab_pool_t *shpool;
  651 + ngx_uint_t i;
  652 +
  653 + if (usfp->shared) {
  654 + return NGX_OK;
  655 + }
  656 +
  657 + shpool = (ngx_slab_pool_t *)ngx_http_upstream_fair_shm_zone->shm.addr;
  658 +
  659 + ngx_shmtx_lock(&shpool->mutex);
  660 +
  661 + usfp->shared = ngx_http_upstream_fair_walk_shm(shpool,
  662 + ngx_http_upstream_fair_rbtree->root,
  663 + ngx_http_upstream_fair_rbtree->sentinel,
  664 + usfp->cycle, usfp);
  665 +
  666 + if (usfp->shared) {
  667 + usfp->shared->refcount++;
  668 + ngx_shmtx_unlock(&shpool->mutex);
  669 + return NGX_OK;
  670 + }
  671 +
  672 + usfp->shared = ngx_slab_alloc_locked(shpool,
  673 + sizeof(ngx_http_upstream_fair_shm_block_t) +
  674 + (usfp->rrp->number - 1) * sizeof(ngx_http_upstream_fair_shared_t));
  675 +
  676 + if (!usfp->shared) {
  677 + ngx_shmtx_unlock(&shpool->mutex);
  678 + return NGX_ERROR;
  679 + }
  680 +
  681 + usfp->shared->node.key = ngx_crc32_short((u_char *) &usfp->cycle, sizeof usfp->cycle) ^
  682 + ngx_crc32_short((u_char *) &usfp, sizeof(usfp));
  683 +
  684 + usfp->shared->refcount = 1;
  685 + usfp->shared->cycle = usfp->cycle;
  686 + usfp->shared->peers = usfp;
  687 +
  688 + for (i = 0; i < usfp->rrp->number; i++) {
  689 + usfp->shared->stats[i].nreq = 0;
  690 + usfp->shared->stats[i].slot = 1;
  691 + usfp->shared->stats[i].last_active[0] = ngx_current_msec;
  692 + }
  693 +
  694 + ngx_rbtree_insert(ngx_http_upstream_fair_rbtree, &usfp->shared->node);
  695 +
  696 + ngx_shmtx_unlock(&shpool->mutex);
  697 + return NGX_OK;
  698 +}
467 699
468 700 ngx_int_t
469 701 ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
@@ -471,7 +703,6 @@ ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
471 703 {
472 704 ngx_http_upstream_fair_peer_data_t *fp;
473 705 ngx_http_upstream_fair_peers_t *usfp;
474   - ngx_slab_pool_t *shpool;
475 706
476 707 fp = r->upstream->peer.data;
477 708
@@ -495,19 +726,9 @@ ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
495 726 us->peer.data = usfp;
496 727
497 728 /* set up shared memory area */
498   - shpool = (ngx_slab_pool_t *)ngx_http_upstream_fair_shm_zone->shm.addr;
499   -
500   - if (!usfp->shared) {
501   - ngx_uint_t i;
502   - usfp->shared = ngx_slab_alloc(shpool, usfp->rrp->number * sizeof(ngx_http_upstream_fair_shared_t));
503   - for (i = 0; i < usfp->rrp->number; i++) {
504   - usfp->shared[i].nreq = 0;
505   - usfp->shared[i].slot = 1;
506   - usfp->shared[i].last_active[0] = ngx_current_msec;
507   - }
508   - }
  729 + ngx_http_upstream_fair_shm_alloc(usfp);
509 730
510   - fp->shared = usfp->shared;
  731 + fp->shared = &usfp->shared->stats[0];
511 732 fp->peer_data = usfp;
512 733 fp->current = usfp->current;
513 734 r->upstream->peer.get = ngx_http_upstream_get_fair_peer;

0 comments on commit 0256ed4

Please sign in to comment.
Something went wrong with that request. Please try again.