aboutsummaryrefslogtreecommitdiff
path: root/src/stable
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/stable/mutex.h8
-rw-r--r--src/stable/myriad.cpp122
-rw-r--r--src/stable/myriad.h53
3 files changed, 139 insertions, 44 deletions
diff --git a/src/stable/mutex.h b/src/stable/mutex.h
index d9e8910..8034974 100644
--- a/src/stable/mutex.h
+++ b/src/stable/mutex.h
@@ -33,7 +33,7 @@ namespace Bu
33 * wait for the mutex to unlock, the odds of which are usually farily 33 * wait for the mutex to unlock, the odds of which are usually farily
34 * low at deconstruction time. 34 * low at deconstruction time.
35 */ 35 */
36 ~Mutex(); 36 virtual ~Mutex();
37 37
38 /** 38 /**
39 * Lock the mutex. This causes all future calls to lock on this 39 * Lock the mutex. This causes all future calls to lock on this
@@ -44,13 +44,13 @@ namespace Bu
44 * computation within a locked section. This can cause thread-deadlock 44 * computation within a locked section. This can cause thread-deadlock
45 * and your program may hang. 45 * and your program may hang.
46 */ 46 */
47 int lock(); 47 virtual int lock();
48 48
49 /** 49 /**
50 * Unlock the mutex. This allows the next thread that asked for a lock 50 * Unlock the mutex. This allows the next thread that asked for a lock
51 * to lock the mutex and continue with execution. 51 * to lock the mutex and continue with execution.
52 */ 52 */
53 int unlock(); 53 virtual int unlock();
54 54
55 /** 55 /**
56 * Try to lock the mutex. This is the option to go with if you cannot 56 * Try to lock the mutex. This is the option to go with if you cannot
@@ -58,7 +58,7 @@ namespace Bu
58 * will attempt to lock the mutex, if the mutex is already locked this 58 * will attempt to lock the mutex, if the mutex is already locked this
59 * function returns immediately with an error code. 59 * function returns immediately with an error code.
60 */ 60 */
61 int trylock(); 61 virtual int trylock();
62 62
63 protected: 63 protected:
64 pthread_mutex_t mutex; /**< The internal mutex reference. */ 64 pthread_mutex_t mutex; /**< The internal mutex reference. */
diff --git a/src/stable/myriad.cpp b/src/stable/myriad.cpp
index eba1ebf..492676e 100644
--- a/src/stable/myriad.cpp
+++ b/src/stable/myriad.cpp
@@ -12,13 +12,13 @@
12#define MyriadRead( target, size ) if( rBacking.read( target, size ) < size ) \ 12#define MyriadRead( target, size ) if( rBacking.read( target, size ) < size ) \
13{ \ 13{ \
14 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \ 14 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
15 "Insufficent data reading myriad data from backing stream."); \ 15 "Insufficient data reading myriad data from backing stream."); \
16} (void)0 16} (void)0
17 17
18#define ReqRead( stream, target, size ) if( stream.read( target, size ) < size ) \ 18#define ReqRead( stream, target, size ) if( stream.read( target, size ) < size ) \
19{ \ 19{ \
20 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \ 20 throw Bu::MyriadException( Bu::MyriadException::invalidFormat, \
21 "Insufficent data reading from myriad stream."); \ 21 "Insufficient data reading from myriad stream."); \
22} (void)0 22} (void)0
23 23
24namespace Bu 24namespace Bu
@@ -84,7 +84,7 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
84 Bu::MutexLocker l( mhStream ); 84 Bu::MutexLocker l( mhStream );
85 if( (eMode&Create) ) 85 if( (eMode&Create) )
86 { 86 {
87 if( !hStream.has( iStream ) ) 87 if( hStream.has( iStream ) )
88 { 88 {
89 if( (eMode&Exclusive) ) 89 if( (eMode&Exclusive) )
90 { 90 {
@@ -112,7 +112,7 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
112 } 112 }
113 { 113 {
114 Bu::MutexLocker l2( mBacking ); 114 Bu::MutexLocker l2( mBacking );
115 if( (eMode&Write) && rBacking.isWritable() ) 115 if( (eMode&Write) && !rBacking.isWritable() )
116 { 116 {
117 throw Bu::MyriadException( MyriadException::badMode, 117 throw Bu::MyriadException( MyriadException::badMode,
118 "Backing stream does not support writing."); 118 "Backing stream does not support writing.");
@@ -129,6 +129,19 @@ Bu::MyriadStream Bu::Myriad::open( Bu::Myriad::StreamId iStream,
129 return Bu::MyriadStream( *this, pStream, eMode ); 129 return Bu::MyriadStream( *this, pStream, eMode );
130} 130}
131 131
132Bu::Myriad::StreamId Bu::Myriad::allocate()
133{
134 Bu::MutexLocker l( mAccess );
135
136 Stream *pStream = new Stream( *this, ++iLastUsedIndex, 0 );
137 mhStream.lock();
138 hStream.insert( pStream->iStream, pStream );
139 mhStream.unlock();
140 bStructureChanged = true;
141
142 return pStream->iStream;
143}
144
132void Bu::Myriad::erase( Bu::Myriad::StreamId iStream ) 145void Bu::Myriad::erase( Bu::Myriad::StreamId iStream )
133{ 146{
134 // For now, let's prevent you from erasing a stream if it's open. 147 // For now, let's prevent you from erasing a stream if it's open.
@@ -252,6 +265,54 @@ int32_t Bu::Myriad::getTotalUnusedBytes(int32_t iAssumeBlockSize ) const
252 return iTotal; 265 return iTotal;
253} 266}
254 267
268Bu::Myriad::StreamIdList Bu::Myriad::getStreamList() const
269{
270 mhStream.lock();
271 StreamIdList lIds = hStream.getKeys();
272 mhStream.unlock();
273 lIds.sort();
274 if( lIds.first() == 0 )
275 {
276 lIds.eraseFirst();
277 }
278 return lIds;
279}
280
281Bu::BitString Bu::Myriad::buildBlockUseMap() const
282{
283 Bu::MutexLocker l( mAccess );
284 Bu::BitString bsMap( iBlockCount );
285 bsMap.fill();
286 for( IndexList::const_iterator i = lFreeBlocks.begin(); i; i++ )
287 {
288 bsMap.setBit( *i, false );
289 }
290 return bsMap;
291}
292
293Bu::Myriad::StreamIdArray Bu::Myriad::buildBlockMap() const
294{
295 Bu::MutexLocker l( mAccess );
296 StreamIdArray bm( iBlockCount );
297 for( int j = 0; j < iBlockCount; j++ )
298 {
299 bm.append( -1 );
300 }
301 Bu::MutexLocker l2( mhStream );
302 for( StreamHash::const_iterator iStream = hStream.begin();
303 iStream; iStream++ )
304 {
305 int32_t iId = iStream.getKey();
306 Stream *pStream = iStream.getValue();
307 for( Bu::Array<int32_t>::const_iterator iBlock =
308 pStream->aBlocks.begin(); iBlock; iBlock++ )
309 {
310 bm[*iBlock] = iId;
311 }
312 }
313 return bm;
314}
315
255void Bu::Myriad::sync() 316void Bu::Myriad::sync()
256{ 317{
257 writeHeader(); 318 writeHeader();
@@ -259,7 +320,7 @@ void Bu::Myriad::sync()
259 320
260bool Bu::Myriad::loadMyriad() 321bool Bu::Myriad::loadMyriad()
261{ 322{
262 Bu::println("Load myriad!"); 323 //Bu::println("Load myriad!");
263 char sMagicCode[4]; 324 char sMagicCode[4];
264 rBacking.setPos( 0 ); 325 rBacking.setPos( 0 );
265 MyriadRead( sMagicCode, 4 ); 326 MyriadRead( sMagicCode, 4 );
@@ -362,7 +423,9 @@ bool Bu::Myriad::loadMyriad()
362 } 423 }
363 424
364 lFreeBlocks = hUnusedBlocks.getKeys(); 425 lFreeBlocks = hUnusedBlocks.getKeys();
365 Bu::println("Free blocks: %1").arg( lFreeBlocks.getSize() ); 426 //Bu::println("Free blocks: %1").arg( lFreeBlocks.getSize() );
427
428 bIsNewStream = false;
366 429
367 return true; 430 return true;
368} 431}
@@ -389,32 +452,21 @@ void Bu::Myriad::createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks )
389 // plus one block index. 452 // plus one block index.
390 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes+4, iBlockSize ); 453 int iHeaderStreamBlocks = blkDiv(iHeaderStreamBytes+4, iBlockSize );
391 454
392 Bu::println("Initial estimate: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).") 455 //Bu::println("Initial estimate: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
393 .arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) )
394 .arg( iHeaderStreamBlocks )
395 .arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) )
396 .arg( iHeaderStreamBlocks*iBlockSize );
397 while( iHeaderStreamBytes+(iHeaderStreamBlocks*4) 456 while( iHeaderStreamBytes+(iHeaderStreamBlocks*4)
398 > iHeaderStreamBlocks*iBlockSize ) 457 > iHeaderStreamBlocks*iBlockSize )
399 { 458 {
400 iHeaderStreamBlocks = blkDiv((iHeaderStreamBytes+((iHeaderStreamBlocks+1)*4)), iBlockSize); 459 iHeaderStreamBlocks = blkDiv((iHeaderStreamBytes+((iHeaderStreamBlocks+1)*4)), iBlockSize);
401 if( iHeaderStreamBlocks > 100 ) 460 if( iHeaderStreamBlocks > 100 )
402 break; 461 break;
403 Bu::println(" Adjustment: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).") 462 //Bu::println(" Adjustment: %1 bytes / %2 cur blocks, %3 computed blocks (%4 target bytes).").arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) ).arg( iHeaderStreamBlocks ).arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) ).arg( iHeaderStreamBlocks*iBlockSize );
404 .arg( iHeaderStreamBytes+(iHeaderStreamBlocks*4) )
405 .arg( iHeaderStreamBlocks )
406 .arg( blkDiv((iHeaderStreamBytes+(iHeaderStreamBlocks*4)), iBlockSize) )
407 .arg( iHeaderStreamBlocks*iBlockSize );
408 } 463 }
409 464
410 if( iPreallocateBlocks > iHeaderStreamBlocks ) 465 if( iPreallocateBlocks < iHeaderStreamBlocks )
411 {
412 rBacking.setSize( iBlockSize*iPreallocateBlocks );
413 }
414 else
415 { 466 {
416 rBacking.setSize( iBlockSize*iHeaderStreamBlocks ); 467 iPreallocateBlocks = iHeaderStreamBlocks;
417 } 468 }
469 rBacking.setSize( iBlockSize*iPreallocateBlocks );
418 470
419 // 471 //
420 // Write Myriad header 472 // Write Myriad header
@@ -459,7 +511,7 @@ void Bu::Myriad::writeHeader()
459 Bu::MutexLocker l( mAccess ); 511 Bu::MutexLocker l( mAccess );
460 if( !rBacking.isWritable() ) 512 if( !rBacking.isWritable() )
461 return; 513 return;
462 Bu::println("Writing stream breakdown:"); 514 //Bu::println("Writing stream breakdown:");
463 Bu::MemBuf mbHeader; 515 Bu::MemBuf mbHeader;
464 { 516 {
465 Bu::MutexLocker l2( mhStream ); 517 Bu::MutexLocker l2( mhStream );
@@ -488,7 +540,7 @@ void Bu::Myriad::writeHeader()
488 psHeader->iSize = iHdrStreamSize; 540 psHeader->iSize = iHdrStreamSize;
489 } 541 }
490 542
491 Bu::println("Computed header size: %1 bytes. Ver=%2, Bpi=%3, BlockSize=%4").arg( iHdrStreamSize ).arg( 1 ).arg( 32 ).arg( iBlockSize ); 543 //Bu::println("Computed header size: %1 bytes. Ver=%2, Bpi=%3, BlockSize=%4").arg( iHdrStreamSize ).arg( 1 ).arg( 32 ).arg( iBlockSize );
492 544
493 uint8_t uVer = 1; 545 uint8_t uVer = 1;
494 uint8_t uBpi = 32; 546 uint8_t uBpi = 32;
@@ -513,17 +565,15 @@ void Bu::Myriad::writeHeader()
513 uint32_t uStreamSize = pStream->getSize(); 565 uint32_t uStreamSize = pStream->getSize();
514 mbHeader.write( &uStreamId, 4 ); 566 mbHeader.write( &uStreamId, 4 );
515 mbHeader.write( &uStreamSize, 4 ); 567 mbHeader.write( &uStreamSize, 4 );
568 int32_t iBlocks = Bu::blkDiv( uStreamSize, (uint32_t)iBlockSize );
516 Bu::Array<int32_t> aBlocks = pStream->getBlockList(); 569 Bu::Array<int32_t> aBlocks = pStream->getBlockList();
517 570
518 Bu::println(" Stream %1 is %2 bytes %3 blocks (%4 blocks computed)") 571 //Bu::println(" Stream %1 is %2 bytes %3 blocks (%4 blocks computed)").arg( *i ).arg( uStreamSize ).arg( aBlocks.getSize() ).arg( Bu::blkDiv( (int)uStreamSize, (int)iBlockSize ) );
519 .arg( *i ).arg( uStreamSize )
520 .arg( aBlocks.getSize() )
521 .arg( Bu::blkDiv( (int)uStreamSize, (int)iBlockSize ) );
522 572
523 for( Bu::Array<int32_t>::iterator i = aBlocks.begin(); i; i++ ) 573// for( Bu::Array<int32_t>::iterator i = aBlocks.begin(); i; i++ )
574 for( int j = 0; j < iBlocks; j++ )
524 { 575 {
525 int32_t iIdx = *i; 576 mbHeader.write( &aBlocks[j], 4 );
526 mbHeader.write( &iIdx, 4 );
527 } 577 }
528 } 578 }
529 579
@@ -556,15 +606,15 @@ int32_t Bu::Myriad::__calcHeaderSize()
556 } 606 }
557 } 607 }
558 608
559 Bu::println("HeaderCalc:"); 609 //Bu::println("HeaderCalc:");
560 Bu::println(" Base (no header stream): %1").arg( iHdrSize ); 610 //Bu::println(" Base (no header stream): %1").arg( iHdrSize );
561 int32_t iNewSize = iHdrSize; 611 int32_t iNewSize = iHdrSize;
562 int32_t iOldSize; 612 int32_t iOldSize;
563 613
564 do { 614 do {
565 iOldSize = iNewSize; 615 iOldSize = iNewSize;
566 iNewSize = iHdrSize + Bu::blkDiv(iNewSize, iBlockSize)*4; 616 iNewSize = iHdrSize + Bu::blkDiv(iNewSize, iBlockSize)*4;
567 Bu::println(" Recomp: %1").arg( iNewSize ); 617 //Bu::println(" Recomp: %1").arg( iNewSize );
568 } while( iOldSize != iNewSize ); 618 } while( iOldSize != iNewSize );
569 619
570 return iNewSize; 620 return iNewSize;
@@ -744,9 +794,7 @@ int32_t Bu::Myriad::Stream::read( int32_t iStart, void *pTarget,
744 794
745 if( iStart+iSize >= this->iSize ) 795 if( iStart+iSize >= this->iSize )
746 { 796 {
747 int32_t iDiff = this->iSize-(iStart+iSize); 797 iSize = this->iSize-iStart;
748 iSize -= iDiff;
749 iStart += iDiff;
750 } 798 }
751 799
752 while( iSize > 0 ) 800 while( iSize > 0 )
diff --git a/src/stable/myriad.h b/src/stable/myriad.h
index 60c5a39..5accd1e 100644
--- a/src/stable/myriad.h
+++ b/src/stable/myriad.h
@@ -7,6 +7,8 @@
7#include "bu/array.h" 7#include "bu/array.h"
8#include "bu/hash.h" 8#include "bu/hash.h"
9 9
10#include "bu/bitstring.h"
11
10namespace Bu 12namespace Bu
11{ 13{
12 class MyriadStream; 14 class MyriadStream;
@@ -29,10 +31,20 @@ namespace Bu
29 }; 31 };
30 subExceptionDeclEnd(); 32 subExceptionDeclEnd();
31 33
34 /**
35 * Myriad Stream Multiplexer. This is a system that allows you to store
36 * many streams within a single backing stream. This is great for databases,
37 * caching, etc. It's fairly lightweight, and allows all streams to grow
38 * dynamically using a block-allocation scheme. This is used extensively
39 * by the caching system and MyriadFs as well as other systems within
40 * libbu++.
41 */
32 class Myriad 42 class Myriad
33 { 43 {
34 public: 44 public:
35 typedef int32_t StreamId; 45 typedef int32_t StreamId;
46 typedef Bu::Array<StreamId> StreamIdArray;
47 typedef Bu::List<StreamId> StreamIdList;
36 enum Mode : int32_t { 48 enum Mode : int32_t {
37 None = 0x00, 49 None = 0x00,
38 50
@@ -43,7 +55,7 @@ namespace Bu
43 Truncate = 0x08, ///< Truncate file if it does exist 55 Truncate = 0x08, ///< Truncate file if it does exist
44 Append = 0x10, ///< Start writing at end of file 56 Append = 0x10, ///< Start writing at end of file
45 //NonBlock = 0x20, ///< Open file in non-blocking mode 57 //NonBlock = 0x20, ///< Open file in non-blocking mode
46 Exclusive = 0x44, ///< Create file, if it exists then fail 58 Exclusive = 0x40, ///< Create file, if it exists then fail
47 59
48 // Helpful mixes 60 // Helpful mixes
49 ReadWrite = 0x03, ///< Open for reading and writing 61 ReadWrite = 0x03, ///< Open for reading and writing
@@ -53,8 +65,9 @@ namespace Bu
53 65
54 public: 66 public:
55 /** 67 /**
56 * Open existing Myriad stream, or initialize a new one if it doesn't 68 * Open existing Myriad container, or initialize a new one if the
57 * exist. 69 * backing stream is empty. If other data is already in the provided
70 * backing stream an error is thrown.
58 * 71 *
59 * Myriad format V0 72 * Myriad format V0
60 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84) 73 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84)
@@ -73,8 +86,32 @@ namespace Bu
73 int32_t iPreallocateBlocks=-1 ); 86 int32_t iPreallocateBlocks=-1 );
74 virtual ~Myriad(); 87 virtual ~Myriad();
75 88
89 /**
90 * Creates a new stream open in the specified eMode and, optionally,
91 * preallocates the specificed amount of space. The stream is zero
92 * bytes even if space is preallocated. The open stream is returned,
93 * ready for use. Use this if you don't care what the id is of the
94 * newly created stream.
95 */
76 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 ); 96 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 );
97
98 /**
99 * Open an existing stream or create a new stream with the specified
100 * id (iStream) with the specified eMode. This respects the normal file
101 * modes, see Bu::Myriad::Mode for details.
102 */
77 MyriadStream open( StreamId iStream, Mode eMode ); 103 MyriadStream open( StreamId iStream, Mode eMode );
104
105 /**
106 * Allocate a new stream but do not open it, just ensure it exists and
107 * return the id of the newly allocated stream.
108 */
109 StreamId allocate();
110
111 /**
112 * Erase the stream specified by iStream. This only can work when the
113 * stream is not open at the moment.
114 */
78 void erase( StreamId iStream ); 115 void erase( StreamId iStream );
79 void setSize( StreamId iStream, int32_t iNewSize ); 116 void setSize( StreamId iStream, int32_t iNewSize );
80 int32_t getSize( StreamId iStream ) const; 117 int32_t getSize( StreamId iStream ) const;
@@ -87,6 +124,16 @@ namespace Bu
87 int32_t getTotalStreams() const; 124 int32_t getTotalStreams() const;
88 int32_t getTotalUsedBytes() const; 125 int32_t getTotalUsedBytes() const;
89 int32_t getTotalUnusedBytes( int32_t iAssumeBlockSize=-1 ) const; 126 int32_t getTotalUnusedBytes( int32_t iAssumeBlockSize=-1 ) const;
127 Bu::BitString buildBlockUseMap() const;
128 StreamIdArray buildBlockMap() const;
129
130 /**
131 * Lists all stream ids that you are allowed to open. Technically there
132 * is always a zero stream, but it is used by Myriad for stream/block
133 * accounting. It works like a normal stream but you should not open
134 * it.
135 */
136 StreamIdList getStreamList() const;
90 137
91 /** 138 /**
92 * Flush all caches to the backing stream, write all structural and 139 * Flush all caches to the backing stream, write all structural and