summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2014-07-22 16:39:01 +0000
committerMike Buland <eichlan@xagasoft.com>2014-07-22 16:39:01 +0000
commit21a4337dc2f969dc3ec81e6ba3170119bcb67016 (patch)
treeaf8077ea0e89ec29b499e46583f3de35d1b3103c
parent6482ec1f7550f0fca153bd8f556327902c7afec8 (diff)
downloadlibbu++-21a4337dc2f969dc3ec81e6ba3170119bcb67016.tar.gz
libbu++-21a4337dc2f969dc3ec81e6ba3170119bcb67016.tar.bz2
libbu++-21a4337dc2f969dc3ec81e6ba3170119bcb67016.tar.xz
libbu++-21a4337dc2f969dc3ec81e6ba3170119bcb67016.zip
Deferred erase now works on cache entries. You can erase a cache entry while
it still has active references, and it will be safely cleaned up when the last reference is released.
-rw-r--r--src/stable/array.h24
-rw-r--r--src/stable/file.cpp9
-rw-r--r--src/stable/file.h4
-rw-r--r--src/tests/cachedel.cpp288
-rw-r--r--src/unstable/cachebase.h76
-rw-r--r--src/unstable/cacheobject.h3
6 files changed, 392 insertions, 12 deletions
diff --git a/src/stable/array.h b/src/stable/array.h
index a598865..a662705 100644
--- a/src/stable/array.h
+++ b/src/stable/array.h
@@ -297,6 +297,30 @@ namespace Bu
297 return core->iSize; 297 return core->iSize;
298 } 298 }
299 299
300 void setSize( long iNewLen, const value &initTo=value() )
301 {
302 if( core->iSize == iNewLen )
303 return;
304
305 _hardCopy();
306 if( iNewLen > core->iCapacity )
307 {
308 core->setCapacity( iNewLen );
309 for( int j = core->iSize; j < iNewLen; j++ )
310 {
311 core->va.construct(
312 &core->pData[j],
313 initTo
314 );
315 }
316 core->iSize = iNewLen;
317 }
318 else
319 {
320 core->iSize = iNewLen;
321 }
322 }
323
300 /** 324 /**
301 * Get the capacity of the array. This number will grow as data is 325 * Get the capacity of the array. This number will grow as data is
302 * added, and is mainly for the curious, it doesn't really determine 326 * added, and is mainly for the curious, it doesn't really determine
diff --git a/src/stable/file.cpp b/src/stable/file.cpp
index b551d24..35933f1 100644
--- a/src/stable/file.cpp
+++ b/src/stable/file.cpp
@@ -240,7 +240,7 @@ void Bu::File::setSize( Bu::size iSize )
240 240
241Bu::size Bu::File::getSize() const 241Bu::size Bu::File::getSize() const
242{ 242{
243 struct stat st; 243 struct ::stat st;
244 fstat( fd, &st ); 244 fstat( fd, &st );
245 return st.st_size; 245 return st.st_size;
246} 246}
@@ -250,7 +250,7 @@ Bu::size Bu::File::getBlockSize() const
250#ifdef WIN32 250#ifdef WIN32
251 return 4096; 251 return 4096;
252#else 252#else
253 struct stat st; 253 struct ::stat st;
254 fstat( fd, &st ); 254 fstat( fd, &st );
255 return st.st_blksize; 255 return st.st_blksize;
256#endif 256#endif
@@ -261,6 +261,11 @@ Bu::String Bu::File::getLocation() const
261 return "to be implemented"; 261 return "to be implemented";
262} 262}
263 263
264void Bu::File::stat( struct ::stat *pStat )
265{
266 fstat( fd, pStat );
267}
268
264#ifndef WIN32 269#ifndef WIN32
265void Bu::File::chmod( mode_t t ) 270void Bu::File::chmod( mode_t t )
266{ 271{
diff --git a/src/stable/file.h b/src/stable/file.h
index ad60e80..e3497d3 100644
--- a/src/stable/file.h
+++ b/src/stable/file.h
@@ -15,6 +15,8 @@
15#include "bu/string.h" 15#include "bu/string.h"
16#include "bu/exceptionbase.h" 16#include "bu/exceptionbase.h"
17 17
18struct stat;
19
18namespace Bu 20namespace Bu
19{ 21{
20 subExceptionDecl( FileException ); 22 subExceptionDecl( FileException );
@@ -76,6 +78,8 @@ namespace Bu
76 virtual size getBlockSize() const; 78 virtual size getBlockSize() const;
77 virtual Bu::String getLocation() const; 79 virtual Bu::String getLocation() const;
78 80
81 void stat( struct ::stat *pStat );
82
79 /** 83 /**
80 * Create a temp file and return its handle. The file is opened 84 * Create a temp file and return its handle. The file is opened
81 * Read/Write. 85 * Read/Write.
diff --git a/src/tests/cachedel.cpp b/src/tests/cachedel.cpp
new file mode 100644
index 0000000..817757c
--- /dev/null
+++ b/src/tests/cachedel.cpp
@@ -0,0 +1,288 @@
1#include "bu/myriadcache.h"
2#include "bu/uuid.h"
3#include "bu/string.h"
4#include "bu/sio.h"
5#include "bu/membuf.h"
6
7class Something : public Bu::CacheObject<Bu::Uuid, Something>
8{
9friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, Something &s );
10friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s );
11public:
12 Something()
13 {
14 }
15
16 Something( const Bu::String &sName ) :
17 uId( Bu::Uuid::generate() ),
18 sName( sName )
19 {
20 }
21
22 virtual ~Something()
23 {
24 }
25
26 virtual Bu::Uuid getKey() const
27 {
28 return uId;
29 }
30
31 Bu::String getName() const
32 {
33 return sName;
34 }
35
36 void setName( const Bu::String &sNewName )
37 {
38 sName = sNewName;
39 changed();
40 }
41
42 virtual Bu::String toString() const=0;
43
44private:
45 Bu::Uuid uId;
46 Bu::String sName;
47};
48
49class SubSomethingA : public Something
50{
51friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingA &s );
52friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingA &s );
53public:
54 SubSomethingA()
55 {
56 }
57
58 SubSomethingA( const Bu::String &sName, int iNumber ) :
59 Something( sName ),
60 iNumber( iNumber )
61 {
62 }
63
64 virtual Bu::String toString() const
65 {
66 return Bu::String("[typeA] %1 (%2)").arg( getName() ).arg( iNumber );
67 }
68
69private:
70 int iNumber;
71};
72
73class SubSomethingB : public Something
74{
75friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingB &s );
76friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingB &s );
77public:
78 SubSomethingB()
79 {
80 }
81
82 SubSomethingB( const Bu::String &sName, const Bu::String &sString ) :
83 Something( sName ),
84 sString( sString )
85 {
86 }
87
88 virtual Bu::String toString() const
89 {
90 return Bu::String("[typeB] %1 (%2)").arg( getName() ).arg( sString );
91 }
92
93private:
94 Bu::String sString;
95};
96
97Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, Something &s )
98{
99 return ar >> s.uId >> s.sName;
100}
101
102Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const Something &s )
103{
104 return ar << s.uId << s.sName;
105}
106
107Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingA &s )
108{
109 return ar >> (Something &)s >> s.iNumber;
110}
111
112Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingA &s )
113{
114 return ar << (Something &)s << s.iNumber;
115}
116
117Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, SubSomethingB &s )
118{
119 return ar >> (Something &)s >> s.sString;
120}
121
122Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const SubSomethingB &s )
123{
124 return ar << (Something &)s << s.sString;
125}
126
127namespace Bu
128{
129 template<>
130 void _cacheObjectSave<const Something>( Bu::Stream &s, const Something *pObject )
131 {
132 Bu::Archive ar( s, Bu::Archive::save );
133 if( typeid(*pObject) == typeid(SubSomethingA) )
134 {
135 ar << (uint8_t)1 << (SubSomethingA &)*pObject;
136 }
137 else if( typeid(*pObject) == typeid(SubSomethingB) )
138 {
139 ar << (uint8_t)2 << (SubSomethingB &)*pObject;
140 }
141 else
142 {
143 Bu::println("Not a recognized type!");
144 throw Bu::ExceptionBase("Not recognized type!");
145 }
146 }
147
148 template<>
149 Something *_cacheObjectLoad<Bu::Uuid, Something>( Bu::CacheObject<Bu::Uuid, Something>::Initializer &initObj, const Bu::Uuid &rKey, Bu::Stream &s )
150 {
151 Bu::Archive ar( s, Bu::Archive::load );
152 uint8_t uType;
153 ar >> uType;
154 switch( uType )
155 {
156 case 1:
157 {
158 SubSomethingA *ret = initObj(new SubSomethingA());
159 ar >> *ret;
160 return ret;
161 }
162 break;
163
164 case 2:
165 {
166 SubSomethingB *ret = initObj(new SubSomethingB());
167 ar >> *ret;
168 return ret;
169 }
170 break;
171
172 default:
173 throw Bu::ExceptionBase("Flagrant error! Invalid type!");
174 }
175
176 return NULL;
177 }
178}
179
180typedef Bu::CachePtr<Bu::Uuid, Something> SomethingPtr;
181typedef Bu::CachePtr<Bu::Uuid, SubSomethingA, Something> SomethingAPtr;
182typedef Bu::CachePtr<Bu::Uuid, SubSomethingB, Something> SomethingBPtr;
183typedef Bu::MyriadCache<Bu::Uuid, Something> SomethingCache;
184
185int main( int, char *[] )
186{
187 Bu::MemBuf mbStore;
188 SomethingCache c( mbStore );
189
190 SomethingPtr ptr;
191 if( time(NULL)%2 )
192 ptr = c.insert( new SubSomethingA("Hello", 55) ).cast<Something>();
193 else
194 ptr = c.insert( new SubSomethingB("Goodbye", "Things") ).cast<Something>();
195
196 Bu::Uuid id = ptr.getKey();
197 Bu::println("Something[%1]: %2").
198 arg( ptr.getKey() ).
199 arg( ptr->getName() );
200
201 Bu::println("has %1: %2").arg( id ).arg( c.has( id ) );
202 c.erase( ptr.getKey() );
203 Bu::println("has %1: %2").arg( id ).arg( c.has( id ) );
204 SomethingPtr b = ptr;
205
206 SomethingPtr p2 = c.insert( new SubSomethingA("new test", 123) ).cast<Something>();
207 id = p2.getKey();
208 p2.unbind();
209 c.erase( id );
210
211 return 0;
212}
213
214/*
215int main( int argc, char *argv[] )
216{
217 Bu::File fStore("test.myr", Bu::File::Create|Bu::File::ReadWrite);
218 SomethingCache c( fStore );
219
220 for( int j = 1; j < argc; j++ )
221 {
222 SomethingPtr ptr = c.insert( new Something(argv[j]) );
223
224 Bu::println("Something[%1]: %2").
225 arg( ptr.getKey() ).
226 arg( ptr->getName() );
227 }
228
229 SomethingCache::KeyList lKeys = c.getKeys();
230 Bu::println("Count: %1").arg( lKeys.getSize() );
231 int j = 0;
232 for( SomethingCache::KeyList::iterator i = lKeys.begin(); i; i++ )
233 {
234 Bu::println(" - %1: '%2'").arg( *i ).arg( c.get( *i )->getName() );
235 if( ((j++)%2) )
236 c.erase( *i );
237 }
238 Bu::println("Count: %1").arg( c.getSize() );
239
240 c._debug();
241
242 SomethingPtr p2;
243 SomethingPtr p1( c.get( lKeys.first() ) );
244
245 c._debug();
246
247 {
248 SomethingPtr p2( p1 );
249 c._debug();
250 }
251
252 c._debug();
253
254 p2 = p1;
255
256 c._debug();
257
258 p1.unbind();
259
260 c._debug();
261
262 Bu::println("Name: %1").arg( p1->getName() );
263
264 p1.unbind();
265 p1.lock();
266 p1.unlock();
267
268 c._debug();
269
270 SomethingPtr p3 = c.getLazy( lKeys.first() );
271
272 c._debug();
273
274 {
275 SomethingPtr::Locker l( p3 );
276
277 Bu::println("Name again: %1").arg( p3->getName() );
278
279 p3->setName( p3->getName() + " - again" );
280 }
281
282 c.sync();
283
284 c._debug();
285
286 return 0;
287}
288*/
diff --git a/src/unstable/cachebase.h b/src/unstable/cachebase.h
index 1584246..b17d377 100644
--- a/src/unstable/cachebase.h
+++ b/src/unstable/cachebase.h
@@ -29,6 +29,7 @@ namespace Bu
29 private: 29 private:
30 CacheEntry( obtype *pObject ) : 30 CacheEntry( obtype *pObject ) :
31 iRefCount( 0 ), 31 iRefCount( 0 ),
32 bDeleted( false ),
32 pObject( pObject ) 33 pObject( pObject )
33 { 34 {
34 } 35 }
@@ -78,10 +79,29 @@ namespace Bu
78 return bRet; 79 return bRet;
79 } 80 }
80 81
82 bool isDeleted()
83 {
84 mEntry.lock();
85 bool bRet = bDeleted;
86 mEntry.unlock();
87 return bRet;
88 }
89
90 // Indicates that the entry was both deleted
91 // and has a refcount of zero
92 bool isReadyForCleanup()
93 {
94 mEntry.lock();
95 bool bRet = bDeleted && iRefCount == 0;
96 mEntry.unlock();
97 return bRet;
98 }
99
81 private: 100 private:
82 mutable Bu::Mutex mEntry; 101 mutable Bu::Mutex mEntry;
83 mutable Bu::Mutex mObject; 102 mutable Bu::Mutex mObject;
84 int iRefCount; 103 int iRefCount;
104 bool bDeleted;
85 obtype *pObject; 105 obtype *pObject;
86 }; 106 };
87 107
@@ -104,7 +124,7 @@ namespace Bu
104 obtype * &rpData ) 124 obtype * &rpData )
105 { 125 {
106 if( pCache == NULL ) 126 if( pCache == NULL )
107 throw Bu::ExceptionBase("Invalid pointer"); 127 throw Bu::ExceptionBase("Invalid cache pointer");
108 128
109 if( !rpData ) 129 if( !rpData )
110 { 130 {
@@ -241,6 +261,12 @@ namespace Bu
241 return pCache->template cast<obtype, castto>( *this ); 261 return pCache->template cast<obtype, castto>( *this );
242 } 262 }
243 263
264 template<typename castto>
265 CachePtr<keytype, castto, basetype> cast() const
266 {
267 return pCache->template cast<obtype, castto>( *this );
268 }
269
244 bool operator==( const MyType &rhs ) const 270 bool operator==( const MyType &rhs ) const
245 { 271 {
246 return pCache == rhs.pCache && 272 return pCache == rhs.pCache &&
@@ -410,19 +436,46 @@ namespace Bu
410 else 436 else
411 return CachePtr<keytype, castto, obtype>( this, ptr.kId ); 437 return CachePtr<keytype, castto, obtype>( this, ptr.kId );
412 } 438 }
439
440 template<typename supertype, typename castto>
441 CachePtr<keytype, castto, obtype> cast( const CachePtr<keytype, supertype, obtype> &ptr )
442 {
443 if( ptr.pEnt )
444 return CachePtr<keytype, castto, obtype>( this, ptr.pEnt, ptr.kId );
445 else
446 return CachePtr<keytype, castto, obtype>( this, ptr.kId );
447 }
413 448
414 /** 449 /**
415 * Removes an item from the cache. 450 * Removes an item from the cache.
416 * This routine calls eraseNow for now. Later the intention is that 451 * The object in question can have references to it, and those
417 * this function will always succeed. It will remove the object from 452 * references will still work after the erase is called. When erase
418 * the backing store and the active tables. It will not be able to 453 * is called the object is immediately removed from the backing store
419 * be requested again, and all changes will be ignored. When the 454 * as well as from the main index. At that point existing references
420 * object's last references are released the memory will be freed 455 * can be used as normal, but when the last reference is released
421 * automatically. 456 * the memory will be automatically cleaned up.
422 */ 457 */
423 void erase( const keytype &key ) 458 void erase( const keytype &key )
424 { 459 {
425 eraseNow( key ); 460 Bu::ReadWriteMutex::WriteLocker wl( mCacheEntry );
461 if( hCacheEntry.has( key ) )
462 {
463 Entry *pEnt = hCacheEntry.get( key );
464 pEnt->mEntry.lock();
465 if( pEnt->iRefCount == 0 )
466 {
467 pEnt->mEntry.unlock();
468 delete pEnt->pObject;
469 delete pEnt;
470 }
471 else
472 {
473 pEnt->bDeleted = true;
474 pEnt->mEntry.unlock();
475 }
476 hCacheEntry.erase( key );
477 }
478 _erase( key );
426 } 479 }
427 480
428 /** 481 /**
@@ -467,8 +520,13 @@ namespace Bu
467 return pEnt; 520 return pEnt;
468 } 521 }
469 522
470 void releaseRef( Entry * )//pEnt ) 523 void releaseRef( Entry *pEnt )
471 { 524 {
525 if( pEnt->isReadyForCleanup() )
526 {
527 delete pEnt->pObject;
528 delete pEnt;
529 }
472 } 530 }
473 531
474 void objectChanged( const keytype &k ) 532 void objectChanged( const keytype &k )
diff --git a/src/unstable/cacheobject.h b/src/unstable/cacheobject.h
index 6eb507b..47e09de 100644
--- a/src/unstable/cacheobject.h
+++ b/src/unstable/cacheobject.h
@@ -86,7 +86,8 @@ namespace Bu
86 protected: 86 protected:
87 void changed( bool bChanged=true ) 87 void changed( bool bChanged=true )
88 { 88 {
89 if( this->bChanged == false && bChanged == true && pCache ) 89 if( this->bChanged == false && bChanged == true && pCache &&
90 pEntry && !pEntry->isDeleted() )
90 pCache->objectChanged( getKey() ); 91 pCache->objectChanged( getKey() );
91 92
92 this->bChanged = bChanged; 93 this->bChanged = bChanged;