1 8 9 package com.sleepycat.je; 10 11 import java.util.logging.Level ; 12 import java.util.logging.Logger ; 13 14 import com.sleepycat.je.dbi.CursorImpl; 15 import com.sleepycat.je.dbi.DatabaseImpl; 16 import com.sleepycat.je.dbi.GetMode; 17 import com.sleepycat.je.dbi.PutMode; 18 import com.sleepycat.je.dbi.RangeRestartException; 19 import com.sleepycat.je.dbi.CursorImpl.KeyChangeStatus; 20 import com.sleepycat.je.dbi.CursorImpl.SearchMode; 21 import com.sleepycat.je.latch.LatchSupport; 22 import com.sleepycat.je.tree.BIN; 23 import com.sleepycat.je.tree.DBIN; 24 import com.sleepycat.je.tree.Key; 25 import com.sleepycat.je.tree.LN; 26 import com.sleepycat.je.tree.Node; 27 import com.sleepycat.je.txn.BuddyLocker; 28 import com.sleepycat.je.txn.LockType; 29 import com.sleepycat.je.txn.Locker; 30 import com.sleepycat.je.txn.LockerFactory; 31 import com.sleepycat.je.utilint.DatabaseUtil; 32 import com.sleepycat.je.utilint.InternalException; 33 34 38 public class Cursor { 39 40 43 CursorImpl cursorImpl; 45 48 CursorConfig config; 49 50 61 private boolean updateOperationsProhibited; 62 63 66 private Database dbHandle; 67 68 71 private DatabaseImpl dbImpl; 72 73 74 private boolean readUncommittedDefault; 75 private boolean serializableIsolationDefault; 76 77 private Logger logger; 78 79 86 Cursor(Database dbHandle, Transaction txn, CursorConfig cursorConfig) 87 throws DatabaseException { 88 89 if (cursorConfig == null) { 90 cursorConfig = CursorConfig.DEFAULT; 91 } 92 93 Locker locker = LockerFactory.getReadableLocker 94 (dbHandle.getEnvironment(), 95 txn, 96 dbHandle.isTransactional(), 97 false, cursorConfig.getReadCommitted()); 99 100 init(dbHandle, dbHandle.getDatabaseImpl(), locker, 101 dbHandle.isWritable(), cursorConfig); 102 } 103 104 111 Cursor(Database dbHandle, Locker locker, CursorConfig cursorConfig) 112 throws DatabaseException { 113 114 if (cursorConfig == null) { 115 cursorConfig = CursorConfig.DEFAULT; 116 } 117 118 locker = LockerFactory.getReadableLocker 119 (dbHandle.getEnvironment(), 120 dbHandle, 121 locker, 122 false, cursorConfig.getReadCommitted()); 124 125 init(dbHandle, dbHandle.getDatabaseImpl(), locker, 126 dbHandle.isWritable(), cursorConfig); 127 } 128 129 136 Cursor(DatabaseImpl dbImpl, Locker locker, CursorConfig cursorConfig) 137 throws DatabaseException { 138 139 if (cursorConfig == null) { 140 cursorConfig = CursorConfig.DEFAULT; 141 } 142 143 init(null, dbImpl, locker, true, cursorConfig); 144 } 145 146 private void init(Database dbHandle, 147 DatabaseImpl dbImpl, 148 Locker locker, 149 boolean isWritable, 150 CursorConfig cursorConfig) 151 throws DatabaseException { 152 153 assert locker != null; 154 assert dbImpl != null; 155 156 cursorImpl = new CursorImpl(dbImpl, 157 locker, 158 false ); 159 160 161 cursorImpl.setAllowEviction(true); 162 163 readUncommittedDefault = 164 cursorConfig.getReadUncommitted() || 165 locker.isReadUncommittedDefault(); 166 167 serializableIsolationDefault = 168 cursorImpl.getLocker().isSerializableIsolation(); 169 170 updateOperationsProhibited = 171 (dbImpl.isTransactional() && !locker.isTransactional()) || 172 !isWritable; 173 174 this.dbImpl = dbImpl; 175 this.dbHandle = dbHandle; 176 if (dbHandle != null) { 177 dbHandle.addCursor(this); 178 } 179 this.config = cursorConfig; 180 this.logger = dbImpl.getDbEnvironment().getLogger(); 181 } 182 183 186 Cursor(Cursor cursor, boolean samePosition) 187 throws DatabaseException { 188 189 readUncommittedDefault = cursor.readUncommittedDefault; 190 serializableIsolationDefault = cursor.serializableIsolationDefault; 191 updateOperationsProhibited = cursor.updateOperationsProhibited; 192 193 cursorImpl = cursor.cursorImpl.dup(samePosition); 194 dbImpl = cursor.dbImpl; 195 dbHandle = cursor.dbHandle; 196 if (dbHandle != null) { 197 dbHandle.addCursor(this); 198 } 199 config = cursor.config; 200 logger = dbImpl.getDbEnvironment().getLogger(); 201 } 202 203 206 CursorImpl getCursorImpl() { 207 return cursorImpl; 208 } 209 210 214 public Database getDatabase() { 215 return dbHandle; 216 } 217 218 222 DatabaseImpl getDatabaseImpl() { 223 return dbImpl; 224 } 225 226 230 public CursorConfig getConfig() { 231 try { 232 return config.cloneConfig(); 233 } catch (Error E) { 234 dbImpl.getDbEnvironment().invalidate(E); 235 throw E; 236 } 237 } 238 239 void setNonCloning(boolean nonCloning) { 240 cursorImpl.setNonCloning(nonCloning); 241 } 242 243 247 public synchronized void close() 248 throws DatabaseException { 249 250 try { 251 checkState(false); 252 cursorImpl.close(); 253 if (dbHandle != null) { 254 dbHandle.removeCursor(this); 255 } 256 } catch (Error E) { 257 dbImpl.getDbEnvironment().invalidate(E); 258 throw E; 259 } 260 } 261 262 266 public int count() 267 throws DatabaseException { 268 269 checkState(true); 270 trace(Level.FINEST, "Cursor.count: ", null); 271 272 277 return countInternal(null); 278 } 279 280 284 public Cursor dup(boolean samePosition) 285 throws DatabaseException { 286 287 try { 288 checkState(false); 289 return new Cursor(this, samePosition); 290 } catch (Error E) { 291 dbImpl.getDbEnvironment().invalidate(E); 292 throw E; 293 } 294 } 295 296 300 public OperationStatus delete() 301 throws DatabaseException { 302 303 checkState(true); 304 checkUpdatesAllowed("delete"); 305 trace(Level.FINEST, "Cursor.delete: ", null); 306 307 return deleteInternal(); 308 } 309 310 314 public OperationStatus put(DatabaseEntry key, DatabaseEntry data) 315 throws DatabaseException { 316 317 checkState(false); 318 DatabaseUtil.checkForNullDbt(key, "key", true); 319 DatabaseUtil.checkForNullDbt(data, "data", true); 320 DatabaseUtil.checkForPartialKey(key); 321 checkUpdatesAllowed("put"); 322 trace(Level.FINEST, "Cursor.put: ", key, data, null); 323 324 return putInternal(key, data, PutMode.OVERWRITE); 325 } 326 327 331 public OperationStatus putNoOverwrite(DatabaseEntry key, 332 DatabaseEntry data) 333 throws DatabaseException { 334 335 checkState(false); 336 DatabaseUtil.checkForNullDbt(key, "key", true); 337 DatabaseUtil.checkForNullDbt(data, "data", true); 338 DatabaseUtil.checkForPartialKey(key); 339 checkUpdatesAllowed("putNoOverwrite"); 340 trace(Level.FINEST, "Cursor.putNoOverwrite: ", key, data, null); 341 342 return putInternal(key, data, PutMode.NOOVERWRITE); 343 } 344 345 349 public OperationStatus putNoDupData(DatabaseEntry key, DatabaseEntry data) 350 throws DatabaseException { 351 352 checkState(false); 353 DatabaseUtil.checkForNullDbt(key, "key", true); 354 DatabaseUtil.checkForNullDbt(data, "data", true); 355 DatabaseUtil.checkForPartialKey(key); 356 checkUpdatesAllowed("putNoDupData"); 357 trace(Level.FINEST, "Cursor.putNoDupData: ", key, data, null); 358 359 return putInternal(key, data, PutMode.NODUP); 360 } 361 362 366 public OperationStatus putCurrent(DatabaseEntry data) 367 throws DatabaseException { 368 369 checkState(true); 370 DatabaseUtil.checkForNullDbt(data, "data", true); 371 checkUpdatesAllowed("putCurrent"); 372 trace(Level.FINEST, "Cursor.putCurrent: ", null, data, null); 373 374 return putInternal(null, data, PutMode.CURRENT); 375 } 376 377 381 public OperationStatus getCurrent(DatabaseEntry key, 382 DatabaseEntry data, 383 LockMode lockMode) 384 throws DatabaseException { 385 386 try { 387 checkState(true); 388 checkArgsNoValRequired(key, data); 389 trace(Level.FINEST, "Cursor.getCurrent: ", lockMode); 390 391 return getCurrentInternal(key, data, lockMode); 392 } catch (Error E) { 393 dbImpl.getDbEnvironment().invalidate(E); 394 throw E; 395 } 396 } 397 398 402 public OperationStatus getFirst(DatabaseEntry key, 403 DatabaseEntry data, 404 LockMode lockMode) 405 throws DatabaseException { 406 407 checkState(false); 408 checkArgsNoValRequired(key, data); 409 trace(Level.FINEST, "Cursor.getFirst: ",lockMode); 410 411 return position(key, data, lockMode, true); 412 } 413 414 418 public OperationStatus getLast(DatabaseEntry key, 419 DatabaseEntry data, 420 LockMode lockMode) 421 throws DatabaseException { 422 423 checkState(false); 424 checkArgsNoValRequired(key, data); 425 trace(Level.FINEST, "Cursor.getLast: ", lockMode); 426 427 return position(key, data, lockMode, false); 428 } 429 430 434 public OperationStatus getNext(DatabaseEntry key, 435 DatabaseEntry data, 436 LockMode lockMode) 437 throws DatabaseException { 438 439 checkState(false); 440 checkArgsNoValRequired(key, data); 441 trace(Level.FINEST, "Cursor.getNext: ", lockMode); 442 443 if (cursorImpl.isNotInitialized()) { 444 return position(key, data, lockMode, true); 445 } else { 446 return retrieveNext(key, data, lockMode, GetMode.NEXT); 447 } 448 } 449 450 454 public OperationStatus getNextDup(DatabaseEntry key, 455 DatabaseEntry data, 456 LockMode lockMode) 457 throws DatabaseException { 458 459 checkState(true); 460 checkArgsNoValRequired(key, data); 461 trace(Level.FINEST, "Cursor.getNextDup: ", lockMode); 462 463 return retrieveNext(key, data, lockMode, GetMode.NEXT_DUP); 464 } 465 466 470 public OperationStatus getNextNoDup(DatabaseEntry key, 471 DatabaseEntry data, 472 LockMode lockMode) 473 throws DatabaseException { 474 475 checkState(false); 476 checkArgsNoValRequired(key, data); 477 trace(Level.FINEST, "Cursor.getNextNoDup: ", lockMode); 478 479 if (cursorImpl.isNotInitialized()) { 480 return position(key, data, lockMode, true); 481 } else { 482 return retrieveNext(key, data, lockMode, GetMode.NEXT_NODUP); 483 } 484 } 485 486 490 public OperationStatus getPrev(DatabaseEntry key, 491 DatabaseEntry data, 492 LockMode lockMode) 493 throws DatabaseException { 494 495 checkState(false); 496 checkArgsNoValRequired(key, data); 497 trace(Level.FINEST, "Cursor.getPrev: ", lockMode); 498 499 if (cursorImpl.isNotInitialized()) { 500 return position(key, data, lockMode, false); 501 } else { 502 return retrieveNext(key, data, lockMode, GetMode.PREV); 503 } 504 } 505 506 510 public OperationStatus getPrevDup(DatabaseEntry key, 511 DatabaseEntry data, 512 LockMode lockMode) 513 throws DatabaseException { 514 515 checkState(true); 516 checkArgsNoValRequired(key, data); 517 trace(Level.FINEST, "Cursor.getPrevDup: ", lockMode); 518 519 return retrieveNext(key, data, lockMode, GetMode.PREV_DUP); 520 } 521 522 526 public OperationStatus getPrevNoDup(DatabaseEntry key, 527 DatabaseEntry data, 528 LockMode lockMode) 529 throws DatabaseException { 530 531 checkState(false); 532 checkArgsNoValRequired(key, data); 533 trace(Level.FINEST, "Cursor.getPrevNoDup: ", lockMode); 534 535 if (cursorImpl.isNotInitialized()) { 536 return position(key, data, lockMode, false); 537 } else { 538 return retrieveNext(key, data, lockMode, GetMode.PREV_NODUP); 539 } 540 } 541 542 546 public OperationStatus getSearchKey(DatabaseEntry key, 547 DatabaseEntry data, 548 LockMode lockMode) 549 throws DatabaseException { 550 551 checkState(false); 552 DatabaseUtil.checkForNullDbt(key, "key", true); 553 DatabaseUtil.checkForNullDbt(data, "data", false); 554 trace(Level.FINEST, "Cursor.getSearchKey: ", key, null, lockMode); 555 556 return search(key, data, lockMode, SearchMode.SET); 557 } 558 559 563 public OperationStatus getSearchKeyRange(DatabaseEntry key, 564 DatabaseEntry data, 565 LockMode lockMode) 566 throws DatabaseException { 567 568 checkState(false); 569 DatabaseUtil.checkForNullDbt(key, "key", true); 570 DatabaseUtil.checkForNullDbt(data, "data", false); 571 trace(Level.FINEST, "Cursor.getSearchKeyRange: ", key, null, lockMode); 572 573 return search(key, data, lockMode, SearchMode.SET_RANGE); 574 } 575 576 580 public OperationStatus getSearchBoth(DatabaseEntry key, 581 DatabaseEntry data, 582 LockMode lockMode) 583 throws DatabaseException { 584 585 checkState(false); 586 checkArgsValRequired(key, data); 587 trace(Level.FINEST, "Cursor.getSearchBoth: ", key, data, lockMode); 588 589 return search(key, data, lockMode, SearchMode.BOTH); 590 } 591 592 596 public OperationStatus getSearchBothRange(DatabaseEntry key, 597 DatabaseEntry data, 598 LockMode lockMode) 599 throws DatabaseException { 600 601 checkState(false); 602 checkArgsValRequired(key, data); 603 trace(Level.FINEST, "Cursor.getSearchBothRange: ", key, data, 604 lockMode); 605 606 return search(key, data, lockMode, SearchMode.BOTH_RANGE); 607 } 608 609 612 int countInternal(LockMode lockMode) 613 throws DatabaseException { 614 615 try { 616 CursorImpl original = null; 617 CursorImpl dup = null; 618 619 624 try { 625 original = cursorImpl; 626 dup = original.cloneCursor(true); 627 return dup.count(getLockType(lockMode, false)); 628 } finally { 629 if (dup != original && 630 dup != null) { 631 dup.close(); 632 } 633 } 634 } catch (Error E) { 635 dbImpl.getDbEnvironment().invalidate(E); 636 throw E; 637 } 638 } 639 640 644 OperationStatus deleteInternal() 645 throws DatabaseException { 646 647 try { 648 649 DatabaseEntry oldKey = null; 650 DatabaseEntry oldData = null; 651 boolean doNotifyTriggers = 652 dbHandle != null && dbHandle.hasTriggers(); 653 if (doNotifyTriggers) { 654 oldKey = new DatabaseEntry(); 655 oldData = new DatabaseEntry(); 656 OperationStatus status = getCurrentInternal(oldKey, oldData, 657 LockMode.RMW); 658 if (status != OperationStatus.SUCCESS) { 659 return OperationStatus.KEYEMPTY; 660 } 661 } 662 663 668 if (doNotifyTriggers) { 669 dbHandle.notifyTriggers(cursorImpl.getLocker(), 670 oldKey, oldData, null); 671 } 672 673 674 OperationStatus status = deleteNoNotify(); 675 return status; 676 } catch (Error E) { 677 dbImpl.getDbEnvironment().invalidate(E); 678 throw E; 679 } 680 } 681 682 686 OperationStatus deleteNoNotify() 687 throws DatabaseException { 688 689 CursorImpl original = null; 690 CursorImpl dup = null; 691 OperationStatus status = OperationStatus.KEYEMPTY; 692 try { 693 694 original = cursorImpl; 695 dup = original.cloneCursor(true); 696 697 698 dup.latchBINs(); 699 status = dup.delete(); 700 701 return status; 702 } finally { 703 if (original != null) { 704 original.releaseBINs(); 705 } 706 if (dup != null) { 707 dup.releaseBINs(); 708 } 709 710 711 boolean success = (status == OperationStatus.SUCCESS); 712 if (cursorImpl == dup) { 713 if (!success) { 714 cursorImpl.reset(); 715 } 716 } else { 717 if (success) { 718 original.close(); 719 cursorImpl = dup; 720 } else { 721 dup.close(); 722 } 723 } 724 } 725 } 726 727 732 OperationStatus putInternal(DatabaseEntry key, 733 DatabaseEntry data, 734 PutMode putMode) 735 throws DatabaseException { 736 737 try { 738 739 DatabaseEntry oldData = null; 740 boolean doNotifyTriggers = 741 dbHandle != null && dbHandle.hasTriggers(); 742 if (doNotifyTriggers && (putMode == PutMode.CURRENT || 743 putMode == PutMode.OVERWRITE)) { 744 oldData = new DatabaseEntry(); 745 if (key == null && putMode == PutMode.CURRENT) { 746 747 key = new DatabaseEntry(); 748 } 749 } 750 751 752 OperationStatus commitStatus = 753 putNoNotify(key, data, putMode, oldData); 754 755 756 if (doNotifyTriggers && commitStatus == OperationStatus.SUCCESS) { 757 if (oldData != null && oldData.getData() == null) { 758 oldData = null; 759 } 760 dbHandle.notifyTriggers(cursorImpl.getLocker(), key, 761 oldData, data); 762 } 763 return commitStatus; 764 } catch (Error E) { 765 dbImpl.getDbEnvironment().invalidate(E); 766 throw E; 767 } 768 } 769 770 774 OperationStatus putNoNotify(DatabaseEntry key, 775 DatabaseEntry data, 776 PutMode putMode, 777 DatabaseEntry returnOldData) 778 throws DatabaseException { 779 780 Locker nextKeyLocker = null; 781 CursorImpl nextKeyCursor = null; 782 try { 783 784 Locker cursorLocker = cursorImpl.getLocker(); 785 if (putMode != PutMode.CURRENT && 786 dbImpl.getDbEnvironment() 787 .getTxnManager() 788 .areOtherSerializableTransactionsActive(cursorLocker)) { 789 nextKeyLocker = new BuddyLocker 790 (dbImpl.getDbEnvironment(), cursorLocker); 791 nextKeyCursor = new CursorImpl(dbImpl, nextKeyLocker); 792 793 nextKeyCursor.setAllowEviction(true); 794 nextKeyCursor.lockNextKeyForInsert(key, data); 795 } 796 797 798 return putAllowPhantoms 799 (key, data, putMode, returnOldData, nextKeyCursor); 800 } finally { 801 802 if (nextKeyCursor != null) { 803 nextKeyCursor.close(); 804 } 805 if (nextKeyLocker != null) { 806 nextKeyLocker.operationEnd(); 807 } 808 } 809 } 810 811 821 private OperationStatus putAllowPhantoms(DatabaseEntry key, 822 DatabaseEntry data, 823 PutMode putMode, 824 DatabaseEntry returnOldData, 825 CursorImpl nextKeyCursor) 826 throws DatabaseException { 827 828 if (data == null) { 829 throw new NullPointerException 830 ("put passed a null DatabaseEntry arg"); 831 } 832 833 if (putMode != PutMode.CURRENT && key == null) { 834 throw new IllegalArgumentException 835 ("put passed a null DatabaseEntry arg"); 836 } 837 838 CursorImpl original = null; 839 OperationStatus status = OperationStatus.NOTFOUND; 840 CursorImpl dup = null; 841 try { 842 843 original = cursorImpl; 844 845 if (putMode == PutMode.CURRENT) { 846 847 dup = original.cloneCursor(true); 848 } else { 849 850 854 dup = original.cloneCursor(false, nextKeyCursor); 855 } 856 857 858 if (putMode == PutMode.CURRENT) { 859 status = dup.putCurrent(data, key, returnOldData); 860 } else if (putMode == PutMode.OVERWRITE) { 861 status = dup.put(key, data, returnOldData); 862 } else if (putMode == PutMode.NOOVERWRITE) { 863 status = dup.putNoOverwrite(key, data); 864 } else if (putMode == PutMode.NODUP) { 865 status = dup.putNoDupData(key, data); 866 } else { 867 throw new InternalException("unknown PutMode"); 868 } 869 870 return status; 871 } finally { 872 if (original != null) { 873 original.releaseBINs(); 874 } 875 876 boolean success = (status == OperationStatus.SUCCESS); 877 if (cursorImpl == dup) { 878 if (!success) { 879 cursorImpl.reset(); 880 } 881 } else { 882 if (success) { 883 original.close(); 884 cursorImpl = dup; 885 } else { 886 if (dup != null) { 887 dup.close(); 888 } 889 } 890 } 891 } 892 } 893 894 898 OperationStatus position(DatabaseEntry key, 899 DatabaseEntry data, 900 LockMode lockMode, 901 boolean first) 902 throws DatabaseException { 903 904 try { 905 if (!isSerializableIsolation(lockMode)) { 906 return positionAllowPhantoms 907 (key, data, getLockType(lockMode, false), first); 908 } 909 910 913 while (true) { 914 try { 915 916 if (!first) { 917 cursorImpl.lockEofNode(LockType.RANGE_READ); 918 } 919 920 921 LockType lockType = getLockType(lockMode, first); 922 923 924 OperationStatus status = 925 positionAllowPhantoms(key, data, lockType, first); 926 927 930 if (first && status != OperationStatus.SUCCESS) { 931 cursorImpl.lockEofNode(LockType.RANGE_READ); 932 } 933 934 return status; 935 } catch (RangeRestartException e) { 936 continue; 937 } 938 } 939 } catch (Error E) { 940 dbImpl.getDbEnvironment().invalidate(E); 941 throw E; 942 } 943 } 944 945 948 private OperationStatus positionAllowPhantoms(DatabaseEntry key, 949 DatabaseEntry data, 950 LockType lockType, 951 boolean first) 952 throws DatabaseException { 953 954 assert (key != null && data != null); 955 956 OperationStatus status = OperationStatus.NOTFOUND; 957 CursorImpl dup = null; 958 try { 959 960 964 dup = beginRead(false); 965 966 967 if (!dup.positionFirstOrLast(first, null)) { 968 969 status = OperationStatus.NOTFOUND; 970 assert LatchSupport.countLatchesHeld() == 0: 971 LatchSupport.latchesHeldToString(); 972 973 } else { 974 975 assert LatchSupport.countLatchesHeld() == 1: 976 LatchSupport.latchesHeldToString(); 977 status = dup.getCurrentAlreadyLatched 978 (key, data, lockType, first); 979 980 if (status == OperationStatus.SUCCESS) { 981 if (dup.getDupBIN() != null) { 982 dup.incrementLNCount(); 983 } 984 } else { 985 986 status = dup.getNext(key, data, lockType, first, false); 987 } 988 } 989 } finally { 990 991 996 cursorImpl.releaseBINs(); 997 endRead(dup, status == OperationStatus.SUCCESS); 998 } 999 return status; 1000 } 1001 1002 1005 OperationStatus search(DatabaseEntry key, 1006 DatabaseEntry data, 1007 LockMode lockMode, 1008 SearchMode searchMode) 1009 throws DatabaseException { 1010 1011 try { 1012 if (!isSerializableIsolation(lockMode)) { 1013 LockType lockType = getLockType(lockMode, false); 1014 KeyChangeStatus result = searchAllowPhantoms 1015 (key, data, lockType, lockType, searchMode); 1016 return result.status; 1017 } 1018 1019 1022 while (true) { 1023 try { 1024 1025 LockType searchLockType = getLockType(lockMode, false); 1026 1027 1028 LockType advanceLockType = getLockType(lockMode, true); 1029 1030 1031 DatabaseEntry tryKey = new DatabaseEntry 1032 (key.getData(), key.getOffset(), key.getSize()); 1033 DatabaseEntry tryData = new DatabaseEntry 1034 (data.getData(), data.getOffset(), data.getSize()); 1035 KeyChangeStatus result; 1036 1037 if (searchMode.isExactSearch()) { 1038 1039 1042 result = searchExactAndRangeLock 1043 (tryKey, tryData, searchLockType, advanceLockType, 1044 searchMode); 1045 } else { 1046 1047 result = searchAllowPhantoms 1048 (tryKey, tryData, searchLockType, advanceLockType, 1049 searchMode); 1050 1051 1052 if (result.status != OperationStatus.SUCCESS) { 1053 cursorImpl.lockEofNode(LockType.RANGE_READ); 1054 } 1055 } 1056 1057 1060 if (result.status == OperationStatus.SUCCESS) { 1061 key.setData(tryKey.getData(), 0, tryKey.getSize()); 1062 data.setData(tryData.getData(), 0, tryData.getSize()); 1063 } 1064 1065 return result.status; 1066 } catch (RangeRestartException e) { 1067 continue; 1068 } 1069 } 1070 } catch (Error E) { 1071 dbImpl.getDbEnvironment().invalidate(E); 1072 throw E; 1073 } 1074 } 1075 1076 1084 private KeyChangeStatus searchExactAndRangeLock(DatabaseEntry key, 1085 DatabaseEntry data, 1086 LockType searchLockType, 1087 LockType advanceLockType, 1088 SearchMode searchMode) 1089 throws DatabaseException { 1090 1091 1092 searchMode = (searchMode == SearchMode.SET) ? 1093 SearchMode.SET_RANGE : SearchMode.BOTH_RANGE; 1094 1095 KeyChangeStatus result = null; 1096 boolean noNextKeyFound; 1097 1098 CursorImpl dup = 1099 beginRead(false ); 1100 1101 try { 1102 1103 1108 result = searchInternal 1109 (dup, key, data, searchLockType, advanceLockType, searchMode, 1110 true ); 1111 1112 1113 noNextKeyFound = !result.keyChange; 1114 1115 1116 if (result.keyChange && result.status == OperationStatus.SUCCESS) { 1117 result.status = OperationStatus.NOTFOUND; 1118 } 1119 } finally { 1120 endRead(dup, result != null && 1121 result.status == OperationStatus.SUCCESS); 1122 } 1123 1124 1125 if (noNextKeyFound) { 1126 cursorImpl.lockEofNode(LockType.RANGE_READ); 1127 } 1128 1129 return result; 1130 } 1131 1132 1135 private KeyChangeStatus searchAllowPhantoms(DatabaseEntry key, 1136 DatabaseEntry data, 1137 LockType searchLockType, 1138 LockType advanceLockType, 1139 SearchMode searchMode) 1140 throws DatabaseException { 1141 1142 OperationStatus status = OperationStatus.NOTFOUND; 1143 1144 CursorImpl dup = 1145 beginRead(false ); 1146 1147 try { 1148 KeyChangeStatus result = searchInternal 1149 (dup, key, data, searchLockType, advanceLockType, searchMode, 1150 false ); 1151 1152 status = result.status; 1153 return result; 1154 } finally { 1155 endRead(dup, status == OperationStatus.SUCCESS); 1156 } 1157 } 1158 1159 1162 private KeyChangeStatus searchInternal(CursorImpl dup, 1163 DatabaseEntry key, 1164 DatabaseEntry data, 1165 LockType searchLockType, 1166 LockType advanceLockType, 1167 SearchMode searchMode, 1168 boolean advanceAfterRangeSearch) 1169 throws DatabaseException { 1170 1171 assert key != null && data != null; 1172 1173 OperationStatus status = OperationStatus.NOTFOUND; 1174 boolean keyChange = false; 1175 1176 try { 1177 1178 int searchResult = 1179 dup.searchAndPosition(key, data, searchMode, searchLockType); 1180 if ((searchResult & CursorImpl.FOUND) != 0) { 1181 1182 1220 boolean exactKeyMatch = 1221 ((searchResult & CursorImpl.EXACT_KEY) != 0); 1222 boolean exactDataMatch = 1223 ((searchResult & CursorImpl.EXACT_DATA) != 0); 1224 boolean foundLast = 1225 ((searchResult & CursorImpl.FOUND_LAST) != 0); 1226 1227 1235 boolean rangeMatch = false; 1236 if (searchMode == SearchMode.SET_RANGE && 1237 !exactKeyMatch) { 1238 rangeMatch = true; 1239 } 1240 1241 if (searchMode == SearchMode.BOTH_RANGE && 1242 (!exactKeyMatch || !exactDataMatch)) { 1243 rangeMatch = true; 1244 } 1245 1246 1250 DatabaseEntry useKey = 1251 (searchMode == SearchMode.SET) ? 1252 null : key; 1253 1254 1264 if (rangeMatch || 1265 (status = dup.getCurrentAlreadyLatched 1266 (useKey, data, searchLockType, true)) == 1267 OperationStatus.KEYEMPTY) { 1268 1269 if (foundLast) { 1270 status = OperationStatus.NOTFOUND; 1271 } else if (searchMode == SearchMode.SET) { 1272 1273 1278 status = dup.getNextDuplicate 1279 (key, data, advanceLockType, true, rangeMatch); 1280 } else if (searchMode == SearchMode.BOTH) { 1281 1282 1288 if (status == OperationStatus.KEYEMPTY) { 1289 status = OperationStatus.NOTFOUND; 1290 } 1291 } else { 1292 assert !searchMode.isExactSearch(); 1293 1294 1295 byte[] searchKey = null; 1296 if (searchMode.isDataSearch()) { 1297 searchKey = Key.makeKey(key); 1298 } 1299 1300 1305 if (exactKeyMatch) { 1306 KeyChangeStatus result = 1307 dup.getNextWithKeyChangeStatus 1308 (key, data, advanceLockType, true, rangeMatch); 1309 status = result.status; 1310 1311 1317 keyChange = searchMode.isDataSearch() ? 1318 (status == OperationStatus.SUCCESS) : 1319 result.keyChange; 1320 1321 } else if (searchMode.isDataSearch() && 1322 !advanceAfterRangeSearch) { 1323 1324 1329 status = OperationStatus.NOTFOUND; 1330 } else { 1331 1332 1336 status = dup.getNextNoDup 1337 (key, data, advanceLockType, true, rangeMatch); 1338 1339 1340 keyChange = (status == OperationStatus.SUCCESS); 1341 } 1342 1343 1349 if (status == OperationStatus.SUCCESS && 1350 searchMode.isDataSearch()) { 1351 if (Key.compareKeys 1352 (key.getData(), searchKey, 1353 dbImpl.getBtreeComparator()) != 0) { 1354 status = OperationStatus.NOTFOUND; 1355 } 1356 } 1357 } 1358 } 1359 } 1360 } finally { 1361 1362 1367 cursorImpl.releaseBINs(); 1368 if (status != OperationStatus.SUCCESS && dup != cursorImpl) { 1369 dup.releaseBINs(); 1370 } 1371 } 1372 1373 return new KeyChangeStatus(status, keyChange); 1374 } 1375 1376 1379 OperationStatus retrieveNext(DatabaseEntry key, 1380 DatabaseEntry data, 1381 LockMode lockMode, 1382 GetMode getMode) 1383 throws DatabaseException { 1384 1385 try { 1386 if (!isSerializableIsolation(lockMode)) { 1387 return retrieveNextAllowPhantoms 1388 (key, data, getLockType(lockMode, false), getMode); 1389 } 1390 1391 1394 while (true) { 1395 try { 1396 OperationStatus status; 1397 if (getMode == GetMode.NEXT_DUP) { 1398 1399 1402 status = getNextDupAndRangeLock(key, data, lockMode); 1403 } else { 1404 1405 1406 if (!getMode.isForward()) { 1407 rangeLockCurrentPosition(getMode); 1408 } 1409 1410 1413 LockType lockType = 1414 getLockType(lockMode, getMode.isForward()); 1415 1416 1417 status = retrieveNextAllowPhantoms 1418 (key, data, lockType, getMode); 1419 1420 if (getMode.isForward() && 1421 status != OperationStatus.SUCCESS) { 1422 1423 cursorImpl.lockEofNode(LockType.RANGE_READ); 1424 } 1425 } 1426 1427 return status; 1428 } catch (RangeRestartException e) { 1429 continue; 1430 } 1431 } 1432 } catch (Error E) { 1433 dbImpl.getDbEnvironment().invalidate(E); 1434 throw E; 1435 } 1436 } 1437 1438 1444 private OperationStatus getNextDupAndRangeLock(DatabaseEntry key, 1445 DatabaseEntry data, 1446 LockMode lockMode) 1447 throws DatabaseException { 1448 1449 1450 DatabaseEntry tryKey = new DatabaseEntry(); 1451 DatabaseEntry tryData = new DatabaseEntry(); 1452 1453 1454 LockType lockType = getLockType(lockMode, true); 1455 OperationStatus status; 1456 boolean noNextKeyFound; 1457 1458 1462 while (true) { 1463 assert LatchSupport.countLatchesHeld() == 0; 1464 CursorImpl dup = beginRead(true); 1465 1466 try { 1467 KeyChangeStatus result = dup.getNextWithKeyChangeStatus 1468 (tryKey, tryData, lockType, true, false); 1469 status = result.status; 1470 noNextKeyFound = (status != OperationStatus.SUCCESS); 1471 if (result.keyChange && status == OperationStatus.SUCCESS) { 1472 status = OperationStatus.NOTFOUND; 1473 } 1474 } catch (DatabaseException DBE) { 1475 endRead(dup, false); 1476 throw DBE; 1477 } 1478 1479 if (checkForInsertion(GetMode.NEXT, cursorImpl, dup)) { 1480 endRead(dup, false); 1481 continue; 1482 } else { 1483 endRead(dup, status == OperationStatus.SUCCESS); 1484 assert LatchSupport.countLatchesHeld() == 0; 1485 break; 1486 } 1487 } 1488 1489 1490 if (noNextKeyFound) { 1491 cursorImpl.lockEofNode(LockType.RANGE_READ); 1492 } 1493 1494 1495 if (status == OperationStatus.SUCCESS) { 1496 key.setData(tryKey.getData(), 0, tryKey.getSize()); 1497 data.setData(tryData.getData(), 0, tryData.getSize()); 1498 } 1499 1500 return status; 1501 } 1502 1503 1510 private void rangeLockCurrentPosition(GetMode getMode) 1511 throws DatabaseException { 1512 1513 DatabaseEntry tempKey = new DatabaseEntry(); 1514 DatabaseEntry tempData = new DatabaseEntry(); 1515 tempKey.setPartial(0, 0, true); 1516 tempData.setPartial(0, 0, true); 1517 1518 OperationStatus status; 1519 CursorImpl dup = cursorImpl.cloneCursor(true); 1520 try { 1521 if (getMode == GetMode.PREV_NODUP) { 1522 status = dup.getFirstDuplicate 1523 (tempKey, tempData, LockType.RANGE_READ); 1524 } else { 1525 status = dup.getCurrent 1526 (tempKey, tempData, LockType.RANGE_READ); 1527 } 1528 if (status != OperationStatus.SUCCESS) { 1529 while (true) { 1530 assert LatchSupport.countLatchesHeld() == 0; 1531 1532 status = dup.getNext 1533 (tempKey, tempData, LockType.RANGE_READ, true, false); 1534 1535 if (checkForInsertion(GetMode.NEXT, cursorImpl, dup)) { 1536 dup.close(); 1537 dup = cursorImpl.cloneCursor(true); 1538 continue; 1539 } else { 1540 assert LatchSupport.countLatchesHeld() == 0; 1541 break; 1542 } 1543 } 1544 } 1545 } finally { 1546 if (cursorImpl == dup) { 1547 dup.reset(); 1548 } else { 1549 dup.close(); 1550 } 1551 } 1552 1553 if (status != OperationStatus.SUCCESS) { 1554 cursorImpl.lockEofNode(LockType.RANGE_READ); 1555 } 1556 } 1557 1558 1561 private OperationStatus retrieveNextAllowPhantoms(DatabaseEntry key, 1562 DatabaseEntry data, 1563 LockType lockType, 1564 GetMode getMode) 1565 throws DatabaseException { 1566 1567 assert (key != null && data != null); 1568 1569 OperationStatus status; 1570 1571 while (true) { 1572 assert LatchSupport.countLatchesHeld() == 0; 1573 CursorImpl dup = beginRead(true); 1574 1575 try { 1576 if (getMode == GetMode.NEXT) { 1577 status = dup.getNext 1578 (key, data, lockType, true, false); 1579 } else if (getMode == GetMode.PREV) { 1580 status = dup.getNext 1581 (key, data, lockType, false, false); 1582 } else if (getMode == GetMode.NEXT_DUP) { 1583 status = dup.getNextDuplicate 1584 (key, data, lockType, true, false); 1585 } else if (getMode == GetMode.PREV_DUP) { 1586 status = dup.getNextDuplicate 1587 (key, data, lockType, false, false); 1588 } else if (getMode == GetMode.NEXT_NODUP) { 1589 status = dup.getNextNoDup 1590 (key, data, lockType, true, false); 1591 } else if (getMode == GetMode.PREV_NODUP) { 1592 status = dup.getNextNoDup 1593 (key, data, lockType, false, false); 1594 } else { 1595 throw new InternalException("unknown GetMode"); 1596 } 1597 } catch (DatabaseException DBE) { 1598 endRead(dup, false); 1599 throw DBE; 1600 } 1601 1602 if (checkForInsertion(getMode, cursorImpl, dup)) { 1603 endRead(dup, false); 1604 continue; 1605 } else { 1606 endRead(dup, status == OperationStatus.SUCCESS); 1607 assert LatchSupport.countLatchesHeld() == 0; 1608 break; 1609 } 1610 } 1611 return status; 1612 } 1613 1614 1617 OperationStatus getCurrentInternal(DatabaseEntry key, 1618 DatabaseEntry data, 1619 LockMode lockMode) 1620 throws DatabaseException { 1621 1622 1623 LockType lockType = getLockType(lockMode, false); 1624 1625 return cursorImpl.getCurrent(key, data, lockType); 1626 } 1627 1628 1639 private boolean checkForInsertion(GetMode getMode, 1640 CursorImpl origCursor, 1641 CursorImpl dupCursor) 1642 throws DatabaseException { 1643 1644 BIN origBIN = origCursor.getBIN(); 1645 BIN dupBIN = dupCursor.getBIN(); 1646 DBIN origDBIN = origCursor.getDupBIN(); 1647 1648 1649 1650 boolean forward = true; 1651 if (getMode == GetMode.PREV || 1652 getMode == GetMode.PREV_DUP || 1653 getMode == GetMode.PREV_NODUP) { 1654 forward = false; 1655 } 1656 boolean ret = false; 1657 if (origBIN != dupBIN) { 1658 1659 origCursor.latchBINs(); 1660 1661 try { 1662 if (origDBIN == null) { 1663 if (forward) { 1664 if (origBIN.getNEntries() - 1 > 1665 origCursor.getIndex()) { 1666 1667 1671 for (int i = origCursor.getIndex() + 1; 1672 i < origBIN.getNEntries(); 1673 i++) { 1674 if (!origBIN.isEntryKnownDeleted(i)) { 1675 Node n = origBIN.fetchTarget(i); 1676 if (n != null && !n.containsDuplicates()) { 1677 LN ln = (LN) n; 1678 1679 if (!ln.isDeleted()) { 1680 ret = true; 1681 break; 1682 } 1683 } 1684 } else { 1685 1686 } 1687 } 1688 } 1689 } else { 1690 if (origCursor.getIndex() > 0) { 1691 1692 1696 for (int i = 0; i < origCursor.getIndex(); i++) { 1697 if (!origBIN.isEntryKnownDeleted(i)) { 1698 Node n = origBIN.fetchTarget(i); 1699 if (n != null && !n.containsDuplicates()) { 1700 LN ln = (LN) n; 1701 1702 if (!ln.isDeleted()) { 1703 ret = true; 1704 break; 1705 } 1706 } else { 1707 1708 } 1709 } 1710 } 1711 } 1712 } 1713 } 1714 } finally { 1715 origCursor.releaseBINs(); 1716 } 1717 return ret; 1718 } 1719 1720 if (origDBIN != dupCursor.getDupBIN() && 1721 origCursor.getIndex() == dupCursor.getIndex() && 1722 getMode != GetMode.NEXT_NODUP && 1723 getMode != GetMode.PREV_NODUP) { 1724 1725 origCursor.latchBINs(); 1726 try { 1727 if (forward) { 1728 if (origDBIN.getNEntries() - 1 > 1729 origCursor.getDupIndex()) { 1730 1731 1735 for (int i = origCursor.getDupIndex() + 1; 1736 i < origDBIN.getNEntries(); 1737 i++) { 1738 if (!origDBIN.isEntryKnownDeleted(i)) { 1739 Node n = origDBIN.fetchTarget(i); 1740 LN ln = (LN) n; 1741 1742 if (n != null && !ln.isDeleted()) { 1743 ret = true; 1744 break; 1745 } 1746 } 1747 } 1748 } 1749 } else { 1750 if (origCursor.getDupIndex() > 0) { 1751 1752 1756 for (int i = 0; i < origCursor.getDupIndex(); i++) { 1757 if (!origDBIN.isEntryKnownDeleted(i)) { 1758 Node n = origDBIN.fetchTarget(i); 1759 LN ln = (LN) n; 1760 1761 if (n != null && !ln.isDeleted()) { 1762 ret = true; 1763 break; 1764 } 1765 } 1766 } 1767 } 1768 } 1769 } finally { 1770 origCursor.releaseBINs(); 1771 } 1772 return ret; 1773 } 1774 return false; 1775 } 1776 1777 1783 private CursorImpl beginRead(boolean addCursor) 1784 throws DatabaseException { 1785 1786 CursorImpl dup; 1787 if (cursorImpl.isNotInitialized()) { 1788 dup = cursorImpl; 1789 } else { 1790 dup = cursorImpl.cloneCursor(addCursor); 1791 } 1792 return dup; 1793 } 1794 1795 1801 private void endRead(CursorImpl dup, boolean success) 1802 throws DatabaseException { 1803 1804 if (dup == cursorImpl) { 1805 if (!success) { 1806 cursorImpl.reset(); 1807 } 1808 } else { 1809 if (success) { 1810 cursorImpl.close(); 1811 cursorImpl = dup; 1812 } else { 1813 dup.close(); 1814 } 1815 } 1816 } 1817 1818 boolean advanceCursor(DatabaseEntry key, DatabaseEntry data) { 1819 return cursorImpl.advanceCursor(key, data); 1820 } 1821 1822 private LockType getLockType(LockMode lockMode, boolean rangeLock) { 1823 1824 if (isReadUncommittedMode(lockMode)) { 1825 return LockType.NONE; 1826 } else if (lockMode == null || lockMode == LockMode.DEFAULT) { 1827 return rangeLock ? LockType.RANGE_READ: LockType.READ; 1828 } else if (lockMode == LockMode.RMW) { 1829 return rangeLock ? LockType.RANGE_WRITE: LockType.WRITE; 1830 } else if (lockMode == LockMode.READ_COMMITTED) { 1831 throw new IllegalArgumentException 1832 (lockMode.toString() + " not allowed with Cursor methods"); 1833 } else { 1834 assert false : lockMode; 1835 return LockType.NONE; 1836 } 1837 } 1838 1839 1844 boolean isReadUncommittedMode(LockMode lockMode) { 1845 1846 return (lockMode == LockMode.READ_UNCOMMITTED || 1847 (readUncommittedDefault && 1848 (lockMode == null || lockMode == LockMode.DEFAULT))); 1849 } 1850 1851 private boolean isSerializableIsolation(LockMode lockMode) { 1852 1853 return serializableIsolationDefault && 1854 !isReadUncommittedMode(lockMode); 1855 } 1856 1857 protected void checkUpdatesAllowed(String operation) 1858 throws DatabaseException { 1859 1860 if (updateOperationsProhibited) { 1861 throw new DatabaseException 1862 ("A transaction was not supplied when opening this cursor: " + 1863 operation); 1864 } 1865 } 1866 1867 1871 private void checkArgsNoValRequired(DatabaseEntry key, 1872 DatabaseEntry data) { 1873 DatabaseUtil.checkForNullDbt(key, "key", false); 1874 DatabaseUtil.checkForNullDbt(data, "data", false); 1875 } 1876 1877 1880 private void checkArgsValRequired(DatabaseEntry key, 1881 DatabaseEntry data) { 1882 DatabaseUtil.checkForNullDbt(key, "key", true); 1883 DatabaseUtil.checkForNullDbt(data, "data", true); 1884 } 1885 1886 1889 void checkState(boolean mustBeInitialized) 1890 throws DatabaseException { 1891 1892 checkEnv(); 1893 cursorImpl.checkCursorState(mustBeInitialized); 1894 } 1895 1896 1899 void checkEnv() 1900 throws RunRecoveryException { 1901 1902 cursorImpl.checkEnv(); 1903 } 1904 1905 1910 void trace(Level level, 1911 String methodName, 1912 DatabaseEntry key, 1913 DatabaseEntry data, 1914 LockMode lockMode) { 1915 if (logger.isLoggable(level)) { 1916 StringBuffer sb = new StringBuffer (); 1917 sb.append(methodName); 1918 traceCursorImpl(sb); 1919 if (key != null) { 1920 sb.append(" key=").append(key.dumpData()); 1921 } 1922 if (data != null) { 1923 sb.append(" data=").append(data.dumpData()); 1924 } 1925 if (lockMode != null) { 1926 sb.append(" lockMode=").append(lockMode); 1927 } 1928 logger.log(level, sb.toString()); 1929 } 1930 } 1931 1936 void trace(Level level, String methodName, LockMode lockMode) { 1937 if (logger.isLoggable(level)) { 1938 StringBuffer sb = new StringBuffer (); 1939 sb.append(methodName); 1940 traceCursorImpl(sb); 1941 if (lockMode != null) { 1942 sb.append(" lockMode=").append(lockMode); 1943 } 1944 logger.log(level, sb.toString()); 1945 } 1946 } 1947 1948 private void traceCursorImpl(StringBuffer sb) { 1949 sb.append(" locker=").append(cursorImpl.getLocker().getId()); 1950 if (cursorImpl.getBIN() != null) { 1951 sb.append(" bin=").append(cursorImpl.getBIN().getNodeId()); 1952 } 1953 sb.append(" idx=").append(cursorImpl.getIndex()); 1954 1955 if (cursorImpl.getDupBIN() != null) { 1956 sb.append(" Dbin=").append(cursorImpl.getDupBIN().getNodeId()); 1957 } 1958 sb.append(" dupIdx=").append(cursorImpl.getDupIndex()); 1959 } 1960} 1961 | Popular Tags |