KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > db4o > inside > btree > BTreeNode


1 /* Copyright (C) 2004 - 2006 db4objects Inc. http://www.db4o.com
2
3 This file is part of the db4o open source object database.
4
5 db4o is free software; you can redistribute it and/or modify it under
6 the terms of version 2 of the GNU General Public License as published
7 by the Free Software Foundation and as clarified by db4objects' GPL
8 interpretation policy, available at
9 http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
10 Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
11 Suite 350, San Mateo, CA 94403, USA.
12
13 db4o is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */

21 package com.db4o.inside.btree;
22
23 import com.db4o.*;
24 import com.db4o.foundation.*;
25 import com.db4o.inside.ix.*;
26
27 /**
28  * We work with BTreeNode in two states:
29  *
30  * - deactivated: never read, no valid members, ID correct or 0 if new
31  * - write: real representation of keys, values and children in arrays
32  * The write state can be detected with canWrite(). States can be changed
33  * as needed with prepareRead() and prepareWrite().
34  *
35  * @exclude
36  */

37 public final class BTreeNode extends YapMeta{
38     
39     private static final int COUNT_LEAF_AND_3_LINK_LENGTH = (YapConst.INT_LENGTH * 4) + 1;
40  
41     private static final int SLOT_LEADING_LENGTH = YapConst.LEADING_LENGTH + COUNT_LEAF_AND_3_LINK_LENGTH;
42     
43    
44     final BTree _btree;
45     
46     
47     private int _count;
48     
49     private boolean _isLeaf;
50     
51     
52     private Object JavaDoc[] _keys;
53     
54     /**
55      * Can contain BTreeNode or Integer for ID of BTreeNode
56      */

57     private Object JavaDoc[] _children;
58     
59     /**
60      * Only used for leafs
61      */

62     private Object JavaDoc[] _values;
63     
64     
65     private int _parentID;
66     
67     private int _previousID;
68     
69     private int _nextID;
70     
71     private boolean _cached;
72     
73     private boolean _dead;
74     
75     
76     
77     /* Constructor for new nodes */
78     public BTreeNode(BTree btree,
79                      int count,
80                      boolean isLeaf,
81                      int parentID,
82                      int previousID,
83                      int nextID){
84         _btree = btree;
85         _parentID = parentID;
86         _previousID = previousID;
87         _nextID = nextID;
88         _count = count;
89         _isLeaf = isLeaf;
90         prepareArrays();
91         setStateDirty();
92     }
93     
94     /* Constructor for existing nodes, requires valid ID */
95     public BTreeNode(int id, BTree btree){
96         _btree = btree;
97         setID(id);
98         setStateDeactivated();
99     }
100     
101     /* Constructor to create a new root from two nodes */
102     public BTreeNode(Transaction trans, BTreeNode firstChild, BTreeNode secondChild){
103         this(firstChild._btree, 2, false, 0, 0, 0);
104         _keys[0] = firstChild._keys[0];
105         _children[0] = firstChild;
106         _keys[1] = secondChild._keys[0];
107         _children[1] = secondChild;
108         
109         write(trans.systemTransaction());
110         
111         firstChild.setParentID(trans, getID());
112         secondChild.setParentID(trans, getID());
113     }
114     
115     public BTree btree() {
116         return _btree;
117     }
118     
119     /**
120      * @return the split node if this node is split
121      * or this if the first key has changed
122      */

123     public BTreeNode add(Transaction trans){
124         
125         YapReader reader = prepareRead(trans);
126         
127         Searcher s = search(reader);
128         
129         if(_isLeaf){
130             
131             prepareWrite(trans);
132             
133             if (wasRemoved(trans, s)) {
134                 cancelRemoval(trans, s.cursor());
135                 return null;
136             }
137             
138             if(s.count() > 0 && ! s.beforeFirst()){
139                 s.moveForward();
140             }
141             
142             prepareInsert(s.cursor());
143             _keys[s.cursor()] = newAddPatch(trans);
144             if(handlesValues()){
145                 _values[s.cursor()] = valueHandler().current();
146             }
147             
148         }else{
149             
150             BTreeNode childNode = child(reader, s.cursor());
151             BTreeNode childNodeOrSplit = childNode.add(trans);
152             if(childNodeOrSplit == null){
153                 return null;
154             }
155             prepareWrite(trans);
156             _keys[s.cursor()] = childNode._keys[0];
157             if(childNode != childNodeOrSplit){
158                 int splitCursor = s.cursor() + 1;
159                 prepareInsert(splitCursor);
160                 _keys[splitCursor] = childNodeOrSplit._keys[0];
161                 _children[splitCursor] = childNodeOrSplit;
162             }
163         }
164         
165         if(_count >= _btree.nodeSize()){
166             return split(trans);
167         }
168         
169         if(s.cursor() == 0){
170             return this;
171         }
172         
173         return null;
174     }
175
176     private BTreeAdd newAddPatch(Transaction trans) {
177         sizeIncrement(trans);
178         return new BTreeAdd(trans, currentKey());
179     }
180
181     private Object JavaDoc currentKey() {
182         return keyHandler().current();
183     }
184
185     private void cancelRemoval(Transaction trans, int index) {
186         final BTreeUpdate patch = (BTreeUpdate)keyPatch(index);
187         BTreeUpdate nextPatch = patch.removeFor(trans);
188         _keys[index] = newCancelledRemoval(trans, patch.getObject(), nextPatch);
189         sizeIncrement(trans);
190     }
191
192     private BTreePatch newCancelledRemoval(Transaction trans, Object JavaDoc originalObject, BTreeUpdate existingPatches) {
193         return new BTreeCancelledRemoval(trans, originalObject, currentKey(), existingPatches);
194     }
195
196     private void sizeIncrement(Transaction trans) {
197         _btree.sizeChanged(trans, 1);
198     }
199
200     private boolean wasRemoved(Transaction trans, Searcher s) {
201         if (!s.foundMatch()) {
202             return false;
203         }
204         BTreePatch patch = keyPatch(trans, s.cursor());
205         return patch != null && patch.isRemove();
206     }
207     
208     BTreeNodeSearchResult searchLeaf(Transaction trans, SearchTarget target) {
209         YapReader reader = prepareRead(trans);
210         Searcher s = search(reader, target);
211         if(! _isLeaf){
212             return child(reader, s.cursor()).searchLeaf(trans, target);
213         }
214             
215         if(! s.foundMatch() || target == SearchTarget.ANY || target == SearchTarget.HIGHEST){
216             return new BTreeNodeSearchResult(trans, reader, btree(), s, this);
217         }
218         
219         if(target == SearchTarget.LOWEST){
220             BTreeNodeSearchResult res = findLowestLeafMatch(trans, s.cursor() - 1);
221             if(res != null){
222                 return res;
223             }
224             return createMatchingSearchResult(trans, reader, s.cursor());
225         }
226         
227         throw new IllegalStateException JavaDoc();
228         
229     }
230
231     private BTreeNodeSearchResult findLowestLeafMatch(Transaction trans, int index){
232         return findLowestLeafMatch(trans, prepareRead(trans), index);
233     }
234     
235     private BTreeNodeSearchResult findLowestLeafMatch(Transaction trans, YapReader reader, int index){
236         
237         if(index >= 0){
238             if(!compareEquals(reader, index)){
239                 return null;
240             }
241             if(index > 0){
242                 BTreeNodeSearchResult res = findLowestLeafMatch(trans, reader, index - 1);
243                 if(res != null){
244                     return res;
245                 }
246                 return createMatchingSearchResult(trans, reader, index);
247             }
248         }
249         
250         final BTreeNode node = previousNode();
251         if(node != null){
252             final YapReader nodeReader = node.prepareRead(trans);
253             BTreeNodeSearchResult res = node.findLowestLeafMatch(trans, nodeReader, node.lastIndex());
254             if(res != null){
255                 return res;
256             }
257         }
258         
259         if(index < 0){
260             return null;
261         }
262         
263         return createMatchingSearchResult(trans, reader, index);
264     }
265
266     private boolean compareEquals(final YapReader reader, int index) {
267         if(canWrite()){
268             return compareInWriteMode(index) == 0;
269         }
270         return compareInReadMode(reader, index) == 0;
271     }
272
273     private BTreeNodeSearchResult createMatchingSearchResult(Transaction trans, YapReader reader, int index) {
274         return new BTreeNodeSearchResult(trans, reader, btree(), this, index, true);
275     }
276     
277     public boolean canWrite(){
278         return _keys != null;
279     }
280     
281     BTreeNode child(int index){
282         if (_children[index] instanceof BTreeNode){
283             return (BTreeNode)_children[index];
284         }
285         return _btree.produceNode(((Integer JavaDoc)_children[index]).intValue());
286     }
287     
288     BTreeNode child(YapReader reader, int index){
289         if( childLoaded(index) ){
290             return (BTreeNode)_children[index];
291         }
292         BTreeNode child = _btree.produceNode(childID(reader, index));
293
294         if(_children != null){
295             if(_cached || child.canWrite()){
296                 _children[index] = child;
297             }
298         }
299         
300         return child;
301     }
302     
303     private int childID(YapReader reader, int index){
304         if(_children == null){
305             seekChild(reader, index);
306             return reader.readInt();
307         }
308         return childID(index);
309     }
310     
311     private int childID(int index){
312         if(childLoaded(index)){
313             return ((BTreeNode)_children[index]).getID();
314         }
315         return ((Integer JavaDoc)_children[index]).intValue();
316     }
317     
318     private boolean childLoaded(int index){
319         if(_children == null){
320             return false;
321         }
322         return _children[index] instanceof BTreeNode;
323     }
324     
325     private boolean childCanSupplyFirstKey(int index){
326         if(! childLoaded(index)){
327             return false;
328         }
329         return ((BTreeNode)_children[index]).canWrite();
330     }
331     
332     void commit(Transaction trans){
333         commitOrRollback(trans, true);
334     }
335     
336     void commitOrRollback(Transaction trans, boolean isCommit){
337         
338         if(DTrace.enabled){
339             DTrace.BTREE_NODE_COMMIT_OR_ROLLBACK.log(getID());
340         }
341         
342         if(_dead){
343             return;
344         }
345         
346         _cached = false;
347         
348         if(! _isLeaf){
349             return;
350         }
351         
352         if(! isDirty(trans)){
353             return;
354         }
355         
356         Object JavaDoc keyZero = _keys[0];
357         
358         boolean vals = handlesValues();
359         
360         Object JavaDoc[] tempKeys = new Object JavaDoc[_btree.nodeSize()];
361         Object JavaDoc[] tempValues = vals ? new Object JavaDoc[_btree.nodeSize()] : null;
362         
363         int count = 0;
364     
365         for (int i = 0; i < _count; i++) {
366             Object JavaDoc key = _keys[i];
367             BTreePatch patch = keyPatch(i);
368             if(patch != null){
369                 key = isCommit ? patch.commit(trans, _btree) : patch.rollback(trans, _btree);
370             }
371             if(key != No4.INSTANCE){
372                 tempKeys[count] = key;
373                 if(vals){
374                     tempValues[count] = _values[i];
375                 }
376                 count ++;
377             }
378         }
379         
380         _keys = tempKeys;
381         _values = tempValues;
382         
383         _count = count;
384         
385         if(freeIfEmpty(trans)){
386             return;
387         }
388         
389         // TODO: Merge nodes here on low _count value.
390

391         if(_keys[0] != keyZero){
392             tellParentAboutChangedKey(trans);
393         }
394         
395     }
396     
397     private boolean freeIfEmpty(Transaction trans){
398         return freeIfEmpty(trans, _count);
399     }
400     
401     private boolean freeIfEmpty(Transaction trans, int count){
402         if(count > 0){
403             return false;
404         }
405         if(isRoot()){
406             return false;
407         }
408         free(trans);
409         return true;
410     }
411
412     private boolean isRoot() {
413         return _btree.root() == this;
414     }
415     
416     public boolean equals(Object JavaDoc obj) {
417         if (this == obj){
418             return true;
419         }
420         if(! (obj instanceof BTreeNode)){
421             return false;
422         }
423         BTreeNode other = (BTreeNode) obj;
424         return getID() == other.getID();
425     }
426     
427     private void free(Transaction trans){
428         _dead = true;
429         if(! isRoot()){
430             BTreeNode parent = _btree.produceNode(_parentID);
431             parent.removeChild(trans, this);
432         }
433         pointPreviousTo(trans, _nextID);
434         pointNextTo(trans, _previousID);
435         trans.systemTransaction().slotFreePointerOnCommit(getID());
436         _btree.removeNode(this);
437     }
438     
439     void holdChildrenAsIDs(){
440         if(_children == null){
441             return;
442         }
443         for (int i = 0; i < _count; i++) {
444             if(_children[i] instanceof BTreeNode){
445                 _children[i] = new Integer JavaDoc( ((BTreeNode)_children[i]).getID() );
446             }
447         }
448     }
449     
450     private void removeChild(Transaction trans, BTreeNode child) {
451         prepareWrite(trans);
452         int id = child.getID();
453         for (int i = 0; i < _count; i++) {
454             if(childID(i) == id){
455                 if(freeIfEmpty(trans, _count -1)){
456                     return;
457                 }
458                 remove(i);
459                 if(i <= 1){
460                     tellParentAboutChangedKey(trans);
461                 }
462                 if(_count == 0){
463                     // root node empty case only, have to turn it into a leaf
464
_isLeaf = true;
465                     prepareValues();
466                 }
467                 return;
468             }
469         }
470         throw new IllegalStateException JavaDoc("child not found");
471     }
472     
473     private void keyChanged(Transaction trans, BTreeNode child) {
474         prepareWrite(trans);
475         int id = child.getID();
476         for (int i = 0; i < _count; i++) {
477             if(childID(i) == id){
478                 _keys[i] = child._keys[0];
479                 _children[i] = child;
480                 keyChanged(trans, i);
481                 return;
482             }
483         }
484         throw new IllegalStateException JavaDoc("child not found");
485     }
486     
487     private void tellParentAboutChangedKey(Transaction trans){
488         if(! isRoot()){
489             BTreeNode parent = _btree.produceNode(_parentID);
490             parent.keyChanged(trans, this);
491         }
492     }
493
494     private boolean isDirty(Transaction trans){
495         if(! canWrite()){
496             return false;
497         }
498         
499         for (int i = 0; i < _count; i++) {
500             if(keyPatch(trans, i) != null){
501                 return true;
502             }
503         }
504         
505         return false;
506     }
507     
508     private int compareInWriteMode(int index){
509         return keyHandler().compareTo(key(index));
510     }
511     
512     private int compareInReadMode(YapReader reader, int index){
513         seekKey(reader, index);
514         return keyHandler().compareTo(keyHandler().readIndexEntry(reader));
515     }
516     
517     public int count() {
518         return _count;
519     }
520     
521     private int entryLength(){
522         int len = keyHandler().linkLength();
523         if(_isLeaf){
524             if(handlesValues()){
525                 len += valueHandler().linkLength();
526             }
527         }else{
528             len += YapConst.ID_LENGTH;
529         }
530         return len;
531     }
532     
533     public int firstKeyIndex(Transaction trans) {
534         for (int ix = 0; ix < _count; ix++) {
535             if(indexIsValid(trans, ix)){
536                 return ix;
537             }
538         }
539         return -1;
540     }
541     
542     public int lastKeyIndex(Transaction trans) {
543         for (int ix = _count - 1; ix >= 0; ix--) {
544             if(indexIsValid(trans, ix)){
545                 return ix;
546             }
547         }
548         return -1;
549     }
550     
551     public boolean indexIsValid(Transaction trans, int index){
552         if(!canWrite()){
553             return true;
554         }
555         BTreePatch patch = keyPatch(index);
556         if(patch == null){
557             return true;
558         }
559         return patch.key(trans) != No4.INSTANCE;
560     }
561     
562     private Object JavaDoc firstKey(Transaction trans){
563         final int index = firstKeyIndex(trans);
564         if (-1 == index) {
565             return No4.INSTANCE;
566         }
567         return key(trans, index);
568     }
569     
570     public byte getIdentifier() {
571         return YapConst.BTREE_NODE;
572     }
573     
574     private boolean handlesValues(){
575         return _btree._valueHandler != Null.INSTANCE;
576     }
577     
578     private void prepareInsert(int pos){
579         if(pos > lastIndex()){
580             _count ++;
581             return;
582         }
583         int len = _count - pos;
584         System.arraycopy(_keys, pos, _keys, pos + 1, len);
585         if(_values != null){
586             System.arraycopy(_values, pos, _values, pos + 1, len);
587         }
588         if(_children != null){
589             System.arraycopy(_children, pos, _children, pos + 1, len);
590         }
591         _count++;
592     }
593     
594     private void remove(int pos){
595         if(DTrace.enabled){
596             DTrace.BTREE_NODE_REMOVE.log(getID());
597         }
598         int len = _count - pos;
599         _count--;
600         System.arraycopy(_keys, pos + 1, _keys, pos, len);
601         _keys[_count] = null;
602         if(_values != null){
603             System.arraycopy(_values, pos + 1, _values, pos, len);
604             _values[_count] = null;
605         }
606         if(_children != null){
607             System.arraycopy(_children, pos + 1, _children, pos, len);
608             _children[_count] = null;
609         }
610     }
611     
612     Object JavaDoc key(int index){
613         Object JavaDoc obj = _keys[index];
614         if( obj instanceof BTreePatch){
615             return ((BTreePatch)obj).getObject();
616         }
617         return obj;
618     }
619     
620     Object JavaDoc key(Transaction trans, YapReader reader, int index){
621         if(canWrite()){
622             return key(trans, index);
623         }
624         seekKey(reader, index);
625         return keyHandler().readIndexEntry(reader);
626     }
627     
628     Object JavaDoc key(Transaction trans, int index){
629         BTreePatch patch = keyPatch(index);
630         if(patch == null){
631             return _keys[index];
632         }
633         return patch.key(trans);
634     }
635     
636     private BTreePatch keyPatch(int index){
637         Object JavaDoc obj = _keys[index];
638         if( obj instanceof BTreePatch){
639             return (BTreePatch)obj;
640         }
641         return null;
642     }
643     
644     private BTreePatch keyPatch(Transaction trans, int index){
645         Object JavaDoc obj = _keys[index];
646         if( obj instanceof BTreePatch){
647             return ((BTreePatch)obj).forTransaction(trans);
648         }
649         return null;
650     }
651     
652     private Indexable4 keyHandler(){
653         return _btree._keyHandler;
654     }
655     
656     void markAsCached(int height){
657         _cached = true;
658         _btree.addNode(this);
659         
660         if( _isLeaf || (_children == null)){
661             return;
662         }
663         
664         height --;
665         
666         if(height < 1){
667             holdChildrenAsIDs();
668             return;
669         }
670         
671         for (int i = 0; i < _count; i++) {
672             if(_children[i] instanceof BTreeNode){
673                 ((BTreeNode)_children[i]).markAsCached(height);
674             }
675         }
676     }
677     
678     public int ownLength() {
679         return SLOT_LEADING_LENGTH
680           + (_count * entryLength())
681           + YapConst.BRACKETS_BYTES;
682     }
683     
684     YapReader prepareRead(Transaction trans){
685
686         if(canWrite()){
687             return null;
688         }
689         
690         if(isNew()){
691             return null;
692         }
693         
694         if(_cached){
695             read(trans.systemTransaction());
696             _btree.addToProcessing(this);
697             return null;
698         }
699         
700         YapReader reader = trans.i_file.readReaderByID(trans.systemTransaction(), getID());
701         
702         if (Deploy.debug) {
703             reader.readBegin(getIdentifier());
704         }
705         
706         readNodeHeader(reader);
707         
708         return reader;
709     }
710
711     void prepareWrite(Transaction trans){
712         
713         if(_dead){
714             return;
715         }
716         
717         if(canWrite()){
718             setStateDirty();
719             return;
720         }
721         
722         read(trans.systemTransaction());
723         setStateDirty();
724         _btree.addToProcessing(this);
725     }
726     
727     private void prepareArrays(){
728         if(canWrite()){
729             return;
730         }
731         _keys = new Object JavaDoc[_btree.nodeSize()];
732         if(_isLeaf){
733             prepareValues();
734         }else{
735             _children = new Object JavaDoc[_btree.nodeSize()];
736         }
737     }
738     
739     private void prepareValues(){
740         if(handlesValues()){
741             _values = new Object JavaDoc[_btree.nodeSize()];
742         }
743     }
744     
745     private void readNodeHeader(YapReader reader){
746         _count = reader.readInt();
747         byte leafByte = reader.readByte();
748         _isLeaf = (leafByte == 1);
749         _parentID = reader.readInt();
750         _previousID = reader.readInt();
751         _nextID = reader.readInt();
752     }
753     
754     public void readThis(Transaction trans, YapReader reader) {
755         readNodeHeader(reader);
756
757         prepareArrays();
758
759         boolean isInner = ! _isLeaf;
760         boolean vals = handlesValues() && _isLeaf;
761         for (int i = 0; i < _count; i++) {
762             _keys[i] = keyHandler().readIndexEntry(reader);
763             if(vals){
764                 _values[i] = valueHandler().readIndexEntry(reader);
765             }else{
766                 if(isInner){
767                     _children[i] = new Integer JavaDoc(reader.readInt());
768                 }
769             }
770         }
771     }
772     
773     public void remove(Transaction trans, int index){
774         if(!_isLeaf){
775             throw new IllegalStateException JavaDoc();
776         }
777             
778         prepareWrite(trans);
779         
780         BTreePatch patch = keyPatch(index);
781         
782         // no patch, no problem, can remove
783
if(patch == null){
784             _keys[index] = newRemovePatch(trans);
785             keyChanged(trans, index);
786             return;
787         }
788         
789         BTreePatch transPatch = patch.forTransaction(trans);
790         if(transPatch != null){
791             if(transPatch.isAdd()){
792                 cancelAdding(trans, index);
793                 return;
794             }
795         }else{
796             // If the patch is a removal of a cancelled removal for another
797
// transaction, we need one for this transaction also.
798
if(! patch.isAdd()){
799                 ((BTreeUpdate)patch).append(newRemovePatch(trans));
800                 return;
801             }
802         }
803         
804         // now we try if removal is OK for the next element in this node
805
if(index != lastIndex()){
806             if(compareInWriteMode(index + 1 ) != 0){
807                 return;
808             }
809             remove(trans, index + 1);
810             return;
811         }
812         
813         // nothing else worked so far, move on to the next node, try there
814
BTreeNode node = nextNode();
815         
816         if(node == null){
817             return;
818         }
819         
820         node.prepareWrite(trans);
821         if(node.compareInWriteMode(0) != 0){
822             return;
823         }
824         
825         node.remove(trans, 0);
826     }
827
828     private void cancelAdding(Transaction trans, int index) {
829         _btree.notifyRemoveListener(keyPatch(index).getObject());
830         if(freeIfEmpty(trans, _count-1)){
831             sizeDecrement(trans);
832             return;
833         }
834         remove(index);
835         keyChanged(trans, index);
836         sizeDecrement(trans);
837     }
838
839     private void sizeDecrement(Transaction trans) {
840         _btree.sizeChanged(trans, -1);
841     }
842
843     private int lastIndex() {
844         return _count - 1;
845     }
846
847     private BTreeUpdate newRemovePatch(Transaction trans) {
848         _btree.sizeChanged(trans, -1);
849         return new BTreeRemove(trans, currentKey());
850     }
851
852     private void keyChanged(Transaction trans, int index) {
853         if(index == 0){
854             tellParentAboutChangedKey(trans);
855         }
856     }
857     
858     
859     void rollback(Transaction trans){
860         commitOrRollback(trans, false);
861     }
862     
863     private Searcher search(YapReader reader){
864         return search(reader, SearchTarget.ANY);
865     }
866     
867     private Searcher search(YapReader reader, SearchTarget target){
868         Searcher s = new Searcher(target, _count);
869         if(canWrite()){
870             while(s.incomplete()){
871                 s.resultIs( compareInWriteMode(s.cursor()));
872             }
873         }else{
874             while(s.incomplete()){
875                 s.resultIs( compareInReadMode(reader, s.cursor()));
876             }
877         }
878         return s;
879     }
880     
881     private void seekAfterKey(YapReader reader, int ix){
882         seekKey(reader, ix);
883         reader._offset += keyHandler().linkLength();
884     }
885     
886     private void seekChild(YapReader reader, int ix){
887         seekAfterKey(reader, ix);
888     }
889     
890     private void seekKey(YapReader reader, int ix){
891         reader._offset = SLOT_LEADING_LENGTH + (entryLength() * ix);
892     }
893     
894     private void seekValue(YapReader reader, int ix){
895         if(handlesValues()){
896             seekAfterKey(reader, ix);
897         }else{
898             seekKey(reader, ix);
899         }
900     }
901     
902     private BTreeNode split(Transaction trans){
903         
904         
905         BTreeNode res = new BTreeNode(_btree, _btree._halfNodeSize, _isLeaf,_parentID, getID(), _nextID);
906         
907         System.arraycopy(_keys, _btree._halfNodeSize, res._keys, 0, _btree._halfNodeSize);
908         for (int i = _btree._halfNodeSize; i < _keys.length; i++) {
909             _keys[i] = null;
910         }
911         if(_values != null){
912             res._values = new Object JavaDoc[_btree.nodeSize()];
913             System.arraycopy(_values, _btree._halfNodeSize, res._values, 0, _btree._halfNodeSize);
914             for (int i = _btree._halfNodeSize; i < _values.length; i++) {
915                 _values[i] = null;
916             }
917         }
918         if(_children != null){
919             res._children = new Object JavaDoc[_btree.nodeSize()];
920             System.arraycopy(_children, _btree._halfNodeSize, res._children, 0, _btree._halfNodeSize);
921             for (int i = _btree._halfNodeSize; i < _children.length; i++) {
922                 _children[i] = null;
923             }
924         }
925         
926         _count = _btree._halfNodeSize;
927         
928         res.write(trans.systemTransaction());
929         _btree.addNode(res);
930         
931         int splitID = res.getID();
932         
933         pointNextTo(trans, splitID);
934         
935         setNextID(trans, splitID);
936
937         if(_children != null){
938             for (int i = 0; i < _btree._halfNodeSize; i++) {
939                 if(res._children[i] == null){
940                     break;
941                 }
942                 res.child(i).setParentID(trans, splitID );
943             }
944         }
945         return res;
946     }
947     
948     private void pointNextTo(Transaction trans, int id){
949         if(_nextID != 0){
950             nextNode().setPreviousID(trans, id);
951         }
952     }
953
954     private void pointPreviousTo(Transaction trans, int id){
955         if(_previousID != 0){
956             previousNode().setNextID(trans, id);
957         }
958     }
959
960     public BTreeNode previousNode() {
961         if(_previousID == 0){
962             return null;
963         }
964         return _btree.produceNode(_previousID);
965     }
966     
967     public BTreeNode nextNode() {
968         if(_nextID == 0){
969             return null;
970         }
971         return _btree.produceNode(_nextID);
972     }
973     
974     BTreePointer firstPointer(Transaction trans) {
975         YapReader reader = prepareRead(trans);
976         if (_isLeaf) {
977             return leafFirstPointer(trans, reader);
978         }
979         return branchFirstPointer(trans, reader);
980     }
981
982     private BTreePointer branchFirstPointer(Transaction trans, YapReader reader) {
983         for (int i = 0; i < _count; i++) {
984             BTreePointer childFirstPointer = child(reader, i).firstPointer(trans);
985             if(childFirstPointer != null){
986                 return childFirstPointer;
987             }
988         }
989         return null;
990     }
991
992     private BTreePointer leafFirstPointer(Transaction trans, YapReader reader) {
993         int index = firstKeyIndex(trans);
994         if(index == -1){
995             return null;
996         }
997         return new BTreePointer(trans, reader, this, index);
998     }
999     
1000    public BTreePointer lastPointer(Transaction trans) {
1001        YapReader reader = prepareRead(trans);
1002        if (_isLeaf) {
1003            return leafLastPointer(trans, reader);
1004        }
1005        return branchLastPointer(trans, reader);
1006    }
1007
1008    private BTreePointer branchLastPointer(Transaction trans, YapReader reader) {
1009        for (int i = _count - 1; i >= 0; i--) {
1010            BTreePointer childLastPointer = child(reader, i).lastPointer(trans);
1011            if(childLastPointer != null){
1012                return childLastPointer;
1013            }
1014        }
1015        return null;
1016    }
1017
1018    private BTreePointer leafLastPointer(Transaction trans, YapReader reader) {
1019        int index = lastKeyIndex(trans);
1020        if(index == -1){
1021            return null;
1022        }
1023        return new BTreePointer(trans, reader, this, index);
1024    }
1025    
1026    void purge(){
1027        if(_dead){
1028            _keys = null;
1029            _values = null;
1030            _children = null;
1031            return;
1032        }
1033        
1034        if(_cached){
1035            return;
1036        }
1037        
1038        if(!canWrite()){
1039            return;
1040        }
1041        
1042        for (int i = 0; i < _count; i++) {
1043            if(_keys[i] instanceof BTreePatch){
1044                holdChildrenAsIDs();
1045                _btree.addNode(this);
1046                return;
1047            }
1048        }
1049    }
1050    
1051    private void setParentID(Transaction trans, int id){
1052        prepareWrite(trans);
1053        _parentID = id;
1054        setStateDirty();
1055    }
1056    
1057    private void setPreviousID(Transaction trans, int id){
1058        prepareWrite(trans);
1059        _previousID = id;
1060        setStateDirty();
1061    }
1062    
1063    private void setNextID(Transaction trans, int id){
1064        prepareWrite(trans);
1065        _nextID = id;
1066        setStateDirty();
1067    }
1068    
1069    public void traverseKeys(Transaction trans, Visitor4 visitor){
1070        YapReader reader = prepareRead(trans);
1071        if(_isLeaf){
1072            for (int i = 0; i < _count; i++) {
1073                Object JavaDoc obj = key(trans,reader, i);
1074                if(obj != No4.INSTANCE){
1075                    visitor.visit(obj);
1076                }
1077            }
1078        }else{
1079            for (int i = 0; i < _count; i++) {
1080                child(reader,i).traverseKeys(trans, visitor);
1081            }
1082        }
1083    }
1084    
1085    public void traverseValues(Transaction trans, Visitor4 visitor){
1086        if(! handlesValues()){
1087            traverseKeys(trans, visitor);
1088            return;
1089        }
1090        YapReader reader = prepareRead(trans);
1091        if(_isLeaf){
1092            for (int i = 0; i < _count; i++) {
1093                if(key(trans,reader, i) != No4.INSTANCE){
1094                    visitor.visit(value(reader, i));
1095                }
1096            }
1097        }else{
1098            for (int i = 0; i < _count; i++) {
1099                child(reader,i).traverseValues(trans, visitor);
1100            }
1101        }
1102    }
1103    
1104    Object JavaDoc value(int index) {
1105        return _values[index];
1106    }
1107    
1108    Object JavaDoc value(YapReader reader, int index){
1109        if( _values != null ){
1110            return _values[index];
1111        }
1112        seekValue(reader, index);
1113        return valueHandler().readIndexEntry(reader);
1114    }
1115
1116    
1117    private Indexable4 valueHandler(){
1118        return _btree._valueHandler;
1119    }
1120    
1121    public boolean writeObjectBegin() {
1122        if(_dead){
1123            return false;
1124        }
1125        if(!canWrite()){
1126            return false;
1127        }
1128        return super.writeObjectBegin();
1129    }
1130    
1131    
1132    public void writeThis(Transaction trans, YapReader a_writer) {
1133        
1134        int count = 0;
1135        int startOffset = a_writer._offset;
1136        
1137        a_writer.incrementOffset(COUNT_LEAF_AND_3_LINK_LENGTH);
1138
1139        if(_isLeaf){
1140            boolean vals = handlesValues();
1141            for (int i = 0; i < _count; i++) {
1142                Object JavaDoc obj = key(trans, i);
1143                if(obj != No4.INSTANCE){
1144                    count ++;
1145                    keyHandler().writeIndexEntry(a_writer, obj);
1146                    if(vals){
1147                        valueHandler().writeIndexEntry(a_writer, _values[i]);
1148                    }
1149                }
1150            }
1151        }else{
1152            for (int i = 0; i < _count; i++) {
1153                if(childCanSupplyFirstKey(i)){
1154                    BTreeNode child = (BTreeNode)_children[i];
1155                    Object JavaDoc childKey = child.firstKey(trans);
1156                    if(childKey != No4.INSTANCE){
1157                        count ++;
1158                        keyHandler().writeIndexEntry(a_writer, childKey);
1159                        a_writer.writeIDOf(trans, child);
1160                    }
1161                }else{
1162                    count ++;
1163                    keyHandler().writeIndexEntry(a_writer, key(i));
1164                    a_writer.writeIDOf(trans, _children[i]);
1165                }
1166            }
1167        }
1168        
1169        int endOffset = a_writer._offset;
1170        a_writer._offset = startOffset;
1171        a_writer.writeInt(count);
1172        a_writer.append( _isLeaf ? (byte) 1 : (byte) 0);
1173        a_writer.writeInt(_parentID);
1174        a_writer.writeInt(_previousID);
1175        a_writer.writeInt(_nextID);
1176        a_writer._offset = endOffset;
1177
1178    }
1179    
1180    public String JavaDoc toString() {
1181        if(_count == 0){
1182            return "Node " + getID() + " not loaded";
1183        }
1184        String JavaDoc str = "\nBTreeNode";
1185        str += "\nid: " + getID();
1186        str += "\nparent: " + _parentID;
1187        str += "\nprevious: " + _previousID;
1188        str += "\nnext: " + _nextID;
1189        str += "\ncount:" + _count;
1190        str += "\nleaf:" + _isLeaf + "\n";
1191        
1192        if(canWrite()){
1193            
1194            str += " { ";
1195            
1196            boolean first = true;
1197            
1198            for (int i = 0; i < _count; i++) {
1199                if(_keys[i] != null){
1200                    if(! first){
1201                        str += ", ";
1202                    }
1203                    str += _keys[i].toString();
1204                    first = false;
1205                }
1206            }
1207            
1208            str += " }";
1209        }
1210        return str;
1211    }
1212
1213    public void debugLoadFully(Transaction trans) {
1214        prepareWrite(trans);
1215        if (_isLeaf) {
1216            return;
1217        }
1218        for (int i=0; i<_count; ++i) {
1219            if(_children[i] instanceof Integer JavaDoc){
1220                _children[i] = btree().produceNode(((Integer JavaDoc)_children[i]).intValue());
1221            }
1222            ((BTreeNode)_children[i]).debugLoadFully(trans);
1223        }
1224    }
1225
1226    public static void defragIndex(ReaderPair readers,Indexable4 keyHandler,Indexable4 valueHandler) {
1227        if (Deploy.debug) {
1228            readers.readBegin(YapConst.BTREE_NODE);
1229        }
1230        // count
1231
int count=readers.readInt();
1232        // leafByte
1233
byte leafByte = readers.readByte();
1234        boolean isLeaf = (leafByte == 1);
1235        boolean handlesValues=(valueHandler!=null)&&isLeaf;
1236
1237        readers.copyID(); // parent ID
1238
readers.copyID(); // previous ID
1239
readers.copyID(); // next ID
1240

1241        for (int i = 0; i < count; i++) {
1242            keyHandler.defragIndexEntry(readers);
1243            if(handlesValues){
1244                valueHandler.defragIndexEntry(readers);
1245            }else{
1246                if(!isLeaf){
1247                    readers.copyID();
1248                }
1249            }
1250        }
1251        if (Deploy.debug) {
1252            readers.readEnd();
1253        }
1254    }
1255
1256    public boolean isLeaf() {
1257        return _isLeaf;
1258    }
1259
1260    /** This traversal goes over all nodes, not just leafs */
1261    void traverseAllNodes(Transaction trans, Visitor4 command) {
1262        YapReader reader = prepareRead(trans);
1263        command.visit(this);
1264        if(_isLeaf){
1265            return;
1266        }
1267        for (int childIdx=0;childIdx<_count;childIdx++) {
1268            child(reader, childIdx).traverseAllNodes(trans, command);
1269        }
1270    }
1271}
1272
Popular Tags