001: /*
002:
003: Derby - Class org.apache.derby.impl.store.raw.data.CachedPage
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.store.raw.data;
023:
024: import org.apache.derby.iapi.reference.SQLState;
025:
026: import org.apache.derby.impl.store.raw.data.BasePage;
027:
028: import org.apache.derby.iapi.store.raw.log.LogInstant;
029: import org.apache.derby.iapi.store.raw.ContainerHandle;
030: import org.apache.derby.iapi.store.raw.PageKey;
031:
032: import org.apache.derby.iapi.services.cache.Cacheable;
033: import org.apache.derby.iapi.services.cache.CacheManager;
034: import org.apache.derby.iapi.services.context.ContextService;
035:
036: import org.apache.derby.iapi.services.monitor.Monitor;
037:
038: import org.apache.derby.iapi.services.sanity.SanityManager;
039:
040: import org.apache.derby.iapi.services.io.FormatIdUtil;
041: import org.apache.derby.iapi.services.io.StoredFormatIds;
042:
043: import org.apache.derby.iapi.error.StandardException;
044: import org.apache.derby.iapi.error.ExceptionSeverity;
045: import java.io.IOException;
046:
047: /**
048: A base page that is cached.
049:
050: Since there are multiple page formats, use this abstract class to implement
051: cacheable interface.
052:
053: */
054:
055: public abstract class CachedPage extends BasePage implements Cacheable {
056: protected boolean alreadyReadPage; // true when page read by another
057: // class
058:
059: protected byte[] pageData; // the actual page data - this is
060: // the 'buffer' in the buffer cache
061:
062: // The isDirty flag indicates if the pageData or pageHeader has been
063: // modified. The preDirty flag indicates that the pageData or the
064: // pageHeader is about to be modified. The reason for these 2 flags
065: // instead of just one is to accomodate checkpoint. After a clean
066: // (latched) page sends a log record to the log stream but before that page
067: // is dirtied by the log operation, a checkpoint could be taken. If so,
068: // then the redoLWM will be after the log record but, without preDirty, the
069: // cache cleaning will not have waited for the change. So the preDirty bit
070: // is to stop the cache cleaning from skipping over this (latched) page
071: // even though it has not really been modified yet.
072:
073: protected boolean isDirty; // must be set to true whenever the
074: // pageData array is touched
075: // directly or indirectly.
076:
077: protected boolean preDirty; // set to true if the page is clean
078: // and the pageData array is about
079: // to be touched directly or
080: // indirectly.
081:
082: protected int initialRowCount; // keep a running count of rows for
083: // estimated row count.
084:
085: private long containerRowCount; // the number of rows in the
086: // container when this page is read
087: // from disk
088:
089: /*
090: ** These fields are immutable and can be used by the subclasses directly.
091: */
092:
093: /**
094: The page cache I live in.
095:
096: <BR> MT - Immutable
097: */
098: protected CacheManager pageCache;
099:
100: /**
101: The container cache my container lives in.
102:
103: <BR> MT - Immutable
104: */
105: protected CacheManager containerCache;
106:
107: /**
108: My factory class.
109:
110: <BR> MT - Immutable -
111: */
112: protected BaseDataFileFactory dataFactory; // my factory class.
113:
114: protected static final int PAGE_FORMAT_ID_SIZE = 4;
115:
116: /*
117: * the page need to be written and synced to disk
118: */
119: public static final int WRITE_SYNC = 1;
120:
121: /*
122: * the page need to be write to disk but not synced
123: */
124: public static final int WRITE_NO_SYNC = 2;
125:
126: public CachedPage() {
127: super ();
128: }
129:
130: public final void setFactory(BaseDataFileFactory factory) {
131: dataFactory = factory;
132: pageCache = factory.getPageCache();
133: containerCache = factory.getContainerCache();
134: }
135:
136: /**
137: Initialize a CachedPage.
138: <p>
139: Initialize the object, ie. perform work normally perfomed in
140: constructor. Called by setIdentity() and createIdentity().
141: */
142: protected void initialize() {
143: super .initialize();
144: isDirty = false;
145: preDirty = false;
146: initialRowCount = 0;
147: containerRowCount = 0;
148: }
149:
150: /*
151: ** Methods of Cacheable
152: */
153:
154: /**
155: * Find the container and then read the page from that container.
156: * <p>
157: * This is the way new pages enter the page cache.
158: * <p>
159: *
160: * @return always true, higher levels have already checked the page number
161: * is valid for an open.
162: *
163: * @exception StandardException Standard Cloudscape policy.
164: *
165: * @see Cacheable#setIdentity
166: **/
167: public Cacheable setIdentity(Object key) throws StandardException {
168: if (SanityManager.DEBUG) {
169: SanityManager.ASSERT(key instanceof PageKey);
170: }
171:
172: initialize();
173:
174: PageKey newIdentity = (PageKey) key;
175:
176: FileContainer myContainer = (FileContainer) containerCache
177: .find(newIdentity.getContainerId());
178:
179: setContainerRowCount(myContainer.getEstimatedRowCount(0));
180:
181: try {
182: if (!alreadyReadPage) {
183: // Fill in the pageData array by reading bytes from disk.
184: readPage(myContainer, newIdentity);
185: } else {
186: // pageData array already filled
187: alreadyReadPage = false;
188: }
189:
190: // if the formatID on disk is not the same as this page instance's
191: // format id, instantiate the real page object
192: int fmtId = getTypeFormatId();
193:
194: int onPageFormatId = FormatIdUtil
195: .readFormatIdInteger(pageData);
196: if (fmtId != onPageFormatId) {
197: return changeInstanceTo(onPageFormatId, newIdentity)
198: .setIdentity(key);
199: }
200:
201: // this is the correct page instance
202: initFromData(myContainer, newIdentity);
203: } finally {
204: containerCache.release(myContainer);
205: myContainer = null;
206: }
207:
208: fillInIdentity(newIdentity);
209:
210: initialRowCount = 0;
211:
212: return this ;
213: }
214:
215: /**
216: * Find the container and then create the page in that container.
217: * <p>
218: * This is the process of creating a new page in a container, in that
219: * case no need to read the page from disk - just need to initialize it
220: * in the cache.
221: * <p>
222: *
223: * @return new page, higher levels have already checked the page number is
224: * valid for an open.
225: *
226: * @param key Which page is this?
227: * @param createParameter details needed to create page like size,
228: * format id, ...
229: *
230: * @exception StandardException Standard exception policy.
231: *
232: * @see Cacheable#createIdentity
233: **/
234: public Cacheable createIdentity(Object key, Object createParameter)
235: throws StandardException {
236:
237: if (SanityManager.DEBUG) {
238: SanityManager.ASSERT(key instanceof PageKey);
239: }
240:
241: initialize();
242:
243: PageKey newIdentity = (PageKey) key;
244:
245: int[] createArgs = (int[]) createParameter;
246:
247: if (createArgs[0] == -1) {
248: throw StandardException.newException(
249: SQLState.DATA_UNKNOWN_PAGE_FORMAT, newIdentity);
250: }
251:
252: // createArgs[0] contains the integer form of the formatId
253: // if it is not the same as this instance's formatId, instantiate the
254: // real page object
255: if (createArgs[0] != getTypeFormatId()) {
256: return (changeInstanceTo(createArgs[0], newIdentity)
257: .createIdentity(key, createParameter));
258: }
259:
260: // this is the correct page instance
261: initializeHeaders(5);
262: createPage(newIdentity, createArgs);
263:
264: fillInIdentity(newIdentity);
265:
266: initialRowCount = 0;
267:
268: /*
269: * if we need to grow the container and the page has not been
270: * preallocated, writing page before the log is written so that we
271: * know if there is an IO error - like running out of disk space - then
272: * we don't write out the log record, because if we do, it may fail
273: * after the log goes to disk and then the database may not be
274: * recoverable.
275: *
276: * WRITE_SYNC is used when we create the page without first
277: * preallocating it
278: * WRITE_NO_SYNC is used when we are preallocating the page - there
279: * will be a SYNC call after all the pages are preallocated
280: * 0 means creating a page that has already been preallocated.
281: */
282: if ((createArgs[1] & WRITE_SYNC) != 0
283: || (createArgs[1] & WRITE_NO_SYNC) != 0)
284: writePage(newIdentity, (createArgs[1] & WRITE_SYNC) != 0);
285:
286: if (SanityManager.DEBUG) {
287: if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE)) {
288: String syncFlag = ((createArgs[1] & WRITE_SYNC) != 0) ? "Write_Sync"
289: : (((createArgs[1] & WRITE_NO_SYNC) != 0) ? "Write_NO_Sync"
290: : "No_write");
291:
292: SanityManager.DEBUG(FileContainer.SPACE_TRACE,
293: "creating new page " + newIdentity + " with "
294: + syncFlag);
295: }
296: }
297:
298: return this ;
299: }
300:
301: /**
302: * Convert this page to requested type, as defined by input format id.
303: * <p>
304: * The current cache entry is a different format id than the requested
305: * type, change it. This object is instantiated to the wrong subtype of
306: * cachedPage, this routine will create an object with the correct subtype,
307: * and transfer all pertinent information from this to the new correct
308: * object.
309: * <p>
310: *
311: * @return The new object created with the input fid and transfered info.
312: *
313: * @param fid The format id of the new page.
314: * @param newIdentity The key of the new page.
315: *
316: * @exception StandardException Standard exception policy.
317: **/
318: private CachedPage changeInstanceTo(int fid, PageKey newIdentity)
319: throws StandardException {
320: CachedPage realPage;
321: try {
322: realPage = (CachedPage) Monitor
323: .newInstanceFromIdentifier(fid);
324:
325: } catch (StandardException se) {
326: if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY) {
327: throw se;
328: } else {
329: throw StandardException.newException(
330: SQLState.DATA_UNKNOWN_PAGE_FORMAT, se,
331: newIdentity);
332: }
333: }
334:
335: realPage.setFactory(dataFactory);
336:
337: // avoid creating the data buffer if possible, transfer it to the new
338: // page if this is the first time the page buffer is used, then
339: // createPage will create the page array with the correct page size
340: if (this .pageData != null) {
341: realPage.alreadyReadPage = true;
342: realPage.usePageBuffer(this .pageData);
343: }
344:
345: // RESOLVE (12/15/06) - the following code is commented out, but
346: // not sure why.
347:
348: // this page should not be used any more, null out all its content and
349: // wait for GC to clean it up
350:
351: //destroyPage();// let this subtype have a chance to get rid of stuff
352: //this.pageData = null; // this instance no longer own the data array
353: //this.pageCache = null;
354: //this.dataFactory = null;
355: //this.containerCache = null;
356:
357: return realPage;
358: }
359:
360: /**
361: * Is the page dirty?
362: * <p>
363: * The isDirty flag indicates if the pageData or pageHeader has been
364: * modified. The preDirty flag indicates that the pageData or the
365: * pageHeader is about to be modified. The reason for these 2 flags
366: * instead of just one is to accomodate checkpoint. After a clean
367: * (latched) page sends a log record to the log stream but before that page
368: * is dirtied by the log operation, a checkpoint could be taken. If so,
369: * then the redoLWM will be after the log record but, without preDirty, the
370: * cache cleaning will not have waited for the change. So the preDirty bit
371: * is to stop the cache cleaning from skipping over this (latched) page
372: * even though it has not really been modified yet.
373: *
374: * @return true if the page is dirty.
375: *
376: * @see Cacheable#isDirty
377: **/
378: public boolean isDirty() {
379: synchronized (this ) {
380: return isDirty || preDirty;
381: }
382: }
383:
384: /**
385: * Has the page or its header been modified.
386: * <p>
387: * See comment on class header on meaning of isDirty and preDirty bits.
388: * <p>
389: *
390: * @return true if changes have actually been made to the page in memory.
391: **/
392: public boolean isActuallyDirty() {
393: synchronized (this ) {
394: return isDirty;
395: }
396: }
397:
398: /**
399: * Set state to indicate the page or its header is about to be modified.
400: * <p>
401: * See comment on class header on meaning of isDirty and preDirty bits.
402: **/
403: public void preDirty() {
404: synchronized (this ) {
405: if (!isDirty)
406: preDirty = true;
407: }
408: }
409:
410: /**
411: * Set state to indicate the page or its header has been modified.
412: * <p>
413: * See comment on class header on meaning of isDirty and preDirty bits.
414: * <p>
415: **/
416: protected void setDirty() {
417: synchronized (this ) {
418: isDirty = true;
419: preDirty = false;
420: }
421: }
422:
423: /**
424: * exclusive latch on page is being released.
425: * <p>
426: * The only work done in CachedPage is to update the row count on the
427: * container if it is too out of sync.
428: **/
429: protected void releaseExclusive() {
430: // look at dirty bit without latching, the updating of the row
431: // count is just an optimization so does not need the latch.
432: //
433: // if this page actually has > 1/8 rows of the entire container, then
434: // consider updating the row count if it is different.
435: //
436: // No need to special case allocation pages because it has recordCount
437: // of zero, thus the if clause will never be true for an allocation
438: // page.
439: if (isDirty && !isOverflowPage()
440: && (containerRowCount / 8) < recordCount()) {
441: int currentRowCount = internalNonDeletedRecordCount();
442: int delta = currentRowCount - initialRowCount;
443: int posDelta = delta > 0 ? delta : (-delta);
444:
445: if ((containerRowCount / 8) < posDelta) {
446: // This pages delta row count represents a significant change
447: // with respect to current container row count so update
448: // container row count
449: FileContainer myContainer = null;
450:
451: try {
452: myContainer = (FileContainer) containerCache
453: .find(identity.getContainerId());
454:
455: if (myContainer != null) {
456: myContainer.updateEstimatedRowCount(delta);
457: setContainerRowCount(myContainer
458: .getEstimatedRowCount(0));
459:
460: initialRowCount = currentRowCount;
461:
462: // since I have the container, might as well update the
463: // unfilled information
464: myContainer.trackUnfilledPage(identity
465: .getPageNumber(), unfilled());
466: }
467: } catch (StandardException se) {
468: // do nothing, not sure what could fail but this update
469: // is just an optimization so no need to throw error.
470: } finally {
471: if (myContainer != null)
472: containerCache.release(myContainer);
473: }
474: }
475: }
476:
477: super .releaseExclusive();
478: }
479:
480: /**
481: * Write the page to disk.
482: * <p>
483: * MP - In a simple world we would just not allow clean until it held the
484: * latch on the page. But in order to fit into the cache system, we
485: * don't have enough state around to just make clean() latch the page
486: * while doing the I/O - but we still need someway to insure that no
487: * changes happen to the page while the I/O is taking place.
488: * Also someday it would be fine to allow reads of this page
489: * while the I/O was taking place.
490: *
491: *
492: * @exception StandardException Error writing the page.
493: *
494: * @see Cacheable#clean
495: **/
496: public void clean(boolean remove) throws StandardException {
497:
498: // must wait for the page to be unlatched
499: synchronized (this ) {
500: if (!isDirty())
501: return;
502:
503: // is someone else cleaning it
504: while (inClean) {
505: try {
506: wait();
507: } catch (InterruptedException ie) {
508: throw StandardException.interrupt(ie);
509: }
510: }
511:
512: // page is not "inClean" by other thread at this point.
513:
514: if (!isDirty())
515: return;
516:
517: inClean = true;
518:
519: // If page is in LATCHED state (as opposed to UNLATCH or PRELATCH)
520: // wait for the page to move to UNLATCHED state. See Comments in
521: // Generic/BasePage.java describing the interaction of inClean,
522: // (owner != null), and preLatch.
523: while ((owner != null) && !preLatch) {
524: try {
525: wait();
526: } catch (InterruptedException ie) {
527: inClean = false;
528: throw StandardException.interrupt(ie);
529: }
530: }
531:
532: // The page is now effectively latched by the cleaner.
533: // We only want to clean the page if the page is actually dirtied,
534: // not when it is just pre-dirtied.
535: if (!isActuallyDirty()) {
536: // the person who latched it gives up the
537: // latch without really dirtying the page
538: preDirty = false;
539: inClean = false;
540: notifyAll();
541: return;
542: }
543: }
544:
545: try {
546: writePage(getPageId(), false);
547: } catch (StandardException se) {
548: // If we get an error while trying to write a page, current
549: // recovery system requires that entire DB is shutdown. Then
550: // when system is rebooted we will run redo recovery which
551: // if it does not encounter disk errors will guarantee to recover
552: // to a transaction consistent state. If this write is a
553: // persistent device problem, redo recovery will likely fail
554: // attempting to the same I/O. Mark corrupt will stop all further
555: // writes of data and log by the system.
556: throw dataFactory.markCorrupt(se);
557: } finally {
558: // if there is something wrong in writing out the page,
559: // do not leave it inClean state or it will block the next cleaner
560: // forever
561:
562: synchronized (this ) {
563: inClean = false;
564: notifyAll();
565: }
566: }
567: }
568:
569: public void clearIdentity() {
570: alreadyReadPage = false;
571: super .clearIdentity();
572: }
573:
574: /**
575: * read the page from disk into this CachedPage object.
576: * <p>
577: * A page is read in from disk into the pageData array of this object,
578: * and then put in the cache.
579: * <p>
580: *
581: * @param myContainer the container to read the page from.
582: * @param newIdentity indentity (ie. page number) of the page to read
583: *
584: * @exception StandardException Standard exception policy.
585: **/
586: private void readPage(FileContainer myContainer, PageKey newIdentity)
587: throws StandardException {
588: int pagesize = myContainer.getPageSize();
589:
590: // we will reuse the existing page array if it is same size, the
591: // cache does support caching various sized pages.
592: setPageArray(pagesize);
593:
594: for (int io_retry_count = 0;;) {
595: try {
596: myContainer.readPage(newIdentity.getPageNumber(),
597: pageData);
598: break;
599: } catch (IOException ioe) {
600: io_retry_count++;
601:
602: // Retrying read I/O's has been found to be successful sometimes
603: // in completing the read without having to fail the calling
604: // query, and in some cases avoiding complete db shutdown.
605: // Some situations are:
606: // spurious interrupts being sent to thread by clients.
607: // unreliable hardware like a network mounted file system.
608: //
609: // The only option other than retrying is to fail the I/O
610: // immediately and throwing an error, thus performance cost
611: // not really a consideration.
612: //
613: // The retry max of 4 is arbitrary, but has been enough that
614: // not many read I/O errors have been reported.
615: if (io_retry_count > 4) {
616: // page cannot be physically read
617:
618: StandardException se = StandardException
619: .newException(
620: SQLState.FILE_READ_PAGE_EXCEPTION,
621: ioe, newIdentity, new Integer(
622: pagesize));
623:
624: if (dataFactory.getLogFactory().inRFR()) {
625: //if in rollforward recovery, it is possible that this
626: //page actually does not exist on the disk yet because
627: //the log record we are proccessing now is actually
628: //creating the page, we will recreate the page if we
629: //are in rollforward recovery, so just throw the
630: //exception.
631: throw se;
632: } else {
633: if (SanityManager.DEBUG) {
634: // by shutting down system in debug mode, maybe
635: // we can catch root cause of the interrupt.
636: throw dataFactory.markCorrupt(se);
637: } else {
638: // No need to shut down runtime database on read
639: // error in delivered system, throwing exception
640: // should be enough. Thrown exception has nested
641: // IO exception which is root cause of error.
642: throw se;
643: }
644: }
645: }
646: }
647: }
648: }
649:
650: /**
651: * write the page from this CachedPage object to disk.
652: * <p>
653: *
654: * @param identity indentity (ie. page number) of the page to read
655: * @param syncMe does the write of this single page have to be sync'd?
656: *
657: * @exception StandardException Standard exception policy.
658: **/
659: private void writePage(PageKey identity, boolean syncMe)
660: throws StandardException {
661:
662: // make subclass write the page format
663: writeFormatId(identity);
664:
665: // let subclass have a chance to write any cached data to page data
666: // array
667: writePage(identity);
668:
669: // force WAL - and check to see if database is corrupt or is frozen.
670: // last log Instant may be null if the page is being forced
671: // to disk on a createPage (which violates the WAL protocol actually).
672: // See FileContainer.newPage
673: LogInstant flushLogTo = getLastLogInstant();
674: dataFactory.flush(flushLogTo);
675:
676: if (flushLogTo != null) {
677: clearLastLogInstant();
678: }
679:
680: // find the container and file access object
681: FileContainer myContainer = (FileContainer) containerCache
682: .find(identity.getContainerId());
683:
684: if (myContainer != null) {
685: try {
686: myContainer.writePage(identity.getPageNumber(),
687: pageData, syncMe);
688:
689: //
690: // Do some in memory unlogged bookkeeping tasks while we have
691: // the container.
692: //
693:
694: if (!isOverflowPage() && isDirty()) {
695:
696: // let the container knows whether this page is a not
697: // filled, non-overflow page
698: myContainer.trackUnfilledPage(identity
699: .getPageNumber(), unfilled());
700:
701: // if this is not an overflow page, see if the page's row
702: // count has changed since it come into the cache.
703: //
704: // if the page is not invalid, row count is 0. Otherwise,
705: // count non-deleted records on page.
706: //
707: // Cannot call nonDeletedRecordCount because the page is
708: // unlatched now even though nobody is changing it
709: int currentRowCount = internalNonDeletedRecordCount();
710:
711: if (currentRowCount != initialRowCount) {
712: myContainer
713: .updateEstimatedRowCount(currentRowCount
714: - initialRowCount);
715:
716: setContainerRowCount(myContainer
717: .getEstimatedRowCount(0));
718:
719: initialRowCount = currentRowCount;
720: }
721: }
722:
723: } catch (IOException ioe) {
724: // page cannot be written
725: throw StandardException.newException(
726: SQLState.FILE_WRITE_PAGE_EXCEPTION, ioe,
727: identity,
728: new Integer(myContainer.getPageSize()));
729: } finally {
730: containerCache.release(myContainer);
731: myContainer = null;
732: }
733: } else {
734: StandardException nested = StandardException.newException(
735: SQLState.DATA_CONTAINER_VANISHED, identity
736: .getContainerId());
737: throw dataFactory.markCorrupt(StandardException
738: .newException(SQLState.FILE_WRITE_PAGE_EXCEPTION,
739: nested, identity, new Integer(myContainer
740: .getPageSize())));
741: }
742:
743: synchronized (this ) {
744: // change page state to not dirty after the successful write
745: isDirty = false;
746: preDirty = false;
747: }
748: }
749:
750: public void setContainerRowCount(long rowCount) {
751: containerRowCount = rowCount;
752: }
753:
754: /*
755: ** if the page size is different from the page buffer, then make a
756: ** new page buffer and make subclass use the new page buffer
757: */
758:
759: protected void setPageArray(int pageSize) throws StandardException {
760: if ((pageData == null) || (pageData.length != pageSize)) {
761: pageData = new byte[pageSize];
762:
763: if (pageData == null || pageData.length != pageSize) {
764: throw StandardException.newException(
765: SQLState.DATA_OBJECT_ALLOCATION_FAILED, "PAGE");
766: }
767:
768: usePageBuffer(pageData);
769: }
770: }
771:
772: /**
773: * Returns the page data array used to write on disk version.
774: *
775: * <p>
776: * returns the page data array, that is actually written to the disk,
777: * when the page is cleaned from the page cache. Takes care of flushing
778: * in-memory information to the array (like page header and format id info).
779: * <p>
780: *
781: * @return The array of bytes that is the on disk version of page.
782: *
783: * @exception StandardException Standard exception policy.
784: **/
785: protected byte[] getPageArray() throws StandardException {
786: // make subclass write the page format
787: writeFormatId(identity);
788:
789: // let subclass have a chance to write any cached
790: // data to page data array
791: writePage(identity);
792:
793: return pageData;
794: }
795:
796: /* methods for subclass of cached page */
797:
798: // use a new pageData buffer, initialize in memory structure that depend on
799: // the pageData's size. The actual disk data may not have not been read in
800: // yet so don't look at the content of the buffer
801: protected abstract void usePageBuffer(byte[] buffer);
802:
803: // initialize in memory structure using the read in buffer in pageData
804: protected abstract void initFromData(FileContainer container,
805: PageKey id) throws StandardException;
806:
807: // create the page
808: protected abstract void createPage(PageKey id, int[] args)
809: throws StandardException;
810:
811: // page is about to be written, write everything to pageData array
812: protected abstract void writePage(PageKey id)
813: throws StandardException;
814:
815: // write out the formatId to the pageData
816: protected abstract void writeFormatId(PageKey identity)
817: throws StandardException;
818: }
|