1 #include "asmsupport.h"
3 #include <exec/types.h>
4 #include <proto/exec.h>
6 #include "btreenodes.h"
7 #include "btreenodes_protos.h"
9 #include "adminspaces_protos.h"
10 #include "cachebuffers_protos.h"
12 #include "req_protos.h"
15 extern void setchecksum(struct CacheBuffer
*);
16 extern LONG
readcachebuffercheck(struct CacheBuffer
**,ULONG
,ULONG
);
17 extern void outputcachebuffer(struct CacheBuffer
*cb
);
21 The idea behind a multiway tree is that multiway trees do
22 not require a very good balance to be effective.
26 We store new nodes in a leaf-container which can contain
27 upto x nodes. When the leaf-container is full it is split
28 into two seperate leaf-containers containing x/2 and x/2+1
29 nodes. A node-container is created which keeps track of the
30 two leaf-containers. The new leaf-containers will be split
31 when they are full as well, and so on.
33 At some point the node-container will be full. When this
34 happens we split it in much the same way we split the
35 leaf-containers. In effect this will mean adding a new
38 When deleting a leaf from a leaf-container we will check if
39 the container contains less than x/2 leafs. If this is the
40 case we attempt to merge the leaf-container with the next or
41 previous leaf-container (or both). For this to work the
42 total number of free leafs in the next and previous
43 container must be equal to the number of leafs in the
44 current leaf-container.
50 /* Internal functions */
52 LONG
splitbtreecontainer(BLCK rootblock
,struct CacheBuffer
*cb
);
53 WORD
getbnodeindex(struct BTreeContainer
*btc
);
54 struct BNode
*searchforbnode(ULONG key
,struct BTreeContainer
*btc
);
55 struct BNode
*insertbnode(ULONG key
,struct BTreeContainer
*btc
);
56 void removebnode(ULONG key
,struct BTreeContainer
*btc
);
60 static void __inline
copywordsforward(UWORD
*src
,UWORD
*dst
,UWORD len
) {
66 static void __inline
copywordsbackward(UWORD
*src
,UWORD
*dst
,UWORD len
) {
74 LONG
getparentbtreecontainer(BLCK rootblock
,struct CacheBuffer
**io_cb
) {
75 ULONG childkey
=BE2L(((struct fsBNodeContainer
*)((*io_cb
)->data
))->btc
.bnode
[0].be_key
);
76 BLCK childblock
=(*io_cb
)->blckno
;
79 _XDEBUG((DEBUG_NODES
,"getparentbtreecontainer: Getting parent of block %ld\n",(*io_cb
)->blckno
));
81 /* This function gets the BTreeContainer parent of the passed in CacheBuffer. If
82 there is no parent this function sets io_cb to 0 */
84 if(rootblock
!=childblock
) {
85 while((errorcode
=readcachebuffercheck(io_cb
,rootblock
,BNODECONTAINER_ID
))==0) {
86 struct fsBNodeContainer
*bnc
=(*io_cb
)->data
;
87 struct BTreeContainer
*btc
=&bnc
->btc
;
89 WORD n
=BE2W(btc
->be_nodecount
);
91 if(btc
->isleaf
==TRUE
) {
92 #ifdef CHECKCODE_BNODES
93 dreq("getparentbtreecontainer() couldn't find parent for bnodecontainer at block %ld!\nPlease notify the author!",childblock
);
94 outputcachebuffer(*io_cb
);
95 errorcode
=INTERR_BTREE
;
102 if(BE2L(btc
->bnode
[n
].be_data
)==childblock
) {
103 return(0); /* Found parent!! */
107 bn
=searchforbnode(childkey
,btc
); /* This searchforbnode() doesn't have to get EXACT key matches. */
108 rootblock
=BE2L(bn
->be_data
);
119 LONG
createbnode(BLCK rootblock
,ULONG key
,struct CacheBuffer
**returned_cb
,struct BNode
**returned_bnode
) {
122 _XDEBUG((DEBUG_NODES
,"createbnode: Creating BNode with key %ld, using %ld as root.\n",key
,rootblock
));
124 while((errorcode
=findbnode(rootblock
, key
, returned_cb
, returned_bnode
))==0) {
125 struct fsBNodeContainer
*bnc
=(*returned_cb
)->data
;
126 struct BTreeContainer
*btc
=&bnc
->btc
;
127 LONG extbranches
=(globals
->bytes_block
-sizeof(struct fsBNodeContainer
))/btc
->nodesize
;
129 #ifdef CHECKCODE_BNODES
130 if(*returned_bnode
!=0 && BE2L((*returned_bnode
)->be_key
)==key
) {
131 dreq("createbnode: findbnode() says key %ld already exists!",key
);
132 outputcachebuffer(*returned_cb
);
136 _XDEBUG((DEBUG_NODES
,"createbnode: findbnode found block %ld\n",(*returned_cb
)->blckno
));
138 if(BE2W(btc
->be_nodecount
)<extbranches
) {
139 /* Simply insert new node in this BTreeContainer */
141 _XDEBUG((DEBUG_NODES
,"createbnode: Simple insert\n"));
143 preparecachebuffer(*returned_cb
);
145 *returned_bnode
=insertbnode(key
,btc
);
147 setchecksum(*returned_cb
);
148 // errorcode=storecachebuffer(*returned_cb);
151 else if((errorcode
=splitbtreecontainer(rootblock
,*returned_cb
))!=0) {
155 /* Loop and try insert it the normal way again :-) */
163 LONG
splitbtreecontainer(BLCK rootblock
,struct CacheBuffer
*cb
) {
164 struct CacheBuffer
*cbparent
;
168 _XDEBUG((DEBUG_NODES
,"splitbtreecontainer: splitting block %ld\n",cb
->blckno
));
173 if((errorcode
=getparentbtreecontainer(rootblock
,&cbparent
))==0) {
175 /* We need to create Root tree-container */
177 _XDEBUG((DEBUG_NODES
,"splitbtreecontainer: creating root tree-container\n"));
180 if((errorcode
=allocadminspace(&cb
))==0) {
181 struct fsBNodeContainer
*bnc
=cb
->data
;
182 struct fsBNodeContainer
*bncparent
=cbparent
->data
;
183 struct BTreeContainer
*btcparent
=&bncparent
->btc
;
185 CopyMemQuick(cbparent
->data
,cb
->data
,globals
->bytes_block
);
186 bnc
->bheader
.be_ownblock
=L2BE(cb
->blckno
);
188 _XDEBUG((DEBUG_NODES
,"splitbtreecontainer: allocated admin space for root\n"));
190 lockcachebuffer(cb
); /* Lock cachebuffer which now contains the data previously in root.
191 It must be locked here, otherwise preparecachebuffer below could
194 if((errorcode
=storecachebuffer(cb
))==0) {
195 preparecachebuffer(cbparent
);
196 clearcachebuffer(cbparent
); /* Not strictly needed, but makes things more clear. */
198 bncparent
->bheader
.id
=BNODECONTAINER_ID
;
199 bncparent
->bheader
.be_ownblock
=L2BE(cbparent
->blckno
);
201 btcparent
->isleaf
=FALSE
;
202 btcparent
->nodesize
=sizeof(struct BNode
);
203 btcparent
->be_nodecount
=0;
205 bn
=insertbnode(0,btcparent
);
206 bn
->be_data
=L2BE(cb
->blckno
);
208 errorcode
=storecachebuffer(cbparent
);
211 unlockcachebuffer(cbparent
); /* Unlock cachebuffer which was root, and still is root */
216 struct fsBNodeContainer
*bncparent
=cbparent
->data
;
217 struct BTreeContainer
*btcparent
=&bncparent
->btc
;
218 LONG branches
=(globals
->bytes_block
-sizeof(struct fsBNodeContainer
))/btcparent
->nodesize
;
220 if(BE2W(btcparent
->be_nodecount
)==branches
) {
221 /* We need to split the parent tree-container first! */
223 errorcode
=splitbtreecontainer(rootblock
,cbparent
);
227 if((errorcode
=getparentbtreecontainer(rootblock
,&cbparent
))==0) {
228 /* cbparent might have changed after the split */
229 bncparent
=cbparent
->data
;
230 btcparent
=&bncparent
->btc
;
236 struct CacheBuffer
*cbnew
;
238 /* We can split this container and add it to the parent
239 because the parent has enough room. */
241 lockcachebuffer(cbparent
);
243 if((errorcode
=allocadminspace(&cbnew
))==0) {
244 struct fsBNodeContainer
*bncnew
=cbnew
->data
;
245 struct BTreeContainer
*btcnew
=&bncnew
->btc
;
246 struct fsBNodeContainer
*bnc
=cb
->data
;
247 struct BTreeContainer
*btc
=&bnc
->btc
;
248 LONG branches
=(globals
->bytes_block
-sizeof(struct fsBNodeContainer
))/btc
->nodesize
;
250 ULONG newblckno
=cbnew
->blckno
;
252 bncnew
->bheader
.id
=BNODECONTAINER_ID
;
253 bncnew
->bheader
.be_ownblock
=L2BE(cbnew
->blckno
);
255 btcnew
->isleaf
=btc
->isleaf
;
256 btcnew
->nodesize
=btc
->nodesize
;
258 btcnew
->be_nodecount
=W2BE(branches
-branches
/2);
260 copywordsforward((UWORD
*)((UBYTE
*)btc
->bnode
+branches
/2*btc
->nodesize
),(UWORD
*)btcnew
->bnode
,(branches
-branches
/2)*btc
->nodesize
/2);
262 newkey
=BE2L(btcnew
->bnode
[0].be_key
);
264 if((errorcode
=storecachebuffer(cbnew
))==0) {
266 preparecachebuffer(cb
);
268 btc
->be_nodecount
=W2BE(branches
/2);
270 if((errorcode
=storecachebuffer(cb
))==0) {
271 preparecachebuffer(cbparent
);
273 bn
=insertbnode(newkey
,btcparent
);
274 bn
->be_data
=L2BE(newblckno
);
276 errorcode
=storecachebuffer(cbparent
);
281 unlockcachebuffer(cbparent
);
286 unlockcachebuffer(cb
);
293 LONG
findbnode(BLCK rootblock
, ULONG key
, struct CacheBuffer
**returned_cb
, struct BNode
**returned_bnode
) {
296 /* This function finds the BNode with the given key. If no exact match can be
297 found then this function will return either the next or previous closest
298 match (don't rely on this).
300 If there were no BNode's at all, then *returned_cb will be the Rootblock
301 and *returned_bnode will be zero.
303 Any error will be returned. If non-zero then don't rely on the contents
304 of *returned_cb and *returned_bnode. */
306 _XDEBUG((DEBUG_NODES
,"findbnode: Looking for BNode with key %ld, from root %ld\n",key
,rootblock
));
308 while((errorcode
=readcachebuffercheck(returned_cb
, rootblock
, BNODECONTAINER_ID
))==0) {
309 struct fsBNodeContainer
*bnc
=(*returned_cb
)->data
;
310 struct BTreeContainer
*btc
=&bnc
->btc
;
312 if(BE2W(btc
->be_nodecount
)==0) {
317 *returned_bnode
=searchforbnode(key
, btc
);
318 if(btc
->isleaf
==TRUE
) {
321 rootblock
=BE2L((*returned_bnode
)->be_data
);
324 _XDEBUG((DEBUG_NODES
,"findbnode: *returned_cb->blckno = %ld, Exiting with errorcode %ld\n",(*returned_cb
)->blckno
,errorcode
));
331 struct BNode
*searchforbnode(ULONG key
, struct BTreeContainer
*tc
) {
333 WORD n
=BE2W(tc
->be_nodecount
)-1;
335 /* This function looks for the BNode equal to the key. If no
336 exact match is available then the BNode which is slightly
337 lower than key will be returned. If no such BNode exists
338 either, then the first BNode in this block is returned.
340 This function will return the first BNode even if there
341 are no BNode's at all in this block (this can only happen
342 for the Root of the tree). Be sure to check if the Root
343 is not empty before calling this function. */
345 tn
=(struct BNode
*)((UBYTE
*)tc
->bnode
+n
*tc
->nodesize
);
348 if(n
<=0 || key
>= BE2L(tn
->be_key
)) {
351 tn
=(struct BNode
*)((UBYTE
*)tn
-tc
->nodesize
);
358 struct BNode
*insertbnode(ULONG key
,struct BTreeContainer
*btc
) {
359 struct BNode
*bn
=btc
->bnode
;
363 bn
=(struct BNode
*)((UBYTE
*)bn
+btc
->nodesize
*(BE2W(btc
->be_nodecount
)-1));
365 src
=(UWORD
*)((UBYTE
*)bn
+btc
->nodesize
);
366 dst
=src
+btc
->nodesize
/2;
368 /* This routine inserts a node sorted into a BTreeContainer. It does
369 this by starting at the end, and moving the nodes one by one to
370 a higher slot until the empty slot has the correct position for
371 this key. Donot use this function on completely filled
375 if(bn
<btc
->bnode
|| key
> BE2L(bn
->be_key
)) {
376 bn
=(struct BNode
*)((UBYTE
*)bn
+btc
->nodesize
);
377 bn
->be_key
=L2BE(key
);
378 btc
->be_nodecount
= W2BE(BE2W(btc
->be_nodecount
)+1);
382 WORD l
=btc
->nodesize
/2;
389 bn
=(struct BNode
*)((UBYTE
*)bn
-btc
->nodesize
);
397 LONG
deleteinternalnode(BLCK rootblock
,struct CacheBuffer
*cb
,ULONG key
) {
398 struct fsBNodeContainer
*bnc
=cb
->data
;
399 struct BTreeContainer
*btc
=&bnc
->btc
;
400 UWORD branches
=(globals
->bytes_block
-sizeof(struct fsBNodeContainer
))/btc
->nodesize
;
403 /* Deletes specified internal node. */
405 preparecachebuffer(cb
);
407 removebnode(key
,btc
);
409 if((errorcode
=storecachebuffer(cb
))==0) {
411 /* Now checks if the container still contains enough nodes,
412 and takes action accordingly. */
414 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: branches = %ld, btc->nodecount = %ld\n",branches
,BE2W(btc
->be_nodecount
)));
416 if(BE2W(btc
->be_nodecount
)<(branches
+1)/2) {
417 struct CacheBuffer
*cbparent
=cb
;
419 /* nodecount has become to low. We need to merge this Container
420 with a neighbouring Container, or we need to steal a few nodes
421 from a neighbouring Container. */
425 /* We get the parent of the container here, so we can find out what
426 containers neighbour the container which currently hasn't got enough nodes. */
428 if((errorcode
=getparentbtreecontainer(rootblock
,&cbparent
))==0) {
430 struct fsBNodeContainer
*bncparent
=cbparent
->data
;
431 struct BTreeContainer
*btcparent
=&bncparent
->btc
;
434 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: get parent returned block %ld.\n",cbparent
->blckno
));
436 for(n
=0; n
<BE2W(btcparent
->be_nodecount
); n
++) {
437 if(BE2L(btcparent
->bnode
[n
].be_data
)==cb
->blckno
) {
442 /* n is now the offset of our own bnode. */
444 lockcachebuffer(cbparent
);
446 if(n
<BE2W(btcparent
->be_nodecount
)-1) { // Check if we have a next neighbour.
447 struct CacheBuffer
*cb_next
;
449 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: using next container.\n"));
451 if((errorcode
=readcachebuffercheck(&cb_next
,BE2L(btcparent
->bnode
[n
+1].be_data
),BNODECONTAINER_ID
))==0) {
452 struct fsBNodeContainer
*bnc_next
=cb_next
->data
;
453 struct BTreeContainer
*btc_next
=&bnc_next
->btc
;
455 lockcachebuffer(cb_next
);
457 if(BE2W(btc_next
->be_nodecount
)+BE2W(btc
->be_nodecount
)>branches
) { // Check if we need to steal nodes.
458 WORD nodestosteal
=(BE2W(btc_next
->be_nodecount
)+BE2W(btc
->be_nodecount
))/2-BE2W(btc
->be_nodecount
);
460 /* Merging them is not possible. Steal a few nodes then. */
462 preparecachebuffer(cb
);
464 copywordsforward((UWORD
*)btc_next
->bnode
,(UWORD
*)((UBYTE
*)btc
->bnode
+BE2W(btc
->be_nodecount
)*btc
->nodesize
),nodestosteal
*btc
->nodesize
/2);
465 btc
->be_nodecount
=W2BE(BE2W(btc
->be_nodecount
)+nodestosteal
);
467 if((errorcode
=storecachebuffer(cb
))==0) {
468 preparecachebuffer(cb_next
);
470 copywordsforward((UWORD
*)((UBYTE
*)btc_next
->bnode
+btc_next
->nodesize
*nodestosteal
),(UWORD
*)btc_next
->bnode
,(btc
->nodesize
/2)*(BE2W(btc_next
->be_nodecount
) - nodestosteal
));
471 btc_next
->be_nodecount
=W2BE(BE2W(btc_next
->be_nodecount
)-nodestosteal
);
473 if((errorcode
=storecachebuffer(cb_next
))==0) {
474 preparecachebuffer(cbparent
);
476 btcparent
->bnode
[n
+1].be_key
=btc_next
->bnode
[0].be_key
; // BE->BE Copy!
478 errorcode
=storecachebuffer(cbparent
);
482 else { // Merging is possible.
483 preparecachebuffer(cb
);
485 copywordsforward((UWORD
*)btc_next
->bnode
,(UWORD
*)((UBYTE
*)btc
->bnode
+btc
->nodesize
*BE2W(btc
->be_nodecount
)),btc
->nodesize
*BE2W(btc_next
->be_nodecount
)/2);
486 btc
->be_nodecount
=W2BE(BE2W(btc
->be_nodecount
)+BE2W(btc_next
->be_nodecount
));
488 if((errorcode
=storecachebuffer(cb
))==0) {
489 if((errorcode
=freeadminspace(cb_next
->blckno
))==0) {
490 errorcode
=deleteinternalnode(rootblock
,cbparent
,BE2L(btcparent
->bnode
[n
+1].be_key
));
495 unlockcachebuffer(cb_next
);
498 else if(n
>0) { // Check if we have a previous neighbour.
499 struct CacheBuffer
*cb2
;
501 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: using prev container.\n"));
503 if((errorcode
=readcachebuffercheck(&cb2
,BE2L(btcparent
->bnode
[n
-1].be_data
),BNODECONTAINER_ID
))==0) {
504 struct fsBNodeContainer
*bnc2
=cb2
->data
;
505 struct BTreeContainer
*btc2
=&bnc2
->btc
;
507 lockcachebuffer(cb2
);
509 if(BE2W(btc2
->be_nodecount
)+BE2W(btc
->be_nodecount
)>branches
) {
510 WORD nodestosteal
=(BE2W(btc2
->be_nodecount
)+BE2W(btc
->be_nodecount
))/2-BE2W(btc
->be_nodecount
);
512 /* Merging them is not possible. Steal a few nodes then. */
514 preparecachebuffer(cb
);
516 copywordsbackward((UWORD
*)((UBYTE
*)btc
->bnode
+BE2W(btc
->be_nodecount
)*btc
->nodesize
),(UWORD
*)((UBYTE
*)btc
->bnode
+(BE2W(btc
->be_nodecount
)+nodestosteal
)*btc
->nodesize
),BE2W(btc
->be_nodecount
)*btc
->nodesize
/2);
517 btc
->be_nodecount
=W2BE(BE2W(btc
->be_nodecount
)+nodestosteal
);
518 copywordsforward((UWORD
*)((UBYTE
*)btc2
->bnode
+(BE2W(btc2
->be_nodecount
)-nodestosteal
)*btc2
->nodesize
),(UWORD
*)btc
->bnode
,nodestosteal
*btc
->nodesize
/2);
520 if((errorcode
=storecachebuffer(cb
))==0) {
522 preparecachebuffer(cb2
);
524 btc2
->be_nodecount
=W2BE(BE2W(btc2
->be_nodecount
)-nodestosteal
);
526 if((errorcode
=storecachebuffer(cb2
))==0) {
527 preparecachebuffer(cbparent
);
529 btcparent
->bnode
[n
].be_key
=btc
->bnode
[0].be_key
; // BE->BE copy!
531 errorcode
=storecachebuffer(cbparent
);
536 preparecachebuffer(cb2
);
538 copywordsforward((UWORD
*)btc
->bnode
,(UWORD
*)((UBYTE
*)btc2
->bnode
+BE2W(btc2
->be_nodecount
)*btc2
->nodesize
),BE2W(btc
->be_nodecount
)*btc
->nodesize
/2);
539 btc2
->be_nodecount
=W2BE(BE2W(btc2
->be_nodecount
)+BE2W(btc
->be_nodecount
));
541 if((errorcode
=storecachebuffer(cb2
))==0) {
542 if((errorcode
=freeadminspace(cb
->blckno
))==0) {
543 errorcode
=deleteinternalnode(rootblock
,cbparent
,BE2L(btcparent
->bnode
[n
].be_key
));
548 unlockcachebuffer(cb2
);
553 // Never happens, except for root and then we don't care.
557 unlockcachebuffer(cbparent
);
560 else if(BE2W(btc
->be_nodecount
)==1) {
561 /* No parent, so must be root. */
563 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: no parent so must be root\n"));
565 if(btc
->isleaf
==FALSE
) {
566 struct CacheBuffer
*cb2
;
567 struct fsBNodeContainer
*bnc
=cb
->data
;
569 /* The current root has only 1 node. We now copy the data of this node into the
570 root and promote that data to be the new root. The rootblock number stays the
573 preparecachebuffer(cb
);
575 if((errorcode
=readcachebuffercheck(&cb2
,BE2L(btc
->bnode
[0].be_data
),BNODECONTAINER_ID
))==0) {
577 CopyMemQuick(cb2
->data
,cb
->data
,globals
->bytes_block
);
578 bnc
->bheader
.be_ownblock
=L2BE(cb
->blckno
);
580 if((errorcode
=storecachebuffer(cb
))==0) {
581 errorcode
=freeadminspace(cb2
->blckno
);
588 /* If not, then root contains leafs. */
591 _XDEBUG((DEBUG_NODES
,"deleteinternalnode: almost done\n"));
593 /* otherwise, it must be the root, and the root is allowed
594 to contain less than the minimum amount of nodes. */
598 unlockcachebuffer(cb
);
607 LONG
deletebnode(BLCK rootblock
,ULONG key
) {
608 struct CacheBuffer
*cb
;
612 if((errorcode
=findbnode(rootblock
,key
,&cb
,&bn
))==0) {
613 #ifdef CHECKCODE_BNODES
614 if(bn
==0 || BE2L(bn
->be_key
)!=key
) {
615 dreq("deletebnode: key %ld doesn't exist!",key
);
616 outputcachebuffer(cb
);
617 return(INTERR_BTREE
);
621 _XDEBUG((DEBUG_NODES
,"deletebnode: key %ld\n",key
));
623 errorcode
=deleteinternalnode(rootblock
,cb
,key
);
631 void removebnode(ULONG key
,struct BTreeContainer
*btc
) {
632 struct BNode
*bn
=btc
->bnode
;
635 _XDEBUG((DEBUG_NODES
,"removebnode: key %ld\n",key
));
637 /* This routine removes a node from a BTreeContainer indentified
638 by its key. If no such key exists this routine does nothing.
639 It correctly handles empty BTreeContainers. */
641 while(n
<BE2W(btc
->be_nodecount
)) {
642 if(BE2L(bn
->be_key
) == key
) {
643 btc
->be_nodecount
= W2BE(BE2W(btc
->be_nodecount
)-1);
645 copywordsforward((UWORD
*)((UBYTE
*)bn
+btc
->nodesize
),(UWORD
*)bn
,(BE2W(btc
->be_nodecount
)-n
)*btc
->nodesize
/2);
648 bn
=(struct BNode
*)((UBYTE
*)bn
+btc
->nodesize
);
655 struct BNode
*next(struct BTreeContainer
*tc
, struct BNode
*tn
) {
656 if((UBYTE
*)tn
== (UBYTE
*)tc
->bnode
+ (BE2W(tc
->be_nodecount
)-1)*tc
->nodesize
) {
660 return((struct BNode
*)((UBYTE
*)tn
+tc
->nodesize
));
666 struct BNode
*previous(struct BTreeContainer
*tc
, struct BNode
*tn
) {
671 return((struct BNode
*)((UBYTE
*)tn
-tc
->nodesize
));
677 LONG
nextbnode(BLCK rootblock
, struct CacheBuffer
**io_cb
, struct BNode
**io_bnode
) {
679 ULONG key
=BE2L((*io_bnode
)->be_key
);
680 BLCK blockwithnext
=0;
683 /* This function locates the next BNode in the tree. If there is no next
684 BNode then this function will return no error and zero *io_bnode. */
686 while((errorcode
=readcachebuffercheck(io_cb
, rootblock
, BNODECONTAINER_ID
))==0) {
687 struct fsBNodeContainer
*bnc
=(*io_cb
)->data
;
688 struct BTreeContainer
*btc
=&bnc
->btc
;
690 bn
=searchforbnode(key
, btc
);
692 if((*io_bnode
=next(btc
, bn
))!=0) {
693 blockwithnext
=BE2L((*io_bnode
)->be_data
);
696 if(btc
->isleaf
==TRUE
) {
697 /* Traversed the tree to the end. */
699 if(*io_bnode
!=0 || blockwithnext
==0) { // Checks if next is in this block, or no next was found ever.
703 errorcode
=findbnode(blockwithnext
, key
, io_cb
, io_bnode
);
707 rootblock
=BE2L(bn
->be_data
);
715 LONG
previousbnode(BLCK rootblock
, struct CacheBuffer
**io_cb
, struct BNode
**io_bnode
) {
718 /* This function locates the previous BNode in the tree. If there is no previous
719 BNode then this function will return no error and zero *io_bnode.
721 This function will not walk the tree again if the Previous BNode is in the same
722 block as the current one. */
724 if((bn
=previous(&((struct fsBNodeContainer
*)((*io_cb
)->data
))->btc
, *io_bnode
))!=0) { // Quick check if there is a direct Previous available.
729 ULONG key
=BE2L((*io_bnode
)->be_key
);
730 BLCK blockwithprevious
=0;
733 /* No direct previous was available, so we walk the tree: */
735 while((errorcode
=readcachebuffercheck(io_cb
, rootblock
, BNODECONTAINER_ID
))==0) {
736 struct fsBNodeContainer
*bnc
=(*io_cb
)->data
;
737 struct BTreeContainer
*btc
=&bnc
->btc
;
739 bn
=searchforbnode(key
, btc
);
741 if((*io_bnode
=previous(btc
, bn
))!=0) {
742 blockwithprevious
=BE2L((*io_bnode
)->be_data
);
745 if(btc
->isleaf
==TRUE
) {
746 /* Traversed the tree to the end. */
748 if(*io_bnode
!=0 || blockwithprevious
==0) { // Checks if previous is in this block, or no previous was found ever.
752 errorcode
=findbnode(blockwithprevious
, key
, io_cb
, io_bnode
);
756 rootblock
=BE2L(bn
->be_data
);
765 LONG
lastbnode(BLCK rootblock
, struct CacheBuffer
**returned_cb
, struct BNode
**returned_bnode
) {
766 return(findbnode(rootblock
, 0xFFFFFFFF, returned_cb
, returned_bnode
));