00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __UT_ThreadSafeCache__
00021 #define __UT_ThreadSafeCache__
00022
00023 #include "UT_API.h"
00024 #include <SYS/SYS_Types.h>
00025 #include <SYS/SYS_AtomicInt.h>
00026 #include <SYS/SYS_AtomicIntImpl.h>
00027 #include "UT_LockUtil.h"
00028
00029
00030
00031
00032 template <class Lock>
00033 class UT_API UT_ThreadSafeCache {
00034 public:
00035
00036
00037 class UT_CacheItem
00038 {
00039 public:
00040 UT_CacheItem()
00041 : myPrev(0), myNext(0), myMemory(0)
00042 , myRefCount(0), myTimeStamp(0)
00043 , myAllocated(false) {}
00044 virtual ~UT_CacheItem() {}
00045
00046 protected:
00047
00048
00049 virtual int64 allocate(void *parms) = 0;
00050
00051
00052 virtual void deallocate(void *user_data) = 0;
00053
00054
00055 int64 getMemoryUsage() const { return myMemory; }
00056
00057 private:
00058 int getRefCount() const { return myRefCount; }
00059 void incRefCount() { myRefCount.add(1); }
00060 void decRefCount() { myRefCount.add(-1); }
00061
00062 bool isInCache() const { return myNext; }
00063
00064 private:
00065 UT_CacheItem *myPrev;
00066 UT_CacheItem *myNext;
00067 int64 myMemory;
00068 uint64 myTimeStamp;
00069 SYS_AtomicInt32 myRefCount;
00070 bool myAllocated;
00071
00072 friend class UT_ThreadSafeCache;
00073 friend class UT_ThreadSafeCache::unsafe_traverser;
00074 friend class UT_LimitedCache;
00075 };
00076
00077 public:
00078
00079
00080 UT_ThreadSafeCache(bool destroy = true);
00081 ~UT_ThreadSafeCache();
00082
00083
00084 void setMaxMemory(int64 size_mb, bool prune = false);
00085
00086 void setMaxMemoryBytes(int64 size_bytes, bool prune = false);
00087 int64 getMaxMemoryBytes() const
00088 { return myMemoryLimit; }
00089
00090
00091
00092 int64 getMemoryUsage() const { return myMemoryUsed; }
00093
00094
00095 int64 entries() const { return myEntries; }
00096
00097
00098 void setUserData(void *data) { myUserData = data; }
00099
00100
00101
00102 void setCheckMemoryLimit(bool check)
00103 { myCheckMemoryLimit = check; }
00104 bool getCheckMemoryLimit() const
00105 { return myCheckMemoryLimit; }
00106
00107
00108
00109
00110
00111
00112 void access(UT_CacheItem *item, void *parms = 0)
00113 {
00114 item->incRefCount();
00115
00116 accessUnreferenced(item, parms);
00117 }
00118
00119 void accessUnreferenced(UT_CacheItem *item, void *parms = 0)
00120 {
00121
00122
00123
00124
00125
00126
00127 if (item->myAllocated && isNearHead(item))
00128 {
00129 return;
00130 }
00131
00132
00133 accessLockedReorder(item, parms);
00134 }
00135
00136
00137 void release(UT_CacheItem *item);
00138
00139
00140 void freeItem(UT_CacheItem *item);
00141
00142
00143 void freeAllItems();
00144
00145
00146 void pruneItems(int64 memory_limit);
00147
00148 class UT_API unsafe_traverser
00149 {
00150 public:
00151 unsafe_traverser()
00152 : myCurr(NULL) {}
00153 unsafe_traverser(const unsafe_traverser &src)
00154 : myCurr(src.myCurr) {}
00155 ~unsafe_traverser() {}
00156
00157 const UT_CacheItem *get() const { return myCurr; }
00158 int operator==(const unsafe_traverser &cmp) const
00159 { return myCurr == cmp.myCurr; }
00160 int operator!=(const unsafe_traverser &cmp) const
00161 { return myCurr != cmp.myCurr; }
00162 bool atEnd() const
00163 { return !myCurr; }
00164 unsafe_traverser &operator++()
00165 {
00166 if (myCurr)
00167 myCurr = myCurr->myNext;
00168 return *this;
00169 }
00170 const unsafe_traverser &operator=(const unsafe_traverser &src)
00171 {
00172 myCurr = src.myCurr;
00173 return *this;
00174 }
00175 private:
00176 unsafe_traverser(UT_CacheItem *head)
00177 : myCurr(head) {}
00178 const UT_CacheItem *myCurr;
00179 friend class UT_ThreadSafeCache;
00180 };
00181
00182 unsafe_traverser unsafe_begin() const
00183 { return unsafe_traverser(myHead); }
00184 unsafe_traverser unsafe_end() const
00185 { return unsafe_traverser(); }
00186
00187
00188 int64 getFaults() const { return myFaults; }
00189
00190 private:
00191
00192 void accessLockedReorder(UT_CacheItem *item, void *parms);
00193
00194 void pruneItemsNoLock(int64 memory_limit);
00195 void addToCache(UT_CacheItem *item);
00196 void removeFromCache(UT_CacheItem *item);
00197 void allocateItem(UT_CacheItem *item, void *parms)
00198 {
00199 if (!item->myAllocated)
00200 {
00201 int handle = myObjLock.lock(item);
00202 if (!item->myAllocated)
00203 {
00204 item->myMemory = item->allocate(
00205 parms ? parms : myUserData);
00206 item->myAllocated = true;
00207 }
00208 myObjLock.unlock(item, handle);
00209 }
00210 }
00211
00212
00213
00214 bool isNearHead(const UT_CacheItem *item) const
00215 { return myHeadTime - item->myTimeStamp <=
00216 myQuarterEntries; }
00217
00218 private:
00219 UT_ObjLockType<Lock> myObjLock;
00220 Lock myThreadLock;
00221 UT_CacheItem *myHead;
00222 int64 myMemoryLimit;
00223 int64 myMemoryUsed;
00224 int64 myEntries;
00225 int64 myQuarterEntries;
00226 int64 myFaults;
00227 uint64 myHeadTime;
00228 void *myUserData;
00229 bool myDestroy;
00230 bool myCheckMemoryLimit;
00231 friend class UT_LimitedCache;
00232 };
00233
00234 #endif