4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
27 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
28 * Use is subject to license terms.
31 * This file is part of Lustre, http://www.lustre.org/
32 * Lustre is a trademark of Sun Microsystems, Inc.
34 * lustre/ldlm/interval_tree.c
36 * Interval tree library used by ldlm extent lock code
38 * Author: Huang Wei <huangwei@clusterfs.com>
39 * Author: Jay Xiong <jinshan.xiong@sun.com>
41 #include "../include/lustre_dlm.h"
42 #include "../include/obd_support.h"
43 #include "../include/interval_tree.h"
50 static inline int node_is_left_child(struct interval_node *node)
52 return node == node->in_parent->in_left;
55 static inline int node_is_right_child(struct interval_node *node)
57 return node == node->in_parent->in_right;
60 static inline int node_is_red(struct interval_node *node)
62 return node->in_color == INTERVAL_RED;
65 static inline int node_is_black(struct interval_node *node)
67 return node->in_color == INTERVAL_BLACK;
70 static inline int extent_compare(struct interval_node_extent *e1,
71 struct interval_node_extent *e2)
75 if (e1->start == e2->start) {
76 if (e1->end < e2->end)
78 else if (e1->end > e2->end)
83 if (e1->start < e2->start)
91 static inline int extent_equal(struct interval_node_extent *e1,
92 struct interval_node_extent *e2)
94 return (e1->start == e2->start) && (e1->end == e2->end);
97 static inline __u64 max_u64(__u64 x, __u64 y)
102 static struct interval_node *interval_first(struct interval_node *node)
106 while (node->in_left)
107 node = node->in_left;
111 static struct interval_node *interval_next(struct interval_node *node)
116 return interval_first(node->in_right);
117 while (node->in_parent && node_is_right_child(node))
118 node = node->in_parent;
119 return node->in_parent;
122 static void __rotate_change_maxhigh(struct interval_node *node,
123 struct interval_node *rotate)
125 __u64 left_max, right_max;
127 rotate->in_max_high = node->in_max_high;
128 left_max = node->in_left ? node->in_left->in_max_high : 0;
129 right_max = node->in_right ? node->in_right->in_max_high : 0;
130 node->in_max_high = max_u64(interval_high(node),
131 max_u64(left_max, right_max));
134 /* The left rotation "pivots" around the link from node to node->right, and
135 * - node will be linked to node->right's left child, and
136 * - node->right's left child will be linked to node's right child. */
137 static void __rotate_left(struct interval_node *node,
138 struct interval_node **root)
140 struct interval_node *right = node->in_right;
141 struct interval_node *parent = node->in_parent;
143 node->in_right = right->in_left;
145 right->in_left->in_parent = node;
147 right->in_left = node;
148 right->in_parent = parent;
150 if (node_is_left_child(node))
151 parent->in_left = right;
153 parent->in_right = right;
157 node->in_parent = right;
159 /* update max_high for node and right */
160 __rotate_change_maxhigh(node, right);
163 /* The right rotation "pivots" around the link from node to node->left, and
164 * - node will be linked to node->left's right child, and
165 * - node->left's right child will be linked to node's left child. */
166 static void __rotate_right(struct interval_node *node,
167 struct interval_node **root)
169 struct interval_node *left = node->in_left;
170 struct interval_node *parent = node->in_parent;
172 node->in_left = left->in_right;
174 left->in_right->in_parent = node;
175 left->in_right = node;
177 left->in_parent = parent;
179 if (node_is_right_child(node))
180 parent->in_right = left;
182 parent->in_left = left;
186 node->in_parent = left;
188 /* update max_high for node and left */
189 __rotate_change_maxhigh(node, left);
192 #define interval_swap(a, b) do { \
193 struct interval_node *c = a; a = b; b = c; \
197 * Operations INSERT and DELETE, when run on a tree with n keys,
198 * take O(logN) time.Because they modify the tree, the result
199 * may violate the red-black properties.To restore these properties,
200 * we must change the colors of some of the nodes in the tree
201 * and also change the pointer structure.
203 static void interval_insert_color(struct interval_node *node,
204 struct interval_node **root)
206 struct interval_node *parent, *gparent;
208 while ((parent = node->in_parent) && node_is_red(parent)) {
209 gparent = parent->in_parent;
210 /* Parent is RED, so gparent must not be NULL */
211 if (node_is_left_child(parent)) {
212 struct interval_node *uncle;
214 uncle = gparent->in_right;
215 if (uncle && node_is_red(uncle)) {
216 uncle->in_color = INTERVAL_BLACK;
217 parent->in_color = INTERVAL_BLACK;
218 gparent->in_color = INTERVAL_RED;
223 if (parent->in_right == node) {
224 __rotate_left(parent, root);
225 interval_swap(node, parent);
228 parent->in_color = INTERVAL_BLACK;
229 gparent->in_color = INTERVAL_RED;
230 __rotate_right(gparent, root);
232 struct interval_node *uncle;
234 uncle = gparent->in_left;
235 if (uncle && node_is_red(uncle)) {
236 uncle->in_color = INTERVAL_BLACK;
237 parent->in_color = INTERVAL_BLACK;
238 gparent->in_color = INTERVAL_RED;
243 if (node_is_left_child(node)) {
244 __rotate_right(parent, root);
245 interval_swap(node, parent);
248 parent->in_color = INTERVAL_BLACK;
249 gparent->in_color = INTERVAL_RED;
250 __rotate_left(gparent, root);
254 (*root)->in_color = INTERVAL_BLACK;
257 struct interval_node *interval_insert(struct interval_node *node,
258 struct interval_node **root)
261 struct interval_node **p, *parent = NULL;
263 LASSERT(!interval_is_intree(node));
267 if (extent_equal(&parent->in_extent, &node->in_extent))
270 /* max_high field must be updated after each iteration */
271 if (parent->in_max_high < interval_high(node))
272 parent->in_max_high = interval_high(node);
274 if (extent_compare(&node->in_extent, &parent->in_extent) < 0)
275 p = &parent->in_left;
277 p = &parent->in_right;
280 /* link node into the tree */
281 node->in_parent = parent;
282 node->in_color = INTERVAL_RED;
283 node->in_left = NULL;
284 node->in_right = NULL;
287 interval_insert_color(node, root);
292 EXPORT_SYMBOL(interval_insert);
294 static inline int node_is_black_or_0(struct interval_node *node)
296 return !node || node_is_black(node);
299 static void interval_erase_color(struct interval_node *node,
300 struct interval_node *parent,
301 struct interval_node **root)
303 struct interval_node *tmp;
305 while (node_is_black_or_0(node) && node != *root) {
306 if (parent->in_left == node) {
307 tmp = parent->in_right;
308 if (node_is_red(tmp)) {
309 tmp->in_color = INTERVAL_BLACK;
310 parent->in_color = INTERVAL_RED;
311 __rotate_left(parent, root);
312 tmp = parent->in_right;
314 if (node_is_black_or_0(tmp->in_left) &&
315 node_is_black_or_0(tmp->in_right)) {
316 tmp->in_color = INTERVAL_RED;
318 parent = node->in_parent;
320 if (node_is_black_or_0(tmp->in_right)) {
321 struct interval_node *o_left;
323 o_left = tmp->in_left;
325 o_left->in_color = INTERVAL_BLACK;
326 tmp->in_color = INTERVAL_RED;
327 __rotate_right(tmp, root);
328 tmp = parent->in_right;
330 tmp->in_color = parent->in_color;
331 parent->in_color = INTERVAL_BLACK;
333 tmp->in_right->in_color = INTERVAL_BLACK;
334 __rotate_left(parent, root);
339 tmp = parent->in_left;
340 if (node_is_red(tmp)) {
341 tmp->in_color = INTERVAL_BLACK;
342 parent->in_color = INTERVAL_RED;
343 __rotate_right(parent, root);
344 tmp = parent->in_left;
346 if (node_is_black_or_0(tmp->in_left) &&
347 node_is_black_or_0(tmp->in_right)) {
348 tmp->in_color = INTERVAL_RED;
350 parent = node->in_parent;
352 if (node_is_black_or_0(tmp->in_left)) {
353 struct interval_node *o_right;
355 o_right = tmp->in_right;
357 o_right->in_color = INTERVAL_BLACK;
358 tmp->in_color = INTERVAL_RED;
359 __rotate_left(tmp, root);
360 tmp = parent->in_left;
362 tmp->in_color = parent->in_color;
363 parent->in_color = INTERVAL_BLACK;
365 tmp->in_left->in_color = INTERVAL_BLACK;
366 __rotate_right(parent, root);
373 node->in_color = INTERVAL_BLACK;
377 * if the @max_high value of @node is changed, this function traverse a path
378 * from node up to the root to update max_high for the whole tree.
380 static void update_maxhigh(struct interval_node *node,
383 __u64 left_max, right_max;
386 left_max = node->in_left ? node->in_left->in_max_high : 0;
387 right_max = node->in_right ? node->in_right->in_max_high : 0;
388 node->in_max_high = max_u64(interval_high(node),
389 max_u64(left_max, right_max));
391 if (node->in_max_high >= old_maxhigh)
393 node = node->in_parent;
397 void interval_erase(struct interval_node *node,
398 struct interval_node **root)
400 struct interval_node *child, *parent;
403 LASSERT(interval_is_intree(node));
405 if (!node->in_left) {
406 child = node->in_right;
407 } else if (!node->in_right) {
408 child = node->in_left;
409 } else { /* Both left and right child are not NULL */
410 struct interval_node *old = node;
412 node = interval_next(node);
413 child = node->in_right;
414 parent = node->in_parent;
415 color = node->in_color;
418 child->in_parent = parent;
420 parent->in_right = child;
422 parent->in_left = child;
424 node->in_color = old->in_color;
425 node->in_right = old->in_right;
426 node->in_left = old->in_left;
427 node->in_parent = old->in_parent;
429 if (old->in_parent) {
430 if (node_is_left_child(old))
431 old->in_parent->in_left = node;
433 old->in_parent->in_right = node;
438 old->in_left->in_parent = node;
440 old->in_right->in_parent = node;
441 update_maxhigh(child ? : parent, node->in_max_high);
442 update_maxhigh(node, old->in_max_high);
447 parent = node->in_parent;
448 color = node->in_color;
451 child->in_parent = parent;
453 if (node_is_left_child(node))
454 parent->in_left = child;
456 parent->in_right = child;
461 update_maxhigh(child ? : parent, node->in_max_high);
464 if (color == INTERVAL_BLACK)
465 interval_erase_color(child, parent, root);
467 EXPORT_SYMBOL(interval_erase);