00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00104
00108 Cache &cache;
00109
00114 StrictMutex mutex;
00115
00120 SXMutex lock;
00121
00125 PBuffer pBuffer;
00126
00127
00128
00129
00130
00135 BlockId blockId;
00136
00143 uint nReferences;
00144
00149 LocalCondition ioCompletionCondition;
00150
00155 MappedPageListener *pMappedPageListener;
00156
00160 DataStatus dataStatus;
00161
00162
00163
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
00189 return isScratchLocked() || lock.isLocked(LOCKMODE_X);
00190 }
00191
00192
00193
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
00280
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