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.
138 static void __rotate_left(struct interval_node *node,
139 struct interval_node **root)
141 struct interval_node *right = node->in_right;
142 struct interval_node *parent = node->in_parent;
144 node->in_right = right->in_left;
146 right->in_left->in_parent = node;
148 right->in_left = node;
149 right->in_parent = parent;
151 if (node_is_left_child(node))
152 parent->in_left = right;
154 parent->in_right = right;
158 node->in_parent = right;
160 /* update max_high for node and right */
161 __rotate_change_maxhigh(node, right);
164 /* The right rotation "pivots" around the link from node to node->left, and
165 * - node will be linked to node->left's right child, and
166 * - node->left's right child will be linked to node's left child.
168 static void __rotate_right(struct interval_node *node,
169 struct interval_node **root)
171 struct interval_node *left = node->in_left;
172 struct interval_node *parent = node->in_parent;
174 node->in_left = left->in_right;
176 left->in_right->in_parent = node;
177 left->in_right = node;
179 left->in_parent = parent;
181 if (node_is_right_child(node))
182 parent->in_right = left;
184 parent->in_left = left;
188 node->in_parent = left;
190 /* update max_high for node and left */
191 __rotate_change_maxhigh(node, left);
194 #define interval_swap(a, b) do { \
195 struct interval_node *c = a; a = b; b = c; \
199 * Operations INSERT and DELETE, when run on a tree with n keys,
200 * take O(logN) time.Because they modify the tree, the result
201 * may violate the red-black properties.To restore these properties,
202 * we must change the colors of some of the nodes in the tree
203 * and also change the pointer structure.
205 static void interval_insert_color(struct interval_node *node,
206 struct interval_node **root)
208 struct interval_node *parent, *gparent;
210 while ((parent = node->in_parent) && node_is_red(parent)) {
211 gparent = parent->in_parent;
212 /* Parent is RED, so gparent must not be NULL */
213 if (node_is_left_child(parent)) {
214 struct interval_node *uncle;
216 uncle = gparent->in_right;
217 if (uncle && node_is_red(uncle)) {
218 uncle->in_color = INTERVAL_BLACK;
219 parent->in_color = INTERVAL_BLACK;
220 gparent->in_color = INTERVAL_RED;
225 if (parent->in_right == node) {
226 __rotate_left(parent, root);
227 interval_swap(node, parent);
230 parent->in_color = INTERVAL_BLACK;
231 gparent->in_color = INTERVAL_RED;
232 __rotate_right(gparent, root);
234 struct interval_node *uncle;
236 uncle = gparent->in_left;
237 if (uncle && node_is_red(uncle)) {
238 uncle->in_color = INTERVAL_BLACK;
239 parent->in_color = INTERVAL_BLACK;
240 gparent->in_color = INTERVAL_RED;
245 if (node_is_left_child(node)) {
246 __rotate_right(parent, root);
247 interval_swap(node, parent);
250 parent->in_color = INTERVAL_BLACK;
251 gparent->in_color = INTERVAL_RED;
252 __rotate_left(gparent, root);
256 (*root)->in_color = INTERVAL_BLACK;
259 struct interval_node *interval_insert(struct interval_node *node,
260 struct interval_node **root)
263 struct interval_node **p, *parent = NULL;
265 LASSERT(!interval_is_intree(node));
269 if (extent_equal(&parent->in_extent, &node->in_extent))
272 /* max_high field must be updated after each iteration */
273 if (parent->in_max_high < interval_high(node))
274 parent->in_max_high = interval_high(node);
276 if (extent_compare(&node->in_extent, &parent->in_extent) < 0)
277 p = &parent->in_left;
279 p = &parent->in_right;
282 /* link node into the tree */
283 node->in_parent = parent;
284 node->in_color = INTERVAL_RED;
285 node->in_left = NULL;
286 node->in_right = NULL;
289 interval_insert_color(node, root);
294 EXPORT_SYMBOL(interval_insert);
296 static inline int node_is_black_or_0(struct interval_node *node)
298 return !node || node_is_black(node);
301 static void interval_erase_color(struct interval_node *node,
302 struct interval_node *parent,
303 struct interval_node **root)
305 struct interval_node *tmp;
307 while (node_is_black_or_0(node) && node != *root) {
308 if (parent->in_left == node) {
309 tmp = parent->in_right;
310 if (node_is_red(tmp)) {
311 tmp->in_color = INTERVAL_BLACK;
312 parent->in_color = INTERVAL_RED;
313 __rotate_left(parent, root);
314 tmp = parent->in_right;
316 if (node_is_black_or_0(tmp->in_left) &&
317 node_is_black_or_0(tmp->in_right)) {
318 tmp->in_color = INTERVAL_RED;
320 parent = node->in_parent;
322 if (node_is_black_or_0(tmp->in_right)) {
323 struct interval_node *o_left;
325 o_left = tmp->in_left;
327 o_left->in_color = INTERVAL_BLACK;
328 tmp->in_color = INTERVAL_RED;
329 __rotate_right(tmp, root);
330 tmp = parent->in_right;
332 tmp->in_color = parent->in_color;
333 parent->in_color = INTERVAL_BLACK;
335 tmp->in_right->in_color = INTERVAL_BLACK;
336 __rotate_left(parent, root);
341 tmp = parent->in_left;
342 if (node_is_red(tmp)) {
343 tmp->in_color = INTERVAL_BLACK;
344 parent->in_color = INTERVAL_RED;
345 __rotate_right(parent, root);
346 tmp = parent->in_left;
348 if (node_is_black_or_0(tmp->in_left) &&
349 node_is_black_or_0(tmp->in_right)) {
350 tmp->in_color = INTERVAL_RED;
352 parent = node->in_parent;
354 if (node_is_black_or_0(tmp->in_left)) {
355 struct interval_node *o_right;
357 o_right = tmp->in_right;
359 o_right->in_color = INTERVAL_BLACK;
360 tmp->in_color = INTERVAL_RED;
361 __rotate_left(tmp, root);
362 tmp = parent->in_left;
364 tmp->in_color = parent->in_color;
365 parent->in_color = INTERVAL_BLACK;
367 tmp->in_left->in_color = INTERVAL_BLACK;
368 __rotate_right(parent, root);
375 node->in_color = INTERVAL_BLACK;
379 * if the @max_high value of @node is changed, this function traverse a path
380 * from node up to the root to update max_high for the whole tree.
382 static void update_maxhigh(struct interval_node *node,
385 __u64 left_max, right_max;
388 left_max = node->in_left ? node->in_left->in_max_high : 0;
389 right_max = node->in_right ? node->in_right->in_max_high : 0;
390 node->in_max_high = max_u64(interval_high(node),
391 max_u64(left_max, right_max));
393 if (node->in_max_high >= old_maxhigh)
395 node = node->in_parent;
399 void interval_erase(struct interval_node *node,
400 struct interval_node **root)
402 struct interval_node *child, *parent;
405 LASSERT(interval_is_intree(node));
407 if (!node->in_left) {
408 child = node->in_right;
409 } else if (!node->in_right) {
410 child = node->in_left;
411 } else { /* Both left and right child are not NULL */
412 struct interval_node *old = node;
414 node = interval_next(node);
415 child = node->in_right;
416 parent = node->in_parent;
417 color = node->in_color;
420 child->in_parent = parent;
422 parent->in_right = child;
424 parent->in_left = child;
426 node->in_color = old->in_color;
427 node->in_right = old->in_right;
428 node->in_left = old->in_left;
429 node->in_parent = old->in_parent;
431 if (old->in_parent) {
432 if (node_is_left_child(old))
433 old->in_parent->in_left = node;
435 old->in_parent->in_right = node;
440 old->in_left->in_parent = node;
442 old->in_right->in_parent = node;
443 update_maxhigh(child ? : parent, node->in_max_high);
444 update_maxhigh(node, old->in_max_high);
449 parent = node->in_parent;
450 color = node->in_color;
453 child->in_parent = parent;
455 if (node_is_left_child(node))
456 parent->in_left = child;
458 parent->in_right = child;
463 update_maxhigh(child ? : parent, node->in_max_high);
466 if (color == INTERVAL_BLACK)
467 interval_erase_color(child, parent, root);
469 EXPORT_SYMBOL(interval_erase);