KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > impl > store > raw > data > CachedPage


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.data.CachedPage
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

21
22 package org.apache.derby.impl.store.raw.data;
23
24 import org.apache.derby.iapi.reference.SQLState;
25
26 import org.apache.derby.impl.store.raw.data.BasePage;
27
28 import org.apache.derby.iapi.store.raw.log.LogInstant;
29 import org.apache.derby.iapi.store.raw.ContainerHandle;
30 import org.apache.derby.iapi.store.raw.PageKey;
31
32 import org.apache.derby.iapi.services.cache.Cacheable;
33 import org.apache.derby.iapi.services.cache.CacheManager;
34 import org.apache.derby.iapi.services.context.ContextService;
35
36 import org.apache.derby.iapi.services.monitor.Monitor;
37
38 import org.apache.derby.iapi.services.sanity.SanityManager;
39
40 import org.apache.derby.iapi.services.io.FormatIdUtil;
41 import org.apache.derby.iapi.services.io.StoredFormatIds;
42
43 import org.apache.derby.iapi.error.StandardException;
44 import org.apache.derby.iapi.error.ExceptionSeverity;
45 import java.io.IOException JavaDoc;
46
47 /**
48     A base page that is cached.
49
50     Since there are multiple page formats, use this abstract class to implement
51     cacheable interface.
52
53 */

54
55 public abstract class CachedPage extends BasePage implements Cacheable
56 {
57     protected boolean alreadyReadPage; // true when page read by another
58
// class
59

60     protected byte[] pageData; // the actual page data - this is
61
// the 'buffer' in the buffer cache
62

63     // The isDirty flag indicates if the pageData or pageHeader has been
64
// modified. The preDirty flag indicates that the pageData or the
65
// pageHeader is about to be modified. The reason for these 2 flags
66
// instead of just one is to accomodate checkpoint. After a clean
67
// (latched) page sends a log record to the log stream but before that page
68
// is dirtied by the log operation, a checkpoint could be taken. If so,
69
// then the redoLWM will be after the log record but, without preDirty, the
70
// cache cleaning will not have waited for the change. So the preDirty bit
71
// is to stop the cache cleaning from skipping over this (latched) page
72
// even though it has not really been modified yet.
73

74     protected boolean isDirty; // must be set to true whenever the
75
// pageData array is touched
76
// directly or indirectly.
77

78     protected boolean preDirty; // set to true if the page is clean
79
// and the pageData array is about
80
// to be touched directly or
81
// indirectly.
82

83
84     protected int initialRowCount; // keep a running count of rows for
85
// estimated row count.
86

87     private long containerRowCount; // the number of rows in the
88
// container when this page is read
89
// from disk
90

91     /*
92     ** These fields are immutable and can be used by the subclasses directly.
93     */

94
95     /**
96         The page cache I live in.
97
98         <BR> MT - Immutable
99     */

100     protected CacheManager pageCache;
101
102     /**
103         The container cache my container lives in.
104
105         <BR> MT - Immutable
106     */

107     protected CacheManager containerCache;
108
109     /**
110         My factory class.
111
112         <BR> MT - Immutable -
113     */

114     protected BaseDataFileFactory dataFactory; // my factory class.
115

116
117     protected static final int PAGE_FORMAT_ID_SIZE = 4;
118
119     /*
120      * the page need to be written and synced to disk
121      */

122     public static final int WRITE_SYNC = 1;
123
124     /*
125      * the page need to be write to disk but not synced
126      */

127     public static final int WRITE_NO_SYNC = 2;
128
129     public CachedPage()
130     {
131         super();
132     }
133
134     public final void setFactory(BaseDataFileFactory factory)
135     {
136         dataFactory = factory;
137         pageCache = factory.getPageCache();
138         containerCache = factory.getContainerCache();
139     }
140
141     /**
142         Initialize a CachedPage.
143         <p>
144         Initialize the object, ie. perform work normally perfomed in
145         constructor. Called by setIdentity() and createIdentity().
146     */

147     protected void initialize()
148     {
149         super.initialize();
150         isDirty = false;
151         preDirty = false;
152         initialRowCount = 0;
153         containerRowCount = 0;
154     }
155
156     /*
157     ** Methods of Cacheable
158     */

159
160     /**
161      * Find the container and then read the page from that container.
162      * <p>
163      * This is the way new pages enter the page cache.
164      * <p>
165      *
166      * @return always true, higher levels have already checked the page number
167      * is valid for an open.
168      *
169      * @exception StandardException Standard Cloudscape policy.
170      *
171      * @see Cacheable#setIdentity
172      **/

173     public Cacheable setIdentity(Object JavaDoc key)
174         throws StandardException
175     {
176         if (SanityManager.DEBUG)
177         {
178             SanityManager.ASSERT(key instanceof PageKey);
179         }
180
181         initialize();
182
183         PageKey newIdentity = (PageKey) key;
184
185         FileContainer myContainer =
186             (FileContainer) containerCache.find(newIdentity.getContainerId());
187
188         setContainerRowCount(myContainer.getEstimatedRowCount(0));
189
190         try
191         {
192             if (!alreadyReadPage)
193             {
194                 // Fill in the pageData array by reading bytes from disk.
195
readPage(myContainer, newIdentity);
196             }
197             else
198             {
199                 // pageData array already filled
200
alreadyReadPage = false;
201             }
202
203             // if the formatID on disk is not the same as this page instance's
204
// format id, instantiate the real page object
205
int fmtId = getTypeFormatId();
206
207             int onPageFormatId = FormatIdUtil.readFormatIdInteger(pageData);
208             if (fmtId != onPageFormatId)
209             {
210                 return changeInstanceTo(
211                             onPageFormatId, newIdentity).setIdentity(key);
212             }
213
214             // this is the correct page instance
215
initFromData(myContainer, newIdentity);
216         }
217         finally
218         {
219             containerCache.release(myContainer);
220             myContainer = null;
221         }
222
223         fillInIdentity(newIdentity);
224
225         initialRowCount = 0;
226
227         return this;
228     }
229
230     /**
231      * Find the container and then create the page in that container.
232      * <p>
233      * This is the process of creating a new page in a container, in that
234      * case no need to read the page from disk - just need to initialize it
235      * in the cache.
236      * <p>
237      *
238      * @return new page, higher levels have already checked the page number is
239      * valid for an open.
240      *
241      * @param key Which page is this?
242      * @param createParameter details needed to create page like size,
243      * format id, ...
244      *
245      * @exception StandardException Standard exception policy.
246      *
247      * @see Cacheable#createIdentity
248      **/

249     public Cacheable createIdentity(
250     Object JavaDoc key,
251     Object JavaDoc createParameter)
252         throws StandardException
253     {
254
255         if (SanityManager.DEBUG)
256         {
257             SanityManager.ASSERT(key instanceof PageKey);
258         }
259
260         initialize();
261
262         PageKey newIdentity = (PageKey) key;
263
264         int[] createArgs = (int[]) createParameter;
265
266         if (createArgs[0] == -1)
267         {
268             throw StandardException.newException(
269                     SQLState.DATA_UNKNOWN_PAGE_FORMAT, newIdentity);
270         }
271
272         // createArgs[0] contains the integer form of the formatId
273
// if it is not the same as this instance's formatId, instantiate the
274
// real page object
275
if (createArgs[0] != getTypeFormatId())
276         {
277             return(
278                 changeInstanceTo(createArgs[0], newIdentity).createIdentity(
279                         key, createParameter));
280         }
281         
282         // this is the correct page instance
283
initializeHeaders(5);
284         createPage(newIdentity, createArgs);
285
286         fillInIdentity(newIdentity);
287
288         initialRowCount = 0;
289
290         /*
291          * if we need to grow the container and the page has not been
292          * preallocated, writing page before the log is written so that we
293          * know if there is an IO error - like running out of disk space - then
294          * we don't write out the log record, because if we do, it may fail
295          * after the log goes to disk and then the database may not be
296          * recoverable.
297          *
298          * WRITE_SYNC is used when we create the page without first
299          * preallocating it
300          * WRITE_NO_SYNC is used when we are preallocating the page - there
301          * will be a SYNC call after all the pages are preallocated
302          * 0 means creating a page that has already been preallocated.
303          */

304         if ((createArgs[1] & WRITE_SYNC) != 0 ||
305             (createArgs[1] & WRITE_NO_SYNC) != 0)
306             writePage(newIdentity, (createArgs[1] & WRITE_SYNC) != 0);
307
308         if (SanityManager.DEBUG)
309         {
310             if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE))
311             {
312                 String JavaDoc syncFlag =
313                     ((createArgs[1] & WRITE_SYNC) != 0) ? "Write_Sync" :
314                     (((createArgs[1] & WRITE_NO_SYNC) != 0) ? "Write_NO_Sync" :
315                                                               "No_write");
316
317                 SanityManager.DEBUG(
318                     FileContainer.SPACE_TRACE,
319                     "creating new page " + newIdentity + " with " + syncFlag);
320             }
321         }
322
323         return this;
324     }
325
326     /**
327      * Convert this page to requested type, as defined by input format id.
328      * <p>
329      * The current cache entry is a different format id than the requested
330      * type, change it. This object is instantiated to the wrong subtype of
331      * cachedPage, this routine will create an object with the correct subtype,
332      * and transfer all pertinent information from this to the new correct
333      * object.
334      * <p>
335      *
336      * @return The new object created with the input fid and transfered info.
337      *
338      * @param fid The format id of the new page.
339      * @param newIdentity The key of the new page.
340      *
341      * @exception StandardException Standard exception policy.
342      **/

343     private CachedPage changeInstanceTo(int fid, PageKey newIdentity)
344          throws StandardException
345     {
346         CachedPage realPage;
347         try
348         {
349             realPage =
350                 (CachedPage) Monitor.newInstanceFromIdentifier(fid);
351
352         }
353         catch (StandardException se)
354         {
355             if (se.getSeverity() > ExceptionSeverity.STATEMENT_SEVERITY)
356             {
357                 throw se;
358             }
359             else
360             {
361                 throw StandardException.newException(
362                     SQLState.DATA_UNKNOWN_PAGE_FORMAT, se, newIdentity);
363             }
364         }
365
366         realPage.setFactory(dataFactory);
367
368         // avoid creating the data buffer if possible, transfer it to the new
369
// page if this is the first time the page buffer is used, then
370
// createPage will create the page array with the correct page size
371
if (this.pageData != null)
372         {
373             realPage.alreadyReadPage = true;
374             realPage.usePageBuffer(this.pageData);
375         }
376
377         // RESOLVE (12/15/06) - the following code is commented out, but
378
// not sure why.
379

380         // this page should not be used any more, null out all its content and
381
// wait for GC to clean it up
382

383         //destroyPage();// let this subtype have a chance to get rid of stuff
384
//this.pageData = null; // this instance no longer own the data array
385
//this.pageCache = null;
386
//this.dataFactory = null;
387
//this.containerCache = null;
388

389         return realPage;
390     }
391
392     /**
393      * Is the page dirty?
394      * <p>
395      * The isDirty flag indicates if the pageData or pageHeader has been
396      * modified. The preDirty flag indicates that the pageData or the
397      * pageHeader is about to be modified. The reason for these 2 flags
398      * instead of just one is to accomodate checkpoint. After a clean
399      * (latched) page sends a log record to the log stream but before that page
400      * is dirtied by the log operation, a checkpoint could be taken. If so,
401      * then the redoLWM will be after the log record but, without preDirty, the
402      * cache cleaning will not have waited for the change. So the preDirty bit
403      * is to stop the cache cleaning from skipping over this (latched) page
404      * even though it has not really been modified yet.
405      *
406      * @return true if the page is dirty.
407      *
408      * @see Cacheable#isDirty
409      **/

410     public boolean isDirty()
411     {
412         synchronized (this)
413         {
414             return isDirty || preDirty;
415         }
416     }
417
418     /**
419      * Has the page or its header been modified.
420      * <p>
421      * See comment on class header on meaning of isDirty and preDirty bits.
422      * <p>
423      *
424      * @return true if changes have actually been made to the page in memory.
425      **/

426     public boolean isActuallyDirty()
427     {
428         synchronized (this)
429         {
430             return isDirty;
431         }
432     }
433
434     /**
435      * Set state to indicate the page or its header is about to be modified.
436      * <p>
437      * See comment on class header on meaning of isDirty and preDirty bits.
438      **/

439     public void preDirty()
440     {
441         synchronized (this)
442         {
443             if (!isDirty)
444                 preDirty = true;
445         }
446     }
447
448     /**
449      * Set state to indicate the page or its header has been modified.
450      * <p>
451      * See comment on class header on meaning of isDirty and preDirty bits.
452      * <p>
453      **/

454     protected void setDirty()
455     {
456         synchronized (this)
457         {
458             isDirty = true;
459             preDirty = false;
460         }
461     }
462
463     /**
464      * exclusive latch on page is being released.
465      * <p>
466      * The only work done in CachedPage is to update the row count on the
467      * container if it is too out of sync.
468      **/

469     protected void releaseExclusive()
470     {
471         // look at dirty bit without latching, the updating of the row
472
// count is just an optimization so does not need the latch.
473
//
474
// if this page actually has > 1/8 rows of the entire container, then
475
// consider updating the row count if it is different.
476
//
477
// No need to special case allocation pages because it has recordCount
478
// of zero, thus the if clause will never be true for an allocation
479
// page.
480
if (isDirty && !isOverflowPage() &&
481             (containerRowCount / 8) < recordCount())
482         {
483             int currentRowCount = internalNonDeletedRecordCount();
484             int delta = currentRowCount-initialRowCount;
485             int posDelta = delta > 0 ? delta : (-delta);
486
487             if ((containerRowCount/8) < posDelta)
488             {
489                 // This pages delta row count represents a significant change
490
// with respect to current container row count so update
491
// container row count
492
FileContainer myContainer = null;
493
494                 try
495                 {
496                     myContainer = (FileContainer)
497                         containerCache.find(identity.getContainerId());
498
499                     if (myContainer != null)
500                     {
501                         myContainer.updateEstimatedRowCount(delta);
502                         setContainerRowCount(
503                                 myContainer.getEstimatedRowCount(0));
504
505                         initialRowCount = currentRowCount;
506
507                         // since I have the container, might as well update the
508
// unfilled information
509
myContainer.trackUnfilledPage(
510                             identity.getPageNumber(), unfilled());
511                     }
512                 }
513                 catch (StandardException se)
514                 {
515                     // do nothing, not sure what could fail but this update
516
// is just an optimization so no need to throw error.
517
}
518                 finally
519                 {
520                     if (myContainer != null)
521                         containerCache.release(myContainer);
522                 }
523             }
524         }
525
526         super.releaseExclusive();
527     }
528
529
530     /**
531      * Write the page to disk.
532      * <p>
533      * MP - In a simple world we would just not allow clean until it held the
534      * latch on the page. But in order to fit into the cache system, we
535      * don't have enough state around to just make clean() latch the page
536      * while doing the I/O - but we still need someway to insure that no
537      * changes happen to the page while the I/O is taking place.
538      * Also someday it would be fine to allow reads of this page
539      * while the I/O was taking place.
540      *
541      *
542      * @exception StandardException Error writing the page.
543      *
544      * @see Cacheable#clean
545      **/

546     public void clean(boolean remove) throws StandardException
547     {
548
549         // must wait for the page to be unlatched
550
synchronized (this)
551         {
552             if (!isDirty())
553                 return;
554
555             // is someone else cleaning it
556
while (inClean)
557             {
558                 try
559                 {
560                     wait();
561                 }
562                 catch (InterruptedException JavaDoc ie)
563                 {
564                     throw StandardException.interrupt(ie);
565                 }
566             }
567
568             // page is not "inClean" by other thread at this point.
569

570             if (!isDirty())
571                 return;
572
573             inClean = true;
574
575             // If page is in LATCHED state (as opposed to UNLATCH or PRELATCH)
576
// wait for the page to move to UNLATCHED state. See Comments in
577
// Generic/BasePage.java describing the interaction of inClean,
578
// (owner != null), and preLatch.
579
while ((owner != null) && !preLatch)
580             {
581                 try
582                 {
583                     wait();
584                 }
585                 catch (InterruptedException JavaDoc ie)
586                 {
587                     inClean = false;
588                     throw StandardException.interrupt(ie);
589                 }
590             }
591
592             // The page is now effectively latched by the cleaner.
593
// We only want to clean the page if the page is actually dirtied,
594
// not when it is just pre-dirtied.
595
if (!isActuallyDirty())
596             {
597                 // the person who latched it gives up the
598
// latch without really dirtying the page
599
preDirty = false;
600                 inClean = false;
601                 notifyAll();
602                 return;
603             }
604         }
605
606         try
607         {
608             writePage(getPageId(), false);
609         }
610         catch(StandardException se)
611         {
612             // If we get an error while trying to write a page, current
613
// recovery system requires that entire DB is shutdown. Then
614
// when system is rebooted we will run redo recovery which
615
// if it does not encounter disk errors will guarantee to recover
616
// to a transaction consistent state. If this write is a
617
// persistent device problem, redo recovery will likely fail
618
// attempting to the same I/O. Mark corrupt will stop all further
619
// writes of data and log by the system.
620
throw dataFactory.markCorrupt(se);
621         }
622         finally
623         {
624             // if there is something wrong in writing out the page,
625
// do not leave it inClean state or it will block the next cleaner
626
// forever
627

628             synchronized (this)
629             {
630                 inClean = false;
631                 notifyAll();
632             }
633         }
634     }
635
636     public void clearIdentity()
637     {
638         alreadyReadPage = false;
639         super.clearIdentity();
640     }
641
642     /**
643      * read the page from disk into this CachedPage object.
644      * <p>
645      * A page is read in from disk into the pageData array of this object,
646      * and then put in the cache.
647      * <p>
648      *
649      * @param myContainer the container to read the page from.
650      * @param newIdentity indentity (ie. page number) of the page to read
651      *
652      * @exception StandardException Standard exception policy.
653      **/

654     private void readPage(
655     FileContainer myContainer,
656     PageKey newIdentity)
657         throws StandardException
658     {
659         int pagesize = myContainer.getPageSize();
660
661         // we will reuse the existing page array if it is same size, the
662
// cache does support caching various sized pages.
663
setPageArray(pagesize);
664
665         for (int io_retry_count = 0;;)
666         {
667             try
668             {
669                 myContainer.readPage(newIdentity.getPageNumber(), pageData);
670                 break;
671             }
672             catch (IOException JavaDoc ioe)
673             {
674                 io_retry_count++;
675                                 
676                 // Retrying read I/O's has been found to be successful sometimes
677
// in completing the read without having to fail the calling
678
// query, and in some cases avoiding complete db shutdown.
679
// Some situations are:
680
// spurious interrupts being sent to thread by clients.
681
// unreliable hardware like a network mounted file system.
682
//
683
// The only option other than retrying is to fail the I/O
684
// immediately and throwing an error, thus performance cost
685
// not really a consideration.
686
//
687
// The retry max of 4 is arbitrary, but has been enough that
688
// not many read I/O errors have been reported.
689
if (io_retry_count > 4)
690                 {
691                     // page cannot be physically read
692

693                     StandardException se =
694                         StandardException.newException(
695                                    SQLState.FILE_READ_PAGE_EXCEPTION,
696                                    ioe, newIdentity, new Integer JavaDoc(pagesize));
697
698                         
699                     if (dataFactory.getLogFactory().inRFR())
700                     {
701                         //if in rollforward recovery, it is possible that this
702
//page actually does not exist on the disk yet because
703
//the log record we are proccessing now is actually
704
//creating the page, we will recreate the page if we
705
//are in rollforward recovery, so just throw the
706
//exception.
707
throw se;
708                     }
709                     else
710                     {
711                         if (SanityManager.DEBUG)
712                         {
713                             // by shutting down system in debug mode, maybe
714
// we can catch root cause of the interrupt.
715
throw dataFactory.markCorrupt(se);
716                         }
717                         else
718                         {
719                             // No need to shut down runtime database on read
720
// error in delivered system, throwing exception
721
// should be enough. Thrown exception has nested
722
// IO exception which is root cause of error.
723
throw se;
724                         }
725                     }
726                 }
727             }
728         }
729     }
730
731
732     /**
733      * write the page from this CachedPage object to disk.
734      * <p>
735      *
736      * @param identity indentity (ie. page number) of the page to read
737      * @param syncMe does the write of this single page have to be sync'd?
738      *
739      * @exception StandardException Standard exception policy.
740      **/

741     private void writePage(
742     PageKey identity,
743     boolean syncMe)
744          throws StandardException
745     {
746
747         // make subclass write the page format
748
writeFormatId(identity);
749
750         // let subclass have a chance to write any cached data to page data
751
// array
752
writePage(identity);
753
754         // force WAL - and check to see if database is corrupt or is frozen.
755
// last log Instant may be null if the page is being forced
756
// to disk on a createPage (which violates the WAL protocol actually).
757
// See FileContainer.newPage
758
LogInstant flushLogTo = getLastLogInstant();
759         dataFactory.flush(flushLogTo);
760
761         if (flushLogTo != null)
762         {
763             clearLastLogInstant();
764         }
765
766
767         // find the container and file access object
768
FileContainer myContainer =
769             (FileContainer) containerCache.find(identity.getContainerId());
770
771         if (myContainer != null)
772         {
773             try
774             {
775                 myContainer.writePage(
776                     identity.getPageNumber(), pageData, syncMe);
777
778                 //
779
// Do some in memory unlogged bookkeeping tasks while we have
780
// the container.
781
//
782

783                 if (!isOverflowPage() && isDirty())
784                 {
785
786                     // let the container knows whether this page is a not
787
// filled, non-overflow page
788
myContainer.trackUnfilledPage(
789                         identity.getPageNumber(), unfilled());
790
791                     // if this is not an overflow page, see if the page's row
792
// count has changed since it come into the cache.
793
//
794
// if the page is not invalid, row count is 0. Otherwise,
795
// count non-deleted records on page.
796
//
797
// Cannot call nonDeletedRecordCount because the page is
798
// unlatched now even though nobody is changing it
799
int currentRowCount = internalNonDeletedRecordCount();
800
801                     if (currentRowCount != initialRowCount)
802                     {
803                         myContainer.updateEstimatedRowCount(
804                             currentRowCount - initialRowCount);
805
806                         setContainerRowCount(
807                             myContainer.getEstimatedRowCount(0));
808
809                         initialRowCount = currentRowCount;
810                     }
811                 }
812
813             }
814             catch (IOException JavaDoc ioe)
815             {
816                 // page cannot be written
817
throw StandardException.newException(
818                     SQLState.FILE_WRITE_PAGE_EXCEPTION,
819                     ioe, identity, new Integer JavaDoc(myContainer.getPageSize()));
820             }
821             finally
822             {
823                 containerCache.release(myContainer);
824                 myContainer = null;
825             }
826         }
827         else
828         {
829             StandardException nested =
830                 StandardException.newException(
831                     SQLState.DATA_CONTAINER_VANISHED,
832                     identity.getContainerId());
833             throw dataFactory.markCorrupt(
834                 StandardException.newException(
835                     SQLState.FILE_WRITE_PAGE_EXCEPTION, nested,
836                     identity, new Integer JavaDoc(myContainer.getPageSize())));
837         }
838
839         synchronized (this)
840         {
841             // change page state to not dirty after the successful write
842
isDirty = false;
843             preDirty = false;
844         }
845     }
846
847     public void setContainerRowCount(long rowCount)
848     {
849         containerRowCount = rowCount;
850     }
851
852     /*
853     ** if the page size is different from the page buffer, then make a
854     ** new page buffer and make subclass use the new page buffer
855     */

856
857     protected void setPageArray(int pageSize) throws StandardException
858     {
859         if ((pageData == null) || (pageData.length != pageSize))
860         {
861             pageData = new byte[pageSize];
862
863             if (pageData == null || pageData.length != pageSize)
864             {
865                 throw StandardException.newException(
866                         SQLState.DATA_OBJECT_ALLOCATION_FAILED, "PAGE");
867             }
868                 
869             usePageBuffer(pageData);
870         }
871     }
872
873
874     /**
875      * Returns the page data array used to write on disk version.
876      *
877      * <p>
878      * returns the page data array, that is actually written to the disk,
879      * when the page is cleaned from the page cache. Takes care of flushing
880      * in-memory information to the array (like page header and format id info).
881      * <p>
882      *
883      * @return The array of bytes that is the on disk version of page.
884      *
885      * @exception StandardException Standard exception policy.
886      **/

887     protected byte[] getPageArray() throws StandardException
888     {
889         // make subclass write the page format
890
writeFormatId(identity);
891
892         // let subclass have a chance to write any cached
893
// data to page data array
894
writePage(identity);
895
896         return pageData;
897     }
898
899     /* methods for subclass of cached page */
900
901     // use a new pageData buffer, initialize in memory structure that depend on
902
// the pageData's size. The actual disk data may not have not been read in
903
// yet so don't look at the content of the buffer
904
protected abstract void usePageBuffer(byte[] buffer);
905
906
907     // initialize in memory structure using the read in buffer in pageData
908
protected abstract void initFromData(FileContainer container, PageKey id)
909         throws StandardException;
910
911
912     // create the page
913
protected abstract void createPage(PageKey id, int[] args)
914         throws StandardException;
915
916     // page is about to be written, write everything to pageData array
917
protected abstract void writePage(PageKey id) throws StandardException;
918
919     // write out the formatId to the pageData
920
protected abstract void writeFormatId(PageKey identity)
921         throws StandardException;
922 }
923
Popular Tags