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