RandomAllocationSegmentBaseImpl.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/segment/RandomAllocationSegmentBaseImpl.h#10 $
00003 // Fennel is a library of data storage and processing components.
00004 // Copyright (C) 2005-2009 The Eigenbase Project
00005 // Copyright (C) 2005-2009 SQLstream, Inc.
00006 // Copyright (C) 2005-2009 LucidEra, Inc.
00007 // Portions Copyright (C) 1999-2009 John V. Sichi
00008 //
00009 // This program is free software; you can redistribute it and/or modify it
00010 // under the terms of the GNU General Public License as published by the Free
00011 // Software Foundation; either version 2 of the License, or (at your option)
00012 // any later version approved by The Eigenbase Project.
00013 //
00014 // This program is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU General Public License
00020 // along with this program; if not, write to the Free Software
00021 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 */
00023 
00024 #ifndef Fennel_RandomAllocationSegmentBaseImpl_Included
00025 #define Fennel_RandomAllocationSegmentBaseImpl_Included
00026 
00027 #include "fennel/segment/RandomAllocationSegmentBase.h"
00028 #include "fennel/segment/SegPageLock.h"
00029 
00030 FENNEL_BEGIN_NAMESPACE
00031 
00032 // NOTE:  read comments on struct StoredNode before modifying
00033 // the structs below
00034 
00038 static const PageOwnerId UNALLOCATED_PAGE_OWNER_ID = PageOwnerId(0);
00039 
00044 struct FENNEL_SEGMENT_EXPORT SegmentAllocationNode
00045     : public StoredNode
00046 {
00047     static const MagicNumber MAGIC_NUMBER = 0xa3db80b98208bfd4LL;
00048 
00052     struct ExtentEntry
00053     {
00054         // NOTE:  This should be a BlockNum, but even with a very large block
00055         // size it will never need more than 32 bits to cover the number of
00056         // entries in an extent allocation node.  So, keep it to four bytes to
00057         // minimize the number of SegmentAllocationNodes needed.
00058         uint32_t nUnallocatedPages;
00059     };
00060 
00067     BlockNum nPagesPerExtent;
00068 
00077     PageId nextSegAllocPageId;
00078 
00082     uint nExtents;
00083 
00084     ExtentEntry &getExtentEntry(uint i)
00085     {
00086         assert(i < nExtents);
00087         return reinterpret_cast<ExtentEntry *>(this+1)[i];
00088     }
00089 
00090     ExtentEntry const &getExtentEntry(uint i) const
00091     {
00092         assert(i < nExtents);
00093         return reinterpret_cast<ExtentEntry const *>(this+1)[i];
00094     }
00095 };
00096 
00097 typedef SegNodeLock<SegmentAllocationNode> SegAllocLock;
00098 
00099 inline PageId RandomAllocationSegmentBase::getFirstSegAllocPageId() const
00100 {
00101     return FIRST_LINEAR_PAGE_ID;
00102 }
00103 
00104 inline PageId RandomAllocationSegmentBase::getSegAllocPageId(
00105     uint iSegPage) const
00106 {
00107     return getLinearPageId(nPagesPerSegAlloc*iSegPage);
00108 }
00109 
00110 inline BlockNum RandomAllocationSegmentBase::makePageNum(
00111     ExtentNum extentNum,BlockNum iPageInExtent) const
00112 {
00113     // weird calculation to take into account interspersal of SegAllocNodes
00114     uint nSegPages = extentNum / nExtentsPerSegAlloc + 1;
00115     return iPageInExtent + extentNum*nPagesPerExtent + nSegPages;
00116 }
00117 
00118 inline PageId RandomAllocationSegmentBase::getExtentAllocPageId(
00119     ExtentNum extentNum) const
00120 {
00121     return getLinearPageId(makePageNum(extentNum,0));
00122 }
00123 
00124 template <class ExtentAllocationNodeT,
00125     class ExtentAllocLockT,
00126     class PageEntryT>
00127 PageId RandomAllocationSegmentBase::allocateFromExtentTemplate(
00128     ExtentNum extentNum,
00129     PageOwnerId ownerId,
00130     SharedSegment allocNodeSegment)
00131 {
00132     permAssert(ownerId != UNALLOCATED_PAGE_OWNER_ID);
00133 
00134     SegmentAccessor segAccessor(allocNodeSegment, pCache);
00135     ExtentAllocLockT extentAllocLock(segAccessor);
00136     extentAllocLock.lockExclusive(getExtAllocPageIdForWrite(extentNum));
00137     ExtentAllocationNodeT &node = extentAllocLock.getNodeForWrite();
00138     return
00139         allocateFromLockedExtentTemplate<ExtentAllocationNodeT, PageEntryT>(
00140             node,
00141             extentNum,
00142             ownerId);
00143 }
00144 
00145 template <class ExtentAllocationNodeT, class ExtentAllocLockT, class PageEntryT>
00146 void RandomAllocationSegmentBase::formatPageExtentsTemplate(
00147     SegmentAllocationNode &segAllocNode,
00148     ExtentNum &extentNum)
00149 {
00150     SegmentAccessor selfAccessor(getTracingSegment(), pCache);
00151     ExtentAllocLockT extentAllocLock(selfAccessor);
00152     uint startOffset = extentNum % nExtentsPerSegAlloc;
00153     for (uint i = startOffset; i < segAllocNode.nExtents; ++i, ++extentNum) {
00154         // -1 for the extent allocation node itself
00155         segAllocNode.getExtentEntry(i).nUnallocatedPages =
00156             nPagesPerExtent - 1;
00157         extentAllocLock.lockExclusive(getExtentAllocPageId(extentNum));
00158         extentAllocLock.setMagicNumber();
00159         formatExtentTemplate<
00160                 ExtentAllocationNodeT,
00161                 ExtentAllocLockT,
00162                 PageEntryT>(
00163             extentAllocLock.getNodeForWrite());
00164     }
00165 }
00166 
00167 template <class ExtentAllocationNodeT, class ExtentAllocLockT, class PageEntryT>
00168 void RandomAllocationSegmentBase::formatExtentTemplate(
00169     ExtentAllocationNodeT &extentNode)
00170 {
00171     // mark all pages as free
00172     for (uint i = 0; i < nPagesPerExtent; i++) {
00173         PageEntryT &pageEntry = extentNode.getPageEntry(i);
00174         markPageEntryUnused(pageEntry);
00175     }
00176 
00177     // mark the first entry representing the extent allocation node itself
00178     // as permanently allocated
00179     extentNode.getPageEntry(0).ownerId = ANON_PAGE_OWNER_ID;
00180 }
00181 
00182 template <class ExtentAllocationNodeT, class ExtentAllocLockT, class PageEntryT>
00183 PageId RandomAllocationSegmentBase::allocateFromNewExtentTemplate(
00184     ExtentNum extentNum,
00185     PageOwnerId ownerId,
00186     SharedSegment allocNodeSegment)
00187 {
00188     SegmentAccessor segAccessor(allocNodeSegment, pCache);
00189     ExtentAllocLockT extentAllocLock(segAccessor);
00190     extentAllocLock.lockExclusive(getExtAllocPageIdForWrite(extentNum));
00191     extentAllocLock.setMagicNumber();
00192     ExtentAllocationNodeT &extentNode = extentAllocLock.getNodeForWrite();
00193     formatExtentTemplate<ExtentAllocationNodeT, ExtentAllocLockT, PageEntryT>(
00194         extentNode);
00195     return
00196         allocateFromLockedExtentTemplate<ExtentAllocationNodeT, PageEntryT>(
00197             extentNode,
00198             extentNum,
00199             ownerId);
00200 }
00201 
00202 template <class ExtentAllocationNodeT, class PageEntryT>
00203 PageId RandomAllocationSegmentBase::allocateFromLockedExtentTemplate(
00204     ExtentAllocationNodeT &node, ExtentNum extentNum, PageOwnerId ownerId)
00205 {
00206     // find a free page
00207     for (uint i = 0; i < nPagesPerExtent; i++) {
00208         PageEntryT &pageEntry = node.getPageEntry(i);
00209         if (pageEntry.ownerId == UNALLOCATED_PAGE_OWNER_ID) {
00210             if (i == 0) {
00211                 // entry 0 is the extent allocation node itself so it
00212                 // should never be marked as unallocated
00213                 permAssert(false);
00214             }
00215             pageEntry.ownerId = ownerId;
00216             PageId pageId = getLinearPageId(makePageNum(extentNum,i));
00217             return pageId;
00218         }
00219     }
00220 
00221     permAssert(false);
00222 }
00223 
00224 template <class ExtentAllocationNodeT, class ExtentAllocLockT, class PageEntryT>
00225 void RandomAllocationSegmentBase::freePageEntryTemplate(
00226     ExtentNum extentNum,
00227     BlockNum iPageInExtent)
00228 {
00229     SegmentAccessor segAccessor(getTracingSegment(), pCache);
00230     ExtentAllocLockT extentAllocLock(segAccessor);
00231 
00232     extentAllocLock.lockExclusive(getExtentAllocPageId(extentNum));
00233     ExtentAllocationNodeT &extentNode = extentAllocLock.getNodeForWrite();
00234     PageEntryT &pageEntry = extentNode.getPageEntry(iPageInExtent);
00235     permAssert(pageEntry.ownerId != UNALLOCATED_PAGE_OWNER_ID);
00236     markPageEntryUnused(pageEntry);
00237 }
00238 
00239 template <class ExtentAllocationNodeT, class ExtentAllocLockT>
00240 void RandomAllocationSegmentBase::setPageSuccessorTemplate(
00241     PageId pageId,
00242     PageId successorId,
00243     SharedSegment allocNodeSegment)
00244 {
00245     assert(isPageIdAllocated(pageId));
00246     assert((successorId == NULL_PAGE_ID) || isPageIdAllocated(successorId));
00247 
00248     uint iSegAlloc;
00249     ExtentNum extentNum;
00250     BlockNum iPageInExtent;
00251     splitPageId(pageId, iSegAlloc, extentNum, iPageInExtent);
00252     permAssert(iPageInExtent);
00253 
00254     SegmentAccessor segAccessor(allocNodeSegment, pCache);
00255     ExtentAllocLockT extentAllocLock(segAccessor);
00256     extentAllocLock.lockExclusive(getExtAllocPageIdForWrite(extentNum));
00257     ExtentAllocationNodeT &node = extentAllocLock.getNodeForWrite();
00258     node.getPageEntry(iPageInExtent).successorId = successorId;
00259 }
00260 
00261 template <class PageEntryT>
00262 PageOwnerId RandomAllocationSegmentBase::getPageOwnerIdTemplate(
00263     PageId pageId,
00264     bool thisSegment)
00265 {
00266     PageEntryT pageEntry;
00267 
00268     getPageEntryCopy(pageId, pageEntry, false, thisSegment);
00269     return pageEntry.ownerId;
00270 }
00271 
00272 template <class ExtentAllocationNodeT, class ExtentAllocLockT, class PageEntryT>
00273 void RandomAllocationSegmentBase::getPageEntryCopyTemplate(
00274     PageId pageId,
00275     PageEntryT &pageEntryCopy,
00276     bool isAllocated,
00277     bool thisSegment)
00278 {
00279     if (isAllocated) {
00280         assert(testPageId(pageId, true, thisSegment));
00281     }
00282 
00283     ExtentNum extentNum;
00284     BlockNum iPageInExtent;
00285     uint iSegAlloc;
00286     splitPageId(pageId, iSegAlloc, extentNum, iPageInExtent);
00287     assert(iPageInExtent);
00288 
00289     SharedSegment allocNodeSegment;
00290     PageId extentPageId;
00291     if (thisSegment) {
00292         allocNodeSegment = getTracingSegment();
00293         extentPageId = getExtentAllocPageId(extentNum);
00294     } else {
00295         extentPageId = getExtAllocPageIdForRead(extentNum, allocNodeSegment);
00296     }
00297 
00298     SegmentAccessor segAccessor(allocNodeSegment, pCache);
00299     ExtentAllocLockT extentAllocLock(segAccessor);
00300     extentAllocLock.lockShared(extentPageId);
00301     ExtentAllocationNodeT const &extentNode =
00302         extentAllocLock.getNodeForRead();
00303 
00304     PageEntryT const &pageEntry =
00305         extentNode.getPageEntry(iPageInExtent);
00306 
00307     pageEntryCopy = pageEntry;
00308 }
00309 
00310 FENNEL_END_NAMESPACE
00311 
00312 #endif
00313 
00314 // End RandomAllocationSegmentBaseImpl.h

Generated on Mon Jun 22 04:00:20 2009 for Fennel by  doxygen 1.5.1