Mercurial > hg > nginx
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 |