revert between 56095 -> 55830 in arch
[AROS.git] / rom / filesys / SFS / FS / btreenodes.c
blob515ff9ae71e41b1f6fa0cb85921367ad793ce2eb
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"
11 #include "debug.h"
12 #include "req_protos.h"
13 #include "globals.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.
24 x-Way trees
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
36 level to the tree.
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) {
61 while(len-->0) {
62 *dst++=*src++;
66 static void __inline copywordsbackward(UWORD *src,UWORD *dst,UWORD len) {
67 while(len-->0) {
68 *--dst=*--src;
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;
77 LONG errorcode=0;
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;
88 struct BNode *bn;
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;
96 #endif
98 break;
101 while(n-->0) {
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);
112 *io_cb=0;
114 return(errorcode);
119 LONG createbnode(BLCK rootblock,ULONG key,struct CacheBuffer **returned_cb,struct BNode **returned_bnode) {
120 LONG errorcode;
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);
134 #endif
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);
149 break;
151 else if((errorcode=splitbtreecontainer(rootblock,*returned_cb))!=0) {
152 break;
155 /* Loop and try insert it the normal way again :-) */
158 return(errorcode);
163 LONG splitbtreecontainer(BLCK rootblock,struct CacheBuffer *cb) {
164 struct CacheBuffer *cbparent;
165 struct BNode *bn;
166 LONG errorcode;
168 _XDEBUG((DEBUG_NODES,"splitbtreecontainer: splitting block %ld\n",cb->blckno));
170 lockcachebuffer(cb);
172 cbparent=cb;
173 if((errorcode=getparentbtreecontainer(rootblock,&cbparent))==0) {
174 if(cbparent==0) {
175 /* We need to create Root tree-container */
177 _XDEBUG((DEBUG_NODES,"splitbtreecontainer: creating root tree-container\n"));
179 cbparent=cb;
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
192 kill it. */
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 */
215 if(errorcode==0) {
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);
225 if(errorcode==0) {
226 cbparent=cb;
227 if((errorcode=getparentbtreecontainer(rootblock,&cbparent))==0) {
228 /* cbparent might have changed after the split */
229 bncparent=cbparent->data;
230 btcparent=&bncparent->btc;
235 if(errorcode==0) {
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;
249 ULONG newkey;
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);
288 return(errorcode);
293 LONG findbnode(BLCK rootblock, ULONG key, struct CacheBuffer **returned_cb, struct BNode **returned_bnode) {
294 LONG errorcode;
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) {
313 *returned_bnode=0;
314 break;
317 *returned_bnode=searchforbnode(key, btc);
318 if(btc->isleaf==TRUE) {
319 break;
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));
326 return(errorcode);
331 struct BNode *searchforbnode(ULONG key, struct BTreeContainer *tc) {
332 struct BNode *tn;
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);
347 for(;;) {
348 if(n<=0 || key >= BE2L(tn->be_key)) {
349 return(tn);
351 tn=(struct BNode *)((UBYTE *)tn-tc->nodesize);
352 n--;
358 struct BNode *insertbnode(ULONG key,struct BTreeContainer *btc) {
359 struct BNode *bn=btc->bnode;
360 UWORD *src;
361 UWORD *dst;
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
372 BTreeContainers! */
374 for(;;) {
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);
379 break;
381 else {
382 WORD l=btc->nodesize/2;
384 while(l-->0) {
385 *--dst=*--src;
389 bn=(struct BNode *)((UBYTE *)bn-btc->nodesize);
392 return(bn);
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;
401 LONG errorcode;
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. */
423 lockcachebuffer(cb);
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) {
429 if(cbparent!=0) {
430 struct fsBNodeContainer *bncparent=cbparent->data;
431 struct BTreeContainer *btcparent=&bncparent->btc;
432 WORD n;
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) {
438 break;
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);
535 else {
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);
552 else {
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
571 same that way. */
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);
584 else {
585 dumpcachebuffer(cb);
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);
602 return(errorcode);
607 LONG deletebnode(BLCK rootblock,ULONG key) {
608 struct CacheBuffer *cb;
609 struct BNode *bn;
610 LONG errorcode;
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);
619 #endif
621 _XDEBUG((DEBUG_NODES,"deletebnode: key %ld\n",key));
623 errorcode=deleteinternalnode(rootblock,cb,key);
626 return(errorcode);
631 void removebnode(ULONG key,struct BTreeContainer *btc) {
632 struct BNode *bn=btc->bnode;
633 WORD n=0;
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);
646 break;
648 bn=(struct BNode *)((UBYTE *)bn+btc->nodesize);
649 n++;
655 struct BNode *next(struct BTreeContainer *tc, struct BNode *tn) {
656 if((UBYTE *)tn == (UBYTE *)tc->bnode + (BE2W(tc->be_nodecount)-1)*tc->nodesize) {
657 return(0);
659 else {
660 return((struct BNode *)((UBYTE *)tn+tc->nodesize));
666 struct BNode *previous(struct BTreeContainer *tc, struct BNode *tn) {
667 if(tn==tc->bnode) {
668 return(0);
670 else {
671 return((struct BNode *)((UBYTE *)tn-tc->nodesize));
677 LONG nextbnode(BLCK rootblock, struct CacheBuffer **io_cb, struct BNode **io_bnode) {
678 struct BNode *bn;
679 ULONG key=BE2L((*io_bnode)->be_key);
680 BLCK blockwithnext=0;
681 LONG errorcode;
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.
700 break;
703 errorcode=findbnode(blockwithnext, key, io_cb, io_bnode);
704 break;
707 rootblock=BE2L(bn->be_data);
710 return(errorcode);
715 LONG previousbnode(BLCK rootblock, struct CacheBuffer **io_cb, struct BNode **io_bnode) {
716 struct BNode *bn;
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.
725 *io_bnode=bn;
726 return(0);
728 else {
729 ULONG key=BE2L((*io_bnode)->be_key);
730 BLCK blockwithprevious=0;
731 LONG errorcode;
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.
749 break;
752 errorcode=findbnode(blockwithprevious, key, io_cb, io_bnode);
753 break;
756 rootblock=BE2L(bn->be_data);
759 return(errorcode);
765 LONG lastbnode(BLCK rootblock, struct CacheBuffer **returned_cb, struct BNode **returned_bnode) {
766 return(findbnode(rootblock, 0xFFFFFFFF, returned_cb, returned_bnode));