📄 allocpage.java
字号:
/* Derby - Class org.apache.derby.impl.store.raw.data.AllocPage Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */package org.apache.derby.impl.store.raw.data;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.reference.SQLState;import org.apache.derby.iapi.services.io.TypedFormat;import org.apache.derby.iapi.services.io.FormatIdUtil;import org.apache.derby.iapi.services.io.StoredFormatIds;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.store.raw.ContainerHandle;import org.apache.derby.iapi.store.raw.Loggable;import org.apache.derby.iapi.store.raw.PageKey;import org.apache.derby.iapi.store.raw.PageTimeStamp;import org.apache.derby.iapi.store.raw.RawStoreFactory;import org.apache.derby.iapi.store.raw.log.LogInstant;import org.apache.derby.iapi.store.raw.xact.RawTransaction;import org.apache.derby.impl.store.raw.data.BaseContainerHandle;import org.apache.derby.impl.store.raw.data.BasePage;import org.apache.derby.impl.store.raw.data.PageVersion;import java.io.IOException;import java.io.ObjectOutput;import java.io.ObjectInput;import org.apache.derby.iapi.services.io.ArrayInputStream;/** An allocation page of the file container. <P> This class extends a normal Stored page, with the exception that a hunk of space may be 'borrowed' by the file container to store the file header. <P> The borrowed space is not visible to the alloc page even though it is present in the page data array. It is accessed directly by the FileContainer. Any change made to the borrowed space is not managed or seen by the allocation page. <P The reason for having this borrowed space is so that the container header does not need to have a page of its own. <P><B>Page Format</B><BR> An allocation page extends a stored page, the on disk format is different from a stored page in that N bytes are 'borrowed' by the container and the page header of an allocation page will be slightly bigger than a normal stored page. This N bytes are stored between the page header and the record space. <P> The reason why this N bytes can't simply be a row is because it needs to be statically accessible by the container object to avoid a chicken and egg problem of the container object needing to instantiate an alloc page object before it can be objectified, and an alloc page object needing to instantiate a container object before it can be objectified. So this N bytes must be stored outside of the normal record interface yet it must be settable because only the first alloc page has this borrowed space. Other (non-first) alloc page have N == 0. <PRE> <-- borrowed -> +----------+-------------+---+---------+-------------------+-------------+--------+ | FormatId | page header | N | N bytes | alloc extend rows | slot offset |checksum| +----------+-------------+---+---------+-------------------+-------------+--------+ </PRE> N is a byte that indicates the size of the borrowed space. Once an alloc page is initialized, the value of N cannot change. <P> The maximum space that can be borrowed by the container is 256 bytes. <P> The allocation page are of the same page size as any other pages in the container. The first allocation page of the FileContainer starts at the first physical byte of the container. Subsequent allocation pages are chained via the nextAllocPageOffset. Each allocation page is expected to manage at least 1000 user pages (for 1K page size) so this chaining may not be a severe performance hit. The logical -> physical mapping of an allocation page is stored in the previous allocation page. The container object will need to maintain this mapping. <P> The following fields are stored in the page header <PRE> @format_id RAW_STORE_ALLOC_PAGE @purpose manage page allocation @upgrade @disk_layout FormatId(int) StoredPageHeader see StoredPage nextAllocPageNubmer(long) the next allocation page's number nextAllocPageOffset(long) the file offset of the next allocation page reserved1(long) reserved for future usage reserved2(long) reserved for future usage reserved3(long) reserved for future usage reserved4(long) reserved for future usage N(byte) the size of the borrowed container info containerInfo(byte[N]) the content of the borrowed container info AllocExtent the one and only extent on this alloc page @end_format </PRE> <P> The allocation page contains allocation extent rows. In this first cut implementation, there is only 1 allocation extent row per allocation page. <P> The allocation extent row is an externalizable object and is directly written on to the page by the alloc page. In other words, it will not be converted in to a storeableRow. This is to cut down overhead, enhance performance and gives more control of the size and layout of the allocation extent row to the alloc page. <P> <HR WIDTH="100%"> <BR> DETAIL implmentation notes <BR> <HR WIDTH="100%"> <P> Create Container - an embryonic allocation page is formatted on disk by a spcial static function to avoid instantiating a full AllocPage object. This embryonic allocation has enough information that it can find the file header and not much else. Then the allocation page is perperly initiated by creating the first extent. <P> Open Container - A static AllocPage method will be used to read off the container information directly from disk. Even if the first alloc page (page 0) is already in the page cache, it will not be used because cleaning the alloc page will introduce a deadlock if the container is not in the container cache. Long term, the first alloc page should probably live in the container cache rather than in the page cache. <P> Get Page - The first alloc page (page 0) will be read into the page cache. Continue to follow the alloc page chain until the alloc page that manages the specified page is found. From the alloc page, the physical offset of the specified page is located. <P> Cleaning alloc page - the alloc page is written out the same way any page is written out. The container object will provide a call back to the alloc page to write the current version of the container object back into the borrowed space before the alloc page itself is written out. <P> Cleaning the container object - get the the first alloc page, dirty it and clean it (which will cause it to call the container object to write itself out into the borrowed space). The versioning of the container is independent of the versioning of the alloc page. The container version is stored inside the borrowed space and is opaque to the alloc page. <P> For the fields in an allocation extent row @see AllocExtent*/public class AllocPage extends StoredPage{ /* * typed format */ public static final int FORMAT_NUMBER = StoredFormatIds.RAW_STORE_ALLOC_PAGE; // format Id must fit in 4 bytes /** Return my format identifier. */ public int getTypeFormatId() { return StoredFormatIds.RAW_STORE_ALLOC_PAGE; } /***************************************************************** * alloc page header *****************************************************************/ private long nextAllocPageNumber; // if isLast, nextAllocPageNumber == INVALID_PAGE_NUMBER private long nextAllocPageOffset; private long reserved1; private long reserved2; private long reserved3; private long reserved4; private AllocExtent extent; private int borrowedSpace; /***************************************************************** * constants *****************************************************************/ /* * allocation page header * 8 bytes long next alloc page number * 8 bytes long next alloc page physical offset * 8 bytes long reserved1 * 8 bytes long reserved2 * 8 bytes long reserved3 * 8 bytes long reserved4 */ protected static final int ALLOC_PAGE_HEADER_OFFSET = StoredPage.PAGE_HEADER_OFFSET + StoredPage.PAGE_HEADER_SIZE; protected static final int ALLOC_PAGE_HEADER_SIZE = 8+8+(4*8); /* borrowed_SPACE_OFFSET is where the borrowed space len is kept */ protected static final int BORROWED_SPACE_OFFSET = ALLOC_PAGE_HEADER_OFFSET + ALLOC_PAGE_HEADER_SIZE; /* size of the borrowed space length */ protected static final int BORROWED_SPACE_LEN = 1; // 1 byte to store the containerInfo length /* * BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN is the beginning offset of * the borrowed space */ /* * the entire borrowed space must live within MAX_BORROWED_SPACE of the * alloc page */ protected static final int MAX_BORROWED_SPACE = RawStoreFactory.PAGE_SIZE_MINIMUM / 5; // cannot take more then 1/5 of the page public AllocPage() { super(); } /* * overwriting StoredPage methods */ protected int getMaxFreeSpace() { // the maximum free space is reduced by the allocation page header the // size of the borrowed space. In all allocation page except the first // one, there is no borrowed space and this is indeed the max free // space. In the first allocation page, need to further subtract // the borrowed space return super.getMaxFreeSpace() - ALLOC_PAGE_HEADER_SIZE - BORROWED_SPACE_LEN - borrowedSpace; } /* * Methods of cachedPage - create, read and write up a page * Overwriting StoredPage's CachedPage methods */ /** * Create a new alloc page. * * @exception StandardException Standard exception policy. **/ protected void createPage(PageKey newIdentity, int[] args) throws StandardException { super.createPage(newIdentity, args); // args[0] is the format id // args[1] is whether to sync the page to disk or not // args[2] is the pagesize (used by StoredPage) // args[3] is the spareSize (used by StoredPage) // args[4] is the number of bytes to reserve for container header // args[5] is the minimumRecordSize // NOTE: the arg list here must match the one in FileContainer int pageSize = args[2]; int minimumRecordSize = args[5]; borrowedSpace = args[4]; if (SanityManager.DEBUG) { // MAX_BORROWED_SPACE can't be bigger than what can be represented in 1 byte space SanityManager.ASSERT(MAX_BORROWED_SPACE <= 255); if (!(borrowedSpace + BORROWED_SPACE_LEN + BORROWED_SPACE_OFFSET < MAX_BORROWED_SPACE)) { SanityManager.THROWASSERT( "borrowedSpace too big = " + borrowedSpace); } SanityManager.ASSERT(pageData != null); } pageData[BORROWED_SPACE_OFFSET] = (byte)borrowedSpace; // remember that the borrowed space have been wiped out now, it // needs to be put back when the page is written out. // blot out borrowed space before checksum is verified if (borrowedSpace > 0) { clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, borrowedSpace); } // init the rest of the header and the allocation extent nextAllocPageNumber = ContainerHandle.INVALID_PAGE_NUMBER; nextAllocPageOffset = 0; reserved1 = reserved2 = reserved3 = reserved4 = 0; // calculate how much space we have left for the extent map int maxSpace = getMaxFreeSpace(); // the pages this extent is going to manage starts from pageNum+1 // starting physical offset is pageSize*(pageNum+1) since we have // no logical to physical mapping yet... extent = createExtent(newIdentity.getPageNumber()+1, pageSize, 0 /* pagesAlloced */, maxSpace); } private AllocExtent createExtent(long pageNum, int pageSize, int pagesAlloced, int availspace) { int maxPages = AllocExtent.MAX_RANGE(availspace); if (SanityManager.DEBUG) SanityManager.ASSERT(maxPages > 8, "cannot manage > 8 pages"); if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(TEST_MULTIPLE_ALLOC_PAGE)) { maxPages = 2; // 2 pages per alloc page } } return new AllocExtent(pageNum*pageSize, // starting offset pageNum, // extent start page number pagesAlloced, // #pages already allocated pageSize, // page size maxPages); // max #pages to manage } /** Initialize in memory structure using the buffer in pageData @exception StandardException If the page cannot be read correctly, or is inconsistent. */ protected void initFromData(FileContainer myContainer, PageKey newIdentity) throws StandardException { if (pageData.length < BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN) { throw dataFactory.markCorrupt( StandardException.newException( SQLState.DATA_CORRUPT_PAGE, newIdentity)); } byte n = pageData[BORROWED_SPACE_OFFSET]; borrowedSpace = (int)n;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -