aboutsummaryrefslogtreecommitdiff
path: root/src/stable/myriad.h
diff options
context:
space:
mode:
authorMike Buland <mike@xagasoft.com>2024-08-27 13:37:36 -0700
committerMike Buland <mike@xagasoft.com>2024-08-27 13:37:36 -0700
commitf1e3f25d9b7a12cdedb99e4cb0bfa66157a1a972 (patch)
treec8414b8040cdcd38bd98471d96a01908cdef49ad /src/stable/myriad.h
parentcaee572ff94822ca2ed354fcb79ca04ed9adf388 (diff)
downloadlibbu++-f1e3f25d9b7a12cdedb99e4cb0bfa66157a1a972.tar.gz
libbu++-f1e3f25d9b7a12cdedb99e4cb0bfa66157a1a972.tar.bz2
libbu++-f1e3f25d9b7a12cdedb99e4cb0bfa66157a1a972.tar.xz
libbu++-f1e3f25d9b7a12cdedb99e4cb0bfa66157a1a972.zip
Making progress.
Diffstat (limited to 'src/stable/myriad.h')
-rw-r--r--src/stable/myriad.h287
1 files changed, 96 insertions, 191 deletions
diff --git a/src/stable/myriad.h b/src/stable/myriad.h
index e63c29f..07b4a1d 100644
--- a/src/stable/myriad.h
+++ b/src/stable/myriad.h
@@ -1,24 +1,14 @@
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_MYRIAD_H 1#ifndef BU_MYRIAD_H
9#define BU_MYRIAD_H 2#define BU_MYRIAD_H
10 3
11#include <stdint.h> 4#include "bu/stream.h"
12#include "bu/bitstring.h"
13#include "bu/exceptionbase.h" 5#include "bu/exceptionbase.h"
6#include "bu/mutex.h"
14#include "bu/array.h" 7#include "bu/array.h"
15#include "bu/hash.h" 8#include "bu/hash.h"
16#include "bu/mutex.h"
17#include "bu/extratypes.h"
18 9
19namespace Bu 10namespace Bu
20{ 11{
21 class Stream;
22 class MyriadStream; 12 class MyriadStream;
23 13
24 subExceptionDeclBegin( MyriadException ) 14 subExceptionDeclBegin( MyriadException )
@@ -31,212 +21,127 @@ namespace Bu
31 noSuchStream, 21 noSuchStream,
32 streamExists, 22 streamExists,
33 invalidStreamId, 23 invalidStreamId,
34 protectedStream 24 protectedStream,
25 invalidParameter,
26 invalidBackingStream,
27 badMode,
35 }; 28 };
36 subExceptionDeclEnd(); 29 subExceptionDeclEnd();
37 30
38 /**
39 * Myriad block-allocated stream multiplexing system. This is a system for
40 * creating streams that contain other streams in a flexible and lightweight
41 * manner. Basically, you can create a file (or any other stream) that can
42 * store any number of flexible, growing streams. The streams within the
43 * Myriad stream are automatically numbered, not named. This works more
44 * or less like a filesystem, but without the extra layer for managing
45 * file and directory links. This would actually be very easy to add
46 * on top of Myriad, but is not required.
47 *
48 * Header format is as follows:
49 *
50 * MMMMvBssssSSSS*
51 * M = Magic number (0AD3FA84)
52 * v = version number
53 * B = Bits per int
54 * s = Blocksize in bytes
55 * S = Number of Streams
56 *
57 * The * represents the Stream headers, one per stream, as follows:
58 * IIIIssss$
59 * I = Id number of the stream
60 * s = size of stream in bytes
61 *
62 * The $ represents the Block headers, one per used block, as follows:
63 * IIII
64 * I = Index of the block
65 *
66 * The stream/block data is interleaved in the header, so all blocks stored
67 * with one stream are together. The block headers are in order, and the
68 * data in them is required to be "solid" you cannot fill partial blocks
69 * mid-way through a stream.
70 *
71 * The initial block starts with the nids header, and is both the zero block
72 * and the zero stream. For now, the minimum block size is the size needed
73 * to store the base header, the zero stream header, and the first two
74 * blocks of the zero stream, so 30 bytes. Since it's reccomended to use
75 * a size that will fit evenly into filesystem blocks, then a size of 32 is
76 * probably the smallest reccomended size because all powers of two equal
77 * to or greater than 32 are evenly divisible by 32.
78 *
79 * I have had a thought that if the block size were smaller than 42 bytes
80 * the header would consume the first N blocks where N * block size is
81 * enough space to house the initial header, the first stream header, and
82 * the first N block headers. This, of course, causes you to hit an
83 * infinite header if the block size is small enough.
84 */
85 class Myriad 31 class Myriad
86 { 32 {
87 friend class MyriadStream;
88 public: 33 public:
89 /** 34 typedef int32_t StreamId;
90 * Create a Myriad object that uses the given stream to store data. 35 enum Mode {
91 * This stream must be random access. The block size and preallocate 36 None = 0x00,
92 * values passed in are values that will be used if the given stream 37
93 * is empty. In that case the stream will be "formatted" for myriad 38 // Flags
94 * with the specified block size. If there is already a viable Myriad 39 Read = 0x01, ///< Open file for reading
95 * format present in the stream, then the blocksize and preallocate 40 Write = 0x02, ///< Open file for writing
96 * values will be ignored and the values from the stream will be used 41 Create = 0x04, ///< Create file if it doesn't exist
97 * instead. If the stream doesn't appear to be Myriad formatted an 42 Truncate = 0x08, ///< Truncate file if it does exist
98 * exception will be thrown. 43 Append = 0x10, ///< Always append on every write
99 */ 44 NonBlock = 0x20, ///< Open file in non-blocking mode
100 Myriad( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 ); 45 Exclusive = 0x44, ///< Create file, if it exists then fail
101 virtual ~Myriad(); 46
102 47 // Helpful mixes
103 /** 48 ReadWrite = 0x03, ///< Open for reading and writing
104 * Destroy whatever data may be in the base stream and create a new 49 WriteNew = 0x0E ///< Create a file (or truncate) for writing.
105 * Myriad system there with the given blocksize. Use this with care, 50 /// Same as Write|Create|Truncate
106 * it will destroy anything that was already in the stream, and 51 };
107 * generally, should not ever have to be used.
108 */
109 void initialize( int iBlockSize, int iPreAllocate=1 );
110
111 /**
112 * Create a new stream within the Myriad system. The ID of the new
113 * stream is returned.
114 */
115 int createStream( int iPreAllocate=1 );
116
117 /**
118 * Create a new stream within the Myriad system with a given id. The
119 * id that you provide will be the new id of the stream unless it's
120 * already used, in which case an error is thrown. This is primarilly
121 * useful when copying an old Myriad file into a new one.
122 */
123 int createStreamWithId( int iId, int iPreAllocate=1 );
124
125 /**
126 * Delete a stream that's already within the Myriad.
127 */
128 void deleteStream( int iId );
129 52
53 public:
130 /** 54 /**
131 * Return a new Stream object assosiated with the given stream ID. 55 * Open existing Myriad stream, or initialize a new one if it doesn't
56 * exist.
57 *
58 * Myriad format V0
59 * 0 - 3: Myriad_MAGIC_CODE (0ad3fa84)
60 * 4 - 4: Version Id (1)
61 * 5 - 5: Bits per integer (32)
62 * 6 - 9: Block size in bytes.
63 * 10 - 13: Number of streams.
64 * 14 - ...: Stream Data
65 *
66 * Stream Data:
67 * 0 - 3: Stream Id
68 * 4 - 7: Size of stream in bytes
69 * 8 - ...: List of blocks in stream (4 bytes per block
132 */ 70 */
133 MyriadStream openStream( int iId ); 71 Myriad( Bu::Stream &rBacking, int32_t iBlockSize=-1, int32_t iPreallocateBlocks=-1 );
134 72 virtual ~Myriad();
135 Bu::Array<int> getStreamIds();
136 int getStreamSize( int iId );
137 bool hasStream( int iId );
138 73
139 int getNumStreams(); 74 MyriadStream create( Mode eMode, int32_t iPreallocateBytes=-1 );
140 int getBlockSize(); 75 MyriadStream open( StreamId iStream, Mode eMode );
141 int getNumBlocks(); 76 bool erase( StreamId iStream );
142 int getNumUsedBlocks(); 77 bool setSize( StreamId iStream, int32_t iNewSize );
143 Bu::size getTotalUsedBytes();
144 Bu::size getTotalUnusedBytes();
145 Bu::size getTotalUnusedBytes( int iFakeBlockSize );
146 78
147 /** 79 private:
148 * Syncronize the header data, etc. with the storage stream. It's not 80 bool loadMyriad();
149 * a bad idea to call this periodically. 81 void createMyriad( int32_t iBlockSize, int32_t iPreallocateBlocks );
150 */ 82 int32_t allocateBlock();
151 void sync();
152 83
84 void openStream( StreamId id );
85 void closeStream( StreamId id );
153 /** 86 /**
154 * Read the first few bytes from the given stream and return true/false 87 * Block restricted read, it will not read past the end of the block
155 * depending on weather or not it's a Myriad stream. This will throw 88 * that iStart places it in.
156 * an exception if the stream is empty, or is not random access.
157 */
158 static bool isMyriad( Bu::Stream &sStore, uint8_t &uVer );
159
160 /**
161 * Read the first few bytes from the given stream and return true/false
162 * depending on weather or not it's a Myriad stream. This will throw
163 * an exception if the stream is empty, or is not random access.
164 */ 89 */
165 static bool isMyriad( Bu::Stream &sStore ); 90 int32_t blockRead( int32_t iStart, void *pTarget, int32_t iSize );
166 91
167 const Bu::BitString getBlocksUsed() const; 92 public:
168
169 private:
170 /** 93 /**
171 * Initialize this object based on the data already in the assosiated 94 * Bridge/communication/tracking class for individual Myriad streams.
172 * stream. This will be called automatically for you if you forget, 95 * Not for general use, this is used by Myriad and MyriadStream to
173 * but if you want to pre-initialize for some reason, just call this 96 * control access.
174 * once before you actually start doing anything with your Myriad.
175 */ 97 */
176 void initialize();
177
178 enum
179 {
180 blockUnused = 0xFFFFFFFFUL
181 };
182
183 typedef Bu::Array<int> BlockArray;
184 class Stream 98 class Stream
185 { 99 {
186 public: 100 friend Bu::Myriad;
187 void setSize( int iNewSize );
188 void growTo( int iNewSize );
189 int getSize() const;
190
191 int iId;
192 BlockArray aBlocks;
193
194 private: 101 private:
195 int iSize; 102 Stream( Myriad &rParent, StreamId iStream, int32_t iSize );
196 mutable Bu::Mutex mStream; 103 virtual ~Stream();
197 };
198 typedef Bu::Array<Stream *> StreamArray;
199 104
200 class Block
201 {
202 public: 105 public:
203 char *pData; 106 int32_t read( int32_t iStart, void *pTarget, int32_t iSize );
204 bool bChanged; 107
205 int iBlockIndex; 108 /**
206 }; 109 * Doesn't actually open, just increments the open counter.
207 110 * If the open counter is non-zero then at least one stream has
208 void updateHeader(); 111 * a lock on this stream.
209 int findEmptyBlock(); 112 */
210 113 void open();
211 /** 114
212 *@todo Change this to use a binary search, it's nicer. 115 /**
213 */ 116 * Doesn't actually close, just decrements the open counter.
214 Stream *findStream( int iId ); 117 *@returns true if there are still handles open, false if no
118 * streams have a lock.
119 */
120 bool close();
215 121
216 Block *getBlock( int iBlock ); 122 private:
217 void releaseBlock( Block *pBlock ); 123 mutable Bu::Mutex mAccess;
218 void syncBlock( Block *pBlock ); 124 Myriad &rParent;
125 StreamId iStream;
126 int32_t iSize;
127 Bu::Array<int32_t> aBlocks;
128 int32_t iOpenCount;
129 bool bStructureChanged;
130 };
219 131
220 int streamAddBlock( Stream *pStream ); 132 private:
221 void setStreamSize( Stream *pStream, long iSize );
222 133
223 void headerChanged(); 134 typedef Bu::Hash<StreamId, Stream *> StreamHash;
224 135
225 private: 136 typedef Bu::List<int32_t> IndexList;
226 Bu::Stream &sStore; 137 Bu::Mutex mAccess;
227 int iBlockSize; 138 mutable Bu::Mutex mBacking;
228 int iBlocks; 139 Bu::Stream &rBacking;
229 int iUsed; 140 int32_t iBlockSize;
230 typedef Bu::List<int> IndexList; 141 int32_t iBlockCount;
142 bool bIsNewStream;
143 StreamHash hStream;
231 IndexList lFreeBlocks; 144 IndexList lFreeBlocks;
232// Bu::BitString bsBlockUsed;
233 StreamArray aStreams;
234 typedef Bu::Hash<int, Block *> BlockHash;
235 BlockHash hActiveBlocks;
236 bool bHeaderChanged;
237
238 Bu::Mutex mHeader;
239 Bu::Mutex mActiveBlocks;
240 }; 145 };
241}; 146};
242 147