SegPageIter.cpp

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/segment/SegPageIter.cpp#9 $
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 #include "fennel/common/CommonPreamble.h"
00025 #include "fennel/segment/SegPageIter.h"
00026 #include "fennel/segment/Segment.h"
00027 #include "fennel/cache/CacheAccessor.h"
00028 #include "fennel/common/CompoundId.h"
00029 
00030 FENNEL_BEGIN_CPPFILE("$Id: //open/dev/fennel/segment/SegPageIter.cpp#9 $");
00031 
00032 // TODO:  old stuff (!prefetch, chain)?
00033 
00034 // TODO:  call nicePage on pages as they pass
00035 
00036 // TODO:  deallocate pages as they pass
00037 
00038 // TODO:  require nPagesPerBatch to be power of 2, and use & instead of %
00039 
00040 SegPageIter::SegPageIter()
00041 {
00042 }
00043 
00044 void SegPageIter::mapRange(
00045     SegmentAccessor const &segmentAccessorInit,
00046     PageId beginPageIdInit,
00047     PageId endPageIdInit)
00048 {
00049     assert(segmentAccessorInit.pSegment);
00050     assert(segmentAccessorInit.pCacheAccessor);
00051     segmentAccessor = segmentAccessorInit;
00052     initPrefetchQueue();
00053     endPageId = endPageIdInit;
00054     for (uint i = 0; i < queueSize; i++) {
00055         if (atEnd) {
00056             break;
00057         }
00058         if (i > 0) {
00059             beginPageIdInit = segmentAccessor.pSegment->getPageSuccessor(
00060                 prefetchQueue[i - 1]);
00061         }
00062         prefetchPage(beginPageIdInit);
00063     }
00064 }
00065 
00066 void SegPageIter::initPrefetchQueue()
00067 {
00068     segmentAccessor.pCacheAccessor->getPrefetchParams(
00069         prefetchPagesMax,
00070         prefetchThrottleRate);
00071     queueSize = prefetchPagesMax;
00072     noPrefetch = (queueSize == 0);
00073     // Reset the queue size so we have space to store at least one page
00074     if (queueSize < 1) {
00075         queueSize = 1;
00076     }
00077     prefetchQueue.resize(queueSize);
00078 
00079     nFreePageSlots = queueSize;
00080     currPageSlot = 0;
00081     iFetch = 0;
00082     atEnd = 0;
00083     throttleCount = 0;
00084     forceReject = false;
00085 }
00086 
00087 void SegPageIter::operator ++ ()
00088 {
00089     assert(!isSingular());
00090     assert(**this != endPageId);
00091 
00092     // Move past the page currently at the front of the queue.
00093     iFetch = (iFetch + 1) % queueSize;
00094     ++nFreePageSlots;
00095 
00096     if (atEnd) {
00097         return;
00098     }
00099 
00100     // Pre-fetch a page to replace the page that was at the front
00101     // of the queue.
00102     int iPrev = currPageSlot - 1;
00103     if (iPrev < 0) {
00104         iPrev += queueSize;
00105     }
00106     prefetchPage(
00107         segmentAccessor.pSegment->getPageSuccessor(prefetchQueue[iPrev]));
00108 }
00109 
00110 void SegPageIter::prefetchPage(PageId pageId)
00111 {
00112     // Store the page we're about to pre-fetch in the first empty slot
00113     // in the queue
00114     prefetchQueue[currPageSlot++] = pageId;
00115     currPageSlot %= queueSize;
00116     --nFreePageSlots;
00117 
00118     if (pageId == endPageId) {
00119         atEnd = 1;
00120         return;
00121     }
00122 
00123     // If pre-fetches are turned off, don't bothering issuing the pre-fetch
00124     // request.
00125     BlockId blockId = NULL_BLOCK_ID;
00126     if (!forceReject && !noPrefetch) {
00127         blockId = segmentAccessor.pSegment->translatePageId(pageId);
00128     }
00129     if (!forceReject &&
00130         (noPrefetch ||
00131             segmentAccessor.pCacheAccessor->prefetchPage(
00132                 blockId,
00133                 segmentAccessor.pSegment->getMappedPageListener(blockId))))
00134     {
00135         // If the pre-fetch rate was throttled down, then wait until we
00136         // reach the desired number of successful pre-fetches before
00137         // throttling the rate back up, one page at a time.
00138         if (throttleCount > 0) {
00139             assert(prefetchPagesMax != 0);
00140             if (--throttleCount == 0) {
00141                 // At a minimum, reenable pre-fetches
00142                 noPrefetch = false;
00143 
00144                 // If we haven't throttled back to the max pre-fetch
00145                 // rate, then reset the counter so we can continue
00146                 // counting successful pre-fetches to allow the rate
00147                 // to continue throttling up.  In the case where the
00148                 // pre-fetch rate is a single page, no further throttling
00149                 // is possible.
00150                 if (prefetchPagesMax > 1) {
00151                     nFreePageSlots++;
00152                     if (nFreePageSlots < prefetchPagesMax) {
00153                         throttleCount = prefetchThrottleRate;
00154                     }
00155                 }
00156             }
00157         }
00158     } else {
00159         // If pre-fetches aren't already disabled, then set the number of
00160         // pre-fetches to the number of outstanding pre-fetches by
00161         // disallowing any new pre-fetches until the existing ones are used.
00162         // If we're down to doing a single pre-fetch, then turn off
00163         // pre-fetches.
00164         if (prefetchPagesMax > 0) {
00165             if (nFreePageSlots > 0) {
00166                 nFreePageSlots = 0;
00167             }
00168             if (iFetch == currPageSlot) {
00169                 noPrefetch = true;
00170             }
00171             throttleCount = prefetchThrottleRate;
00172         }
00173         forceReject = false;
00174     }
00175 }
00176 
00177 void SegPageIter::forcePrefetchReject()
00178 {
00179     forceReject = true;
00180 }
00181 
00182 FENNEL_END_CPPFILE("$Id: //open/dev/fennel/segment/SegPageIter.cpp#9 $");
00183 
00184 // End SegPageIter.cpp

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