blob: 957ec309954affe59d5d0fe01d85b74ac7951e24 [file] [log] [blame]
Igor Sysoev822834e2004-05-25 15:28:46 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev822834e2004-05-25 15:28:46 +00007#include <ngx_config.h>
8#include <ngx_core.h>
9
10
Igor Sysoev805d9db2005-02-03 19:33:37 +000011static void *ngx_radix_alloc(ngx_radix_tree_t *tree);
Igor Sysoev822834e2004-05-25 15:28:46 +000012
13
Igor Sysoevaa828612005-02-09 14:31:07 +000014ngx_radix_tree_t *
Igor Sysoev1ebfead2005-02-16 13:40:36 +000015ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate)
Igor Sysoev822834e2004-05-25 15:28:46 +000016{
Igor Sysoevaa828612005-02-09 14:31:07 +000017 uint32_t key, mask, inc;
Igor Sysoev822834e2004-05-25 15:28:46 +000018 ngx_radix_tree_t *tree;
19
Igor Sysoevc1571722005-03-19 12:38:37 +000020 tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t));
21 if (tree == NULL) {
Igor Sysoev822834e2004-05-25 15:28:46 +000022 return NULL;
23 }
24
Igor Sysoev822834e2004-05-25 15:28:46 +000025 tree->pool = pool;
26 tree->free = NULL;
Igor Sysoeva20b6e62004-05-26 15:30:12 +000027 tree->start = NULL;
Igor Sysoev822834e2004-05-25 15:28:46 +000028 tree->size = 0;
29
Igor Sysoevc1571722005-03-19 12:38:37 +000030 tree->root = ngx_radix_alloc(tree);
31 if (tree->root == NULL) {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +000032 return NULL;
33 }
34
Igor Sysoev87a7d1c2004-05-26 19:33:53 +000035 tree->root->right = NULL;
36 tree->root->left = NULL;
37 tree->root->parent = NULL;
Igor Sysoev805d9db2005-02-03 19:33:37 +000038 tree->root->value = NGX_RADIX_NO_VALUE;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +000039
Igor Sysoev1ebfead2005-02-16 13:40:36 +000040 if (preallocate == 0) {
41 return tree;
42 }
43
Igor Sysoevaa828612005-02-09 14:31:07 +000044 /*
Igor Sysoevd039a2e2005-02-22 14:40:13 +000045 * The preallocation the first nodes: 0, 1, 00, 01, 10, 11, 000, 001, etc.
46 * increases the TLB hits even if for the first lookup iterations.
Igor Sysoevaa828612005-02-09 14:31:07 +000047 * On the 32-bit platforms the 7 preallocated bits takes continuous 4K,
Igor Sysoev1ebfead2005-02-16 13:40:36 +000048 * 8 - 8K, 9 - 16K, etc. On the 64-bit platforms the 6 preallocated bits
49 * takes continuous 4K, 7 - 8K, 8 - 16K, etc. There is no sense to
50 * to preallocate more than one page, because further preallocation
Igor Sysoev8184d1b2005-03-04 14:06:57 +000051 * distributes the only bit per page. Instead, the random insertion
Igor Sysoev1ebfead2005-02-16 13:40:36 +000052 * may distribute several bits per page.
53 *
54 * Thus, by default we preallocate maximum
55 * 6 bits on amd64 (64-bit platform and 4K pages)
56 * 7 bits on i386 (32-bit platform and 4K pages)
57 * 7 bits on sparc64 in 64-bit mode (8K pages)
58 * 8 bits on sparc64 in 32-bit mode (8K pages)
Igor Sysoevaa828612005-02-09 14:31:07 +000059 */
60
Igor Sysoev1ebfead2005-02-16 13:40:36 +000061 if (preallocate == -1) {
62 switch (ngx_pagesize / sizeof(ngx_radix_tree_t)) {
63
64 /* amd64 */
65 case 128:
66 preallocate = 6;
67 break;
68
69 /* i386, sparc64 */
70 case 256:
71 preallocate = 7;
72 break;
73
74 /* sparc64 in 32-bit mode */
75 default:
76 preallocate = 8;
77 }
78 }
79
Igor Sysoevaa828612005-02-09 14:31:07 +000080 mask = 0;
81 inc = 0x80000000;
82
83 while (preallocate--) {
84
85 key = 0;
86 mask >>= 1;
87 mask |= 0x80000000;
88
89 do {
90 if (ngx_radix32tree_insert(tree, key, mask, NGX_RADIX_NO_VALUE)
91 != NGX_OK)
92 {
93 return NULL;
94 }
95
96 key += inc;
97
98 } while (key);
99
100 inc >>= 1;
101 }
102
Igor Sysoev822834e2004-05-25 15:28:46 +0000103 return tree;
104}
105
106
Igor Sysoevaa828612005-02-09 14:31:07 +0000107ngx_int_t
108ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask,
109 uintptr_t value)
Igor Sysoev822834e2004-05-25 15:28:46 +0000110{
111 uint32_t bit;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000112 ngx_radix_node_t *node, *next;
Igor Sysoev822834e2004-05-25 15:28:46 +0000113
114 bit = 0x80000000;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000115
Igor Sysoev822834e2004-05-25 15:28:46 +0000116 node = tree->root;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000117 next = tree->root;
Igor Sysoev822834e2004-05-25 15:28:46 +0000118
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000119 while (bit & mask) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000120 if (key & bit) {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000121 next = node->right;
Igor Sysoev822834e2004-05-25 15:28:46 +0000122
123 } else {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000124 next = node->left;
Igor Sysoev822834e2004-05-25 15:28:46 +0000125 }
126
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000127 if (next == NULL) {
128 break;
129 }
130
Igor Sysoev805d9db2005-02-03 19:33:37 +0000131 bit >>= 1;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000132 node = next;
Igor Sysoev822834e2004-05-25 15:28:46 +0000133 }
134
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000135 if (next) {
Igor Sysoev805d9db2005-02-03 19:33:37 +0000136 if (node->value != NGX_RADIX_NO_VALUE) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000137 return NGX_BUSY;
138 }
139
140 node->value = value;
141 return NGX_OK;
142 }
143
144 while (bit & mask) {
Igor Sysoevc1571722005-03-19 12:38:37 +0000145 next = ngx_radix_alloc(tree);
146 if (next == NULL) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000147 return NGX_ERROR;
148 }
149
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000150 next->right = NULL;
151 next->left = NULL;
152 next->parent = node;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000153 next->value = NGX_RADIX_NO_VALUE;
Igor Sysoev822834e2004-05-25 15:28:46 +0000154
155 if (key & bit) {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000156 node->right = next;
Igor Sysoev822834e2004-05-25 15:28:46 +0000157
158 } else {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000159 node->left = next;
Igor Sysoev822834e2004-05-25 15:28:46 +0000160 }
161
162 bit >>= 1;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000163 node = next;
Igor Sysoev822834e2004-05-25 15:28:46 +0000164 }
165
Igor Sysoev805d9db2005-02-03 19:33:37 +0000166 node->value = value;
167
Igor Sysoev822834e2004-05-25 15:28:46 +0000168 return NGX_OK;
169}
170
171
Igor Sysoevaa828612005-02-09 14:31:07 +0000172ngx_int_t
173ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask)
Igor Sysoev822834e2004-05-25 15:28:46 +0000174{
175 uint32_t bit;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000176 ngx_radix_node_t *node;
Igor Sysoev822834e2004-05-25 15:28:46 +0000177
178 bit = 0x80000000;
179 node = tree->root;
180
181 while (node && (bit & mask)) {
182 if (key & bit) {
183 node = node->right;
184
185 } else {
186 node = node->left;
187 }
188
189 bit >>= 1;
190 }
191
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000192 if (node == NULL) {
193 return NGX_ERROR;
194 }
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000195
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000196 if (node->right || node->left) {
Igor Sysoev805d9db2005-02-03 19:33:37 +0000197 if (node->value != NGX_RADIX_NO_VALUE) {
198 node->value = NGX_RADIX_NO_VALUE;
199 return NGX_OK;
200 }
201
202 return NGX_ERROR;
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000203 }
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000204
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000205 for ( ;; ) {
206 if (node->parent->right == node) {
207 node->parent->right = NULL;
Igor Sysoevc2068d02005-10-19 12:33:58 +0000208
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000209 } else {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000210 node->parent->left = NULL;
211 }
212
213 node->right = tree->free;
214 tree->free = node;
215
216 node = node->parent;
217
Igor Sysoevc2068d02005-10-19 12:33:58 +0000218 if (node->right || node->left) {
219 break;
220 }
221
222 if (node->value != NGX_RADIX_NO_VALUE) {
223 break;
224 }
225
226 if (node->parent == NULL) {
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000227 break;
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000228 }
Igor Sysoev822834e2004-05-25 15:28:46 +0000229 }
Igor Sysoev87a7d1c2004-05-26 19:33:53 +0000230
231 return NGX_OK;
Igor Sysoev822834e2004-05-25 15:28:46 +0000232}
233
234
Igor Sysoevaa828612005-02-09 14:31:07 +0000235uintptr_t
236ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key)
Igor Sysoev822834e2004-05-25 15:28:46 +0000237{
238 uint32_t bit;
239 uintptr_t value;
240 ngx_radix_node_t *node;
241
242 bit = 0x80000000;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000243 value = NGX_RADIX_NO_VALUE;
Igor Sysoev822834e2004-05-25 15:28:46 +0000244 node = tree->root;
245
246 while (node) {
Igor Sysoev805d9db2005-02-03 19:33:37 +0000247 if (node->value != NGX_RADIX_NO_VALUE) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000248 value = node->value;
249 }
250
251 if (key & bit) {
252 node = node->right;
253
254 } else {
255 node = node->left;
256 }
257
258 bit >>= 1;
259 }
260
261 return value;
262}
263
264
Igor Sysoevaa828612005-02-09 14:31:07 +0000265static void *
266ngx_radix_alloc(ngx_radix_tree_t *tree)
Igor Sysoev822834e2004-05-25 15:28:46 +0000267{
268 char *p;
269
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000270 if (tree->free) {
271 p = (char *) tree->free;
272 tree->free = tree->free->right;
273 return p;
274 }
275
Igor Sysoev805d9db2005-02-03 19:33:37 +0000276 if (tree->size < sizeof(ngx_radix_node_t)) {
Igor Sysoevc1571722005-03-19 12:38:37 +0000277 tree->start = ngx_palloc(tree->pool, ngx_pagesize);
278 if (tree->start == NULL) {
Igor Sysoev822834e2004-05-25 15:28:46 +0000279 return NULL;
280 }
281
Igor Sysoev0ed19cc2004-06-10 18:36:57 +0000282 tree->size = ngx_pagesize;
Igor Sysoev822834e2004-05-25 15:28:46 +0000283 }
284
Igor Sysoeva20b6e62004-05-26 15:30:12 +0000285 p = tree->start;
Igor Sysoev805d9db2005-02-03 19:33:37 +0000286 tree->start += sizeof(ngx_radix_node_t);
287 tree->size -= sizeof(ngx_radix_node_t);
Igor Sysoev822834e2004-05-25 15:28:46 +0000288
289 return p;
290}