Mercurial > hg > nginx-quic
view src/http/ngx_http_busy_lock.c @ 4497:95ab6658654a
Fix of rbtree lookup on hash collisions.
Previous code incorrectly assumed that nodes with identical keys are linked
together. This might not be true after tree rebalance.
Patch by Lanshun Zhou.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 27 Feb 2012 22:15:39 +0000 |
parents | 41f640a693de |
children | 14411ee4d89f |
line wrap: on
line source
/* * Copyright (C) Igor Sysoev * Copyright (C) Nginx, Inc. */ #include <ngx_config.h> #include <ngx_core.h> #include <ngx_http.h> static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc, int lock); int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc) { if (bl->busy < bl->max_busy) { bl->busy++; if (bc->time) { bc->time = 0; bl->waiting--; } return NGX_OK; } if (bc->time) { if (bc->time < bl->timeout) { ngx_add_timer(bc->event, 1000); return NGX_AGAIN; } bl->waiting--; return NGX_DONE; } if (bl->timeout == 0) { return NGX_DONE; } if (bl->waiting < bl->max_waiting) { bl->waiting++; #if 0 ngx_add_timer(bc->event, 1000); bc->event->event_handler = bc->event_handler; #endif /* TODO: ngx_handle_level_read_event() */ return NGX_AGAIN; } return NGX_ERROR; } int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc, int lock) { int rc; rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0, "http busylock: %d w:%d mw::%d", rc, bl->waiting, bl->max_waiting); if (rc == NGX_OK) { /* no the same request, there's free slot */ return NGX_OK; } if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */ return NGX_OK; } /* rc == NGX_AGAIN: the same request */ if (bc->time) { if (bc->time < bl->timeout) { ngx_add_timer(bc->event, 1000); return NGX_AGAIN; } bl->waiting--; return NGX_DONE; } if (bl->timeout == 0) { return NGX_DONE; } if (bl->waiting < bl->max_waiting) { #if 0 bl->waiting++; ngx_add_timer(bc->event, 1000); bc->event->event_handler = bc->event_handler; #endif /* TODO: ngx_handle_level_read_event() */ return NGX_AGAIN; } return NGX_ERROR; } void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc) { if (bl == NULL) { return; } if (bl->md5) { bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7)); bl->cacheable--; } bl->busy--; } static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc, int lock) { int i, b, cacheable, free; u_int mask; b = 0; cacheable = 0; free = -1; #if (NGX_SUPPRESS_WARN) mask = 0; #endif for (i = 0; i < bl->max_busy; i++) { if ((b & 7) == 0) { mask = bl->md5_mask[i / 8]; } if (mask & 1) { if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) { return NGX_AGAIN; } cacheable++; } else if (free == -1) { free = i; } #if 1 if (cacheable == bl->cacheable) { if (free == -1 && cacheable < bl->max_busy) { free = i + 1; } break; } #endif mask >>= 1; b++; } if (free == -1) { return NGX_ERROR; } if (lock) { if (bl->busy == bl->max_busy) { return NGX_ERROR; } ngx_memcpy(&bl->md5[free * 16], bc->md5, 16); bl->md5_mask[free / 8] |= 1 << (free & 7); bc->slot = free; bl->cacheable++; bl->busy++; } return NGX_OK; } char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *p = conf; ngx_uint_t i, dup, invalid; ngx_str_t *value, line; ngx_http_busy_lock_t *bl, **blp; blp = (ngx_http_busy_lock_t **) (p + cmd->offset); if (*blp) { return "is duplicate"; } /* ngx_calloc_shared() */ bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t)); if (bl == NULL) { return NGX_CONF_ERROR; } *blp = bl; /* ngx_calloc_shared() */ bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)); if (bl->mutex == NULL) { return NGX_CONF_ERROR; } dup = 0; invalid = 0; value = cf->args->elts; for (i = 1; i < cf->args->nelts; i++) { if (value[i].data[1] != '=') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%s\"", value[i].data); return NGX_CONF_ERROR; } switch (value[i].data[0]) { case 'b': if (bl->max_busy) { dup = 1; break; } bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2); if (bl->max_busy == NGX_ERROR) { invalid = 1; break; } continue; case 'w': if (bl->max_waiting) { dup = 1; break; } bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2); if (bl->max_waiting == NGX_ERROR) { invalid = 1; break; } continue; case 't': if (bl->timeout) { dup = 1; break; } line.len = value[i].len - 2; line.data = value[i].data + 2; bl->timeout = ngx_parse_time(&line, 1); if (bl->timeout == (time_t) NGX_ERROR) { invalid = 1; break; } continue; default: invalid = 1; } if (dup) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "duplicate value \"%s\"", value[i].data); return NGX_CONF_ERROR; } if (invalid) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%s\"", value[i].data); return NGX_CONF_ERROR; } } if (bl->timeout == 0 && bl->max_waiting) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "busy lock waiting is useless with zero timeout, ignoring"); } return NGX_CONF_OK; }