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