TwoQVictimPolicy.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/cache/TwoQVictimPolicy.h#8 $
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_TwoQVictimPolicy_Included
00025 #define Fennel_TwoQVictimPolicy_Included
00026 
00027 #include "fennel/common/IntrusiveDList.h"
00028 
00029 #include <boost/dynamic_bitset.hpp>
00030 
00031 FENNEL_BEGIN_NAMESPACE
00032 
00038 class FENNEL_CACHE_EXPORT TwoQPageQueue
00039 {
00043     IntrusiveDListNode *head;
00044 
00048     IntrusiveDListNode *tail;
00049 
00053     uint len;
00054 
00058     void validateQueue()
00059     {
00060         assert(head == NULL || head->getPrev() == NULL);
00061         assert(tail == NULL || tail->getNext() == NULL);
00062 
00063         uint actualLen = 0;
00064         IntrusiveDListNode *curr = head;
00065         while (curr != NULL) {
00066             actualLen++;
00067             curr = curr->getNext();
00068         }
00069         assert(actualLen == len);
00070 
00071         curr = tail;
00072         actualLen = 0;
00073         while (curr != NULL) {
00074             actualLen++;
00075             curr = curr->getPrev();
00076         }
00077         assert(actualLen == len);
00078     }
00079 
00080 public:
00081     TwoQPageQueue()
00082     {
00083         head = NULL;
00084         tail = NULL;
00085         len = 0;
00086     }
00087 
00093     void insertAtHead(IntrusiveDListNode &page)
00094     {
00095         if (head == NULL) {
00096             assert(tail == NULL);
00097             tail = &page;
00098         } else {
00099             page.insertBefore(*head);
00100         }
00101         head = &page;
00102         len++;
00103     }
00104 
00110     void moveToHead(IntrusiveDListNode &page)
00111     {
00112         if (head == &page) {
00113             return;
00114         }
00115         if (tail == &page) {
00116             tail = page.getPrev();
00117         }
00118         page.detach();
00119         page.insertBefore(*head);
00120         head = &page;
00121     }
00122 
00128     void insertAtTail(IntrusiveDListNode &page)
00129     {
00130         if (tail == NULL) {
00131             assert(head == NULL);
00132             head = &page;
00133         } else {
00134             page.insertAfter(*tail);
00135         }
00136         tail = &page;
00137         len++;
00138     }
00139 
00145     void moveToTail(IntrusiveDListNode &page)
00146     {
00147         if (tail == &page) {
00148             return;
00149         }
00150         if (head == &page) {
00151             head = page.getNext();
00152         }
00153         page.detach();
00154         page.insertAfter(*tail);
00155         tail = &page;
00156     }
00157 
00163     void remove(IntrusiveDListNode &page)
00164     {
00165         assert(len == 1 || (page.getNext() != NULL || page.getPrev() != NULL));
00166         if (&page == head && &page == tail) {
00167             assert(len == 1);
00168             head = tail = NULL;
00169         } else if (&page == head) {
00170             head = head->getNext();
00171         } else if (&page == tail) {
00172             tail = tail->getPrev();
00173         }
00174         page.detach();
00175         assert(len > 0);
00176         len--;
00177     }
00178 
00182     uint size()
00183     {
00184         return len;
00185     }
00186 
00190     IntrusiveDListNode *getHead()
00191     {
00192         return head;
00193     }
00194 };
00195 
00203 class FENNEL_CACHE_EXPORT TwoQDirtyPage
00204     : public IntrusiveDListNode
00205 {
00206 public:
00211     enum DirtyPageState {
00215         PAGE_CLEAN,
00216 
00220         PAGE_DIRTY_POPULAR_UNPINNED,
00221 
00225         PAGE_DIRTY_FRESHMAN,
00226 
00230         PAGE_DIRTY_POPULAR_PINNED
00231     };
00232 
00233 private:
00237     CachePage *pParentPage;
00238 
00242     DirtyPageState dirtyState;
00243 
00244 public:
00250     void setParentPage(CachePage &parentPageInit)
00251     {
00252         pParentPage = &parentPageInit;
00253     }
00254 
00258     CachePage &getParentPage()
00259     {
00260         return *pParentPage;
00261     }
00262 
00266     DirtyPageState getDirtyState()
00267     {
00268         return dirtyState;
00269     }
00270 
00276     void setDirtyState(DirtyPageState newState)
00277     {
00278         dirtyState = newState;
00279     }
00280 };
00281 
00286 class FENNEL_CACHE_EXPORT TwoQVictim
00287     : public IntrusiveDListNode
00288 {
00289 public:
00294     enum PageState {
00298         PAGE_STATE_POPULAR_PINNED,
00302         PAGE_STATE_POPULAR_UNPINNED,
00306         PAGE_STATE_FRESHMAN,
00310         PAGE_STATE_FREE
00311     };
00312 
00313 private:
00317     PageState state;
00318 
00322     TwoQDirtyPage dirtyPageNode;
00323 
00324 public:
00325 
00326     TwoQVictim()
00327     {
00328         state = PAGE_STATE_FREE;
00329         dirtyPageNode.setDirtyState(TwoQDirtyPage::PAGE_CLEAN);
00330     }
00331 
00335     PageState getState()
00336     {
00337         return state;
00338     }
00339 
00345     void setState(PageState newState)
00346     {
00347         state = newState;
00348     }
00349 
00353     TwoQDirtyPage &getDirtyPageNode()
00354     {
00355         return dirtyPageNode;
00356     }
00357 };
00358 
00362 template <class PageT>
00363 class TwoQPageListIter : public IntrusiveTwoDListIter<PageT, PageT>
00364 {
00368     virtual PageT *getReturnElement(PageT *page) const
00369     {
00370         return page;
00371     }
00372 
00373 public:
00374     TwoQPageListIter()
00375         : IntrusiveTwoDListIter<PageT, PageT>()
00376     {
00377     }
00378 
00379     TwoQPageListIter(PageT *list1, PageT *list2)
00380         : IntrusiveTwoDListIter<PageT, PageT>(list1, list2)
00381     {
00382     }
00383 
00384     ~TwoQPageListIter()
00385     {
00386     }
00387 };
00388 
00389 
00394 template <class PageT>
00395 class TwoQDirtyPageListIter : public IntrusiveTwoDListIter<TwoQDirtyPage, PageT>
00396 {
00406     virtual PageT *getReturnElement(TwoQDirtyPage *dirtyPage) const
00407     {
00408         if (dirtyPage == NULL) {
00409             return NULL;
00410         } else {
00411             return static_cast<PageT *>(&(dirtyPage->getParentPage()));
00412         }
00413     }
00414 
00415 public:
00416     TwoQDirtyPageListIter()
00417         : IntrusiveTwoDListIter<TwoQDirtyPage, PageT>()
00418     {
00419     }
00420 
00421     TwoQDirtyPageListIter(TwoQDirtyPage *list1, TwoQDirtyPage *list2)
00422         : IntrusiveTwoDListIter<TwoQDirtyPage, PageT>(list1, list2)
00423     {
00424     }
00425 
00426     ~TwoQDirtyPageListIter()
00427     {
00428     }
00429 };
00430 
00473 template <class PageT>
00474 class TwoQVictimPolicy
00475 {
00479     SXMutex mutex;
00480 
00485     TwoQPageQueue popularPinnedQueue;
00486 
00490     TwoQPageQueue popularUnpinnedQueue;
00491 
00495     TwoQPageQueue freshmenQueue;
00496 
00501     TwoQPageQueue dirtyPopularUnpinnedQueue;
00502 
00507     TwoQPageQueue dirtyFreshmenQueue;
00508 
00512     std::vector<BlockId> historyQueue;
00513 
00517     uint historyQueueStart;
00518 
00522     uint currHistoryQueueLen;
00523 
00531     boost::dynamic_bitset<> historyBitmap;
00532 
00536     uint nCachePages;
00537 
00543     uint maxFreshmenQueueLen;
00544 
00548     uint maxHistoryQueueLen;
00549 
00555     uint freshmenQueuePercentage;
00556 
00561     uint pageHistoryQueuePercentage;
00562 
00566     void init()
00567     {
00568         nCachePages = 0;
00569         maxFreshmenQueueLen = 0;
00570         maxHistoryQueueLen = 0;
00571         historyQueueStart = 0;
00572         currHistoryQueueLen = 0;
00573     }
00574 
00578     bool isPageClean(PageT &page)
00579     {
00580         return
00581             (!page.isDirty() &&
00582                 page.getDirtyPageNode().getDirtyState() ==
00583                     TwoQDirtyPage::PAGE_CLEAN);
00584     }
00585 
00594     void notifyPopularPageAccess(PageT &page, bool pin)
00595     {
00596         assert(mutex.isLocked(LOCKMODE_X));
00597         TwoQVictim::PageState state = page.TwoQVictim::getState();
00598         assert(
00599             state != TwoQVictim::PAGE_STATE_FRESHMAN &&
00600             state != TwoQVictim::PAGE_STATE_POPULAR_PINNED);
00601 
00602         if (pin) {
00603             // Remove the page from the popular-unpinned queues and add
00604             // it to the popular-pinned queue.
00605             if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
00606                 popularUnpinnedQueue.remove(page);
00607                 TwoQDirtyPage &dirtyPageNode =
00608                     page.TwoQVictim::getDirtyPageNode();
00609                 if (dirtyPageNode.getDirtyState() ==
00610                     TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED)
00611                 {
00612                     dirtyPopularUnpinnedQueue.remove(dirtyPageNode);
00613                     dirtyPageNode.setDirtyState(
00614                         TwoQDirtyPage::PAGE_DIRTY_POPULAR_PINNED);
00615                 } else {
00616                     assert(isPageClean(page));
00617                 }
00618             }
00619             popularPinnedQueue.insertAtTail(page);
00620             page.TwoQVictim::setState(TwoQVictim::PAGE_STATE_POPULAR_PINNED);
00621 
00622         } else {
00623             // Move the page to the end of the popular-unpinned queues.
00624             if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
00625                 popularUnpinnedQueue.moveToTail(page);
00626                 TwoQDirtyPage &dirtyPageNode =
00627                     page.TwoQVictim::getDirtyPageNode();
00628                 if (dirtyPageNode.getDirtyState() ==
00629                     TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED)
00630                 {
00631                     dirtyPopularUnpinnedQueue.moveToTail(dirtyPageNode);
00632                 } else {
00633                     assert(isPageClean(page));
00634                 }
00635             } else {
00636                 // The page was originally free and now needs to be put
00637                 // into the popular-unpinned queue.
00638                 assert(isPageClean(page));
00639                 popularUnpinnedQueue.insertAtTail(page);
00640                 page.TwoQVictim::setState(
00641                     TwoQVictim::PAGE_STATE_POPULAR_UNPINNED);
00642             }
00643         }
00644     }
00645 
00646 public:
00647 
00656     typedef TwoQPageListIter<PageT> PageIterator;
00657 
00665     typedef TwoQDirtyPageListIter<PageT> DirtyPageIterator;
00666 
00677     typedef SXMutexSharedGuard SharedGuard;
00678 
00682     typedef SXMutexExclusiveGuard ExclusiveGuard;
00683 
00687     TwoQVictimPolicy()
00688     {
00689         init();
00690         freshmenQueuePercentage = CacheParams::defaultFreshmenQueuePercentage;
00691         pageHistoryQueuePercentage =
00692             CacheParams::defaultPageHistoryQueuePercentage;
00693     }
00694 
00695     TwoQVictimPolicy(const CacheParams &params)
00696     {
00697         init();
00698         freshmenQueuePercentage = params.freshmenQueuePercentage;
00699         pageHistoryQueuePercentage = params.pageHistoryQueuePercentage;
00700     }
00701 
00708     void setAllocatedPageCount(uint nCachePagesInit)
00709     {
00710         ExclusiveGuard exclusiveGuard(mutex);
00711 
00712         if (nCachePagesInit == nCachePages) {
00713             return;
00714         }
00715 
00716         uint newHistoryQueueLen =
00717             nCachePagesInit * pageHistoryQueuePercentage / 100;
00718         if ((currHistoryQueueLen > newHistoryQueueLen) ||
00719             (historyQueueStart != 0))
00720         {
00721             // If the new queue is smaller than the currently used size,
00722             // copy the existing history queue into a temporary vector,
00723             // truncating the front of the queue to match the size of
00724             // the new vector.  We also need to recreate the vector if
00725             // the new queue is larger than the currently used size,
00726             // and the existing history queue has cycled around such
00727             // that the starting element is no longer at position 0.
00728             std::vector<BlockId> temp;
00729             temp.resize(newHistoryQueueLen);
00730             uint excess =
00731                 (currHistoryQueueLen > newHistoryQueueLen)
00732                     ? (currHistoryQueueLen - newHistoryQueueLen) : 0;
00733             currHistoryQueueLen -= excess;
00734             for (uint i = 0; i < currHistoryQueueLen; i++) {
00735                 temp[i] =
00736                     historyQueue[
00737                         (historyQueueStart + excess + i) %
00738                         maxHistoryQueueLen];
00739             }
00740             historyQueueStart = 0;
00741             historyQueue.resize(newHistoryQueueLen);
00742             historyQueue.swap(temp);
00743         } else {
00744             historyQueue.resize(newHistoryQueueLen);
00745         }
00746 
00747         // It's possible that a blockId has been removed from the history
00748         // bitmap, but the corresponding update hasn't been made in the
00749         // history queue itself.  If so, remove the blockId from the queue
00750         // so when we rebuild the bitmap below, that blockId won't be included.
00751         assert(historyQueueStart == 0);
00752         for (uint i = 0; i < currHistoryQueueLen; i++) {
00753             if (!historyBitmap.test(
00754                 opaqueToInt(historyQueue[i] % historyBitmap.size())))
00755             {
00756                 historyQueue[i] = NULL_BLOCK_ID;
00757             }
00758         }
00759 
00760         nCachePages = nCachePagesInit;
00761         maxFreshmenQueueLen = nCachePages * freshmenQueuePercentage / 100;
00762         maxHistoryQueueLen = newHistoryQueueLen;
00763 
00764         historyBitmap.resize(maxHistoryQueueLen * 64);
00765         // Rebuild the history bitmap, if there are existing entries in the
00766         // history queue.  Ignore the invalid blockIds.
00767         if (currHistoryQueueLen > 0) {
00768             historyBitmap.reset();
00769             for (uint i = 0; i < currHistoryQueueLen; i++) {
00770                 if (historyQueue[i] != NULL_BLOCK_ID) {
00771                     historyBitmap.set(
00772                         opaqueToInt(historyQueue[i]) % historyBitmap.size());
00773                 }
00774             }
00775         }
00776     }
00777 
00785     void registerPage(PageT &page)
00786     {
00787         page.TwoQVictim::setState(TwoQVictim::PAGE_STATE_FREE);
00788         page.TwoQVictim::getDirtyPageNode().setParentPage(page);
00789         page.TwoQVictim::getDirtyPageNode().setDirtyState(
00790             TwoQDirtyPage::PAGE_CLEAN);
00791     }
00792 
00800     void unregisterPage(PageT &page)
00801     {
00802         assert(page.TwoQVictim::getState() == TwoQVictim::PAGE_STATE_FREE);
00803         assert(
00804             page.TwoQVictim::getDirtyPageNode().getDirtyState() ==
00805             TwoQDirtyPage::PAGE_CLEAN);
00806     }
00807 
00834     void notifyPageAccess(PageT &page, bool pin)
00835     {
00836         ExclusiveGuard exclusiveGuard(mutex);
00837 
00838         switch (page.TwoQVictim::getState()) {
00839         case TwoQVictim::PAGE_STATE_FRESHMAN:
00840         case TwoQVictim::PAGE_STATE_POPULAR_PINNED:
00841             return;
00842 
00843         case TwoQVictim::PAGE_STATE_POPULAR_UNPINNED:
00844             notifyPopularPageAccess(page, pin);
00845             break;
00846 
00847         case TwoQVictim::PAGE_STATE_FREE:
00848             if (historyBitmap.test(
00849                 opaqueToInt(page.getBlockId()) % historyBitmap.size()))
00850             {
00851                 notifyPopularPageAccess(page, pin);
00852             } else {
00853                 assert(isPageClean(page));
00854                 page.TwoQVictim::setState(TwoQVictim::PAGE_STATE_FRESHMAN);
00855                 freshmenQueue.insertAtTail(page);
00856             }
00857             break;
00858 
00859         default:
00860             permAssert(false);
00861         }
00862     }
00863 
00872     void notifyPageNice(PageT &page)
00873     {
00874         ExclusiveGuard exclusiveGuard(mutex);
00875         TwoQVictim::PageState state = page.TwoQVictim::getState();
00876         assert(state != TwoQVictim::PAGE_STATE_FREE);
00877 
00878         if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
00879             popularUnpinnedQueue.moveToHead(page);
00880             TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
00881             if (dirtyPageNode.getDirtyState() ==
00882                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED)
00883             {
00884                 dirtyPopularUnpinnedQueue.moveToHead(dirtyPageNode);
00885             } else {
00886                 assert(isPageClean(page));
00887             }
00888         } else if (state == TwoQVictim::PAGE_STATE_FRESHMAN) {
00889             freshmenQueue.moveToHead(page);
00890             TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
00891             if (dirtyPageNode.getDirtyState() ==
00892                 TwoQDirtyPage::PAGE_DIRTY_FRESHMAN)
00893             {
00894                 dirtyFreshmenQueue.moveToHead(dirtyPageNode);
00895             } else {
00896                 assert(isPageClean(page));
00897             }
00898         }
00899     }
00900 
00909     void notifyPageMap(PageT &page, bool pin)
00910     {
00911         // first access for a newly mapped page will not get a corresponding
00912         // call to notifyPageAcces, so do it now
00913         notifyPageAccess(page, pin);
00914     }
00915 
00924     void notifyPageUnmap(PageT &page, bool discard)
00925     {
00926         ExclusiveGuard exclusiveGuard(mutex);
00927         TwoQVictim::PageState state = page.TwoQVictim::getState();
00928         assert(
00929             state != TwoQVictim::PAGE_STATE_POPULAR_PINNED &&
00930             state != TwoQVictim::PAGE_STATE_FREE);
00931 
00932         if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
00933             popularUnpinnedQueue.remove(page);
00934             TwoQDirtyPage &dirtyPageNode =
00935                 page.TwoQVictim::getDirtyPageNode();
00936             if (dirtyPageNode.getDirtyState() ==
00937                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED)
00938             {
00939                 dirtyPopularUnpinnedQueue.remove(dirtyPageNode);
00940                 dirtyPageNode.setDirtyState(TwoQDirtyPage::PAGE_CLEAN);
00941             } else {
00942                 assert(isPageClean(page));
00943             }
00944         } else {
00945             // If the page is currently in the freshmen queue, add it to
00946             // the history queue, unless the page is being discarded.
00947             // Remove the page currently at the head of the history queue,
00948             // if the history queue is at max capacity.  Also make the
00949             // corresponding updates in the history bitmap.
00950             if (!discard) {
00951                 if (currHistoryQueueLen >= maxHistoryQueueLen) {
00952                     historyBitmap.set(
00953                         opaqueToInt(historyQueue[historyQueueStart])
00954                             % historyBitmap.size(),
00955                         false);
00956                     historyQueueStart =
00957                         (historyQueueStart + 1) % maxHistoryQueueLen;
00958                     currHistoryQueueLen--;
00959                 }
00960                 uint currIdx =
00961                     (historyQueueStart + currHistoryQueueLen) %
00962                         maxHistoryQueueLen;
00963                 historyQueue[currIdx] = page.getBlockId();
00964                 historyBitmap.set(
00965                     opaqueToInt(page.getBlockId()) % historyBitmap.size());
00966                 currHistoryQueueLen++;
00967             }
00968 
00969             freshmenQueue.remove(page);
00970             TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
00971             if (dirtyPageNode.getDirtyState() ==
00972                 TwoQDirtyPage::PAGE_DIRTY_FRESHMAN)
00973             {
00974                 dirtyFreshmenQueue.remove(dirtyPageNode);
00975                 dirtyPageNode.setDirtyState(TwoQDirtyPage::PAGE_CLEAN);
00976             } else {
00977                 assert(isPageClean(page));
00978             }
00979         }
00980 
00981         // If the page is being discarded, remove it from the history bitmap.
00982         // Just clear the blockId from the history bitmap, but leave the
00983         // blockId in the history queue itself.  The page will get cleaned out
00984         // if we need to resize the history queue.
00985         if (discard) {
00986             historyBitmap.set(
00987                 opaqueToInt(page.getBlockId()) % historyBitmap.size(),
00988                 false);
00989         }
00990 
00991         page.TwoQVictim::setState(TwoQVictim::PAGE_STATE_FREE);
00992         assert(page.getNext() == NULL && page.getPrev() == NULL);
00993     }
00994 
01001     void notifyPageUnpin(PageT &page)
01002     {
01003         ExclusiveGuard exclusiveGuard(mutex);
01004         TwoQVictim::PageState state = page.TwoQVictim::getState();
01005         assert(
01006             state != TwoQVictim::PAGE_STATE_POPULAR_UNPINNED &&
01007             state != TwoQVictim::PAGE_STATE_FREE);
01008 
01009         // If the page is poular and pinned, move it to the popular-unpinned
01010         // queues.
01011         if (state == TwoQVictim::PAGE_STATE_POPULAR_PINNED) {
01012             popularPinnedQueue.remove(page);
01013             popularUnpinnedQueue.insertAtTail(page);
01014             TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
01015             if (dirtyPageNode.getDirtyState() ==
01016                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_PINNED)
01017             {
01018                 dirtyPopularUnpinnedQueue.insertAtTail(dirtyPageNode);
01019                 dirtyPageNode.setDirtyState(
01020                     TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED);
01021             } else {
01022                 assert(isPageClean(page));
01023             }
01024             page.TwoQVictim::setState(TwoQVictim::PAGE_STATE_POPULAR_UNPINNED);
01025         }
01026         // If the page state is free or a freshman, then there's nothing to do
01027     }
01028 
01035     void notifyPageDirty(PageT &page)
01036     {
01037         ExclusiveGuard exclusiveGuard(mutex);
01038         TwoQVictim::PageState state = page.TwoQVictim::getState();
01039         assert(state != TwoQVictim::PAGE_STATE_FREE);
01040 
01041         TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
01042         assert(
01043             dirtyPageNode.getDirtyState() == TwoQDirtyPage::PAGE_CLEAN);
01044 
01045         // Set the dirty state to match the queue containing the page, and
01046         // then if appropriate, add the dirty node to the corresponding
01047         // dirty queue.  In the case of pages that are in the popular-pinned
01048         // queue, just set the dirty state since we don't have a dirty queue
01049         // for popular-pinned pages.  But we need to set the dirty state so
01050         // we know that the page is dirty when it's unpinned and moved to
01051         // the popular-unpinned queue.
01052         if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
01053             dirtyPopularUnpinnedQueue.insertAtTail(dirtyPageNode);
01054             dirtyPageNode.setDirtyState(
01055                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED);
01056         } else if (state == TwoQVictim::PAGE_STATE_FRESHMAN) {
01057             dirtyFreshmenQueue.insertAtTail(dirtyPageNode);
01058             dirtyPageNode.setDirtyState(
01059                     TwoQDirtyPage::PAGE_DIRTY_FRESHMAN);
01060         } else if (state == TwoQVictim::PAGE_STATE_POPULAR_PINNED) {
01061             dirtyPageNode.setDirtyState(
01062                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_PINNED);
01063         }
01064     }
01065 
01071     void notifyPageClean(PageT &page)
01072     {
01073         ExclusiveGuard exclusiveGuard(mutex);
01074         TwoQVictim::PageState state = page.TwoQVictim::getState();
01075         // Note that it is possible for the page to be in the popular-pinned
01076         // queue if the page has just been pinned and the thread accessing
01077         // the page is waiting for I/O on the page to complete before using it.
01078         assert(state != TwoQVictim::PAGE_STATE_FREE);
01079 
01080         // Remove the dirty node from the queue if it's currently in a
01081         // queue, and then reset its dirty state to indicate that the page
01082         // is now clean.
01083         TwoQDirtyPage &dirtyPageNode = page.TwoQVictim::getDirtyPageNode();
01084         if (state == TwoQVictim::PAGE_STATE_POPULAR_UNPINNED) {
01085             assert(
01086                 dirtyPageNode.getDirtyState() ==
01087                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_UNPINNED);
01088             dirtyPopularUnpinnedQueue.remove(dirtyPageNode);
01089         } else if (state == TwoQVictim::PAGE_STATE_FRESHMAN) {
01090             assert(
01091                 dirtyPageNode.getDirtyState() ==
01092                 TwoQDirtyPage::PAGE_DIRTY_FRESHMAN);
01093             dirtyFreshmenQueue.remove(dirtyPageNode);
01094         } else if (state == TwoQVictim::PAGE_STATE_POPULAR_PINNED) {
01095             assert(
01096                 dirtyPageNode.getDirtyState() ==
01097                 TwoQDirtyPage::PAGE_DIRTY_POPULAR_PINNED);
01098         }
01099         dirtyPageNode.setDirtyState(TwoQDirtyPage::PAGE_CLEAN);
01100     }
01101 
01109     void notifyPageDiscard(BlockId blockId)
01110     {
01111         ExclusiveGuard exclusiveGuard(mutex);
01112         // Just clear the blockId from the history bitmap, but leave the
01113         // blockId in the history queue itself.  The page will get cleaned out
01114         // if we need to resize the history queue.
01115         historyBitmap.set(opaqueToInt(blockId % historyBitmap.size()), false);
01116     }
01117 
01125     SXMutex &getMutex()
01126     {
01127         return mutex;
01128     }
01129 
01136     std::pair<PageIterator,PageIterator> getVictimRange()
01137     {
01138         // If the freshmen queue has hit its size limit, victimize from
01139         // that queue first.  If all of its pages are pinned, then try
01140         // victimizing from the popular-unpinned page queue.  Do the
01141         // reverse if the freshmen queue has hit its size limit.
01142 
01143         if (freshmenQueue.size() < maxFreshmenQueueLen) {
01144             return std::pair<PageIterator, PageIterator>(
01145                 PageIterator(
01146                     static_cast<PageT *>(popularUnpinnedQueue.getHead()),
01147                     static_cast<PageT *>(freshmenQueue.getHead())),
01148                 PageIterator());
01149         } else {
01150             return std::pair<PageIterator, PageIterator>(
01151                 PageIterator(
01152                     static_cast<PageT *>(freshmenQueue.getHead()),
01153                     static_cast<PageT *>(popularUnpinnedQueue.getHead())),
01154                 PageIterator());
01155         }
01156     }
01157 
01164     std::pair<DirtyPageIterator,DirtyPageIterator> getDirtyVictimRange()
01165     {
01166         // If the freshmen queue has hit its size limit, victimize from
01167         // that queue first.  If all of its pages are pinned, then try
01168         // victimizing from the popular-unpinned page queue.  Do the
01169         // reverse if the freshmen queue has hit its size limit.
01170 
01171         if (freshmenQueue.size() < maxFreshmenQueueLen) {
01172             return std::pair<DirtyPageIterator, DirtyPageIterator>(
01173                 DirtyPageIterator(
01174                     static_cast<TwoQDirtyPage *>(
01175                         dirtyPopularUnpinnedQueue.getHead()),
01176                     static_cast<TwoQDirtyPage *>(dirtyFreshmenQueue.getHead())),
01177                 DirtyPageIterator());
01178         } else {
01179             return std::pair<DirtyPageIterator, DirtyPageIterator>(
01180                 DirtyPageIterator(
01181                     static_cast<TwoQDirtyPage *>(dirtyFreshmenQueue.getHead()),
01182                     static_cast<TwoQDirtyPage *>(
01183                         dirtyPopularUnpinnedQueue.getHead())),
01184                 DirtyPageIterator());
01185         }
01186     }
01187 };
01188 
01189 FENNEL_END_NAMESPACE
01190 
01191 #endif
01192 
01193 // End TwoQVictimPolicy.h

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