Mercurial > hg > nginx-ranges
comparison src/http/modules/ngx_http_limit_req_module.c @ 635:e67b227c8dbb default tip
Merge with current.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 25 Apr 2011 04:07:55 +0400 |
parents | c5122335e41d |
children |
comparison
equal
deleted
inserted
replaced
578:f3a9e57d2e17 | 635:e67b227c8dbb |
---|---|
49 } ngx_http_limit_req_conf_t; | 49 } ngx_http_limit_req_conf_t; |
50 | 50 |
51 | 51 |
52 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 52 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
53 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, | 53 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, |
54 ngx_uint_t hash, u_char *data, size_t len, ngx_http_limit_req_node_t **lrp); | 54 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep); |
55 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, | 55 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
56 ngx_uint_t n); | 56 ngx_uint_t n); |
57 | 57 |
58 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); | 58 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
59 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | 59 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, |
184 | 184 |
185 ngx_shmtx_lock(&ctx->shpool->mutex); | 185 ngx_shmtx_lock(&ctx->shpool->mutex); |
186 | 186 |
187 ngx_http_limit_req_expire(ctx, 1); | 187 ngx_http_limit_req_expire(ctx, 1); |
188 | 188 |
189 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr); | 189 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess); |
190 | |
191 if (lr) { | |
192 ngx_queue_remove(&lr->queue); | |
193 | |
194 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
195 | |
196 excess = lr->excess; | |
197 | |
198 } else { | |
199 excess = 0; | |
200 } | |
201 | 190 |
202 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 191 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
203 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); | 192 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); |
204 | 193 |
194 if (rc == NGX_DECLINED) { | |
195 | |
196 n = offsetof(ngx_rbtree_node_t, color) | |
197 + offsetof(ngx_http_limit_req_node_t, data) | |
198 + len; | |
199 | |
200 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
201 if (node == NULL) { | |
202 | |
203 ngx_http_limit_req_expire(ctx, 0); | |
204 | |
205 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
206 if (node == NULL) { | |
207 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
208 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
209 } | |
210 } | |
211 | |
212 lr = (ngx_http_limit_req_node_t *) &node->color; | |
213 | |
214 node->key = hash; | |
215 lr->len = (u_char) len; | |
216 | |
217 tp = ngx_timeofday(); | |
218 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
219 | |
220 lr->excess = 0; | |
221 ngx_memcpy(lr->data, vv->data, len); | |
222 | |
223 ngx_rbtree_insert(&ctx->sh->rbtree, node); | |
224 | |
225 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
226 | |
227 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
228 | |
229 return NGX_DECLINED; | |
230 } | |
231 | |
232 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
233 | |
234 if (rc == NGX_OK) { | |
235 return NGX_DECLINED; | |
236 } | |
237 | |
205 if (rc == NGX_BUSY) { | 238 if (rc == NGX_BUSY) { |
206 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
207 | |
208 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, | 239 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, |
209 "limiting requests, excess: %ui.%03ui by zone \"%V\"", | 240 "limiting requests, excess: %ui.%03ui by zone \"%V\"", |
210 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); | 241 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
211 | 242 |
212 return NGX_HTTP_SERVICE_UNAVAILABLE; | 243 return NGX_HTTP_SERVICE_UNAVAILABLE; |
213 } | 244 } |
214 | 245 |
215 if (rc == NGX_AGAIN) { | 246 /* rc == NGX_AGAIN */ |
216 ngx_shmtx_unlock(&ctx->shpool->mutex); | 247 |
217 | 248 if (lrcf->nodelay) { |
218 if (lrcf->nodelay) { | 249 return NGX_DECLINED; |
219 return NGX_DECLINED; | 250 } |
220 } | 251 |
221 | 252 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, |
222 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, | 253 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
223 "delaying request, excess: %ui.%03ui, by zone \"%V\"", | 254 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
224 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); | 255 |
225 | 256 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
226 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { | 257 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
227 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 258 } |
228 } | 259 |
229 | 260 r->read_event_handler = ngx_http_test_reading; |
230 r->read_event_handler = ngx_http_test_reading; | 261 r->write_event_handler = ngx_http_limit_req_delay; |
231 r->write_event_handler = ngx_http_limit_req_delay; | 262 ngx_add_timer(r->connection->write, |
232 ngx_add_timer(r->connection->write, (ngx_msec_t) excess); | 263 (ngx_msec_t) excess * 1000 / ctx->rate); |
233 | 264 |
234 return NGX_AGAIN; | 265 return NGX_AGAIN; |
235 } | |
236 | |
237 if (rc == NGX_OK) { | |
238 goto done; | |
239 } | |
240 | |
241 /* rc == NGX_DECLINED */ | |
242 | |
243 n = offsetof(ngx_rbtree_node_t, color) | |
244 + offsetof(ngx_http_limit_req_node_t, data) | |
245 + len; | |
246 | |
247 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
248 if (node == NULL) { | |
249 | |
250 ngx_http_limit_req_expire(ctx, 0); | |
251 | |
252 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
253 if (node == NULL) { | |
254 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
255 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
256 } | |
257 } | |
258 | |
259 lr = (ngx_http_limit_req_node_t *) &node->color; | |
260 | |
261 node->key = hash; | |
262 lr->len = (u_char) len; | |
263 | |
264 tp = ngx_timeofday(); | |
265 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
266 | |
267 lr->excess = 0; | |
268 ngx_memcpy(lr->data, vv->data, len); | |
269 | |
270 ngx_rbtree_insert(&ctx->sh->rbtree, node); | |
271 | |
272 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
273 | |
274 done: | |
275 | |
276 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
277 | |
278 return NGX_DECLINED; | |
279 } | 266 } |
280 | 267 |
281 | 268 |
282 static void | 269 static void |
283 ngx_http_limit_req_delay(ngx_http_request_t *r) | 270 ngx_http_limit_req_delay(ngx_http_request_t *r) |
353 } | 340 } |
354 | 341 |
355 | 342 |
356 static ngx_int_t | 343 static ngx_int_t |
357 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, | 344 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, |
358 u_char *data, size_t len, ngx_http_limit_req_node_t **lrp) | 345 u_char *data, size_t len, ngx_uint_t *ep) |
359 { | 346 { |
360 ngx_int_t rc, excess; | 347 ngx_int_t rc, excess; |
361 ngx_time_t *tp; | 348 ngx_time_t *tp; |
362 ngx_msec_t now; | 349 ngx_msec_t now; |
363 ngx_msec_int_t ms; | 350 ngx_msec_int_t ms; |
388 lr = (ngx_http_limit_req_node_t *) &node->color; | 375 lr = (ngx_http_limit_req_node_t *) &node->color; |
389 | 376 |
390 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); | 377 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); |
391 | 378 |
392 if (rc == 0) { | 379 if (rc == 0) { |
380 ngx_queue_remove(&lr->queue); | |
381 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
393 | 382 |
394 tp = ngx_timeofday(); | 383 tp = ngx_timeofday(); |
395 | 384 |
396 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 385 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
397 ms = (ngx_msec_int_t) (now - lr->last); | 386 ms = (ngx_msec_int_t) (now - lr->last); |
400 | 389 |
401 if (excess < 0) { | 390 if (excess < 0) { |
402 excess = 0; | 391 excess = 0; |
403 } | 392 } |
404 | 393 |
394 *ep = excess; | |
395 | |
405 if ((ngx_uint_t) excess > lrcf->burst) { | 396 if ((ngx_uint_t) excess > lrcf->burst) { |
406 *lrp = lr; | |
407 return NGX_BUSY; | 397 return NGX_BUSY; |
408 } | 398 } |
409 | 399 |
410 lr->excess = excess; | 400 lr->excess = excess; |
411 lr->last = now; | 401 lr->last = now; |
412 | |
413 *lrp = lr; | |
414 | 402 |
415 if (excess) { | 403 if (excess) { |
416 return NGX_AGAIN; | 404 return NGX_AGAIN; |
417 } | 405 } |
418 | 406 |
424 } while (node != sentinel && hash == node->key); | 412 } while (node != sentinel && hash == node->key); |
425 | 413 |
426 break; | 414 break; |
427 } | 415 } |
428 | 416 |
429 *lrp = NULL; | 417 *ep = 0; |
430 | 418 |
431 return NGX_DECLINED; | 419 return NGX_DECLINED; |
432 } | 420 } |
433 | 421 |
434 | 422 |