1 package com.quadcap.sql.index; 2 3 40 41 import java.io.BufferedReader ; 42 import java.io.InputStreamReader ; 43 import java.io.IOException ; 44 45 import java.util.Properties ; 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 63 public class BtreeCursor extends PooledObject implements BCursor { 64 Object 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 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 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 { 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 134 public PooledObject create() { 135 return new BtreeCursor(); 136 } 137 138 141 public void init(Btree tree, boolean skipSetup) throws IOException { 142 this.tree = tree; 143 this.fileLock = tree.lock; 144 if (!skipSetup) { 145 beforeFirst(); 146 } 147 } 148 149 153 protected void setup(boolean restoreKey) throws IOException { 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 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 186 public final boolean seek(byte[] key) throws IOException { 187 return seek(key, key.length); 188 } 189 190 193 public boolean seek(byte[] key, int len) throws IOException { 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 if (Trace.bit(6)) { 204 Debug.println(toString() + ".seek(" + 205 Util.hexBytes(key, 0, len) + ") = " + ret); 206 } 207 return ret; 209 } 210 } 211 212 final String id() { 214 return tree.getFile().getName().substring(0, 1) + 215 " " + SubPageManager.toString(tree.getRootBlock()); 216 } 217 final String dr() { 218 return !Trace.bit(12) ? 219 ", val = " + (lengths[1] > 0 ? Util.hexBytes(getVal()) : "null") : 220 ""; 221 } 222 224 227 boolean seek1(int level, byte[] key, int len) throws IOException { 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 252 final void setBlock(int i, Block b) { 253 if (blocks[i] != null) blocks[i].decrRefCount(); 254 blocks[i] = b; 255 } 256 257 260 public void beforeFirst() throws IOException { 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 if (Trace.bit(1)) { 280 Debug.println(toString() + ".beforeFirst()"); 281 } 282 } 284 } 285 286 287 290 public void afterLast() throws IOException { 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 if (Trace.bit(1)) { 307 Debug.println(toString() + ".afterLast()"); 308 } 309 } 311 } 312 313 316 public boolean absolute(int x) throws IOException { 317 synchronized (fileLock) { 318 if (x > 0) { 319 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 if (Trace.bit(1)) { 336 Debug.println(toString() + ".absolute(" + x + ") = true"); 337 } 338 return true; 340 } else if (x < 0) { 341 int absx = 0 - x; 342 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 if (Trace.bit(1)) { 354 Debug.println(toString() + ".absolute(" + x + ") = true"); 355 } 356 if (size > 0) position = size + x; 358 return true; 359 } else { 360 throw new IOException ("absolute 0"); 361 } 362 } 363 } 364 365 369 public boolean next() throws IOException { 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 if (Trace.bit(1)) { 379 Debug.println(toString() + ".next() false"); 380 } 381 return false; 383 } 384 p = pointers[depth-1]; 385 cnt = Bnode.getCount(blocks[depth-1]); 386 if (p >= cnt) { 387 if (Trace.bit(1)) { 389 Debug.println(toString() + ".next() false"); 390 } 391 return false; 393 } 394 } 395 holdKey(0); 396 pointers[depth-1]++; 397 if (position >= 0) position++; 398 if (Trace.bit(1)) { 400 Debug.println(toString() + ".next(): " + 401 Util.hexBytes(getKeyBuf(), 0, getKeyLen()) + 402 " = " + dr()); 403 } 404 return true; 406 } 407 } 408 409 413 public boolean prev() throws IOException { 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 if (Trace.bit(1)) { 437 Debug.println(toString() + ".prev() true"); 438 } 439 return true; 441 } 442 } 443 444 448 public boolean delete() throws IOException { 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 if (Trace.bit(9)) { 463 Debug.println(toString() + ".delete() = " + ret); 464 } 465 return ret; 467 } 468 } 469 470 471 476 public boolean insert(byte[] key, int klen, 477 byte[] data, int doff, int dlen) throws IOException { 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 ("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 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 return ret; 507 } 508 } 509 510 public boolean insert(byte[] key, byte[] data) throws IOException { 511 return insert(key, key.length, data, 0, data.length); 512 } 513 514 517 public boolean replace(byte[] data, int doff, int dlen) 518 throws IOException 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 ("bad tree"); 529 } 530 531 root.setKey(b, p, curKey, lengths[0], data, doff, dlen, true); 532 tree.notifyUpdate(this); 533 if (Trace.bit(8)) { 535 Debug.println(toString() + ".replace(" + k(curKey, 0, lengths[0]) + ") = true"); 536 } 537 return true; 539 } 540 } 541 542 public boolean replace(byte[] data) throws IOException { 543 return replace(data, 0, data.length); 544 } 545 546 549 public long size() throws IOException { 550 synchronized (fileLock) { 551 setup(true); 552 if (size < 0) { 553 size = subtreeSize(root, root.getBlock()); 554 } 555 return size; 556 } 557 } 558 559 562 public long position() throws IOException { 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 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 641 final boolean getNextBlock() throws IOException { 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 { 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 ("holdKey: getKeyAndData failed"); 694 } 695 } else { 696 throw new RuntimeException ("Hold what, mate?"); 700 } 701 } 704 705 static long subtreeSize(Bnode root, Block b) throws IOException { 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 724 public String toString() { 725 return "BtreeCursor[" + tree + "]"; 726 } 727 728 String k(byte[] b, int off, int len) { 729 return tree.compare.toString(b, off, len); 730 } 731 732 String t() { 733 StringBuffer sb = new StringBuffer (); 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 lastBuf = new StringBuffer (); 745 746 private static final int countNext(BCursor c) throws IOException { 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 { 754 int cnt = 0; 755 StringBuffer 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 (buf, 0, len)); 764 } 765 sb.append("}"); 766 lastCount = cnt; 767 return cnt; 768 } 769 770 final static String r(boolean b) { 771 return b ? "{true}" : "{false}"; 772 } 773 static void itest(BCursor bc) throws IOException { 774 InputStreamReader ir = new InputStreamReader (System.in); 775 BufferedReader r = new BufferedReader (ir); 776 String ret = ""; 777 while (true) { 778 System.out.print("BC" + ret + " (" + ((BtreeCursor)bc).t() + "): "); 779 System.out.flush(); 780 String line = r.readLine(); 781 if (line == null) break; 782 try { 783 ret = doLine(bc, line); 784 if (ret == null) break; 785 } catch (Throwable t) { 786 t.printStackTrace(System.out); 787 System.out.println("-------------------------"); 788 } 789 } 790 } 791 792 static String doLine(BCursor bc, String line) throws Exception { 793 String ks = line.toLowerCase().substring(1).trim(); 794 byte[] k = ks.getBytes(); 795 byte[] d = ks.toUpperCase().getBytes(); 796 String 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 (bc.getKeyBuf(), 0, 820 bc.getKeyLen())); 821 show("current val = " + new String (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 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 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 { 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 ("*** Error, found " + i); 878 if (!c.insert(k, k.length, k, 0, k.length)) { 879 throw new IOException ("*** 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 { 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 (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 { 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 921 public static void main(String [] args) { 922 try { 923 String name = "test.db"; 924 int blocksize = 4096; 925 int cachesize = 256; 926 BlockFile f = new BlockFile(name, "rw", 927 new Properties (), 928 blocksize, cachesize); 929 long rootBlock = f.newPage(); 930 Btree t = new Btree(f, rootBlock, true); 931 935 BCursor c = t.getCursor(); 936 ktest(c); 940 } catch (Throwable t) { 941 t.printStackTrace(System.out); 942 } 943 } 944 945 static void jtest(BCursor c) throws Exception { 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 } 1016 | Popular Tags |