507
|
1
|
|
2 /*
|
|
3 * Copyright (C) Igor Sysoev
|
|
4 */
|
|
5
|
|
6
|
|
7 #include <ngx_config.h>
|
|
8 #include <ngx_core.h>
|
|
9
|
|
10
|
589
|
11 void *
|
|
12 ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
|
|
13 {
|
|
14 ngx_uint_t i;
|
|
15 ngx_hash_elt_t *elt;
|
|
16
|
|
17 #if 0
|
|
18 ngx_str_t line;
|
|
19
|
|
20 line.len = len;
|
|
21 line.data = name;
|
|
22 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%V\"", &line);
|
|
23 #endif
|
|
24
|
|
25 elt = hash->buckets[key % hash->size];
|
|
26
|
|
27 if (elt == NULL) {
|
|
28 return NULL;
|
|
29 }
|
|
30
|
|
31 while (elt->value) {
|
|
32 if (len != (size_t) elt->len) {
|
|
33 goto next;
|
|
34 }
|
|
35
|
|
36 for (i = 0; i < len; i++) {
|
|
37 if (name[i] != elt->name[i]) {
|
|
38 goto next;
|
|
39 }
|
|
40 }
|
|
41
|
|
42 return elt->value;
|
|
43
|
|
44 next:
|
|
45
|
|
46 elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
|
|
47 sizeof(void *));
|
|
48 continue;
|
|
49 }
|
|
50
|
|
51 return NULL;
|
|
52 }
|
|
53
|
|
54
|
|
55 void *
|
|
56 ngx_hash_find_wildcard(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
|
|
57 {
|
|
58 void *value;
|
|
59 ngx_uint_t i, n, key;
|
|
60
|
|
61 #if 0
|
|
62 ngx_str_t line;
|
|
63
|
|
64 line.len = len;
|
|
65 line.data = name;
|
|
66 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wc:\"%V\"", &line);
|
|
67 #endif
|
|
68
|
|
69 n = len;
|
|
70
|
|
71 while (n) {
|
|
72 if (name[n - 1] == '.') {
|
|
73 break;
|
|
74 }
|
|
75
|
|
76 n--;
|
|
77 }
|
|
78
|
|
79 key = 0;
|
|
80
|
|
81 for (i = n; i < len; i++) {
|
|
82 key = ngx_hash(key, name[i]);
|
|
83 }
|
|
84
|
|
85 #if 0
|
|
86 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
|
|
87 #endif
|
|
88
|
|
89 value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);
|
|
90
|
|
91 if (value) {
|
591
|
92
|
|
93 /*
|
|
94 * the 2 low bits of value have the special meaning:
|
|
95 * 00 - value is data pointer,
|
|
96 * 01 - value is pointer to wildcard hash allowing
|
|
97 * "*.example.com" only,
|
|
98 * 11 - value is pointer to wildcard hash allowing
|
|
99 * both "example.com" and "*.example.com".
|
|
100 */
|
|
101
|
589
|
102 if ((uintptr_t) value & 1) {
|
591
|
103
|
|
104 hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
|
|
105
|
|
106 if (n == 0) {
|
|
107 if ((uintptr_t) value & 2) {
|
|
108 return hwc->value;
|
|
109
|
|
110 } else {
|
|
111 return NULL;
|
|
112 }
|
|
113 }
|
589
|
114
|
|
115 value = ngx_hash_find_wildcard(hwc, name, n - 1);
|
|
116
|
|
117 if (value) {
|
|
118 return value;
|
|
119 }
|
|
120
|
|
121 return hwc->value;
|
|
122 }
|
|
123
|
|
124 return value;
|
|
125 }
|
|
126
|
|
127 return hwc->value;
|
|
128 }
|
|
129
|
|
130
|
|
131 #define NGX_HASH_ELT_SIZE(name) \
|
|
132 sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *))
|
|
133
|
507
|
134 ngx_int_t
|
589
|
135 ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
|
|
136 {
|
|
137 u_char *elts;
|
|
138 size_t *test, len;
|
|
139 ngx_uint_t i, n, key, size, start, bucket_size;
|
|
140 ngx_hash_elt_t *elt, **buckets;
|
|
141
|
|
142 for (n = 0; n < nelts; n++) {
|
|
143 if (names[n].key.len >= 255) {
|
|
144 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
|
|
145 "the \"%V\" value to hash is to long: %uz bytes, "
|
|
146 "the maximum length can be 255 bytes only",
|
|
147 &names[n].key, names[n].key.len);
|
|
148 return NGX_ERROR;
|
|
149 }
|
|
150
|
|
151 if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
|
|
152 {
|
|
153 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
|
|
154 "could not build the %s hash, you should "
|
|
155 "increase %s_bucket_size: %i",
|
|
156 hinit->name, hinit->name, hinit->bucket_size);
|
|
157 return NGX_ERROR;
|
|
158 }
|
|
159 }
|
|
160
|
|
161 test = ngx_alloc(hinit->max_size * sizeof(ngx_uint_t), hinit->pool->log);
|
|
162 if (test == NULL) {
|
|
163 return NGX_ERROR;
|
|
164 }
|
|
165
|
|
166 start = nelts / (ngx_cacheline_size / (2 * sizeof(void *)) - 1);
|
|
167 start = start ? start : 1;
|
|
168
|
|
169 bucket_size = hinit->bucket_size - sizeof(void *);
|
|
170
|
|
171 for (size = start; size < hinit->max_size; size++) {
|
|
172
|
|
173 ngx_memzero(test, size * sizeof(ngx_uint_t));
|
|
174
|
|
175 for (n = 0; n < nelts; n++) {
|
|
176 if (names[n].key.data == NULL) {
|
|
177 continue;
|
|
178 }
|
|
179
|
|
180 key = names[n].key_hash % size;
|
|
181 test[key] += NGX_HASH_ELT_SIZE(&names[n]);
|
|
182
|
|
183 #if 0
|
|
184 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
185 "%ui: %ui %ui \"%V\"",
|
|
186 size, key, test[key], &names[n].key);
|
|
187 #endif
|
|
188
|
|
189 if (test[key] > bucket_size) {
|
|
190 goto next;
|
|
191 }
|
|
192 }
|
|
193
|
|
194 goto found;
|
|
195
|
|
196 next:
|
|
197
|
|
198 continue;
|
|
199 }
|
|
200
|
|
201 ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
|
|
202 "could not build the %s hash, you should increase "
|
|
203 "either %s_max_size: %i or %s_bucket_size: %i",
|
|
204 hinit->name, hinit->name, hinit->max_size,
|
|
205 hinit->name, hinit->bucket_size);
|
|
206
|
|
207 ngx_free(test);
|
|
208
|
|
209 return NGX_ERROR;
|
|
210
|
|
211 found:
|
|
212
|
|
213 for (i = 0; i < size; i++) {
|
|
214 test[i] = sizeof(void *);
|
|
215 }
|
|
216
|
|
217 for (n = 0; n < nelts; n++) {
|
|
218 if (names[n].key.data == NULL) {
|
|
219 continue;
|
|
220 }
|
|
221
|
|
222 key = names[n].key_hash % size;
|
|
223 test[key] += NGX_HASH_ELT_SIZE(&names[n]);
|
|
224 }
|
|
225
|
|
226 len = 0;
|
|
227
|
|
228 for (i = 0; i < size; i++) {
|
|
229 if (test[i] == sizeof(void *)) {
|
|
230 continue;
|
|
231 }
|
|
232
|
|
233 test[i] = ngx_align(test[i], ngx_cacheline_size);
|
|
234
|
|
235 len += test[i];
|
|
236 }
|
|
237
|
|
238 if (hinit->hash == NULL) {
|
|
239 hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
|
|
240 + size * sizeof(ngx_hash_elt_t *));
|
|
241 if (hinit->hash == NULL) {
|
|
242 ngx_free(test);
|
|
243 return NGX_ERROR;
|
|
244 }
|
|
245
|
|
246 buckets = (ngx_hash_elt_t **)
|
|
247 ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));
|
|
248
|
|
249 } else {
|
|
250 buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
|
|
251 if (buckets == NULL) {
|
|
252 ngx_free(test);
|
|
253 return NGX_ERROR;
|
|
254 }
|
|
255 }
|
|
256
|
|
257 elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
|
|
258 if (elts == NULL) {
|
|
259 ngx_free(test);
|
|
260 return NGX_ERROR;
|
|
261 }
|
|
262
|
|
263 elts = ngx_align_ptr(elts, ngx_cacheline_size);
|
|
264
|
|
265 for (i = 0; i < size; i++) {
|
|
266 if (test[i] == sizeof(void *)) {
|
|
267 continue;
|
|
268 }
|
|
269
|
|
270 buckets[i] = (ngx_hash_elt_t *) elts;
|
|
271 elts += test[i];
|
|
272
|
|
273 }
|
|
274
|
|
275 for (i = 0; i < size; i++) {
|
|
276 test[i] = 0;
|
|
277 }
|
|
278
|
|
279 for (n = 0; n < nelts; n++) {
|
|
280 if (names[n].key.data == NULL) {
|
|
281 continue;
|
|
282 }
|
|
283
|
|
284 key = names[n].key_hash % size;
|
|
285 elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
|
|
286
|
|
287 elt->value = names[n].value;
|
|
288 elt->len = (u_char) names[n].key.len;
|
|
289
|
|
290 for (i = 0; i < names[n].key.len; i++) {
|
|
291 elt->name[i] = ngx_tolower(names[n].key.data[i]);
|
|
292 }
|
|
293
|
|
294 test[key] += NGX_HASH_ELT_SIZE(&names[n]);
|
|
295 }
|
|
296
|
|
297 for (i = 0; i < size; i++) {
|
|
298 if (buckets[i] == NULL) {
|
|
299 continue;
|
|
300 }
|
|
301
|
|
302 elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);
|
|
303
|
|
304 elt->value = NULL;
|
|
305 }
|
|
306
|
|
307 ngx_free(test);
|
|
308
|
|
309 hinit->hash->buckets = buckets;
|
|
310 hinit->hash->size = size;
|
|
311
|
|
312 #if 0
|
|
313
|
|
314 for (i = 0; i < size; i++) {
|
|
315 ngx_str_t val;
|
|
316 ngx_uint_t key;
|
|
317
|
|
318 elt = buckets[i];
|
|
319
|
|
320 if (elt == NULL) {
|
|
321 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
322 "%ui: NULL", i);
|
|
323 continue;
|
|
324 }
|
|
325
|
|
326 while (elt->value) {
|
|
327 val.len = elt->len;
|
|
328 val.data = &elt->name[0];
|
|
329
|
|
330 key = hinit->key(val.data, val.len);
|
|
331
|
|
332 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
333 "%ui: %p \"%V\" %ui", i, elt, &val, key);
|
|
334
|
|
335 elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
|
|
336 sizeof(void *));
|
|
337 }
|
|
338 }
|
|
339
|
|
340 #endif
|
|
341
|
|
342 return NGX_OK;
|
|
343 }
|
|
344
|
|
345
|
|
346 ngx_int_t
|
|
347 ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
|
|
348 ngx_uint_t nelts)
|
|
349 {
|
|
350 size_t len;
|
591
|
351 ngx_uint_t i, n, dot;
|
589
|
352 ngx_array_t curr_names, next_names;
|
|
353 ngx_hash_key_t *name, *next_name;
|
|
354 ngx_hash_init_t h;
|
|
355 ngx_hash_wildcard_t *wdc;
|
|
356
|
|
357 if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
|
|
358 sizeof(ngx_hash_key_t))
|
|
359 != NGX_OK)
|
|
360 {
|
|
361 return NGX_ERROR;
|
|
362 }
|
|
363
|
|
364 if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
|
|
365 sizeof(ngx_hash_key_t))
|
|
366 != NGX_OK)
|
|
367 {
|
|
368 return NGX_ERROR;
|
|
369 }
|
|
370
|
|
371 for (n = 0; n < nelts; n = i) {
|
|
372
|
|
373 #if 0
|
|
374 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
375 "wc0: \"%V\"", &names[n].key);
|
|
376 #endif
|
|
377
|
591
|
378 dot = 0;
|
|
379
|
589
|
380 for (len = 0; len < names[n].key.len; len++) {
|
|
381 if (names[n].key.data[len] == '.') {
|
591
|
382 dot = 1;
|
589
|
383 break;
|
|
384 }
|
|
385 }
|
|
386
|
|
387 name = ngx_array_push(&curr_names);
|
|
388 if (name == NULL) {
|
|
389 return NGX_ERROR;
|
|
390 }
|
|
391
|
591
|
392 name->key.len = len;
|
589
|
393 name->key.data = names[n].key.data;
|
|
394 name->key_hash = hinit->key(name->key.data, name->key.len);
|
|
395 name->value = names[n].value;
|
|
396
|
|
397 #if 0
|
|
398 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
399 "wc1: \"%V\"", &name->key);
|
|
400 #endif
|
|
401
|
591
|
402 if (dot) {
|
|
403 len++;
|
|
404 }
|
|
405
|
589
|
406 next_names.nelts = 0;
|
|
407
|
|
408 if (names[n].key.len != len) {
|
|
409 next_name = ngx_array_push(&next_names);
|
|
410 if (next_name == NULL) {
|
|
411 return NGX_ERROR;
|
|
412 }
|
|
413
|
|
414 next_name->key.len = names[n].key.len - len;
|
|
415 next_name->key.data = names[n].key.data + len;
|
|
416 next_name->key_hash= 0;
|
|
417 next_name->value = names[n].value;
|
|
418
|
|
419 #if 0
|
|
420 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
421 "wc2: \"%V\"", &next_name->key);
|
|
422 #endif
|
|
423 }
|
|
424
|
|
425 for (i = n + 1; i < nelts; i++) {
|
|
426 if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
|
|
427 break;
|
|
428 }
|
|
429
|
|
430 next_name = ngx_array_push(&next_names);
|
|
431 if (next_name == NULL) {
|
|
432 return NGX_ERROR;
|
|
433 }
|
|
434
|
|
435 next_name->key.len = names[i].key.len - len;
|
|
436 next_name->key.data = names[i].key.data + len;
|
|
437 next_name->key_hash= 0;
|
|
438 next_name->value = names[i].value;
|
|
439
|
|
440 #if 0
|
|
441 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
591
|
442 "wc3: \"%V\"", &next_name->key);
|
589
|
443 #endif
|
|
444 }
|
|
445
|
|
446 if (next_names.nelts) {
|
|
447 h = *hinit;
|
|
448 h.hash = NULL;
|
|
449
|
|
450 if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
|
|
451 next_names.nelts)
|
|
452 != NGX_OK)
|
|
453 {
|
|
454 return NGX_ERROR;
|
|
455 }
|
|
456
|
|
457 wdc = (ngx_hash_wildcard_t *) h.hash;
|
|
458
|
|
459 if (names[n].key.len == len) {
|
|
460 wdc->value = names[n].value;
|
|
461 #if 0
|
|
462 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
|
|
463 "wdc: \"%V\"", wdc->value);
|
|
464 #endif
|
|
465 }
|
|
466
|
591
|
467 name->value = (void *) ((uintptr_t) wdc | (dot ? 1 : 3));
|
589
|
468 }
|
|
469 }
|
|
470
|
|
471 if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
|
|
472 curr_names.nelts)
|
|
473 != NGX_OK)
|
|
474 {
|
|
475 return NGX_ERROR;
|
|
476 }
|
|
477
|
|
478 return NGX_OK;
|
|
479 }
|
|
480
|
|
481
|
|
482 ngx_uint_t
|
|
483 ngx_hash_key(u_char *data, size_t len)
|
|
484 {
|
|
485 ngx_uint_t i, key;
|
|
486
|
|
487 key = 0;
|
|
488
|
|
489 for (i = 0; i < len; i++) {
|
|
490 key = ngx_hash(key, data[i]);
|
|
491 }
|
|
492
|
|
493 return key;
|
|
494 }
|
|
495
|
|
496
|
|
497 ngx_uint_t
|
|
498 ngx_hash_key_lc(u_char *data, size_t len)
|
|
499 {
|
|
500 ngx_uint_t i, key;
|
|
501
|
|
502 key = 0;
|
|
503
|
|
504 for (i = 0; i < len; i++) {
|
|
505 key = ngx_hash(key, ngx_tolower(data[i]));
|
|
506 }
|
|
507
|
|
508 return key;
|
|
509 }
|
|
510
|
|
511
|
|
512 ngx_int_t
|
|
513 ngx_hash0_init(ngx_hash0_t *hash, ngx_pool_t *pool, void *names,
|
|
514 ngx_uint_t nelts)
|
507
|
515 {
|
|
516 u_char *p;
|
509
|
517 ngx_str_t *name, *bucket;
|
|
518 ngx_uint_t i, n, key, size, best, *test, buckets, min_buckets;
|
|
519
|
|
520 if (nelts == 0) {
|
|
521 for (name = (ngx_str_t *) names;
|
|
522 name->len;
|
|
523 name = (ngx_str_t *) ((char *) name + hash->bucket_size))
|
|
524 {
|
|
525 nelts++;
|
|
526 }
|
|
527 }
|
507
|
528
|
|
529 test = ngx_alloc(hash->max_size * sizeof(ngx_uint_t), pool->log);
|
|
530 if (test == NULL) {
|
|
531 return NGX_ERROR;
|
|
532 }
|
|
533
|
|
534 min_buckets = hash->bucket_limit + 1;
|
|
535
|
|
536 #if (NGX_SUPPRESS_WARN)
|
|
537 best = 0;
|
|
538 #endif
|
|
539
|
|
540 for (size = 1; size < hash->max_size; size++) {
|
|
541
|
|
542 buckets = 0;
|
|
543
|
|
544 for (i = 0; i < size; i++) {
|
|
545 test[i] = 0;
|
|
546 }
|
|
547
|
509
|
548 for (n = 0, name = (ngx_str_t *) names;
|
|
549 n < nelts;
|
|
550 n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
|
507
|
551 {
|
583
|
552 if (name->data == NULL) {
|
|
553 continue;
|
|
554 }
|
|
555
|
507
|
556 key = 0;
|
|
557
|
509
|
558 for (i = 0; i < name->len; i++) {
|
|
559 key += ngx_tolower(name->data[i]);
|
507
|
560 }
|
|
561
|
|
562 key %= size;
|
|
563
|
|
564 if (test[key] == hash->bucket_limit) {
|
|
565 break;
|
|
566 }
|
|
567
|
|
568 test[key]++;
|
|
569
|
|
570 if (buckets < test[key]) {
|
|
571 buckets = test[key];
|
|
572 }
|
|
573 }
|
|
574
|
509
|
575 if (n == nelts) {
|
507
|
576 if (min_buckets > buckets) {
|
|
577 min_buckets = buckets;
|
|
578 best = size;
|
|
579 }
|
|
580
|
|
581 if (hash->bucket_limit == 1) {
|
|
582 break;
|
|
583 }
|
|
584 }
|
|
585 }
|
|
586
|
|
587 if (min_buckets == hash->bucket_limit + 1) {
|
|
588 ngx_log_error(NGX_LOG_EMERG, pool->log, 0,
|
|
589 "could not build the %s hash, you should increase "
|
|
590 "either %s_size: %i or %s_bucket_limit: %i",
|
|
591 hash->name, hash->name, hash->max_size,
|
|
592 hash->name, hash->bucket_limit);
|
|
593 ngx_free(test);
|
|
594 return NGX_ERROR;
|
|
595 }
|
|
596
|
|
597 hash->buckets = ngx_pcalloc(pool, best * hash->bucket_size);
|
|
598 if (hash->buckets == NULL) {
|
|
599 ngx_free(test);
|
|
600 return NGX_ERROR;
|
|
601 }
|
|
602
|
|
603 if (hash->bucket_limit != 1) {
|
|
604
|
|
605 for (i = 0; i < best; i++) {
|
|
606 test[i] = 0;
|
|
607 }
|
|
608
|
509
|
609 for (n = 0, name = (ngx_str_t *) names;
|
|
610 n < nelts;
|
|
611 n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
|
507
|
612 {
|
583
|
613 if (name->data == NULL) {
|
|
614 continue;
|
|
615 }
|
|
616
|
507
|
617 key = 0;
|
|
618
|
509
|
619 for (i = 0; i < name->len; i++) {
|
|
620 key += ngx_tolower(name->data[i]);
|
507
|
621 }
|
|
622
|
|
623 key %= best;
|
|
624
|
|
625 test[key]++;
|
|
626 }
|
|
627
|
|
628 for (i = 0; i < best; i++) {
|
|
629 if (test[i] == 0) {
|
|
630 continue;
|
|
631 }
|
|
632
|
|
633 bucket = ngx_palloc(pool, test[i] * hash->bucket_size);
|
|
634 if (bucket == NULL) {
|
|
635 ngx_free(test);
|
|
636 return NGX_ERROR;
|
|
637 }
|
|
638
|
|
639 hash->buckets[i] = bucket;
|
|
640 bucket->len = 0;
|
|
641 }
|
|
642 }
|
|
643
|
509
|
644 for (n = 0, name = (ngx_str_t *) names;
|
|
645 n < nelts;
|
|
646 n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size))
|
507
|
647 {
|
583
|
648 if (name->data == NULL) {
|
|
649 continue;
|
|
650 }
|
|
651
|
507
|
652 key = 0;
|
|
653
|
509
|
654 for (i = 0; i < name->len; i++) {
|
|
655 key += ngx_tolower(name->data[i]);
|
507
|
656 }
|
|
657
|
|
658 key %= best;
|
|
659
|
|
660 if (hash->bucket_limit == 1) {
|
|
661 p = (u_char *) hash->buckets + key * hash->bucket_size;
|
509
|
662 ngx_memcpy(p, name, hash->bucket_size);
|
507
|
663 continue;
|
|
664 }
|
|
665
|
|
666 for (bucket = hash->buckets[key];
|
|
667 bucket->len;
|
|
668 bucket = (ngx_str_t *) ((char *) bucket + hash->bucket_size))
|
|
669 {
|
|
670 bucket->len &= 0x7fffffff;
|
|
671 }
|
|
672
|
509
|
673 ngx_memcpy(bucket, name, hash->bucket_size);
|
507
|
674 bucket->len |= 0x80000000;
|
|
675 }
|
|
676
|
|
677 ngx_free(test);
|
|
678
|
|
679 hash->hash_size = best;
|
|
680 hash->min_buckets = min_buckets;
|
|
681
|
|
682 return NGX_OK;
|
|
683 }
|