KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > index > BtreeCursor


1 package com.quadcap.sql.index;
2
3 /* Copyright 1997 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.BufferedReader JavaDoc;
42 import java.io.InputStreamReader JavaDoc;
43 import java.io.IOException JavaDoc;
44
45 import java.util.Properties JavaDoc;
46
47 import com.quadcap.sql.file.Block;
48 import com.quadcap.sql.file.BlockFile;
49 import com.quadcap.sql.file.ByteUtil;
50 import com.quadcap.sql.file.SubPageManager;
51
52 import com.quadcap.sql.lock.PooledObject;
53 import com.quadcap.sql.lock.ObjectPool;
54
55 import com.quadcap.util.Debug;
56 import com.quadcap.util.Util;
57
58 /**
59  * A cursor for a Quadcap Btree.
60  *
61  * @author Stan Bailes
62  */

63 public class BtreeCursor extends PooledObject implements BCursor {
64     Object JavaDoc fileLock;
65     
66     Btree tree;
67     Bnode root = null;
68     Comparator compare = null;
69
70     Block[] blocks = new Block[16];
71     int[] pointers = new int[16];
72
73     byte[] curKey = new byte[4096];
74     byte[] curVal = new byte[4096];
75     int[] lengths = new int[2];
76
77     int depth = -1;
78     long size = -1;
79
80     /**
81      * <pre>
82      * For the position variable:
83      * -2 unknown
84      * -1 after last
85      * 0 before first
86      * >0 on key
87      * </pre>
88      */

89     static final long posUNKNOWN = -2;
90     static final long posAFTER_LAST = -1;
91     static final long posBEFORE_FIRST = 0;
92
93     long position = posUNKNOWN;
94
95     /**
96      * Constructor for cursor on a given Btree.
97      */

98     private BtreeCursor() {}
99
100     static final boolean noPool = false;
101     static ObjectPool pool = new ObjectPool(new BtreeCursor());
102
103     static BtreeCursor get(Btree tree, boolean skipSetup) throws IOException JavaDoc {
104         BtreeCursor c = null;
105         if (noPool) {
106             c = new BtreeCursor();
107         } else {
108             synchronized (tree.lock) {
109                 c = (BtreeCursor)pool.get();
110             }
111         }
112         if (c != null) {
113             c.init(tree, skipSetup);
114         }
115         return c;
116     }
117
118     public void release() {
119         unsetup();
120         synchronized (fileLock) {
121             Btree theTree = tree;
122             tree = null;
123             fileLock = null;
124             theTree.releaseCursor(this);
125             if (!noPool) {
126                 pool.release(this);
127             }
128         }
129     }
130     
131     /**
132      * PooledObject factory
133      */

134     public PooledObject create() {
135         return new BtreeCursor();
136     }
137
138     /**
139      * Init for use/reuse
140      */

141     public void init(Btree tree, boolean skipSetup) throws IOException JavaDoc {
142         this.tree = tree;
143         this.fileLock = tree.lock;
144         if (!skipSetup) {
145             beforeFirst();
146         }
147     }
148
149     /**
150      * Called to re-establish the synchronization of this cursor in
151      * the case where the underlying index has been modified.
152      */

153     protected void setup(boolean restoreKey) throws IOException JavaDoc {
154         if (depth < 0) {
155             synchronized (fileLock) {
156                 this.root = tree.getRoot();
157                 this.compare = tree.compare;
158                 if (restoreKey) {
159                     if (lengths[0] > 0) {
160                         seek(curKey, lengths[0]);
161                     } else {
162                         beforeFirst();
163                     }
164                 }
165             }
166         }
167     }
168
169     /**
170      * Called (in theory) by the owning Btree when the index is modified.
171      */

172     public void unsetup() {
173         for (int i = 0; i < blocks.length; i++) {
174             setBlock(i, null);
175         }
176         this.root = null;
177         this.depth = -1;
178         this.size = -1;
179         if (position > 0) position = posUNKNOWN;
180     }
181
182     /**
183      * Seek: Position the cursor on or before the specified key value.
184      * Return true if the key matches exactly.
185      */

186     public final boolean seek(byte[] key) throws IOException JavaDoc {
187         return seek(key, key.length);
188     }
189
190     /**
191      * Seek, but the key can be a subsequence of the given byte array.
192      */

193     public boolean seek(byte[] key, int len) throws IOException JavaDoc {
194         synchronized (fileLock) {
195             position = posUNKNOWN;
196             setup(false);
197             setBlock(0, root.getBlock());
198             boolean ret = seek1(0, key, len);
199             if (ret) {
200                 holdKey(0);
201             }
202             //#ifdef DEBUG
203
if (Trace.bit(6)) {
204                 Debug.println(toString() + ".seek(" +
205                               Util.hexBytes(key, 0, len) + ") = " + ret);
206             }
207             //#endif
208
return ret;
209         }
210     }
211
212     //#ifdef DEBUG
213
final String JavaDoc id() {
214         return tree.getFile().getName().substring(0, 1) +
215             " " + SubPageManager.toString(tree.getRootBlock());
216     }
217     final String JavaDoc dr() {
218         return !Trace.bit(12) ?
219             ", val = " + (lengths[1] > 0 ? Util.hexBytes(getVal()) : "null") :
220             "";
221     }
222     //#endif
223

224     /**
225      * (Private) seek recursion kernel
226      */

227     boolean seek1(int level, byte[] key, int len) throws IOException JavaDoc {
228         Block b = blocks[level];
229     int bs;
230         bs = Bnode.bsearch(b, compare, key, len, 0, Bnode.getCount(b)-1);
231     int index = bs < 0 ? (-1-bs) : bs;
232     if (!Bnode.isLeaf(b)) {
233         if (bs < 0) {
234         index = index - 1;
235         if (index < 0) index = 0;
236         }
237             pointers[level] = index;
238         Block c = root.getBlock(Bnode.blockRef(b, index));
239             setBlock(++level, c);
240         return seek1(level, key, len);
241         } else {
242             pointers[level] = index;
243             depth = level+1;
244             return bs >= 0;
245         }
246     }
247
248     /**
249      * Manage updates to the 'blocks' array through this function to
250      * assuage refcount madness.
251      */

252     final void setBlock(int i, Block b) {
253         if (blocks[i] != null) blocks[i].decrRefCount();
254         blocks[i] = b;
255     }
256
257     /**
258      * Move the cursor before the first key.
259      */

260     public void beforeFirst() throws IOException JavaDoc {
261         synchronized (fileLock) {
262             this.root = tree.getRoot();
263             this.compare = tree.compare;
264             lengths[0] = lengths[1] = 0;
265             Block b = root.getBlock();
266             for (int level = 0; b != null; level++) {
267                 setBlock(level, b);
268                 pointers[level] = 0;
269                 if (!Bnode.isLeaf(b)) {
270                     b = root.getBlock(Bnode.blockRef(b, 0));
271                 } else {
272                     depth = level + 1;
273                     b = null;
274                 }
275             }
276             position = posBEFORE_FIRST;
277
278             //#ifdef DEBUG
279
if (Trace.bit(1)) {
280                 Debug.println(toString() + ".beforeFirst()");
281             }
282             //#endif
283
}
284     }
285     
286     
287     /**
288      * Move the cursor after the last key.
289      */

290     public void afterLast() throws IOException JavaDoc {
291         synchronized (fileLock) {
292             setup(false);
293             Block b = root.getBlock();
294             for (int level = 0; b != null; level++) {
295                 setBlock(level, b);
296                 int count = Bnode.getCount(b);
297                 pointers[level] = count;
298                 if (!Bnode.isLeaf(b)) {
299                     b = root.getBlock(Bnode.blockRef(b, pointers[level]-1));
300                 } else {
301                     b = null;
302                 }
303             }
304             position = posAFTER_LAST;
305             //#ifdef DEBUG
306
if (Trace.bit(1)) {
307                 Debug.println(toString() + ".afterLast()");
308             }
309             //#endif
310
}
311     }
312
313     /**
314      * Move the cursor to the specified absolute position
315      */

316     public boolean absolute(int x) throws IOException JavaDoc {
317         synchronized (fileLock) {
318             if (x > 0) {
319                 // from first
320
beforeFirst();
321                 int cur = 1;
322                 int cnt = Bnode.getCount(blocks[depth-1]);
323                 while (cur + cnt < x) {
324                     cur += cnt;
325                     if (!getNextBlock()) return false;
326                     cnt = Bnode.getCount(blocks[depth-1]);
327                 }
328                 int p = x - cur;
329                 if (p < 0 || p >= cnt) return false;
330                 pointers[depth-1] = p;
331                 holdKey(0);
332                 pointers[depth-1]++;
333                 position = x;
334                 //#ifdef DEBUG
335
if (Trace.bit(1)) {
336                     Debug.println(toString() + ".absolute(" + x + ") = true");
337                 }
338                 //#endif
339
return true;
340             } else if (x < 0) {
341                 int absx = 0 - x;
342                 // from last
343
afterLast();
344                 int cnt = Bnode.getCount(blocks[depth-1]);
345                 while (cnt < absx) {
346                     absx -= cnt;
347                     if (!getPrevBlock()) return false;
348                     cnt = Bnode.getCount(blocks[depth-1]);
349                 }
350                 pointers[depth-1] -= absx;
351                 holdKey(0);
352                 //#ifdef DEBUG
353
if (Trace.bit(1)) {
354                     Debug.println(toString() + ".absolute(" + x + ") = true");
355                 }
356                 //#endif
357
if (size > 0) position = size + x;
358                 return true;
359             } else {
360                 throw new IOException JavaDoc("absolute 0");
361             }
362         }
363     }
364
365     /**
366      * Move the cursor to the next row and return <b>true</b> if the
367      * cursor is positioned on a valid row.
368      */

369     public boolean next() throws IOException JavaDoc {
370         synchronized (fileLock) {
371             setup(true);
372             if (depth <= 0) return false;
373             int p = pointers[depth-1];
374             int cnt = Bnode.getCount(blocks[depth-1]);
375             if (p >= cnt) {
376                 if (cnt == 0 || !getNextBlock()) {
377                     //#ifdef DEBUG
378
if (Trace.bit(1)) {
379                         Debug.println(toString() + ".next() false");
380                     }
381                     //#endif
382
return false;
383                 }
384                 p = pointers[depth-1];
385                 cnt = Bnode.getCount(blocks[depth-1]);
386                 if (p >= cnt) {
387                     //#ifdef DEBUG
388
if (Trace.bit(1)) {
389                         Debug.println(toString() + ".next() false");
390                     }
391                     //#endif
392
return false;
393                 }
394             }
395             holdKey(0);
396             pointers[depth-1]++;
397             if (position >= 0) position++;
398             //#ifdef DEBUG
399
if (Trace.bit(1)) {
400                 Debug.println(toString() + ".next(): " +
401                               Util.hexBytes(getKeyBuf(), 0, getKeyLen()) +
402                               " = " + dr());
403             }
404             //#endif
405
return true;
406         }
407     }
408
409     /**
410      * Move the cursor to the next row and return <b>true</b> if the
411      * cursor is positioned on a valid row.
412      */

413     public boolean prev() throws IOException JavaDoc {
414         synchronized (fileLock) {
415             setup(true);
416             if (depth < 0) return false;
417             int p = pointers[depth-1] - 1;
418             int cnt = Bnode.getCount(blocks[depth-1]);
419             if (p < 0 || cnt <= 0) {
420                 if (cnt <= 0 || !getPrevBlock()) return false;
421                 p = pointers[depth-1];
422                 if (p < 0 || cnt <= 0) return false;
423             }
424             pointers[depth-1] = p;
425             holdKey(0);
426             if (position > 0) {
427                 position--;
428             } else if (position == posAFTER_LAST) {
429                 if (size < 0) {
430                     position = posUNKNOWN;
431                 } else {
432                     position = size;
433                 }
434             }
435             //#ifdef DEBUG
436
if (Trace.bit(1)) {
437                 Debug.println(toString() + ".prev() true");
438             }
439             //#endif
440
return true;
441         }
442     }
443
444     /**
445      * Delete the current row (if the cursor is positioned on a valid
446      * row, that is ;-)
447      */

448     public boolean delete() throws IOException JavaDoc {
449         synchronized (fileLock) {
450             boolean ret = false;
451             setup(true);
452             if (depth >= 0) {
453                 int p = pointers[depth-1];
454                 int cnt = Bnode.getCount(blocks[depth-1]);
455                 if (p >= 0 && p < cnt) {
456                     root.deleteKeyAtPos(blocks[depth-1], p, false);
457                     tree.notifyUpdate(this);
458                     ret = true;
459                 }
460             }
461             //#ifdef DEBUG
462
if (Trace.bit(9)) {
463                 Debug.println(toString() + ".delete() = " + ret);
464             }
465             //#endif
466
return ret;
467         }
468     }
469
470
471     /**
472      * Insert a new key/data pair. We are presumably positioned just before
473      * the spot where the new record should go, but we should check, anyway.
474      * This will return false if the key already exists in the index.
475      */

476     public boolean insert(byte[] key, int klen,
477                           byte[] data, int doff, int dlen) throws IOException JavaDoc {
478         synchronized (fileLock) {
479             setup(true);
480
481             int p = pointers[depth-1];
482             final Block b = blocks[depth-1];
483             final int cnt = Bnode.getCount(b);
484         
485             if (p < 0 || p > cnt) throw new IOException JavaDoc("bad tree");
486
487             boolean ret = true;
488             if (p >= 0 && p < cnt) {
489                 int r = Bnode.keyCompareAtPos(compare, key, klen, b, p);
490                 if (r != -1) ret = false;
491             } else if (p > 0 && cnt > 0) {
492                 int r = Bnode.keyCompareAtPos(compare, key, klen, b, p-1);
493                 if (r != 1) ret = false;
494             }
495             if (ret) {
496                 root.setKey(b, p, key, klen, data, doff, dlen, false);
497                 tree.notifyUpdate(this);
498             }
499             //#ifdef DEBUG
500
if (Trace.bit(7)) {
501                 Debug.println(toString() + ".insert(" + k(key, 0, klen) +
502                               (!Trace.bit(12) ? (", " + k(data, doff, dlen)) : "") +
503                               ") = " + ret);
504             }
505             //#endif
506
return ret;
507         }
508     }
509     
510     public boolean insert(byte[] key, byte[] data) throws IOException JavaDoc {
511         return insert(key, key.length, data, 0, data.length);
512     }
513
514     /**
515      * Replace the data portion of the current item with the specified data
516      */

517     public boolean replace(byte[] data, int doff, int dlen)
518         throws IOException JavaDoc
519     {
520         synchronized (fileLock) {
521             setup(true);
522
523             int p = pointers[depth-1];
524             final Block b = blocks[depth-1];
525             final int cnt = Bnode.getCount(b);
526         
527             if (p < 0 || p > cnt) {
528                 throw new IOException JavaDoc("bad tree");
529             }
530
531             root.setKey(b, p, curKey, lengths[0], data, doff, dlen, true);
532             tree.notifyUpdate(this);
533             //#ifdef DEBUG
534
if (Trace.bit(8)) {
535                 Debug.println(toString() + ".replace(" + k(curKey, 0, lengths[0]) + ") = true");
536             }
537             //#endif
538
return true;
539         }
540     }
541
542     public boolean replace(byte[] data) throws IOException JavaDoc {
543         return replace(data, 0, data.length);
544     }
545     
546     /**
547      * Return the total number of entries in this index
548      */

549     public long size() throws IOException JavaDoc {
550         synchronized (fileLock) {
551             setup(true);
552             if (size < 0) {
553                 size = subtreeSize(root, root.getBlock());
554             }
555             return size;
556         }
557     }
558
559     /**
560      * Return the current position in the index
561      */

562     public long position() throws IOException JavaDoc {
563         synchronized (fileLock) {
564             setup(true);
565             if (position < 0) {
566                 long total = 0;
567                 boolean r = false;
568                 for (int d = 0; d < depth-1; d++) {
569                     Block b = blocks[d];
570                     int p = pointers[d];
571                     int c = Bnode.getCount(b);
572                     if (d == 0) r = (c / 2) <= p;
573                     if (r) p++;
574                     else { c = p; p = 0; }
575                     if (Bnode.isLeaf(b)) {
576                         total += (c - p);
577                     } else {
578                         for (int i = p; i < c; i++) {
579                             Block s = root.getBlock(Bnode.blockRef(b, i));
580                             try {
581                                 total += subtreeSize(root, s);
582                             } finally {
583                                 s.decrRefCount();
584                             }
585                         }
586                     }
587                 }
588                 position = r ? size() - total : total + 1;
589             }
590             return position;
591         }
592     }
593
594     /**
595      * Close the index
596      */

597     public void close() {
598         unsetup();
599     }
600
601     public int getKey(byte[] buf) {
602         System.arraycopy(curKey, 0, buf, 0, lengths[0]);
603         return lengths[0];
604     }
605
606     public byte[] getKeyBuf() { return curKey; }
607
608     public void setKeyBuf(byte[] buf) { curKey = buf; }
609
610     public int getKeyLen() { return lengths[0]; }
611
612     public byte[] getKey() {
613         byte[] ret = new byte[lengths[0]];
614         System.arraycopy(curKey, 0, ret, 0, ret.length);
615         return ret;
616     }
617
618     public int getVal(byte[] buf) {
619         System.arraycopy(curVal, 0, buf, 0, lengths[1]);
620         return lengths[1];
621     }
622
623     public byte[] getValBuf() { return curVal; }
624
625     public void setValBuf(byte[] buf) { curVal = buf; }
626
627     public int getValLen() { return lengths[1]; }
628
629     public byte[] getVal() {
630         byte[] ret = new byte[lengths[1]];
631         System.arraycopy(curVal, 0, ret, 0, ret.length);
632         return ret;
633     }
634
635     public long getValAsLong() {
636         return ByteUtil.getLong(curVal, 0);
637     }
638
639     //--------------------------------- private stuff
640

641     final boolean getNextBlock() throws IOException JavaDoc {
642     int d = depth - 2;
643     while (d >= 0 && pointers[d]+1 >= Bnode.getCount(blocks[d])) {
644         d--;
645     }
646
647         if (d < 0) return false;
648         Block b = root.getBlock(Bnode.blockRef(blocks[d],
649                                                ++pointers[d]));
650         
651         setBlock(d+1, b);
652         pointers[d+1] = 0;
653
654         for (int i = d+2; i < depth; i++) {
655             pointers[i] = 0;
656             Block c = root.getBlock(Bnode.blockRef(blocks[i-1],
657                                                    pointers[i-1]));
658             setBlock(i, c);
659         }
660     return true;
661     }
662     
663     final boolean getPrevBlock() throws IOException JavaDoc {
664     int d = depth - 2;
665     while (d >= 0 && pointers[d] <= 0) {
666         d--;
667     }
668
669     if (d < depth-1) {
670         if (d < 0) {
671         return false;
672         }
673             Block b = root.getBlock(Bnode.blockRef(blocks[d],
674                                                    --pointers[d]));
675             setBlock(d+1, b);
676         pointers[d+1] = 0;
677
678         for (int i = d+2; i < depth; i++) {
679                 Block c = root.getBlock(Bnode.blockRef(blocks[i-1],
680                                                        pointers[i-1]));
681                 setBlock(i, c);
682         pointers[i] = Bnode.getCount(c)-1;
683         }
684     }
685     return true;
686     }
687
688     final void holdKey(int off) {
689         int p = pointers[depth-1] - off;
690         Block b = blocks[depth-1];
691         if (p >= 0 && p < Bnode.getCount(b)) {
692             if (!Bnode.getKeyAndData(b, p, curKey, curVal, lengths)) {
693                 throw new RuntimeException JavaDoc("holdKey: getKeyAndData failed");
694             }
695         } else {
696             //msg("holdKey: p = " + p + ", pointers[depth(" + depth + ")-1]=" +
697
// pointers[depth-1] + ", off = " + off + ", count = " +
698
// Bnode.getCount(b));
699
throw new RuntimeException JavaDoc("Hold what, mate?");
700         }
701         //Debug.println("holdKey: [" + k(curKey, 0, lengths[0]) +
702
//" / " + k(curVal, 0, lengths[1]) + "]");
703
}
704         
705     static long subtreeSize(Bnode root, Block b) throws IOException JavaDoc {
706         int count = Bnode.getCount(b);
707         if (Bnode.isLeaf(b)) return count;
708         else {
709             long total = 0;
710             for (int i = 0; i < count; i++) {
711                 Block c = root.getBlock(Bnode.blockRef(b, i));
712                 try {
713                     total += subtreeSize(root, c);
714                 } finally {
715                     c.decrRefCount();
716                 }
717             }
718             return total;
719         }
720     }
721
722     //#ifdef DEBUG
723

724     public String JavaDoc toString() {
725         return "BtreeCursor[" + tree + "]";
726     }
727     
728     String JavaDoc k(byte[] b, int off, int len) {
729         return tree.compare.toString(b, off, len);
730     }
731     
732     String JavaDoc t() {
733         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
734         for (int i = 0; i < depth; i++) {
735             if (i > 0) sb.append(' ');
736             sb.append(String.valueOf(pointers[i]));
737             sb.append('/');
738             sb.append(String.valueOf(Bnode.getCount(blocks[i])));
739         }
740         return sb.toString();
741     }
742         
743     static int lastCount = -1;
744     static StringBuffer JavaDoc lastBuf = new StringBuffer JavaDoc();
745     
746     private static final int countNext(BCursor c) throws IOException JavaDoc {
747         int cnt = 0;
748         while (c.next()) cnt++;
749         lastCount = cnt;
750         return cnt;
751     }
752     
753     private static final int countPrev(BCursor c) throws IOException JavaDoc {
754         int cnt = 0;
755         StringBuffer JavaDoc sb = lastBuf;
756         sb.setLength(0);
757         sb.append("{");
758         byte[] buf = new byte[111];
759         while (c.prev()) {
760             cnt++;
761             int len = c.getKey(buf);
762             if (cnt > 0) sb.append(',');
763             sb.append(new String JavaDoc(buf, 0, len));
764         }
765         sb.append("}");
766         lastCount = cnt;
767         return cnt;
768     }
769
770     final static String JavaDoc r(boolean b) {
771         return b ? "{true}" : "{false}";
772     }
773     static void itest(BCursor bc) throws IOException JavaDoc {
774         InputStreamReader JavaDoc ir = new InputStreamReader JavaDoc(System.in);
775         BufferedReader JavaDoc r = new BufferedReader JavaDoc(ir);
776         String JavaDoc ret = "";
777         while (true) {
778             System.out.print("BC" + ret + " (" + ((BtreeCursor)bc).t() + "): ");
779             System.out.flush();
780             String JavaDoc line = r.readLine();
781             if (line == null) break;
782             try {
783                 ret = doLine(bc, line);
784                 if (ret == null) break;
785             } catch (Throwable JavaDoc t) {
786                 t.printStackTrace(System.out);
787                 System.out.println("-------------------------");
788             }
789         }
790     }
791
792     static String JavaDoc doLine(BCursor bc, String JavaDoc line) throws Exception JavaDoc {
793         String JavaDoc ks = line.toLowerCase().substring(1).trim();
794         byte[] k = ks.getBytes();
795         byte[] d = ks.toUpperCase().getBytes();
796         String JavaDoc ret = "";
797         if (line.startsWith("g")) {
798             ret = r(bc.seek(k));
799         } else if (line.equals("<")) {
800             bc.beforeFirst();
801         } else if (line.equals(">")) {
802             bc.afterLast();
803         } else if (line.equals("n")) {
804             ret = r(bc.next());
805         } else if (line.equals("p")) {
806             ret = r(bc.prev());
807         } else if (line.equals("d")) {
808             ret = r(bc.delete());
809         } else if (line.startsWith("i")) {
810             ret = r(bc.insert(k, k.length, d, 0, d.length));
811         } else if (line.startsWith("r")) {
812             ret = r(bc.replace(d, 0, d.length));
813         } else if (line.equals("c")) {
814             bc.close();
815         } else if (line.equals("s")) {
816             show("position = " + bc.position() + " of " +
817                  bc.size() + " records");
818         } else if (line.equals("k")) {
819             show("current key = " + new String JavaDoc(bc.getKeyBuf(), 0,
820                                                bc.getKeyLen()));
821             show("current val = " + new String JavaDoc(bc.getValBuf(), 0,
822                                                bc.getValLen()));
823             show("current val as long: " + bc.getValAsLong());
824                     
825         } else if (line.equals("p")) {
826             show("position = " + bc.position() + " of " +
827                  bc.size() + " records");
828         } else if (line.equals("q")) {
829             return null;
830         } else {
831             int row = 0;
832             boolean bad = true;
833             try {
834                 row = Integer.parseInt(line);
835                 bad = false;
836             } catch (Throwable JavaDoc t) {}
837             if (!bad) {
838                 ret = r(bc.absolute(row));
839             } else {
840                 show("g <key> seek(key)");
841                 show("i <key> insert(key,KEY)");
842                 show("r <key> replace(KEY)");
843                 show("< beforeFirst()");
844                 show("> afterLast()");
845                 show("n next()");
846                 show("p prev()");
847                 show("c close()");
848                 show("d delete()");
849                 show("s position / size");
850             }
851         }
852         return ret;
853     }
854
855     static void show(String JavaDoc s) {
856         System.out.println(s);
857     }
858
859     static final long tick() { return System.currentTimeMillis(); }
860
861     static final void mkey(int i, byte[] b) {
862         int x = b.length;
863         while (x > 0 && i > 0) {
864             b[--x] = (byte)('0' + (i % 10));
865             i /= 10;
866         }
867         while (x > 0) b[--x] = '0';
868     }
869     
870     static void ktest(BCursor c) throws IOException JavaDoc {
871         long s = tick();
872         byte[] k = new byte[8];
873         for (int i = 0; i < k.length; i++) k[i] = '0';
874         for (int ki = 0; ki < 100000; ki++) {
875             int i = (ki * 2003) % 100000;
876             mkey(i, k);
877             if (c.seek(k)) throw new IOException JavaDoc("*** Error, found " + i);
878             if (!c.insert(k, k.length, k, 0, k.length)) {
879                 throw new IOException JavaDoc("*** Error insert: " + i);
880             }
881         }
882         long elap = tick() - s;
883         System.out.println("insert: " + elap + " ms");
884         kshow(c);
885     }
886     
887     static void kshow(BCursor c) throws IOException JavaDoc {
888         long s = tick();
889         int count = 0;
890         int total = 0;
891         int etotal = 0;
892         c.beforeFirst();
893         while (c.next()) {
894             etotal += count;
895             count++;
896             total += Integer.parseInt(new String JavaDoc(c.getValBuf(), 0,
897                                                  c.getValLen()));
898         }
899         long elap = tick() - s;
900         show("seek: " + elap + " ms");
901         show("Count: " + count + ", total/etotal = " + total + "/" + etotal);
902     }
903     
904     static void ktest(Btree t) throws IOException JavaDoc {
905         long s = tick();
906         byte[] k = new byte[8];
907         for (int i = 0; i < k.length; i++) k[i] = '0';
908         for (int ki = 0; ki < 100000; ki++) {
909             int i = (ki * 2003) % 100000;
910             mkey(i, k);
911             t.set(k, k);
912         }
913         long elap = tick() - s;
914         System.out.println("insert: " + elap + " ms");
915         kshow(t.getCursor());
916     }
917     
918     /**
919      * Main for testing
920      */

921     public static void main(String JavaDoc[] args) {
922         try {
923             String JavaDoc name = "test.db";
924             int blocksize = 4096;
925             int cachesize = 256;
926             BlockFile f = new BlockFile(name, "rw",
927                                         new Properties JavaDoc(),
928                                         blocksize, cachesize);
929             long rootBlock = f.newPage();
930             Btree t = new Btree(f, rootBlock, true);
931 // tree.set("abc".getBytes(), "def".getBytes());
932
// tree.set("aabc".getBytes(), "def".getBytes());
933
// tree.set("fabc".getBytes(), "def".getBytes());
934

935             BCursor c = t.getCursor();
936             //itest(c);
937
//jtest(c);
938
//ktest(t);
939
ktest(c);
940         } catch (Throwable JavaDoc t) {
941             t.printStackTrace(System.out);
942         }
943     }
944
945     static void jtest(BCursor c) throws Exception JavaDoc {
946         c.seek("abc".getBytes());
947         c.insert("abc".getBytes(), 3, "def".getBytes(), 0, 3);
948         c.seek("ahc".getBytes());
949         c.insert("ahc".getBytes(), 3, "deh".getBytes(), 0, 3);
950         c.seek("bbc".getBytes());
951         c.insert("bbc".getBytes(), 3, "jej".getBytes(), 0, 3);
952
953         int cSize = countNext(c);
954         if (c.size() != cSize) {
955             System.out.println("Bad size: " + cSize + " vs " + c.size());
956         }
957         for (int i = 1; i <= cSize; i++) {
958             if (i == 0) c.beforeFirst(); else c.absolute(i);
959             if (c.position() != i) {
960                 System.out.println("Bad position " + i + " vs " +
961                                    c.position());
962             }
963             if (countNext(c) != cSize - i) {
964                 System.out.println("Bad count next: " + lastCount +
965                                    " vs " + (cSize - i));
966             }
967             if (i == 0) c.beforeFirst(); else c.absolute(i);
968             if (c.position() != i) {
969                 System.out.println("Bad position " + i + " vs " +
970                                    c.position());
971             }
972             if (countPrev(c) != i) {
973                 System.out.println("Bad count prev: " + i + " vs " +
974                                    lastCount + " " + lastBuf);
975             }
976             if (i == 0) c.afterLast(); else c.absolute(0 - i);
977             if (c.position() != cSize - i) {
978                 System.out.println("Bad position " + (cSize-i) + " vs " +
979                                    c.position());
980             }
981             if (countNext(c) != i-1) {
982                 System.out.println("Bad count next: " + lastCount +
983                                    " vs " + (i-1));
984             }
985             if (i == 0) c.afterLast(); else c.absolute(0 - i);
986             if (c.position() != (cSize-i)) {
987                 System.out.println("Bad position " + (cSize-i) + " vs " +
988                                    c.position());
989             }
990             if (countPrev(c) != cSize - i + 1) {
991                 System.out.println("Bad count prev: " + (cSize-i+1) +
992                                    " vs " +
993                                    lastCount + " " + lastBuf);
994             }
995         }
996                 
997         System.out.println("seek(abc) = " + c.seek("abc".getBytes()) +
998                            ": " + c.position() + "/" + c.size());
999         System.out.println("c.next() = " + c.next());
1000        System.out.println("c.next() = " + c.next());
1001
1002        System.out.println("seek(abb) = " + c.seek("abb".getBytes()));
1003        System.out.println("c.next() = " + c.next());
1004        System.out.println("c.next() = " + c.next());
1005
1006        System.out.println("seek(abd) = " + c.seek("abd".getBytes()));
1007        System.out.println("c.next() = " + c.next());
1008        System.out.println("c.next() = " + c.next());
1009
1010        System.out.println("seek(zzz) = " + c.seek("zzz".getBytes()));
1011        System.out.println("c.next() = " + c.next());
1012        System.out.println("c.next() = " + c.next());
1013    }
1014    //#endif
1015
}
1016
Popular Tags