]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/avl.c
libxfs: refactor manage_zones()
[thirdparty/xfsprogs-dev.git] / repair / avl.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
da23017d
NS
2/*
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
da23017d 5 */
2bd0ea18 6
6b803e5a 7#include "libxfs.h"
2bd0ea18
NS
8#include "avl.h"
9
10#define CERT ASSERT
11
12#ifdef AVL_DEBUG
13
14static void
15avl_checknode(
0c2a7d46
CH
16 avltree_desc_t *tree,
17 avlnode_t *np)
2bd0ea18 18{
0c2a7d46
CH
19 avlnode_t *back = np->avl_back;
20 avlnode_t *forw = np->avl_forw;
21 avlnode_t *nextino = np->avl_nextino;
22 int bal = np->avl_balance;
2bd0ea18
NS
23
24 ASSERT(bal != AVL_BALANCE || (!back && !forw) || (back && forw));
25 ASSERT(bal != AVL_FORW || forw);
26 ASSERT(bal != AVL_BACK || back);
27
28 if (forw) {
29 ASSERT(AVL_START(tree, np) < AVL_START(tree, forw));
30 ASSERT(np->avl_forw->avl_parent == np);
31 ASSERT(back || bal == AVL_FORW);
32 } else {
33 ASSERT(bal != AVL_FORW);
34 ASSERT(bal == AVL_BALANCE || back);
35 ASSERT(bal == AVL_BACK || !back);
36 }
37
38 if (back) {
39 ASSERT(AVL_START(tree, np) > AVL_START(tree, back));
40 ASSERT(np->avl_back->avl_parent == np);
41 ASSERT(forw || bal == AVL_BACK);
42 } else {
43 ASSERT(bal != AVL_BACK);
44 ASSERT(bal == AVL_BALANCE || forw);
45 ASSERT(bal == AVL_FORW || !forw);
46 }
47
48 if (nextino == NULL)
49 ASSERT(forw == NULL);
50 else
51 ASSERT(AVL_END(tree, np) <= AVL_START(tree, nextino));
52}
53
54static void
55avl_checktree(
0c2a7d46
CH
56 avltree_desc_t *tree,
57 avlnode_t *root)
2bd0ea18 58{
0c2a7d46 59 avlnode_t *nlast, *nnext, *np;
ee6cd73e
CH
60 uintptr_t offset = 0;
61 uintptr_t end;
2bd0ea18
NS
62
63 nlast = nnext = root;
64
65 ASSERT(!nnext || nnext->avl_parent == NULL);
66
67 while (nnext) {
68
69 avl_checknode(tree, nnext);
70 end = AVL_END(tree, nnext);
71
72 if (end <= offset) {
73 if ((np = nnext->avl_forw) && np != nlast) {
74 nlast = nnext;
75 nnext = np;
76 } else {
77 nlast = nnext;
78 nnext = nnext->avl_parent;
79 }
80 continue;
81 }
82
83 nlast = nnext;
84 if (np = nnext->avl_back) {
85 if (AVL_END(tree, np) > offset) {
86 nnext = np;
87 continue;
88 }
89 }
90
91 np = nnext;
92 nnext = nnext->avl_forw;
93 if (!nnext)
94 nnext = np->avl_parent;
95
96 offset = end;
97 }
98}
99#else /* ! AVL_DEBUG */
100#define avl_checktree(t,x)
101#endif /* AVL_DEBUG */
102
103
104/*
105 * Reset balance for np up through tree.
106 * ``direction'' is the way that np's balance
107 * is headed after the deletion of one of its children --
108 * e.g., deleting a avl_forw child sends avl_balance toward AVL_BACK.
109 * Called only when deleting a node from the tree.
110 */
111static void
112retreat(
113 avltree_desc_t *tree,
0c2a7d46
CH
114 avlnode_t *np,
115 int direction)
2bd0ea18 116{
0c2a7d46
CH
117 avlnode_t **rootp = &tree->avl_root;
118 avlnode_t *parent;
119 avlnode_t *child;
120 avlnode_t *tmp;
121 int bal;
2bd0ea18
NS
122
123 do {
124 ASSERT(direction == AVL_BACK || direction == AVL_FORW);
125
126 if (np->avl_balance == AVL_BALANCE) {
127 np->avl_balance = direction;
128 return;
129 }
130
131 parent = np->avl_parent;
132
133 /*
134 * If balance is being restored, no local node
135 * reorganization is necessary, but may be at
136 * a higher node. Reset direction and continue.
137 */
138 if (direction != np->avl_balance) {
139 np->avl_balance = AVL_BALANCE;
140 if (parent) {
141 if (parent->avl_forw == np)
142 direction = AVL_BACK;
143 else
144 direction = AVL_FORW;
145
146 np = parent;
147 continue;
148 }
149 return;
150 }
151
152 /*
153 * Imbalance. If a avl_forw node was removed, direction
154 * (and, by reduction, np->avl_balance) is/was AVL_BACK.
155 */
156 if (np->avl_balance == AVL_BACK) {
157
158 ASSERT(direction == AVL_BACK);
159 child = np->avl_back;
160 bal = child->avl_balance;
161
162 if (bal != AVL_FORW) /* single LL */ {
163 /*
164 * np gets pushed down to lesser child's
165 * avl_forw branch.
166 *
dfc130f3 167 * np-> -D +B
2bd0ea18
NS
168 * / \ / \
169 * child-> B deleted A -D
170 * / \ /
171 * A C C
172 */
173#ifdef AVL_PRINT
174 if (!(tree->avl_flags & AVLF_DUPLICITY))
175 cmn_err(CE_CONT, "!LL delete b 0x%x c 0x%x\n",
176 np, child);
177#endif
178 np->avl_back = child->avl_forw;
179 if (child->avl_forw)
180 child->avl_forw->avl_parent = np;
181 child->avl_forw = np;
182
183 if (parent) {
184 if (parent->avl_forw == np) {
185 parent->avl_forw = child;
186 direction = AVL_BACK;
187 } else {
188 ASSERT(parent->avl_back == np);
189 parent->avl_back = child;
190 direction = AVL_FORW;
191 }
192 } else {
193 ASSERT(*rootp == np);
194 *rootp = child;
195 }
196 np->avl_parent = child;
197 child->avl_parent = parent;
198
199 if (bal == AVL_BALANCE) {
200 np->avl_balance = AVL_BACK;
201 child->avl_balance = AVL_FORW;
202 return;
203 } else {
204 np->avl_balance = AVL_BALANCE;
205 child->avl_balance = AVL_BALANCE;
206 np = parent;
207 avl_checktree(tree, *rootp);
208 continue;
209 }
210 }
211
212 /* child->avl_balance == AVL_FORW double LR rotation
213 *
214 * child's avl_forw node gets promoted up, along with
215 * its avl_forw subtree
216 *
dfc130f3 217 * np-> -G C
2bd0ea18
NS
218 * / \ / \
219 * child-> +B H -B G
220 * / \ \ / / \
221 * A +C deleted A D H
222 * \
223 * D
224 */
225#ifdef AVL_PRINT
226 if (!(tree->avl_flags & AVLF_DUPLICITY))
227 cmn_err(CE_CONT, "!LR delete b 0x%x c 0x%x t 0x%x\n",
228 np, child, child->avl_forw);
229#endif
230 tmp = child->avl_forw;
231 bal = tmp->avl_balance;
232
233 child->avl_forw = tmp->avl_back;
234 if (tmp->avl_back)
235 tmp->avl_back->avl_parent = child;
236
237 tmp->avl_back = child;
238 child->avl_parent = tmp;
239
240 np->avl_back = tmp->avl_forw;
241 if (tmp->avl_forw)
242 tmp->avl_forw->avl_parent = np;
243 tmp->avl_forw = np;
244
245 if (bal == AVL_FORW)
246 child->avl_balance = AVL_BACK;
247 else
248 child->avl_balance = AVL_BALANCE;
249
250 if (bal == AVL_BACK)
251 np->avl_balance = AVL_FORW;
252 else
253 np->avl_balance = AVL_BALANCE;
254
255 goto next;
256 }
257
258 ASSERT(np->avl_balance == AVL_FORW && direction == AVL_FORW);
259
260 child = np->avl_forw;
261 bal = child->avl_balance;
262
263 if (bal != AVL_BACK) /* single RR */ {
264 /*
265 * np gets pushed down to greater child's
266 * avl_back branch.
267 *
dfc130f3 268 * np-> +B -D
2bd0ea18
NS
269 * / \ / \
270 * deleted D <-child +B E
271 * / \ \
272 * C E C
273 */
274#ifdef AVL_PRINT
275 if (!(tree->avl_flags & AVLF_DUPLICITY))
276 cmn_err(CE_CONT, "!RR delete b 0x%x c 0x%x\n",
277 np, child);
278#endif
279 np->avl_forw = child->avl_back;
280 if (child->avl_back)
281 child->avl_back->avl_parent = np;
282 child->avl_back = np;
283
284 if (parent) {
285 if (parent->avl_forw == np) {
286 parent->avl_forw = child;
287 direction = AVL_BACK;
288 } else {
289 ASSERT(parent->avl_back == np);
290 parent->avl_back = child;
291 direction = AVL_FORW;
292 }
293 } else {
294 ASSERT(*rootp == np);
295 *rootp = child;
296 }
297 np->avl_parent = child;
298 child->avl_parent = parent;
299
300 if (bal == AVL_BALANCE) {
301 np->avl_balance = AVL_FORW;
302 child->avl_balance = AVL_BACK;
303 return;
304 } else {
305 np->avl_balance = AVL_BALANCE;
306 child->avl_balance = AVL_BALANCE;
307 np = parent;
308 avl_checktree(tree, *rootp);
309 continue;
310 }
311 }
312
313 /* child->avl_balance == AVL_BACK double RL rotation */
314#ifdef AVL_PRINT
315 if (!(tree->avl_flags & AVLF_DUPLICITY))
316 cmn_err(CE_CONT, "!RL delete b 0x%x c 0x%x t 0x%x\n",
317 np, child, child->avl_back);
318#endif
319 tmp = child->avl_back;
320 bal = tmp->avl_balance;
321
322 child->avl_back = tmp->avl_forw;
323 if (tmp->avl_forw)
324 tmp->avl_forw->avl_parent = child;
325
326 tmp->avl_forw = child;
327 child->avl_parent = tmp;
328
329 np->avl_forw = tmp->avl_back;
330 if (tmp->avl_back)
331 tmp->avl_back->avl_parent = np;
332 tmp->avl_back = np;
333
334 if (bal == AVL_BACK)
335 child->avl_balance = AVL_FORW;
336 else
337 child->avl_balance = AVL_BALANCE;
338
339 if (bal == AVL_FORW)
340 np->avl_balance = AVL_BACK;
341 else
342 np->avl_balance = AVL_BALANCE;
343next:
344 np->avl_parent = tmp;
345 tmp->avl_balance = AVL_BALANCE;
346 tmp->avl_parent = parent;
347
348 if (parent) {
349 if (parent->avl_forw == np) {
350 parent->avl_forw = tmp;
351 direction = AVL_BACK;
352 } else {
353 ASSERT(parent->avl_back == np);
354 parent->avl_back = tmp;
355 direction = AVL_FORW;
356 }
357 } else {
358 ASSERT(*rootp == np);
359 *rootp = tmp;
360 return;
361 }
362
363 np = parent;
364 avl_checktree(tree, *rootp);
365 } while (np);
366}
367
368/*
369 * Remove node from tree.
370 * avl_delete does the local tree manipulations,
371 * calls retreat() to rebalance tree up to its root.
372 */
373void
374avl_delete(
0c2a7d46
CH
375 avltree_desc_t *tree,
376 avlnode_t *np)
2bd0ea18 377{
0c2a7d46
CH
378 avlnode_t *forw = np->avl_forw;
379 avlnode_t *back = np->avl_back;
380 avlnode_t *parent = np->avl_parent;
381 avlnode_t *nnext;
2bd0ea18
NS
382
383
384 if (np->avl_back) {
385 /*
386 * a left child exits, then greatest left descendent's nextino
387 * is pointing to np; make it point to np->nextino.
388 */
389 nnext = np->avl_back;
390 while (nnext) {
391 if (!nnext->avl_forw)
392 break; /* can't find anything bigger */
393 nnext = nnext->avl_forw;
394 }
395 } else
396 if (np->avl_parent) {
397 /*
398 * find nearest ancestor with lesser value. That ancestor's
399 * nextino is pointing to np; make it point to np->nextino
400 */
401 nnext = np->avl_parent;
402 while (nnext) {
403 if (AVL_END(tree, nnext) <= AVL_END(tree, np))
404 break;
405 nnext = nnext->avl_parent;
406 }
407 } else
408 nnext = NULL;
409
410 if (nnext) {
411 ASSERT(nnext->avl_nextino == np);
412 nnext->avl_nextino = np->avl_nextino;
413 /*
dfc130f3 414 * Something preceeds np; np cannot be firstino.
2bd0ea18
NS
415 */
416 ASSERT(tree->avl_firstino != np);
417 }
418 else {
419 /*
dfc130f3
RC
420 * Nothing preceeding np; after deletion, np's nextino
421 * is firstino of tree.
2bd0ea18
NS
422 */
423 ASSERT(tree->avl_firstino == np);
424 tree->avl_firstino = np->avl_nextino;
425 }
dfc130f3 426
2bd0ea18
NS
427
428 /*
429 * Degenerate cases...
430 */
431 if (forw == NULL) {
432 forw = back;
433 goto attach;
434 }
435
436 if (back == NULL) {
437attach:
438 if (forw)
439 forw->avl_parent = parent;
440 if (parent) {
441 if (parent->avl_forw == np) {
442 parent->avl_forw = forw;
443 retreat(tree, parent, AVL_BACK);
444 } else {
445 ASSERT(parent->avl_back == np);
446 parent->avl_back = forw;
447 retreat(tree, parent, AVL_FORW);
448 }
449 } else {
450 ASSERT(tree->avl_root == np);
451 tree->avl_root = forw;
452 }
453 avl_checktree(tree, tree->avl_root);
454 return;
455 }
456
457 /*
458 * Harder case: children on both sides.
459 * If back's avl_forw pointer is null, just have back
460 * inherit np's avl_forw tree, remove np from the tree
461 * and adjust balance counters starting at back.
462 *
463 * np-> xI xH (befor retreat())
464 * / \ / \
465 * back-> H J G J
466 * / / \ / \
467 * G ? ? ? ?
468 * / \
469 * ? ?
470 */
471 if ((forw = back->avl_forw) == NULL) {
472 /*
473 * AVL_FORW retreat below will set back's
474 * balance to AVL_BACK.
475 */
476 back->avl_balance = np->avl_balance;
477 back->avl_forw = forw = np->avl_forw;
478 forw->avl_parent = back;
479 back->avl_parent = parent;
dfc130f3 480
2bd0ea18
NS
481 if (parent) {
482 if (parent->avl_forw == np)
483 parent->avl_forw = back;
484 else {
485 ASSERT(parent->avl_back == np);
486 parent->avl_back = back;
487 }
488 } else {
489 ASSERT(tree->avl_root == np);
490 tree->avl_root = back;
491 }
492
493 /*
494 * back is taking np's place in the tree, and
495 * has therefore lost a avl_back node (itself).
496 */
497 retreat(tree, back, AVL_FORW);
498 avl_checktree(tree, tree->avl_root);
499 return;
500 }
501
502 /*
503 * Hardest case: children on both sides, and back's
504 * avl_forw pointer isn't null. Find the immediately
505 * inferior buffer by following back's avl_forw line
506 * to the end, then have it inherit np's avl_forw tree.
507 *
508 * np-> xI xH
509 * / \ / \
510 * G J back-> G J (before retreat())
511 * / \ / \
dfc130f3 512 * F ?... F ?1
2bd0ea18
NS
513 * / \
514 * ? H <-forw
515 * /
516 * ?1
517 */
27527004 518 while ((back = forw->avl_forw))
2bd0ea18
NS
519 forw = back;
520
521 /*
522 * Will be adjusted by retreat() below.
523 */
524 forw->avl_balance = np->avl_balance;
dfc130f3 525
2bd0ea18
NS
526 /*
527 * forw inherits np's avl_forw...
528 */
529 forw->avl_forw = np->avl_forw;
530 np->avl_forw->avl_parent = forw;
531
532 /*
533 * ... forw's parent gets forw's avl_back...
534 */
535 back = forw->avl_parent;
536 back->avl_forw = forw->avl_back;
537 if (forw->avl_back)
538 forw->avl_back->avl_parent = back;
539
540 /*
541 * ... forw gets np's avl_back...
542 */
543 forw->avl_back = np->avl_back;
544 np->avl_back->avl_parent = forw;
545
546 /*
547 * ... and forw gets np's parent.
548 */
549 forw->avl_parent = parent;
550
551 if (parent) {
552 if (parent->avl_forw == np)
553 parent->avl_forw = forw;
554 else
555 parent->avl_back = forw;
556 } else {
557 ASSERT(tree->avl_root == np);
558 tree->avl_root = forw;
559 }
560
561 /*
562 * What used to be forw's parent is the starting
563 * point for rebalancing. It has lost a avl_forw node.
564 */
565 retreat(tree, back, AVL_BACK);
566 avl_checktree(tree, tree->avl_root);
567}
568
569
570/*
dfc130f3
RC
571 * avl_findanyrange:
572 *
2bd0ea18
NS
573 * Given range r [start, end), find any range which is contained in r.
574 * if checklen is non-zero, then only ranges of non-zero length are
dfc130f3 575 * considered in finding a match.
2bd0ea18
NS
576 */
577avlnode_t *
578avl_findanyrange(
0c2a7d46 579 avltree_desc_t *tree,
ee6cd73e
CH
580 uintptr_t start,
581 uintptr_t end,
dfc130f3 582 int checklen)
2bd0ea18 583{
0c2a7d46 584 avlnode_t *np = tree->avl_root;
2bd0ea18
NS
585
586 /* np = avl_findadjacent(tree, start, AVL_SUCCEED); */
587 while (np) {
588 if (start < AVL_START(tree, np)) {
589 if (np->avl_back) {
590 np = np->avl_back;
591 continue;
592 }
593 /* if we were to add node with start, would
594 * have a growth of AVL_BACK
595 */
596 /* if succeeding node is needed, this is it.
597 */
598 break;
599 }
600 if (start >= AVL_END(tree, np)) {
601 if (np->avl_forw) {
602 np = np->avl_forw;
603 continue;
604 }
605 /* if we were to add node with start, would
dfc130f3 606 * have a growth of AVL_FORW;
2bd0ea18
NS
607 */
608 /* we are looking for a succeeding node;
609 * this is nextino.
610 */
611 np = np->avl_nextino;
612 break;
613 }
614 /* AVL_START(tree, np) <= start < AVL_END(tree, np) */
615 break;
616 }
617 if (np) {
618 if (checklen == AVL_INCLUDE_ZEROLEN) {
619 if (end <= AVL_START(tree, np)) {
620 /* something follows start, but is
621 * is entierly after the range (end)
622 */
623 return(NULL);
624 }
625 /* np may stradle [start, end) */
626 return(np);
627 }
628 /*
dfc130f3 629 * find non-zero length region
2bd0ea18
NS
630 */
631 while (np && (AVL_END(tree, np) - AVL_START(tree, np) == 0)
632 && (AVL_START(tree, np) < end))
633 np = np->avl_nextino;
634
635 if ((np == NULL) || (AVL_START(tree, np) >= end))
636 return NULL;
637 return(np);
638 }
639 /*
640 * nothing succeeds start, all existing ranges are before start.
641 */
642 return NULL;
643}
644
2bd0ea18
NS
645/*
646 * Returns a pointer to node which contains exact value.
647 */
648avlnode_t *
649avl_find(
0c2a7d46 650 avltree_desc_t *tree,
ee6cd73e 651 uintptr_t value)
2bd0ea18 652{
0c2a7d46 653 avlnode_t *np = tree->avl_root;
ee6cd73e 654 uintptr_t nvalue;
2bd0ea18
NS
655
656 while (np) {
657 nvalue = AVL_START(tree, np);
658 if (value < nvalue) {
659 np = np->avl_back;
660 continue;
661 }
662 if (value == nvalue) {
663 return np;
664 }
665 np = np->avl_forw;
666 }
667 return NULL;
668}
669
670
671/*
672 * Balance buffer AVL tree after attaching a new node to root.
673 * Called only by avl_insert.
674 */
675static void
676avl_balance(
0c2a7d46
CH
677 avlnode_t **rootp,
678 avlnode_t *np,
679 int growth)
2bd0ea18
NS
680{
681 /*
682 * At this point, np points to the node to which
683 * a new node has been attached. All that remains is to
684 * propagate avl_balance up the tree.
685 */
686 for ( ; ; ) {
0c2a7d46
CH
687 avlnode_t *parent = np->avl_parent;
688 avlnode_t *child;
2bd0ea18
NS
689
690 CERT(growth == AVL_BACK || growth == AVL_FORW);
691
692 /*
693 * If the buffer was already balanced, set avl_balance
694 * to the new direction. Continue if there is a
695 * parent after setting growth to reflect np's
696 * relation to its parent.
697 */
698 if (np->avl_balance == AVL_BALANCE) {
699 np->avl_balance = growth;
700 if (parent) {
701 if (parent->avl_forw == np)
702 growth = AVL_FORW;
703 else {
704 ASSERT(parent->avl_back == np);
705 growth = AVL_BACK;
706 }
707
708 np = parent;
709 continue;
710 }
711 break;
712 }
713
714 if (growth != np->avl_balance) {
715 /*
716 * Subtree is now balanced -- no net effect
717 * in the size of the subtree, so leave.
718 */
719 np->avl_balance = AVL_BALANCE;
720 break;
721 }
722
723 if (growth == AVL_BACK) {
724
725 child = np->avl_back;
726 CERT(np->avl_balance == AVL_BACK && child);
727
728 if (child->avl_balance == AVL_BACK) { /* single LL */
729 /*
730 * ``A'' just got inserted;
731 * np points to ``E'', child to ``C'',
732 * and it is already AVL_BACK --
733 * child will get promoted to top of subtree.
734
735 np-> -E C
736 / \ / \
737 child-> -C F -B E
738 / \ / / \
739 -B D A D F
740 /
741 A
742
743 Note that child->avl_parent and
744 avl_balance get set in common code.
745 */
746 np->avl_parent = child;
747 np->avl_balance = AVL_BALANCE;
748 np->avl_back = child->avl_forw;
749 if (child->avl_forw)
750 child->avl_forw->avl_parent = np;
751 child->avl_forw = np;
752 } else {
753 /*
754 * double LR
755 *
756 * child's avl_forw node gets promoted to
757 * the top of the subtree.
758
759 np-> -E C
760 / \ / \
761 child-> +B F -B E
762 / \ / / \
dfc130f3 763 A +C A D F
2bd0ea18
NS
764 \
765 D
766
767 */
0c2a7d46 768 avlnode_t *tmp = child->avl_forw;
2bd0ea18
NS
769
770 CERT(child->avl_balance == AVL_FORW && tmp);
771
772 child->avl_forw = tmp->avl_back;
773 if (tmp->avl_back)
774 tmp->avl_back->avl_parent = child;
775
776 tmp->avl_back = child;
777 child->avl_parent = tmp;
778
779 np->avl_back = tmp->avl_forw;
780 if (tmp->avl_forw)
781 tmp->avl_forw->avl_parent = np;
782
783 tmp->avl_forw = np;
784 np->avl_parent = tmp;
785
786 if (tmp->avl_balance == AVL_BACK)
787 np->avl_balance = AVL_FORW;
788 else
789 np->avl_balance = AVL_BALANCE;
790
791 if (tmp->avl_balance == AVL_FORW)
792 child->avl_balance = AVL_BACK;
793 else
794 child->avl_balance = AVL_BALANCE;
795
796 /*
797 * Set child to point to tmp since it is
798 * now the top of the subtree, and will
799 * get attached to the subtree parent in
800 * the common code below.
801 */
802 child = tmp;
803 }
804
805 } else /* growth == AVL_BACK */ {
806
807 /*
808 * This code is the mirror image of AVL_FORW above.
809 */
810
811 child = np->avl_forw;
812 CERT(np->avl_balance == AVL_FORW && child);
813
814 if (child->avl_balance == AVL_FORW) { /* single RR */
815 np->avl_parent = child;
816 np->avl_balance = AVL_BALANCE;
817 np->avl_forw = child->avl_back;
818 if (child->avl_back)
819 child->avl_back->avl_parent = np;
820 child->avl_back = np;
821 } else {
822 /*
823 * double RL
824 */
0c2a7d46 825 avlnode_t *tmp = child->avl_back;
2bd0ea18
NS
826
827 ASSERT(child->avl_balance == AVL_BACK && tmp);
828
829 child->avl_back = tmp->avl_forw;
830 if (tmp->avl_forw)
831 tmp->avl_forw->avl_parent = child;
832
833 tmp->avl_forw = child;
834 child->avl_parent = tmp;
835
836 np->avl_forw = tmp->avl_back;
837 if (tmp->avl_back)
838 tmp->avl_back->avl_parent = np;
839
840 tmp->avl_back = np;
841 np->avl_parent = tmp;
842
843 if (tmp->avl_balance == AVL_FORW)
844 np->avl_balance = AVL_BACK;
845 else
846 np->avl_balance = AVL_BALANCE;
847
848 if (tmp->avl_balance == AVL_BACK)
849 child->avl_balance = AVL_FORW;
850 else
851 child->avl_balance = AVL_BALANCE;
852
853 child = tmp;
854 }
855 }
856
857 child->avl_parent = parent;
858 child->avl_balance = AVL_BALANCE;
859
860 if (parent) {
861 if (parent->avl_back == np)
862 parent->avl_back = child;
863 else
864 parent->avl_forw = child;
865 } else {
866 ASSERT(*rootp == np);
867 *rootp = child;
868 }
869
870 break;
871 }
872}
873
874static
875avlnode_t *
876avl_insert_find_growth(
0c2a7d46 877 avltree_desc_t *tree,
ee6cd73e
CH
878 uintptr_t start, /* range start at start, */
879 uintptr_t end, /* exclusive */
0c2a7d46 880 int *growthp) /* OUT */
2bd0ea18
NS
881{
882 avlnode_t *root = tree->avl_root;
0c2a7d46 883 avlnode_t *np;
2bd0ea18
NS
884
885 np = root;
886 ASSERT(np); /* caller ensures that there is atleast one node in tree */
887
888 for ( ; ; ) {
889 CERT(np->avl_parent || root == np);
890 CERT(!np->avl_parent || root != np);
891 CERT(!(np->avl_back) || np->avl_back->avl_parent == np);
892 CERT(!(np->avl_forw) || np->avl_forw->avl_parent == np);
893 CERT(np->avl_balance != AVL_FORW || np->avl_forw);
894 CERT(np->avl_balance != AVL_BACK || np->avl_back);
895 CERT(np->avl_balance != AVL_BALANCE ||
896 np->avl_back == NULL || np->avl_forw);
897 CERT(np->avl_balance != AVL_BALANCE ||
898 np->avl_forw == NULL || np->avl_back);
899
900 if (AVL_START(tree, np) >= end) {
901 if (np->avl_back) {
902 np = np->avl_back;
903 continue;
904 }
905 *growthp = AVL_BACK;
906 break;
907 }
908
909 if (AVL_END(tree, np) <= start) {
910 if (np->avl_forw) {
911 np = np->avl_forw;
912 continue;
913 }
914 *growthp = AVL_FORW;
915 break;
916 }
917 /* found exact match -- let caller decide if it is an error */
918 return(NULL);
919 }
920 return(np);
921}
922
923
924static void
925avl_insert_grow(
0c2a7d46
CH
926 avltree_desc_t *tree,
927 avlnode_t *parent,
928 avlnode_t *newnode,
929 int growth)
2bd0ea18 930{
0c2a7d46 931 avlnode_t *nnext;
ee6cd73e 932 uintptr_t start = AVL_START(tree, newnode);
2bd0ea18
NS
933
934 if (growth == AVL_BACK) {
935
936 parent->avl_back = newnode;
937 /*
938 * we are growing to the left; previous in-order to newnode is
939 * closest ancestor with lesser value. Before this
940 * insertion, this ancestor will be pointing to
941 * newnode's parent. After insertion, next in-order to newnode
942 * is the parent.
943 */
944 newnode->avl_nextino = parent;
945 nnext = parent;
946 while (nnext) {
947 if (AVL_END(tree, nnext) <= start)
948 break;
949 nnext = nnext->avl_parent;
950 }
951 if (nnext) {
952 /*
953 * nnext will be null if newnode is
954 * the least element, and hence very first in the list.
955 */
956 ASSERT(nnext->avl_nextino == parent);
957 nnext->avl_nextino = newnode;
958 }
959 }
960 else {
961 parent->avl_forw = newnode;
962 newnode->avl_nextino = parent->avl_nextino;
963 parent->avl_nextino = newnode;
964 }
965}
966
967
968avlnode_t *
969avl_insert(
0c2a7d46
CH
970 avltree_desc_t *tree,
971 avlnode_t *newnode)
2bd0ea18 972{
0c2a7d46 973 avlnode_t *np;
ee6cd73e
CH
974 uintptr_t start = AVL_START(tree, newnode);
975 uintptr_t end = AVL_END(tree, newnode);
2bd0ea18
NS
976 int growth;
977
978 ASSERT(newnode);
979 ASSERT(start <= end);
980
981 /*
982 * Clean all pointers for sanity; some will be reset as necessary.
983 */
984 newnode->avl_nextino = NULL;
985 newnode->avl_parent = NULL;
986 newnode->avl_forw = NULL;
987 newnode->avl_back = NULL;
988 newnode->avl_balance = AVL_BALANCE;
989
990 if ((np = tree->avl_root) == NULL) { /* degenerate case... */
991 tree->avl_root = newnode;
992 tree->avl_firstino = newnode;
993 return newnode;
994 }
995
996 if ((np = avl_insert_find_growth(tree, start, end, &growth)) == NULL) {
997 if (start != end) { /* non-zero length range */
2d9475a4 998 fprintf(stderr,
507f4e33 999 _("avl_insert: Warning! duplicate range [%llu,%llu]\n"),
2d9475a4
NS
1000 (unsigned long long)start,
1001 (unsigned long long)end);
2bd0ea18
NS
1002 }
1003 return(NULL);
1004 }
1005
1006 avl_insert_grow(tree, np, newnode, growth);
1007 if (growth == AVL_BACK) {
1008 /*
1009 * Growing to left. if np was firstino, newnode will be firstino
1010 */
1011 if (tree->avl_firstino == np)
1012 tree->avl_firstino = newnode;
1013 }
1014#ifdef notneeded
1015 else
1016 if (growth == AVL_FORW)
1017 /*
1018 * Cannot possibly be firstino; there is somebody to our left.
1019 */
1020 ;
1021#endif
1022
1023 newnode->avl_parent = np;
1024 CERT(np->avl_forw == newnode || np->avl_back == newnode);
1025
1026 avl_balance(&tree->avl_root, np, growth);
1027
1028 avl_checktree(tree, tree->avl_root);
1029
1030 return newnode;
1031}
1032
1033/*
1034 *
1035 * avl_insert_immediate(tree, afterp, newnode):
dfc130f3 1036 * insert newnode immediately into tree immediately after afterp.
2bd0ea18
NS
1037 * after insertion, newnode is right child of afterp.
1038 */
1039void
1040avl_insert_immediate(
1041 avltree_desc_t *tree,
1042 avlnode_t *afterp,
1043 avlnode_t *newnode)
1044{
1045 /*
1046 * Clean all pointers for sanity; some will be reset as necessary.
1047 */
1048 newnode->avl_nextino = NULL;
1049 newnode->avl_parent = NULL;
1050 newnode->avl_forw = NULL;
1051 newnode->avl_back = NULL;
1052 newnode->avl_balance = AVL_BALANCE;
1053
1054 if (afterp == NULL) {
1055 tree->avl_root = newnode;
1056 tree->avl_firstino = newnode;
1057 return;
1058 }
1059
1060 ASSERT(afterp->avl_forw == NULL);
1061 avl_insert_grow(tree, afterp, newnode, AVL_FORW); /* grow to right */
1062 CERT(afterp->avl_forw == newnode);
1063 avl_balance(&tree->avl_root, afterp, AVL_FORW);
1064 avl_checktree(tree, tree->avl_root);
1065}
1066
1067
1068/*
1069 * Returns first in order node
1070 */
1071avlnode_t *
0c2a7d46 1072avl_firstino(avlnode_t *root)
2bd0ea18 1073{
0c2a7d46 1074 avlnode_t *np;
2bd0ea18
NS
1075
1076 if ((np = root) == NULL)
1077 return NULL;
1078
1079 while (np->avl_back)
1080 np = np->avl_back;
1081 return np;
1082}
1083
2bd0ea18
NS
1084/*
1085 * Returns last in order node
1086 */
1087avlnode_t *
0c2a7d46 1088avl_lastino(avlnode_t *root)
2bd0ea18 1089{
0c2a7d46 1090 avlnode_t *np;
2bd0ea18
NS
1091
1092 if ((np = root) == NULL)
1093 return NULL;
1094
1095 while (np->avl_forw)
1096 np = np->avl_forw;
1097 return np;
1098}
2bd0ea18
NS
1099
1100void
1101avl_init_tree(avltree_desc_t *tree, avlops_t *ops)
1102{
1103 tree->avl_root = NULL;
1104 tree->avl_firstino = NULL;
1105 tree->avl_ops = ops;
1106}
1107
1108#ifdef AVL_DEBUG
1109static void
1110avl_printnode(avltree_desc_t *tree, avlnode_t *np, int nl)
1111{
1112 printf("[%d-%d]%c", AVL_START(tree, np),
1113 (AVL_END(tree, np) - 1), nl ? '\n' : ' ');
1114}
1115#endif
1116#ifdef STAND_ALONE_DEBUG
1117
1118struct avl_debug_node {
1119 avlnode_t avl_node;
1120 xfs_off_t avl_start;
1121 unsigned int avl_size;
1122}
1123
1124avlops_t avl_debug_ops = {
1125 avl_debug_start,
1126 avl_debug_end,
1127}
1128
ee6cd73e 1129static uintptr_t
2bd0ea18
NS
1130avl_debug_start(avlnode_t *node)
1131{
ee6cd73e 1132 return (uintptr_t)(struct avl_debug_node *)node->avl_start;
2bd0ea18
NS
1133}
1134
ee6cd73e 1135static uintptr_t
2bd0ea18
NS
1136avl_debug_end(avlnode_t *node)
1137{
ee6cd73e 1138 return (uintptr_t)
2bd0ea18
NS
1139 ((struct avl_debug_node *)node->avl_start +
1140 (struct avl_debug_node *)node->avl_size);
1141}
1142
dfc130f3
RC
1143avl_debug_node freenodes[100];
1144avl_debug_node *freehead = &freenodes[0];
2bd0ea18
NS
1145
1146static avlnode_t *
1147alloc_avl_debug_node()
1148{
1149 freehead->avl_balance = AVL_BALANCE;
1150 freehead->avl_parent = freehead->avl_forw = freehead->avl_back = NULL;
1151 return(freehead++);
1152}
1153
1154static void
1155avl_print(avltree_desc_t *tree, avlnode_t *root, int depth)
1156{
1157 int i;
1158
1159 if (!root)
1160 return;
1161 if (root->avl_forw)
1162 avl_print(tree, root->avl_forw, depth+5);
1163 for (i = 0; i < depth; i++)
1164 putchar((int) ' ');
1165 avl_printnode(tree, root,1);
1166 if (root->avl_back)
1167 avl_print(tree, root->avl_back, depth+5);
1168}
1169
1170main()
1171{
dfc130f3
RC
1172 int i, j;
1173 avlnode_t *np;
2bd0ea18
NS
1174 avltree_desc_t tree;
1175 char linebuf[256], cmd[256];
1176
1177 avl_init_tree(&tree, &avl_debug_ops);
1178
1179 for (i = 100; i > 0; i = i - 10)
dfc130f3 1180 {
2bd0ea18
NS
1181 np = alloc__debug_avlnode();
1182 ASSERT(np);
1183 np->avl_start = i;
1184 np->avl_size = 10;
1185 avl_insert(&tree, np);
1186 }
1187 avl_print(&tree, tree.avl_root, 0);
1188
1189 for (np = tree.avl_firstino; np != NULL; np = np->avl_nextino)
1190 avl_printnode(&tree, np, 0);
1191 printf("\n");
1192
1193 while (1) {
9ee7055c 1194 printf(_("Command [fpdir] : "));
2bd0ea18
NS
1195 fgets(linebuf, 256, stdin);
1196 if (feof(stdin)) break;
1197 cmd[0] = NULL;
1198 if (sscanf(linebuf, "%[fpdir]%d", cmd, &i) != 2)
1199 continue;
1200 switch (cmd[0]) {
1201 case 'd':
1202 case 'f':
9ee7055c 1203 printf(_("end of range ? "));
2bd0ea18
NS
1204 fgets(linebuf, 256, stdin);
1205 j = atoi(linebuf);
1206
1207 if (i == j) j = i+1;
1208 np = avl_findinrange(&tree,i,j);
1209 if (np) {
1210 avl_printnode(&tree, np, 1);
1211 if (cmd[0] == 'd')
1212 avl_delete(&tree, np);
1213 } else
9ee7055c 1214 printf(_("Cannot find %d\n"), i);
2bd0ea18
NS
1215 break;
1216 case 'p':
1217 avl_print(&tree, tree.avl_root, 0);
1218 for (np = tree.avl_firstino;
1219 np != NULL; np = np->avl_nextino)
1220 avl_printnode(&tree, np, 0);
1221 printf("\n");
1222 break;
1223 case 'i':
1224 np = alloc_avlnode();
1225 ASSERT(np);
1226 np->avl_start = i;
9ee7055c 1227 printf(_("size of range ? "));
2bd0ea18
NS
1228 fgets(linebuf, 256, stdin);
1229 j = atoi(linebuf);
1230
1231 np->avl_size = j;
1232 avl_insert(&tree, np);
1233 break;
1234 case 'r': {
dfc130f3 1235 avlnode_t *b, *e, *t;
2bd0ea18
NS
1236 int checklen;
1237
9ee7055c 1238 printf(_("End of range ? "));
2bd0ea18
NS
1239 fgets(linebuf, 256, stdin);
1240 j = atoi(linebuf);
1241
9ee7055c 1242 printf(_("checklen 0/1 ? "));
2bd0ea18
NS
1243 fgets(linebuf, 256, stdin);
1244 checklen = atoi(linebuf);
1245
1246
1247 b = avl_findanyrange(&tree, i, j, checklen);
1248 if (b) {
9ee7055c 1249 printf(_("Found something\n"));
2bd0ea18
NS
1250 t = b;
1251 while (t) {
1252 if (t != b &&
1253 AVL_START(&tree, t) >= j)
1254 break;
1255 avl_printnode(&tree, t, 0);
1256 t = t->avl_nextino;
1257 }
1258 printf("\n");
1259 }
1260 }
1261 }
1262 }
1263}
1264#endif
1265
1266/*
dfc130f3 1267 * Given a tree, find value; will find return range enclosing value,
2bd0ea18 1268 * or range immediately succeeding value,
dfc130f3 1269 * or range immediately preceeding value.
2bd0ea18
NS
1270 */
1271avlnode_t *
1272avl_findadjacent(
0c2a7d46 1273 avltree_desc_t *tree,
ee6cd73e 1274 uintptr_t value,
0c2a7d46 1275 int dir)
2bd0ea18 1276{
0c2a7d46 1277 avlnode_t *np = tree->avl_root;
2bd0ea18
NS
1278
1279 while (np) {
1280 if (value < AVL_START(tree, np)) {
1281 if (np->avl_back) {
1282 np = np->avl_back;
1283 continue;
1284 }
1285 /* if we were to add node with value, would
1286 * have a growth of AVL_BACK
1287 */
1288 if (dir == AVL_SUCCEED) {
1289 /* if succeeding node is needed, this is it.
1290 */
1291 return(np);
1292 }
1293 if (dir == AVL_PRECEED) {
1294 /*
1295 * find nearest ancestor with lesser value.
1296 */
1297 np = np->avl_parent;
1298 while (np) {
1299 if (AVL_END(tree, np) <= value)
1300 break;
1301 np = np->avl_parent;
1302 }
1303 return(np);
1304 }
1305 ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED);
1306 break;
1307 }
1308 if (value >= AVL_END(tree, np)) {
1309 if (np->avl_forw) {
1310 np = np->avl_forw;
1311 continue;
1312 }
1313 /* if we were to add node with value, would
dfc130f3 1314 * have a growth of AVL_FORW;
2bd0ea18
NS
1315 */
1316 if (dir == AVL_SUCCEED) {
1317 /* we are looking for a succeeding node;
1318 * this is nextino.
1319 */
1320 return(np->avl_nextino);
1321 }
1322 if (dir == AVL_PRECEED) {
1323 /* looking for a preceeding node; this is it. */
1324 return(np);
dfc130f3 1325 }
2bd0ea18
NS
1326 ASSERT(dir == AVL_SUCCEED || dir == AVL_PRECEED);
1327 }
1328 /* AVL_START(tree, np) <= value < AVL_END(tree, np) */
1329 return(np);
1330 }
1331 return NULL;
1332}
1333
1334
2bd0ea18 1335/*
dfc130f3 1336 * avl_findranges:
2bd0ea18
NS
1337 *
1338 * Given range r [start, end), find all ranges in tree which are contained
1339 * in r. At return, startp and endp point to first and last of
dfc130f3 1340 * a chain of elements which describe the contained ranges. Elements
2bd0ea18
NS
1341 * in startp ... endp are in sort order, and can be accessed by
1342 * using avl_nextino.
1343 */
1344
1345void
1346avl_findranges(
0c2a7d46 1347 avltree_desc_t *tree,
ee6cd73e
CH
1348 uintptr_t start,
1349 uintptr_t end,
dfc130f3 1350 avlnode_t **startp,
2bd0ea18
NS
1351 avlnode_t **endp)
1352{
0c2a7d46 1353 avlnode_t *np;
2bd0ea18
NS
1354
1355 np = avl_findadjacent(tree, start, AVL_SUCCEED);
dfc130f3 1356 if (np == NULL /* nothing succeding start */
2bd0ea18
NS
1357 || (np && (end <= AVL_START(tree, np))))
1358 /* something follows start,
1359 but... is entirely after end */
1360 {
1361 *startp = NULL;
1362 *endp = NULL;
1363 return;
1364 }
1365
1366 *startp = np;
1367
1368 /* see if end is in this region itself */
1369 if (end <= AVL_END(tree, np) ||
1370 np->avl_nextino == NULL ||
1371 (np->avl_nextino &&
1372 (end <= AVL_START(tree, np->avl_nextino)))) {
1373 *endp = np;
1374 return;
1375 }
1376 /* have to munge for end */
1377 /*
1378 * note: have to look for (end - 1), since
1379 * findadjacent will look for exact value, and does not
1380 * care about the fact that end is actually one more
1381 * than the value actually being looked for; thus feed it one less.
1382 */
1383 *endp = avl_findadjacent(tree, (end-1), AVL_PRECEED);
1384 ASSERT(*endp);
1385}