/** * read the page from disk into this CachedPage object. * * <p>A page is read in from disk into the pageData array of this object, and then put in the * cache. * * <p> * * @param myContainer the container to read the page from. * @param newIdentity indentity (ie. page number) of the page to read * @exception StandardException Standard exception policy. */ private void readPage(FileContainer myContainer, PageKey newIdentity) throws StandardException { int pagesize = myContainer.getPageSize(); // we will reuse the existing page array if it is same size, the // cache does support caching various sized pages. setPageArray(pagesize); for (int io_retry_count = 0; ; ) { try { myContainer.readPage(newIdentity.getPageNumber(), pageData); break; } catch (IOException ioe) { io_retry_count++; // Retrying read I/O's has been found to be successful sometimes // in completing the read without having to fail the calling // query, and in some cases avoiding complete db shutdown. // Some situations are: // spurious interrupts being sent to thread by clients. // unreliable hardware like a network mounted file system. // // The only option other than retrying is to fail the I/O // immediately and throwing an error, thus performance cost // not really a consideration. // // The retry max of 4 is arbitrary, but has been enough that // not many read I/O errors have been reported. if (io_retry_count > 4) { // page cannot be physically read StandardException se = StandardException.newException( SQLState.FILE_READ_PAGE_EXCEPTION, ioe, newIdentity, new Integer(pagesize)); if (dataFactory.getLogFactory().inRFR()) { // if in rollforward recovery, it is possible that this // page actually does not exist on the disk yet because // the log record we are proccessing now is actually // creating the page, we will recreate the page if we // are in rollforward recovery, so just throw the // exception. throw se; } else { if (SanityManager.DEBUG) { // by shutting down system in debug mode, maybe // we can catch root cause of the interrupt. throw dataFactory.markCorrupt(se); } else { // No need to shut down runtime database on read // error in delivered system, throwing exception // should be enough. Thrown exception has nested // IO exception which is root cause of error. throw se; } } } } } }
/** * 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 Derby 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; }
/** * write the page from this CachedPage object to disk. * * <p> * * @param identity indentity (ie. page number) of the page to read * @param syncMe does the write of this single page have to be sync'd? * @exception StandardException Standard exception policy. */ private void writePage(PageKey identity, boolean syncMe) throws StandardException { // make subclass write the page format writeFormatId(identity); // let subclass have a chance to write any cached data to page data // array writePage(identity); // force WAL - and check to see if database is corrupt or is frozen. // last log Instant may be null if the page is being forced // to disk on a createPage (which violates the WAL protocol actually). // See FileContainer.newPage LogInstant flushLogTo = getLastLogInstant(); dataFactory.flush(flushLogTo); if (flushLogTo != null) { clearLastLogInstant(); } // find the container and file access object FileContainer myContainer = (FileContainer) containerCache.find(identity.getContainerId()); if (myContainer == null) { StandardException nested = StandardException.newException( SQLState.DATA_CONTAINER_VANISHED, identity.getContainerId()); throw dataFactory.markCorrupt( StandardException.newException(SQLState.FILE_WRITE_PAGE_EXCEPTION, nested, identity)); } try { myContainer.writePage(identity.getPageNumber(), pageData, syncMe); // // Do some in memory unlogged bookkeeping tasks while we have // the container. // if (!isOverflowPage() && isDirty()) { // let the container knows whether this page is a not // filled, non-overflow page myContainer.trackUnfilledPage(identity.getPageNumber(), unfilled()); // if this is not an overflow page, see if the page's row // count has changed since it come into the cache. // // if the page is not invalid, row count is 0. Otherwise, // count non-deleted records on page. // // Cannot call nonDeletedRecordCount because the page is // unlatched now even though nobody is changing it int currentRowCount = internalNonDeletedRecordCount(); if (currentRowCount != initialRowCount) { myContainer.updateEstimatedRowCount(currentRowCount - initialRowCount); setContainerRowCount(myContainer.getEstimatedRowCount(0)); initialRowCount = currentRowCount; } } } catch (IOException ioe) { // page cannot be written throw StandardException.newException(SQLState.FILE_WRITE_PAGE_EXCEPTION, ioe, identity); } finally { containerCache.release(myContainer); myContainer = null; } synchronized (this) { // change page state to not dirty after the successful write isDirty = false; preDirty = false; } }