1 8 9 package com.sleepycat.collections; 10 11 import com.sleepycat.compat.DbCompat; 12 import com.sleepycat.je.Cursor; 13 import com.sleepycat.je.CursorConfig; 14 import com.sleepycat.je.DatabaseEntry; 15 import com.sleepycat.je.DatabaseException; 16 import com.sleepycat.je.JoinConfig; 17 import com.sleepycat.je.JoinCursor; 18 import com.sleepycat.je.LockMode; 19 import com.sleepycat.je.OperationStatus; 20 import com.sleepycat.util.keyrange.KeyRange; 21 import com.sleepycat.util.keyrange.RangeCursor; 22 23 32 final class DataCursor implements Cloneable { 33 34 35 static final int REPOS_EXACT = 0; 36 37 static final int REPOS_NEXT = 1; 38 39 static final int REPOS_EOF = 2; 40 41 private RangeCursor cursor; 42 private JoinCursor joinCursor; 43 private DataView view; 44 private KeyRange range; 45 private boolean writeAllowed; 46 private boolean readUncommitted; 47 private DatabaseEntry keyThang; 48 private DatabaseEntry valueThang; 49 private DatabaseEntry primaryKeyThang; 50 private DatabaseEntry otherThang; 51 private DataCursor[] indexCursorsToClose; 52 53 56 DataCursor(DataView view, boolean writeAllowed) 57 throws DatabaseException { 58 59 init(view, writeAllowed, null, null); 60 } 61 62 65 DataCursor(DataView view, boolean writeAllowed, CursorConfig config) 66 throws DatabaseException { 67 68 init(view, writeAllowed, config, null); 69 } 70 71 75 DataCursor(DataView view, boolean writeAllowed, Object singleKey) 76 throws DatabaseException { 77 78 init(view, writeAllowed, null, view.subRange(view.range, singleKey)); 79 } 80 81 85 DataCursor(DataView view, boolean writeAllowed, 86 Object beginKey, boolean beginInclusive, 87 Object endKey, boolean endInclusive) 88 throws DatabaseException { 89 90 init(view, writeAllowed, null, 91 view.subRange 92 (view.range, beginKey, beginInclusive, endKey, endInclusive)); 93 } 94 95 98 DataCursor(DataView view, DataCursor[] indexCursors, 99 JoinConfig joinConfig, boolean closeIndexCursors) 100 throws DatabaseException { 101 102 if (view.isSecondary()) { 103 throw new IllegalArgumentException ( 104 "The primary collection in a join must not be a secondary " + 105 "database"); 106 } 107 Cursor[] cursors = new Cursor[indexCursors.length]; 108 for (int i = 0; i < cursors.length; i += 1) { 109 cursors[i] = indexCursors[i].cursor.getCursor(); 110 } 111 joinCursor = view.db.join(cursors, joinConfig); 112 init(view, false, null, null); 113 if (closeIndexCursors) { 114 indexCursorsToClose = indexCursors; 115 } 116 } 117 118 121 DataCursor cloneCursor() 122 throws DatabaseException { 123 124 checkNoJoinCursor(); 125 126 DataCursor o; 127 try { 128 o = (DataCursor) super.clone(); 129 } catch (CloneNotSupportedException neverHappens) { 130 return null; 131 } 132 133 o.initThangs(); 134 KeyRange.copy(keyThang, o.keyThang); 135 KeyRange.copy(valueThang, o.valueThang); 136 if (primaryKeyThang != keyThang) { 137 KeyRange.copy(primaryKeyThang, o.primaryKeyThang); 138 } 139 140 o.cursor = cursor.dup(true); 141 return o; 142 } 143 144 147 RangeCursor getCursor() { 148 return cursor; 149 } 150 151 154 private void init(DataView view, 155 boolean writeAllowed, 156 CursorConfig config, 157 KeyRange range) 158 throws DatabaseException { 159 160 if (config == null) { 161 config = view.cursorConfig; 162 } 163 this.view = view; 164 this.writeAllowed = writeAllowed && view.writeAllowed; 165 this.range = (range != null) ? range : view.range; 166 readUncommitted = config.getReadUncommitted() || 167 view.currentTxn.isReadUncommitted(); 168 initThangs(); 169 170 if (joinCursor == null) { 171 cursor = new MyRangeCursor 172 (this.range, config, view, this.writeAllowed); 173 } 174 } 175 176 179 private void initThangs() 180 throws DatabaseException { 181 182 keyThang = new DatabaseEntry(); 183 primaryKeyThang = view.isSecondary() ? (new DatabaseEntry()) 184 : keyThang; 185 valueThang = new DatabaseEntry(); 186 } 187 188 191 private void setThangs(byte[] keyBytes, 192 byte[] priKeyBytes, 193 byte[] valueBytes) { 194 195 keyThang.setData(KeyRange.copyBytes(keyBytes)); 196 197 if (keyThang != primaryKeyThang) { 198 primaryKeyThang.setData(KeyRange.copyBytes(priKeyBytes)); 199 } 200 201 valueThang.setData(KeyRange.copyBytes(valueBytes)); 202 } 203 204 207 void close() 208 throws DatabaseException { 209 210 if (joinCursor != null) { 211 JoinCursor toClose = joinCursor; 212 joinCursor = null; 213 toClose.close(); 214 } 215 if (cursor != null) { 216 Cursor toClose = cursor.getCursor(); 217 cursor = null; 218 view.currentTxn.closeCursor(toClose ); 219 } 220 if (indexCursorsToClose != null) { 221 DataCursor[] toClose = indexCursorsToClose; 222 indexCursorsToClose = null; 223 for (int i = 0; i < toClose.length; i += 1) { 224 toClose[i].close(); 225 } 226 } 227 } 228 229 235 int repositionRange(byte[] keyBytes, 236 byte[] priKeyBytes, 237 byte[] valueBytes, 238 boolean lockForWrite) 239 throws DatabaseException { 240 241 LockMode lockMode = getLockMode(lockForWrite); 242 OperationStatus status = null; 243 244 245 setThangs(keyBytes, priKeyBytes, valueBytes); 246 247 248 if (view.dupsAllowed) { 249 status = cursor.getSearchBothRange(keyThang, primaryKeyThang, 250 valueThang, lockMode); 251 } 252 if (status != OperationStatus.SUCCESS) { 253 status = cursor.getSearchKeyRange(keyThang, primaryKeyThang, 254 valueThang, lockMode); 255 } 256 257 258 if (status == OperationStatus.SUCCESS) { 259 if (!KeyRange.equalBytes(keyBytes, 0, keyBytes.length, 260 keyThang.getData(), 261 keyThang.getOffset(), 262 keyThang.getSize())) { 263 return REPOS_NEXT; 264 } 265 if (view.dupsAllowed) { 266 DatabaseEntry thang = view.isSecondary() ? primaryKeyThang 267 : valueThang; 268 byte[] bytes = view.isSecondary() ? priKeyBytes 269 : valueBytes; 270 if (!KeyRange.equalBytes(bytes, 0, bytes.length, 271 thang.getData(), 272 thang.getOffset(), 273 thang.getSize())) { 274 return REPOS_NEXT; 275 } 276 } 277 return REPOS_EXACT; 278 } else { 279 return REPOS_EOF; 280 } 281 } 282 283 291 boolean repositionExact(byte[] keyBytes, 292 byte[] priKeyBytes, 293 byte[] valueBytes, 294 boolean lockForWrite) 295 throws DatabaseException { 296 297 LockMode lockMode = getLockMode(lockForWrite); 298 OperationStatus status = null; 299 300 301 setThangs(keyBytes, priKeyBytes, valueBytes); 302 303 304 if (view.recNumRenumber) { 305 306 status = cursor.getSearchKey(keyThang, primaryKeyThang, 307 valueThang, lockMode); 308 } else { 309 status = cursor.getSearchBoth(keyThang, primaryKeyThang, 310 valueThang, lockMode); 311 } 312 313 return (status == OperationStatus.SUCCESS); 314 } 315 316 319 DataView getView() { 320 321 return view; 322 } 323 324 327 KeyRange getRange() { 328 329 return range; 330 } 331 332 336 boolean isWriteAllowed() { 337 338 return writeAllowed; 339 } 340 341 344 Object getCurrentKey() 345 throws DatabaseException { 346 347 return view.makeKey(keyThang, primaryKeyThang); 348 } 349 350 353 Object getCurrentValue() 354 throws DatabaseException { 355 356 return view.makeValue(primaryKeyThang, valueThang); 357 } 358 359 362 DatabaseEntry getKeyThang() { 363 return keyThang; 364 } 365 366 370 DatabaseEntry getPrimaryKeyThang() { 371 return primaryKeyThang; 372 } 373 374 377 DatabaseEntry getValueThang() { 378 return valueThang; 379 } 380 381 384 boolean hasRecNumAccess() { 385 386 return view.recNumAccess; 387 } 388 389 392 int getCurrentRecordNumber() 393 throws DatabaseException { 394 395 if (view.btreeRecNumDb) { 396 397 if (otherThang == null) { 398 otherThang = new DatabaseEntry(); 399 } 400 DbCompat.getCurrentRecordNumber(cursor.getCursor(), otherThang, 401 getLockMode(false)); 402 return DbCompat.getRecordNumber(otherThang); 403 } else { 404 405 return DbCompat.getRecordNumber(keyThang); 406 } 407 } 408 409 412 OperationStatus getCurrent(boolean lockForWrite) 413 throws DatabaseException { 414 415 checkNoJoinCursor(); 416 return cursor.getCurrent(keyThang, primaryKeyThang, valueThang, 417 getLockMode(lockForWrite)); 418 } 419 420 423 OperationStatus getFirst(boolean lockForWrite) 424 throws DatabaseException { 425 426 LockMode lockMode = getLockMode(lockForWrite); 427 if (joinCursor != null) { 428 return joinCursor.getNext(keyThang, valueThang, lockMode); 429 } else { 430 return cursor.getFirst(keyThang, primaryKeyThang, valueThang, 431 lockMode); 432 } 433 } 434 435 438 OperationStatus getNext(boolean lockForWrite) 439 throws DatabaseException { 440 441 LockMode lockMode = getLockMode(lockForWrite); 442 if (joinCursor != null) { 443 return joinCursor.getNext(keyThang, valueThang, lockMode); 444 } else { 445 return cursor.getNext(keyThang, primaryKeyThang, valueThang, 446 lockMode); 447 } 448 } 449 450 453 OperationStatus getNextNoDup(boolean lockForWrite) 454 throws DatabaseException { 455 456 LockMode lockMode = getLockMode(lockForWrite); 457 if (joinCursor != null) { 458 return joinCursor.getNext(keyThang, valueThang, lockMode); 459 } else if (view.dupsView) { 460 return cursor.getNext 461 (keyThang, primaryKeyThang, valueThang, lockMode); 462 } else { 463 return cursor.getNextNoDup 464 (keyThang, primaryKeyThang, valueThang, lockMode); 465 } 466 } 467 468 471 OperationStatus getNextDup(boolean lockForWrite) 472 throws DatabaseException { 473 474 checkNoJoinCursor(); 475 if (view.dupsView) { 476 return null; 477 } else { 478 return cursor.getNextDup 479 (keyThang, primaryKeyThang, valueThang, 480 getLockMode(lockForWrite)); 481 } 482 } 483 484 487 OperationStatus getLast(boolean lockForWrite) 488 throws DatabaseException { 489 490 checkNoJoinCursor(); 491 return cursor.getLast(keyThang, primaryKeyThang, valueThang, 492 getLockMode(lockForWrite)); 493 } 494 495 498 OperationStatus getPrev(boolean lockForWrite) 499 throws DatabaseException { 500 501 checkNoJoinCursor(); 502 return cursor.getPrev(keyThang, primaryKeyThang, valueThang, 503 getLockMode(lockForWrite)); 504 } 505 506 509 OperationStatus getPrevNoDup(boolean lockForWrite) 510 throws DatabaseException { 511 512 checkNoJoinCursor(); 513 LockMode lockMode = getLockMode(lockForWrite); 514 if (view.dupsView) { 515 return null; 516 } else if (view.dupsView) { 517 return cursor.getPrev 518 (keyThang, primaryKeyThang, valueThang, lockMode); 519 } else { 520 return cursor.getPrevNoDup 521 (keyThang, primaryKeyThang, valueThang, lockMode); 522 } 523 } 524 525 528 OperationStatus getPrevDup(boolean lockForWrite) 529 throws DatabaseException { 530 531 checkNoJoinCursor(); 532 if (view.dupsView) { 533 return null; 534 } else { 535 return cursor.getPrevDup 536 (keyThang, primaryKeyThang, valueThang, 537 getLockMode(lockForWrite)); 538 } 539 } 540 541 545 OperationStatus getSearchKey(Object key, Object value, 546 boolean lockForWrite) 547 throws DatabaseException { 548 549 checkNoJoinCursor(); 550 if (view.dupsView) { 551 if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) { 552 KeyRange.copy(view.dupsKey, keyThang); 553 return cursor.getSearchBoth 554 (keyThang, primaryKeyThang, valueThang, 555 getLockMode(lockForWrite)); 556 } 557 } else { 558 if (view.useKey(key, value, keyThang, range)) { 559 return doGetSearchKey(lockForWrite); 560 } 561 } 562 return OperationStatus.NOTFOUND; 563 } 564 565 569 private OperationStatus doGetSearchKey(boolean lockForWrite) 570 throws DatabaseException { 571 572 LockMode lockMode = getLockMode(lockForWrite); 573 if (view.btreeRecNumAccess) { 574 return cursor.getSearchRecordNumber(keyThang, primaryKeyThang, 575 valueThang, lockMode); 576 } else { 577 return cursor.getSearchKey(keyThang, primaryKeyThang, 578 valueThang, lockMode); 579 } 580 } 581 582 585 OperationStatus getSearchKeyRange(Object key, Object value, 586 boolean lockForWrite) 587 throws DatabaseException { 588 589 checkNoJoinCursor(); 590 LockMode lockMode = getLockMode(lockForWrite); 591 if (view.dupsView) { 592 if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) { 593 KeyRange.copy(view.dupsKey, keyThang); 594 return cursor.getSearchBothRange 595 (keyThang, primaryKeyThang, valueThang, lockMode); 596 } 597 } else { 598 if (view.useKey(key, value, keyThang, range)) { 599 return cursor.getSearchKeyRange 600 (keyThang, primaryKeyThang, valueThang, lockMode); 601 } 602 } 603 return OperationStatus.NOTFOUND; 604 } 605 606 610 OperationStatus findBoth(Object key, Object value, boolean lockForWrite) 611 throws DatabaseException { 612 613 checkNoJoinCursor(); 614 LockMode lockMode = getLockMode(lockForWrite); 615 view.useValue(value, valueThang, null); 616 if (view.dupsView) { 617 if (view.useKey(key, value, primaryKeyThang, view.dupsRange)) { 618 KeyRange.copy(view.dupsKey, keyThang); 619 if (otherThang == null) { 620 otherThang = new DatabaseEntry(); 621 } 622 OperationStatus status = cursor.getSearchBoth 623 (keyThang, primaryKeyThang, otherThang, lockMode); 624 if (status == OperationStatus.SUCCESS && 625 KeyRange.equalBytes(otherThang, valueThang)) { 626 return status; 627 } 628 } 629 } else if (view.useKey(key, value, keyThang, range)) { 630 if (view.isSecondary()) { 631 if (otherThang == null) { 632 otherThang = new DatabaseEntry(); 633 } 634 OperationStatus status = cursor.getSearchKey(keyThang, 635 primaryKeyThang, 636 otherThang, 637 lockMode); 638 while (status == OperationStatus.SUCCESS) { 639 if (KeyRange.equalBytes(otherThang, valueThang)) { 640 return status; 641 } 642 status = cursor.getNextDup(keyThang, primaryKeyThang, 643 otherThang, lockMode); 644 } 645 646 } else { 647 return cursor.getSearchBoth(keyThang, null, valueThang, 648 lockMode); 649 } 650 } 651 return OperationStatus.NOTFOUND; 652 } 653 654 658 OperationStatus findValue(Object value, boolean findFirst) 659 throws DatabaseException { 660 661 checkNoJoinCursor(); 662 663 if (view.entityBinding != null && !view.isSecondary() && 664 (findFirst || !view.dupsAllowed)) { 665 return findBoth(null, value, false); 666 } else { 667 if (otherThang == null) { 668 otherThang = new DatabaseEntry(); 669 } 670 view.useValue(value, otherThang, null); 671 OperationStatus status = findFirst ? getFirst(false) 672 : getLast(false); 673 while (status == OperationStatus.SUCCESS) { 674 if (KeyRange.equalBytes(valueThang, otherThang)) { 675 break; 676 } 677 status = findFirst ? getNext(false) : getPrev(false); 678 } 679 return status; 680 } 681 } 682 683 686 int count() 687 throws DatabaseException { 688 689 checkNoJoinCursor(); 690 if (view.dupsView) { 691 return 1; 692 } else { 693 return cursor.count(); 694 } 695 } 696 697 700 OperationStatus putCurrent(Object value) 701 throws DatabaseException { 702 703 checkWriteAllowed(false); 704 view.useValue(value, valueThang, keyThang); 705 706 710 boolean hashWorkaround = (view.dupsOrdered && !view.ordered); 711 if (hashWorkaround) { 712 if (otherThang == null) { 713 otherThang = new DatabaseEntry(); 714 } 715 cursor.getCurrent(keyThang, primaryKeyThang, otherThang, 716 LockMode.DEFAULT); 717 if (KeyRange.equalBytes(valueThang, otherThang)) { 718 return OperationStatus.SUCCESS; 719 } else { 720 throw new IllegalArgumentException ( 721 "Current data differs from put data with sorted duplicates"); 722 } 723 } 724 725 return cursor.putCurrent(valueThang); 726 } 727 728 731 OperationStatus putAfter(Object value) 732 throws DatabaseException { 733 734 checkWriteAllowed(false); 735 view.useValue(value, valueThang, null); 736 return cursor.putAfter(keyThang, valueThang); 737 } 738 739 742 OperationStatus putBefore(Object value) 743 throws DatabaseException { 744 745 checkWriteAllowed(false); 746 view.useValue(value, valueThang, keyThang); 747 return cursor.putBefore(keyThang, valueThang); 748 } 749 750 754 OperationStatus put(Object key, Object value, Object [] oldValue, 755 boolean useCurrentKey) 756 throws DatabaseException { 757 758 initForPut(key, value, oldValue, useCurrentKey); 759 return cursor.put(keyThang, valueThang); 760 } 761 762 766 OperationStatus putNoOverwrite(Object key, Object value, 767 boolean useCurrentKey) 768 throws DatabaseException { 769 770 initForPut(key, value, null, useCurrentKey); 771 return cursor.putNoOverwrite(keyThang, valueThang); 772 } 773 774 778 OperationStatus putNoDupData(Object key, Object value, Object [] oldValue, 779 boolean useCurrentKey) 780 throws DatabaseException { 781 782 initForPut(key, value, oldValue, useCurrentKey); 783 if (view.dupsOrdered) { 784 return cursor.putNoDupData(keyThang, valueThang); 785 } else { 786 if (view.dupsAllowed) { 787 788 OperationStatus status = 789 cursor.getSearchBoth(keyThang, primaryKeyThang, 790 valueThang, 791 getLockMode(false)); 792 if (status == OperationStatus.SUCCESS) { 793 return OperationStatus.KEYEXIST; 794 } else { 795 return cursor.put(keyThang, valueThang); 796 } 797 } else { 798 799 return cursor.putNoOverwrite(keyThang, valueThang); 800 } 801 } 802 } 803 804 807 private void initForPut(Object key, Object value, Object [] oldValue, 808 boolean useCurrentKey) 809 throws DatabaseException { 810 811 checkWriteAllowed(false); 812 if (!useCurrentKey && !view.useKey(key, value, keyThang, range)) { 813 throw new IllegalArgumentException ("key out of range"); 814 } 815 if (oldValue != null) { 816 oldValue[0] = null; 817 if (!view.dupsAllowed) { 818 OperationStatus status = doGetSearchKey(true); 819 if (status == OperationStatus.SUCCESS) { 820 oldValue[0] = getCurrentValue(); 821 } 822 } 823 } 824 view.useValue(value, valueThang, keyThang); 825 } 826 827 831 void useRangeKey() { 832 if (!range.isSingleKey()) { 833 throw new IllegalStateException (); 834 } 835 KeyRange.copy(range.getSingleKey(), keyThang); 836 } 837 838 841 OperationStatus delete() 842 throws DatabaseException { 843 844 checkWriteAllowed(true); 845 return cursor.delete(); 846 } 847 848 851 LockMode getLockMode(boolean lockForWrite) { 852 853 854 855 if (readUncommitted) { 856 return LockMode.READ_UNCOMMITTED; 857 } else if (lockForWrite) { 858 return view.currentTxn.getWriteLockMode(); 859 } else { 860 return LockMode.DEFAULT; 861 } 862 } 863 864 867 private void checkNoJoinCursor() { 868 869 if (joinCursor != null) { 870 throw new UnsupportedOperationException 871 ("Not allowed with a join cursor"); 872 } 873 } 874 875 879 private void checkWriteAllowed(boolean allowSecondary) { 880 881 checkNoJoinCursor(); 882 883 if (!writeAllowed || (!allowSecondary && view.isSecondary())) { 884 throw new UnsupportedOperationException 885 ("Writing is not allowed"); 886 } 887 } 888 } 889 | Popular Tags |