interval_tree.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 753 行 · 第 1/2 页

C
753
字号
        p = root;        while (*p) {                parent = *p;                if (node_equal(parent, node))                        RETURN(parent);                /* max_high field must be updated after each iteration */                if (parent->in_max_high < interval_high(node))                        parent->in_max_high = interval_high(node);                if (node_compare(node, parent) < 0)                        p = &parent->in_left;                else                         p = &parent->in_right;        }        /* link node into the tree */        node->in_parent = parent;        node->in_color = INTERVAL_RED;        node->in_left = node->in_right = NULL;        *p = node;        interval_insert_color(node, root);        RETURN(NULL);}EXPORT_SYMBOL(interval_insert);static inline int node_is_black_or_0(struct interval_node *node){        return !node || node_is_black(node);}static void interval_erase_color(struct interval_node *node,                                 struct interval_node *parent,                                 struct interval_node **root){        struct interval_node *tmp;        ENTRY;        while (node_is_black_or_0(node) && node != *root) {                if (parent->in_left == node) {                        tmp = parent->in_right;                        if (node_is_red(tmp)) {                                tmp->in_color = INTERVAL_BLACK;                                parent->in_color = INTERVAL_RED;                                __rotate_left(parent, root);                                tmp = parent->in_right;                        }                        if (node_is_black_or_0(tmp->in_left) &&                            node_is_black_or_0(tmp->in_right)) {                                tmp->in_color = INTERVAL_RED;                                node = parent;                                parent = node->in_parent;                        } else {                                if (node_is_black_or_0(tmp->in_right)) {                                        struct interval_node *o_left;                                        if ((o_left = tmp->in_left))                                             o_left->in_color = INTERVAL_BLACK;                                        tmp->in_color = INTERVAL_RED;                                        __rotate_right(tmp, root);                                        tmp = parent->in_right;                                }                                tmp->in_color = parent->in_color;                                parent->in_color = INTERVAL_BLACK;                                if (tmp->in_right)                                    tmp->in_right->in_color = INTERVAL_BLACK;                                __rotate_left(parent, root);                                node = *root;                                break;                        }                } else {                        tmp = parent->in_left;                        if (node_is_red(tmp)) {                                tmp->in_color = INTERVAL_BLACK;                                parent->in_color = INTERVAL_RED;                                __rotate_right(parent, root);                                tmp = parent->in_left;                        }                        if (node_is_black_or_0(tmp->in_left) &&                            node_is_black_or_0(tmp->in_right)) {                                tmp->in_color = INTERVAL_RED;                                node = parent;                                parent = node->in_parent;                        } else {                                if (node_is_black_or_0(tmp->in_left)) {                                        struct interval_node *o_right;                                        if ((o_right = tmp->in_right))                                            o_right->in_color = INTERVAL_BLACK;                                        tmp->in_color = INTERVAL_RED;                                        __rotate_left(tmp, root);                                        tmp = parent->in_left;                                }                                tmp->in_color = parent->in_color;                                parent->in_color = INTERVAL_BLACK;                                if (tmp->in_left)                                        tmp->in_left->in_color = INTERVAL_BLACK;                                __rotate_right(parent, root);                                node = *root;                                break;                        }                }        }        if (node)                node->in_color = INTERVAL_BLACK;        EXIT;}/*  * if the @max_high value of @node is changed, this function traverse  a path  * from node  up to the root to update max_high for the whole tree. */static void update_maxhigh(struct interval_node *node,                           __u64  old_maxhigh){        __u64 left_max, right_max;        ENTRY;        while (node) {                left_max = node->in_left ? node->in_left->in_max_high : 0;                right_max = node->in_right ? node->in_right->in_max_high : 0;                node->in_max_high = max_u64(interval_high(node),                                            max_u64(left_max, right_max));                if (node->in_max_high >= old_maxhigh)                        break;                node = node->in_parent;        }        EXIT;}void interval_erase(struct interval_node *node,                    struct interval_node **root){        struct interval_node *child, *parent;        int color;        ENTRY;        if (!node->in_left) {                child = node->in_right;        } else if (!node->in_right) {                child = node->in_left;        } else { /* Both left and right child are not NULL */                struct interval_node *old = node;                node = interval_next(node);                child = node->in_right;                parent = node->in_parent;                color = node->in_color;                if (child)                        child->in_parent = parent;                if (parent == old) {                        parent->in_right = child;                        parent = node;                } else {                        parent->in_left = child;                }                node->in_color = old->in_color;                node->in_right = old->in_right;                node->in_left = old->in_left;                node->in_parent = old->in_parent;                if (old->in_parent) {                        if (node_is_left_child(old))                                old->in_parent->in_left = node;                        else                                old->in_parent->in_right = node;                } else {                        *root = node;                }                old->in_left->in_parent = node;                if (old->in_right)                        old->in_right->in_parent = node;                update_maxhigh(child, node->in_max_high);                update_maxhigh(node, old->in_max_high);                goto color;        }        parent = node->in_parent;        color = node->in_color;        if (child)                child->in_parent = parent;        if (parent) {                if (node_is_left_child(node))                        parent->in_left = child;                else                        parent->in_right = child;        } else {                *root = child;        }        update_maxhigh(child, node->in_max_high);color:        if (color == INTERVAL_BLACK)                interval_erase_color(child, parent, root);        EXIT;}EXPORT_SYMBOL(interval_erase);static inline int interval_may_overlap(struct interval_node *node,                                          struct interval_node_extent *ext){        return (ext->start <= node->in_max_high &&                ext->end >= interval_low(node));}/* * This function finds all intervals that overlap interval ext, * and calls func to handle resulted intervals one by one. * in lustre, this function will find all conflicting locks in * the granted queue and add these locks to the ast work list. * * { *       if (node == NULL) *               return 0; *       if (ext->end < interval_low(node)) { *               interval_search(node->in_left, ext, func, data); *       } else if (interval_may_overlap(node, ext)) { *               if (extent_overlapped(ext, &node->in_extent)) *                       func(node, data); *               interval_search(node->in_left, ext, func, data); *               interval_search(node->in_right, ext, func, data); *       } *       return 0; * } * */enum interval_iter interval_search(struct interval_node *node,                                   struct interval_node_extent *ext,                                   interval_callback_t func,                                   void *data){        struct interval_node *parent;        enum interval_iter rc = INTERVAL_ITER_CONT;        LASSERT(ext != NULL);        LASSERT(func != NULL);        while (node) {                if (ext->end < interval_low(node)) {                        if (node->in_left) {                                node = node->in_left;                                continue;                        }                } else if (interval_may_overlap(node, ext)) {                        if (extent_overlapped(ext, &node->in_extent)) {                                rc = func(node, data);                                if (rc == INTERVAL_ITER_STOP)                                        break;                        }                        if (node->in_left) {                                node = node->in_left;                                continue;                        }                        if (node->in_right) {                                node = node->in_right;                                continue;                        }                }                 parent = node->in_parent;                while (parent) {                        if (node_is_left_child(node) &&                            parent->in_right) {                                /* If we ever got the left, it means that the                                  * parent met ext->end<interval_low(parent), or                                 * may_overlap(parent). If the former is true,                                 * we needn't go back. So stop early and check                                 * may_overlap(parent) after this loop.  */                                node = parent->in_right;                                break;                        }                        node = parent;                        parent = parent->in_parent;                }                if (parent == NULL || !interval_may_overlap(parent, ext))                        break;        }        return rc;}EXPORT_SYMBOL(interval_search);static enum interval_iter interval_overlap_cb(struct interval_node *n,                                              void *args){        *(int *)args = 1;        return INTERVAL_ITER_STOP;}int interval_is_overlapped(struct interval_node *root,                           struct interval_node_extent *ext){        int has = 0;        (void)interval_search(root, ext, interval_overlap_cb, &has);        return has;}EXPORT_SYMBOL(interval_is_overlapped);/* Don't expand to low. Expanding downwards is expensive, and meaningless to * some extents, because programs seldom do IO backward. * * The recursive algorithm of expanding low: * expand_low { *        struct interval_node *tmp; *        static __u64 res = 0; * *        if (root == NULL) *                return res; *        if (root->in_max_high < low) { *                res = max_u64(root->in_max_high + 1, res); *                return res; *        } else if (low < interval_low(root)) { *                interval_expand_low(root->in_left, low); *                return res; *        } * *        if (interval_high(root) < low) *                res = max_u64(interval_high(root) + 1, res); *        interval_expand_low(root->in_left, low); *        interval_expand_low(root->in_right, low); * *        return res; * } * * It's much easy to eliminate the recursion, see interval_search for  * an example. -jay */static inline __u64 interval_expand_low(struct interval_node *root, __u64 low){        /* we only concern the empty tree right now. */        if (root == NULL)                return 0;        return low;}static inline __u64 interval_expand_high(struct interval_node *node, __u64 high){        __u64 result = ~0;        while (node != NULL) {                if (node->in_max_high < high)                        break;                                        if (interval_low(node) > high) {                        result = interval_low(node) - 1;                        node = node->in_left;                } else {                        node = node->in_right;                }        }        return result;}/* expanding the extent based on @ext. */void interval_expand(struct interval_node *root,                     struct interval_node_extent *ext,                     struct interval_node_extent *limiter){        /* The assertion of interval_is_overlapped is expensive because we may         * travel many nodes to find the overlapped node. */        LASSERT(interval_is_overlapped(root, ext) == 0);        if (!limiter || limiter->start < ext->start)                ext->start = interval_expand_low(root, ext->start);        if (!limiter || limiter->end > ext->end)                ext->end = interval_expand_high(root, ext->end);        LASSERT(interval_is_overlapped(root, ext) == 0);}EXPORT_SYMBOL(interval_expand);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?