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 LASSERT(node->in_parent != NULL);
53 return node == node->in_parent->in_left;
56 static inline int node_is_right_child(struct interval_node *node)
58 LASSERT(node->in_parent != NULL);
59 return node == node->in_parent->in_right;
62 static inline int node_is_red(struct interval_node *node)
64 return node->in_color == INTERVAL_RED;
67 static inline int node_is_black(struct interval_node *node)
69 return node->in_color == INTERVAL_BLACK;
72 static inline int extent_compare(struct interval_node_extent *e1,
73 struct interval_node_extent *e2)
77 if (e1->start == e2->start) {
78 if (e1->end < e2->end)
80 else if (e1->end > e2->end)
85 if (e1->start < e2->start)
93 static inline int extent_equal(struct interval_node_extent *e1,
94 struct interval_node_extent *e2)
96 return (e1->start == e2->start) && (e1->end == e2->end);
99 static inline int node_compare(struct interval_node *n1,
100 struct interval_node *n2)
102 return extent_compare(&n1->in_extent, &n2->in_extent);
105 static inline int node_equal(struct interval_node *n1,
106 struct interval_node *n2)
108 return extent_equal(&n1->in_extent, &n2->in_extent);
111 static inline __u64 max_u64(__u64 x, __u64 y)
113 return x > y ? x : y;
116 static struct interval_node *interval_first(struct interval_node *node)
120 while (node->in_left)
121 node = node->in_left;
125 static struct interval_node *interval_next(struct interval_node *node)
130 return interval_first(node->in_right);
131 while (node->in_parent && node_is_right_child(node))
132 node = node->in_parent;
133 return node->in_parent;
136 static void __rotate_change_maxhigh(struct interval_node *node,
137 struct interval_node *rotate)
139 __u64 left_max, right_max;
141 rotate->in_max_high = node->in_max_high;
142 left_max = node->in_left ? node->in_left->in_max_high : 0;
143 right_max = node->in_right ? node->in_right->in_max_high : 0;
144 node->in_max_high = max_u64(interval_high(node),
145 max_u64(left_max, right_max));
148 /* The left rotation "pivots" around the link from node to node->right, and
149 * - node will be linked to node->right's left child, and
150 * - node->right's left child will be linked to node's right child. */
151 static void __rotate_left(struct interval_node *node,
152 struct interval_node **root)
154 struct interval_node *right = node->in_right;
155 struct interval_node *parent = node->in_parent;
157 node->in_right = right->in_left;
159 right->in_left->in_parent = node;
161 right->in_left = node;
162 right->in_parent = parent;
164 if (node_is_left_child(node))
165 parent->in_left = right;
167 parent->in_right = right;
171 node->in_parent = right;
173 /* update max_high for node and right */
174 __rotate_change_maxhigh(node, right);
177 /* The right rotation "pivots" around the link from node to node->left, and
178 * - node will be linked to node->left's right child, and
179 * - node->left's right child will be linked to node's left child. */
180 static void __rotate_right(struct interval_node *node,
181 struct interval_node **root)
183 struct interval_node *left = node->in_left;
184 struct interval_node *parent = node->in_parent;
186 node->in_left = left->in_right;
188 left->in_right->in_parent = node;
189 left->in_right = node;
191 left->in_parent = parent;
193 if (node_is_right_child(node))
194 parent->in_right = left;
196 parent->in_left = left;
200 node->in_parent = left;
202 /* update max_high for node and left */
203 __rotate_change_maxhigh(node, left);
206 #define interval_swap(a, b) do { \
207 struct interval_node *c = a; a = b; b = c; \
211 * Operations INSERT and DELETE, when run on a tree with n keys,
212 * take O(logN) time.Because they modify the tree, the result
213 * may violate the red-black properties.To restore these properties,
214 * we must change the colors of some of the nodes in the tree
215 * and also change the pointer structure.
217 static void interval_insert_color(struct interval_node *node,
218 struct interval_node **root)
220 struct interval_node *parent, *gparent;
222 while ((parent = node->in_parent) && node_is_red(parent)) {
223 gparent = parent->in_parent;
224 /* Parent is RED, so gparent must not be NULL */
225 if (node_is_left_child(parent)) {
226 struct interval_node *uncle;
228 uncle = gparent->in_right;
229 if (uncle && node_is_red(uncle)) {
230 uncle->in_color = INTERVAL_BLACK;
231 parent->in_color = INTERVAL_BLACK;
232 gparent->in_color = INTERVAL_RED;
237 if (parent->in_right == node) {
238 __rotate_left(parent, root);
239 interval_swap(node, parent);
242 parent->in_color = INTERVAL_BLACK;
243 gparent->in_color = INTERVAL_RED;
244 __rotate_right(gparent, root);
246 struct interval_node *uncle;
248 uncle = gparent->in_left;
249 if (uncle && node_is_red(uncle)) {
250 uncle->in_color = INTERVAL_BLACK;
251 parent->in_color = INTERVAL_BLACK;
252 gparent->in_color = INTERVAL_RED;
257 if (node_is_left_child(node)) {
258 __rotate_right(parent, root);
259 interval_swap(node, parent);
262 parent->in_color = INTERVAL_BLACK;
263 gparent->in_color = INTERVAL_RED;
264 __rotate_left(gparent, root);
268 (*root)->in_color = INTERVAL_BLACK;
271 struct interval_node *interval_insert(struct interval_node *node,
272 struct interval_node **root)
275 struct interval_node **p, *parent = NULL;
277 LASSERT(!interval_is_intree(node));
281 if (node_equal(parent, node))
284 /* max_high field must be updated after each iteration */
285 if (parent->in_max_high < interval_high(node))
286 parent->in_max_high = interval_high(node);
288 if (node_compare(node, parent) < 0)
289 p = &parent->in_left;
291 p = &parent->in_right;
294 /* link node into the tree */
295 node->in_parent = parent;
296 node->in_color = INTERVAL_RED;
297 node->in_left = NULL;
298 node->in_right = NULL;
301 interval_insert_color(node, root);
306 EXPORT_SYMBOL(interval_insert);
308 static inline int node_is_black_or_0(struct interval_node *node)
310 return !node || node_is_black(node);
313 static void interval_erase_color(struct interval_node *node,
314 struct interval_node *parent,
315 struct interval_node **root)
317 struct interval_node *tmp;
319 while (node_is_black_or_0(node) && node != *root) {
320 if (parent->in_left == node) {
321 tmp = parent->in_right;
322 if (node_is_red(tmp)) {
323 tmp->in_color = INTERVAL_BLACK;
324 parent->in_color = INTERVAL_RED;
325 __rotate_left(parent, root);
326 tmp = parent->in_right;
328 if (node_is_black_or_0(tmp->in_left) &&
329 node_is_black_or_0(tmp->in_right)) {
330 tmp->in_color = INTERVAL_RED;
332 parent = node->in_parent;
334 if (node_is_black_or_0(tmp->in_right)) {
335 struct interval_node *o_left;
337 o_left = tmp->in_left;
339 o_left->in_color = INTERVAL_BLACK;
340 tmp->in_color = INTERVAL_RED;
341 __rotate_right(tmp, root);
342 tmp = parent->in_right;
344 tmp->in_color = parent->in_color;
345 parent->in_color = INTERVAL_BLACK;
347 tmp->in_right->in_color = INTERVAL_BLACK;
348 __rotate_left(parent, root);
353 tmp = parent->in_left;
354 if (node_is_red(tmp)) {
355 tmp->in_color = INTERVAL_BLACK;
356 parent->in_color = INTERVAL_RED;
357 __rotate_right(parent, root);
358 tmp = parent->in_left;
360 if (node_is_black_or_0(tmp->in_left) &&
361 node_is_black_or_0(tmp->in_right)) {
362 tmp->in_color = INTERVAL_RED;
364 parent = node->in_parent;
366 if (node_is_black_or_0(tmp->in_left)) {
367 struct interval_node *o_right;
369 o_right = tmp->in_right;
371 o_right->in_color = INTERVAL_BLACK;
372 tmp->in_color = INTERVAL_RED;
373 __rotate_left(tmp, root);
374 tmp = parent->in_left;
376 tmp->in_color = parent->in_color;
377 parent->in_color = INTERVAL_BLACK;
379 tmp->in_left->in_color = INTERVAL_BLACK;
380 __rotate_right(parent, root);
387 node->in_color = INTERVAL_BLACK;
391 * if the @max_high value of @node is changed, this function traverse a path
392 * from node up to the root to update max_high for the whole tree.
394 static void update_maxhigh(struct interval_node *node,
397 __u64 left_max, right_max;
400 left_max = node->in_left ? node->in_left->in_max_high : 0;
401 right_max = node->in_right ? node->in_right->in_max_high : 0;
402 node->in_max_high = max_u64(interval_high(node),
403 max_u64(left_max, right_max));
405 if (node->in_max_high >= old_maxhigh)
407 node = node->in_parent;
411 void interval_erase(struct interval_node *node,
412 struct interval_node **root)
414 struct interval_node *child, *parent;
417 LASSERT(interval_is_intree(node));
419 if (!node->in_left) {
420 child = node->in_right;
421 } else if (!node->in_right) {
422 child = node->in_left;
423 } else { /* Both left and right child are not NULL */
424 struct interval_node *old = node;
426 node = interval_next(node);
427 child = node->in_right;
428 parent = node->in_parent;
429 color = node->in_color;
432 child->in_parent = parent;
434 parent->in_right = child;
436 parent->in_left = child;
438 node->in_color = old->in_color;
439 node->in_right = old->in_right;
440 node->in_left = old->in_left;
441 node->in_parent = old->in_parent;
443 if (old->in_parent) {
444 if (node_is_left_child(old))
445 old->in_parent->in_left = node;
447 old->in_parent->in_right = node;
452 old->in_left->in_parent = node;
454 old->in_right->in_parent = node;
455 update_maxhigh(child ? : parent, node->in_max_high);
456 update_maxhigh(node, old->in_max_high);
461 parent = node->in_parent;
462 color = node->in_color;
465 child->in_parent = parent;
467 if (node_is_left_child(node))
468 parent->in_left = child;
470 parent->in_right = child;
475 update_maxhigh(child ? : parent, node->in_max_high);
478 if (color == INTERVAL_BLACK)
479 interval_erase_color(child, parent, root);
481 EXPORT_SYMBOL(interval_erase);