aboutsummaryrefslogtreecommitdiff
path: root/src/tests/cache.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/cache.cpp')
-rw-r--r--src/tests/cache.cpp419
1 files changed, 335 insertions, 84 deletions
diff --git a/src/tests/cache.cpp b/src/tests/cache.cpp
index 6fc4e4a..15662af 100644
--- a/src/tests/cache.cpp
+++ b/src/tests/cache.cpp
@@ -55,22 +55,148 @@ private:
55 bool bChanged; 55 bool bChanged;
56}; 56};
57 57
58template<typename keytype, typename obtype>
59class CacheBase;
60
61template<typename keytype, typename obtype>
62class CacheEntry
63{
64friend class CacheBase<keytype, obtype>;
65private:
66 CacheEntry( obtype *pObject ) :
67 iRefCount( 0 ),
68 pObject( pObject )
69 {
70 }
71
72public:
73 int getRefCount() const
74 {
75 mEntry.lock();
76 int ret = iRefCount;
77 mEntry.unlock();
78 return ret;
79 }
80
81 obtype *getPtr() const
82 {
83 return pObject;
84 }
85
86 void lock() const
87 {
88 mObject.lock();
89 }
90
91 void unlock() const
92 {
93 mObject.unlock();
94 }
95
96 void incRef()
97 {
98 mEntry.lock();
99 iRefCount++;
100 mEntry.unlock();
101 }
102
103 bool decRef()
104 {
105 mEntry.lock();
106 iRefCount--;
107 bool bRet = iRefCount > 0;
108 mEntry.unlock();
109 return bRet;
110 }
111
112private:
113 mutable Bu::Mutex mEntry;
114 mutable Bu::Mutex mObject;
115 int iRefCount;
116 obtype *pObject;
117};
118
119template<typename keytype, typename basetype>
120class CachePtrInterface
121{
122protected:
123 CachePtrInterface()
124 {
125 }
126
127 virtual ~CachePtrInterface()
128 {
129 }
130
131 template<typename obtype>
132 void checkRef( CacheBase<keytype, basetype> *pCache,
133 const keytype &kId,
134 CacheEntry<keytype, basetype> * &rpEnt,
135 obtype * &rpData )
136 {
137 if( pCache == NULL )
138 throw Bu::ExceptionBase("Invalid pointer");
139
140 if( !rpData )
141 {
142 rpEnt = pCache->getRef( kId );
143 rpEnt->incRef();
144 rpData = dynamic_cast<obtype *>(rpEnt->getPtr());
145 if( rpData == NULL )
146 {
147 rpEnt->decRef();
148 rpEnt = NULL;
149 throw std::bad_cast();
150 }
151 }
152 }
153
154 template<typename obtype>
155 void releaseRef( CacheBase<keytype, basetype> *pCache,
156 CacheEntry<keytype, basetype> * &rpEnt,
157 obtype * &rpData )
158 {
159 if( pCache == NULL )
160 return;
161
162 if( rpData == NULL )
163 return;
164
165 rpData = NULL;
166 rpEnt->decRef();
167 pCache->releaseRef( rpEnt );
168 rpEnt = NULL;
169 }
170};
171
58template<typename keytype, typename obtype, typename basetype=obtype> 172template<typename keytype, typename obtype, typename basetype=obtype>
59class CachePtr 173class CachePtr : protected CachePtrInterface<keytype, basetype>
60{ 174{
61friend class CacheBase<keytype, basetype>; 175friend class CacheBase<keytype, basetype>;
62private: 176private:
63 CachePtr( CacheBase<keytype, basetype> *pCache, obtype *pData, 177 typedef CachePtr<keytype, obtype, basetype> MyType;
178
179 CachePtr( CacheBase<keytype, basetype> *pCache,
180 CacheEntry<keytype, basetype> *pEnt,
64 const keytype &kId ) : 181 const keytype &kId ) :
65 pCache( pCache ), 182 pCache( pCache ),
66 kId( kId ), 183 kId( kId ),
67 pData( pData ) 184 pEnt( pEnt ),
185 pData( NULL )
68 { 186 {
187 pEnt->incRef();
188 pData = dynamic_cast<obtype *>( pEnt->getPtr() );
189 if( pData == NULL )
190 {
191 pEnt->decRef();
192 throw std::bad_cast();
193 }
69 } 194 }
70 195
71 CachePtr( CacheBase<keytype, basetype> *pCache, const keytype &kId ) : 196 CachePtr( CacheBase<keytype, basetype> *pCache, const keytype &kId ) :
72 pCache( pCache ), 197 pCache( pCache ),
73 kId( kId ), 198 kId( kId ),
199 pEnt( NULL ),
74 pData( NULL ) 200 pData( NULL )
75 { 201 {
76 } 202 }
@@ -78,12 +204,23 @@ private:
78public: 204public:
79 CachePtr() : 205 CachePtr() :
80 pCache( NULL ), 206 pCache( NULL ),
207 pEnt( NULL ),
81 pData( NULL ) 208 pData( NULL )
82 { 209 {
83 } 210 }
84 211
212 CachePtr( const MyType &rhs ) :
213 pCache( rhs.pCache ),
214 kId( rhs.kId ),
215 pEnt( rhs.pEnt ),
216 pData( rhs.pData )
217 {
218 pEnt->incRef();
219 }
220
85 virtual ~CachePtr() 221 virtual ~CachePtr()
86 { 222 {
223 release();
87 } 224 }
88 225
89 const keytype &getKey() const 226 const keytype &getKey() const
@@ -96,34 +233,113 @@ public:
96 checkRef(); 233 checkRef();
97 return pData; 234 return pData;
98 } 235 }
236
237 const obtype &operator*() const
238 {
239 checkRef();
240 return pData;
241 }
99 242
100 obtype *operator->() 243 obtype *operator->()
101 { 244 {
102 checkRef(); 245 checkRef();
103 return pData; 246 return pData;
104 } 247 }
248
249 const obtype *operator->() const
250 {
251 checkRef();
252 return pData;
253 }
254
255 MyType operator=( const MyType &rhs )
256 {
257 release();
258 pCache = rhs.pCache;
259 kId = rhs.kId;
260 pEnt = rhs.pEnt;
261 pData = rhs.pData;
262 pEnt->incRef();
263
264 return *this;
265 }
266
267 bool operator==( const MyType &rhs ) const
268 {
269 return pCache == rhs.pCache &&
270 kId == rhs.kId;
271 }
272
273 bool operator!=( const MyType &rhs ) const
274 {
275 return pCache != rhs.pCache ||
276 kId != rhs.kId;
277 }
278
279 void release()
280 {
281 CachePtrInterface<keytype, basetype>::releaseRef( pCache, pEnt, pData );
282 }
283
284 void lock()
285 {
286 checkRef();
287 if( pEnt )
288 pEnt->lock();
289 }
290
291 void unlock()
292 {
293 checkRef();
294 if( pEnt )
295 pEnt->unlock();
296 }
297
298 class Locker
299 {
300 public:
301 Locker( MyType &rPtr ) :
302 rPtr( rPtr ),
303 bLocked( true )
304 {
305 rPtr.lock();
306 }
307
308 ~Locker()
309 {
310 unlock();
311 }
312
313 void unlock()
314 {
315 if( !bLocked )
316 return;
317 rPtr.unlock();
318 bLocked = false;
319 }
320
321 private:
322 MyType &rPtr;
323 bool bLocked;
324 };
105 325
106private: 326private:
107 void checkRef() 327 void checkRef()
108 { 328 {
109 if( pCache == NULL ) 329 CachePtrInterface<keytype, basetype>::checkRef( pCache, kId, pEnt, pData );
110 throw Bu::ExceptionBase("Invalid pointer");
111
112 if( !pData )
113 pData = pCache->getRef( kId );
114 } 330 }
115 331
116private: 332private:
117 CacheBase<keytype, basetype> *pCache; 333 CacheBase<keytype, basetype> *pCache;
118 mutable keytype kId; 334 mutable keytype kId;
335 mutable CacheEntry<keytype, basetype> *pEnt;
119 mutable obtype *pData; 336 mutable obtype *pData;
120
121}; 337};
122 338
123template<typename keytype, typename obtype> 339template<typename keytype, typename obtype>
124class CacheBase 340class CacheBase
125{ 341{
126friend class CachePtr<keytype, obtype>; 342friend class CachePtrInterface<keytype, obtype>;
127public: 343public:
128 CacheBase() 344 CacheBase()
129 { 345 {
@@ -133,14 +349,17 @@ public:
133 { 349 {
134 } 350 }
135 351
352 typedef CacheEntry<keytype, obtype> Entry;
136 typedef Bu::List<keytype> KeyList; 353 typedef Bu::List<keytype> KeyList;
137 354
355
138 CachePtr<keytype, obtype> insert( const obtype *pObject ) 356 CachePtr<keytype, obtype> insert( const obtype *pObject )
139 { 357 {
140 CacheEntry *pEnt = addEntry( pObject ); 358 Entry *pEnt = addEntry( pObject );
141 359
142 pEnt->incRef(); 360 return CachePtr<keytype, obtype>(
143 return CachePtr<keytype, obtype>( this, pEnt->getPtr(), pObject->getKey() ); 361 this, pEnt, pObject->getKey()
362 );
144 } 363 }
145 364
146 template<typename supertype> 365 template<typename supertype>
@@ -150,84 +369,68 @@ public:
150 if( pCast == NULL ) 369 if( pCast == NULL )
151 throw std::bad_cast(); 370 throw std::bad_cast();
152 371
153 CacheEntry *pEnt = addEntry( pCast ); 372 Entry *pEnt = addEntry( pCast );
154 373
155 pEnt->incRef(); 374 return CachePtr<keytype, supertype, obtype>(
156 return CachePtr<keytype, supertype, obtype>( this, pObject, pObject->getKey() ); 375 this, pEnt, pObject->getKey()
376 );
157 } 377 }
158 378
159 CachePtr<keytype, obtype> get( const keytype &key ) 379 CachePtr<keytype, obtype> get( const keytype &key )
160 { 380 {
161 CacheEntry *pEnt = getEntry( key ); 381 Entry *pEnt = getEntry( key );
162 pEnt->incRef(); 382 return CachePtr<keytype, obtype>( this, pEnt, key );
163 return CachePtr<keytype, obtype>( this, pEnt->getPtr(), key );
164 } 383 }
165 384
166 template<typename supertype> 385 template<typename supertype>
167 CachePtr<keytype, supertype, obtype> get( const keytype &key ) 386 CachePtr<keytype, supertype, obtype> get( const keytype &key )
168 { 387 {
169 CacheEntry *pEnt = getEntry( key ); 388 Entry *pEnt = getEntry( key );
170 pEnt->incRef(); 389 return CachePtr<keytype, supertype, obtype>( this, pEnt, key );
171 supertype *pCast = dynamic_cast<supertype *>( pEnt->getPtr() );
172 if( pCast == NULL )
173 {
174 pEnt->decRef();
175 throw std::bad_cast();
176 }
177 return CachePtr<keytype, supertype, obtype>( this, pCast, key );
178 } 390 }
179 391
180 virtual KeyList getKeys() const=0; 392 CachePtr<keytype, obtype> getLazy( const keytype &key )
181
182 virtual void sync()=0;
183
184protected:
185 obtype *getRef( const keytype &k )
186 { 393 {
187 CacheEntry *pEnt = getEntry( k ); 394 return CachePtr<keytype, obtype>( this, key );
188 pEnt->incRef();
189 return pEnt->getPtr();
190 } 395 }
191 396
192 void objectChanged( const keytype &k ) 397 template<typename supertype>
398 CachePtr<keytype, supertype, obtype> getLazy( const keytype &key )
193 { 399 {
400 return CachePtr<keytype, supertype, obtype>( this, key );
194 } 401 }
195 402
196 class CacheEntry 403 virtual KeyList getKeys() const=0;
404
405 virtual void sync()=0;
406
407 void _debug()
197 { 408 {
198 public: 409 Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry );
199 CacheEntry( obtype *pObject ) : 410 Bu::println("Cache entries:");
200 iRefCount( 0 ), 411 for( typename CacheEntryHash::iterator i = hCacheEntry.begin(); i; i++ )
201 pObject( pObject )
202 { 412 {
413 Bu::println(" %1: refs=%2").
414 arg( i.getKey() ).
415 arg( i.getValue()->getRefCount() );
203 } 416 }
417 }
204 418
205 void incRef() 419protected:
206 { 420 Entry *getRef( const keytype &k )
207 mEntry.lock(); 421 {
208 iRefCount++; 422 Entry *pEnt = getEntry( k );
209 mEntry.unlock(); 423 return pEnt;
210 } 424 }
211 425
212 bool decRef() 426 void releaseRef( Entry * )//pEnt )
213 { 427 {
214 mEntry.lock(); 428 }
215 iRefCount--;
216 bool bRet = iRefCount > 0;
217 mEntry.unlock();
218 return bRet;
219 }
220 429
221 obtype *getPtr() 430 void objectChanged( const keytype &k )
222 { 431 {
223 return pObject; 432 }
224 }
225 433
226 private:
227 Bu::Mutex mEntry;
228 int iRefCount;
229 obtype *pObject;
230 };
231 434
232protected: 435protected:
233 virtual void _create( const obtype *o )=0; 436 virtual void _create( const obtype *o )=0;
@@ -237,9 +440,9 @@ protected:
237 virtual void _save( const obtype *o )=0; 440 virtual void _save( const obtype *o )=0;
238 441
239private: 442private:
240 CacheEntry *addEntry( const obtype *pObject ) 443 Entry *addEntry( const obtype *pObject )
241 { 444 {
242 CacheEntry *pEnt = new CacheEntry( const_cast<obtype *>(pObject) ); 445 Entry *pEnt = new Entry( const_cast<obtype *>(pObject) );
243 mCacheEntry.lockWrite(); 446 mCacheEntry.lockWrite();
244 hCacheEntry.insert( pObject->getKey(), pEnt ); 447 hCacheEntry.insert( pObject->getKey(), pEnt );
245 mCacheEntry.unlockWrite(); 448 mCacheEntry.unlockWrite();
@@ -248,9 +451,9 @@ private:
248 return pEnt; 451 return pEnt;
249 } 452 }
250 453
251 CacheEntry *getEntry( const keytype &k ) 454 Entry *getEntry( const keytype &k )
252 { 455 {
253 CacheEntry *pEnt = NULL; 456 Entry *pEnt = NULL;
254 try 457 try
255 { 458 {
256 Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry ); 459 Bu::ReadWriteMutex::ReadLocker rl( mCacheEntry );
@@ -260,7 +463,7 @@ private:
260 { 463 {
261 // try to load the object from the backing store 464 // try to load the object from the backing store
262 obtype *pObject = _load( k ); 465 obtype *pObject = _load( k );
263 pEnt = new CacheEntry( pObject ); 466 pEnt = new Entry( pObject );
264 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); 467 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
265 hCacheEntry.insert( k, pEnt ); 468 hCacheEntry.insert( k, pEnt );
266 } 469 }
@@ -268,10 +471,9 @@ private:
268 } 471 }
269 472
270private: 473private:
271 typedef Bu::Hash<keytype, CacheEntry *> CacheEntryHash; 474 typedef Bu::Hash<keytype, Entry *> CacheEntryHash;
272 CacheEntryHash hCacheEntry; 475 CacheEntryHash hCacheEntry;
273 Bu::ReadWriteMutex mCacheEntry; 476 Bu::ReadWriteMutex mCacheEntry;
274
275}; 477};
276 478
277template<typename keytype, typename obtype> 479template<typename keytype, typename obtype>
@@ -282,21 +484,26 @@ public:
282 sStore( sStore ), 484 sStore( sStore ),
283 mStore( sStore, iBlockSize, iPreallocate ) 485 mStore( sStore, iBlockSize, iPreallocate )
284 { 486 {
285 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
286 try 487 try
287 { 488 {
489 Bu::ReadWriteMutex::ReadLocker l( rwStore );
288 Bu::MyriadStream ms = mStore.openStream( 1 ); 490 Bu::MyriadStream ms = mStore.openStream( 1 );
289 Bu::Archive ar( ms, Bu::Archive::load ); 491 Bu::Archive ar( ms, Bu::Archive::load );
290 ar >> hIndex; 492 uint8_t uVer;
493 ar >> uVer;
494 switch( uVer )
495 {
496 case 0:
497 ar >> hIndex;
498 break;
499 }
291 } 500 }
292 catch(...) 501 catch(...)
293 { 502 {
294 if( mStore.createStreamWithId( 1 ) != 1 ) 503 if( mStore.createStreamWithId( 1 ) != 1 )
295 throw Bu::ExceptionBase("Error creating index stream."); 504 throw Bu::ExceptionBase("Error creating index stream.");
296 505
297 Bu::MyriadStream ms = mStore.openStream( 1 ); 506 sync();
298 Bu::Archive ar( ms, Bu::Archive::save );
299 ar << hIndex;
300 } 507 }
301 } 508 }
302 509
@@ -318,7 +525,7 @@ public:
318 Bu::ReadWriteMutex::ReadLocker wl( rwStore ); 525 Bu::ReadWriteMutex::ReadLocker wl( rwStore );
319 Bu::MyriadStream ms = mStore.openStream( 1 ); 526 Bu::MyriadStream ms = mStore.openStream( 1 );
320 Bu::Archive ar( ms, Bu::Archive::save ); 527 Bu::Archive ar( ms, Bu::Archive::save );
321 ar << hIndex; 528 ar << (uint8_t)0 << hIndex;
322 ar.close(); 529 ar.close();
323 ms.setSize( ms.tell() ); 530 ms.setSize( ms.tell() );
324 } 531 }
@@ -413,21 +620,65 @@ Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s )
413typedef CachePtr<Bu::Uuid, Something> SomethingPtr; 620typedef CachePtr<Bu::Uuid, Something> SomethingPtr;
414typedef MyriadCache<Bu::Uuid, Something> SomethingCache; 621typedef MyriadCache<Bu::Uuid, Something> SomethingCache;
415 622
416int main() 623int main( int argc, char *argv[] )
417{ 624{
418 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite); 625 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite);
419 SomethingCache c( fStore ); 626 SomethingCache c( fStore );
420 627
421 SomethingPtr ptr = c.insert( new Something("Bob") ); 628 for( int j = 1; j < argc; j++ )
422 629 {
423 Bu::println("Something[%1]: %2").arg( ptr.getKey() ).arg(ptr->getName()); 630 SomethingPtr ptr = c.insert( new Something(argv[j]) );
424 631
632 Bu::println("Something[%1]: %2").
633 arg( ptr.getKey() ).
634 arg( ptr->getName() );
635 }
636
425 SomethingCache::KeyList lKeys = c.getKeys(); 637 SomethingCache::KeyList lKeys = c.getKeys();
426 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ ) 638 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ )
427 { 639 {
428 Bu::println(" - %1").arg( *i ); 640 Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->getName() );
429 } 641 }
430 642
643 c._debug();
644
645 SomethingPtr p2;
646 SomethingPtr p1( c.get( lKeys.first() ) );
647
648 c._debug();
649
650 {
651 SomethingPtr p2( p1 );
652 c._debug();
653 }
654
655 c._debug();
656
657 p2 = p1;
658
659 c._debug();
660
661 p1.release();
662
663 c._debug();
664
665 Bu::println("Name: %1").arg( p1->getName() );
666
667 p1.release();
668 p1.lock();
669 p1.unlock();
670
671 c._debug();
672
673 SomethingPtr p3 = c.getLazy( lKeys.first() );
674
675 c._debug();
676
677 SomethingPtr::Locker l( p3 );
678
679 Bu::println("Name again: %1").arg( p3->getName() );
680
681 c._debug();
431 682
432 return 0; 683 return 0;
433} 684}