aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/experimental/debugmutex.cpp78
-rw-r--r--src/experimental/debugmutex.h102
-rw-r--r--src/stable/mutex.h8
-rw-r--r--src/stable/myriad.cpp122
-rw-r--r--src/stable/myriad.h53
-rw-r--r--src/tests/bigmyriad.cpp9
-rw-r--r--src/tests/myriad.cpp23
-rw-r--r--src/tests/myriadfs.cpp62
-rw-r--r--src/tools/myriad.cpp59
-rw-r--r--src/unit/myriad.unit385
-rw-r--r--src/unstable/bitstring.cpp12
-rw-r--r--src/unstable/bitstring.h10
-rw-r--r--src/unstable/myriadcache.h4
-rw-r--r--src/unstable/myriadfs.cpp30
-rw-r--r--src/unstable/myriadfs.h14
15 files changed, 887 insertions, 84 deletions
diff --git a/src/experimental/debugmutex.cpp b/src/experimental/debugmutex.cpp
new file mode 100644
index 0000000..2b61ae2
--- /dev/null
+++ b/src/experimental/debugmutex.cpp
@@ -0,0 +1,78 @@
1#include "bu/debugmutex.h"
2
3#include "bu/exceptionbase.h"
4
5Bu::DebugMutex::DebugMutex()
6{
7}
8
9Bu::DebugMutex::~DebugMutex()
10{
11}
12
13int Bu::DebugMutex::lock()
14{
15 pthread_t self = pthread_self();
16 mState.lock();
17 bool bFound = false;
18 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
19 {
20 if( (*i) == self )
21 {
22 bFound = true;
23 if( (*i).bLocked == true )
24 {
25 throw Bu::ExceptionBase( Bu::String("Double lock in thread: %1").arg( (*i).sName ).end().getStr() );
26
27 }
28 else
29 {
30 (*i).bLocked = true;
31 }
32 break;
33 }
34 }
35 if( bFound == false )
36 {
37 lThreads.append( ThreadInfo( true ) );
38 }
39 mState.unlock();
40 return Bu::Mutex::lock();
41}
42
43int Bu::DebugMutex::unlock()
44{
45 pthread_t self = pthread_self();
46 mState.lock();
47 bool bFound = false;
48 for( ThreadList::iterator i = lThreads.begin(); i; i++ )
49 {
50 if( (*i) == self )
51 {
52 bFound = true;
53 if( (*i).bLocked == false )
54 {
55 throw Bu::ExceptionBase( Bu::String("Unlock in thread that did not lock: %1").arg( (*i).sName ).end().getStr() );
56
57 }
58 else
59 {
60 (*i).bLocked = false;
61 }
62 break;
63 }
64 }
65 if( bFound == false )
66 {
67 ThreadInfo info( false );
68 throw Bu::ExceptionBase( Bu::String("Unlock in thread that never locked mutex: %1").arg( info.sName ).end().getStr() );
69 }
70 mState.unlock();
71 return Bu::Mutex::unlock();
72}
73
74int Bu::DebugMutex::trylock()
75{
76 return Bu::Mutex::trylock();
77}
78
diff --git a/src/experimental/debugmutex.h b/src/experimental/debugmutex.h
new file mode 100644
index 0000000..ca8ef9f
--- /dev/null
+++ b/src/experimental/debugmutex.h
@@ -0,0 +1,102 @@
1/*
2 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#ifndef BU_DEBUG_MUTEX_H
9#define BU_DEBUG_MUTEX_H
10
11#include "bu/mutex.h"
12#include "bu/list.h"
13#include "bu/string.h"
14
15namespace Bu
16{
17 /**
18 * Simple mutex wrapper. Currently this doesn't do anything extra for you
19 * except keep all of the functionality together in an OO sorta' way and
20 * keep you from having to worry about cleaning up your mutexes properly,
21 * or initing them.
22 *@ingroup Threading
23 */
24 class DebugMutex : public Mutex
25 {
26 public:
27 /**
28 * Create an unlocked mutex.
29 */
30 DebugMutex();
31
32 /**
33 * Destroy a mutex. This can only be done when a mutex is unlocked.
34 * Failure to unlock before destroying a mutex object could cause it to
35 * wait for the mutex to unlock, the odds of which are usually farily
36 * low at deconstruction time.
37 */
38 virtual ~DebugMutex();
39
40 /**
41 * Lock the mutex. This causes all future calls to lock on this
42 * instance of mutex to block until the first thread that called mutex
43 * unlocks it. At that point the next thread that called lock will get
44 * a chance to go to work. Because of the nature of a mutex lock it is
45 * a very bad idea to do any kind of serious or rather time consuming
46 * computation within a locked section. This can cause thread-deadlock
47 * and your program may hang.
48 */
49 virtual int lock();
50
51 /**
52 * Unlock the mutex. This allows the next thread that asked for a lock
53 * to lock the mutex and continue with execution.
54 */
55 virtual int unlock();
56
57 /**
58 * Try to lock the mutex. This is the option to go with if you cannot
59 * avoid putting lengthy operations within a locked section. trylock
60 * will attempt to lock the mutex, if the mutex is already locked this
61 * function returns immediately with an error code.
62 */
63 virtual int trylock();
64
65 private:
66 Bu::Mutex mState;
67
68 class ThreadInfo
69 {
70 public:
71 ThreadInfo( bool bLocked=false ) :
72 idThread( pthread_self() ),
73 bLocked( bLocked )
74 {
75 char buf[64];
76 if( pthread_getname_np( idThread, buf, 64 ) == 0 )
77 sName = buf;
78 }
79 ~ThreadInfo() {}
80
81 bool operator==( const ThreadInfo &rhs )
82 {
83 return pthread_equal( idThread, rhs.idThread );
84 }
85
86 bool operator==( const pthread_t &rhs )
87 {
88 return pthread_equal( idThread, rhs );
89 }
90
91 pthread_t idThread;
92 Bu::String sName;
93 bool bLocked;
94 };
95 typedef Bu::List<ThreadInfo> ThreadList;
96 ThreadList lThreads;
97 };
98}
99
100#endif
101
102
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
diff --git a/src/tests/bigmyriad.cpp b/src/tests/bigmyriad.cpp
index 9d24741..73a3315 100644
--- a/src/tests/bigmyriad.cpp
+++ b/src/tests/bigmyriad.cpp
@@ -5,14 +5,15 @@
5int main() 5int main()
6{ 6{
7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create ); 7 Bu::File f("big.myr", Bu::File::Read|Bu::File::Write|Bu::File::Create );
8 Bu::Myriad m( f, 256, 12 ); 8 Bu::Myriad m( f, 512, 12 );
9 9
10 char *buf = new char[1024*1024*10]; 10#define SSIZE (1024*8) // 1024*1024*10
11 char *buf = new char[SSIZE];
11 12
12 for( int j = 0; j < 25; j++ ) 13 for( int j = 0; j < 25; j++ )
13 { 14 {
14 memset( buf, j, 1024*1024*10 ); 15 memset( buf, j, SSIZE );
15 m.create( Bu::Myriad::Write ).write( buf, 1024*1024*10 ); 16 m.create( Bu::Myriad::Write ).write( buf, SSIZE );
16// m.sync(); 17// m.sync();
17 printf("\r%03d%%", (j+1)*100/25 ); 18 printf("\r%03d%%", (j+1)*100/25 );
18 fflush( stdout ); 19 fflush( stdout );
diff --git a/src/tests/myriad.cpp b/src/tests/myriad.cpp
new file mode 100644
index 0000000..ee4eac4
--- /dev/null
+++ b/src/tests/myriad.cpp
@@ -0,0 +1,23 @@
1#include <bu/myriad.h>
2#include <bu/myriadstream.h>
3#include <bu/string.h>
4#include <bu/sio.h>
5#include <bu/file.h>
6
7int main( int , char *[] )
8{
9 Bu::File fMyriad("test.myr", Bu::File::WriteNew|Bu::File::Read );
10 Bu::Myriad m( fMyriad, 32 );
11
12 Bu::MyriadStream ms = m.create( Bu::Myriad::ReadWrite );
13 ms.setSize( 150 );
14 ms.setPos( 145 );
15 char stuff[10];
16 int32_t iRead = ms.read( stuff, 10 );
17
18 Bu::println("Tried to read 10, expect 5, got %1").arg( iRead );
19
20
21 return 0;
22}
23
diff --git a/src/tests/myriadfs.cpp b/src/tests/myriadfs.cpp
new file mode 100644
index 0000000..29ac3d9
--- /dev/null
+++ b/src/tests/myriadfs.cpp
@@ -0,0 +1,62 @@
1#include "bu/file.h"
2#include "bu/membuf.h"
3#include "bu/myriadfs.h"
4#include "bu/myriadstream.h"
5#include "bu/sio.h"
6
7using namespace Bu;
8
9int main()
10{
11// Bu::MemBuf mb;
12 Bu::File mb("store.mfs", File::Read|File::Write|File::Create );
13 Bu::MyriadFs mfs( mb, 512 );
14
15 sio << "Creating dirs..." << sio.nl;
16 mfs.create("/etc", Bu::MyriadFs::typeDir|0755 );
17 mfs.create("/dev", Bu::MyriadFs::typeDir|0755 );
18 mfs.create("/usr", Bu::MyriadFs::typeDir|0755 );
19
20 mfs.create("/dev/null", Bu::MyriadFs::typeChrDev|0666, 1, 3 );
21 mfs.create("/dev/zero", Bu::MyriadFs::typeChrDev|0666, 1, 5 );
22 mfs.create("/dev/sda", Bu::MyriadFs::typeBlkDev|0660, 8, 0 );
23
24 sio << "Creating files..." << sio.nl;
25 {
26 Bu::MyriadStream ms = mfs.open("/hello", Bu::MyriadFs::Read );
27 ms.write("world!");
28 }
29 {
30 Bu::MyriadStream ms = mfs.open("/etc/hello", Bu::MyriadFs::Read );
31 ms.write("world, again!");
32 }
33 {
34 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Write );
35 ms.write("[longer text shouldn't be seen]");
36 }
37 {
38 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Write|Bu::MyriadFs::Create|Bu::MyriadFs::Truncate );
39 ms.write("[short text]");
40 }
41
42 sio << "Reading files..." << sio.nl;
43 {
44 Bu::MyriadStream ms = mfs.open("/hello", Bu::MyriadFs::Read );
45 char buf[512];
46 buf[ms.read( buf, 512 )] = '\0';
47 sio << "read: '" << buf << "'" << sio.nl;
48 }
49 {
50 Bu::MyriadStream ms = mfs.open("/etc/hello", Bu::MyriadFs::Read );
51 char buf[512];
52 buf[ms.read( buf, 512 )] = '\0';
53 sio << "read: '" << buf << "'" << sio.nl;
54 }
55 {
56 Bu::MyriadStream ms = mfs.open("/etc/trunc", Bu::MyriadFs::Read );
57 char buf[512];
58 buf[ms.read( buf, 512 )] = '\0';
59 sio << "read: '" << buf << "'" << sio.nl;
60 }
61}
62
diff --git a/src/tools/myriad.cpp b/src/tools/myriad.cpp
index 346cd85..0dd9840 100644
--- a/src/tools/myriad.cpp
+++ b/src/tools/myriad.cpp
@@ -94,6 +94,49 @@ Bu::Formatter &operator>>( Bu::Formatter &f, Mode & /*e*/ )
94 return f; 94 return f;
95} 95}
96 96
97void printMap( const Bu::BitString &bs )
98{
99 for( int j = 0; j < bs.getSize(); j++ )
100 {
101 if( j>0 && (j%50) == 0 )
102 Bu::println("");
103 if( bs.getBit( j ) )
104 Bu::print("#");
105 else
106 Bu::print("-");
107 }
108 Bu::println("\n");
109}
110
111void printMap( const Bu::Array<int32_t> &bm )
112{
113 int iBigest = 0;
114 for( int j = 0; j < bm.getSize(); j++ )
115 {
116 if( iBigest < bm[j] )
117 iBigest = bm[j];
118 }
119 int iWidth = Bu::String("%1").arg( iBigest ).end().getSize();
120 Bu::String sEmpty;
121 for( int j = 0; j < iWidth; j++ )
122 {
123 sEmpty += '-';
124 }
125 int iBreakAt = 60/(iWidth+1);
126 for( int j = 0; j < bm.getSize(); j++ )
127 {
128 if( j>0 && (j%iBreakAt) == 0 )
129 Bu::println("");
130
131 if( bm[j] < 0 )
132 Bu::print("%1 ").arg( sEmpty, Bu::Fmt(2).right().fill(' '));
133 else
134 Bu::print("%1 ").arg( bm[j], Bu::Fmt(2).right().fill(' '));
135
136 }
137 Bu::println("\n");
138}
139
97int main( int argc, char *argv[] ) 140int main( int argc, char *argv[] )
98{ 141{
99 Options opts( argc, argv ); 142 Options opts( argc, argv );
@@ -168,6 +211,8 @@ int main( int argc, char *argv[] )
168 File fOut( opts.sFile, File::Write|File::Read ); 211 File fOut( opts.sFile, File::Write|File::Read );
169 Myriad m( fOut ); 212 Myriad m( fOut );
170 m.erase( opts.iStream ); 213 m.erase( opts.iStream );
214 printMap( m.buildBlockUseMap() );
215 printMap( m.buildBlockMap() );
171 } 216 }
172 break; 217 break;
173 218
@@ -273,17 +318,8 @@ int main( int argc, char *argv[] )
273 { 318 {
274 File fIn( opts.sFile, File::Write|File::Read ); 319 File fIn( opts.sFile, File::Write|File::Read );
275 Myriad m( fIn ); 320 Myriad m( fIn );
276/* Bu::BitString bs = m.getBlocksUsed(); 321 printMap( m.buildBlockUseMap() );
277 for( int j = 0; j < bs.getSize(); j++ ) 322 printMap( m.buildBlockMap() );
278 {
279 if( j>0 && (j%50) == 0 )
280 Bu::println("");
281 if( bs.getBit( j ) )
282 Bu::print("#");
283 else
284 Bu::print("-");
285 }*/
286 Bu::println("\n");
287 } 323 }
288 break; 324 break;
289 325
@@ -295,4 +331,3 @@ int main( int argc, char *argv[] )
295 331
296 return 0; 332 return 0;
297} 333}
298
diff --git a/src/unit/myriad.unit b/src/unit/myriad.unit
new file mode 100644
index 0000000..f7bea97
--- /dev/null
+++ b/src/unit/myriad.unit
@@ -0,0 +1,385 @@
1// vim: syntax=cpp
2/*
3 * Copyright (C) 2007-2023 Xagasoft, All rights reserved.
4 *
5 * This file is part of the libbu++ library and is released under the
6 * terms of the license contained in the file LICENSE.
7 */
8
9#include "bu/string.h"
10#include "bu/file.h"
11#include "bu/myriad.h"
12#include "bu/myriadstream.h"
13#include "bu/array.h"
14
15#include "bu/sio.h"
16#include "bu/archive.h"
17#include "bu/md5.h"
18#include "bu/unitsuite.h"
19
20#include <stdlib.h>
21
22using namespace Bu;
23
24class VerifyObject
25{
26friend Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const VerifyObject &vo );
27friend Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, VerifyObject &vo );
28public:
29 VerifyObject( int iUnits ) :
30 iUnits( iUnits ),
31 iBytesWritten( 0 )
32 {
33 }
34
35 virtual ~VerifyObject()
36 {
37 }
38
39 int getBytesWritten()
40 {
41 return iBytesWritten;
42 }
43
44private:
45 int iUnits;
46 mutable int iBytesWritten;
47};
48
49Bu::ArchiveBase &operator<<( Bu::ArchiveBase &ar, const VerifyObject &vo )
50{
51 Md5 sum;
52 ar << vo.iUnits;
53 vo.iBytesWritten = sizeof(int);
54 sum.addData( &vo.iUnits, sizeof(int) );
55 for( int j = 0; j < vo.iUnits; j++ )
56 {
57 int iRand = random()%128;
58// ar << iRand;
59 Bu::String sDat( iRand );
60 for( int j = 0; j < iRand; j++ )
61 sDat[j] = (char)((uint8_t)(random()%256));
62 ar << sDat;
63 sum.addData( &iRand, sizeof(int) );
64 sum.addData( sDat.getStr(), iRand );
65 vo.iBytesWritten += sizeof(long) + iRand;
66 }
67 Bu::String sRes = sum.getResult();
68 ar << sRes;
69 vo.iBytesWritten += sizeof(long) + sRes.getSize();
70 return ar;
71}
72
73Bu::ArchiveBase &operator>>( Bu::ArchiveBase &ar, VerifyObject &vo )
74{
75 Md5 sum;
76 ar >> vo.iUnits;
77 sum.addData( &vo.iUnits, sizeof(int) );
78 for( int j = 0; j < vo.iUnits; j++ )
79 {
80 int iRand;
81// ar >> iRand;
82 Bu::String sStr;
83 ar >> sStr;
84 iRand = sStr.getSize();
85 sum.addData( &iRand, sizeof(int) );
86 sum.addData( sStr.getStr(), iRand );
87 }
88 Bu::String sSum;
89 ar >> sSum;
90 unitTest( sSum == sum.getResult() );
91 int iTooMuch;
92 try
93 {
94 ar >> iTooMuch;
95 unitFailed("should have thrown an exception.");
96 }
97 catch( Bu::ExceptionBase &e )
98 {
99 }
100 return ar;
101}
102
103suite Myriad
104{
105 test setSize
106 {
107 String sFileName("myriad-XXXXXXX");
108
109 File fMyriad = tempFile( sFileName );
110 Myriad m( fMyriad, 32 );
111
112 MyriadStream ms = m.create( Myriad::ReadWrite );
113 ms.setSize( 150 );
114 ms.setPos( 145 );
115 char stuff[10];
116 unitTest( ms.read( stuff, 10 ) == 5 );
117
118 ms.setSize( 12 );
119 unitTest( ms.read( stuff, 10 ) == 0 );
120 unitTest( ms.write( "hello", 5 ) == 5 );
121 unitTest( ms.tell() == 17 );
122
123 ms.setSize( 500 );
124 unitTest( ms.tell() == 17 );
125 }
126
127 void addBlock( Stream &s, bool bAppend=true )
128 {
129 if( bAppend )
130 s.setPosEnd( 0 );
131 int iSize = (random()%1016)+8;
132 s.write( &iSize, 4 );
133 char *buf = new char[iSize-8];
134 for( int j = 0; j < iSize-8; j++ )
135 {
136 buf[j] = (j+iSize)%256;
137 }
138 if( random()%2 == 0 )
139 {
140 s.write( buf, iSize-8 );
141 }
142 else
143 {
144 for( int j = 0; j < iSize-8; )
145 {
146 int iAmnt = (random()%8)+1;
147 if( iAmnt+j > iSize-8 )
148 iAmnt = iSize-8-j;
149 iAmnt = s.write( buf+j, iAmnt );
150 j += iAmnt;
151 }
152 }
153 delete[] buf;
154 iSize = ~iSize;
155 s.write( &iSize, 4 );
156 }
157
158 void verifyBlock( Stream &s )
159 {
160 int iSize, iInv;
161 if( s.read( &iSize, 4 ) == 0 )
162 return;
163 if( iSize < 8 || iSize > 1024 )
164 throw ExceptionBase("Read bad data, %d", iSize );
165 char *buf = new char[iSize-8];
166 if( s.read( buf, iSize-8 ) < (Bu::size)iSize-8 )
167 {
168 delete[] buf;
169 throw ExceptionBase("Block failed verify (insuffient block data).");
170 }
171 for( int j = 0; j < iSize-8; j++ )
172 {
173 if( buf[j] != (char)((j+iSize)%256) )
174 {
175 char b = buf[j];
176 delete[] buf;
177 throw ExceptionBase("Block failed computed data verify "
178 "(%02X==%02X).", b, (char)((j+iSize)%256) );
179 }
180 }
181 delete[] buf;
182 if( s.read( &iInv, 4 ) < 4 )
183 throw ExceptionBase("Block failed verify (insufficient data).");
184 if( iInv != ~iSize )
185 throw ExceptionBase("Block failed inversion verify.");
186 }
187
188 void verifyStream( Stream &s )
189 {
190 s.setPos( 0 );
191 while( !s.isEos() )
192 verifyBlock( s );
193 }
194
195 test stressGrow
196 {
197 String sFileName("myriad-XXXXXXX");
198
199 File fMyriad = tempFile( sFileName );
200 Myriad m( fMyriad, 64 );
201
202 Array<int> aStreams;
203 for( int j = 0; j < 5; j++ )
204 {
205 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
206 }
207
208 srandom( 512 );
209
210 for( int j = 0; j < 2500; j++ )
211 {
212 switch( random()%5 )
213 {
214 case 0:
215 aStreams.append( m.create( Bu::Myriad::Read ).getId() );
216 break;
217
218 case 1:
219 if( aStreams.getSize() > 0 )
220 {
221 int iStream = random()%aStreams.getSize();
222 {
223 MyriadStream ms = m.open( aStreams[iStream], Myriad::Read );
224 verifyStream( ms );
225 }
226 m.erase( aStreams[iStream] );
227 Array<int>::iterator i = aStreams.begin();
228 for( int k = 0; k < iStream; k++ )
229 i++;
230 aStreams.erase( i );
231 }
232 break;
233
234 default:
235 if( aStreams.getSize() == 0 )
236 {
237 aStreams.append(
238 m.create( Bu::Myriad::Read ).getId()
239 );
240 }
241 {
242 int iStream = random()%aStreams.getSize();
243 MyriadStream ms = m.open( aStreams[iStream], Myriad::ReadWrite );
244 addBlock( ms );
245 verifyStream( ms );
246 }
247 break;
248 }
249 }
250
251 for( Array<int>::iterator i = aStreams.begin(); i; i++ )
252 {
253 MyriadStream ms = m.open( *i, Myriad::Read );
254 verifyStream( ms );
255 }
256 }
257
258 test stressTruncate
259 {
260 String sFileName("myriad-XXXXXXX");
261
262 File fMyriad = tempFile( sFileName );
263 Myriad m( fMyriad, 128 );
264
265 Array<int> aStream;
266
267 for( int j = 0; j < 5; j++ )
268 {
269 aStream.append( m.create( Bu::Myriad::Read ).getId() );
270 }
271
272 srandom( 1024 );
273
274 char b;
275 for( int iter = 0; iter < 2500; iter++ )
276 {
277 for( Array<int>::iterator i = aStream.begin(); i; i++ )
278 {
279 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
280 addBlock( ms, false );
281 ms.setSize( ms.tell() );
282 unitTest( ms.read( &b, 1 ) == 0 );
283 ms.setPos( 0 );
284 verifyBlock( ms );
285 unitTest( ms.read( &b, 1 ) == 0 );
286 }
287 }
288 }
289
290 test stressTruncate2
291 {
292 String sFileName("myriad-XXXXXXX");
293
294 Array<int> aStream;
295
296 setStepCount( 5*2500 + 5 );
297
298 {
299 File fMyriad = tempFile( sFileName );
300 Myriad m( fMyriad, 128 );
301
302 for( int j = 0; j < 5; j++ )
303 {
304 aStream.append( m.create( Bu::Myriad::Read ).getId() );
305 incProgress();
306 }
307 }
308
309 srandom( 1024 );
310
311 char b;
312 for( int iter = 0; iter < 2500; iter++ )
313 {
314 File fMyriad( sFileName, File::ReadWrite );
315 Myriad m( fMyriad );
316 for( Array<int>::iterator i = aStream.begin(); i; i++ )
317 {
318 MyriadStream ms = m.open( *i, Myriad::ReadWrite );
319 addBlock( ms, false );
320 ms.setSize( ms.tell() );
321 unitTest( ms.read( &b, 1 ) == 0 );
322 ms.setPos( 0 );
323 verifyBlock( ms );
324 unitTest( ms.read( &b, 1 ) == 0 );
325 incProgress();
326 }
327 }
328 }
329
330 test stressArchive
331 {
332 String sFileName("myriad-XXXXXX");
333 Array<int> aStream;
334
335 srandom( 2096 );
336
337 setStepCount( 15*250 + 15 );
338
339 {
340 File fMyriad = tempFile( sFileName );
341 Myriad m( fMyriad, 1024 );
342
343 for( int j = 0; j < 15; j++ )
344 {
345 MyriadStream ms = m.create( Myriad::Write );
346 int iStream = ms.getId();
347 aStream.append( iStream );
348 VerifyObject vo( random()%1024 );
349 {
350 Archive ar( ms, Archive::save );
351 ar << vo;
352 unitTest( ms.tell() == vo.getBytesWritten() );
353 ms.setSize( ms.tell() );
354 }
355 unitTest( m.getSize( iStream ) == vo.getBytesWritten() );
356 incProgress();
357 }
358 }
359
360 for( int iter = 0; iter < 250; iter++ )
361 {
362 File fMyriad( sFileName, File::ReadWrite );
363 Myriad m( fMyriad );
364 for( Array<int>::iterator i = aStream.begin(); i; i++ )
365 {
366 VerifyObject vo( random()%1024 );
367 {
368 MyriadStream ms = m.open( *i, Myriad::Read );
369 Archive ar( ms, Archive::load );
370 ar >> vo;
371 }
372 {
373 MyriadStream ms = m.open( *i, Myriad::WriteNew );
374 Archive ar( ms, Archive::save );
375 ar << vo;
376 unitTest( ms.tell() == vo.getBytesWritten() );
377 ms.setSize( ms.tell() );
378 }
379 unitTest( m.getSize( *i ) == vo.getBytesWritten() );
380 incProgress();
381 }
382 }
383 }
384}
385
diff --git a/src/unstable/bitstring.cpp b/src/unstable/bitstring.cpp
index 21c1316..b80c073 100644
--- a/src/unstable/bitstring.cpp
+++ b/src/unstable/bitstring.cpp
@@ -209,7 +209,7 @@ void Bu::BitString::flipBit( long iBit )
209 caData[iBit/8] ^= (1<<(iBit%8)); 209 caData[iBit/8] ^= (1<<(iBit%8));
210} 210}
211 211
212bool Bu::BitString::getBit( long iBit ) 212bool Bu::BitString::getBit( long iBit ) const
213{ 213{
214 if( iBit >= iBits || iBit < 0 ) return false; 214 if( iBit >= iBits || iBit < 0 ) return false;
215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 ) 215 if( (caData[iBit/8] & (1<<(iBit%8))) == 0 )
@@ -224,7 +224,7 @@ long Bu::BitString::getBitLength()
224 return iBits; 224 return iBits;
225} 225}
226 226
227long Bu::BitString::getSize() 227long Bu::BitString::getSize() const
228{ 228{
229 return iBits; 229 return iBits;
230} 230}
@@ -311,6 +311,14 @@ void Bu::BitString::clear()
311 } 311 }
312} 312}
313 313
314void Bu::BitString::fill()
315{
316 if( caData != NULL )
317 {
318 memset( caData, 0xff, iBytes );
319 }
320}
321
314bool Bu::BitString::setBitLength( long iLength, bool bClear ) 322bool Bu::BitString::setBitLength( long iLength, bool bClear )
315{ 323{
316 return setSize( iLength, bClear ); 324 return setSize( iLength, bClear );
diff --git a/src/unstable/bitstring.h b/src/unstable/bitstring.h
index afc22fb..70ba822 100644
--- a/src/unstable/bitstring.h
+++ b/src/unstable/bitstring.h
@@ -88,7 +88,7 @@ namespace Bu
88 *@param iBit The index of the bit to test. 88 *@param iBit The index of the bit to test.
89 *@returns True for a 1, false for a 0. 89 *@returns True for a 1, false for a 0.
90 */ 90 */
91 bool getBit( long iBit ); 91 bool getBit( long iBit ) const;
92 92
93 /** 93 /**
94 * Inverts the entire BitString, in effect this calls flipBit on every 94 * Inverts the entire BitString, in effect this calls flipBit on every
@@ -106,7 +106,7 @@ namespace Bu
106 DEPRECATED 106 DEPRECATED
107 long getBitLength(); 107 long getBitLength();
108 108
109 long getSize(); 109 long getSize() const;
110 110
111 /** 111 /**
112 * Sets the entire BitString to zeros, but it does it very quickly. 112 * Sets the entire BitString to zeros, but it does it very quickly.
@@ -115,6 +115,12 @@ namespace Bu
115 void clear(); 115 void clear();
116 116
117 /** 117 /**
118 * Sets the entire BitString to ones, but it does it very quickly.
119 * This operation runs in O(N).
120 */
121 void fill();
122
123 /**
118 * Gets another BitString that is autonomous of the current one 124 * Gets another BitString that is autonomous of the current one
119 * (contains a copy of the memory, not a pointer) and contains a subset 125 * (contains a copy of the memory, not a pointer) and contains a subset
120 * of the data in the current BitString. This is an inclusive 126 * of the data in the current BitString. This is an inclusive
diff --git a/src/unstable/myriadcache.h b/src/unstable/myriadcache.h
index d6842a5..f71f9b5 100644
--- a/src/unstable/myriadcache.h
+++ b/src/unstable/myriadcache.h
@@ -86,8 +86,8 @@ namespace Bu
86 { 86 {
87 Bu::ReadWriteMutex::WriteLocker wl( rwStore ); 87 Bu::ReadWriteMutex::WriteLocker wl( rwStore );
88 { 88 {
89 Bu::MyriadStream ms = mStore.create( Bu::Myriad::Create ); 89 Bu::Myriad::StreamId id = mStore.allocate();
90 hIndex.insert( o->getKey(), ms.getId() ); 90 hIndex.insert( o->getKey(), id );
91 } 91 }
92 _save( o ); 92 _save( o );
93 93
diff --git a/src/unstable/myriadfs.cpp b/src/unstable/myriadfs.cpp
index ab9ca74..f748a53 100644
--- a/src/unstable/myriadfs.cpp
+++ b/src/unstable/myriadfs.cpp
@@ -8,6 +8,7 @@
8#include "bu/config.h" 8#include "bu/config.h"
9#include "bu/myriadfs.h" 9#include "bu/myriadfs.h"
10#include "bu/myriadstream.h" 10#include "bu/myriadstream.h"
11#include "bu/mutexlocker.h"
11 12
12#include <string.h> 13#include <string.h>
13#include <unistd.h> 14#include <unistd.h>
@@ -107,6 +108,7 @@ Bu::MyriadFs::~MyriadFs()
107 108
108void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf ) 109void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
109{ 110{
111 Bu::MutexLocker lLock( mAccess );
110 int32_t iParent; 112 int32_t iParent;
111 int32_t iNode = lookupInode( sPath, iParent ); 113 int32_t iNode = lookupInode( sPath, iParent );
112 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read ); 114 Bu::MyriadStream is = mStore.open( 2, Bu::Myriad::Read );
@@ -116,6 +118,7 @@ void Bu::MyriadFs::stat( const Bu::String &sPath, Bu::MyriadFs::Stat &rBuf )
116Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode, 118Bu::MyriadStream Bu::MyriadFs::open( const Bu::String &sPath, int iMode,
117 uint16_t uPerms ) 119 uint16_t uPerms )
118{ 120{
121 Bu::MutexLocker lLock( mAccess );
119 int32_t iParent = -1; 122 int32_t iParent = -1;
120 int32_t iNode; 123 int32_t iNode;
121 try 124 try
@@ -164,6 +167,7 @@ void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
164void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms, 167void Bu::MyriadFs::create( const Bu::String &sPath, uint16_t iPerms,
165 uint32_t uSpecial ) 168 uint32_t uSpecial )
166{ 169{
170 Bu::MutexLocker lLock( mAccess );
167 int32_t iParent = -1; 171 int32_t iParent = -1;
168// int32_t iNode; 172// int32_t iNode;
169 try 173 try
@@ -200,6 +204,7 @@ void Bu::MyriadFs::mkDir( const Bu::String &sPath, uint16_t iPerms )
200void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget, 204void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
201 const Bu::String &sPath ) 205 const Bu::String &sPath )
202{ 206{
207 Bu::MutexLocker lLock( mAccess );
203 int32_t iParent = -1; 208 int32_t iParent = -1;
204 int32_t iNode; 209 int32_t iNode;
205 try 210 try
@@ -232,6 +237,7 @@ void Bu::MyriadFs::mkSymLink( const Bu::String &sTarget,
232void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget, 237void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
233 const Bu::String &sPath ) 238 const Bu::String &sPath )
234{ 239{
240 Bu::MutexLocker lLock( mAccess );
235 int32_t iParent = -1; 241 int32_t iParent = -1;
236 int32_t iNode; 242 int32_t iNode;
237 243
@@ -267,6 +273,7 @@ void Bu::MyriadFs::mkHardLink( const Bu::String &sTarget,
267 273
268Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath ) 274Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
269{ 275{
276 Bu::MutexLocker lLock( mAccess );
270 int32_t iParent = -1; 277 int32_t iParent = -1;
271 int32_t iNode; 278 int32_t iNode;
272 iNode = lookupInode( sPath, iParent ); 279 iNode = lookupInode( sPath, iParent );
@@ -279,6 +286,7 @@ Bu::String Bu::MyriadFs::readSymLink( const Bu::String &sPath )
279 286
280Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath ) 287Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
281{ 288{
289 Bu::MutexLocker lLock( mAccess );
282 int32_t iParent = -1; 290 int32_t iParent = -1;
283 int32_t iNode = lookupInode( sPath, iParent ); 291 int32_t iNode = lookupInode( sPath, iParent );
284 return readDir( iNode ); 292 return readDir( iNode );
@@ -287,6 +295,7 @@ Bu::MyriadFs::Dir Bu::MyriadFs::readDir( const Bu::String &sPath )
287void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime, 295void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
288 int64_t iMTime ) 296 int64_t iMTime )
289{ 297{
298 Bu::MutexLocker lLock( mAccess );
290 int32_t iParent = -1; 299 int32_t iParent = -1;
291 int32_t iNode; 300 int32_t iNode;
292 301
@@ -297,6 +306,7 @@ void Bu::MyriadFs::setTimes( const Bu::String &sPath, int64_t iATime,
297 306
298void Bu::MyriadFs::unlink( const Bu::String &sPath ) 307void Bu::MyriadFs::unlink( const Bu::String &sPath )
299{ 308{
309 Bu::MutexLocker lLock( mAccess );
300 int32_t iParent = -1; 310 int32_t iParent = -1;
301// int32_t iNode; 311// int32_t iNode;
302 312
@@ -352,6 +362,7 @@ void Bu::MyriadFs::unlink( const Bu::String &sPath )
352 362
353void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize ) 363void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
354{ 364{
365 Bu::MutexLocker lLock( mAccess );
355 int32_t iParent = -1; 366 int32_t iParent = -1;
356 int32_t iNode; 367 int32_t iNode;
357 iNode = lookupInode( sPath, iParent ); 368 iNode = lookupInode( sPath, iParent );
@@ -361,6 +372,7 @@ void Bu::MyriadFs::setFileSize( const Bu::String &sPath, int32_t iSize )
361 372
362void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo ) 373void Bu::MyriadFs::rename( const Bu::String &sFrom, const Bu::String &sTo )
363{ 374{
375 Bu::MutexLocker lLock( mAccess );
364 mkHardLink( sFrom, sTo ); 376 mkHardLink( sFrom, sTo );
365 unlink( sFrom ); 377 unlink( sFrom );
366} 378}
@@ -572,27 +584,17 @@ int32_t Bu::MyriadFs::allocInode( uint16_t uPerms, uint32_t uSpecial )
572 { 584 {
573 case typeRegFile: 585 case typeRegFile:
574 case typeSymLink: 586 case typeSymLink:
575 { 587 rs.uStreamIndex = mStore.allocate();
576 Bu::MyriadStream ms = mStore.create(
577 Bu::Myriad::Create
578 );
579 rs.uStreamIndex = ms.getId();
580 }
581 break; 588 break;
582 589
583 case typeDir: 590 case typeDir:
584 {
585 Bu::MyriadStream ms = mStore.create(
586 Bu::Myriad::Create
587 );
588 rs.uStreamIndex = ms.getId();
589 }
590// sio << "Creating directory node, storage: " 591// sio << "Creating directory node, storage: "
591// << rs.uStreamIndex << sio.nl; 592// << rs.uStreamIndex << sio.nl;
592 { 593 {
593 Bu::MyriadStream msDir = mStore.open( 594 Bu::MyriadStream msDir = mStore.create(
594 rs.uStreamIndex, Bu::Myriad::Write 595 Bu::Myriad::Write
595 ); 596 );
597 rs.uStreamIndex = msDir.getId();
596 uint32_t uSize = 0; 598 uint32_t uSize = 0;
597 msDir.write( &uSize, 4 ); 599 msDir.write( &uSize, 4 );
598 } 600 }
diff --git a/src/unstable/myriadfs.h b/src/unstable/myriadfs.h
index ff14292..e3008bc 100644
--- a/src/unstable/myriadfs.h
+++ b/src/unstable/myriadfs.h
@@ -11,7 +11,7 @@
11#include <sys/types.h> 11#include <sys/types.h>
12 12
13#include "bu/myriad.h" 13#include "bu/myriad.h"
14#include "bu/readwritemutex.h" 14#include "bu/debugmutex.h"
15 15
16namespace Bu 16namespace Bu
17{ 17{
@@ -108,7 +108,7 @@ namespace Bu
108 Truncate = 0x08, ///< Truncate file if it does exist 108 Truncate = 0x08, ///< Truncate file if it does exist
109 Append = 0x10, ///< Always append on every write 109 Append = 0x10, ///< Always append on every write
110 NonBlock = 0x20, ///< Open file in non-blocking mode 110 NonBlock = 0x20, ///< Open file in non-blocking mode
111 Exclusive = 0x44, ///< Create file, if it exists then fail 111 Exclusive = 0x40, ///< Create file, if it exists then fail
112 112
113 // Helpful mixes 113 // Helpful mixes
114 ReadWrite = 0x03, ///< Open for reading and writing 114 ReadWrite = 0x03, ///< Open for reading and writing
@@ -172,7 +172,13 @@ namespace Bu
172 typedef Bu::Hash<int32_t, int32_t> NodeIndex; 172 typedef Bu::Hash<int32_t, int32_t> NodeIndex;
173 173
174 private: 174 private:
175 /**
176 * Lookup inode.
177 */
175 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent ); 178 int32_t lookupInode( const Bu::String &sPath, int32_t &iParent );
179 /**
180 * Lookup inode.
181 */
176 int32_t lookupInode( Bu::String::const_iterator iStart, 182 int32_t lookupInode( Bu::String::const_iterator iStart,
177 int32_t iNode, int32_t &iParent ); 183 int32_t iNode, int32_t &iParent );
178 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs ); 184 void readInode( int32_t iNode, RawStat &rs, MyriadStream &rIs );
@@ -190,12 +196,12 @@ namespace Bu
190 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime ); 196 void setTimes( int32_t iNode, int64_t iATime, int64_t iMTime );
191 void destroyNode( int32_t iNode ); 197 void destroyNode( int32_t iNode );
192 198
193 Bu::String filePart( const Bu::String &sPath ); 199 static Bu::String filePart( const Bu::String &sPath );
194 200
195 private: 201 private:
196 Bu::Stream &rStore; 202 Bu::Stream &rStore;
197 Bu::Myriad mStore; 203 Bu::Myriad mStore;
198 Bu::ReadWriteMutex mNodeIndex; 204 Bu::DebugMutex mAccess;
199 NodeIndex hNodeIndex; 205 NodeIndex hNodeIndex;
200 int32_t iUser; 206 int32_t iUser;
201 int32_t iGroup; 207 int32_t iGroup;