diff src/http/ngx_http_busy_lock.c @ 0:f0b350454894 NGINX_0_1_0

nginx 0.1.0 *) The first public version.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Oct 2004 00:00:00 +0400
parents
children 72eb30262aac
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/http/ngx_http_busy_lock.c
@@ -0,0 +1,300 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+
+static int ngx_http_busy_lock_look_cachable(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++;
+
+        ngx_add_timer(bc->event, 1000);
+        bc->event->event_handler = bc->event_handler;
+
+        /* TODO: ngx_handle_level_read_event() */
+
+        return NGX_AGAIN;
+    }
+
+    return NGX_ERROR;
+}
+
+
+int ngx_http_busy_lock_cachable(ngx_http_busy_lock_t *bl,
+                                ngx_http_busy_lock_ctx_t *bc, int lock)
+{
+    int  rc;
+
+    rc = ngx_http_busy_lock_look_cachable(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) {
+        bl->waiting++;
+        ngx_add_timer(bc->event, 1000);
+        bc->event->event_handler = bc->event_handler;
+
+        /* 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->cachable--;
+    }
+
+    bl->busy--;
+}
+
+
+static int ngx_http_busy_lock_look_cachable(ngx_http_busy_lock_t *bl,
+                                            ngx_http_busy_lock_ctx_t *bc,
+                                            int lock)
+{
+    int    i, b, cachable, free;
+    u_int  mask;
+
+    b = 0;
+    cachable = 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;
+            }
+            cachable++;
+
+        } else if (free == -1) {
+            free = i;
+        }
+
+#if 1
+        if (cachable == bl->cachable) {
+            if (free == -1 && cachable < 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->cachable++;
+        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() */
+    if (!(bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t)))) {
+        return NGX_CONF_ERROR;
+    }
+    *blp = bl;
+
+    /* ngx_calloc_shared() */
+    if (!(bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)))) {
+        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 == 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;
+}