comparison src/stream/ngx_stream_limit_conn_module.c @ 7596:b45f052483b8

Limit conn: added shared context. Previously only an rbtree was associated with a limit_conn. To make it possible to associate more data with a limit_conn, shared context is introduced similar to limit_req. Also, shared pool pointer is kept in a way similar to limit_req.
author Roman Arutyunyan <arut@nginx.com>
date Mon, 18 Nov 2019 19:50:59 +0300
parents 9606d93aa586
children
comparison
equal deleted inserted replaced
7595:9606d93aa586 7596:b45f052483b8
14 #define NGX_STREAM_LIMIT_CONN_REJECTED 2 14 #define NGX_STREAM_LIMIT_CONN_REJECTED 2
15 #define NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN 3 15 #define NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN 3
16 16
17 17
18 typedef struct { 18 typedef struct {
19 u_char color; 19 u_char color;
20 u_char len; 20 u_char len;
21 u_short conn; 21 u_short conn;
22 u_char data[1]; 22 u_char data[1];
23 } ngx_stream_limit_conn_node_t; 23 } ngx_stream_limit_conn_node_t;
24 24
25 25
26 typedef struct { 26 typedef struct {
27 ngx_shm_zone_t *shm_zone; 27 ngx_shm_zone_t *shm_zone;
28 ngx_rbtree_node_t *node; 28 ngx_rbtree_node_t *node;
29 } ngx_stream_limit_conn_cleanup_t; 29 } ngx_stream_limit_conn_cleanup_t;
30 30
31 31
32 typedef struct { 32 typedef struct {
33 ngx_rbtree_t *rbtree; 33 ngx_rbtree_t rbtree;
34 ngx_stream_complex_value_t key; 34 ngx_rbtree_node_t sentinel;
35 } ngx_stream_limit_conn_shctx_t;
36
37
38 typedef struct {
39 ngx_stream_limit_conn_shctx_t *sh;
40 ngx_slab_pool_t *shpool;
41 ngx_stream_complex_value_t key;
35 } ngx_stream_limit_conn_ctx_t; 42 } ngx_stream_limit_conn_ctx_t;
36 43
37 44
38 typedef struct { 45 typedef struct {
39 ngx_shm_zone_t *shm_zone; 46 ngx_shm_zone_t *shm_zone;
40 ngx_uint_t conn; 47 ngx_uint_t conn;
41 } ngx_stream_limit_conn_limit_t; 48 } ngx_stream_limit_conn_limit_t;
42 49
43 50
44 typedef struct { 51 typedef struct {
45 ngx_array_t limits; 52 ngx_array_t limits;
46 ngx_uint_t log_level; 53 ngx_uint_t log_level;
47 ngx_flag_t dry_run; 54 ngx_flag_t dry_run;
48 } ngx_stream_limit_conn_conf_t; 55 } ngx_stream_limit_conn_conf_t;
49 56
50 57
51 static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree, 58 static ngx_rbtree_node_t *ngx_stream_limit_conn_lookup(ngx_rbtree_t *rbtree,
52 ngx_str_t *key, uint32_t hash); 59 ngx_str_t *key, uint32_t hash);
158 { 165 {
159 size_t n; 166 size_t n;
160 uint32_t hash; 167 uint32_t hash;
161 ngx_str_t key; 168 ngx_str_t key;
162 ngx_uint_t i; 169 ngx_uint_t i;
163 ngx_slab_pool_t *shpool;
164 ngx_rbtree_node_t *node; 170 ngx_rbtree_node_t *node;
165 ngx_pool_cleanup_t *cln; 171 ngx_pool_cleanup_t *cln;
166 ngx_stream_limit_conn_ctx_t *ctx; 172 ngx_stream_limit_conn_ctx_t *ctx;
167 ngx_stream_limit_conn_node_t *lc; 173 ngx_stream_limit_conn_node_t *lc;
168 ngx_stream_limit_conn_conf_t *lccf; 174 ngx_stream_limit_conn_conf_t *lccf;
193 199
194 s->limit_conn_status = NGX_STREAM_LIMIT_CONN_PASSED; 200 s->limit_conn_status = NGX_STREAM_LIMIT_CONN_PASSED;
195 201
196 hash = ngx_crc32_short(key.data, key.len); 202 hash = ngx_crc32_short(key.data, key.len);
197 203
198 shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; 204 ngx_shmtx_lock(&ctx->shpool->mutex);
199 205
200 ngx_shmtx_lock(&shpool->mutex); 206 node = ngx_stream_limit_conn_lookup(&ctx->sh->rbtree, &key, hash);
201
202 node = ngx_stream_limit_conn_lookup(ctx->rbtree, &key, hash);
203 207
204 if (node == NULL) { 208 if (node == NULL) {
205 209
206 n = offsetof(ngx_rbtree_node_t, color) 210 n = offsetof(ngx_rbtree_node_t, color)
207 + offsetof(ngx_stream_limit_conn_node_t, data) 211 + offsetof(ngx_stream_limit_conn_node_t, data)
208 + key.len; 212 + key.len;
209 213
210 node = ngx_slab_alloc_locked(shpool, n); 214 node = ngx_slab_alloc_locked(ctx->shpool, n);
211 215
212 if (node == NULL) { 216 if (node == NULL) {
213 ngx_shmtx_unlock(&shpool->mutex); 217 ngx_shmtx_unlock(&ctx->shpool->mutex);
214 ngx_stream_limit_conn_cleanup_all(s->connection->pool); 218 ngx_stream_limit_conn_cleanup_all(s->connection->pool);
215 219
216 if (lccf->dry_run) { 220 if (lccf->dry_run) {
217 s->limit_conn_status = 221 s->limit_conn_status =
218 NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN; 222 NGX_STREAM_LIMIT_CONN_REJECTED_DRY_RUN;
229 node->key = hash; 233 node->key = hash;
230 lc->len = (u_char) key.len; 234 lc->len = (u_char) key.len;
231 lc->conn = 1; 235 lc->conn = 1;
232 ngx_memcpy(lc->data, key.data, key.len); 236 ngx_memcpy(lc->data, key.data, key.len);
233 237
234 ngx_rbtree_insert(ctx->rbtree, node); 238 ngx_rbtree_insert(&ctx->sh->rbtree, node);
235 239
236 } else { 240 } else {
237 241
238 lc = (ngx_stream_limit_conn_node_t *) &node->color; 242 lc = (ngx_stream_limit_conn_node_t *) &node->color;
239 243
240 if ((ngx_uint_t) lc->conn >= limits[i].conn) { 244 if ((ngx_uint_t) lc->conn >= limits[i].conn) {
241 245
242 ngx_shmtx_unlock(&shpool->mutex); 246 ngx_shmtx_unlock(&ctx->shpool->mutex);
243 247
244 ngx_log_error(lccf->log_level, s->connection->log, 0, 248 ngx_log_error(lccf->log_level, s->connection->log, 0,
245 "limiting connections%s by zone \"%V\"", 249 "limiting connections%s by zone \"%V\"",
246 lccf->dry_run ? ", dry run," : "", 250 lccf->dry_run ? ", dry run," : "",
247 &limits[i].shm_zone->shm.name); 251 &limits[i].shm_zone->shm.name);
263 } 267 }
264 268
265 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, 269 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
266 "limit conn: %08Xi %d", node->key, lc->conn); 270 "limit conn: %08Xi %d", node->key, lc->conn);
267 271
268 ngx_shmtx_unlock(&shpool->mutex); 272 ngx_shmtx_unlock(&ctx->shpool->mutex);
269 273
270 cln = ngx_pool_cleanup_add(s->connection->pool, 274 cln = ngx_pool_cleanup_add(s->connection->pool,
271 sizeof(ngx_stream_limit_conn_cleanup_t)); 275 sizeof(ngx_stream_limit_conn_cleanup_t));
272 if (cln == NULL) { 276 if (cln == NULL) {
273 return NGX_ERROR; 277 return NGX_ERROR;
368 static void 372 static void
369 ngx_stream_limit_conn_cleanup(void *data) 373 ngx_stream_limit_conn_cleanup(void *data)
370 { 374 {
371 ngx_stream_limit_conn_cleanup_t *lccln = data; 375 ngx_stream_limit_conn_cleanup_t *lccln = data;
372 376
373 ngx_slab_pool_t *shpool;
374 ngx_rbtree_node_t *node; 377 ngx_rbtree_node_t *node;
375 ngx_stream_limit_conn_ctx_t *ctx; 378 ngx_stream_limit_conn_ctx_t *ctx;
376 ngx_stream_limit_conn_node_t *lc; 379 ngx_stream_limit_conn_node_t *lc;
377 380
378 ctx = lccln->shm_zone->data; 381 ctx = lccln->shm_zone->data;
379 shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
380 node = lccln->node; 382 node = lccln->node;
381 lc = (ngx_stream_limit_conn_node_t *) &node->color; 383 lc = (ngx_stream_limit_conn_node_t *) &node->color;
382 384
383 ngx_shmtx_lock(&shpool->mutex); 385 ngx_shmtx_lock(&ctx->shpool->mutex);
384 386
385 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0, 387 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0,
386 "limit conn cleanup: %08Xi %d", node->key, lc->conn); 388 "limit conn cleanup: %08Xi %d", node->key, lc->conn);
387 389
388 lc->conn--; 390 lc->conn--;
389 391
390 if (lc->conn == 0) { 392 if (lc->conn == 0) {
391 ngx_rbtree_delete(ctx->rbtree, node); 393 ngx_rbtree_delete(&ctx->sh->rbtree, node);
392 ngx_slab_free_locked(shpool, node); 394 ngx_slab_free_locked(ctx->shpool, node);
393 } 395 }
394 396
395 ngx_shmtx_unlock(&shpool->mutex); 397 ngx_shmtx_unlock(&ctx->shpool->mutex);
396 } 398 }
397 399
398 400
399 static ngx_inline void 401 static ngx_inline void
400 ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool) 402 ngx_stream_limit_conn_cleanup_all(ngx_pool_t *pool)
416 ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) 418 ngx_stream_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data)
417 { 419 {
418 ngx_stream_limit_conn_ctx_t *octx = data; 420 ngx_stream_limit_conn_ctx_t *octx = data;
419 421
420 size_t len; 422 size_t len;
421 ngx_slab_pool_t *shpool;
422 ngx_rbtree_node_t *sentinel;
423 ngx_stream_limit_conn_ctx_t *ctx; 423 ngx_stream_limit_conn_ctx_t *ctx;
424 424
425 ctx = shm_zone->data; 425 ctx = shm_zone->data;
426 426
427 if (octx) { 427 if (octx) {
436 &shm_zone->shm.name, &ctx->key.value, 436 &shm_zone->shm.name, &ctx->key.value,
437 &octx->key.value); 437 &octx->key.value);
438 return NGX_ERROR; 438 return NGX_ERROR;
439 } 439 }
440 440
441 ctx->rbtree = octx->rbtree; 441 ctx->sh = octx->sh;
442 ctx->shpool = octx->shpool;
442 443
443 return NGX_OK; 444 return NGX_OK;
444 } 445 }
445 446
446 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; 447 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
447 448
448 if (shm_zone->shm.exists) { 449 if (shm_zone->shm.exists) {
449 ctx->rbtree = shpool->data; 450 ctx->sh = ctx->shpool->data;
450 451
451 return NGX_OK; 452 return NGX_OK;
452 } 453 }
453 454
454 ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); 455 ctx->sh = ngx_slab_alloc(ctx->shpool,
455 if (ctx->rbtree == NULL) { 456 sizeof(ngx_stream_limit_conn_shctx_t));
457 if (ctx->sh == NULL) {
456 return NGX_ERROR; 458 return NGX_ERROR;
457 } 459 }
458 460
459 shpool->data = ctx->rbtree; 461 ctx->shpool->data = ctx->sh;
460 462
461 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); 463 ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel,
462 if (sentinel == NULL) { 464 ngx_stream_limit_conn_rbtree_insert_value);
465
466 len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
467
468 ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len);
469 if (ctx->shpool->log_ctx == NULL) {
463 return NGX_ERROR; 470 return NGX_ERROR;
464 } 471 }
465 472
466 ngx_rbtree_init(ctx->rbtree, sentinel, 473 ngx_sprintf(ctx->shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
467 ngx_stream_limit_conn_rbtree_insert_value);
468
469 len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len;
470
471 shpool->log_ctx = ngx_slab_alloc(shpool, len);
472 if (shpool->log_ctx == NULL) {
473 return NGX_ERROR;
474 }
475
476 ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z",
477 &shm_zone->shm.name); 474 &shm_zone->shm.name);
478 475
479 return NGX_OK; 476 return NGX_OK;
480 } 477 }
481 478