1 9 10 package com.sleepycat.collections; 11 12 import com.sleepycat.compat.DbCompat; 13 import com.sleepycat.je.Cursor; 14 import com.sleepycat.je.CursorConfig; 15 import com.sleepycat.je.DatabaseEntry; 16 import com.sleepycat.je.DatabaseException; 17 import com.sleepycat.je.LockMode; 18 import com.sleepycat.je.OperationStatus; 19 import com.sleepycat.je.SecondaryCursor; 20 21 32 class RangeCursor implements Cloneable { 33 34 38 private Cursor cursor; 39 private SecondaryCursor secCursor; 40 private CurrentTransaction currentTxn; 41 private boolean writeCursor; 42 43 47 private KeyRange range; 48 49 57 private boolean isRecnoOrQueue; 58 59 66 private DatabaseEntry privKey; 67 private DatabaseEntry privPKey; 68 private DatabaseEntry privData; 69 70 79 private boolean initialized; 80 81 84 RangeCursor(DataView view, KeyRange range, boolean writeAllowed) 85 throws DatabaseException { 86 87 this.range = range; 88 this.currentTxn = view.currentTxn; 89 isRecnoOrQueue = view.recNumAllowed && !view.btreeRecNumDb; 90 91 97 writeCursor = DbCompat.getWriteCursor(view.cursorConfig) || 98 (view.cursorConfig == CursorConfig.DEFAULT && writeAllowed); 99 100 cursor = currentTxn.openCursor(view.db, view.cursorConfig, writeCursor, 101 view.useTransaction()); 102 init(); 103 } 104 105 110 RangeCursor dup(boolean samePosition) 111 throws DatabaseException { 112 113 try { 114 RangeCursor c = (RangeCursor) super.clone(); 115 c.cursor = currentTxn.dupCursor(cursor, writeCursor, 116 samePosition); 117 c.init(); 118 return c; 119 } catch (CloneNotSupportedException neverHappens) { 120 return null; 121 } 122 } 123 124 127 private void init() { 128 129 if (cursor instanceof SecondaryCursor) { 130 secCursor = (SecondaryCursor) cursor; 131 } else { 132 secCursor = null; 133 } 134 135 if (range.hasBound()) { 136 privKey = new DatabaseEntry(); 137 privPKey = new DatabaseEntry(); 138 privData = new DatabaseEntry(); 139 } else { 140 privKey = null; 141 privPKey = null; 142 privData = null; 143 } 144 } 145 146 149 Cursor getCursor() { 150 return cursor; 151 } 152 153 158 private void setParams(DatabaseEntry key, DatabaseEntry pKey, 159 DatabaseEntry data) { 160 privKey = key; 161 privPKey = pKey; 162 privData = data; 163 } 164 165 174 private Cursor beginOperation() 175 throws DatabaseException { 176 177 Cursor oldCursor = cursor; 178 if (initialized) { 179 cursor = currentTxn.dupCursor(cursor, writeCursor, true); 180 if (secCursor != null) { 181 secCursor = (SecondaryCursor) cursor; 182 } 183 } else { 184 return cursor; 185 } 186 return oldCursor; 187 } 188 189 197 private void endOperation(Cursor oldCursor, OperationStatus status, 198 DatabaseEntry key, DatabaseEntry pKey, 199 DatabaseEntry data) 200 throws DatabaseException { 201 202 if (status == OperationStatus.SUCCESS) { 203 if (oldCursor != null && oldCursor != cursor) { 204 currentTxn.closeCursor(oldCursor); 205 } 206 if (key != null) { 207 swapData(key, privKey); 208 } 209 if (pKey != null && secCursor != null) { 210 swapData(pKey, privPKey); 211 } 212 if (data != null) { 213 swapData(data, privData); 214 } 215 initialized = true; 216 } else { 217 if (oldCursor != null && oldCursor != cursor) { 218 currentTxn.closeCursor(cursor); 219 cursor = oldCursor; 220 if (secCursor != null) { 221 secCursor = (SecondaryCursor) cursor; 222 } 223 } 224 } 225 } 226 227 231 private static void swapData(DatabaseEntry e1, DatabaseEntry e2) { 232 233 byte[] d1 = e1.getData(); 234 int o1 = e1.getOffset(); 235 int s1 = e1.getSize(); 236 237 e1.setData(e2.getData(), e2.getOffset(), e2.getSize()); 238 e2.setData(d1, o1, s1); 239 } 240 241 247 private static void shareData(DatabaseEntry from, DatabaseEntry to) { 248 249 if (from != null) { 250 to.setData(from.getData(), from.getOffset(), from.getSize()); 251 } 252 } 253 254 public OperationStatus getFirst(DatabaseEntry key, 255 DatabaseEntry pKey, 256 DatabaseEntry data, 257 LockMode lockMode) 258 throws DatabaseException { 259 260 OperationStatus status; 261 if (!range.hasBound()) { 262 setParams(key, pKey, data); 263 status = doGetFirst(lockMode); 264 endOperation(null, status, null, null, null); 265 return status; 266 } 267 if (range.singleKey) { 268 KeyRange.copy(range.beginKey, privKey); 269 status = doGetSearchKey(lockMode); 270 endOperation(null, status, key, pKey, data); 271 } else { 272 status = OperationStatus.NOTFOUND; 273 Cursor oldCursor = beginOperation(); 274 try { 275 if (range.beginKey == null) { 276 status = doGetFirst(lockMode); 277 } else { 278 KeyRange.copy(range.beginKey, privKey); 279 status = doGetSearchKeyRange(lockMode); 280 if (status == OperationStatus.SUCCESS && 281 !range.beginInclusive && 282 range.compare(privKey, range.beginKey) == 0) { 283 status = doGetNext(lockMode); 284 } 285 } 286 if (status == OperationStatus.SUCCESS && 287 !range.check(privKey)) { 288 status = OperationStatus.NOTFOUND; 289 } 290 } finally { 291 endOperation(oldCursor, status, key, pKey, data); 292 } 293 } 294 return status; 295 } 296 297 public OperationStatus getLast(DatabaseEntry key, 298 DatabaseEntry pKey, 299 DatabaseEntry data, 300 LockMode lockMode) 301 throws DatabaseException { 302 303 OperationStatus status = OperationStatus.NOTFOUND; 304 if (!range.hasBound()) { 305 setParams(key, pKey, data); 306 status = doGetLast(lockMode); 307 endOperation(null, status, null, null, null); 308 return status; 309 } 310 Cursor oldCursor = beginOperation(); 311 try { 312 if (range.endKey == null) { 313 status = doGetLast(lockMode); 314 } else { 315 KeyRange.copy(range.endKey, privKey); 316 status = doGetSearchKeyRange(lockMode); 317 if (status == OperationStatus.SUCCESS) { 318 if (range.endInclusive && 319 range.compare(range.endKey, privKey) == 0) { 320 status = doGetNextNoDup(lockMode); 321 if (status == OperationStatus.SUCCESS) { 322 status = doGetPrev(lockMode); 323 } else { 324 status = doGetLast(lockMode); 325 } 326 } else { 327 status = doGetPrev(lockMode); 328 } 329 } else { 330 status = doGetLast(lockMode); 331 } 332 } 333 if (status == OperationStatus.SUCCESS && 334 !range.checkBegin(privKey, true)) { 335 status = OperationStatus.NOTFOUND; 336 } 337 } finally { 338 endOperation(oldCursor, status, key, pKey, data); 339 } 340 return status; 341 } 342 343 public OperationStatus getNext(DatabaseEntry key, 344 DatabaseEntry pKey, 345 DatabaseEntry data, 346 LockMode lockMode) 347 throws DatabaseException { 348 349 OperationStatus status; 350 if (!initialized) { 351 return getFirst(key, pKey, data, lockMode); 352 } 353 if (!range.hasBound()) { 354 setParams(key, pKey, data); 355 status = doGetNext(lockMode); 356 endOperation(null, status, null, null, null); 357 return status; 358 } 359 if (range.singleKey) { 360 status = doGetNextDup(lockMode); 361 endOperation(null, status, key, pKey, data); 362 } else { 363 status = OperationStatus.NOTFOUND; 364 Cursor oldCursor = beginOperation(); 365 try { 366 status = doGetNext(lockMode); 367 if (status == OperationStatus.SUCCESS && 368 !range.check(privKey)) { 369 status = OperationStatus.NOTFOUND; 370 } 371 } finally { 372 endOperation(oldCursor, status, key, pKey, data); 373 } 374 } 375 return status; 376 } 377 378 public OperationStatus getNextNoDup(DatabaseEntry key, 379 DatabaseEntry pKey, 380 DatabaseEntry data, 381 LockMode lockMode) 382 throws DatabaseException { 383 384 OperationStatus status; 385 if (!initialized) { 386 return getFirst(key, pKey, data, lockMode); 387 } 388 if (!range.hasBound()) { 389 setParams(key, pKey, data); 390 status = doGetNextNoDup(lockMode); 391 endOperation(null, status, null, null, null); 392 return status; 393 } 394 if (range.singleKey) { 395 status = OperationStatus.NOTFOUND; 396 } else { 397 status = OperationStatus.NOTFOUND; 398 Cursor oldCursor = beginOperation(); 399 try { 400 status = doGetNextNoDup(lockMode); 401 if (status == OperationStatus.SUCCESS && 402 !range.check(privKey)) { 403 status = OperationStatus.NOTFOUND; 404 } 405 } finally { 406 endOperation(oldCursor, status, key, pKey, data); 407 } 408 } 409 return status; 410 } 411 412 public OperationStatus getPrev(DatabaseEntry key, 413 DatabaseEntry pKey, 414 DatabaseEntry data, 415 LockMode lockMode) 416 throws DatabaseException { 417 418 OperationStatus status; 419 if (!initialized) { 420 return getLast(key, pKey, data, lockMode); 421 } 422 if (!range.hasBound()) { 423 setParams(key, pKey, data); 424 status = doGetPrev(lockMode); 425 endOperation(null, status, null, null, null); 426 return status; 427 } 428 if (range.singleKey) { 429 status = doGetPrevDup(lockMode); 430 endOperation(null, status, key, pKey, data); 431 } else { 432 status = OperationStatus.NOTFOUND; 433 Cursor oldCursor = beginOperation(); 434 try { 435 status = doGetPrev(lockMode); 436 if (status == OperationStatus.SUCCESS && 437 !range.check(privKey)) { 438 status = OperationStatus.NOTFOUND; 439 } 440 } finally { 441 endOperation(oldCursor, status, key, pKey, data); 442 } 443 } 444 return status; 445 } 446 447 public OperationStatus getPrevNoDup(DatabaseEntry key, 448 DatabaseEntry pKey, 449 DatabaseEntry data, 450 LockMode lockMode) 451 throws DatabaseException { 452 453 OperationStatus status; 454 if (!initialized) { 455 return getLast(key, pKey, data, lockMode); 456 } 457 if (!range.hasBound()) { 458 setParams(key, pKey, data); 459 status = doGetPrevNoDup(lockMode); 460 endOperation(null, status, null, null, null); 461 return status; 462 } 463 if (range.singleKey) { 464 status = OperationStatus.NOTFOUND; 465 } else { 466 status = OperationStatus.NOTFOUND; 467 Cursor oldCursor = beginOperation(); 468 try { 469 status = doGetPrevNoDup(lockMode); 470 if (status == OperationStatus.SUCCESS && 471 !range.check(privKey)) { 472 status = OperationStatus.NOTFOUND; 473 } 474 } finally { 475 endOperation(oldCursor, status, key, pKey, data); 476 } 477 } 478 return status; 479 } 480 481 public OperationStatus getSearchKey(DatabaseEntry key, 482 DatabaseEntry pKey, 483 DatabaseEntry data, 484 LockMode lockMode) 485 throws DatabaseException { 486 487 OperationStatus status; 488 if (!range.hasBound()) { 489 setParams(key, pKey, data); 490 status = doGetSearchKey(lockMode); 491 endOperation(null, status, null, null, null); 492 return status; 493 } 494 if (!range.check(key)) { 495 status = OperationStatus.NOTFOUND; 496 } else { 497 shareData(key, privKey); 498 status = doGetSearchKey(lockMode); 499 endOperation(null, status, key, pKey, data); 500 } 501 return status; 502 } 503 504 public OperationStatus getSearchBoth(DatabaseEntry key, 505 DatabaseEntry pKey, 506 DatabaseEntry data, 507 LockMode lockMode) 508 throws DatabaseException { 509 510 OperationStatus status; 511 if (!range.hasBound()) { 512 setParams(key, pKey, data); 513 status = doGetSearchBoth(lockMode); 514 endOperation(null, status, null, null, null); 515 return status; 516 } 517 if (!range.check(key)) { 518 status = OperationStatus.NOTFOUND; 519 } else { 520 shareData(key, privKey); 521 if (secCursor != null) { 522 shareData(pKey, privPKey); 523 } else { 524 shareData(data, privData); 525 } 526 status = doGetSearchBoth(lockMode); 527 endOperation(null, status, key, pKey, data); 528 } 529 return status; 530 } 531 532 public OperationStatus getSearchKeyRange(DatabaseEntry key, 533 DatabaseEntry pKey, 534 DatabaseEntry data, 535 LockMode lockMode) 536 throws DatabaseException { 537 538 OperationStatus status = OperationStatus.NOTFOUND; 539 if (!range.hasBound()) { 540 setParams(key, pKey, data); 541 status = doGetSearchKeyRange(lockMode); 542 endOperation(null, status, null, null, null); 543 return status; 544 } 545 Cursor oldCursor = beginOperation(); 546 try { 547 shareData(key, privKey); 548 status = doGetSearchKeyRange(lockMode); 549 if (status == OperationStatus.SUCCESS && 550 !range.check(privKey)) { 551 status = OperationStatus.NOTFOUND; 552 } 553 } finally { 554 endOperation(oldCursor, status, key, pKey, data); 555 } 556 return status; 557 } 558 559 public OperationStatus getSearchBothRange(DatabaseEntry key, 560 DatabaseEntry pKey, 561 DatabaseEntry data, 562 LockMode lockMode) 563 throws DatabaseException { 564 565 OperationStatus status = OperationStatus.NOTFOUND; 566 if (!range.hasBound()) { 567 setParams(key, pKey, data); 568 status = doGetSearchBothRange(lockMode); 569 endOperation(null, status, null, null, null); 570 return status; 571 } 572 Cursor oldCursor = beginOperation(); 573 try { 574 shareData(key, privKey); 575 if (secCursor != null) { 576 shareData(pKey, privPKey); 577 } else { 578 shareData(data, privData); 579 } 580 status = doGetSearchBothRange(lockMode); 581 if (status == OperationStatus.SUCCESS && 582 !range.check(privKey)) { 583 status = OperationStatus.NOTFOUND; 584 } 585 } finally { 586 endOperation(oldCursor, status, key, pKey, data); 587 } 588 return status; 589 } 590 591 public OperationStatus getSearchRecordNumber(DatabaseEntry key, 592 DatabaseEntry pKey, 593 DatabaseEntry data, 594 LockMode lockMode) 595 throws DatabaseException { 596 597 OperationStatus status; 598 if (!range.hasBound()) { 599 setParams(key, pKey, data); 600 status = doGetSearchRecordNumber(lockMode); 601 endOperation(null, status, null, null, null); 602 return status; 603 } 604 if (!range.check(key)) { 605 status = OperationStatus.NOTFOUND; 606 } else { 607 shareData(key, privKey); 608 status = doGetSearchRecordNumber(lockMode); 609 endOperation(null, status, key, pKey, data); 610 } 611 return status; 612 } 613 614 public OperationStatus getNextDup(DatabaseEntry key, 615 DatabaseEntry pKey, 616 DatabaseEntry data, 617 LockMode lockMode) 618 throws DatabaseException { 619 620 if (!initialized) { 621 throw new DatabaseException("Cursor not initialized"); 622 } 623 OperationStatus status; 624 if (!range.hasBound()) { 625 setParams(key, pKey, data); 626 status = doGetNextDup(lockMode); 627 endOperation(null, status, null, null, null); 628 } else { 629 status = doGetNextDup(lockMode); 630 endOperation(null, status, key, pKey, data); 631 } 632 return status; 633 } 634 635 public OperationStatus getPrevDup(DatabaseEntry key, 636 DatabaseEntry pKey, 637 DatabaseEntry data, 638 LockMode lockMode) 639 throws DatabaseException { 640 641 if (!initialized) { 642 throw new DatabaseException("Cursor not initialized"); 643 } 644 OperationStatus status; 645 if (!range.hasBound()) { 646 setParams(key, pKey, data); 647 status = doGetPrevDup(lockMode); 648 endOperation(null, status, null, null, null); 649 } else { 650 status = doGetPrevDup(lockMode); 651 endOperation(null, status, key, pKey, data); 652 } 653 return status; 654 } 655 656 public OperationStatus getCurrent(DatabaseEntry key, 657 DatabaseEntry pKey, 658 DatabaseEntry data, 659 LockMode lockMode) 660 throws DatabaseException { 661 662 if (!initialized) { 663 throw new DatabaseException("Cursor not initialized"); 664 } 665 if (secCursor != null && pKey != null) { 666 return secCursor.getCurrent(key, pKey, data, lockMode); 667 } else { 668 return cursor.getCurrent(key, data, lockMode); 669 } 670 } 671 672 675 676 public void close() 677 throws DatabaseException { 678 679 currentTxn.closeCursor(cursor); 680 } 681 682 public int count() 683 throws DatabaseException { 684 685 return cursor.count(); 686 } 687 688 public OperationStatus delete() 689 throws DatabaseException { 690 691 return cursor.delete(); 692 } 693 694 public OperationStatus put(DatabaseEntry key, DatabaseEntry data) 695 throws DatabaseException { 696 697 return cursor.put(key, data); 698 } 699 700 public OperationStatus putNoOverwrite(DatabaseEntry key, 701 DatabaseEntry data) 702 throws DatabaseException { 703 704 return cursor.putNoOverwrite(key, data); 705 } 706 707 public OperationStatus putNoDupData(DatabaseEntry key, DatabaseEntry data) 708 throws DatabaseException { 709 710 return cursor.putNoDupData(key, data); 711 } 712 713 public OperationStatus putCurrent(DatabaseEntry data) 714 throws DatabaseException { 715 716 return cursor.putCurrent(data); 717 } 718 719 public OperationStatus putAfter(DatabaseEntry key, DatabaseEntry data) 720 throws DatabaseException { 721 722 return DbCompat.putAfter(cursor, key, data); 723 } 724 725 public OperationStatus putBefore(DatabaseEntry key, DatabaseEntry data) 726 throws DatabaseException { 727 728 return DbCompat.putBefore(cursor, key, data); 729 } 730 731 private OperationStatus doGetFirst(LockMode lockMode) 732 throws DatabaseException { 733 734 if (secCursor != null && privPKey != null) { 735 return secCursor.getFirst(privKey, privPKey, privData, lockMode); 736 } else { 737 return cursor.getFirst(privKey, privData, lockMode); 738 } 739 } 740 741 private OperationStatus doGetLast(LockMode lockMode) 742 throws DatabaseException { 743 744 if (secCursor != null && privPKey != null) { 745 return secCursor.getLast(privKey, privPKey, privData, lockMode); 746 } else { 747 return cursor.getLast(privKey, privData, lockMode); 748 } 749 } 750 751 private OperationStatus doGetNext(LockMode lockMode) 752 throws DatabaseException { 753 754 if (secCursor != null && privPKey != null) { 755 return secCursor.getNext(privKey, privPKey, privData, lockMode); 756 } else { 757 return cursor.getNext(privKey, privData, lockMode); 758 } 759 } 760 761 private OperationStatus doGetNextDup(LockMode lockMode) 762 throws DatabaseException { 763 764 if (secCursor != null && privPKey != null) { 765 return secCursor.getNextDup(privKey, privPKey, privData, lockMode); 766 } else { 767 return cursor.getNextDup(privKey, privData, lockMode); 768 } 769 } 770 771 private OperationStatus doGetNextNoDup(LockMode lockMode) 772 throws DatabaseException { 773 774 if (secCursor != null && privPKey != null) { 775 return secCursor.getNextNoDup(privKey, privPKey, privData, 776 lockMode); 777 } else { 778 return cursor.getNextNoDup(privKey, privData, lockMode); 779 } 780 } 781 782 private OperationStatus doGetPrev(LockMode lockMode) 783 throws DatabaseException { 784 785 if (secCursor != null && privPKey != null) { 786 return secCursor.getPrev(privKey, privPKey, privData, lockMode); 787 } else { 788 return cursor.getPrev(privKey, privData, lockMode); 789 } 790 } 791 792 private OperationStatus doGetPrevDup(LockMode lockMode) 793 throws DatabaseException { 794 795 if (secCursor != null && privPKey != null) { 796 return secCursor.getPrevDup(privKey, privPKey, privData, lockMode); 797 } else { 798 return cursor.getPrevDup(privKey, privData, lockMode); 799 } 800 } 801 802 private OperationStatus doGetPrevNoDup(LockMode lockMode) 803 throws DatabaseException { 804 805 if (secCursor != null && privPKey != null) { 806 return secCursor.getPrevNoDup(privKey, privPKey, privData, 807 lockMode); 808 } else { 809 return cursor.getPrevNoDup(privKey, privData, lockMode); 810 } 811 } 812 813 private OperationStatus doGetSearchKey(LockMode lockMode) 814 throws DatabaseException { 815 816 if (isRecnoOrQueue && DbCompat.getRecordNumber(privKey) <= 0) { 817 return OperationStatus.NOTFOUND; 818 } 819 if (secCursor != null && privPKey != null) { 820 return secCursor.getSearchKey(privKey, privPKey, privData, 821 lockMode); 822 } else { 823 return cursor.getSearchKey(privKey, privData, lockMode); 824 } 825 } 826 827 private OperationStatus doGetSearchKeyRange(LockMode lockMode) 828 throws DatabaseException { 829 830 if (isRecnoOrQueue && DbCompat.getRecordNumber(privKey) <= 0) { 831 return OperationStatus.NOTFOUND; 832 } 833 if (secCursor != null && privPKey != null) { 834 return secCursor.getSearchKeyRange(privKey, privPKey, privData, 835 lockMode); 836 } else { 837 return cursor.getSearchKeyRange(privKey, privData, lockMode); 838 } 839 } 840 841 private OperationStatus doGetSearchBoth(LockMode lockMode) 842 throws DatabaseException { 843 844 if (isRecnoOrQueue && DbCompat.getRecordNumber(privKey) <= 0) { 845 return OperationStatus.NOTFOUND; 846 } 847 if (secCursor != null && privPKey != null) { 848 return secCursor.getSearchBoth(privKey, privPKey, privData, 849 lockMode); 850 } else { 851 return cursor.getSearchBoth(privKey, privData, lockMode); 852 } 853 } 854 855 private OperationStatus doGetSearchBothRange(LockMode lockMode) 856 throws DatabaseException { 857 858 if (isRecnoOrQueue && DbCompat.getRecordNumber(privKey) <= 0) { 859 return OperationStatus.NOTFOUND; 860 } 861 if (secCursor != null && privPKey != null) { 862 return secCursor.getSearchBothRange(privKey, privPKey, privData, 863 lockMode); 864 } else { 865 return cursor.getSearchBothRange(privKey, privData, lockMode); 866 } 867 } 868 869 private OperationStatus doGetSearchRecordNumber(LockMode lockMode) 870 throws DatabaseException { 871 872 if (DbCompat.getRecordNumber(privKey) <= 0) { 873 return OperationStatus.NOTFOUND; 874 } 875 if (secCursor != null && privPKey != null) { 876 return DbCompat.getSearchRecordNumber(secCursor, privKey, privPKey, 877 privData, lockMode); 878 } else { 879 return DbCompat.getSearchRecordNumber(cursor, privKey, privData, 880 lockMode); 881 } 882 } 883 } 884 | Popular Tags |