ip_tree.c
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <unistd.h>
00034 #include <assert.h>
00035
00036 #include "../../dprint.h"
00037 #include "../../mem/shm_mem.h"
00038 #include "ip_tree.h"
00039
00040
00041
00042 static struct ip_tree* root = 0;
00043
00044
00045 static inline struct ip_node* prv_get_tree_branch(unsigned char b)
00046 {
00047 return root->entries[b].node;
00048 }
00049
00050
00051
00052 static inline void prv_lock_tree_branch(unsigned char b)
00053 {
00054 lock_set_get( root->entry_lock_set, root->entries[b].lock_idx);
00055 }
00056
00057
00058
00059
00060 static inline void prv_unlock_tree_branch(unsigned char b)
00061 {
00062 lock_set_release( root->entry_lock_set, root->entries[b].lock_idx);
00063 }
00064
00065
00066
00067 struct ip_node* get_tree_branch(unsigned char b)
00068 {
00069 return prv_get_tree_branch(b);
00070 }
00071 void lock_tree_branch(unsigned char b)
00072 {
00073 prv_lock_tree_branch(b);
00074 }
00075 void unlock_tree_branch(unsigned char b)
00076 {
00077 prv_unlock_tree_branch(b);
00078 }
00079
00080
00081
00082 static gen_lock_set_t* init_lock_set(int *size)
00083 {
00084 gen_lock_set_t *lset;
00085
00086 lset=0;
00087 for( ; *size ; *size=((*size)>>1) ) {
00088 LM_INFO("probing %d set size\n", *size);
00089
00090 lset = lock_set_alloc( *size );
00091 if (lset==0) {
00092 LM_INFO("cannot get %d locks\n", *size);
00093 continue;
00094 }
00095
00096 if (lock_set_init(lset)==0) {
00097 LM_INFO("cannot init %d locks\n", *size);
00098 lock_set_dealloc( lset );
00099 lset = 0;
00100 continue;
00101 }
00102
00103 break;
00104 }
00105
00106 if (*size==0) {
00107 LM_ERR("cannot get a lock set\n");
00108 return 0;
00109 }
00110 return lset;
00111 }
00112
00113
00114
00115
00116 int init_ip_tree(int maximum_hits)
00117 {
00118 int size;
00119 int i;
00120
00121
00122 root = (struct ip_tree*)shm_malloc(sizeof(struct ip_tree));
00123 if (root==0) {
00124 LM_ERR("shm malloc failed\n");
00125 goto error;
00126 }
00127 memset( root, 0, sizeof(struct ip_tree));
00128
00129
00130 size = MAX_IP_BRANCHES;
00131 root->entry_lock_set = init_lock_set( &size );
00132 if (root->entry_lock_set==0) {
00133 LM_ERR("failed to create locks\n");
00134 goto error;
00135 }
00136
00137 for(i=0;i<MAX_IP_BRANCHES;i++) {
00138 root->entries[i].node = 0;
00139 root->entries[i].lock_idx = i % size;
00140 }
00141
00142 root->max_hits = maximum_hits;
00143
00144 return 0;
00145 error:
00146 if (root)
00147 shm_free(root);
00148 return -1;
00149 }
00150
00151
00152
00153
00154
00155 static inline void destroy_ip_node(struct ip_node *node)
00156 {
00157 struct ip_node *foo, *bar;
00158
00159 foo = node->kids;
00160 while (foo){
00161 bar = foo;
00162 foo = foo->next;
00163 destroy_ip_node(bar);
00164 }
00165
00166 shm_free(node);
00167 }
00168
00169
00170
00171
00172 void destroy_ip_tree(void)
00173 {
00174 int i;
00175
00176 if (root==0)
00177 return;
00178
00179
00180 if (root->entry_lock_set) {
00181 lock_set_destroy(root->entry_lock_set);
00182 lock_set_dealloc(root->entry_lock_set);
00183 }
00184
00185
00186 for(i=0;i<MAX_IP_BRANCHES;i++)
00187 if (root->entries[i].node)
00188 destroy_ip_node(root->entries[i].node);
00189
00190 shm_free( root );
00191 root = 0;
00192
00193 return;
00194 }
00195
00196
00197
00198
00199 static inline struct ip_node *new_ip_node(unsigned char byte)
00200 {
00201 struct ip_node *new_node;
00202
00203 new_node = (struct ip_node*)shm_malloc(sizeof(struct ip_node));
00204 if (!new_node) {
00205 LM_ERR("no more shm mem\n");
00206 return 0;
00207 }
00208 memset( new_node, 0, sizeof(struct ip_node));
00209 new_node->byte = byte;
00210 return new_node;
00211 }
00212
00213
00214
00215
00216 struct ip_node *split_node(struct ip_node* dad, unsigned char byte)
00217 {
00218 struct ip_node *new_node;
00219
00220
00221 if ( (new_node=new_ip_node(byte))==0 )
00222 return 0;
00223
00224 if (dad->hits[CURR_POS]>=1)
00225 new_node->hits[CURR_POS] = (dad->hits[CURR_POS])-1;
00226 if (dad->leaf_hits[CURR_POS]>=1)
00227 new_node->leaf_hits[PREV_POS] = (dad->leaf_hits[PREV_POS])-1;
00228
00229
00230 if (dad->kids) {
00231 dad->kids->prev = new_node;
00232 new_node->next = dad->kids;
00233 }
00234 dad->kids = new_node;
00235 new_node->branch = dad->branch;
00236 new_node->prev = dad;
00237
00238 return new_node;
00239 }
00240
00241
00242 #define is_hot_non_leaf(_node) \
00243 ( (_node)->hits[PREV_POS]>=root->max_hits>>2 ||\
00244 (_node)->hits[CURR_POS]>=root->max_hits>>2 ||\
00245 (((_node)->hits[PREV_POS]+(_node)->hits[CURR_POS])>>1)>=\
00246 root->max_hits>>2 )
00247
00248 #define is_hot_leaf(_node) \
00249 ( (_node)->leaf_hits[PREV_POS]>=root->max_hits ||\
00250 (_node)->leaf_hits[CURR_POS]>=root->max_hits ||\
00251 (((_node)->leaf_hits[PREV_POS]+(_node)->leaf_hits[CURR_POS])>>1)>=\
00252 root->max_hits )
00253
00254 #define is_warm_leaf(_node) \
00255 ( (_node)->hits[CURR_POS]>=root->max_hits>>2 )
00256
00257 #define MAX_TYPE_VAL(_x) \
00258 (( (1<<(8*sizeof(_x)-1))-1 )|( (1<<(8*sizeof(_x)-1)) ))
00259
00260
00261 int is_node_hot_leaf(struct ip_node *node)
00262 {
00263 return is_hot_leaf(node);
00264 }
00265
00266
00267
00268 struct ip_node* mark_node(unsigned char *ip,int ip_len,
00269 struct ip_node **father,unsigned char *flag)
00270 {
00271 struct ip_node *node;
00272 struct ip_node *kid;
00273 int byte_pos;
00274
00275 kid = root->entries[ ip[0] ].node;
00276 node = 0;
00277 byte_pos = 0;
00278
00279 LM_DBG("search on branch %d (top=%p)\n", ip[0],kid);
00280
00281 while (kid && byte_pos<ip_len) {
00282 while (kid && kid->byte!=(unsigned char)ip[byte_pos]) {
00283 kid = kid->next;
00284 }
00285 if (kid) {
00286 node = kid;
00287 kid = kid->kids;
00288 byte_pos++;
00289 }
00290 }
00291
00292 LM_DBG("only first %d were matched!\n",byte_pos);
00293 *flag = 0;
00294 *father = 0;
00295
00296
00297 if (byte_pos==ip_len) {
00298
00299 node->flags |= NODE_IPLEAF_FLAG;
00300
00301 if(node->leaf_hits[CURR_POS]<MAX_TYPE_VAL(node->leaf_hits[CURR_POS])-1)
00302 node->leaf_hits[CURR_POS]++;
00303
00304 if ( (node->flags&NODE_ISRED_FLAG)==0 ) {
00305 if (is_hot_leaf(node) ) {
00306 *flag |= RED_NODE|NEWRED_NODE;
00307 node->flags |= NODE_ISRED_FLAG;
00308 }
00309 } else {
00310 *flag |= RED_NODE;
00311 }
00312 } else if (byte_pos==0) {
00313
00314 assert(node==0);
00315
00316 if ( (node=new_ip_node(ip[0]))==0)
00317 return 0;
00318 node->hits[CURR_POS] = 1;
00319 node->branch = ip[0];
00320 *flag = NEW_NODE ;
00321
00322 root->entries[ ip[0] ].node = node;
00323 } else{
00324
00325 if ( node->hits[CURR_POS]<MAX_TYPE_VAL(node->hits[CURR_POS])-1 )
00326 node->hits[CURR_POS]++;
00327 if ( is_hot_non_leaf(node) ) {
00328
00329 *flag = NEW_NODE ;
00330 LM_DBG("splitting node %p [%d]\n",node,node->byte);
00331 *father = node;
00332 node = split_node(node,ip[byte_pos]);
00333 } else {
00334
00335
00336
00337 if ( !is_warm_leaf(node) )
00338 *flag = NO_UPDATE;
00339 }
00340 }
00341
00342 return node;
00343 }
00344
00345
00346
00347
00348 void remove_node(struct ip_node *node)
00349 {
00350 LM_DBG("destroying node %p\n",node);
00351
00352 if (node->prev==0) {
00353 assert(root->entries[node->byte].node==node);
00354 root->entries[node->byte].node = 0;
00355 } else {
00356
00357 if (node->prev->kids==node)
00358
00359 node->prev->kids = node->next;
00360 else
00361
00362 node->prev->next = node->next;
00363 if (node->next)
00364 node->next->prev = node->prev;
00365 }
00366
00367
00368 node->next = node->prev = 0;
00369 destroy_ip_node(node);
00370 }
00371