aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2013-03-17 23:22:35 +0000
committerMike Buland <eichlan@xagasoft.com>2013-03-17 23:22:35 +0000
commita6d249cad214dc0baff0e80e56ffdec91d8a1cf0 (patch)
treeef74be780dc2d065ae07bd633518efff17f874e3
parent55f8e2c01fe4513d5e3de55f567c392b4a18ecc2 (diff)
downloadlibbu++-a6d249cad214dc0baff0e80e56ffdec91d8a1cf0.tar.gz
libbu++-a6d249cad214dc0baff0e80e56ffdec91d8a1cf0.tar.bz2
libbu++-a6d249cad214dc0baff0e80e56ffdec91d8a1cf0.tar.xz
libbu++-a6d249cad214dc0baff0e80e56ffdec91d8a1cf0.zip
The new cache system is tested and ready, it just needs to be put in it's place.
The old cache system will be going away now, so if you need it for anything, grab a version before this commit. Oh, also, happy 1,000th commit!
-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*/