0
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
660
|
4 * Copyright (C) Nginx, Inc.
|
0
|
5 */
|
|
6
|
|
7
|
|
8 #include <ngx_config.h>
|
|
9 #include <ngx_core.h>
|
|
10 #include <ngx_http.h>
|
|
11
|
|
12
|
|
13
|
340
|
14 static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
|
|
15 ngx_http_busy_lock_ctx_t *bc,
|
|
16 int lock);
|
0
|
17
|
|
18
|
|
19 int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc)
|
|
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
|
58
|
50 #if 0
|
0
|
51 ngx_add_timer(bc->event, 1000);
|
|
52 bc->event->event_handler = bc->event_handler;
|
58
|
53 #endif
|
0
|
54
|
|
55 /* TODO: ngx_handle_level_read_event() */
|
|
56
|
|
57 return NGX_AGAIN;
|
|
58 }
|
|
59
|
|
60 return NGX_ERROR;
|
|
61 }
|
|
62
|
|
63
|
340
|
64 int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
|
|
65 ngx_http_busy_lock_ctx_t *bc, int lock)
|
0
|
66 {
|
|
67 int rc;
|
|
68
|
340
|
69 rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);
|
0
|
70
|
|
71 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, bc->event->log, 0,
|
|
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) {
|
58
|
101 #if 0
|
0
|
102 bl->waiting++;
|
|
103 ngx_add_timer(bc->event, 1000);
|
|
104 bc->event->event_handler = bc->event_handler;
|
58
|
105 #endif
|
0
|
106
|
|
107 /* TODO: ngx_handle_level_read_event() */
|
|
108
|
|
109 return NGX_AGAIN;
|
|
110 }
|
|
111
|
|
112 return NGX_ERROR;
|
|
113 }
|
|
114
|
|
115
|
|
116 void ngx_http_busy_unlock(ngx_http_busy_lock_t *bl,
|
|
117 ngx_http_busy_lock_ctx_t *bc)
|
|
118 {
|
|
119 if (bl == NULL) {
|
|
120 return;
|
|
121 }
|
|
122
|
|
123 if (bl->md5) {
|
|
124 bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
|
340
|
125 bl->cacheable--;
|
0
|
126 }
|
|
127
|
|
128 bl->busy--;
|
|
129 }
|
|
130
|
|
131
|
340
|
132 static int ngx_http_busy_lock_look_cacheable(ngx_http_busy_lock_t *bl,
|
|
133 ngx_http_busy_lock_ctx_t *bc,
|
|
134 int lock)
|
0
|
135 {
|
340
|
136 int i, b, cacheable, free;
|
0
|
137 u_int mask;
|
|
138
|
|
139 b = 0;
|
340
|
140 cacheable = 0;
|
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 }
|
340
|
157 cacheable++;
|
0
|
158
|
|
159 } else if (free == -1) {
|
|
160 free = i;
|
|
161 }
|
|
162
|
|
163 #if 1
|
340
|
164 if (cacheable == bl->cacheable) {
|
|
165 if (free == -1 && cacheable < bl->max_busy) {
|
0
|
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
|
340
|
190 bl->cacheable++;
|
0
|
191 bl->busy++;
|
|
192 }
|
|
193
|
|
194 return NGX_OK;
|
|
195 }
|
|
196
|
|
197
|
|
198 char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
|
|
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() */
|
50
|
213 bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
|
|
214 if (bl == NULL) {
|
0
|
215 return NGX_CONF_ERROR;
|
|
216 }
|
|
217 *blp = bl;
|
|
218
|
|
219 /* ngx_calloc_shared() */
|
50
|
220 bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
|
|
221 if (bl->mutex == NULL) {
|
0
|
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] != '=') {
|
|
232 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
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);
|
662
|
277 if (bl->timeout == (time_t) NGX_ERROR) {
|
0
|
278 invalid = 1;
|
|
279 break;
|
|
280 }
|
|
281
|
|
282 continue;
|
|
283
|
|
284 default:
|
|
285 invalid = 1;
|
|
286 }
|
|
287
|
|
288 if (dup) {
|
|
289 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
290 "duplicate value \"%s\"", value[i].data);
|
|
291 return NGX_CONF_ERROR;
|
|
292 }
|
|
293
|
|
294 if (invalid) {
|
|
295 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
|
|
296 "invalid value \"%s\"", value[i].data);
|
|
297 return NGX_CONF_ERROR;
|
|
298 }
|
|
299 }
|
|
300
|
|
301 if (bl->timeout == 0 && bl->max_waiting) {
|
|
302 ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
666
|
303 "busy lock waiting is useless with zero timeout, ignoring");
|
0
|
304 }
|
|
305
|
|
306 return NGX_CONF_OK;
|
|
307 }
|