summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2013-03-13 02:50:06 +0000
committerMike Buland <eichlan@xagasoft.com>2013-03-13 02:50:06 +0000
commit0ac226c809b6495d5dbc09c2f847638e10aca315 (patch)
treef01e3af3320bdb93e9bc029ae760fa5518c0d5c8
parenta7c44a1356a8ee1384d70dd98941e00c89ec2702 (diff)
downloadlibbu++-0ac226c809b6495d5dbc09c2f847638e10aca315.tar.gz
libbu++-0ac226c809b6495d5dbc09c2f847638e10aca315.tar.bz2
libbu++-0ac226c809b6495d5dbc09c2f847638e10aca315.tar.xz
libbu++-0ac226c809b6495d5dbc09c2f847638e10aca315.zip
The new caching system is almost there. It's more elaborate internally, and
it works very, very differently, but the interface is proving much easier to use and it should be much faster, not to mention thread-safe.
-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}