KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2
3    Derby - Class org.apache.derby.impl.store.raw.data.AllocPage
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.services.sanity.SanityManager;
25
26 import org.apache.derby.iapi.reference.SQLState;
27
28 import org.apache.derby.iapi.services.io.TypedFormat;
29 import org.apache.derby.iapi.services.io.FormatIdUtil;
30 import org.apache.derby.iapi.services.io.StoredFormatIds;
31
32 import org.apache.derby.iapi.error.StandardException;
33
34 import org.apache.derby.iapi.store.raw.ContainerHandle;
35 import org.apache.derby.iapi.store.raw.Loggable;
36 import org.apache.derby.iapi.store.raw.PageKey;
37 import org.apache.derby.iapi.store.raw.PageTimeStamp;
38 import org.apache.derby.iapi.store.raw.RawStoreFactory;
39
40 import org.apache.derby.iapi.store.raw.log.LogInstant;
41 import org.apache.derby.iapi.store.raw.xact.RawTransaction;
42
43 import org.apache.derby.impl.store.raw.data.BaseContainerHandle;
44 import org.apache.derby.impl.store.raw.data.BasePage;
45 import org.apache.derby.impl.store.raw.data.PageVersion;
46
47 import java.io.IOException JavaDoc;
48
49 import java.io.ObjectOutput JavaDoc;
50 import java.io.ObjectInput JavaDoc;
51
52 import org.apache.derby.iapi.services.io.ArrayInputStream;
53
54 /**
55     An allocation page of the file container.
56     <P>
57     This class extends a normal Stored page, with the exception that a hunk of
58     space may be 'borrowed' by the file container to store the file header.
59     <P>
60     The borrowed space is not visible to the alloc page even though it is
61     present in the page data array. It is accessed directly by the
62     FileContainer. Any change made to the borrowed space is not managed or
63     seen by the allocation page.
64     <P
65     The reason for having this borrowed space is so that the container header
66     does not need to have a page of its own.
67
68     <P><B>Page Format</B><BR>
69     An allocation page extends a stored page, the on disk format is different
70     from a stored page in that N bytes are 'borrowed' by the container and the
71     page header of an allocation page will be slightly bigger than a normal
72     stored page. This N bytes are stored between the page header and the
73     record space.
74     <P>
75     The reason why this N bytes can't simply be a row is because it needs to be
76     statically accessible by the container object to avoid a chicken and egg
77     problem of the container object needing to instantiate an alloc page object
78     before it can be objectified, and an alloc page object needing to
79     instantiate a container object before it can be objectified. So this N
80     bytes must be stored outside of the normal record interface yet it must be
81     settable because only the first alloc page has this borrowed space. Other
82     (non-first) alloc page have N == 0.
83
84     <PRE>
85                              <-- borrowed ->
86     +----------+-------------+---+---------+-------------------+-------------+--------+
87     | FormatId | page header | N | N bytes | alloc extend rows | slot offset |checksum|
88     +----------+-------------+---+---------+-------------------+-------------+--------+
89     </PRE>
90
91     N is a byte that indicates the size of the borrowed space. Once an alloc
92     page is initialized, the value of N cannot change.
93     <P>
94     The maximum space that can be borrowed by the container is 256 bytes.
95     <P>
96     The allocation page are of the same page size as any other pages in the
97     container. The first allocation page of the FileContainer starts at the
98     first physical byte of the container. Subsequent allocation pages are
99     chained via the nextAllocPageOffset. Each allocation page is expected to
100     manage at least 1000 user pages (for 1K page size) so this chaining may not
101     be a severe performance hit. The logical -> physical mapping of an
102     allocation page is stored in the previous allocation page. The container
103     object will need to maintain this mapping.
104     <P>
105     The following fields are stored in the page header
106     <PRE>
107     @format_id RAW_STORE_ALLOC_PAGE
108     @purpose manage page allocation
109     @upgrade
110     @disk_layout
111         FormatId(int)
112         StoredPageHeader see StoredPage
113         nextAllocPageNubmer(long) the next allocation page's number
114         nextAllocPageOffset(long) the file offset of the next allocation page
115         reserved1(long) reserved for future usage
116         reserved2(long) reserved for future usage
117         reserved3(long) reserved for future usage
118         reserved4(long) reserved for future usage
119         N(byte) the size of the borrowed container info
120         containerInfo(byte[N]) the content of the borrowed container info
121         AllocExtent the one and only extent on this alloc page
122
123     @end_format
124     </PRE>
125
126     <P>
127     The allocation page contains allocation extent rows. In this first cut
128     implementation, there is only 1 allocation extent row per allocation page.
129     <P>
130     The allocation extent row is an externalizable object and is directly
131     written on to the page by the alloc page. In other words, it will not be
132     converted in to a storeableRow. This is to cut down overhead, enhance
133     performance and gives more control of the size and layout of the allocation
134     extent row to the alloc page.
135     <P>
136     <HR WIDTH="100%">
137     <BR> DETAIL implmentation notes <BR>
138     <HR WIDTH="100%">
139     <P>
140     Create Container - an embryonic allocation page is formatted on disk by a
141     spcial static function to avoid instantiating a full AllocPage object.
142     This embryonic allocation has enough information that it can find the
143     file header and not much else. Then the allocation page is perperly
144     initiated by creating the first extent.
145     <P>
146     Open Container - A static AllocPage method will be used to read off the
147     container information directly from disk. Even if
148     the first alloc page (page 0) is already in the page cache, it will not be
149     used because cleaning the alloc page will introduce a deadlock if the
150     container is not in the container cache. Long term, the first alloc page
151     should probably live in the container cache rather than in the page cache.
152     <P>
153     Get Page - The first alloc page (page 0) will be read into the page cache.
154     Continue to follow the alloc page chain until the alloc page that manages
155     the specified page is found. From the alloc page, the physical offset of
156     the specified page is located.
157     <P>
158     Cleaning alloc page - the alloc page is written out the same way any page
159     is written out. The container object will provide a call back to the alloc
160     page to write the current version of the container object back into the
161     borrowed space before the alloc page itself is written out.
162     <P>
163     Cleaning the container object - get the the first alloc page, dirty it and
164     clean it (which will cause it to call the container object to write itself
165     out into the borrowed space). The versioning of the container is
166     independent of the versioning of the alloc page. The container version is
167     stored inside the borrowed space and is opaque to the alloc page.
168     <P>
169     For the fields in an allocation extent row
170
171     @see AllocExtent
172 */

173
174
175 public class AllocPage extends StoredPage
176 {
177     /*
178      * typed format
179      */

180     public static final int FORMAT_NUMBER = StoredFormatIds.RAW_STORE_ALLOC_PAGE;
181     // format Id must fit in 4 bytes
182

183     /**
184         Return my format identifier.
185     */

186     public int getTypeFormatId() {
187         return StoredFormatIds.RAW_STORE_ALLOC_PAGE;
188     }
189
190     /*****************************************************************
191      * alloc page header
192      *****************************************************************/

193     private long nextAllocPageNumber; // if isLast, nextAllocPageNumber == INVALID_PAGE_NUMBER
194
private long nextAllocPageOffset;
195     private long reserved1;
196     private long reserved2;
197     private long reserved3;
198     private long reserved4;
199
200     private AllocExtent extent;
201
202     private int borrowedSpace;
203
204     /*****************************************************************
205      * constants
206      *****************************************************************/

207
208     /*
209      * allocation page header
210      * 8 bytes long next alloc page number
211      * 8 bytes long next alloc page physical offset
212      * 8 bytes long reserved1
213      * 8 bytes long reserved2
214      * 8 bytes long reserved3
215      * 8 bytes long reserved4
216      */

217     protected static final int ALLOC_PAGE_HEADER_OFFSET =
218         StoredPage.PAGE_HEADER_OFFSET + StoredPage.PAGE_HEADER_SIZE;
219
220     protected static final int ALLOC_PAGE_HEADER_SIZE = 8+8+(4*8);
221
222     /* borrowed_SPACE_OFFSET is where the borrowed space len is kept */
223     protected static final int BORROWED_SPACE_OFFSET =
224         ALLOC_PAGE_HEADER_OFFSET + ALLOC_PAGE_HEADER_SIZE;
225
226     /* size of the borrowed space length */
227     protected static final int BORROWED_SPACE_LEN = 1; // 1 byte to store the containerInfo length
228

229     /*
230      * BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN is the beginning offset of
231      * the borrowed space
232      */

233
234     /*
235      * the entire borrowed space must live within MAX_BORROWED_SPACE of the
236      * alloc page
237      */

238     protected static final int MAX_BORROWED_SPACE =
239             RawStoreFactory.PAGE_SIZE_MINIMUM / 5; // cannot take more then 1/5 of the page
240

241     public AllocPage()
242     {
243         super();
244     }
245
246     /*
247      * overwriting StoredPage methods
248      */

249
250     protected int getMaxFreeSpace() {
251
252         // the maximum free space is reduced by the allocation page header the
253
// size of the borrowed space. In all allocation page except the first
254
// one, there is no borrowed space and this is indeed the max free
255
// space. In the first allocation page, need to further subtract
256
// the borrowed space
257

258         return super.getMaxFreeSpace() - ALLOC_PAGE_HEADER_SIZE -
259             BORROWED_SPACE_LEN - borrowedSpace;
260     }
261
262
263     /*
264      * Methods of cachedPage - create, read and write up a page
265      * Overwriting StoredPage's CachedPage methods
266      */

267
268     /**
269      * Create a new alloc page.
270      *
271      * @exception StandardException Standard exception policy.
272      **/

273     protected void createPage(PageKey newIdentity, int[] args)
274          throws StandardException
275     {
276
277         super.createPage(newIdentity, args);
278
279         // args[0] is the format id
280
// args[1] is whether to sync the page to disk or not
281
// args[2] is the pagesize (used by StoredPage)
282
// args[3] is the spareSize (used by StoredPage)
283
// args[4] is the number of bytes to reserve for container header
284
// args[5] is the minimumRecordSize
285
// NOTE: the arg list here must match the one in FileContainer
286
int pageSize = args[2];
287         int minimumRecordSize = args[5];
288         borrowedSpace = args[4];
289
290         if (SanityManager.DEBUG)
291         {
292             // MAX_BORROWED_SPACE can't be bigger than what can be represented in 1 byte space
293
SanityManager.ASSERT(MAX_BORROWED_SPACE <= 255);
294
295             if (!(borrowedSpace + BORROWED_SPACE_LEN + BORROWED_SPACE_OFFSET
296                     < MAX_BORROWED_SPACE))
297             {
298                 SanityManager.THROWASSERT(
299                     "borrowedSpace too big = " + borrowedSpace);
300             }
301             SanityManager.ASSERT(pageData != null);
302         }
303         pageData[BORROWED_SPACE_OFFSET] = (byte)borrowedSpace;
304
305         // remember that the borrowed space have been wiped out now, it
306
// needs to be put back when the page is written out.
307
// blot out borrowed space before checksum is verified
308
if (borrowedSpace > 0)
309         {
310             clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, borrowedSpace);
311         }
312
313         // init the rest of the header and the allocation extent
314
nextAllocPageNumber = ContainerHandle.INVALID_PAGE_NUMBER;
315         nextAllocPageOffset = 0;
316         reserved1 = reserved2 = reserved3 = reserved4 = 0;
317
318         // calculate how much space we have left for the extent map
319
int maxSpace = getMaxFreeSpace();
320
321         // the pages this extent is going to manage starts from pageNum+1
322
// starting physical offset is pageSize*(pageNum+1) since we have
323
// no logical to physical mapping yet...
324
extent = createExtent(newIdentity.getPageNumber()+1, pageSize, 0 /* pagesAlloced */, maxSpace);
325     }
326
327     private AllocExtent createExtent(long pageNum, int pageSize, int pagesAlloced, int availspace)
328     {
329         int maxPages = AllocExtent.MAX_RANGE(availspace);
330
331         if (SanityManager.DEBUG)
332             SanityManager.ASSERT(maxPages > 8, "cannot manage > 8 pages");
333
334
335         if (SanityManager.DEBUG)
336         {
337             if (SanityManager.DEBUG_ON(TEST_MULTIPLE_ALLOC_PAGE))
338             {
339                 maxPages = 2; // 2 pages per alloc page
340
}
341         }
342
343         return new AllocExtent(pageNum*pageSize, // starting offset
344
pageNum, // extent start page number
345
pagesAlloced, // #pages already allocated
346
pageSize, // page size
347
maxPages); // max #pages to manage
348
}
349
350     /**
351         Initialize in memory structure using the buffer in pageData
352
353         @exception StandardException If the page cannot be read correctly, or is inconsistent.
354     */

355     protected void initFromData(FileContainer myContainer, PageKey newIdentity)
356          throws StandardException
357     {
358         if (pageData.length < BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN)
359         {
360             throw dataFactory.markCorrupt(
361                 StandardException.newException(
362                     SQLState.DATA_CORRUPT_PAGE, newIdentity));
363         }
364
365         byte n = pageData[BORROWED_SPACE_OFFSET];
366         borrowedSpace = (int)n;
367
368         if (pageData.length < BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + n)
369         {
370             throw dataFactory.markCorrupt(
371                 StandardException.newException(
372                     SQLState.DATA_CORRUPT_PAGE, newIdentity));
373         }
374
375         // blot out borrowed space before checksum is verified
376
if (borrowedSpace > 0)
377         {
378             clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, borrowedSpace);
379         }
380
381         super.initFromData(myContainer, newIdentity);
382
383         try
384         {
385             // now init alloc page header fields
386
readAllocPageHeader();
387
388             // now init the allocation extent - read it from offset
389
int offset = BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + borrowedSpace;
390             extent = readExtent(offset);
391         }
392         catch (IOException JavaDoc ioe)
393         {
394             throw dataFactory.markCorrupt(
395                 StandardException.newException(
396                     SQLState.DATA_CORRUPT_PAGE, ioe, newIdentity));
397         }
398         catch (ClassNotFoundException JavaDoc cnfe)
399         {
400             throw dataFactory.markCorrupt(
401                 StandardException.newException(
402                     SQLState.DATA_CORRUPT_PAGE, cnfe, newIdentity));
403         }
404     }
405
406     /**
407         Write the page out
408
409         @exception StandardException If the page cannot be written
410     */

411     protected void writePage(PageKey identity) throws StandardException
412     {
413         try
414         {
415             updateAllocPageHeader(); // write out the next alloc page chain
416

417             // blot out borrowed space before checksum is calculated - even
418
// though the page is first read in with borrowed space blotted
419
// out, whenever this page got cleaned the container will overlay
420
// the container info in the borrowed space.
421
int n = (int)pageData[BORROWED_SPACE_OFFSET];
422             if (SanityManager.DEBUG)
423             {
424                 if (n != borrowedSpace)
425                     SanityManager.THROWASSERT(
426                         "different borrowed space " + n + ", " + borrowedSpace);
427             }
428             if (n > 0)
429             {
430                 clearSection(BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN, n);
431             }
432
433             int offset = BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + n;
434             writeExtent(offset);
435         }
436         catch (IOException JavaDoc ioe)
437         {
438             // i/o methods on the byte array have thrown an IOException
439
throw dataFactory.markCorrupt(
440                 StandardException.newException(
441                     SQLState.DATA_CORRUPT_PAGE, ioe, identity));
442         }
443
444         // let store page write out the rest and do the checksum
445
super.writePage(identity);
446     }
447
448
449     private void readAllocPageHeader() throws IOException JavaDoc
450     {
451         ArrayInputStream lrdi = rawDataIn;
452         lrdi.setPosition(ALLOC_PAGE_HEADER_OFFSET);
453
454         nextAllocPageNumber = lrdi.readLong();
455         nextAllocPageOffset = lrdi.readLong();
456         reserved1 = lrdi.readLong();
457         reserved2 = lrdi.readLong();
458         reserved3 = lrdi.readLong();
459         reserved4 = lrdi.readLong();
460     }
461
462     private void updateAllocPageHeader() throws IOException JavaDoc
463     {
464         // rawDataOut and logicalDataOut are defined by StoredPage
465
rawDataOut.setPosition(ALLOC_PAGE_HEADER_OFFSET);
466         logicalDataOut.writeLong(nextAllocPageNumber);
467         logicalDataOut.writeLong(nextAllocPageOffset);
468         logicalDataOut.writeLong(0); // reserved1
469
logicalDataOut.writeLong(0); // reserved2
470
logicalDataOut.writeLong(0); // reserved3
471
logicalDataOut.writeLong(0); // reserved4
472
}
473
474     private AllocExtent readExtent(int offset)
475          throws IOException JavaDoc, ClassNotFoundException JavaDoc
476     {
477         ArrayInputStream lrdi = rawDataIn;
478         rawDataIn.setPosition(offset);
479         AllocExtent newExtent = new AllocExtent();
480         newExtent.readExternal(lrdi);
481
482         // in 1.3 or later, make sure the upgrade from before 1.3 is legal.
483
if (SanityManager.DEBUG)
484         {
485             int max_range = newExtent.MAX_RANGE(getMaxFreeSpace());
486             long extent_start = newExtent.getFirstPagenum();
487             long extent_end = newExtent.getExtentEnd();
488
489             // extent_start + max_range - 1 is the absolute last page this
490
// extent can hope to manage. See if it did the calculation
491
// correctly after upgrade.
492

493             if ((extent_start+max_range-1) < extent_end)
494             {
495                 SanityManager.THROWASSERT(
496                     "extent range exceed what extent's space can handle ");
497             }
498         }
499
500         return newExtent;
501     }
502
503     private void writeExtent(int offset) throws IOException JavaDoc
504     {
505         // rawDataOut and logicalDataOut are defined by StoredPage
506
rawDataOut.setPosition(offset);
507         extent.writeExternal(logicalDataOut);
508     }
509
510     /*
511      * borrowed space management
512      */

513
514     /**
515         Write the container information into the container information area.
516
517         @param containerInfo the container information
518
519         @param epage the allocation page data which may not be fully formed,
520         but is guarenteed to be big enough to cover the area inhibited by the
521         container info
522
523         @param create if create, write out the length of the container info
524         also. Else check to make sure epage's original container info is of the
525         same length
526
527         @exception StandardException Cloudscape standard error policy
528     */

529     public static void WriteContainerInfo(byte[] containerInfo,
530                                           byte[] epage,
531                                           boolean create)
532          throws StandardException
533     {
534         int N = (containerInfo == null) ? 0 : containerInfo.length;
535
536         if (SanityManager.DEBUG)
537         {
538             if (create)
539                 SanityManager.ASSERT(
540                     containerInfo != null, "containerInfo is null");
541
542             SanityManager.ASSERT(epage != null, "page array is null");
543
544             if (!((containerInfo == null) ||
545                   ((containerInfo.length + BORROWED_SPACE_OFFSET +
546                       BORROWED_SPACE_LEN) < epage.length)))
547             {
548                 SanityManager.THROWASSERT(
549                     "containerInfo too big for page array: " +
550                     containerInfo.length);
551             }
552
553             if (BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + N >=
554                                                             MAX_BORROWED_SPACE)
555                 SanityManager.THROWASSERT(
556                                  "exceed max borrowable space: " + N);
557         }
558
559         if ((N + BORROWED_SPACE_LEN + BORROWED_SPACE_OFFSET) > epage.length)
560         {
561             if (SanityManager.DEBUG)
562                 SanityManager.THROWASSERT(
563                    "exceed max borrowable space on page: " + N);
564         }
565
566         if (create)
567         {
568             epage[BORROWED_SPACE_OFFSET] = (byte)N;
569         }
570         else
571         {
572             int oldN = (int)epage[BORROWED_SPACE_OFFSET];
573             if (oldN != N)
574             {
575                 throw StandardException.newException(
576                         SQLState.DATA_CHANGING_CONTAINER_INFO,
577                         new Long JavaDoc(oldN),
578                         new Long JavaDoc(N));
579             }
580         }
581
582         if (N != 0)
583             System.arraycopy(containerInfo, 0, epage,
584                              BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN,
585                              N);
586     }
587
588     /**
589         Extract the container information from epage.
590
591         @param containerInfo where to put the extracted information
592
593         @param epage the allocation page which has the container information.
594         Epage may not be fully formed, but is guarenteed to be big enough to
595         cover the area inhibited by the container info
596     */

597     public static void ReadContainerInfo(byte[] containerInfo,
598                                          byte[] epage)
599     {
600         int N = (int)epage[BORROWED_SPACE_OFFSET];
601
602         if (SanityManager.DEBUG)
603         {
604             if (N != containerInfo.length)
605                 SanityManager.THROWASSERT("N not what is expected : " + N);
606
607             if (BORROWED_SPACE_OFFSET + BORROWED_SPACE_LEN + N
608                                                         >= MAX_BORROWED_SPACE)
609             {
610                 SanityManager.THROWASSERT("exceed max borrowable space: " + N);
611             }
612         }
613
614         if (N != 0)
615             System.arraycopy(epage, BORROWED_SPACE_OFFSET+BORROWED_SPACE_LEN,
616                              containerInfo, 0, N);
617     }
618
619
620     /*
621      * specific methods to AllocPage
622      */

623
624     /**
625         Return the next free page number after given page number
626      */

627     public long nextFreePageNumber(long pnum)
628     {
629         return extent.getFreePageNumber(pnum);
630     }
631
632
633     /**
634         Add a page which is managed by this alloc page.
635         Return the page number of the newly added page.
636
637         <BR> MT - thread aware (latched)
638
639         @param mycontainer (future) allows the alloc page to call back to the
640             container to grow the container by creating and syncing multiple
641             pages at once
642         @param ntt the nested top action that is the allocation transaction.
643             NTT will comit before the user transaction
644         @param userHandle the container handle that is opened by the user
645             transaction. Use the userHandle to latch the new page so that
646             it may remain latched after NTT is committed so the user
647             transaction can guarentee to have an empty page
648
649         @exception StandardException If the page cannot be added
650     */

651     public void addPage(FileContainer mycontainer, long newPageNumber,
652                         RawTransaction ntt, BaseContainerHandle userHandle) throws StandardException
653     {
654         // RESOLVED:
655
//
656
// to prevent allocating a free page before the freeing transaction has
657
// commit, need to grab the DEALLOCATE_PROTECTION_HANDLE
658
// the lock probably should be gotten in FileContainer
659
// and not here
660

661         // page allocation is logged under the nested top action
662
owner.getAllocationActionSet().
663             actionAllocatePage(
664                 ntt, this, newPageNumber,
665                 AllocExtent.ALLOCATED_PAGE, AllocExtent.FREE_PAGE);
666     }
667
668
669     /*
670         Deallocate page
671     */

672     public void deallocatePage(BaseContainerHandle userHandle, long pageNumber)
673          throws StandardException
674     {
675         if (SanityManager.DEBUG) {
676             SanityManager.ASSERT(isLatched());
677         }
678
679         // RESOLVED:
680
//
681
// to prevent this page from being freed before this transaction commits,
682
// need to grab the DEALLOCATE_PROTECTION_HANDLE lock on the
683
// deallocated page
684
// the lock probably should be gotten in FileContainer
685
// and not here
686

687         owner.getAllocationActionSet().
688             actionAllocatePage(userHandle.getTransaction(),
689                                this, pageNumber, AllocExtent.DEALLOCATED_PAGE,
690                                AllocExtent.ALLOCATED_PAGE);
691     }
692
693     /*
694      * update unfilled page information
695      * We will be using inputExtent's unfilledPage bitmap as the new bitmap, so
696      * caller of this routine need to not touch the bitmap after this call (in
697      * other words, call this ONLY in allocationCache invalidate and throw away
698      * the reference to the bitImpl)
699      */

700     protected void updateUnfilledPageInfo(AllocExtent inputExtent)
701     {
702         if (SanityManager.DEBUG) {
703             SanityManager.ASSERT(isLatched());
704         }
705
706         // update the unfilled page bit map unlogged - it is just a hint, not
707
// worth logging it - don't dirty the page either, since we didn't log
708
// it. It will be dirtied soon enough by addPage or deallocPage,
709
// that is the only reasons why we are invalidataing the
710
// allocation cache and updating the unfilled page info.
711
// If we dirty the page, the BI will be copied to the side log
712
extent.updateUnfilledPageInfo(inputExtent);
713
714     }
715
716     public boolean canAddFreePage(long lastAllocatedPage)
717     {
718         if (SanityManager.DEBUG)
719             SanityManager.ASSERT(isLatched());
720
721         if (extent.isRetired())
722             return false;
723
724         // if we want to try allocating not from the beginning of the bit map
725
// and this alloc page is before that point and this is not the last
726
// alloc page, then skip over this alloc page
727
if (lastAllocatedPage != ContainerHandle.INVALID_PAGE_NUMBER &&
728             extent.getLastPagenum() <= lastAllocatedPage &&
729             !isLast())
730             return false;
731
732         // Else we either want to start examining from this alloc page, or this
733
// is the last page, see if we can add a page.
734
return extent.canAddFreePage(lastAllocatedPage);
735     }
736
737     public long getNextAllocPageOffset()
738     {
739         if (SanityManager.DEBUG)
740         {
741             SanityManager.ASSERT(
742                 !isLast(), "next alloc page not present for last alloc page");
743
744             SanityManager.ASSERT(isLatched());
745         }
746
747         return nextAllocPageOffset;
748     }
749
750     public void chainNewAllocPage(BaseContainerHandle allocHandle,
751                                   long newAllocPageNum, long newAllocPageOffset)
752          throws StandardException
753     {
754         if (SanityManager.DEBUG)
755         {
756             SanityManager.ASSERT(isLatched());
757             if (SanityManager.DEBUG_ON(FileContainer.SPACE_TRACE))
758                 SanityManager.DEBUG(FileContainer.SPACE_TRACE,
759                                     "chaining new alloc page " +
760                                     newAllocPageNum + " to " +
761                                     getPageNumber());
762         }
763
764         owner.getAllocationActionSet().
765             actionChainAllocPage(allocHandle.getTransaction(),
766                                  this, newAllocPageNum, newAllocPageOffset);
767     }
768
769     public long getNextAllocPageNumber()
770     {
771         if (SanityManager.DEBUG)
772         {
773             SanityManager.ASSERT(isLatched());
774             SanityManager.ASSERT(
775                 !isLast(), "next alloc page not present for last alloc page");
776         }
777         return nextAllocPageNumber;
778     }
779
780     public boolean isLast()
781     {
782         if (SanityManager.DEBUG)
783             SanityManager.ASSERT(isLatched());
784         return nextAllocPageNumber == ContainerHandle.INVALID_PAGE_NUMBER;
785     }
786
787     /*
788      * get the last pagenumber currently managed by this alloc page
789      */

790     public long getLastPagenum()
791     {
792         if (SanityManager.DEBUG)
793             SanityManager.ASSERT(isLatched());
794
795         return extent.getLastPagenum();
796     }
797
798     /*
799      * get the largest page number this alloc page can manage.
800      * This is the different from the last pagenumber currently managed by this
801      * alloc page unless the alloc page is full and all the pages have been
802      * allocated
803      */

804     public long getMaxPagenum()
805     {
806         return extent.getExtentEnd();
807     }
808
809     /*
810      * get the last preallocated pagenumber managed by this alloc page
811      */

812     protected long getLastPreallocPagenum()
813     {
814         if (SanityManager.DEBUG)
815             SanityManager.ASSERT(isLatched());
816
817         return extent.getLastPreallocPagenum();
818     }
819
820
821     protected int getPageStatus(long pageNumber)
822     {
823         if (SanityManager.DEBUG)
824             SanityManager.ASSERT(isLatched());
825
826         return extent.getPageStatus(pageNumber);
827     }
828
829
830     /**
831         Do the actual page allocation/deallocation/ree underneath a log operation.
832         Change the page status to new status
833
834         @exception StandardException If the page cannot be allocated
835     */

836     protected void setPageStatus(LogInstant instant, long pageNumber, int newStatus) throws StandardException
837     {
838         if (SanityManager.DEBUG) {
839             SanityManager.ASSERT(isLatched(), "page is not latched");
840             SanityManager.ASSERT(extent != null, "extent is null");
841         }
842
843         logAction(instant);
844
845         switch(newStatus)
846         {
847         case AllocExtent.ALLOCATED_PAGE:
848             extent.allocPage(pageNumber);
849             break;
850         case AllocExtent.DEALLOCATED_PAGE:
851             extent.deallocPage(pageNumber);
852             break;
853         case AllocExtent.FREE_PAGE:
854             extent.deallocPage(pageNumber);
855             break;
856         }
857     }
858
859     /**
860         Chain the next page number and offset underneath a log record
861
862         @exception StandardException Standard Cloudscape error policy
863     */

864     protected void chainNextAllocPage(LogInstant instant,
865                                       long newAllocPageNum,
866                                       long newAllocPageOffset)
867          throws StandardException
868     {
869         if (SanityManager.DEBUG)
870             SanityManager.ASSERT(isLatched(), "page is not latched");
871
872         logAction(instant);
873
874         nextAllocPageNumber = newAllocPageNum;
875         nextAllocPageOffset = newAllocPageOffset;
876     }
877
878     /**
879      * Compress free pages.
880      * <p>
881      * Compress the free pages at the end of the range maintained by
882      * this allocation page. All pages being compressed should be FREE.
883      * Only pages in the last allocation page can be compressed.
884      * <p>
885      *
886      * @param instant log address for this operation.
887      * @param new_highest_page The new highest page on this allocation
888      * page. The number is the offset of the page
889      * in the array of pages maintained by this
890      * allocation page, for instance a value of 0
891      * indicates all page except the first one are
892      * to be truncated. If all pages are
893      * truncated then the offset is set to -1.
894      * @param num_pages_truncated The number of allocated pages in this
895      * allocation page prior to the truncate.
896      * Note that all pages from NewHighestPage+1
897      * through newHighestPage+num_pages_truncated
898      * should be FREE.
899      *
900      * @exception StandardException Standard exception policy.
901      **/

902     protected void compressSpace(
903     LogInstant instant,
904     int new_highest_page,
905     int num_pages_truncated)
906          throws StandardException
907     {
908         if (SanityManager.DEBUG)
909         {
910             SanityManager.ASSERT(isLatched(), "page is not latched");
911             SanityManager.ASSERT(isLast(), "compress on non last alloc page.");
912             SanityManager.ASSERT(new_highest_page >= 0, "negative new high page.");
913         }
914
915         logAction(instant);
916
917         extent.compressPages(new_highest_page, num_pages_truncated);
918     }
919
920     /**
921      * Handle undo of compress space operation.
922      **/

923     protected void undoCompressSpace(
924     LogInstant instant,
925     int new_highest_page,
926     int num_pages_truncated)
927         throws StandardException
928     {
929         logAction(instant);
930
931         extent.undoCompressPages(new_highest_page, num_pages_truncated);
932
933     }
934
935     public String JavaDoc toString()
936     {
937         if (SanityManager.DEBUG)
938         {
939             String JavaDoc str =
940                 "*** Alloc page ***\n" +
941                 "nextAllocPageNumber = " + nextAllocPageNumber +
942                 "\nnextAllocPageOffset = " + nextAllocPageOffset +
943                 "\nreserved1 = " + reserved1 +
944                 "\nreserved2 = " + reserved2 +
945                 "\nreserved3 = " + reserved3 +
946                 "\nreserved4 = " + reserved4 +
947                 "\nborrowedSpace = " + borrowedSpace +
948                 "\nextent = " + extent.toDebugString() + "\n" +
949                 super.toString();
950             return str;
951         }
952         else
953         {
954             return null;
955         }
956     }
957
958
959     /**
960         Return a copy of the allocExtent to be cached by the container.
961         the container must take care to maintain its coherency by
962         invalidating the cache before any update.
963     */

964     protected AllocExtent getAllocExtent()
965     {
966         return extent;
967
968         // return new AllocExtent(extent);
969
}
970
971     /**
972         Preallocate user page if needed.
973
974         @param myContainer the container object
975         @param preAllocThreshold start preallocating after this threshold
976         @param preAllocSize preallocate this number of pages
977     */

978     protected void preAllocatePage(FileContainer myContainer,
979                                    int preAllocThreshold,
980                                    int preAllocSize)
981     {
982         if (SanityManager.DEBUG)
983             SanityManager.ASSERT(isLatched(), "page is not latched");
984
985         long lastPreallocatedPagenum = extent.getLastPreallocPagenum();
986
987         if (lastPreallocatedPagenum < preAllocThreshold)
988             return;
989
990         // don't pre-allocate more than we the extent can handle - this is
991
// because if I preallocate the next alloc page as a stored page,
992
// that's going to be problem when we try to get it as an alloc page
993
// later. We don't handle changing from a store page type to an alloc
994
// page type on disk very well.
995
if (extent.getExtentEnd() < (lastPreallocatedPagenum+preAllocSize))
996             preAllocSize = (int)(extent.getExtentEnd() - lastPreallocatedPagenum);
997
998         if (preAllocSize <= 0)
999             return;
1000
1001        // pre-allocate - only a container knows how to write pages
1002
// preAllocSize may exceed what this allocation page can really
1003
// handle, but no harm done. The next allocation page will benefit
1004
// from the work we have done...
1005
int n = myContainer.preAllocate(lastPreallocatedPagenum, preAllocSize);
1006        
1007        if (n > 0) // successfully preallocated some pages
1008
{
1009            // this is purely a performance issue during runtime. During
1010
// recovery, any page that is actually initialized will have its
1011
// own initPage log record. Update extent's preAllocpageNumber
1012
// unlogged.
1013
//
1014
// We could have logged a redo-only log record, but we are counting
1015
// on myContainer.preAllocate to do the right thing if we recovered
1016
// and have out of date preallocate information. A reason why
1017
// logging this is undesirable is that the alloc page may think the
1018
// preallocation happened, but the container may actually choose to
1019
// lie about it - if it thinks there is no advantage in actually
1020
// doing the I/O now. So best to leave it alone.
1021
extent.setLastPreallocPagenum(lastPreallocatedPagenum + n);
1022
1023            // don't dirty the page - the new preAlloc page number is only set
1024
// in memory. A page should only get 'dirtied' by a log operation,
1025
// we are cheating here. Same with updating the extentStatus bit
1026
// without logging.
1027
}
1028
1029    }
1030
1031    /**
1032     * compress out empty pages at end of container.
1033     * <p>
1034     * Call the extent to update the data structure make the bit map look
1035     * like contiguous free pages at the end of the extent no longer exist.
1036     * Similar to preallocate do the operation unlogged, need to force the
1037     * change to the extent before actually removing the space from the
1038     * file.
1039     * <p>
1040     * The sequence is:
1041     * 1) update extent data structure
1042     * 2) force extent changes to disk
1043     * 3) truncate pages
1044     *
1045     * If the system crashes between 1 and 2 then no changes are on disk.
1046     * If the system crashes between 2 and 3 then there are extra pages in
1047     * the file that extent does not know about, this is the same case
1048     * as preallocation which the code already handes. It will handle
1049     * any set of pages from 0 to all of the intended pages being
1050     * truncated. The next allocate looks at actual size of file as
1051     * does the right thing.
1052     *
1053     * <p)
1054     * MT - expect Container level X lock
1055     *
1056     * @exception StandardException Standard exception policy.
1057     **/

1058    protected boolean compress(
1059    RawTransaction ntt,
1060    FileContainer myContainer)
1061        throws StandardException
1062    {
1063        boolean all_pages_compressed = false;
1064
1065        if (SanityManager.DEBUG)
1066        {
1067            SanityManager.ASSERT(isLatched(), "page is not latched");
1068        }
1069
1070        int last_valid_page = extent.compress(owner, ntt, this);
1071
1072        if (last_valid_page >= 0)
1073        {
1074            // a non-negative return means that pages can be returned to
1075
// the operating system.
1076
myContainer.truncatePages(extent.getPagenum(last_valid_page));
1077
1078            if (last_valid_page == this.getPageNumber())
1079            {
1080                // all pages of the extent have been returned to OS.
1081
all_pages_compressed = true;
1082            }
1083        }
1084
1085        return(all_pages_compressed);
1086    }
1087
1088    /*********************************************************************
1089     * Extent Testing
1090     *
1091     * Use these strings to simulate error conditions for
1092     * testing purposes.
1093     *
1094     *********************************************************************/

1095    public static final String JavaDoc TEST_MULTIPLE_ALLOC_PAGE = SanityManager.DEBUG ? "TEST_MULTI_ALLOC_PAGE" : null;
1096}
1097
Popular Tags