0
|
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
|
340
|
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);
|
0
|
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
|
58
|
49 #if 0
|
0
|
50 ngx_add_timer(bc->event, 1000);
|
|
51 bc->event->event_handler = bc->event_handler;
|
58
|
52 #endif
|
0
|
53
|
|
54 /* TODO: ngx_handle_level_read_event() */
|
|
55
|
|
56 return NGX_AGAIN;
|
|
57 }
|
|
58
|
|
59 return NGX_ERROR;
|
|
60 }
|
|
61
|
|
62
|
340
|
63 int ngx_http_busy_lock_cacheable(ngx_http_busy_lock_t *bl,
|
|
64 ngx_http_busy_lock_ctx_t *bc, int lock)
|
0
|
65 {
|
|
66 int rc;
|
|
67
|
340
|
68 rc = ngx_http_busy_lock_look_cacheable(bl, bc, lock);
|
0
|
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) {
|
58
|
100 #if 0
|
0
|
101 bl->waiting++;
|
|
102 ngx_add_timer(bc->event, 1000);
|
|
103 bc->event->event_handler = bc->event_handler;
|
58
|
104 #endif
|
0
|
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));
|
340
|
124 bl->cacheable--;
|
0
|
125 }
|
|
126
|
|
127 bl->busy--;
|
|
128 }
|
|
129
|
|
130
|
340
|
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)
|
0
|
134 {
|
340
|
135 int i, b, cacheable, free;
|
0
|
136 u_int mask;
|
|
137
|
|
138 b = 0;
|
340
|
139 cacheable = 0;
|
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 }
|
340
|
156 cacheable++;
|
0
|
157
|
|
158 } else if (free == -1) {
|
|
159 free = i;
|
|
160 }
|
|
161
|
|
162 #if 1
|
340
|
163 if (cacheable == bl->cacheable) {
|
|
164 if (free == -1 && cacheable < bl->max_busy) {
|
0
|
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
|
340
|
189 bl->cacheable++;
|
0
|
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() */
|
50
|
212 bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t));
|
|
213 if (bl == NULL) {
|
0
|
214 return NGX_CONF_ERROR;
|
|
215 }
|
|
216 *blp = bl;
|
|
217
|
|
218 /* ngx_calloc_shared() */
|
50
|
219 bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t));
|
|
220 if (bl->mutex == NULL) {
|
0
|
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 }
|