src/vfer_btree_delay.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2005, 2006, Internet2
00003  * Legal conditions are in file LICENSE
00004  * (MD5 = c434f2e53b8089d8b4d0172c7ce07360).
00005  */
00006 /**
00007  * @file   vfer_btree_delay.c
00008  * @author Ivan Beschastnikh
00009  * @brief  Implements the AVL tree delay history data structure
00010  *
00011  * Implements the AVL tree to maintain delay history
00012  *
00013  * -     04/30/06        ivan            Created
00014  */
00015 
00016 #include "vfer_btree_delay.h"
00017 #include "vfer.h"
00018 
00019 /* static functions prototype */
00020         static void     Tree_Print_Helper       (node_t* node);
00021 inline  static node_t*  Tree_Acquire_Node       (tree_t* tree);
00022 inline  static void     Tree_Release_Node       (tree_t* tree, node_t* node);
00023 inline  static void     Tree_RotateR            (tree_t* tree, node_t* node);
00024 inline  static void     Tree_RotateL            (tree_t* tree, node_t* node);
00025 inline  static void     Tree_Delete             (tree_t* tree, node_t* node);
00026 inline  static void     Tree_Balance            (tree_t* tree, node_t* node);
00027         
00028 /**
00029  * Recursively prints the node, and the left, and right subtrees of the node
00030  *
00031  * @param node pointer to a delay node in the tree structure
00032  */
00033 static void Tree_Print_Helper(node_t* node) {
00034         printf("[%d](", node->val);
00035         if (node->left != NULL) {
00036                 Tree_Print_Helper(node->left);
00037         }
00038         printf(")(");
00039         if (node->right != NULL) {
00040                 Tree_Print_Helper(node->right);
00041         }
00042         printf(")");
00043         return;
00044 }
00045 
00046 /**
00047  * Acquires a preallocated node
00048  *
00049  * @param tree binary delay tree structure pointer 
00050  * @return NULL if no more nodes available
00051  *         otherwise returns a pointer to a preallocated node
00052  */
00053 inline static node_t* Tree_Acquire_Node(tree_t* tree) {
00054         node_t* ret;
00055         /* if (tree->nodes_free == 0) return NULL;
00056            ret = &(tree->nodes[tree->free_nodes[0]]); 
00057            tree->free_nodes[0] = tree->free_nodes[tree->nodes_free - 1];
00058            tree->nodes_free--; */
00059         
00060         ALLOC(ret, node_t*, node_t, 1);
00061         if (ret == NULL) {
00062                 ERROR_PRINT("btree_delay.c", "Tree_Acquire_Node", "ERROR: Failed to alloc a btree node");
00063                 return NULL;
00064         }
00065         ret->parent = ret->right = ret->left = NULL;
00066         ret->height = 1;
00067         return ret;
00068 }
00069 
00070 /**
00071  * Releases a preallocated node
00072  *
00073  * @param tree binary delay tree structure pointer
00074  * @param node pointer to a delay node in the tree structure
00075  */
00076 inline static void Tree_Release_Node(tree_t* tree, node_t* node) {
00077         /* tree->free_nodes[tree->nodes_free] = node->index;
00078            tree->nodes_free++; */
00079         RELEASE(node, 1);
00080 }
00081 
00082 /**
00083  * Performs a right rotation on the tree at node node
00084  *
00085  * @param tree binary delay tree structure pointer
00086  * @param node pointer to a delay node in the tree structure
00087  */
00088 inline static void Tree_RotateR(tree_t* tree, node_t* node) {
00089         node_t* left_child;
00090         
00091         left_child                      = node->left;
00092         left_child->parent              = node->parent;
00093         node->left                      = left_child->right;
00094         if (left_child->right != NULL) {
00095                 left_child->right->parent = node;
00096         }
00097         left_child->right               = node;
00098         node->parent                    = left_child;
00099 
00100         if (left_child->parent == NULL) {
00101                 tree->root = left_child;
00102         } else {
00103                 if (left_child->parent->right == node) {
00104                         left_child->parent->right = left_child;
00105                 } else {
00106                         left_child->parent->left = left_child;
00107                 }
00108         }
00109         NODE_RECOMPUTE_HEIGHT(node);
00110         NODE_RECOMPUTE_HEIGHT(left_child);
00111 
00112 //      printf("rotater: \n");
00113 //      Tree_Print(tree);
00114         return;
00115 } /* Tree_RotateR() */
00116 
00117 /**
00118  * Performs a left rotation on the tree at node node
00119  *
00120  * @param tree binary delay tree structure pointer
00121  * @param node pointer to a delay node in the tree structure
00122  */
00123 inline static void Tree_RotateL(tree_t* tree, node_t* node) {
00124         node_t* right_child;
00125 
00126         right_child                     = node->right;
00127         right_child->parent             = node->parent;
00128         node->right                     = right_child->left;
00129         if (right_child->left != NULL) {
00130                 right_child->left->parent = node;
00131         }
00132         right_child->left               = node;
00133         node->parent                    = right_child;
00134 
00135         if (right_child->parent == NULL) {
00136                 tree->root = right_child;
00137         } else {
00138                 if (right_child->parent->right == node) {
00139                         right_child->parent->right = right_child;
00140                 } else {
00141                         right_child->parent->left = right_child;
00142                 }
00143         }
00144 
00145         NODE_RECOMPUTE_HEIGHT(node);
00146         NODE_RECOMPUTE_HEIGHT(right_child);
00147 
00148 //      printf("rotatel: \n");
00149 //      Tree_Print(tree);
00150         return;
00151 } /* Tree_RotateL() */
00152 
00153 /**
00154  * Rotates the node to be deleted down into a leaf node, then
00155  * prunes it off directly
00156  *
00157  * @param tree binary delay tree structure pointer
00158  * @param node pointer to a delay node in the tree structure
00159  */
00160 inline static void Tree_Delete(tree_t* tree, node_t* node) {
00161         /* loop until node is a leaf by rotating the tree at the node
00162            so as to make the node travel always end up lower */
00163         while (node->left != NULL || node->right != NULL) {
00164                 if (node->left == NULL) {
00165                         Tree_RotateL(tree, node);
00166                 } else {
00167                         Tree_RotateR(tree, node);
00168                 }
00169         }
00170 
00171         /* now we have to sever the link from the parent node to this
00172            node and make sure to handle all the corner cases */
00173         if (node->parent == NULL) {
00174                 tree->root = NULL;
00175         } else {
00176                 if (node->parent->left == node) {
00177                         node->parent->left = NULL;
00178                 } else {
00179                         node->parent->right = NULL;
00180                 }
00181         }
00182         Tree_Release_Node(tree, node);
00183 //      printf("delete: \n");
00184 //      Tree_Print(tree);
00185 } /* Tree_Delete() */
00186 
00187 /**
00188  * Walks up from the node in question and rotate right/left the subtrees
00189  * until we reach root if any of them need balancing
00190  *
00191  * @param tree binary delay tree structure pointer
00192  * @param node pointer to a delay node in the tree structure
00193  */
00194 inline static void Tree_Balance(tree_t* tree, node_t* node) {
00195         node_t* parent;
00196 
00197         while (node != NULL) {
00198                 parent = node->parent;
00199 
00200                 if (node->left != NULL &&
00201                     node->height == node->left->height) {
00202                         node->height++;
00203                 }
00204                 if (node->right != NULL &&
00205                     node->height == node->right->height) {
00206                         node->height++;
00207                 }
00208                 
00209 //              /* printf("balancing node[%d] height[%d] balance[%d]\n", node->val, node->height, NODE_BALANCE(node)); */
00210 //              
00211                 if (NODE_BALANCE(node) < -1) {
00212                         Tree_RotateR(tree, node);
00213                 } else if (NODE_BALANCE(node) > 1) {
00214                         Tree_RotateL(tree, node);
00215                 }
00216                 node = parent;
00217         }
00218 //      printf("balance: \n");
00219 //      Tree_Print(tree);
00220         return;
00221 } /* Tree_Balance() */
00222 
00223 
00224 /**
00225  * Initializes the tree with a specific delay window size
00226  *
00227  * @param tree binary delay tree structure pointer
00228  * @param window window size to initiailize the tree with
00229  */
00230 void Tree_Init(tree_t* tree, struct timeval window) {
00231         /* int i;
00232         node_t* nodes;
00233         nodes = tree->nodes;
00234         for (i = 0; i < MAX_NODES; i++) {
00235                 nodes[i].index = i;
00236                 nodes[i].height = 1;
00237                 nodes[i].parent = nodes[i].right = nodes[i].left = NULL;
00238                 tree->free_nodes[i] = i;
00239                 } */
00240         tree->root = NULL;
00241         /* tree->nodes_free = MAX_NODES; */
00242         tree->window = window;
00243         tree->last_val.val = 0;
00244         tree->last_val.stamp.tv_sec = 0;
00245         tree->last_val.stamp.tv_usec = 0;
00246         
00247 } /* Tree_Init() */
00248 
00249 /**
00250  * Sets a new delay window to use for the tree
00251  *
00252  * @param tree binary delay tree structure pointer
00253  * @param window new delay window
00254  */
00255 void Tree_Set_Window(tree_t* tree, struct timeval window) {
00256         tree->window = window;
00257 } /* Tree_Set_Window() */
00258 
00259 /**
00260  * Inserts a new delay value into the tree. Prunes any values that are
00261  * outside of the delay history while doing so. Updates the last_val
00262  * added to tree to the inserted value and timestamp.
00263  *
00264  * @param tree binary delay tree structure pointer
00265  * @param val delay value to insert
00266  * @param stamp timestamp of when the delay value was taken
00267  */
00268 void Tree_Insert(tree_t* tree, int32_t val, struct timeval stamp) {
00269         node_t* root;
00270         node_t* tmp;
00271 
00272         /* update the last value added to tree to inserted value */
00273         tree->last_val.val = val;
00274         tree->last_val.stamp = stamp;
00275         
00276         root = tree->root;
00277         do {
00278                 if (root == NULL) {
00279                         /* besides entering the func with an empty
00280                          * tree we can also get here by expiring all
00281                          * the nodes in a tree */
00282                         root = Tree_Acquire_Node(tree);
00283                         if (root == NULL) {
00284 //                              /* printf("Tree_Insert Reached max nodes, node acquistion failed\n"); */
00285                                 return;
00286                         }
00287                         root->val       = val;
00288                         root->stamp     = stamp;
00289                         tree->root      = root;
00290 //                      printf("insert1: \n");
00291 //                      Tree_Print(tree);
00292                         return;
00293                 }
00294                 
00295                 if (val == root->val) {
00296                         root->stamp = stamp;
00297 //                      printf("insert2: \n");
00298 //                      Tree_Print(tree);
00299                         return;
00300                 }
00301 
00302                 /* on our walk prune those nodes that are too old
00303                  * (outside the current history window) */
00304                 if (VALUE_EXPIRED(root->stamp, stamp, tree->window)) {
00305                         /* printf("expired node[%u %u] stamp[%u %u] win[%u %u]",
00306                            root->stamp.tv_sec, root->stamp.tv_usec,
00307                            stamp.tv_sec, stamp.tv_usec,
00308                            tree->window.tv_sec, tree->window.tv_usec); */
00309                         tmp = root->parent;
00310                         Tree_Delete(tree, root);
00311                         if (tmp == NULL) {
00312                                 root = tree->root;
00313                         } else {
00314                                 root = tmp;
00315                         }
00316                         continue;
00317                 }
00318                 if (val < root->val) {
00319                         if (root->left == NULL) {
00320                                 goto add_left;
00321                         }
00322                         root = root->left;
00323                 } else { /* if (val > root->val) */
00324                         if (root->right == NULL) {
00325                                 goto add_right;
00326                         }
00327                         root = root->right;
00328                 }
00329         } while (1);
00330  add_left:
00331         /* printf("adding left of node[%d]\n", root->val); */
00332         root->left              = Tree_Acquire_Node(tree);
00333         if (root->left == NULL) {
00334 //              printf("insert3: \n");
00335 //              Tree_Print(tree);
00336                 return;
00337         }
00338         root->left->val         = val;
00339         root->left->stamp       = stamp;
00340         root->left->parent      = root;
00341         /* only balance the tree if we added to the height of the tree */
00342         if (root->right == NULL) {
00343                 root->height = 2;
00344         }
00345         Tree_Balance(tree, root->parent);
00346 //      printf("insert4: \n");
00347 //      Tree_Print(tree);
00348         return;
00349  add_right:
00350 ////    printf("adding right of node[%d]\n", root->val);
00351         root->right             = Tree_Acquire_Node(tree);
00352         if (root->right == NULL) {
00353 //              printf("insert5: \n");
00354 //              Tree_Print(tree);
00355                 return;
00356         }
00357         root->right->val        = val;
00358         root->right->stamp      = stamp;
00359         root->right->parent     = root;
00360         /* only balance the tree if we added to the height of the tree */
00361         if (root->left == NULL) {
00362                 root->height = 2;
00363         }
00364         Tree_Balance(tree, root->parent);
00365 //      printf("insert6: \n");
00366 //      Tree_Print(tree);
00367         return;
00368 } /* Tree_Add() */
00369 
00370 /**
00371  * Retrieves the minimum delay from the tree. Returns the last value
00372  * added to the tree if the tree is empty (all values were expired).
00373  *
00374  * @param tree binary delay tree structure pointer
00375  * @param stamp current timestamp with which to possibly prune values in the tree
00376  */
00377 int32_t Tree_Min(tree_t* tree, struct timeval stamp) {
00378         node_t* root;
00379         node_t* tmp;
00380 
00381         if (tree->root == NULL) {
00382                 return tree->last_val.val;
00383         }
00384 
00385         root = tree->root;
00386         do {
00387                 /* on our walk to find the min, prune those nodes that
00388                  * are too old (outside the current history window) */
00389                 while (VALUE_EXPIRED(root->stamp, stamp, tree->window)) {
00390                         tmp = root->parent;
00391                         Tree_Delete(tree, root);
00392                         if (tmp == NULL) {
00393                                 if (tree->root == NULL) {
00394                                         /* expired all nodes in the tree */
00395                                         return tree->last_val.val;
00396                                 }
00397                                 root = tree->root;
00398                         } else {
00399                                 root = tmp;
00400                         }
00401                 }
00402         } while ((root->left != NULL) && (root = root->left));
00403         return root->val;
00404 } /* Tree_Min() */
00405 
00406 /**
00407  * Retrieves the maximum delay from the tree. Returns the last value
00408  * added to the tree if the tree is empty (all values were expired).
00409  *
00410  * @param tree binary delay tree structure pointer
00411  * @param stamp current timestamp with which to possibly prune values in the tree
00412  */
00413 int32_t Tree_Max(tree_t* tree, struct timeval stamp) {
00414         node_t* root;
00415         node_t* tmp;
00416 
00417         if (tree->root == NULL) {
00418                 return tree->last_val.val;
00419         }
00420 
00421         root = tree->root;
00422         do {
00423                 /* on our walk to find the max, prune those nodes that
00424                  * are too old (outside the current history window) */
00425                 while (VALUE_EXPIRED(root->stamp, stamp, tree->window)) {
00426                         tmp = root->parent;
00427                         Tree_Delete(tree, root);
00428                         if (tmp == NULL) {
00429                                 if (tree->root == NULL) {
00430                                         /* expired all nodes in the tree */
00431                                         return tree->last_val.val;
00432                                 }
00433                                 root = tree->root;
00434                         } else {
00435                                 root = tmp;
00436                         }
00437                 }
00438         } while ((root->right != NULL) && (root = root->right));
00439         return root->val;
00440 } /* Tree_Max() */
00441 
00442 /**
00443  * Prints the tree by using the print helper function for recursion
00444  *
00445  * @param tree binary delay tree structure pointer
00446  */
00447 void Tree_Print(tree_t* tree) {
00448         if (tree->root != NULL) {
00449                 Tree_Print_Helper(tree->root);
00450                 printf("\n");
00451         } else {
00452                 printf("Empty Tree\n");
00453         }
00454 } /* Tree_Print() */

Generated on Tue Aug 8 16:07:18 2006 for VFER by  doxygen 1.4.7