CachePage.h

Go to the documentation of this file.
00001 /*
00002 // $Id: //open/dev/fennel/cache/CachePage.h#16 $
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_CachePage_Included
00025 #define Fennel_CachePage_Included
00026 
00027 #include "fennel/synch/SynchObj.h"
00028 #include "fennel/synch/SXMutex.h"
00029 #include "fennel/device/RandomAccessRequest.h"
00030 #include "fennel/cache/Cache.h"
00031 #include "fennel/cache/CacheAllocator.h"
00032 #include "fennel/common/SysCallExcn.h"
00033 
00034 FENNEL_BEGIN_NAMESPACE
00035 
00036 class Cache;
00037 class MappedPageListener;
00038 
00039 template <class PageT,class VictimPolicyT>
00040 class CacheImpl;
00041 
00045 class FENNEL_CACHE_EXPORT PageBucketListNode
00046     : public IntrusiveListNode
00047 {
00048 };
00049 
00056 class FENNEL_CACHE_EXPORT CachePage
00057     : public PageBucketListNode, private RandomAccessRequestBinding
00058 {
00059 public:
00064     enum DataStatus {
00068         DATA_INVALID,
00069 
00073         DATA_ERROR,
00074 
00079         DATA_CLEAN,
00080 
00084         DATA_DIRTY,
00085 
00089         DATA_WRITE,
00090 
00095         DATA_READ
00096     };
00097 
00098 private:
00099     template <class PageT,class VictimPolicyT>
00100     friend class CacheImpl;
00101 
00102 // ----------------------------------------------------------------------
00103 // State variables
00104 // ----------------------------------------------------------------------
00108     Cache &cache;
00109 
00114     StrictMutex mutex;
00115 
00120     SXMutex lock;
00121 
00125     PBuffer pBuffer;
00126 
00127     // NOTE: the data members below should only be accessed while the
00128     // page mutex is held.  This includes indirect access via accessors such as
00129     // getBlockId().
00130 
00135     BlockId blockId;
00136 
00143     uint nReferences;
00144 
00149     LocalCondition ioCompletionCondition;
00150 
00155     MappedPageListener *pMappedPageListener;
00156 
00160     DataStatus dataStatus;
00161 
00162 // ----------------------------------------------------------------------
00163 // Methods internal to CacheImpl
00164 // ----------------------------------------------------------------------
00168     bool hasBlockId() const
00169     {
00170         return blockId != NULL_BLOCK_ID;
00171     }
00172 
00178     void waitForPendingIO(StrictMutexGuard &guard)
00179     {
00180         ioCompletionCondition.wait(guard);
00181     }
00182 
00186     bool isExclusiveLockHeld() const
00187     {
00188         // REVIEW:  should make sure lock is held by this thread?
00189         return isScratchLocked() || lock.isLocked(LOCKMODE_X);
00190     }
00191 
00192 // ----------------------------------------------------------------------
00193 // Implementation of RandomAccessRequestBinding interface (q.v.)
00194 // ----------------------------------------------------------------------
00195     virtual void notifyTransferCompletion(bool bSuccess);
00196     virtual PBuffer getBuffer() const;
00197     virtual uint getBufferSize() const;
00198 
00199 public:
00200     explicit CachePage(Cache &,PBuffer);
00201     virtual ~CachePage();
00202 
00206     Cache &getCache()
00207     {
00208         return cache;
00209     }
00210 
00215     bool isDirty() const
00216     {
00217         return dataStatus == DATA_DIRTY;
00218     }
00219 
00223     bool isTransferInProgress() const
00224     {
00225         return (dataStatus >= DATA_WRITE);
00226     }
00227 
00231     bool isDataValid() const
00232     {
00233         return (dataStatus >= DATA_CLEAN) && (dataStatus <= DATA_WRITE);
00234     }
00235 
00239     bool isDataError() const
00240     {
00241         return (dataStatus == DATA_ERROR);
00242     }
00243 
00247     BlockId getBlockId() const
00248     {
00249         return blockId;
00250     }
00251 
00260     PConstBuffer getReadableData() const
00261     {
00262         assert(isDataValid());
00263         assert(lock.isLocked(LOCKMODE_S) || isExclusiveLockHeld());
00264         return pBuffer;
00265     }
00266 
00274     PBuffer getWritableData()
00275     {
00276         assert(isExclusiveLockHeld());
00277         assert(!isDataError());
00278         assert(!isTransferInProgress());
00279         // REVIEW:  is thread-safety ever an issue here?  If so, it's also an
00280         // issue for the previous assertions.
00281         if (!isDirty()) {
00282             getCache().markPageDirty(*this);
00283         }
00284         return pBuffer;
00285     }
00286 
00290     bool isScratchLocked() const;
00291 
00295     MappedPageListener *getMappedPageListener() const
00296     {
00297         assert(hasBlockId());
00298         return pMappedPageListener;
00299     }
00300 
00309     bool tryUpgrade(TxnId txnId)
00310     {
00311         StrictMutexGuard pageGuard(mutex);
00312         if (isTransferInProgress()) {
00313             return false;
00314         }
00315 #ifdef DEBUG
00316         int errorCode;
00317         if (getCache().getAllocator().setProtection(
00318                 pBuffer, getCache().getPageSize(), false, &errorCode))
00319         {
00320             throw SysCallExcn("memory protection failed", errorCode);
00321         }
00322 #endif
00323         return lock.tryUpgrade(txnId);
00324     }
00325 
00332     void upgrade(TxnId txnId)
00333     {
00334         StrictMutexGuard pageGuard(mutex);
00335         while (isTransferInProgress()) {
00336             waitForPendingIO(pageGuard);
00337         }
00338 #ifdef DEBUG
00339         int errorCode;
00340         if (getCache().getAllocator().setProtection(
00341                 pBuffer, getCache().getPageSize(), false, &errorCode))
00342         {
00343             throw SysCallExcn("memory protection failed", errorCode);
00344         }
00345 #endif
00346         bool rc = lock.tryUpgrade(txnId);
00347         assert(rc);
00348     }
00349 
00356     void swapBuffers(CachePage &other);
00357 };
00358 
00359 FENNEL_END_NAMESPACE
00360 
00361 #endif
00362 
00363 // End CachePage.h

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