Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_busy_lock.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 
12 
13 
14 static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
16  int lock);
17 
18 
20 {
21  if (bl->busy < bl->max_busy) {
22  bl->busy++;
23 
24  if (bc->time) {
25  bc->time = 0;
26  bl->waiting--;
27  }
28 
29  return NGX_OK;
30  }
31 
32  if (bc->time) {
33  if (bc->time < bl->timeout) {
34  ngx_add_timer(bc->event, 1000);
35  return NGX_AGAIN;
36  }
37 
38  bl->waiting--;
39  return NGX_DONE;
40 
41  }
42 
43  if (bl->timeout == 0) {
44  return NGX_DONE;
45  }
46 
47  if (bl->waiting < bl->max_waiting) {
48  bl->waiting++;
49 
50 #if 0
51  ngx_add_timer(bc->event, 1000);
52  bc->event->event_handler = bc->event_handler;
53 #endif
54 
55  /* TODO: ngx_handle_level_read_event() */
56 
57  return NGX_AGAIN;
58  }
59 
60  return NGX_ERROR;
61 }
62 
63 
65  ngx_http_busy_lock_ctx_t *bc, int lock)
66 {
67  int rc;
68 
69  rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);
70 
72  "http busylock: %d w:%d mw::%d",
73  rc, bl->waiting, bl->max_waiting);
74 
75  if (rc == NGX_OK) { /* no the same request, there's free slot */
76  return NGX_OK;
77  }
78 
79  if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */
80  return NGX_OK;
81  }
82 
83  /* rc == NGX_AGAIN: the same request */
84 
85  if (bc->time) {
86  if (bc->time < bl->timeout) {
87  ngx_add_timer(bc->event, 1000);
88  return NGX_AGAIN;
89  }
90 
91  bl->waiting--;
92  return NGX_DONE;
93 
94  }
95 
96  if (bl->timeout == 0) {
97  return NGX_DONE;
98  }
99 
100  if (bl->waiting < bl->max_waiting) {
101 #if 0
102  bl->waiting++;
103  ngx_add_timer(bc->event, 1000);
104  bc->event->event_handler = bc->event_handler;
105 #endif
106 
107  /* TODO: ngx_handle_level_read_event() */
108 
109  return NGX_AGAIN;
110  }
111 
112  return NGX_ERROR;
113 }
114 
115 
118 {
119  if (bl == NULL) {
120  return;
121  }
122 
123  if (bl->md5) {
124  bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
125  bl->cacheable--;
126  }
127 
128  bl->busy--;
129 }
130 
131 
132 static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
134  int lock)
135 {
136  int i, b, cacheable, free;
137  u_int mask;
138 
139  b = 0;
140  cacheable = 0;
141  free = -1;
142 
143 #if (NGX_SUPPRESS_WARN)
144  mask = 0;
145 #endif
146 
147  for (i = 0; i < bl->max_busy; i++) {
148 
149  if ((b & 7) == 0) {
150  mask = bl->md5_mask[i / 8];
151  }
152 
153  if (mask & 1) {
154  if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) {
155  return NGX_AGAIN;
156  }
157  cacheable++;
158 
159  } else if (free == -1) {
160  free = i;
161  }
162 
163 #if 1
164  if (cacheable == bl->cacheable) {
165  if (free == -1 && cacheable < bl->max_busy) {
166  free = i + 1;
167  }
168 
169  break;
170  }
171 #endif
172 
173  mask >>= 1;
174  b++;
175  }
176 
177  if (free == -1) {
178  return NGX_ERROR;
179  }
180 
181  if (lock) {
182  if (bl->busy == bl->max_busy) {
183  return NGX_ERROR;
184  }
185 
186  ngx_memcpy(&bl->md5[free * 16], bc->md5, 16);
187  bl->md5_mask[free / 8] |= 1 << (free & 7);
188  bc->slot = free;
189 
190  bl->cacheable++;
191  bl->busy++;
192  }
193 
194  return NGX_OK;
195 }
196 
197 
199  void *conf)
200 {
201  char *p = conf;
202 
203  ngx_uint_t i, dup, invalid;
204  ngx_str_t *value, line;
205  ngx_http_busy_lock_t *bl, **blp;
206 
207  blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
208  if (*blp) {
209  return "is duplicate";
210  }
211 
212  /* ngx_calloc_shared() */
213  bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
214  if (bl == NULL) {
215  return NGX_CONF_ERROR;
216  }
217  *blp = bl;
218 
219  /* ngx_calloc_shared() */
220  bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
221  if (bl->mutex == NULL) {
222  return NGX_CONF_ERROR;
223  }
224 
225  dup = 0;
226  invalid = 0;
227  value = cf->args->elts;
228 
229  for (i = 1; i < cf->args->nelts; i++) {
230 
231  if (value[i].data[1] != '=') {
233  "invalid value \"%s\"", value[i].data);
234  return NGX_CONF_ERROR;
235  }
236 
237  switch (value[i].data[0]) {
238 
239  case 'b':
240  if (bl->max_busy) {
241  dup = 1;
242  break;
243  }
244 
245  bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
246  if (bl->max_busy == NGX_ERROR) {
247  invalid = 1;
248  break;
249  }
250 
251  continue;
252 
253  case 'w':
254  if (bl->max_waiting) {
255  dup = 1;
256  break;
257  }
258 
259  bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
260  if (bl->max_waiting == NGX_ERROR) {
261  invalid = 1;
262  break;
263  }
264 
265  continue;
266 
267  case 't':
268  if (bl->timeout) {
269  dup = 1;
270  break;
271  }
272 
273  line.len = value[i].len - 2;
274  line.data = value[i].data + 2;
275 
276  bl->timeout = ngx_parse_time(&line, 1);
277  if (bl->timeout == (time_t) NGX_ERROR) {
278  invalid = 1;
279  break;
280  }
281 
282  continue;
283 
284  default:
285  invalid = 1;
286  }
287 
288  if (dup) {
290  "duplicate value \"%s\"", value[i].data);
291  return NGX_CONF_ERROR;
292  }
293 
294  if (invalid) {
296  "invalid value \"%s\"", value[i].data);
297  return NGX_CONF_ERROR;
298  }
299  }
300 
301  if (bl->timeout == 0 && bl->max_waiting) {
303  "busy lock waiting is useless with zero timeout, ignoring");
304  }
305 
306  return NGX_CONF_OK;
307 }