src/http/ngx_http_busy_lock.c - nginx-1.7.10

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_http.h>



  8. static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
  9.                                              ngx_http_busy_lock_ctx_t *bc,
  10.                                              int lock);


  11. int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc)
  12. {
  13.     if (bl->busy < bl->max_busy) {
  14.         bl->busy++;

  15.         if (bc->time) {
  16.             bc->time = 0;
  17.             bl->waiting--;
  18.         }

  19.         return NGX_OK;
  20.     }

  21.     if (bc->time) {
  22.         if (bc->time < bl->timeout) {
  23.             ngx_add_timer(bc->event, 1000);
  24.             return NGX_AGAIN;
  25.         }

  26.         bl->waiting--;
  27.         return NGX_DONE;

  28.     }

  29.     if (bl->timeout == 0) {
  30.         return NGX_DONE;
  31.     }

  32.     if (bl->waiting < bl->max_waiting) {
  33.         bl->waiting++;

  34. #if 0
  35.         ngx_add_timer(bc->event, 1000);
  36.         bc->event->event_handler = bc->event_handler;
  37. #endif

  38.         /* TODO: ngx_handle_level_read_event() */

  39.         return NGX_AGAIN;
  40.     }

  41.     return NGX_ERROR;
  42. }


  43. int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
  44.                                  ngx_http_busy_lock_ctx_t *bc, int lock)
  45. {
  46.     int  rc;

  47.     rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);

  48.     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0,
  49.                    "http busylock: %d w:%d mw::%d",
  50.                    rc, bl->waiting, bl->max_waiting);

  51.     if (rc == NGX_OK) {  /* no the same request, there's free slot */
  52.         return NGX_OK;
  53.     }

  54.     if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */
  55.         return NGX_OK;
  56.     }

  57.     /* rc == NGX_AGAIN:  the same request */

  58.     if (bc->time) {
  59.         if (bc->time < bl->timeout) {
  60.             ngx_add_timer(bc->event, 1000);
  61.             return NGX_AGAIN;
  62.         }

  63.         bl->waiting--;
  64.         return NGX_DONE;

  65.     }

  66.     if (bl->timeout == 0) {
  67.         return NGX_DONE;
  68.     }

  69.     if (bl->waiting < bl->max_waiting) {
  70. #if 0
  71.         bl->waiting++;
  72.         ngx_add_timer(bc->event, 1000);
  73.         bc->event->event_handler = bc->event_handler;
  74. #endif

  75.         /* TODO: ngx_handle_level_read_event() */

  76.         return NGX_AGAIN;
  77.     }

  78.     return NGX_ERROR;
  79. }


  80. void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
  81.                           ngx_http_busy_lock_ctx_t *bc)
  82. {
  83.     if (bl == NULL) {
  84.         return;
  85.     }

  86.     if (bl->md5) {
  87.         bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
  88.         bl->cacheable--;
  89.     }

  90.     bl->busy--;
  91. }


  92. static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
  93.                                              ngx_http_busy_lock_ctx_t *bc,
  94.                                              int lock)
  95. {
  96.     int    i, b, cacheable, free;
  97.     u_int  mask;

  98.     b = 0;
  99.     cacheable = 0;
  100.     free = -1;

  101. #if (NGX_SUPPRESS_WARN)
  102.     mask = 0;
  103. #endif

  104.     for (i = 0; i < bl->max_busy; i++) {

  105.         if ((b & 7) == 0) {
  106.             mask = bl->md5_mask[i / 8];
  107.         }

  108.         if (mask & 1) {
  109.             if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) {
  110.                 return NGX_AGAIN;
  111.             }
  112.             cacheable++;

  113.         } else if (free == -1) {
  114.             free = i;
  115.         }

  116. #if 1
  117.         if (cacheable == bl->cacheable) {
  118.             if (free == -1 && cacheable < bl->max_busy) {
  119.                 free = i + 1;
  120.             }

  121.             break;
  122.         }
  123. #endif

  124.         mask >>= 1;
  125.         b++;
  126.     }

  127.     if (free == -1) {
  128.         return NGX_ERROR;
  129.     }

  130.     if (lock) {
  131.         if (bl->busy == bl->max_busy) {
  132.             return NGX_ERROR;
  133.         }

  134.         ngx_memcpy(&bl->md5[free * 16], bc->md5, 16);
  135.         bl->md5_mask[free / 8] |= 1 << (free & 7);
  136.         bc->slot = free;

  137.         bl->cacheable++;
  138.         bl->busy++;
  139.     }

  140.     return NGX_OK;
  141. }


  142. char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
  143.                                   void *conf)
  144. {
  145.     char  *p = conf;

  146.     ngx_uint_t             i, dup, invalid;
  147.     ngx_str_t             *value, line;
  148.     ngx_http_busy_lock_t  *bl, **blp;

  149.     blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
  150.     if (*blp) {
  151.         return "is duplicate";
  152.     }

  153.     /* ngx_calloc_shared() */
  154.     bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
  155.     if (bl == NULL) {
  156.         return NGX_CONF_ERROR;
  157.     }
  158.     *blp = bl;

  159.     /* ngx_calloc_shared() */
  160.     bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
  161.     if (bl->mutex == NULL) {
  162.         return NGX_CONF_ERROR;
  163.     }

  164.     dup = 0;
  165.     invalid = 0;
  166.     value = cf->args->elts;

  167.     for (i = 1; i < cf->args->nelts; i++) {

  168.         if (value[i].data[1] != '=') {
  169.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  170.                            "invalid value \"%s\"", value[i].data);
  171.             return NGX_CONF_ERROR;
  172.         }

  173.         switch (value[i].data[0]) {

  174.         case 'b':
  175.             if (bl->max_busy) {
  176.                 dup = 1;
  177.                 break;
  178.             }

  179.             bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
  180.             if (bl->max_busy == NGX_ERROR) {
  181.                 invalid = 1;
  182.                 break;
  183.             }

  184.             continue;

  185.         case 'w':
  186.             if (bl->max_waiting) {
  187.                 dup = 1;
  188.                 break;
  189.             }

  190.             bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
  191.             if (bl->max_waiting == NGX_ERROR) {
  192.                 invalid = 1;
  193.                 break;
  194.             }

  195.             continue;

  196.         case 't':
  197.             if (bl->timeout) {
  198.                 dup = 1;
  199.                 break;
  200.             }

  201.             line.len = value[i].len - 2;
  202.             line.data = value[i].data + 2;

  203.             bl->timeout = ngx_parse_time(&line, 1);
  204.             if (bl->timeout == (time_t) NGX_ERROR) {
  205.                 invalid = 1;
  206.                 break;
  207.             }

  208.             continue;

  209.         default:
  210.             invalid = 1;
  211.         }

  212.         if (dup) {
  213.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  214.                                "duplicate value \"%s\"", value[i].data);
  215.             return NGX_CONF_ERROR;
  216.         }

  217.         if (invalid) {
  218.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  219.                                "invalid value \"%s\"", value[i].data);
  220.             return NGX_CONF_ERROR;
  221.         }
  222.     }

  223.     if (bl->timeout == 0 && bl->max_waiting) {
  224.         ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
  225.                    "busy lock waiting is useless with zero timeout, ignoring");
  226.     }

  227.     return NGX_CONF_OK;
  228. }