[nginx] svn commit: r4272 - trunk/src/http/modules

vbart at nginx.com vbart at nginx.com
Thu Nov 10 16:08:14 UTC 2011


Author: vbart
Date: 2011-11-10 16:08:13 +0000 (Thu, 10 Nov 2011)
New Revision: 4272

Modified:
   trunk/src/http/modules/ngx_http_limit_zone_module.c
Log:
Limit zone: support for multiple "limit_conn" limits.


Modified: trunk/src/http/modules/ngx_http_limit_zone_module.c
===================================================================
--- trunk/src/http/modules/ngx_http_limit_zone_module.c	2011-11-10 15:51:55 UTC (rev 4271)
+++ trunk/src/http/modules/ngx_http_limit_zone_module.c	2011-11-10 16:08:13 UTC (rev 4272)
@@ -33,6 +33,11 @@
 typedef struct {
     ngx_shm_zone_t     *shm_zone;
     ngx_uint_t          conn;
+} ngx_http_limit_zone_limit_t;
+
+
+typedef struct {
+    ngx_array_t         limits;
     ngx_uint_t          log_level;
 } ngx_http_limit_zone_conf_t;
 
@@ -40,6 +45,7 @@
 static ngx_rbtree_node_t *ngx_http_limit_zone_lookup(ngx_rbtree_t *rbtree,
     ngx_http_variable_value_t *vv, uint32_t hash);
 static void ngx_http_limit_zone_cleanup(void *data);
+static ngx_inline void ngx_http_limit_zone_cleanup_all(ngx_pool_t *pool);
 
 static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf);
 static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent,
@@ -123,6 +129,7 @@
 {
     size_t                          len, n;
     uint32_t                        hash;
+    ngx_uint_t                      i;
     ngx_slab_pool_t                *shpool;
     ngx_rbtree_node_t              *node;
     ngx_pool_cleanup_t             *cln;
@@ -130,6 +137,7 @@
     ngx_http_limit_zone_ctx_t      *ctx;
     ngx_http_limit_zone_node_t     *lz;
     ngx_http_limit_zone_conf_t     *lzcf;
+    ngx_http_limit_zone_limit_t    *limits;
     ngx_http_limit_zone_cleanup_t  *lzcln;
 
     if (r->main->limit_zone_set) {
@@ -137,97 +145,100 @@
     }
 
     lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module);
+    limits = lzcf->limits.elts;
 
-    if (lzcf->shm_zone == NULL) {
-        return NGX_DECLINED;
-    }
+    r->main->limit_zone_set = 1;
 
-    ctx = lzcf->shm_zone->data;
+    for (i = 0; i < lzcf->limits.nelts; i++) {
+        ctx = limits[i].shm_zone->data;
 
-    vv = ngx_http_get_indexed_variable(r, ctx->index);
+        vv = ngx_http_get_indexed_variable(r, ctx->index);
 
-    if (vv == NULL || vv->not_found) {
-        return NGX_DECLINED;
-    }
+        if (vv == NULL || vv->not_found) {
+            continue;
+        }
 
-    len = vv->len;
+        len = vv->len;
 
-    if (len == 0) {
-        return NGX_DECLINED;
-    }
+        if (len == 0) {
+            continue;
+        }
 
-    if (len > 255) {
-        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "the value of the \"%V\" variable "
-                      "is more than 255 bytes: \"%v\"",
-                      &ctx->var, vv);
-        return NGX_DECLINED;
-    }
+        if (len > 255) {
+            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                          "the value of the \"%V\" variable "
+                          "is more than 255 bytes: \"%v\"",
+                          &ctx->var, vv);
+            continue;
+        }
 
-    r->main->limit_zone_set = 1;
+        hash = ngx_crc32_short(vv->data, len);
 
-    hash = ngx_crc32_short(vv->data, len);
+        shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr;
 
-    cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t));
-    if (cln == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
+        ngx_shmtx_lock(&shpool->mutex);
 
-    shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
+        node = ngx_http_limit_zone_lookup(ctx->rbtree, vv, hash);
 
-    ngx_shmtx_lock(&shpool->mutex);
+        if (node == NULL) {
 
-    node = ngx_http_limit_zone_lookup(ctx->rbtree, vv, hash);
+            n = offsetof(ngx_rbtree_node_t, color)
+                + offsetof(ngx_http_limit_zone_node_t, data)
+                + len;
 
-    if (node == NULL) {
+            node = ngx_slab_alloc_locked(shpool, n);
 
-        n = offsetof(ngx_rbtree_node_t, color)
-            + offsetof(ngx_http_limit_zone_node_t, data)
-            + len;
+            if (node == NULL) {
+                ngx_shmtx_unlock(&shpool->mutex);
+                ngx_http_limit_zone_cleanup_all(r->pool);
+                return NGX_HTTP_SERVICE_UNAVAILABLE;
+            }
 
-        node = ngx_slab_alloc_locked(shpool, n);
-        if (node == NULL) {
-            ngx_shmtx_unlock(&shpool->mutex);
-            return NGX_HTTP_SERVICE_UNAVAILABLE;
-        }
+            lz = (ngx_http_limit_zone_node_t *) &node->color;
 
-        lz = (ngx_http_limit_zone_node_t *) &node->color;
+            node->key = hash;
+            lz->len = (u_char) len;
+            lz->conn = 1;
+            ngx_memcpy(lz->data, vv->data, len);
 
-        node->key = hash;
-        lz->len = (u_char) len;
-        lz->conn = 1;
-        ngx_memcpy(lz->data, vv->data, len);
+            ngx_rbtree_insert(ctx->rbtree, node);
 
-        ngx_rbtree_insert(ctx->rbtree, node);
+        } else {
 
-    } else {
+            lz = (ngx_http_limit_zone_node_t *) &node->color;
 
-        lz = (ngx_http_limit_zone_node_t *) &node->color;
+            if ((ngx_uint_t) lz->conn >= limits[i].conn) {
 
-        if ((ngx_uint_t) lz->conn >= lzcf->conn) {
+                ngx_shmtx_unlock(&shpool->mutex);
 
-            ngx_shmtx_unlock(&shpool->mutex);
+                ngx_log_error(lzcf->log_level, r->connection->log, 0,
+                              "limiting connections by zone \"%V\"",
+                              &limits[i].shm_zone->shm.name);
 
-            ngx_log_error(lzcf->log_level, r->connection->log, 0,
-                          "limiting connections by zone \"%V\"",
-                          &lzcf->shm_zone->shm.name);
+                ngx_http_limit_zone_cleanup_all(r->pool);
+                return NGX_HTTP_SERVICE_UNAVAILABLE;
+            }
 
-            return NGX_HTTP_SERVICE_UNAVAILABLE;
+            lz->conn++;
         }
 
-        lz->conn++;
-    }
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "limit zone: %08XD %d", node->key, lz->conn);
 
-    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "limit zone: %08XD %d", node->key, lz->conn);
+        ngx_shmtx_unlock(&shpool->mutex);
 
-    ngx_shmtx_unlock(&shpool->mutex);
+        cln = ngx_pool_cleanup_add(r->pool,
+                                   sizeof(ngx_http_limit_zone_cleanup_t));
+        if (cln == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
 
-    cln->handler = ngx_http_limit_zone_cleanup;
-    lzcln = cln->data;
+        cln->handler = ngx_http_limit_zone_cleanup;
+        lzcln = cln->data;
 
-    lzcln->shm_zone = lzcf->shm_zone;
-    lzcln->node = node;
+        lzcln->shm_zone = limits[i].shm_zone;
+        lzcln->node = node;
+    }
 
     return NGX_DECLINED;
 }
@@ -350,6 +361,22 @@
 }
 
 
+static ngx_inline void
+ngx_http_limit_zone_cleanup_all(ngx_pool_t *pool)
+{
+    ngx_pool_cleanup_t  *cln;
+
+    cln = pool->cleanup;
+
+    while (cln && cln->handler == ngx_http_limit_zone_cleanup) {
+        ngx_http_limit_zone_cleanup(cln->data);
+        cln = cln->next;
+    }
+
+    pool->cleanup = cln;
+}
+
+
 static ngx_int_t
 ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data)
 {
@@ -426,8 +453,7 @@
     /*
      * set by ngx_pcalloc():
      *
-     *     conf->shm_zone = NULL;
-     *     conf->conn = 0;
+     *     conf->limits.elts = NULL;
      */
 
     conf->log_level = NGX_CONF_UNSET_UINT;
@@ -442,7 +468,7 @@
     ngx_http_limit_zone_conf_t *prev = parent;
     ngx_http_limit_zone_conf_t *conf = child;
 
-    if (conf->shm_zone == NULL) {
+    if (conf->limits.elts == NULL) {
         *conf = *prev;
     }
 
@@ -523,23 +549,39 @@
 static char *
 ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
-    ngx_http_limit_zone_conf_t  *lzcf = conf;
+    ngx_shm_zone_t               *shm_zone;
+    ngx_http_limit_zone_conf_t   *lzcf = conf;
+    ngx_http_limit_zone_limit_t  *limit, *limits;
 
+    ngx_str_t  *value;
     ngx_int_t   n;
-    ngx_str_t  *value;
+    ngx_uint_t  i;
 
-    if (lzcf->shm_zone) {
-        return "is duplicate";
-    }
-
     value = cf->args->elts;
 
-    lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
-                                           &ngx_http_limit_zone_module);
-    if (lzcf->shm_zone == NULL) {
+    shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
+                                     &ngx_http_limit_zone_module);
+    if (shm_zone == NULL) {
         return NGX_CONF_ERROR;
     }
 
+    limits = lzcf->limits.elts;
+
+    if (limits == NULL) {
+        if (ngx_array_init(&lzcf->limits, cf->pool, 1,
+                           sizeof(ngx_http_limit_zone_limit_t))
+            != NGX_OK)
+        {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    for (i = 0; i < lzcf->limits.nelts; i++) {
+        if (shm_zone == limits[i].shm_zone) {
+            return "is duplicate";
+        }
+    }
+
     n = ngx_atoi(value[2].data, value[2].len);
     if (n <= 0) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -553,7 +595,9 @@
         return NGX_CONF_ERROR;
     }
 
-    lzcf->conn = n;
+    limit = ngx_array_push(&lzcf->limits);
+    limit->conn = n;
+    limit->shm_zone = shm_zone;
 
     return NGX_CONF_OK;
 }



More information about the nginx-devel mailing list