aboutsummaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/cache.cpp361
1 files changed, 330 insertions, 31 deletions
diff --git a/src/tests/cache.cpp b/src/tests/cache.cpp
index aa71c39..112d916 100644
--- a/src/tests/cache.cpp
+++ b/src/tests/cache.cpp
@@ -6,6 +6,7 @@
6#include <bu/file.h> 6#include <bu/file.h>
7#include <bu/streamstack.h> 7#include <bu/streamstack.h>
8#include <bu/readwritemutex.h> 8#include <bu/readwritemutex.h>
9#include <bu/mutexlocker.h>
9 10
10#include <bu/sio.h> 11#include <bu/sio.h>
11#include <bu/string.h> 12#include <bu/string.h>
@@ -15,6 +16,7 @@
15// 16//
16 17
17template<typename keytype, typename obtype> class CacheBase; 18template<typename keytype, typename obtype> class CacheBase;
19template<typename keytype, typename obtype> class CacheEntry;
18 20
19template<typename keytype, typename obtype> 21template<typename keytype, typename obtype>
20class CacheObject 22class CacheObject
@@ -36,6 +38,27 @@ public:
36 virtual keytype getKey() const=0; 38 virtual keytype getKey() const=0;
37 virtual int getPersistenceScore() const { return 0; } 39 virtual int getPersistenceScore() const { return 0; }
38 40
41 void lock()
42 {
43 pEntry->lock();
44 }
45
46 void unlock()
47 {
48 pEntry->unlock();
49 }
50
51 int getRefCount() const
52 {
53 return pEntry->getRefCount();
54 }
55
56 bool hasChanged() const
57 {
58 return bChanged;
59 }
60
61protected:
39 void changed( bool bChanged=true ) 62 void changed( bool bChanged=true )
40 { 63 {
41 if( this->bChanged == false && bChanged == true ) 64 if( this->bChanged == false && bChanged == true )
@@ -45,13 +68,16 @@ public:
45 } 68 }
46 69
47private: 70private:
48 void setCache( CacheType *pCache ) 71 typedef CacheEntry<keytype, obtype> Entry;
72 void setCache( CacheType *pCache, Entry *pEntry )
49 { 73 {
50 this->pCache = pCache; 74 this->pCache = pCache;
75 this->pEntry = pEntry;
51 } 76 }
52 77
53private: 78private:
54 CacheType *pCache; 79 CacheType *pCache;
80 Entry *pEntry;
55 bool bChanged; 81 bool bChanged;
56}; 82};
57 83
@@ -93,6 +119,11 @@ public:
93 mObject.unlock(); 119 mObject.unlock();
94 } 120 }
95 121
122 Bu::Mutex &getMutex()
123 {
124 return mObject;
125 }
126
96 void incRef() 127 void incRef()
97 { 128 {
98 mEntry.lock(); 129 mEntry.lock();
@@ -263,7 +294,13 @@ public:
263 294
264 return *this; 295 return *this;
265 } 296 }
266 297
298 template<typename castto>
299 CachePtr<keytype, castto, basetype> cast()
300 {
301 return pCache->cast<obtype, castto>( *this );
302 }
303
267 bool operator==( const MyType &rhs ) const 304 bool operator==( const MyType &rhs ) const
268 { 305 {
269 return pCache == rhs.pCache && 306 return pCache == rhs.pCache &&
@@ -339,6 +376,7 @@ template<typename keytype, typename obtype>
339class CacheBase 376class CacheBase
340{ 377{
341friend class CachePtrInterface<keytype, obtype>; 378friend class CachePtrInterface<keytype, obtype>;
379friend class CacheObject<keytype, obtype>;
342public: 380public:
343 CacheBase() 381 CacheBase()
344 { 382 {
@@ -346,13 +384,14 @@ public:
346 384
347 virtual ~CacheBase() 385 virtual ~CacheBase()
348 { 386 {
387 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
388 syncChanges();
349 } 389 }
350 390
351 typedef CacheEntry<keytype, obtype> Entry; 391 typedef CacheEntry<keytype, obtype> Entry;
352 typedef Bu::List<keytype> KeyList; 392 typedef Bu::List<keytype> KeyList;
353 393
354 394 CachePtr<keytype, obtype> insert( obtype *pObject )
355 CachePtr<keytype, obtype> insert( const obtype *pObject )
356 { 395 {
357 Entry *pEnt = addEntry( pObject ); 396 Entry *pEnt = addEntry( pObject );
358 397
@@ -362,9 +401,9 @@ public:
362 } 401 }
363 402
364 template<typename supertype> 403 template<typename supertype>
365 CachePtr<keytype, supertype, obtype> insert( const supertype *pObject ) 404 CachePtr<keytype, supertype, obtype> insert( supertype *pObject )
366 { 405 {
367 const obtype *pCast = dynamic_cast<const obtype *>( pObject ); 406 obtype *pCast = dynamic_cast<obtype *>( pObject );
368 if( pCast == NULL ) 407 if( pCast == NULL )
369 throw std::bad_cast(); 408 throw std::bad_cast();
370 409
@@ -399,9 +438,45 @@ public:
399 return CachePtr<keytype, supertype, obtype>( this, key ); 438 return CachePtr<keytype, supertype, obtype>( this, key );
400 } 439 }
401 440
441 template<typename supertype, typename castto>
442 CachePtr<keytype, castto, obtype> cast( CachePtr<keytype, supertype, obtype> &ptr )
443 {
444 if( ptr.pEnt )
445 return CachePtr<keytype, castto, obtype>( this, ptr.pEnt, ptr.kId );
446 else
447 return CachePtr<keytype, castto, obtype>( this, ptr.kId );
448 }
449
450 void erase( const keytype &key )
451 {
452 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
453 if( hCacheEntry.has( key ) )
454 {
455 Entry *pEnt = hCacheEntry.get( key );
456 pEnt->mEntry.lock();
457 if( pEnt->iRefCount > 0 )
458 {
459 int iCount = pEnt->iRefCount;
460 pEnt->mEntry.unlock();
461 throw Bu::ExceptionBase( Bu::String("Cache entry %1 cannot be erased, there are %2 active references.").arg( key ).arg( iCount ).end().getStr() );
462 }
463 delete pEnt->pObject;
464 delete pEnt;
465 hCacheEntry.erase( key );
466 }
467 _erase( key );
468 }
469
402 virtual KeyList getKeys() const=0; 470 virtual KeyList getKeys() const=0;
471 virtual int getSize() const=0;
403 472
404 virtual void sync()=0; 473 void sync()
474 {
475 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
476 Bu::println("Syncing storage layer...");
477 _sync();
478 syncChanges();
479 }
405 480
406 void _debug() 481 void _debug()
407 { 482 {
@@ -428,9 +503,10 @@ protected:
428 503
429 void objectChanged( const keytype &k ) 504 void objectChanged( const keytype &k )
430 { 505 {
506 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
507 hChanged.insert( k, true );
431 } 508 }
432 509
433
434protected: 510protected:
435 virtual void _create( const obtype *o )=0; 511 virtual void _create( const obtype *o )=0;
436 virtual void _erase( const keytype &k )=0; 512 virtual void _erase( const keytype &k )=0;
@@ -438,14 +514,17 @@ protected:
438 virtual obtype *_load( const keytype &k )=0; 514 virtual obtype *_load( const keytype &k )=0;
439 virtual void _save( const obtype *o )=0; 515 virtual void _save( const obtype *o )=0;
440 516
517 virtual void _sync()=0;
518
441private: 519private:
442 Entry *addEntry( const obtype *pObject ) 520 Entry *addEntry( obtype *pObject )
443 { 521 {
444 Entry *pEnt = new Entry( const_cast<obtype *>(pObject) ); 522 Entry *pEnt = new Entry( pObject );
445 mCacheEntry.lockWrite(); 523 mCacheEntry.lockWrite();
446 hCacheEntry.insert( pObject->getKey(), pEnt ); 524 hCacheEntry.insert( pObject->getKey(), pEnt );
447 mCacheEntry.unlockWrite(); 525 mCacheEntry.unlockWrite();
448 _create( pObject ); 526 _create( pObject );
527 pObject->setCache( this, pEnt );
449 528
450 return pEnt; 529 return pEnt;
451 } 530 }
@@ -463,25 +542,60 @@ private:
463 // try to load the object from the backing store 542 // try to load the object from the backing store
464 obtype *pObject = _load( k ); 543 obtype *pObject = _load( k );
465 pEnt = new Entry( pObject ); 544 pEnt = new Entry( pObject );
545 pObject->setCache( this, pEnt );
466 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry ); 546 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
467 hCacheEntry.insert( k, pEnt ); 547 hCacheEntry.insert( k, pEnt );
468 } 548 }
469 return pEnt; 549 return pEnt;
470 } 550 }
471 551
552 void syncChanges()
553 {
554 Bu::println("Syncing: %1 entries changed.").arg( hChanged.getSize() );
555 if( !hChanged.isEmpty() )
556 {
557 for( typename CacheKeySet::iterator i = hChanged.begin(); i; i++ )
558 {
559 Entry *pEnt = hCacheEntry.get( i.getKey() );
560 Bu::MutexLocker ml( pEnt->getMutex() );
561 _save( pEnt->getPtr() );
562 }
563 hChanged.clear();
564 }
565 }
566
472private: 567private:
473 typedef Bu::Hash<keytype, Entry *> CacheEntryHash; 568 typedef Bu::Hash<keytype, Entry *> CacheEntryHash;
569 typedef Bu::Hash<keytype, bool> CacheKeySet;
474 CacheEntryHash hCacheEntry; 570 CacheEntryHash hCacheEntry;
571 CacheKeySet hChanged;
475 Bu::ReadWriteMutex mCacheEntry; 572 Bu::ReadWriteMutex mCacheEntry;
476}; 573};
477 574
575template<typename obtype>
576void _cacheObjectSave( Bu::Stream &s, obtype *pObject )
577{
578 Bu::Archive ar( s, Bu::Archive::save );
579 ar << *pObject;
580}
581
582template<typename obtype>
583obtype *_cacheObjectLoad( Bu::Stream &s )
584{
585 Bu::Archive ar( s, Bu::Archive::load );
586 obtype *ret = new obtype();
587 ar >> *ret;
588 return ret;
589}
590
478template<typename keytype, typename obtype> 591template<typename keytype, typename obtype>
479class MyriadCache : public CacheBase<keytype, obtype> 592class MyriadCache : public CacheBase<keytype, obtype>
480{ 593{
481public: 594public:
482 MyriadCache( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ) : 595 MyriadCache( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ) :
483 sStore( sStore ), 596 sStore( sStore ),
484 mStore( sStore, iBlockSize, iPreallocate ) 597 mStore( sStore, iBlockSize, iPreallocate ),
598 bStructureChanged( false )
485 { 599 {
486 try 600 try
487 { 601 {
@@ -502,13 +616,14 @@ public:
502 if( mStore.createStreamWithId( 1 ) != 1 ) 616 if( mStore.createStreamWithId( 1 ) != 1 )
503 throw Bu::ExceptionBase("Error creating index stream."); 617 throw Bu::ExceptionBase("Error creating index stream.");
504 618
505 sync(); 619 _sync();
506 } 620 }
507 } 621 }
508 622
509 virtual ~MyriadCache() 623 virtual ~MyriadCache()
510 { 624 {
511 sync(); 625 Bu::println("MyriadCache destroying.");
626 _sync();
512 } 627 }
513 628
514 using typename CacheBase<keytype,obtype>::KeyList; 629 using typename CacheBase<keytype,obtype>::KeyList;
@@ -518,47 +633,60 @@ public:
518 Bu::ReadWriteMutex::ReadLocker rl( rwStore ); 633 Bu::ReadWriteMutex::ReadLocker rl( rwStore );
519 return hIndex.getKeys(); 634 return hIndex.getKeys();
520 } 635 }
521 636
522 virtual void sync() 637 virtual int getSize() const
523 { 638 {
524 Bu::ReadWriteMutex::ReadLocker wl( rwStore ); 639 Bu::ReadWriteMutex::ReadLocker rl( rwStore );
525 Bu::MyriadStream ms = mStore.openStream( 1 ); 640 return hIndex.getSize();
526 Bu::Archive ar( ms, Bu::Archive::save );
527 ar << (uint8_t)0 << hIndex;
528 ar.close();
529 ms.setSize( ms.tell() );
530 } 641 }
531 642
532protected: 643protected:
533 virtual void _create( const obtype *o ) 644 virtual void _create( const obtype *o )
534 { 645 {
646 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
535 hIndex.insert( o->getKey(), mStore.createStream() ); 647 hIndex.insert( o->getKey(), mStore.createStream() );
536 _save( o ); 648 _save( o );
649
650 bStructureChanged = true;
537 } 651 }
538 652
539 virtual void _erase( const keytype &k ) 653 virtual void _erase( const keytype &k )
540 { 654 {
655 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
541 mStore.deleteStream( hIndex.get( k ) ); 656 mStore.deleteStream( hIndex.get( k ) );
542 hIndex.erase( k ); 657 hIndex.erase( k );
658
659 bStructureChanged = true;
543 } 660 }
544 661
545 virtual obtype *_load( const keytype &k ) 662 virtual obtype *_load( const keytype &k )
546 { 663 {
547 Bu::MyriadStream ms = mStore.openStream( hIndex.get( k ) ); 664 Bu::MyriadStream ms = mStore.openStream( hIndex.get( k ) );
548 Bu::Archive ar( ms, Bu::Archive::load ); 665 return _cacheObjectLoad<obtype>( ms );
549 obtype *ret = new obtype();
550 ar >> *ret;
551 return ret;
552 } 666 }
553 667
554 virtual void _save( const obtype *o ) 668 virtual void _save( const obtype *o )
555 { 669 {
556 Bu::MyriadStream ms = mStore.openStream( hIndex.get( o->getKey() ) ); 670 Bu::MyriadStream ms = mStore.openStream( hIndex.get( o->getKey() ) );
557 { 671 _cacheObjectSave( ms, o );
558 Bu::Archive ar( ms, Bu::Archive::save ); 672 ms.setSize( ms.tell() );
559 ar << *o; 673 }
560 } 674
675 virtual void _sync()
676 {
677 Bu::println("Syncing myriad header.");
678 Bu::ReadWriteMutex::ReadLocker wl( rwStore );
679 if( !bStructureChanged )
680 return;
681
682 Bu::println(" --> Header changed, write required.");
683 Bu::MyriadStream ms = mStore.openStream( 1 );
684 Bu::Archive ar( ms, Bu::Archive::save );
685 ar << (uint8_t)0 << hIndex;
686 ar.close();
561 ms.setSize( ms.tell() ); 687 ms.setSize( ms.tell() );
688
689 bStructureChanged = false;
562 } 690 }
563 691
564private: 692private:
@@ -566,6 +694,7 @@ private:
566 Bu::Myriad mStore; 694 Bu::Myriad mStore;
567 Bu::Hash<keytype, int> hIndex; 695 Bu::Hash<keytype, int> hIndex;
568 mutable Bu::ReadWriteMutex rwStore; 696 mutable Bu::ReadWriteMutex rwStore;
697 bool bStructureChanged;
569}; 698};
570 699
571// 700//
@@ -596,16 +725,72 @@ public:
596 return uId; 725 return uId;
597 } 726 }
598 727
599 Bu::String getName() 728 Bu::String getName() const
600 { 729 {
601 return sName; 730 return sName;
602 } 731 }
603 732
733 void setName( const Bu::String &sNewName )
734 {
735 sName = sNewName;
736 changed();
737 }
738
739 virtual Bu::String toString() const=0;
740
604private: 741private:
605 Bu::Uuid uId; 742 Bu::Uuid uId;
606 Bu::String sName; 743 Bu::String sName;
607}; 744};
608 745
746class SubSomethingA : public Something
747{
748friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingA &s );
749friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingA &s );
750public:
751 SubSomethingA()
752 {
753 }
754
755 SubSomethingA( const Bu::String &sName, int iNumber ) :
756 Something( sName ),
757 iNumber( iNumber )
758 {
759 }
760
761 virtual Bu::String toString() const
762 {
763 return Bu::String("[typeA] %1 (%2)").arg( getName() ).arg( iNumber );
764 }
765
766private:
767 int iNumber;
768};
769
770class SubSomethingB : public Something
771{
772friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingB &s );
773friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingB &s );
774public:
775 SubSomethingB()
776 {
777 }
778
779 SubSomethingB( const Bu::String &sName, const Bu::String &sString ) :
780 Something( sName ),
781 sString( sString )
782 {
783 }
784
785 virtual Bu::String toString() const
786 {
787 return Bu::String("[typeB] %1 (%2)").arg( getName() ).arg( sString );
788 }
789
790private:
791 Bu::String sString;
792};
793
609Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, Something &s ) 794Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, Something &s )
610{ 795{
611 return ar >> s.uId >> s.sName; 796 return ar >> s.uId >> s.sName;
@@ -616,7 +801,77 @@ Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s )
616 return ar << s.uId << s.sName; 801 return ar << s.uId << s.sName;
617} 802}
618 803
804Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingA &s )
805{
806 return ar >> (Something &)s >> s.iNumber;
807}
808
809Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingA &s )
810{
811 return ar << (Something &)s << s.iNumber;
812}
813
814Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingB &s )
815{
816 return ar >> (Something &)s >> s.sString;
817}
818
819Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingB &s )
820{
821 return ar << (Something &)s << s.sString;
822}
823
824template<>
825void _cacheObjectSave<const Something>( Bu::Stream &s, const Something *pObject )
826{
827 Bu::Archive ar( s, Bu::Archive::save );
828 if( typeid(*pObject) == typeid(SubSomethingA) )
829 {
830 ar << (uint8_t)1 << (SubSomethingA &)*pObject;
831 }
832 else if( typeid(*pObject) == typeid(SubSomethingB) )
833 {
834 ar << (uint8_t)2 << (SubSomethingB &)*pObject;
835 }
836 else
837 {
838 Bu::println("Not a recognized type!");
839 throw Bu::ExceptionBase("Not recognized type!");
840 }
841}
842
843template<>
844Something *_cacheObjectLoad<Something>( Bu::Stream &s )
845{
846 Bu::Archive ar( s, Bu::Archive::load );
847 uint8_t uType;
848 ar >> uType;
849 switch( uType )
850 {
851 case 1:
852 {
853 SubSomethingA *ret = new SubSomethingA();
854 ar >> *ret;
855 return ret;
856 }
857 break;
858
859 case 2:
860 {
861 SubSomethingB *ret = new SubSomethingB();
862 ar >> *ret;
863 return ret;
864 }
865 break;
866
867 default:
868 throw Bu::ExceptionBase("Flagrant error! Invalid type!");
869 }
870}
871
619typedef CachePtr<Bu::Uuid, Something> SomethingPtr; 872typedef CachePtr<Bu::Uuid, Something> SomethingPtr;
873typedef CachePtr<Bu::Uuid, SubSomethingA, Something> SomethingAPtr;
874typedef CachePtr<Bu::Uuid, SubSomethingB, Something> SomethingBPtr;
620typedef MyriadCache<Bu::Uuid, Something> SomethingCache; 875typedef MyriadCache<Bu::Uuid, Something> SomethingCache;
621 876
622int main( int argc, char *argv[] ) 877int main( int argc, char *argv[] )
@@ -624,6 +879,39 @@ int main( int argc, char *argv[] )
624 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite); 879 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite);
625 SomethingCache c( fStore ); 880 SomethingCache c( fStore );
626 881
882 SomethingPtr ptr;
883 if( time(NULL)%2 )
884 ptr = c.insert( new SubSomethingA("Hello", 55) ).cast<Something>();
885 else
886 ptr = c.insert( new SubSomethingB("Goodbye", "Things") ).cast<Something>();
887
888 Bu::println("Something[%1]: %2").
889 arg( ptr.getKey() ).
890 arg( ptr->getName() );
891
892 SomethingCache::KeyList lKeys = c.getKeys();
893 Bu::println("Count: %1").arg( lKeys.getSize() );
894 int j = 0;
895 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ )
896 {
897 Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->toString() );
898 }
899 Bu::println("Count: %1").arg( c.getSize() );
900
901 SomethingPtr p2 = c.get( ptr.getKey() );
902 Bu::println("%1 == %2").arg( p2->getName() ).arg( ptr->getName() );
903 SomethingPtr p3 = ptr.cast<Something>();
904 Bu::println("%1: %2").arg( p3.getKey() ).arg( p3->getName() );
905
906 return 0;
907}
908
909/*
910int main( int argc, char *argv[] )
911{
912 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite);
913 SomethingCache c( fStore );
914
627 for( int j = 1; j < argc; j++ ) 915 for( int j = 1; j < argc; j++ )
628 { 916 {
629 SomethingPtr ptr = c.insert( new Something(argv[j]) ); 917 SomethingPtr ptr = c.insert( new Something(argv[j]) );
@@ -634,10 +922,15 @@ int main( int argc, char *argv[] )
634 } 922 }
635 923
636 SomethingCache::KeyList lKeys = c.getKeys(); 924 SomethingCache::KeyList lKeys = c.getKeys();
925 Bu::println("Count: %1").arg( lKeys.getSize() );
926 int j = 0;
637 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ ) 927 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ )
638 { 928 {
639 Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->getName() ); 929 Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->getName() );
930 if( ((j++)%2) )
931 c.erase( *i );
640 } 932 }
933 Bu::println("Count: %1").arg( c.getSize() );
641 934
642 c._debug(); 935 c._debug();
643 936
@@ -673,12 +966,18 @@ int main( int argc, char *argv[] )
673 966
674 c._debug(); 967 c._debug();
675 968
969 {
676 SomethingPtr::Locker l( p3 ); 970 SomethingPtr::Locker l( p3 );
677 971
678 Bu::println("Name again: %1").arg( p3->getName() ); 972 Bu::println("Name again: %1").arg( p3->getName() );
679 973
974 p3->setName( p3->getName() + " - again" );
975 }
976
977 c.sync();
978
680 c._debug(); 979 c._debug();
681 980
682 return 0; 981 return 0;
683} 982}
684 983*/