aboutsummaryrefslogtreecommitdiff
path: root/src/experimental/cache.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/experimental/cache.h')
-rw-r--r--src/experimental/cache.h828
1 files changed, 414 insertions, 414 deletions
diff --git a/src/experimental/cache.h b/src/experimental/cache.h
index e3c8483..795d180 100644
--- a/src/experimental/cache.h
+++ b/src/experimental/cache.h
@@ -18,420 +18,420 @@
18 18
19namespace Bu 19namespace Bu
20{ 20{
21// template<class keytype, class obtype> 21// template<class keytype, class obtype>
22// keytype __cacheGetKey( obtype *&pObj ); 22// keytype __cacheGetKey( obtype *&pObj );
23 template<class keytype, class obtype> 23 template<class keytype, class obtype>
24 keytype __cacheGetKey( const obtype *pObj ) 24 keytype __cacheGetKey( const obtype *pObj )
25 { 25 {
26 return pObj->getKey(); 26 return pObj->getKey();
27 } 27 }
28 28
29 template<class keytype, class obtype> 29 template<class keytype, class obtype>
30 class Cache 30 class Cache
31 { 31 {
32 public: 32 public:
33 /** 33 /**
34 * Cache Pointer - Provides access to data that is held within the 34 * Cache Pointer - Provides access to data that is held within the
35 * cache. This provides safe, refcounting access to data stored in 35 * cache. This provides safe, refcounting access to data stored in
36 * the cache, with support for lazy loading. 36 * the cache, with support for lazy loading.
37 */ 37 */
38 class Ptr 38 class Ptr
39 { 39 {
40 friend class Bu::Cache<keytype, obtype>; 40 friend class Bu::Cache<keytype, obtype>;
41 private: 41 private:
42 Ptr( Cache<keytype, obtype> *pCache, obtype *pData, 42 Ptr( Cache<keytype, obtype> *pCache, obtype *pData,
43 const keytype &kId ) : 43 const keytype &kId ) :
44 pCache( pCache ), 44 pCache( pCache ),
45 pData( pData ), 45 pData( pData ),
46 kId( kId ) 46 kId( kId )
47 { 47 {
48 if( pCache ) 48 if( pCache )
49 pCache->incRef( kId ); 49 pCache->incRef( kId );
50 } 50 }
51 51
52 Ptr( Cache<keytype, obtype> *pCache, const keytype &kId ) : 52 Ptr( Cache<keytype, obtype> *pCache, const keytype &kId ) :
53 pCache( pCache ), 53 pCache( pCache ),
54 pData( NULL ), 54 pData( NULL ),
55 kId( kId ) 55 kId( kId )
56 { 56 {
57 } 57 }
58 58
59 public: 59 public:
60 Ptr( const Ptr &rSrc ) : 60 Ptr( const Ptr &rSrc ) :
61 pCache( rSrc.pCache ), 61 pCache( rSrc.pCache ),
62 pData( rSrc.pData ), 62 pData( rSrc.pData ),
63 kId( rSrc.kId ) 63 kId( rSrc.kId )
64 { 64 {
65 if( pCache && pData ) 65 if( pCache && pData )
66 pCache->incRef( kId ); 66 pCache->incRef( kId );
67 } 67 }
68 68
69 Ptr() : 69 Ptr() :
70 pCache( 0 ), 70 pCache( 0 ),
71 pData( 0 ) 71 pData( 0 )
72 { 72 {
73 } 73 }
74 74
75 virtual ~Ptr() 75 virtual ~Ptr()
76 { 76 {
77 if( pCache && pData ) 77 if( pCache && pData )
78 pCache->decRef( kId ); 78 pCache->decRef( kId );
79 } 79 }
80 80
81 obtype &operator*() 81 obtype &operator*()
82 { 82 {
83 checkPtr(); 83 checkPtr();
84 return *pData; 84 return *pData;
85 } 85 }
86 86
87 const obtype &operator*() const 87 const obtype &operator*() const
88 { 88 {
89 checkPtr(); 89 checkPtr();
90 return *pData; 90 return *pData;
91 } 91 }
92 92
93 obtype *operator->() 93 obtype *operator->()
94 { 94 {
95 checkPtr(); 95 checkPtr();
96 return pData; 96 return pData;
97 } 97 }
98 98
99 const obtype *operator->() const 99 const obtype *operator->() const
100 { 100 {
101 checkPtr(); 101 checkPtr();
102 return pData; 102 return pData;
103 } 103 }
104 104
105 bool isValid() const 105 bool isValid() const
106 { 106 {
107 return pCache != NULL; 107 return pCache != NULL;
108 } 108 }
109 109
110 bool isBound() const 110 bool isBound() const
111 { 111 {
112 return pData != NULL; 112 return pData != NULL;
113 } 113 }
114 114
115 bool isSet() const 115 bool isSet() const
116 { 116 {
117 return pCache != NULL; 117 return pCache != NULL;
118 } 118 }
119 119
120 const keytype &getKey() const 120 const keytype &getKey() const
121 { 121 {
122 return kId; 122 return kId;
123 } 123 }
124 124
125 void unbind() 125 void unbind()
126 { 126 {
127 if( pCache && pData ) 127 if( pCache && pData )
128 pCache->decRef( kId ); 128 pCache->decRef( kId );
129 pData = NULL; 129 pData = NULL;
130 } 130 }
131 131
132 void clear() 132 void clear()
133 { 133 {
134 unbind(); 134 unbind();
135 pCache = NULL; 135 pCache = NULL;
136 } 136 }
137 137
138 void unset() 138 void unset()
139 { 139 {
140 clear(); 140 clear();
141 } 141 }
142 142
143 Ptr &operator=( const Ptr &rRhs ) 143 Ptr &operator=( const Ptr &rRhs )
144 { 144 {
145 if( pCache && pData ) 145 if( pCache && pData )
146 pCache->decRef( kId ); 146 pCache->decRef( kId );
147 pCache = rRhs.pCache; 147 pCache = rRhs.pCache;
148 pData = rRhs.pData; 148 pData = rRhs.pData;
149 kId = rRhs.kId; 149 kId = rRhs.kId;
150 if( pCache && pData ) 150 if( pCache && pData )
151 pCache->incRef( kId ); 151 pCache->incRef( kId );
152 return *this; 152 return *this;
153 } 153 }
154 154
155 bool operator==( const Ptr &rRhs ) const 155 bool operator==( const Ptr &rRhs ) const
156 { 156 {
157 return pCache == rRhs.pCache && kId == rRhs.kId; 157 return pCache == rRhs.pCache && kId == rRhs.kId;
158 } 158 }
159 159
160 bool operator!=( const Ptr &rRhs ) const 160 bool operator!=( const Ptr &rRhs ) const
161 { 161 {
162 return pCache != rRhs.pCache || kId != rRhs.kId; 162 return pCache != rRhs.pCache || kId != rRhs.kId;
163 } 163 }
164 164
165 private: 165 private:
166 void checkPtr() const 166 void checkPtr() const
167 { 167 {
168 if( pCache && !pData ) 168 if( pCache && !pData )
169 { 169 {
170 pData = pCache->getRaw( kId ); 170 pData = pCache->getRaw( kId );
171 pCache->incRef( kId ); 171 pCache->incRef( kId );
172 } 172 }
173 } 173 }
174 174
175 private: 175 private:
176 Bu::Cache<keytype, obtype> *pCache; 176 Bu::Cache<keytype, obtype> *pCache;
177 mutable obtype *pData; 177 mutable obtype *pData;
178 mutable keytype kId; 178 mutable keytype kId;
179 }; 179 };
180 180
181 private: 181 private:
182 typedef Bu::CacheStore<keytype, obtype> Store; 182 typedef Bu::CacheStore<keytype, obtype> Store;
183 typedef Bu::List<Store *> StoreList; 183 typedef Bu::List<Store *> StoreList;
184 typedef Bu::CacheCalc<keytype, obtype> Calc; 184 typedef Bu::CacheCalc<keytype, obtype> Calc;
185 185
186 typedef struct CacheEntry 186 typedef struct CacheEntry
187 { 187 {
188 obtype *pData; 188 obtype *pData;
189 int iRefs; 189 int iRefs;
190 time_t tLastSync; 190 time_t tLastSync;
191 } CacheEntry; 191 } CacheEntry;
192 192
193 typedef Bu::Hash<keytype, CacheEntry> CidHash; 193 typedef Bu::Hash<keytype, CacheEntry> CidHash;
194 194
195 public: 195 public:
196 typedef keytype Key; 196 typedef keytype Key;
197 Cache( Calc *pCalc, Store *pStore ) : 197 Cache( Calc *pCalc, Store *pStore ) :
198 pCalc( pCalc ), 198 pCalc( pCalc ),
199 pStore( pStore ) 199 pStore( pStore )
200 { 200 {
201 TRACE(); 201 TRACE();
202 pCalc->setCache( this ); 202 pCalc->setCache( this );
203 } 203 }
204 204
205 virtual ~Cache() 205 virtual ~Cache()
206 { 206 {
207 TRACE(); 207 TRACE();
208 208
209 // Better safe than sorry, better try a sync before anything 209 // Better safe than sorry, better try a sync before anything
210 // else happens. 210 // else happens.
211 sync(); 211 sync();
212 212
213 // Cycle through and unload all objects from the system. 213 // Cycle through and unload all objects from the system.
214 for( typename CidHash::iterator i = hEnt.begin(); 214 for( typename CidHash::iterator i = hEnt.begin();
215 i != hEnt.end(); i++ ) 215 i != hEnt.end(); i++ )
216 { 216 {
217 if( i.getValue().iRefs > 0 ) 217 if( i.getValue().iRefs > 0 )
218 { 218 {
219 // TODO: Throw an error in this case? iRefs != 0 for an 219 // TODO: Throw an error in this case? iRefs != 0 for an
220 // object when the Cache is destroyed. 220 // object when the Cache is destroyed.
221 throw Bu::ExceptionBase("iRefs not zero."); 221 throw Bu::ExceptionBase("iRefs not zero.");
222 } 222 }
223 pStore->unload( 223 pStore->unload(
224 i.getValue().pData, 224 i.getValue().pData,
225 i.getKey() 225 i.getKey()
226 ); 226 );
227 } 227 }
228 delete pCalc; 228 delete pCalc;
229 delete pStore; 229 delete pStore;
230 } 230 }
231 231
232 Ptr insert( obtype *pData ) 232 Ptr insert( obtype *pData )
233 { 233 {
234 TRACE( pData ); 234 TRACE( pData );
235 if( pStore->has( __cacheGetKey<keytype, obtype>( pData ) ) ) 235 if( pStore->has( __cacheGetKey<keytype, obtype>( pData ) ) )
236 throw Bu::ExceptionBase("Key already exists in cache."); 236 throw Bu::ExceptionBase("Key already exists in cache.");
237 CacheEntry e = {pData, 0, 0}; 237 CacheEntry e = {pData, 0, 0};
238 keytype k = pStore->create( pData ); 238 keytype k = pStore->create( pData );
239 hEnt.insert( k, e ); 239 hEnt.insert( k, e );
240 240
241 pCalc->onLoad( pData, k ); 241 pCalc->onLoad( pData, k );
242 242
243 pStore->sync(); 243 pStore->sync();
244 244
245 return Ptr( this, pData, k ); 245 return Ptr( this, pData, k );
246 } 246 }
247 247
248 bool has( const keytype &cId ) 248 bool has( const keytype &cId )
249 { 249 {
250 return hEnt.has( cId ) || pStore->has( cId ); 250 return hEnt.has( cId ) || pStore->has( cId );
251 } 251 }
252 252
253 /** 253 /**
254 * Retrieve an object from the cache and return a pointer to it. 254 * Retrieve an object from the cache and return a pointer to it.
255 * The object returned may be loaded from backend storage if needed, 255 * The object returned may be loaded from backend storage if needed,
256 * or the currently live object will be returned. 256 * or the currently live object will be returned.
257 *@param cId The id of the object to load. 257 *@param cId The id of the object to load.
258 *@returns A pointer to the object. 258 *@returns A pointer to the object.
259 */ 259 */
260 Ptr get( const keytype &cId ) 260 Ptr get( const keytype &cId )
261 { 261 {
262 TRACE( cId ); 262 TRACE( cId );
263 try { 263 try {
264 return Ptr( this, hEnt.get( cId ).pData, cId ); 264 return Ptr( this, hEnt.get( cId ).pData, cId );
265 } 265 }
266 catch( Bu::HashException &e ) { 266 catch( Bu::HashException &e ) {
267 CacheEntry e = {pStore->load( cId ), 0, time( NULL )}; 267 CacheEntry e = {pStore->load( cId ), 0, time( NULL )};
268 pCalc->onLoad( e.pData, cId ); 268 pCalc->onLoad( e.pData, cId );
269 hEnt.insert( cId, e ); 269 hEnt.insert( cId, e );
270 return Ptr( this, e.pData, cId ); 270 return Ptr( this, e.pData, cId );
271 } 271 }
272 } 272 }
273 273
274 /** 274 /**
275 * Retrieve a handle to an object without loading it now. This function 275 * Retrieve a handle to an object without loading it now. This function
276 * will return a pointer that has not yet been "realized" but can be 276 * will return a pointer that has not yet been "realized" but can be
277 * used normally. Upon initial use in any way the object will be 277 * used normally. Upon initial use in any way the object will be
278 * loaded from the cache, either linking against the already loaded 278 * loaded from the cache, either linking against the already loaded
279 * object or loading it fresh from the backend storage. The advantage 279 * object or loading it fresh from the backend storage. The advantage
280 * of this is that you recieve a usable handle to the data, but it 280 * of this is that you recieve a usable handle to the data, but it
281 * does not count as a reference yet, meaning that the data is loaded 281 * does not count as a reference yet, meaning that the data is loaded
282 * when you need it, not before. 282 * when you need it, not before.
283 */ 283 */
284 Ptr getLazy( const keytype &cId ) 284 Ptr getLazy( const keytype &cId )
285 { 285 {
286 TRACE( cId ); 286 TRACE( cId );
287 return Ptr( this, cId ); 287 return Ptr( this, cId );
288 } 288 }
289 289
290 int getRefCount( const keytype &cId ) 290 int getRefCount( const keytype &cId )
291 { 291 {
292 TRACE( cId ); 292 TRACE( cId );
293 return hEnt.get( cId ).iRefs; 293 return hEnt.get( cId ).iRefs;
294 } 294 }
295 295
296 void unload( const keytype &cId ) 296 void unload( const keytype &cId )
297 { 297 {
298 TRACE( cId ); 298 TRACE( cId );
299 try { 299 try {
300 if( hEnt.get( cId ).iRefs > 0 ) 300 if( hEnt.get( cId ).iRefs > 0 )
301 { 301 {
302 printf("Shouldn't unload, references still exist!\n"); 302 printf("Shouldn't unload, references still exist!\n");
303 return; 303 return;
304 } 304 }
305 } 305 }
306 catch( Bu::HashException &e ) { 306 catch( Bu::HashException &e ) {
307 // It's not here? Eh, return. 307 // It's not here? Eh, return.
308 return; 308 return;
309 } 309 }
310 obtype *pObj = hEnt.get( cId ).pData; 310 obtype *pObj = hEnt.get( cId ).pData;
311 pCalc->onUnload( pObj, cId ); 311 pCalc->onUnload( pObj, cId );
312 hEnt.erase( cId ); 312 hEnt.erase( cId );
313 313
314 // The unload has to happen last just in case cId is a reference 314 // The unload has to happen last just in case cId is a reference
315 // to data that is about to be deleted from memory by the unload. 315 // to data that is about to be deleted from memory by the unload.
316 pStore->unload( pObj, cId ); 316 pStore->unload( pObj, cId );
317 } 317 }
318 318
319 void erase( const keytype &cId ) 319 void erase( const keytype &cId )
320 { 320 {
321 TRACE( cId ); 321 TRACE( cId );
322 try { 322 try {
323 if( hEnt.get( cId ).iRefs > 0 ) 323 if( hEnt.get( cId ).iRefs > 0 )
324 { 324 {
325 printf("Shouldn't erase, references still exist!\n"); 325 printf("Shouldn't erase, references still exist!\n");
326 return; 326 return;
327 } 327 }
328 328
329 obtype *pObj = hEnt.get( cId ).pData; 329 obtype *pObj = hEnt.get( cId ).pData;
330 pCalc->onDestroy( pObj, cId ); 330 pCalc->onDestroy( pObj, cId );
331 hEnt.erase( cId ); 331 hEnt.erase( cId );
332 332
333 pStore->destroy( pObj, cId ); 333 pStore->destroy( pObj, cId );
334 pStore->sync(); 334 pStore->sync();
335 } 335 }
336 catch( Bu::HashException &e ) { 336 catch( Bu::HashException &e ) {
337 pCalc->onDestroy( cId ); 337 pCalc->onDestroy( cId );
338 338
339 if( hEnt.has( cId ) ) 339 if( hEnt.has( cId ) )
340 { 340 {
341 // The object was loaded by onDestroy 341 // The object was loaded by onDestroy
342 erase( cId ); 342 erase( cId );
343 } 343 }
344 else 344 else
345 { 345 {
346 pStore->destroy( cId ); 346 pStore->destroy( cId );
347 pStore->sync(); 347 pStore->sync();
348 } 348 }
349 } 349 }
350 } 350 }
351 351
352 typedef Bu::List<keytype> KeyList; 352 typedef Bu::List<keytype> KeyList;
353 KeyList getKeys() 353 KeyList getKeys()
354 { 354 {
355 return pStore->getKeys(); 355 return pStore->getKeys();
356 } 356 }
357 357
358 KeyList getActiveKeys() 358 KeyList getActiveKeys()
359 { 359 {
360 return hEnt.getKeys(); 360 return hEnt.getKeys();
361 } 361 }
362 362
363 int getSize() 363 int getSize()
364 { 364 {
365 return pStore->getSize(); 365 return pStore->getSize();
366 } 366 }
367 367
368 /** 368 /**
369 * Make sure all currently loaded but not-in-use objects are synced to 369 * Make sure all currently loaded but not-in-use objects are synced to
370 * the store. 370 * the store.
371 */ 371 */
372 void sync() 372 void sync()
373 { 373 {
374 TRACE(); 374 TRACE();
375 int iSynced = 0; 375 int iSynced = 0;
376 for( typename CidHash::iterator i = hEnt.begin(); 376 for( typename CidHash::iterator i = hEnt.begin();
377 i != hEnt.end(); i++ ) 377 i != hEnt.end(); i++ )
378 { 378 {
379 if( i.getValue().iRefs == 0 ) 379 if( i.getValue().iRefs == 0 )
380 { 380 {
381 if( pCalc->shouldSync( 381 if( pCalc->shouldSync(
382 i.getValue().pData, 382 i.getValue().pData,
383 i.getKey(), 383 i.getKey(),
384 i.getValue().tLastSync 384 i.getValue().tLastSync
385 ) ) 385 ) )
386 { 386 {
387 pStore->sync( 387 pStore->sync(
388 i.getValue().pData, 388 i.getValue().pData,
389 i.getKey() 389 i.getKey()
390 ); 390 );
391 iSynced++; 391 iSynced++;
392 i.getValue().tLastSync = time( NULL ); 392 i.getValue().tLastSync = time( NULL );
393 } 393 }
394 } 394 }
395 } 395 }
396 if( iSynced > 0 ) 396 if( iSynced > 0 )
397 { 397 {
398 pStore->sync(); 398 pStore->sync();
399 } 399 }
400 } 400 }
401 401
402 private: 402 private:
403 void incRef( const keytype &cId ) 403 void incRef( const keytype &cId )
404 { 404 {
405 TRACE( cId ); 405 TRACE( cId );
406 hEnt.get( cId ).iRefs++; 406 hEnt.get( cId ).iRefs++;
407 } 407 }
408 408
409 void decRef( const keytype &cId ) 409 void decRef( const keytype &cId )
410 { 410 {
411 TRACE( cId ); 411 TRACE( cId );
412 CacheEntry &e = hEnt.get( cId ); 412 CacheEntry &e = hEnt.get( cId );
413 e.iRefs--; 413 e.iRefs--;
414 } 414 }
415 415
416 obtype *getRaw( const keytype &cId ) 416 obtype *getRaw( const keytype &cId )
417 { 417 {
418 TRACE( cId ); 418 TRACE( cId );
419 try { 419 try {
420 return hEnt.get( cId ).pData; 420 return hEnt.get( cId ).pData;
421 } 421 }
422 catch( Bu::HashException &e ) { 422 catch( Bu::HashException &e ) {
423 CacheEntry e = {pStore->load( cId ), 0, time( NULL )}; 423 CacheEntry e = {pStore->load( cId ), 0, time( NULL )};
424 pCalc->onLoad( e.pData, cId ); 424 pCalc->onLoad( e.pData, cId );
425 hEnt.insert( cId, e ); 425 hEnt.insert( cId, e );
426 return e.pData; 426 return e.pData;
427 } 427 }
428 } 428 }
429 429
430 private: 430 private:
431 CidHash hEnt; 431 CidHash hEnt;
432 Calc *pCalc; 432 Calc *pCalc;
433 Store *pStore; 433 Store *pStore;
434 }; 434 };
435}; 435};
436 436
437#endif 437#endif