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