📄 basepage.java
字号:
/* Derby - Class org.apache.derby.impl.store.raw.data.BasePage 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.reference.SQLState;import org.apache.derby.iapi.services.io.FormatableBitSet;import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;import org.apache.derby.iapi.services.io.DynamicByteArrayOutputStream;import org.apache.derby.iapi.services.locks.C_LockFactory;import org.apache.derby.iapi.services.locks.Lockable;import org.apache.derby.iapi.services.locks.Latch;import org.apache.derby.iapi.services.locks.VirtualLockTable;import org.apache.derby.iapi.services.sanity.SanityManager;import org.apache.derby.iapi.services.io.LimitObjectInput;import org.apache.derby.iapi.services.io.TypedFormat;import org.apache.derby.iapi.error.StandardException;import org.apache.derby.iapi.store.raw.AuxObject;import org.apache.derby.iapi.store.raw.ContainerHandle;import org.apache.derby.iapi.store.raw.ContainerKey;import org.apache.derby.iapi.store.raw.FetchDescriptor;import org.apache.derby.iapi.store.raw.Page;import org.apache.derby.iapi.store.raw.PageKey;import org.apache.derby.iapi.store.raw.RecordHandle;import org.apache.derby.iapi.store.raw.RawStoreFactory;import org.apache.derby.iapi.store.raw.xact.RawTransaction;import org.apache.derby.iapi.store.raw.log.LogInstant;import org.apache.derby.iapi.store.access.Qualifier;import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;import org.apache.derby.iapi.types.DataValueDescriptor;import java.io.IOException;import java.io.OutputStream;import java.io.ObjectInput;import java.util.Hashtable;import java.util.Observer;import java.util.Observable;/** This class implements all the the generic locking behaviour for a Page. It leaves method used to log and store the records up to sub-classes. It is intended that the object can represent multiple pages from different containers during its lifetime. <P> A page contains a set of records, which can be accessed by "slot", which defines the order of the records on the page, or by "id" which defines the identity of the records on the page. Clients access records by both slot and id, depending on their needs. <P> BasePage implements Observer to watch the ContainerHandle which notifies its Observers when it is closing. <BR> MT - mutable **/public abstract class BasePage implements Page, Lockable, Observer, TypedFormat{ /** auxiliary object MT - mutable - content dynamic : single thread required. This reference is set while the page is latched and returned to callers of page while the page is latched. For correct MT behaviour it is assumed that the caller discards any reference to an auxiliary object once the page is unlatched. The reference mya be cleared while the page is latched, or while the page is being cleaned from the cache. In the latter case the cache manager ensures that only a single thread can access this object. */ private AuxObject auxObj; /** this page's identity <BR> MT - immutable - content dynamic : single thread required */ protected PageKey identity; /** In-memory slot table, array of StoredRecordHeaders. <BR> MT - Immutable - Content Dynamic : Single thread required. */ private StoredRecordHeader[] headers; // in memory slot table private int recordCount; /** Page owner during exclusive access. MT - mutable : single thread required, provided by Lockable single thread required. */ protected BaseContainerHandle owner; /** Count of times a latch is held nested during an abort */ private int nestedLatch; /** LockManager held latch during exclusive access. When this is not null, latch.getQualifier() == owner */ private Latch myLatch; protected boolean inClean; // is the page being cleaned /** * Used to determine latch state of a page. * * MT - mutable * * There are 3 latch states for a page: * * UNLATCHED - (owner == null) * PRELATCH - (owner != null) && preLatch * LATCHED - (owner != null) && !preLatch * * A page may be "cleaned" while it is either UNLATCHED, or PRELATCH, but * it must wait for it to be not LATCHED. * * A page may move from UNLATCHED to PRELATCH, while being cleaned. * A page must wait for !inClean before it can move from PRELATCH to * LATCHED. **/ protected boolean preLatch; /** Instant of last log record that updated this page. <BR> MT - mutable : latched */ private LogInstant lastLog; /** Version of the page. <BR> MT - mutable : single thread required - The page must be latched to access this variable or the page muts be in the noidentiy state. */ private long pageVersion = 0; // version of the page /** Status of the page */ private byte pageStatus; /** Values for pageStatus flag page goes thru the following transition: VALID_PAGE <-> deallocated page -> free page <-> VALID_PAGE deallocated and free page are both INVALID_PAGE as far as BasePage is concerned. When a page is deallocated, it transitioned from VALID to INVALID. When a page is allocated, it trnasitioned from INVALID to VALID. */ public static final byte VALID_PAGE = 1; public static final byte INVALID_PAGE = 2; /** Init page flag. INIT_PAGE_REUSE - set if page is being initialized for reuse INIT_PAGE_OVERFLOW - set if page will be an overflow page INIT_PAGE_REUSE_RECORDID - set if page is being reused and its record id can be reset to RecordHandle.FIRST_RECORD_ID, rather to 1+ next recordId on the page */ public static final int INIT_PAGE_REUSE = 0x1; public static final int INIT_PAGE_OVERFLOW = 0x2; public static final int INIT_PAGE_REUSE_RECORDID = 0x4; /** Log Record flag. Why the before image of this record is being logged LOG_RECORD_FOR_UPDATE - set if the record is being logged for update. LOG_RECORD_DEFAULT - for non update. LOG_RECORD_FOR_PURGE - set if the record is being logged for purges and no data required to ve logged. The other cases (copy, purge, delete), we don't need to distinguish, leave no bit set. */ public static final int LOG_RECORD_DEFAULT = 0x0; public static final int LOG_RECORD_FOR_UPDATE = 0x1; public static final int LOG_RECORD_FOR_PURGE = 0x2; /** ** Create a new, empty page. **/ protected BasePage() { } /** Initialized the BasePage. <p> Initialize the object, ie. perform work normally perfomed in constructor. Called by setIdentity() and createIdentity(). */ protected void initialize() { setAuxObject(null); identity = null; recordCount = 0; clearLastLogInstant(); if (SanityManager.DEBUG) { if (nestedLatch != 0) SanityManager.THROWASSERT("nestedLatch is non-zero in initialize - value = " + nestedLatch); if (inClean) SanityManager.THROWASSERT("inClean is true in initialize"); if (preLatch) SanityManager.THROWASSERT("preLatch is true in initialize"); } } /** Must be called by a sub-class before calling setHeaderAtSlot. */ protected void initializeHeaders(int numRecords) { if (SanityManager.DEBUG) { if (recordCount != 0) SanityManager.THROWASSERT( "record count = " + recordCount + " before initSlotTable is called"); } headers = new StoredRecordHeader[numRecords]; } /* ** Cacheable methods */ protected void fillInIdentity(PageKey key) { if (SanityManager.DEBUG) { SanityManager.ASSERT(identity == null); } identity = key; } public void clearIdentity() { if (SanityManager.DEBUG) { SanityManager.ASSERT(!isLatched()); } identity = null; cleanPageForReuse(); } /** Initialized this page for reuse or first use */ protected void cleanPageForReuse() { setAuxObject(null); recordCount = 0; } /** OK to hand object outside to cache.. */ public Object getIdentity() { return identity; } /* ** Methods of Page */ private static final RecordHandle InvalidRecordHandle = new RecordId( new PageKey( new ContainerKey(0,0), ContainerHandle.INVALID_PAGE_NUMBER), RecordHandle.INVALID_RECORD_HANDLE); public final RecordHandle getInvalidRecordHandle() { // a static invalid record handle return InvalidRecordHandle; } public static final RecordHandle MakeRecordHandle(PageKey pkey, int recordHandleConstant) throws StandardException { if (recordHandleConstant >= RecordHandle.FIRST_RECORD_ID) { throw StandardException.newException( SQLState.DATA_CANNOT_MAKE_RECORD_HANDLE, new Long(recordHandleConstant)); } return new RecordId(pkey, recordHandleConstant); } public final RecordHandle makeRecordHandle(int recordHandleConstant) throws StandardException { return MakeRecordHandle(getPageId(), recordHandleConstant); } /** @see Page#getPageNumber */ public final long getPageNumber() { if (SanityManager.DEBUG) { SanityManager.ASSERT(isLatched(), "page is not latched."); SanityManager.ASSERT(identity != null, "identity is null."); } return identity.getPageNumber(); } public final RecordHandle getRecordHandle(int recordId) { if (SanityManager.DEBUG) { SanityManager.ASSERT(isLatched()); } int slot = findRecordById(recordId, FIRST_SLOT_NUMBER); if (slot < 0) return null; return getRecordHandleAtSlot(slot); } public final RecordHandle getRecordHandleAtSlot(int slot) { return getHeaderAtSlot(slot).getHandle(getPageId(), slot); } /** @see Page#recordExists @exception StandardException recordHandle is not a valid record handle */ public final boolean recordExists(RecordHandle handle, boolean ignoreDelete) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(isLatched()); } if (handle.getId() < RecordHandle.FIRST_RECORD_ID) { throw StandardException.newException( SQLState.DATA_INVALID_RECORD_HANDLE, handle); } if (handle.getPageNumber() != getPageNumber()) return false; int slot = findRecordById(handle.getId(), handle.getSlotNumberHint()); return (slot >= FIRST_SLOT_NUMBER && (ignoreDelete || !isDeletedAtSlot(slot))); } /** <OL> <LI>Lock the record (according to the locking policy) <LI>If the record is deleted then return null. We must check after we hold the lock to ensure that we don't look at the delete status of an uncommitted record. <LI>Fetch the record <LI>Unlock the record (according to the locking policy) </OL> @see Page#fetch @exception StandardException messageId equals StandardException.newException(SQLState.RECORD_VANISHED If the record identfied by handle does not exist on this page. @exception StandardException Standard Cloudscape error policy @exception StandardException record is not on page with message id equal to StandardException.newException(SQLState.RECORD_VANISHED. */ public RecordHandle fetch( RecordHandle handle, Object[] row, FormatableBitSet validColumns, boolean forUpdate) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(isLatched()); } owner.getLockingPolicy().lockRecordForRead(myLatch, handle, forUpdate); // See if the record is deleted or not. int slot = getSlotNumber(handle); StoredRecordHeader recordHeader = getHeaderAtSlot(slot); if (recordHeader.isDeleted()) return null; FetchDescriptor hack_fetch = new FetchDescriptor( row.length, validColumns, (Qualifier[][]) null); // magic to copy rows across ... restoreRecordFromSlot( slot, row, hack_fetch, handle, recordHeader, true); owner.getLockingPolicy().unlockRecordAfterRead( owner.getTransaction(), owner, handle, forUpdate, true); return handle; } public RecordHandle fetchFromSlot( RecordHandle rh, int slot, Object[] row, FetchDescriptor fetchDesc, boolean ignoreDelete) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(isLatched());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -