📄 cachedpage.java
字号:
/* Derby - Class org.apache.derby.impl.store.raw.data.CachedPage 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.impl.store.raw.data.BasePage;import org.apache.derby.iapi.store.raw.log.LogInstant;import org.apache.derby.iapi.store.raw.ContainerHandle;import org.apache.derby.iapi.store.raw.PageKey;import org.apache.derby.iapi.services.cache.Cacheable;import org.apache.derby.iapi.services.cache.CacheManager;import org.apache.derby.iapi.services.context.ContextService;import org.apache.derby.iapi.services.monitor.Monitor;import org.apache.derby.iapi.services.sanity.SanityManager;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.error.ExceptionSeverity;import java.io.IOException;/** A base page that is cached. Since there are multiple page formats, use this abstract class to implement cacheable interface.*/public abstract class CachedPage extends BasePage implements Cacheable{ protected boolean alreadyReadPage; // true when page read by another // class protected byte[] pageData; // the actual page data - this is // the 'buffer' in the buffer cache // The isDirty flag indicates if the pageData or pageHeader has been // modified. The preDirty flag indicates that the pageData or the // pageHeader is about to be modified. The reason for these 2 flags // instead of just one is to accomodate checkpoint. After a clean // (latched) page sends a log record to the log stream but before that page // is dirtied by the log operation, a checkpoint could be taken. If so, // then the redoLWM will be after the log record but, without preDirty, the // cache cleaning will not have waited for the change. So the preDirty bit // is to stop the cache cleaning from skipping over this (latched) page // even though it has not really been modified yet. protected boolean isDirty; // must be set to true whenever the // pageData array is touched // directly or indirectly. protected boolean preDirty; // set to true if the page is clean // and the pageData array is about // to be touched directly or // indirectly. protected int initialRowCount; // keep a running count of rows for // estimated row count. private long containerRowCount; // the number of rows in the // container when this page is read // from disk /* ** These fields are immutable and can be used by the subclasses directly. */ /** The page cache I live in. <BR> MT - Immutable */ protected CacheManager pageCache; /** The container cache my container lives in. <BR> MT - Immutable */ protected CacheManager containerCache; /** My factory class. <BR> MT - Immutable - */ protected BaseDataFileFactory dataFactory; // my factory class. protected static final int PAGE_FORMAT_ID_SIZE = 4; /* * the page need to be written and synced to disk */ public static final int WRITE_SYNC = 1; /* * the page need to be write to disk but not synced */ public static final int WRITE_NO_SYNC = 2; public CachedPage() { super(); } public final void setFactory(BaseDataFileFactory factory) { dataFactory = factory; pageCache = factory.getPageCache(); containerCache = factory.getContainerCache(); } /** Initialize a CachedPage. <p> Initialize the object, ie. perform work normally perfomed in constructor. Called by setIdentity() and createIdentity(). */ protected void initialize() { super.initialize(); isDirty = false; preDirty = false; initialRowCount = 0; containerRowCount = 0; } /* ** Methods of Cacheable */ /** * Find the container and then read the page from that container. * <p> * This is the way new pages enter the page cache. * <p> * * @return always true, higher levels have already checked the page number * is valid for an open. * * @exception StandardException Standard Cloudscape policy. * * @see Cacheable#setIdentity **/ public Cacheable setIdentity(Object key) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(key instanceof PageKey); } initialize(); PageKey newIdentity = (PageKey) key; FileContainer myContainer = (FileContainer) containerCache.find(newIdentity.getContainerId()); setContainerRowCount(myContainer.getEstimatedRowCount(0)); try { if (!alreadyReadPage) { // Fill in the pageData array by reading bytes from disk. readPage(myContainer, newIdentity); } else { // pageData array already filled alreadyReadPage = false; } // if the formatID on disk is not the same as this page instance's // format id, instantiate the real page object int fmtId = getTypeFormatId(); int onPageFormatId = FormatIdUtil.readFormatIdInteger(pageData); if (fmtId != onPageFormatId) { return changeInstanceTo( onPageFormatId, newIdentity).setIdentity(key); } // this is the correct page instance initFromData(myContainer, newIdentity); } finally { containerCache.release(myContainer); myContainer = null; } fillInIdentity(newIdentity); initialRowCount = 0; return this; } /** * Find the container and then create the page in that container. * <p> * This is the process of creating a new page in a container, in that * case no need to read the page from disk - just need to initialize it * in the cache. * <p> * * @return new page, higher levels have already checked the page number is * valid for an open. * * @param key Which page is this? * @param createParameter details needed to create page like size, * format id, ... * * @exception StandardException Standard exception policy. * * @see Cacheable#createIdentity **/ public Cacheable createIdentity( Object key, Object createParameter) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(key instanceof PageKey); } initialize(); PageKey newIdentity = (PageKey) key; int[] createArgs = (int[]) createParameter; if (createArgs[0] == -1) { throw StandardException.newException( SQLState.DATA_UNKNOWN_PAGE_FORMAT, newIdentity); } // createArgs[0] contains the integer form of the formatId // if it is not the same as this instance's formatId, instantiate the // real page object if (createArgs[0] != getTypeFormatId()) { return( changeInstanceTo(createArgs[0], newIdentity).createIdentity( key, createParameter)); } // this is the correct page instance initializeHeaders(5); createPage(newIdentity, createArgs); fillInIdentity(newIdentity); initialRowCount = 0; /* * if we need to grow the container and the page has not been * preallocated, writing page before the log is written so that we * know if there is an IO error - like running out of disk space - then * we don't write out the log record, because if we do, it may fail * after the log goes to disk and then the database may not be * recoverable. * * WRITE_SYNC is used when we create the page without first * preallocating it * WRITE_NO_SYNC is used when we are preallocating the page - there * will be a SYNC call after all the pages are preallocated * 0 means creating a page that has already been preallocated. */ if ((createArgs[1] & WRITE_SYNC) != 0 || (createArgs[1] & WRITE_NO_SYNC) != 0) writePage(newIdentity, (createArgs[1] & WRITE_SYNC) != 0); if (SanityManager.DEBUG) { if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE)) { String syncFlag = ((createArgs[1] & WRITE_SYNC) != 0) ? "Write_Sync" : (((createArgs[1] & WRITE_NO_SYNC) != 0) ? "Write_NO_Sync" : "No_write"); SanityManager.DEBUG( FileContainer.SPACE_TRACE, "creating new page " + newIdentity + " with " + syncFlag); } } return this; } /** * Convert this page to requested type, as defined by input format id. * <p> * The current cache entry is a different format id than the requested * type, change it. This object is instantiated to the wrong subtype of * cachedPage, this routine will create an object with the correct subtype, * and transfer all pertinent information from this to the new correct * object. * <p> * * @return The new object created with the input fid and transfered info. * * @param fid The format id of the new page. * @param newIdentity The key of the new page. * * @exception StandardException Standard exception policy. **/ private CachedPage changeInstanceTo(int fid, PageKey newIdentity) throws StandardException { CachedPage realPage; try { realPage = (CachedPage) Monitor.newInstanceFromIdentifier(fid); } catch (StandardException se) { if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY) { throw se; } else { throw StandardException.newException( SQLState.DATA_UNKNOWN_PAGE_FORMAT, se, newIdentity); } } realPage.setFactory(dataFactory); // avoid creating the data buffer if possible, transfer it to the new // page if this is the first time the page buffer is used, then // createPage will create the page array with the correct page size if (this.pageData != null) { realPage.alreadyReadPage = true; realPage.usePageBuffer(this.pageData); } // RESOLVE (12/15/06) - the following code is commented out, but // not sure why. // this page should not be used any more, null out all its content and // wait for GC to clean it up //destroyPage();// let this subtype have a chance to get rid of stuff //this.pageData = null; // this instance no longer own the data array //this.pageCache = null; //this.dataFactory = null; //this.containerCache = null; return realPage; } /** * Is the page dirty? * <p> * The isDirty flag indicates if the pageData or pageHeader has been * modified. The preDirty flag indicates that the pageData or the * pageHeader is about to be modified. The reason for these 2 flags * instead of just one is to accomodate checkpoint. After a clean * (latched) page sends a log record to the log stream but before that page * is dirtied by the log operation, a checkpoint could be taken. If so, * then the redoLWM will be after the log record but, without preDirty, the * cache cleaning will not have waited for the change. So the preDirty bit * is to stop the cache cleaning from skipping over this (latched) page * even though it has not really been modified yet. * * @return true if the page is dirty. * * @see Cacheable#isDirty **/ public boolean isDirty() { synchronized (this) { return isDirty || preDirty; } } /** * Has the page or its header been modified. * <p> * See comment on class header on meaning of isDirty and preDirty bits. * <p> * * @return true if changes have actually been made to the page in memory. **/ public boolean isActuallyDirty() { synchronized (this) { return isDirty; } } /** * Set state to indicate the page or its header is about to be modified. * <p> * See comment on class header on meaning of isDirty and preDirty bits. **/ public void preDirty() { synchronized (this) { if (!isDirty) preDirty = true; } } /** * Set state to indicate the page or its header has been modified. * <p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -