1 21 22 package org.apache.derby.impl.store.raw.data; 23 24 import org.apache.derby.iapi.services.sanity.SanityManager; 25 26 import org.apache.derby.iapi.reference.SQLState; 27 28 import org.apache.derby.iapi.services.io.TypedFormat; 29 import org.apache.derby.iapi.services.io.FormatIdUtil; 30 import org.apache.derby.iapi.services.io.StoredFormatIds; 31 32 import org.apache.derby.iapi.error.StandardException; 33 34 import org.apache.derby.iapi.store.raw.ContainerHandle; 35 import org.apache.derby.iapi.store.raw.Loggable; 36 import org.apache.derby.iapi.store.raw.PageKey; 37 import org.apache.derby.iapi.store.raw.PageTimeStamp; 38 import org.apache.derby.iapi.store.raw.RawStoreFactory; 39 40 import org.apache.derby.iapi.store.raw.log.LogInstant; 41 import org.apache.derby.iapi.store.raw.xact.RawTransaction; 42 43 import org.apache.derby.impl.store.raw.data.BaseContainerHandle; 44 import org.apache.derby.impl.store.raw.data.BasePage; 45 import org.apache.derby.impl.store.raw.data.PageVersion; 46 47 import java.io.IOException ; 48 49 import java.io.ObjectOutput ; 50 import java.io.ObjectInput ; 51 52 import org.apache.derby.iapi.services.io.ArrayInputStream; 53 54 173 174 175 public class AllocPage extends StoredPage 176 { 177 180 public static final int FORMAT_NUMBER = StoredFormatIds.RAW_STORE_ALLOC_PAGE; 181 183 186 public int getTypeFormatId() { 187 return StoredFormatIds.RAW_STORE_ALLOC_PAGE; 188 } 189 190 193 private long nextAllocPageNumber; private long nextAllocPageOffset; 195 private long reserved1; 196 private long reserved2; 197 private long reserved3; 198 private long reserved4; 199 200 private AllocExtent extent; 201 202 private int borrowedSpace; 203 204 207 208 217 protected static final int ALLOC_PAGE_HEADER_OFFSET = 218 StoredPage.PAGE_HEADER_OFFSET + StoredPage.PAGE_HEADER_SIZE; 219 220 protected static final int ALLOC_PAGE_HEADER_SIZE = 8+8+(4*8); 221 222 223 protected static final int BORROWED_SPACE_OFFSET = 224 ALLOC_PAGE_HEADER_OFFSET + ALLOC_PAGE_HEADER_SIZE; 225 226 227 protected static final int BORROWED_SPACE_LEN = 1; 229 233 234 238 protected static final int MAX_BORROWED_SPACE = 239 RawStoreFactory.PAGE_SIZE_MINIMUM / 5; 241 public AllocPage() 242 { 243 super(); 244 } 245 246 249 250 protected int getMaxFreeSpace() { 251 252 258 return super.getMaxFreeSpace() - ALLOC_PAGE_HEADER_SIZE - 259 BORROWED_SPACE_LEN - borrowedSpace; 260 } 261 262 263 267 268 273 protected void createPage(PageKey newIdentity, int[] args) 274 throws StandardException 275 { 276 277 super.createPage(newIdentity, args); 278 279 int pageSize = args[2]; 287 int minimumRecordSize = args[5]; 288 borrowedSpace = args[4]; 289 290 if (SanityManager.DEBUG) 291 { 292 SanityManager.ASSERT(MAX_BORROWED_SPACE <= 255); 294 295 if (!(borrowedSpace + BORROWED_SPACE_LEN + BORROWED_SPACE_OFFSET 296 < MAX_BORROWED_SPACE)) 297 { 298 SanityManager.THROWASSERT( 299 "borrowedSpace too big = " + borrowedSpace); 300 } 301 SanityManager.ASSERT(pageData != null); 302 } 303 pageData[BORROWED_SPACE_OFFSET] = (byte)borrowedSpace; 304 305 if (borrowedSpace > 0) 309 { 310 clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, borrowedSpace); 311 } 312 313 nextAllocPageNumber = ContainerHandle.INVALID_PAGE_NUMBER; 315 nextAllocPageOffset = 0; 316 reserved1 = reserved2 = reserved3 = reserved4 = 0; 317 318 int maxSpace = getMaxFreeSpace(); 320 321 extent = createExtent(newIdentity.getPageNumber()+1, pageSize, 0 , maxSpace); 325 } 326 327 private AllocExtent createExtent(long pageNum, int pageSize, int pagesAlloced, int availspace) 328 { 329 int maxPages = AllocExtent.MAX_RANGE(availspace); 330 331 if (SanityManager.DEBUG) 332 SanityManager.ASSERT(maxPages > 8, "cannot manage > 8 pages"); 333 334 335 if (SanityManager.DEBUG) 336 { 337 if (SanityManager.DEBUG_ON(TEST_MULTIPLE_ALLOC_PAGE)) 338 { 339 maxPages = 2; } 341 } 342 343 return new AllocExtent(pageNum*pageSize, pageNum, pagesAlloced, pageSize, maxPages); } 349 350 355 protected void initFromData(FileContainer myContainer, PageKey newIdentity) 356 throws StandardException 357 { 358 if (pageData.length < BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN) 359 { 360 throw dataFactory.markCorrupt( 361 StandardException.newException( 362 SQLState.DATA_CORRUPT_PAGE, newIdentity)); 363 } 364 365 byte n = pageData[BORROWED_SPACE_OFFSET]; 366 borrowedSpace = (int)n; 367 368 if (pageData.length < BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + n) 369 { 370 throw dataFactory.markCorrupt( 371 StandardException.newException( 372 SQLState.DATA_CORRUPT_PAGE, newIdentity)); 373 } 374 375 if (borrowedSpace > 0) 377 { 378 clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, borrowedSpace); 379 } 380 381 super.initFromData(myContainer, newIdentity); 382 383 try 384 { 385 readAllocPageHeader(); 387 388 int offset = BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + borrowedSpace; 390 extent = readExtent(offset); 391 } 392 catch (IOException ioe) 393 { 394 throw dataFactory.markCorrupt( 395 StandardException.newException( 396 SQLState.DATA_CORRUPT_PAGE, ioe, newIdentity)); 397 } 398 catch (ClassNotFoundException cnfe) 399 { 400 throw dataFactory.markCorrupt( 401 StandardException.newException( 402 SQLState.DATA_CORRUPT_PAGE, cnfe, newIdentity)); 403 } 404 } 405 406 411 protected void writePage(PageKey identity) throws StandardException 412 { 413 try 414 { 415 updateAllocPageHeader(); 417 int n = (int)pageData[BORROWED_SPACE_OFFSET]; 422 if (SanityManager.DEBUG) 423 { 424 if (n != borrowedSpace) 425 SanityManager.THROWASSERT( 426 "different borrowed space " + n + ", " + borrowedSpace); 427 } 428 if (n > 0) 429 { 430 clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, n); 431 } 432 433 int offset = BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + n; 434 writeExtent(offset); 435 } 436 catch (IOException ioe) 437 { 438 throw dataFactory.markCorrupt( 440 StandardException.newException( 441 SQLState.DATA_CORRUPT_PAGE, ioe, identity)); 442 } 443 444 super.writePage(identity); 446 } 447 448 449 private void readAllocPageHeader() throws IOException 450 { 451 ArrayInputStream lrdi = rawDataIn; 452 lrdi.setPosition(ALLOC_PAGE_HEADER_OFFSET); 453 454 nextAllocPageNumber = lrdi.readLong(); 455 nextAllocPageOffset = lrdi.readLong(); 456 reserved1 = lrdi.readLong(); 457 reserved2 = lrdi.readLong(); 458 reserved3 = lrdi.readLong(); 459 reserved4 = lrdi.readLong(); 460 } 461 462 private void updateAllocPageHeader() throws IOException 463 { 464 rawDataOut.setPosition(ALLOC_PAGE_HEADER_OFFSET); 466 logicalDataOut.writeLong(nextAllocPageNumber); 467 logicalDataOut.writeLong(nextAllocPageOffset); 468 logicalDataOut.writeLong(0); logicalDataOut.writeLong(0); logicalDataOut.writeLong(0); logicalDataOut.writeLong(0); } 473 474 private AllocExtent readExtent(int offset) 475 throws IOException , ClassNotFoundException 476 { 477 ArrayInputStream lrdi = rawDataIn; 478 rawDataIn.setPosition(offset); 479 AllocExtent newExtent = new AllocExtent(); 480 newExtent.readExternal(lrdi); 481 482 if (SanityManager.DEBUG) 484 { 485 int max_range = newExtent.MAX_RANGE(getMaxFreeSpace()); 486 long extent_start = newExtent.getFirstPagenum(); 487 long extent_end = newExtent.getExtentEnd(); 488 489 493 if ((extent_start+max_range-1) < extent_end) 494 { 495 SanityManager.THROWASSERT( 496 "extent range exceed what extent's space can handle "); 497 } 498 } 499 500 return newExtent; 501 } 502 503 private void writeExtent(int offset) throws IOException 504 { 505 rawDataOut.setPosition(offset); 507 extent.writeExternal(logicalDataOut); 508 } 509 510 513 514 529 public static void WriteContainerInfo(byte[] containerInfo, 530 byte[] epage, 531 boolean create) 532 throws StandardException 533 { 534 int N = (containerInfo == null) ? 0 : containerInfo.length; 535 536 if (SanityManager.DEBUG) 537 { 538 if (create) 539 SanityManager.ASSERT( 540 containerInfo != null, "containerInfo is null"); 541 542 SanityManager.ASSERT(epage != null, "page array is null"); 543 544 if (!((containerInfo == null) || 545 ((containerInfo.length + BORROWED_SPACE_OFFSET + 546 BORROWED_SPACE_LEN) < epage.length))) 547 { 548 SanityManager.THROWASSERT( 549 "containerInfo too big for page array: " + 550 containerInfo.length); 551 } 552 553 if (BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + N >= 554 MAX_BORROWED_SPACE) 555 SanityManager.THROWASSERT( 556 "exceed max borrowable space: " + N); 557 } 558 559 if ((N + BORROWED_SPACE_LEN + BORROWED_SPACE_OFFSET) > epage.length) 560 { 561 if (SanityManager.DEBUG) 562 SanityManager.THROWASSERT( 563 "exceed max borrowable space on page: " + N); 564 } 565 566 if (create) 567 { 568 epage[BORROWED_SPACE_OFFSET] = (byte)N; 569 } 570 else 571 { 572 int oldN = (int)epage[BORROWED_SPACE_OFFSET]; 573 if (oldN != N) 574 { 575 throw StandardException.newException( 576 SQLState.DATA_CHANGING_CONTAINER_INFO, 577 new Long (oldN), 578 new Long (N)); 579 } 580 } 581 582 if (N != 0) 583 System.arraycopy(containerInfo, 0, epage, 584 BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, 585 N); 586 } 587 588 597 public static void ReadContainerInfo(byte[] containerInfo, 598 byte[] epage) 599 { 600 int N = (int)epage[BORROWED_SPACE_OFFSET]; 601 602 if (SanityManager.DEBUG) 603 { 604 if (N != containerInfo.length) 605 SanityManager.THROWASSERT("N not what is expected : " + N); 606 607 if (BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + N 608 >= MAX_BORROWED_SPACE) 609 { 610 SanityManager.THROWASSERT("exceed max borrowable space: " + N); 611 } 612 } 613 614 if (N != 0) 615 System.arraycopy(epage, BORROWED_SPACE_OFFSET+BORROWED_SPACE_LEN, 616 containerInfo, 0, N); 617 } 618 619 620 623 624 627 public long nextFreePageNumber(long pnum) 628 { 629 return extent.getFreePageNumber(pnum); 630 } 631 632 633 651 public void addPage(FileContainer mycontainer, long newPageNumber, 652 RawTransaction ntt, BaseContainerHandle userHandle) throws StandardException 653 { 654 661 owner.getAllocationActionSet(). 663 actionAllocatePage( 664 ntt, this, newPageNumber, 665 AllocExtent.ALLOCATED_PAGE, AllocExtent.FREE_PAGE); 666 } 667 668 669 672 public void deallocatePage(BaseContainerHandle userHandle, long pageNumber) 673 throws StandardException 674 { 675 if (SanityManager.DEBUG) { 676 SanityManager.ASSERT(isLatched()); 677 } 678 679 687 owner.getAllocationActionSet(). 688 actionAllocatePage(userHandle.getTransaction(), 689 this, pageNumber, AllocExtent.DEALLOCATED_PAGE, 690 AllocExtent.ALLOCATED_PAGE); 691 } 692 693 700 protected void updateUnfilledPageInfo(AllocExtent inputExtent) 701 { 702 if (SanityManager.DEBUG) { 703 SanityManager.ASSERT(isLatched()); 704 } 705 706 extent.updateUnfilledPageInfo(inputExtent); 713 714 } 715 716 public boolean canAddFreePage(long lastAllocatedPage) 717 { 718 if (SanityManager.DEBUG) 719 SanityManager.ASSERT(isLatched()); 720 721 if (extent.isRetired()) 722 return false; 723 724 if (lastAllocatedPage != ContainerHandle.INVALID_PAGE_NUMBER && 728 extent.getLastPagenum() <= lastAllocatedPage && 729 !isLast()) 730 return false; 731 732 return extent.canAddFreePage(lastAllocatedPage); 735 } 736 737 public long getNextAllocPageOffset() 738 { 739 if (SanityManager.DEBUG) 740 { 741 SanityManager.ASSERT( 742 !isLast(), "next alloc page not present for last alloc page"); 743 744 SanityManager.ASSERT(isLatched()); 745 } 746 747 return nextAllocPageOffset; 748 } 749 750 public void chainNewAllocPage(BaseContainerHandle allocHandle, 751 long newAllocPageNum, long newAllocPageOffset) 752 throws StandardException 753 { 754 if (SanityManager.DEBUG) 755 { 756 SanityManager.ASSERT(isLatched()); 757 if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE)) 758 SanityManager.DEBUG(FileContainer.SPACE_TRACE, 759 "chaining new alloc page " + 760 newAllocPageNum + " to " + 761 getPageNumber()); 762 } 763 764 owner.getAllocationActionSet(). 765 actionChainAllocPage(allocHandle.getTransaction(), 766 this, newAllocPageNum, newAllocPageOffset); 767 } 768 769 public long getNextAllocPageNumber() 770 { 771 if (SanityManager.DEBUG) 772 { 773 SanityManager.ASSERT(isLatched()); 774 SanityManager.ASSERT( 775 !isLast(), "next alloc page not present for last alloc page"); 776 } 777 return nextAllocPageNumber; 778 } 779 780 public boolean isLast() 781 { 782 if (SanityManager.DEBUG) 783 SanityManager.ASSERT(isLatched()); 784 return nextAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER; 785 } 786 787 790 public long getLastPagenum() 791 { 792 if (SanityManager.DEBUG) 793 SanityManager.ASSERT(isLatched()); 794 795 return extent.getLastPagenum(); 796 } 797 798 804 public long getMaxPagenum() 805 { 806 return extent.getExtentEnd(); 807 } 808 809 812 protected long getLastPreallocPagenum() 813 { 814 if (SanityManager.DEBUG) 815 SanityManager.ASSERT(isLatched()); 816 817 return extent.getLastPreallocPagenum(); 818 } 819 820 821 protected int getPageStatus(long pageNumber) 822 { 823 if (SanityManager.DEBUG) 824 SanityManager.ASSERT(isLatched()); 825 826 return extent.getPageStatus(pageNumber); 827 } 828 829 830 836 protected void setPageStatus(LogInstant instant, long pageNumber, int newStatus) throws StandardException 837 { 838 if (SanityManager.DEBUG) { 839 SanityManager.ASSERT(isLatched(), "page is not latched"); 840 SanityManager.ASSERT(extent != null, "extent is null"); 841 } 842 843 logAction(instant); 844 845 switch(newStatus) 846 { 847 case AllocExtent.ALLOCATED_PAGE: 848 extent.allocPage(pageNumber); 849 break; 850 case AllocExtent.DEALLOCATED_PAGE: 851 extent.deallocPage(pageNumber); 852 break; 853 case AllocExtent.FREE_PAGE: 854 extent.deallocPage(pageNumber); 855 break; 856 } 857 } 858 859 864 protected void chainNextAllocPage(LogInstant instant, 865 long newAllocPageNum, 866 long newAllocPageOffset) 867 throws StandardException 868 { 869 if (SanityManager.DEBUG) 870 SanityManager.ASSERT(isLatched(), "page is not latched"); 871 872 logAction(instant); 873 874 nextAllocPageNumber = newAllocPageNum; 875 nextAllocPageOffset = newAllocPageOffset; 876 } 877 878 902 protected void compressSpace( 903 LogInstant instant, 904 int new_highest_page, 905 int num_pages_truncated) 906 throws StandardException 907 { 908 if (SanityManager.DEBUG) 909 { 910 SanityManager.ASSERT(isLatched(), "page is not latched"); 911 SanityManager.ASSERT(isLast(), "compress on non last alloc page."); 912 SanityManager.ASSERT(new_highest_page >= 0, "negative new high page."); 913 } 914 915 logAction(instant); 916 917 extent.compressPages(new_highest_page, num_pages_truncated); 918 } 919 920 923 protected void undoCompressSpace( 924 LogInstant instant, 925 int new_highest_page, 926 int num_pages_truncated) 927 throws StandardException 928 { 929 logAction(instant); 930 931 extent.undoCompressPages(new_highest_page, num_pages_truncated); 932 933 } 934 935 public String toString() 936 { 937 if (SanityManager.DEBUG) 938 { 939 String str = 940 "*** Alloc page ***\n" + 941 "nextAllocPageNumber = " + nextAllocPageNumber + 942 "\nnextAllocPageOffset = " + nextAllocPageOffset + 943 "\nreserved1 = " + reserved1 + 944 "\nreserved2 = " + reserved2 + 945 "\nreserved3 = " + reserved3 + 946 "\nreserved4 = " + reserved4 + 947 "\nborrowedSpace = " + borrowedSpace + 948 "\nextent = " + extent.toDebugString() + "\n" + 949 super.toString(); 950 return str; 951 } 952 else 953 { 954 return null; 955 } 956 } 957 958 959 964 protected AllocExtent getAllocExtent() 965 { 966 return extent; 967 968 } 970 971 978 protected void preAllocatePage(FileContainer myContainer, 979 int preAllocThreshold, 980 int preAllocSize) 981 { 982 if (SanityManager.DEBUG) 983 SanityManager.ASSERT(isLatched(), "page is not latched"); 984 985 long lastPreallocatedPagenum = extent.getLastPreallocPagenum(); 986 987 if (lastPreallocatedPagenum < preAllocThreshold) 988 return; 989 990 if (extent.getExtentEnd() < (lastPreallocatedPagenum+preAllocSize)) 996 preAllocSize = (int)(extent.getExtentEnd() - lastPreallocatedPagenum); 997 998 if (preAllocSize <= 0) 999 return; 1000 1001 int n = myContainer.preAllocate(lastPreallocatedPagenum, preAllocSize); 1006 1007 if (n > 0) { 1009 extent.setLastPreallocPagenum(lastPreallocatedPagenum + n); 1022 1023 } 1028 1029 } 1030 1031 1058 protected boolean compress( 1059 RawTransaction ntt, 1060 FileContainer myContainer) 1061 throws StandardException 1062 { 1063 boolean all_pages_compressed = false; 1064 1065 if (SanityManager.DEBUG) 1066 { 1067 SanityManager.ASSERT(isLatched(), "page is not latched"); 1068 } 1069 1070 int last_valid_page = extent.compress(owner, ntt, this); 1071 1072 if (last_valid_page >= 0) 1073 { 1074 myContainer.truncatePages(extent.getPagenum(last_valid_page)); 1077 1078 if (last_valid_page == this.getPageNumber()) 1079 { 1080 all_pages_compressed = true; 1082 } 1083 } 1084 1085 return(all_pages_compressed); 1086 } 1087 1088 1095 public static final String TEST_MULTIPLE_ALLOC_PAGE = SanityManager.DEBUG ? "TEST_MULTI_ALLOC_PAGE" : null; 1096} 1097 | Popular Tags |