1 21 22 package org.apache.derby.impl.store.access.conglomerate; 23 24 import org.apache.derby.iapi.reference.SQLState; 25 26 import org.apache.derby.iapi.services.sanity.SanityManager; 27 28 import org.apache.derby.iapi.error.StandardException; 29 30 import org.apache.derby.iapi.store.access.conglomerate.Conglomerate; 31 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo; 32 import org.apache.derby.iapi.store.access.conglomerate.ScanManager; 33 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager; 34 35 import org.apache.derby.iapi.store.access.ConglomerateController; 36 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo; 37 import org.apache.derby.iapi.store.access.Qualifier; 38 import org.apache.derby.iapi.store.access.RowUtil; 39 import org.apache.derby.iapi.store.access.ScanController; 40 import org.apache.derby.iapi.store.access.ScanInfo; 41 import org.apache.derby.iapi.store.access.SpaceInfo; 42 43 import org.apache.derby.iapi.store.raw.ContainerHandle; 44 import org.apache.derby.iapi.store.raw.FetchDescriptor; 45 import org.apache.derby.iapi.store.raw.Page; 46 import org.apache.derby.iapi.store.raw.RecordHandle; 47 import org.apache.derby.iapi.store.raw.Transaction; 48 49 import org.apache.derby.iapi.store.access.Qualifier; 50 51 import org.apache.derby.iapi.types.DataValueDescriptor; 52 53 import org.apache.derby.iapi.types.Orderable; 54 import org.apache.derby.iapi.types.RowLocation; 55 56 57 import org.apache.derby.iapi.store.access.BackingStoreHashtable; 58 import org.apache.derby.iapi.services.io.FormatableBitSet; 59 60 import java.util.Properties ; 61 62 63 112 113 public abstract class GenericScanController 114 extends GenericController implements ScanManager 115 { 116 117 121 122 164 public static final int SCAN_INIT = 1; 165 public static final int SCAN_INPROGRESS = 2; 166 public static final int SCAN_DONE = 3; 167 public static final int SCAN_HOLD_INIT = 4; 168 public static final int SCAN_HOLD_INPROGRESS = 5; 169 170 174 175 180 private FormatableBitSet init_scanColumnList; 181 private DataValueDescriptor[] init_startKeyValue; 182 private int init_startSearchOperator; 183 private Qualifier[][] init_qualifier; 184 private DataValueDescriptor[] init_stopKeyValue; 185 private int init_stopSearchOperator; 186 187 private FetchDescriptor init_fetchDesc; 188 189 193 private int scan_state; 194 195 196 200 protected boolean rowLocationsInvalidated = false; 201 202 207 private long reusableRecordIdSequenceNumber = 0; 208 209 230 protected RowPosition scan_position; 231 232 235 protected int stat_numpages_visited = 0; 236 protected int stat_numrows_visited = 0; 237 protected int stat_numrows_qualified = 0; 238 239 243 244 248 249 private final void repositionScanForUpateOper() 250 throws StandardException 251 { 252 if (scan_state != SCAN_INPROGRESS) 253 throw StandardException.newException( 254 SQLState.AM_SCAN_NOT_POSITIONED); 255 256 257 if (!open_conglom.latchPage(scan_position)) 258 { 259 throw StandardException.newException( 260 SQLState.AM_RECORD_NOT_FOUND, 261 open_conglom.getContainer().getId(), 262 new Long (scan_position.current_rh.getId())); 263 } 264 265 if (open_conglom.isUseUpdateLocks()) 266 { 267 271 open_conglom.lockPositionForWrite( 272 scan_position, false , true); 273 } 274 } 275 276 277 289 290 297 protected void positionAtInitScan( 298 DataValueDescriptor[] startKeyValue, 299 int startSearchOperator, 300 Qualifier qualifier[][], 301 DataValueDescriptor[] stopKeyValue, 302 int stopSearchOperator, 303 RowPosition pos) 304 throws StandardException 305 { 306 this.init_startKeyValue = startKeyValue; 308 if (RowUtil.isRowEmpty(this.init_startKeyValue)) 309 this.init_startKeyValue = null; 310 311 this.init_startSearchOperator = startSearchOperator; 313 314 if ((qualifier != null) && (qualifier .length == 0)) 316 qualifier = null; 317 this.init_qualifier = qualifier; 318 319 init_fetchDesc = 323 new FetchDescriptor( 324 (open_conglom.getRuntimeMem().get_scratch_row()).length, 325 init_scanColumnList, 326 init_qualifier); 327 328 this.init_stopKeyValue = stopKeyValue; 330 if (RowUtil.isRowEmpty(this.init_stopKeyValue)) 331 this.init_stopKeyValue = null; 332 333 this.init_stopSearchOperator = stopSearchOperator; 335 336 pos.init(); 338 339 340 if (SanityManager.DEBUG) 344 { 345 if (init_scanColumnList != null) 346 { 347 350 FormatableBitSet required_cols; 351 352 if (qualifier != null) 353 required_cols = RowUtil.getQualifierBitSet(qualifier); 354 else 355 required_cols = new FormatableBitSet(0); 356 357 if (this.init_startKeyValue != null) 359 { 360 required_cols.grow(this.init_startKeyValue.length); 361 for (int i = 0; i < this.init_startKeyValue.length; i++) 362 required_cols.set(i); 363 } 364 365 if (this.init_stopKeyValue != null) 366 { 367 required_cols.grow(this.init_stopKeyValue.length); 368 for (int i = 0; i < this.init_stopKeyValue.length; i++) 369 required_cols.set(i); 370 } 371 372 FormatableBitSet required_cols_and_scan_list = 373 (FormatableBitSet) required_cols.clone(); 374 375 required_cols_and_scan_list.and(init_scanColumnList); 376 377 required_cols.grow(init_scanColumnList.size()); 380 381 if (!required_cols_and_scan_list.equals(required_cols)) 382 { 383 SanityManager.THROWASSERT( 384 "Some column specified in a Btree " + 385 " qualifier/start/stop list is " + 386 "not represented in the scanColumnList." + 387 "\n:required_cols_and_scan_list = " + 388 required_cols_and_scan_list + 389 "\n;required_cols = " + required_cols + 390 "\n;init_scanColumnList = " + init_scanColumnList); 391 } 392 } 393 } 394 395 scan_state = SCAN_INIT; 397 } 398 399 400 412 protected void positionAtResumeScan( 413 RowPosition pos) 414 throws StandardException 415 { 416 if (SanityManager.DEBUG) 417 { 418 SanityManager.ASSERT( 419 scan_position.current_rh != null, this.toString()); 420 } 421 422 open_conglom.latchPageAndRepositionScan(scan_position); 427 } 428 429 442 protected void positionAtStartForForwardScan( 443 RowPosition pos) 444 throws StandardException 445 { 446 if (pos.current_rh == null) 447 { 448 pos.current_page = 450 open_conglom.getContainer().getFirstPage(); 451 452 if (SanityManager.DEBUG) 453 { 454 SanityManager.ASSERT( 455 pos.current_page.getPageNumber() == 456 ContainerHandle.FIRST_PAGE_NUMBER); 457 458 if (pos.current_page.recordCount() < 1) 459 SanityManager.THROWASSERT( 460 "record count = " + pos.current_page.recordCount()); 461 } 462 463 pos.current_slot = Page.FIRST_SLOT_NUMBER; 466 } 467 else 468 { 469 471 open_conglom.latchPageAndRepositionScan(pos); 476 477 pos.current_slot -= 1; 480 } 481 482 pos.current_rh = null; 483 this.stat_numpages_visited = 1; 484 this.scan_state = SCAN_INPROGRESS; 485 } 486 487 492 protected void positionAtNextPage( 493 RowPosition pos) 494 throws StandardException 495 { 496 if (pos.current_page != null) 502 { 503 long pageid = pos.current_page.getPageNumber(); 505 506 pos.unlatch(); 508 509 pos.current_page = 511 open_conglom.getContainer().getNextPage(pageid); 512 513 pos.current_slot = Page.FIRST_SLOT_NUMBER - 1; 515 } 516 } 517 518 523 protected void positionAtDoneScan( 524 RowPosition pos) 525 throws StandardException 526 { 527 pos.unlatch(); 529 530 if (scan_position.current_rh != null) 532 { 533 open_conglom.unlockPositionAfterRead(scan_position); 534 scan_position.current_rh = null; 535 } 536 537 this.scan_state = SCAN_DONE; 538 } 539 540 public void reopenScanByRowLocation( 541 RowLocation startRowLocation, 542 Qualifier qualifier[][]) 543 throws StandardException 544 { 545 throw StandardException.newException( 546 SQLState.BTREE_UNIMPLEMENTED_FEATURE); 547 } 548 549 553 554 562 protected RowPosition allocateScanPosition() 563 throws StandardException 564 { 565 return(new RowPosition()); 566 } 567 568 575 protected int fetchRows( 576 DataValueDescriptor[][] row_array, 577 RowLocation[] rowloc_array, 578 BackingStoreHashtable hash_table, 579 long max_rowcnt, 580 int[] key_column_numbers) 581 throws StandardException 582 { 583 int ret_row_count = 0; 584 DataValueDescriptor[] fetch_row = null; 585 586 if (max_rowcnt == -1) 587 max_rowcnt = Long.MAX_VALUE; 588 589 if (SanityManager.DEBUG) 590 { 591 if (row_array != null) 592 { 593 SanityManager.ASSERT(row_array[0] != null, 594 "first array slot in fetchNextGroup() must be non-null."); 595 SanityManager.ASSERT(hash_table == null); 596 } 597 else 598 { 599 SanityManager.ASSERT(hash_table != null); 600 } 601 } 602 603 if (this.scan_state == SCAN_INPROGRESS) 604 { 605 positionAtResumeScan(scan_position); 606 } 607 else if (this.scan_state == SCAN_INIT) 608 { 609 positionAtStartForForwardScan(scan_position); 610 611 } 612 else if (this.scan_state == SCAN_HOLD_INPROGRESS) 613 { 614 reopenAfterEndTransaction(); 615 616 if (SanityManager.DEBUG) 617 { 618 SanityManager.ASSERT( 619 scan_position.current_rh != null, this.toString()); 620 } 621 622 open_conglom.latchPageAndRepositionScan(scan_position); 628 629 this.scan_state = SCAN_INPROGRESS; 630 } 631 else if (this.scan_state == SCAN_HOLD_INIT) 632 { 633 reopenAfterEndTransaction(); 634 635 positionAtStartForForwardScan(scan_position); 636 637 } 638 else 639 { 640 if (SanityManager.DEBUG) 641 SanityManager.ASSERT(this.scan_state == SCAN_DONE); 642 643 return(0); 644 } 645 646 651 656 while (scan_position.current_page != null) 657 { 658 while ((scan_position.current_slot + 1) < 659 scan_position.current_page.recordCount()) 660 { 661 if (scan_position.current_rh != null) 663 { 664 open_conglom.unlockPositionAfterRead(scan_position); 665 666 } 667 if (fetch_row == null) 669 { 670 if (hash_table == null) 671 { 672 if (row_array[ret_row_count] == null) 674 { 675 row_array[ret_row_count] = 676 open_conglom.getRuntimeMem().get_row_for_export(); 677 } 678 679 fetch_row = row_array[ret_row_count]; 680 } 681 else 682 { 683 fetch_row = 684 open_conglom.getRuntimeMem().get_row_for_export(); 685 } 686 } 687 688 scan_position.positionAtNextSlot(); 690 691 boolean lock_granted_while_latch_held = 693 open_conglom.lockPositionForRead( 694 scan_position, (RowPosition) null, true, true); 695 696 if (!lock_granted_while_latch_held) 697 { 698 718 if (scan_position.current_page == null) 719 { 720 724 break; 725 } 726 else if (scan_position.current_slot == -1) 727 { 728 735 if (SanityManager.DEBUG) 736 { 737 SanityManager.ASSERT( 738 scan_position.current_rh == null); 739 } 740 741 continue; 742 } 743 } 744 745 this.stat_numrows_visited++; 746 747 if (SanityManager.DEBUG) 749 { 750 SanityManager.ASSERT(scan_position.current_rh != null); 751 752 if (scan_position.current_slot != 754 scan_position.current_page.getSlotNumber( 755 scan_position.current_rh)) 756 { 757 SanityManager.THROWASSERT( 758 "current_slot = " + scan_position.current_slot + 759 "current_rh = " + scan_position.current_rh + 760 "current_rh.slot = " + 761 scan_position.current_page.getSlotNumber( 762 scan_position.current_rh)); 763 } 764 } 765 766 768 scan_position.current_rh_qualified = 769 (scan_position.current_page.fetchFromSlot( 770 scan_position.current_rh, 771 scan_position.current_slot, 772 fetch_row, 773 init_fetchDesc, 774 false) != null); 775 776 if (scan_position.current_rh_qualified) 777 { 778 780 781 if (SanityManager.DEBUG) 786 { 787 SanityManager.ASSERT( 789 scan_position.current_slot == 790 scan_position.current_page.getSlotNumber( 791 scan_position.current_rh)); 792 } 793 794 ret_row_count++; 796 stat_numrows_qualified++; 797 798 799 if (hash_table == null) 800 { 801 if (rowloc_array != null) 802 { 803 setRowLocationArray( 805 rowloc_array, ret_row_count - 1, scan_position); 806 } 807 808 fetch_row = null; 809 } 810 else 811 { 812 if (hash_table.put(false, fetch_row)) 813 { 814 fetch_row = null; 817 } 818 } 819 820 if (max_rowcnt <= ret_row_count) 821 { 822 scan_position.unlatch(); 824 825 if (SanityManager.DEBUG) 826 { 827 SanityManager.ASSERT( 828 scan_position.current_rh != null); 829 } 830 831 return(ret_row_count); 832 } 833 } 834 } 835 836 positionAtNextPage(scan_position); 837 838 this.stat_numpages_visited++; 839 } 840 841 positionAtDoneScan(scan_position); 843 844 this.stat_numpages_visited--; 846 847 return(ret_row_count); 848 } 849 850 880 protected void reopenScanByRecordHandle( 881 RecordHandle startRecordHandle, 882 Qualifier qualifier[][]) 883 throws StandardException 884 { 885 this.scan_state = 887 (!open_conglom.getHold() ? SCAN_INIT : SCAN_HOLD_INIT); 888 889 scan_position.current_rh = startRecordHandle; 892 } 893 894 protected abstract void setRowLocationArray( 895 RowLocation[] rowloc_array, 896 int index, 897 RowPosition pos) 898 throws StandardException 899 ; 900 901 905 906 910 public void init( 911 OpenConglomerate open_conglom, 912 FormatableBitSet scanColumnList, 913 DataValueDescriptor[] startKeyValue, 914 int startSearchOperator, 915 Qualifier qualifier[][], 916 DataValueDescriptor[] stopKeyValue, 917 int stopSearchOperator) 918 throws StandardException 919 { 920 super.init(open_conglom); 921 922 scan_position = allocateScanPosition(); 924 925 init_scanColumnList = scanColumnList; 927 928 positionAtInitScan( 929 startKeyValue, 930 startSearchOperator, 931 qualifier, 932 stopKeyValue, 933 stopSearchOperator, 934 scan_position); 935 936 reusableRecordIdSequenceNumber = 937 open_conglom.getContainer().getReusableRecordIdSequenceNumber(); 938 } 939 940 941 public final int getNumPagesVisited() 942 { 943 return(stat_numpages_visited); 944 } 945 public final int getNumRowsVisited() 946 { 947 return(stat_numrows_visited); 948 } 949 public final int getNumRowsQualified() 950 { 951 return(stat_numrows_qualified); 952 } 953 public final FormatableBitSet getScanColumnList() 954 { 955 return(init_scanColumnList); 956 } 957 public final DataValueDescriptor[] getStartKeyValue() 958 { 959 return(init_startKeyValue); 960 } 961 public final int getStartSearchOperator() 962 { 963 return(init_startSearchOperator); 964 } 965 public final DataValueDescriptor[] getStopKeyValue() 966 { 967 return(init_stopKeyValue); 968 } 969 public final int getStopSearchOperator() 970 { 971 return(init_stopSearchOperator); 972 } 973 public final Qualifier[][] getQualifier() 974 { 975 return(init_qualifier); 976 } 977 978 979 public final int getScanState() 980 { 981 return(scan_state); 982 } 983 public final void setScanState(int state) 984 { 985 scan_state = state; 986 } 987 public final RowPosition getScanPosition() 988 { 989 return(scan_position); 990 } 991 public final void setScanPosition(RowPosition pos) 992 { 993 scan_position = pos; 994 } 995 996 1000 private void closeScan() 1001 throws StandardException 1002 { 1003 super.close(); 1004 1005 if (open_conglom.getXactMgr() != null) 1008 open_conglom.getXactMgr().closeMe(this); 1009 1010 this.init_qualifier = null; 1012 init_scanColumnList = null; 1013 init_startKeyValue = null; 1014 init_stopKeyValue = null; 1015 } 1016 1017 public void close() 1018 throws StandardException 1019 { 1020 positionAtDoneScan(scan_position); 1024 1025 closeScan(); 1026 } 1027 1028 1036 protected final boolean reopenAfterEndTransaction() 1037 throws StandardException 1038 { 1039 if (!open_conglom.getHold()) 1041 { 1042 return(false); 1043 } 1044 1045 ContainerHandle container = open_conglom.reopen(); 1046 switch (scan_state) { 1047 case SCAN_INPROGRESS: 1048 case SCAN_HOLD_INPROGRESS: 1049 case SCAN_DONE: 1050 if (container.getReusableRecordIdSequenceNumber() != 1051 reusableRecordIdSequenceNumber) 1052 { 1053 rowLocationsInvalidated = true; 1054 } 1055 break; 1056 case SCAN_INIT: 1057 case SCAN_HOLD_INIT: 1058 reusableRecordIdSequenceNumber = 1059 container.getReusableRecordIdSequenceNumber(); 1060 break; 1061 default: 1062 break; 1063 } 1064 return(true); 1065 } 1066 1067 public boolean closeForEndTransaction( 1068 boolean closeHeldScan) 1069 throws StandardException 1070 { 1071 if ((!open_conglom.getHold()) || closeHeldScan) 1072 { 1073 1075 this.scan_state = SCAN_DONE; 1076 1077 closeScan(); 1078 1079 return(true); 1080 } 1081 else 1082 { 1083 super.close(); 1084 1085 1089 if (this.scan_state == SCAN_INPROGRESS) 1090 this.scan_state = SCAN_HOLD_INPROGRESS; 1091 else if (this.scan_state == SCAN_INIT) 1092 this.scan_state = SCAN_HOLD_INIT; 1093 1094 1095 return(false); 1096 } 1097 } 1098 1099 1100 1103 public boolean delete() 1104 throws StandardException 1105 { 1106 repositionScanForUpateOper(); 1107 1108 boolean ret_val = true; 1109 1110 1113 1115 if (scan_position.current_page.isDeletedAtSlot( 1116 scan_position.current_slot)) 1117 { 1118 ret_val = false; 1119 } 1120 else 1121 { 1122 scan_position.current_page.deleteAtSlot( 1124 scan_position.current_slot, true, (LogicalUndo) null); 1125 1126 if (scan_position.current_page.nonDeletedRecordCount() == 0) 1127 { 1128 queueDeletePostCommitWork(scan_position); 1129 } 1130 } 1131 1132 scan_position.unlatch(); 1133 1134 return(ret_val); 1135 } 1136 1137 1138 1157 public void didNotQualify() 1158 throws StandardException 1159 { 1160 } 1161 1162 1269 public void fetchSet( 1270 long max_rowcnt, 1271 int[] key_column_numbers, 1272 BackingStoreHashtable hash_table) 1273 throws StandardException 1274 { 1275 fetchRows( 1276 (DataValueDescriptor[][]) null, 1277 (RowLocation[]) null, 1278 hash_table, 1279 max_rowcnt, 1280 key_column_numbers); 1281 1282 return; 1283 } 1284 1285 1329 public void reopenScan( 1330 DataValueDescriptor[] startKeyValue, 1331 int startSearchOperator, 1332 Qualifier qualifier[][], 1333 DataValueDescriptor[] stopKeyValue, 1334 int stopSearchOperator) 1335 throws StandardException 1336 { 1337 if (SanityManager.DEBUG) 1338 { 1339 if (!open_conglom.getHold()) 1340 { 1341 SanityManager.ASSERT( 1342 !open_conglom.isClosed(), 1343 "GenericScanController.reopenScan() called on a non-held closed scan."); 1344 } 1345 } 1346 1347 this.scan_state = 1349 (!open_conglom.getHold() ? SCAN_INIT : SCAN_HOLD_INIT); 1350 1351 scan_position.current_rh = null; 1352 } 1353 1354 1357 public boolean replace( 1358 DataValueDescriptor[] row, 1359 FormatableBitSet validColumns) 1360 throws StandardException 1361 { 1362 repositionScanForUpateOper(); 1363 1364 boolean ret_val = 1365 scan_position.current_page.update( 1366 scan_position.current_rh, row, validColumns); 1367 1368 scan_position.unlatch(); 1369 1370 return(ret_val); 1371 } 1372 1373 1394 public boolean doesCurrentPositionQualify() 1395 throws StandardException 1396 { 1397 if (scan_state != SCAN_INPROGRESS) 1398 throw StandardException.newException( 1399 SQLState.AM_SCAN_NOT_POSITIONED); 1400 1401 if (!open_conglom.latchPage(scan_position)) 1402 { 1403 return(false); 1404 } 1405 1406 DataValueDescriptor row[] = 1407 open_conglom.getRuntimeMem().get_scratch_row(); 1408 1409 1412 boolean ret_val = 1413 (scan_position.current_page.fetchFromSlot( 1414 scan_position.current_rh, 1415 scan_position.current_slot, 1416 row, 1417 init_fetchDesc, 1418 false) != null); 1419 1420 scan_position.unlatch(); 1421 1422 return(ret_val); 1423 } 1424 1425 1431 public void fetchWithoutQualify(DataValueDescriptor[] row) 1432 throws StandardException 1433 { 1434 fetch(row, false); 1435 } 1436 1437 1442 public void fetch(DataValueDescriptor[] row) 1443 throws StandardException 1444 { 1445 fetch(row, true); 1446 } 1447 1448 1458 private void fetch(DataValueDescriptor[] row, boolean qualify) 1459 throws StandardException 1460 { 1461 if (scan_state != SCAN_INPROGRESS) 1462 throw StandardException.newException( 1463 SQLState.AM_SCAN_NOT_POSITIONED); 1464 1465 if (!open_conglom.latchPage(scan_position)) 1466 { 1467 throw StandardException.newException( 1468 SQLState.AM_RECORD_NOT_FOUND, 1469 open_conglom.getContainer().getId(), 1470 new Long (scan_position.current_rh.getId())); 1471 } 1472 1473 RecordHandle rh = 1475 scan_position.current_page.fetchFromSlot( 1476 scan_position.current_rh, 1477 scan_position.current_slot, 1478 row, 1479 qualify ? init_fetchDesc : null, 1480 false); 1481 1482 scan_position.unlatch(); 1483 1484 if (rh == null) 1485 { 1486 1499 1500 throw StandardException.newException( 1501 SQLState.AM_RECORD_NOT_FOUND, 1502 open_conglom.getContainer().getId(), 1503 new Long (scan_position.current_rh.getId())); 1504 } 1505 1506 return; 1507 } 1508 1509 1515 public void fetchLocation(RowLocation templateLocation) 1516 throws StandardException 1517 { 1518 throw StandardException.newException( 1519 SQLState.BTREE_UNIMPLEMENTED_FEATURE); 1520 } 1521 1522 1535 public ScanInfo getScanInfo() 1536 throws StandardException 1537 { 1538 throw StandardException.newException( 1539 SQLState.BTREE_UNIMPLEMENTED_FEATURE); 1540 } 1541 1542 1543 1544 1556 public boolean isCurrentPositionDeleted() 1557 throws StandardException 1558 { 1559 if (scan_state != SCAN_INPROGRESS) 1560 throw StandardException.newException( 1561 SQLState.AM_SCAN_NOT_POSITIONED); 1562 1563 if (!open_conglom.latchPage(scan_position)) 1564 { 1565 return(true); 1566 } 1567 1568 boolean ret_val = 1569 scan_position.current_page.isDeletedAtSlot( 1570 scan_position.current_slot); 1571 1572 scan_position.unlatch(); 1573 1574 return(ret_val); 1575 } 1576} 1577 | Popular Tags |