blob: f4a70ebddeaf689d9fdf5aabca64bc9d652fb81e [file] [log] [blame]
Peng Taod7e09d02013-05-02 16:46:55 +08001/*
2 * GPL HEADER START
3 *
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
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.
9 *
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).
15 *
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
Oleg Drokin6a5b99a2016-06-14 23:33:40 -040018 * http://www.gnu.org/licenses/gpl-2.0.html
Peng Taod7e09d02013-05-02 16:46:55 +080019 *
Peng Taod7e09d02013-05-02 16:46:55 +080020 * GPL HEADER END
21 */
22/*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Use is subject to license terms.
25 */
26/*
27 * This file is part of Lustre, http://www.lustre.org/
28 * Lustre is a trademark of Sun Microsystems, Inc.
29 *
30 * lustre/ldlm/interval_tree.c
31 *
32 * Interval tree library used by ldlm extent lock code
33 *
34 * Author: Huang Wei <huangwei@clusterfs.com>
35 * Author: Jay Xiong <jinshan.xiong@sun.com>
36 */
Greg Kroah-Hartmane27db142014-07-11 22:29:36 -070037#include "../include/lustre_dlm.h"
38#include "../include/obd_support.h"
39#include "../include/interval_tree.h"
Peng Taod7e09d02013-05-02 16:46:55 +080040
41enum {
42 INTERVAL_RED = 0,
43 INTERVAL_BLACK = 1
44};
45
46static inline int node_is_left_child(struct interval_node *node)
47{
Peng Taod7e09d02013-05-02 16:46:55 +080048 return node == node->in_parent->in_left;
49}
50
51static inline int node_is_right_child(struct interval_node *node)
52{
Peng Taod7e09d02013-05-02 16:46:55 +080053 return node == node->in_parent->in_right;
54}
55
56static inline int node_is_red(struct interval_node *node)
57{
58 return node->in_color == INTERVAL_RED;
59}
60
61static inline int node_is_black(struct interval_node *node)
62{
63 return node->in_color == INTERVAL_BLACK;
64}
65
66static inline int extent_compare(struct interval_node_extent *e1,
67 struct interval_node_extent *e2)
68{
69 int rc;
Andreas Ruprecht902f3bb2014-11-23 14:37:48 +010070
Peng Taod7e09d02013-05-02 16:46:55 +080071 if (e1->start == e2->start) {
72 if (e1->end < e2->end)
73 rc = -1;
74 else if (e1->end > e2->end)
75 rc = 1;
76 else
77 rc = 0;
78 } else {
79 if (e1->start < e2->start)
80 rc = -1;
81 else
82 rc = 1;
83 }
84 return rc;
85}
86
87static inline int extent_equal(struct interval_node_extent *e1,
88 struct interval_node_extent *e2)
89{
90 return (e1->start == e2->start) && (e1->end == e2->end);
91}
92
Peng Taod7e09d02013-05-02 16:46:55 +080093static inline __u64 max_u64(__u64 x, __u64 y)
94{
95 return x > y ? x : y;
96}
97
Peng Taod7e09d02013-05-02 16:46:55 +080098static struct interval_node *interval_first(struct interval_node *node)
99{
Peng Taod7e09d02013-05-02 16:46:55 +0800100 if (!node)
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800101 return NULL;
Peng Taod7e09d02013-05-02 16:46:55 +0800102 while (node->in_left)
103 node = node->in_left;
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800104 return node;
Peng Taod7e09d02013-05-02 16:46:55 +0800105}
106
Peng Taod7e09d02013-05-02 16:46:55 +0800107static struct interval_node *interval_next(struct interval_node *node)
108{
Peng Taod7e09d02013-05-02 16:46:55 +0800109 if (!node)
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800110 return NULL;
Peng Taod7e09d02013-05-02 16:46:55 +0800111 if (node->in_right)
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800112 return interval_first(node->in_right);
Peng Taod7e09d02013-05-02 16:46:55 +0800113 while (node->in_parent && node_is_right_child(node))
114 node = node->in_parent;
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800115 return node->in_parent;
Peng Taod7e09d02013-05-02 16:46:55 +0800116}
117
Peng Taod7e09d02013-05-02 16:46:55 +0800118static void __rotate_change_maxhigh(struct interval_node *node,
119 struct interval_node *rotate)
120{
121 __u64 left_max, right_max;
122
123 rotate->in_max_high = node->in_max_high;
124 left_max = node->in_left ? node->in_left->in_max_high : 0;
125 right_max = node->in_right ? node->in_right->in_max_high : 0;
126 node->in_max_high = max_u64(interval_high(node),
Rashika Kheria5bd77972013-10-26 16:23:21 +0530127 max_u64(left_max, right_max));
Peng Taod7e09d02013-05-02 16:46:55 +0800128}
129
130/* The left rotation "pivots" around the link from node to node->right, and
131 * - node will be linked to node->right's left child, and
Oleg Drokin6f789a62016-02-24 22:00:29 -0500132 * - node->right's left child will be linked to node's right child.
133 */
Peng Taod7e09d02013-05-02 16:46:55 +0800134static void __rotate_left(struct interval_node *node,
135 struct interval_node **root)
136{
137 struct interval_node *right = node->in_right;
138 struct interval_node *parent = node->in_parent;
139
140 node->in_right = right->in_left;
141 if (node->in_right)
142 right->in_left->in_parent = node;
143
144 right->in_left = node;
145 right->in_parent = parent;
146 if (parent) {
147 if (node_is_left_child(node))
148 parent->in_left = right;
149 else
150 parent->in_right = right;
151 } else {
152 *root = right;
153 }
154 node->in_parent = right;
155
156 /* update max_high for node and right */
157 __rotate_change_maxhigh(node, right);
158}
159
160/* The right rotation "pivots" around the link from node to node->left, and
161 * - node will be linked to node->left's right child, and
Oleg Drokin6f789a62016-02-24 22:00:29 -0500162 * - node->left's right child will be linked to node's left child.
163 */
Peng Taod7e09d02013-05-02 16:46:55 +0800164static void __rotate_right(struct interval_node *node,
165 struct interval_node **root)
166{
167 struct interval_node *left = node->in_left;
168 struct interval_node *parent = node->in_parent;
169
170 node->in_left = left->in_right;
171 if (node->in_left)
172 left->in_right->in_parent = node;
173 left->in_right = node;
174
175 left->in_parent = parent;
176 if (parent) {
177 if (node_is_right_child(node))
178 parent->in_right = left;
179 else
180 parent->in_left = left;
181 } else {
182 *root = left;
183 }
184 node->in_parent = left;
185
186 /* update max_high for node and left */
187 __rotate_change_maxhigh(node, left);
188}
189
190#define interval_swap(a, b) do { \
191 struct interval_node *c = a; a = b; b = c; \
192} while (0)
193
194/*
195 * Operations INSERT and DELETE, when run on a tree with n keys,
196 * take O(logN) time.Because they modify the tree, the result
197 * may violate the red-black properties.To restore these properties,
198 * we must change the colors of some of the nodes in the tree
199 * and also change the pointer structure.
200 */
201static void interval_insert_color(struct interval_node *node,
202 struct interval_node **root)
203{
204 struct interval_node *parent, *gparent;
Peng Taod7e09d02013-05-02 16:46:55 +0800205
206 while ((parent = node->in_parent) && node_is_red(parent)) {
207 gparent = parent->in_parent;
208 /* Parent is RED, so gparent must not be NULL */
209 if (node_is_left_child(parent)) {
210 struct interval_node *uncle;
Andreas Ruprecht902f3bb2014-11-23 14:37:48 +0100211
Peng Taod7e09d02013-05-02 16:46:55 +0800212 uncle = gparent->in_right;
213 if (uncle && node_is_red(uncle)) {
214 uncle->in_color = INTERVAL_BLACK;
215 parent->in_color = INTERVAL_BLACK;
216 gparent->in_color = INTERVAL_RED;
217 node = gparent;
218 continue;
219 }
220
221 if (parent->in_right == node) {
222 __rotate_left(parent, root);
223 interval_swap(node, parent);
224 }
225
226 parent->in_color = INTERVAL_BLACK;
227 gparent->in_color = INTERVAL_RED;
228 __rotate_right(gparent, root);
229 } else {
230 struct interval_node *uncle;
Andreas Ruprecht902f3bb2014-11-23 14:37:48 +0100231
Peng Taod7e09d02013-05-02 16:46:55 +0800232 uncle = gparent->in_left;
233 if (uncle && node_is_red(uncle)) {
234 uncle->in_color = INTERVAL_BLACK;
235 parent->in_color = INTERVAL_BLACK;
236 gparent->in_color = INTERVAL_RED;
237 node = gparent;
238 continue;
239 }
240
241 if (node_is_left_child(node)) {
242 __rotate_right(parent, root);
243 interval_swap(node, parent);
244 }
245
246 parent->in_color = INTERVAL_BLACK;
247 gparent->in_color = INTERVAL_RED;
248 __rotate_left(gparent, root);
249 }
250 }
251
252 (*root)->in_color = INTERVAL_BLACK;
Peng Taod7e09d02013-05-02 16:46:55 +0800253}
254
255struct interval_node *interval_insert(struct interval_node *node,
256 struct interval_node **root)
257
258{
259 struct interval_node **p, *parent = NULL;
Peng Taod7e09d02013-05-02 16:46:55 +0800260
261 LASSERT(!interval_is_intree(node));
262 p = root;
263 while (*p) {
264 parent = *p;
Shivani Bhardwaj5d21c5a2015-10-31 20:26:56 +0530265 if (extent_equal(&parent->in_extent, &node->in_extent))
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800266 return parent;
Peng Taod7e09d02013-05-02 16:46:55 +0800267
268 /* max_high field must be updated after each iteration */
269 if (parent->in_max_high < interval_high(node))
270 parent->in_max_high = interval_high(node);
271
Shivani Bhardwaj5d21c5a2015-10-31 20:26:56 +0530272 if (extent_compare(&node->in_extent, &parent->in_extent) < 0)
Peng Taod7e09d02013-05-02 16:46:55 +0800273 p = &parent->in_left;
274 else
275 p = &parent->in_right;
276 }
277
278 /* link node into the tree */
279 node->in_parent = parent;
280 node->in_color = INTERVAL_RED;
Shivani Bhardwaj7b318b42015-10-19 00:17:13 +0530281 node->in_left = NULL;
282 node->in_right = NULL;
Peng Taod7e09d02013-05-02 16:46:55 +0800283 *p = node;
284
285 interval_insert_color(node, root);
286 node->in_intree = 1;
287
Greg Kroah-Hartman0a3bdb02013-08-03 10:35:28 +0800288 return NULL;
Peng Taod7e09d02013-05-02 16:46:55 +0800289}
290EXPORT_SYMBOL(interval_insert);
291
292static inline int node_is_black_or_0(struct interval_node *node)
293{
294 return !node || node_is_black(node);
295}
296
297static void interval_erase_color(struct interval_node *node,
298 struct interval_node *parent,
299 struct interval_node **root)
300{
301 struct interval_node *tmp;
Peng Taod7e09d02013-05-02 16:46:55 +0800302
303 while (node_is_black_or_0(node) && node != *root) {
304 if (parent->in_left == node) {
305 tmp = parent->in_right;
306 if (node_is_red(tmp)) {
307 tmp->in_color = INTERVAL_BLACK;
308 parent->in_color = INTERVAL_RED;
309 __rotate_left(parent, root);
310 tmp = parent->in_right;
311 }
312 if (node_is_black_or_0(tmp->in_left) &&
313 node_is_black_or_0(tmp->in_right)) {
314 tmp->in_color = INTERVAL_RED;
315 node = parent;
316 parent = node->in_parent;
317 } else {
318 if (node_is_black_or_0(tmp->in_right)) {
319 struct interval_node *o_left;
Andreas Ruprecht902f3bb2014-11-23 14:37:48 +0100320
Rashika Kheria16fcfa12013-10-27 18:49:31 +0530321 o_left = tmp->in_left;
322 if (o_left)
Rashika Kheria490f4db2013-10-26 16:19:42 +0530323 o_left->in_color = INTERVAL_BLACK;
Peng Taod7e09d02013-05-02 16:46:55 +0800324 tmp->in_color = INTERVAL_RED;
325 __rotate_right(tmp, root);
326 tmp = parent->in_right;
327 }
328 tmp->in_color = parent->in_color;
329 parent->in_color = INTERVAL_BLACK;
330 if (tmp->in_right)
Rashika Kheria490f4db2013-10-26 16:19:42 +0530331 tmp->in_right->in_color = INTERVAL_BLACK;
Peng Taod7e09d02013-05-02 16:46:55 +0800332 __rotate_left(parent, root);
333 node = *root;
334 break;
335 }
336 } else {
337 tmp = parent->in_left;
338 if (node_is_red(tmp)) {
339 tmp->in_color = INTERVAL_BLACK;
340 parent->in_color = INTERVAL_RED;
341 __rotate_right(parent, root);
342 tmp = parent->in_left;
343 }
344 if (node_is_black_or_0(tmp->in_left) &&
345 node_is_black_or_0(tmp->in_right)) {
346 tmp->in_color = INTERVAL_RED;
347 node = parent;
348 parent = node->in_parent;
349 } else {
350 if (node_is_black_or_0(tmp->in_left)) {
351 struct interval_node *o_right;
Andreas Ruprecht902f3bb2014-11-23 14:37:48 +0100352
Rashika Kheria16fcfa12013-10-27 18:49:31 +0530353 o_right = tmp->in_right;
354 if (o_right)
Rashika Kheria490f4db2013-10-26 16:19:42 +0530355 o_right->in_color = INTERVAL_BLACK;
Peng Taod7e09d02013-05-02 16:46:55 +0800356 tmp->in_color = INTERVAL_RED;
357 __rotate_left(tmp, root);
358 tmp = parent->in_left;
359 }
360 tmp->in_color = parent->in_color;
361 parent->in_color = INTERVAL_BLACK;
362 if (tmp->in_left)
363 tmp->in_left->in_color = INTERVAL_BLACK;
364 __rotate_right(parent, root);
365 node = *root;
366 break;
367 }
368 }
369 }
370 if (node)
371 node->in_color = INTERVAL_BLACK;
Peng Taod7e09d02013-05-02 16:46:55 +0800372}
373
374/*
375 * if the @max_high value of @node is changed, this function traverse a path
376 * from node up to the root to update max_high for the whole tree.
377 */
378static void update_maxhigh(struct interval_node *node,
379 __u64 old_maxhigh)
380{
381 __u64 left_max, right_max;
Peng Taod7e09d02013-05-02 16:46:55 +0800382
383 while (node) {
384 left_max = node->in_left ? node->in_left->in_max_high : 0;
385 right_max = node->in_right ? node->in_right->in_max_high : 0;
386 node->in_max_high = max_u64(interval_high(node),
387 max_u64(left_max, right_max));
388
389 if (node->in_max_high >= old_maxhigh)
390 break;
391 node = node->in_parent;
392 }
Peng Taod7e09d02013-05-02 16:46:55 +0800393}
394
395void interval_erase(struct interval_node *node,
396 struct interval_node **root)
397{
398 struct interval_node *child, *parent;
399 int color;
Peng Taod7e09d02013-05-02 16:46:55 +0800400
401 LASSERT(interval_is_intree(node));
402 node->in_intree = 0;
403 if (!node->in_left) {
404 child = node->in_right;
405 } else if (!node->in_right) {
406 child = node->in_left;
407 } else { /* Both left and right child are not NULL */
408 struct interval_node *old = node;
409
410 node = interval_next(node);
411 child = node->in_right;
412 parent = node->in_parent;
413 color = node->in_color;
414
415 if (child)
416 child->in_parent = parent;
417 if (parent == old)
418 parent->in_right = child;
419 else
420 parent->in_left = child;
421
422 node->in_color = old->in_color;
423 node->in_right = old->in_right;
424 node->in_left = old->in_left;
425 node->in_parent = old->in_parent;
426
427 if (old->in_parent) {
428 if (node_is_left_child(old))
429 old->in_parent->in_left = node;
430 else
431 old->in_parent->in_right = node;
432 } else {
433 *root = node;
434 }
435
436 old->in_left->in_parent = node;
437 if (old->in_right)
438 old->in_right->in_parent = node;
439 update_maxhigh(child ? : parent, node->in_max_high);
440 update_maxhigh(node, old->in_max_high);
441 if (parent == old)
Rashika Kheria490f4db2013-10-26 16:19:42 +0530442 parent = node;
Peng Taod7e09d02013-05-02 16:46:55 +0800443 goto color;
444 }
445 parent = node->in_parent;
446 color = node->in_color;
447
448 if (child)
449 child->in_parent = parent;
450 if (parent) {
451 if (node_is_left_child(node))
452 parent->in_left = child;
453 else
454 parent->in_right = child;
455 } else {
456 *root = child;
457 }
458
459 update_maxhigh(child ? : parent, node->in_max_high);
460
461color:
462 if (color == INTERVAL_BLACK)
463 interval_erase_color(child, parent, root);
Peng Taod7e09d02013-05-02 16:46:55 +0800464}
465EXPORT_SYMBOL(interval_erase);