1 #include <nchan_module.h>
2 #include "nchan_rbtree.h"
3 #include <assert.h>
4
5 //#define DEBUG_LEVEL NGX_LOG_WARN
6 #define DEBUG_LEVEL NGX_LOG_DEBUG
7 #define DBG(fmt, arg...) ngx_log_error(DEBUG_LEVEL, ngx_cycle->log, 0, "RBTREE:" fmt, ##arg)
8 #define ERR(fmt, arg...) ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0, "RBTREE:" fmt, ##arg)
9
rbtree_hash_crc32(void * str)10 static uint32_t rbtree_hash_crc32(void *str) {
11 return ngx_crc32_short(((ngx_str_t *)str)->data, ((ngx_str_t *)str)->len);
12 }
rbtree_compare_str(void * id1,void * id2)13 static ngx_int_t rbtree_compare_str(void *id1, void *id2) {
14 return ngx_memn2cmp(((ngx_str_t *)id1)->data, ((ngx_str_t *)id2)->data, ((ngx_str_t *)id1)->len, ((ngx_str_t *)id2)->len);
15 }
16
17 /*
18 static ngx_int_t rbtree_validate_node(rbtree_seed_t *seed, ngx_rbtree_node_t *node) {
19 if (node == &seed->sentinel) {
20 return 1;
21 }
22
23 ngx_int_t i, max, valid;
24 ngx_rbtree_node_t *cur;
25 valid = 0;
26 max = sizeof(seed->actives)/sizeof(cur);
27
28 for(i=0; i<max; i++){
29 if(seed->actives[i] == node) {
30 valid = 1;
31 break;
32 }
33 }
34 return valid;
35
36 }
37 */
38
39 /*
40 static ngx_int_t rbtree_validate_nodes_reachable(rbtree_seed_t *seed) {
41 ngx_int_t i, max;
42 ngx_rbtree_node_t *cur, *match;
43 max = sizeof(seed->actives)/sizeof(cur);
44
45 for(i=0; i<max; i++){
46 cur = seed->actives[i];
47 if(cur != NULL) {
48 match = rbtree_find_node(seed, seed->id(rbtree_data_from_node(cur)));
49 assert(match == cur);
50 }
51 }
52 return 1;
53 }
54 */
55
rbtree_find_node_generic(rbtree_seed_t * seed,void * id,uint32_t hash,ngx_rbtree_node_t ** last_parent,ngx_int_t * last_compare)56 static ngx_rbtree_node_t * rbtree_find_node_generic(rbtree_seed_t *seed, void *id, uint32_t hash, ngx_rbtree_node_t **last_parent, ngx_int_t *last_compare) {
57 ngx_rbtree_node_t *root = seed->tree.root;
58 ngx_rbtree_node_t *node = root;
59 ngx_rbtree_node_t *sentinel = seed->tree.sentinel;
60 ngx_int_t rc;
61
62 while (node != sentinel) {
63 if (hash < node->key) {
64 node = node->left;
65 continue;
66 }
67 if (hash > node->key) {
68 node = node->right;
69 continue;
70 }
71
72 /* hash == node->key */
73 rc = seed->compare(id, seed->id(rbtree_data_from_node(node)));
74 if (rc == 0) {
75 return node;
76 }
77 node = (rc < 0) ? node->left : node->right;
78 }
79 /* not found */
80
81 return NULL;
82 }
83
rbtree_find_node(rbtree_seed_t * seed,void * id)84 ngx_rbtree_node_t *rbtree_find_node(rbtree_seed_t *seed, void *id) {
85 ngx_rbtree_node_t *found;
86 found = rbtree_find_node_generic(seed, id, seed->hash(id), NULL, NULL);
87 if(found) {
88 DBG("found node %p", found);
89 }
90 else {
91 DBG("node not found");
92 }
93 return found;
94 }
95
rbtree_insert_generic(ngx_rbtree_node_t * temp,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel)96 static void rbtree_insert_generic(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) {
97 ngx_int_t offset = offsetof(rbtree_seed_t, sentinel);
98 rbtree_seed_t *seed = (rbtree_seed_t *)((char *)sentinel - offset);
99 ngx_int_t rc;
100 void *id = seed->id(rbtree_data_from_node(node));
101
102 ngx_rbtree_node_t **p;
103
104 for ( ;; ) {
105
106 if (node->key != temp->key) {
107 p = (node->key < temp->key) ? &temp->left : &temp->right;
108 }
109 else {
110 rc = seed->compare(id, seed->id(rbtree_data_from_node(temp)));
111 p = (rc < 0) ? &temp->left : &temp->right;
112 }
113
114 if (*p == sentinel) {
115 break;
116 }
117
118 temp = *p;
119 }
120
121 *p = node;
122 node->parent = temp;
123 node->left = sentinel;
124 node->right = sentinel;
125 ngx_rbt_red(node);
126 }
127
rbtree_create_node(rbtree_seed_t * seed,size_t data)128 ngx_rbtree_node_t *rbtree_create_node(rbtree_seed_t *seed, size_t data) {
129 ngx_rbtree_node_t *node = ngx_alloc(sizeof(ngx_rbtree_node_t) + data, ngx_cycle->log);
130 if(node) {
131 node->left = NULL;
132 node->right = NULL;
133 node->parent = NULL;
134 seed->allocd_nodes++;
135 }
136 DBG("created node %p", node);
137 return node;
138 }
139
rbtree_destroy_node(rbtree_seed_t * seed,ngx_rbtree_node_t * node)140 ngx_int_t rbtree_destroy_node(rbtree_seed_t *seed, ngx_rbtree_node_t *node) {
141 seed->allocd_nodes--;
142 #if NCHAN_RBTREE_DBG
143 ngx_memset(node, 0x67, sizeof(*node));
144 #endif
145 DBG("Destroyed node %p", node);
146 ngx_free(node);
147
148 return NGX_OK;
149 }
150
rbtree_insert_node(rbtree_seed_t * seed,ngx_rbtree_node_t * node)151 ngx_int_t rbtree_insert_node(rbtree_seed_t *seed, ngx_rbtree_node_t *node) {
152 void *id = seed->id(rbtree_data_from_node(node));
153 node->key = seed->hash(id);
154 ngx_rbtree_insert(&seed->tree, node);
155 seed->active_nodes++;
156
157 #if NCHAN_RBTREE_DBG
158
159 //assert(rbtree_find_node(seed, seed->id(rbtree_data_from_node(node))) == node);
160
161 //super-heavy debugging
162 /*
163 ngx_int_t i, max, inserted = 0;
164 ngx_rbtree_node_t *cur;
165 max = sizeof(seed->actives)/sizeof(cur);
166
167 assert(seed->active_nodes < max);
168
169 for(i=0; i<max; i++){
170 if(seed->actives[i] == NULL) {
171 seed->actives[i]=node;
172 inserted = 1;
173 break;
174 }
175 }
176 assert(inserted);
177 */
178
179 #endif
180 DBG("inserted node %p", node);
181 return NGX_OK;
182 }
183
rbtree_remove_node(rbtree_seed_t * seed,ngx_rbtree_node_t * node)184 ngx_int_t rbtree_remove_node(rbtree_seed_t *seed, ngx_rbtree_node_t *node) {
185
186 ngx_rbtree_delete(&seed->tree, node);
187 DBG("Removed node %p", node);
188 seed->active_nodes--;
189
190 #if NCHAN_RBTREE_DBG
191 //assert(rbtree_find_node(seed, seed->id(rbtree_data_from_node(node))) == NULL);
192 ngx_memset(node, 0x65, sizeof(*node));
193
194
195 //super-heavy debugging
196 /*
197 ngx_int_t i, max, removed = 0;
198 ngx_rbtree_node_t *cur;
199 max = sizeof(seed->actives)/sizeof(cur);
200
201 assert(seed->active_nodes < max);
202
203 for(i=0; i<max; i++){
204 if(seed->actives[i] == node) {
205 seed->actives[i]=NULL;
206 removed = 1;
207 break;
208 }
209 }
210 assert(removed);
211
212 */
213
214 #endif
215 return NGX_OK;
216 }
217
rbtree_walk_real(rbtree_seed_t * seed,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel,rbtree_walk_callback_pt callback,void * data)218 static ngx_inline void rbtree_walk_real(rbtree_seed_t *seed, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel, rbtree_walk_callback_pt callback, void *data) {
219 ngx_rbtree_node_t *left, *right;
220 if(node == sentinel || node == NULL) {
221 return;
222 }
223 left = node->left;
224 right = node->right;
225 rbtree_walk_real(seed, left, sentinel, callback, data);
226 rbtree_walk_real(seed, right, sentinel, callback, data);
227 callback(seed, rbtree_data_from_node(node), data);
228 }
229
rbtree_walk_ordered_incr_real(rbtree_seed_t * seed,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel,rbtree_walk_callback_pt callback,void * data)230 static ngx_inline void rbtree_walk_ordered_incr_real(rbtree_seed_t *seed, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel, rbtree_walk_callback_pt callback, void *data) {
231 ngx_rbtree_node_t *left, *right;
232 if(node == sentinel || node == NULL) {
233 return;
234 }
235 left = node->left;
236 right = node->right;
237 rbtree_walk_real(seed, left, sentinel, callback, data);
238 callback(seed, rbtree_data_from_node(node), data);
239 rbtree_walk_real(seed, right, sentinel, callback, data);
240 }
241
rbtree_walk_ordered_decr_real(rbtree_seed_t * seed,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel,rbtree_walk_callback_pt callback,void * data)242 static ngx_inline void rbtree_walk_ordered_decr_real(rbtree_seed_t *seed, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel, rbtree_walk_callback_pt callback, void *data) {
243 ngx_rbtree_node_t *left, *right;
244 if(node == sentinel || node == NULL) {
245 return;
246 }
247 left = node->left;
248 right = node->right;
249 rbtree_walk_real(seed, right, sentinel, callback, data);
250 callback(seed, rbtree_data_from_node(node), data);
251 rbtree_walk_real(seed, left, sentinel, callback, data);
252 }
253
rbtree_walk(rbtree_seed_t * seed,rbtree_walk_callback_pt callback,void * data)254 ngx_int_t rbtree_walk(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data) {
255 rbtree_walk_real(seed, seed->tree.root, seed->tree.sentinel, callback, data);
256 return NGX_OK;
257 }
258
rbtree_walk_incr(rbtree_seed_t * seed,rbtree_walk_callback_pt callback,void * data)259 ngx_int_t rbtree_walk_incr(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data) {
260 rbtree_walk_ordered_incr_real(seed, seed->tree.root, seed->tree.sentinel, callback, data);
261 return NGX_OK;
262 }
rbtree_walk_decr(rbtree_seed_t * seed,rbtree_walk_callback_pt callback,void * data)263 ngx_int_t rbtree_walk_decr(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data) {
264 rbtree_walk_ordered_decr_real(seed, seed->tree.root, seed->tree.sentinel, callback, data);
265 return NGX_OK;
266 }
267
268 typedef struct {
269 void **els;
270 int (*include)(void *);
271 int n;
272 } rbtree_walk_writesafe_data_t;
273
rbtree_walk_writesafe_callback(rbtree_seed_t * seed,void * node_data,rbtree_walk_writesafe_data_t * d)274 static ngx_int_t rbtree_walk_writesafe_callback(rbtree_seed_t *seed, void *node_data, rbtree_walk_writesafe_data_t *d) {
275 if(d->include(node_data)) {
276 d->els[d->n++]=node_data;
277 }
278 return NGX_OK;
279 }
280
rbtree_walk_writesafe(rbtree_seed_t * seed,int (* include)(void *),rbtree_walk_callback_pt callback,void * data)281 ngx_int_t rbtree_walk_writesafe(rbtree_seed_t *seed, int (*include)(void *), rbtree_walk_callback_pt callback, void *data) {
282 void *els_static[32];
283 int allocd;
284 int i;
285 rbtree_walk_writesafe_data_t d;
286 if(seed->active_nodes > 32) {
287 d.els = ngx_alloc(sizeof(void *) * seed->active_nodes, ngx_cycle->log);
288 allocd = 1;
289 }
290 else {
291 d.els = els_static;
292 allocd = 0;
293 }
294 d.include = include;
295 d.n = 0;
296 rbtree_walk(seed, (rbtree_walk_callback_pt )rbtree_walk_writesafe_callback, &d);
297
298 for(i=0; i<d.n; i++) {
299 callback(seed, d.els[i], data);
300 }
301
302 if(allocd) ngx_free(d.els);
303 return NGX_OK;
304 }
305
rbtree_empty(rbtree_seed_t * seed,rbtree_walk_callback_pt callback,void * data)306 unsigned rbtree_empty(rbtree_seed_t *seed, rbtree_walk_callback_pt callback, void *data) {
307 ngx_rbtree_t *tree = &seed->tree;
308 ngx_rbtree_node_t *cur, *sentinel = tree->sentinel;
309 unsigned int n = 0;
310
311 for(cur = tree->root; cur != NULL && cur != sentinel; cur = tree->root) {
312 if(callback) {
313 callback(seed, rbtree_data_from_node(cur), data);
314 }
315 rbtree_remove_node(seed, cur);
316 rbtree_destroy_node(seed, cur);
317 n++;
318 }
319 return n;
320 }
321
322
rbtree_conditional_walk_real(rbtree_seed_t * seed,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel,rbtree_walk_conditional_callback_pt callback,void * data)323 static ngx_inline void rbtree_conditional_walk_real(rbtree_seed_t *seed, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel, rbtree_walk_conditional_callback_pt callback, void *data) {
324 rbtree_walk_direction_t direction;
325
326 if(node == sentinel || node == NULL) {
327 return;
328 }
329
330 direction = callback(seed, rbtree_data_from_node(node), data);
331 switch(direction) {
332 case RBTREE_WALK_LEFT:
333 rbtree_conditional_walk_real(seed, node->left, sentinel, callback, data);
334 break;
335
336 case RBTREE_WALK_RIGHT:
337 rbtree_conditional_walk_real(seed, node->right, sentinel, callback, data);
338 break;
339
340 case RBTREE_WALK_LEFT_RIGHT:
341 rbtree_conditional_walk_real(seed, node->left, sentinel, callback, data);
342 rbtree_conditional_walk_real(seed, node->right, sentinel, callback, data);
343 break;
344
345 case RBTREE_WALK_STOP:
346 //no more
347 break;
348 }
349 }
350
rbtree_conditional_walk(rbtree_seed_t * seed,rbtree_walk_conditional_callback_pt callback,void * data)351 ngx_int_t rbtree_conditional_walk(rbtree_seed_t *seed, rbtree_walk_conditional_callback_pt callback, void *data) {
352 rbtree_conditional_walk_real(seed, seed->tree.root, seed->tree.sentinel, callback, data);
353 return NGX_OK;
354 }
355
rbtree_init(rbtree_seed_t * seed,char * name,void * (* id)(void *),uint32_t (* hash)(void *),ngx_int_t (* compare)(void *,void *))356 ngx_int_t rbtree_init(rbtree_seed_t *seed, char *name, void *(*id)(void *), uint32_t (*hash)(void *), ngx_int_t (*compare)(void *, void *)) {
357 seed->name=name;
358 assert(id != NULL);
359 if(hash==NULL) {
360 hash = &rbtree_hash_crc32;
361 }
362 if(compare == NULL) {
363 compare = &rbtree_compare_str;
364 }
365 seed->id = id;
366 seed->hash = hash;
367 seed->compare = compare;
368 seed->active_nodes = 0;
369 seed->allocd_nodes = 0;
370 #if NCHAN_RBTREE_DBG
371 /*
372 //super-heavy debugging setup
373 ngx_int_t max = sizeof(seed->actives);
374 ngx_memzero(seed->actives, sizeof(seed->actives));
375 */
376 #endif
377 ngx_rbtree_init(&seed->tree, &seed->sentinel, &rbtree_insert_generic);
378 return NGX_OK;
379 }
380