aboutsummaryrefslogtreecommitdiff
path: root/src/unstable/myriad.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/unstable/myriad.h')
-rw-r--r--src/unstable/myriad.h222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/unstable/myriad.h b/src/unstable/myriad.h
new file mode 100644
index 0000000..3382ab5
--- /dev/null
+++ b/src/unstable/myriad.h
@@ -0,0 +1,222 @@
1/*
2 * Copyright (C) 2007-2011 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
9#define BU_MYRIAD_H
10
11#include <stdint.h>
12#include "bu/bitstring.h"
13#include "bu/exceptionbase.h"
14#include "bu/array.h"
15#include "bu/hash.h"
16
17namespace Bu
18{
19 class Stream;
20 class MyriadStream;
21
22 subExceptionDeclBegin( MyriadException )
23 enum
24 {
25 emptyStream,
26 invalidFormat,
27 badVersion,
28 invalidWordSize,
29 noSuchStream,
30 streamExists,
31 invalidStreamId,
32 protectedStream
33 };
34 subExceptionDeclEnd();
35
36 /**
37 * Myriad block-allocated stream multiplexing system. This is a system for
38 * creating streams that contain other streams in a flexible and lightweight
39 * manner. Basically, you can create a file (or any other stream) that can
40 * store any number of flexible, growing streams. The streams within the
41 * Myriad stream are automatically numbered, not named. This works more
42 * or less like a filesystem, but without the extra layer for managing
43 * file and directory links. This would actually be very easy to add
44 * on top of Myriad, but is not required.
45 *
46 * Header format is as follows:
47 *
48 * MMMMvBssssSSSS*
49 * M = Magic number (0AD3FA84)
50 * v = version number
51 * B = Bits per int
52 * s = Blocksize in bytes
53 * S = Number of Streams
54 *
55 * The * represents the Stream headers, one per stream, as follows:
56 * IIIIssss$
57 * I = Id number of the stream
58 * s = size of stream in bytes
59 *
60 * The $ represents the Block headers, one per used block, as follows:
61 * IIII
62 * I = Index of the block
63 *
64 * The stream/block data is interleaved in the header, so all blocks stored
65 * with one stream are together. The block headers are in order, and the
66 * data in them is required to be "solid" you cannot fill partial blocks
67 * mid-way through a stream.
68 *
69 * The initial block starts with the nids header, and is both the zero block
70 * and the zero stream. For now, the minimum block size is the size needed
71 * to store the base header, the zero stream header, and the first two
72 * blocks of the zero stream, so 30 bytes. Since it's reccomended to use
73 * a size that will fit evenly into filesystem blocks, then a size of 32 is
74 * probably the smallest reccomended size because all powers of two equal
75 * to or greater than 32 are evenly divisible by 32.
76 *
77 * I have had a thought that if the block size were smaller than 42 bytes
78 * the header would consume the first N blocks where N * block size is
79 * enough space to house the initial header, the first stream header, and
80 * the first N block headers. This, of course, causes you to hit an
81 * infinite header if the block size is small enough.
82 */
83 class Myriad
84 {
85 friend class MyriadStream;
86 public:
87 /**
88 * Create a Myriad object that uses the given stream to store data.
89 * This stream must be random access. The block size and preallocate
90 * values passed in are values that will be used if the given stream
91 * is empty. In that case the stream will be "formatted" for myriad
92 * with the specified block size. If there is already a viable Myriad
93 * format present in the stream, then the blocksize and preallocate
94 * values will be ignored and the values from the stream will be used
95 * instead. If the stream doesn't appear to be Myriad formatted an
96 * exception will be thrown.
97 */
98 Myriad( Bu::Stream &sStore, int iBlockSize=512, int iPreallocate=8 );
99 virtual ~Myriad();
100
101 /**
102 * Destroy whatever data may be in the base stream and create a new
103 * Myriad system there with the given blocksize. Use this with care,
104 * it will destroy anything that was already in the stream, and
105 * generally, should not ever have to be used.
106 */
107 void initialize( int iBlockSize, int iPreAllocate=1 );
108
109 /**
110 * Create a new stream within the Myriad system. The ID of the new
111 * stream is returned.
112 */
113 int createStream( int iPreAllocate=1 );
114
115 /**
116 * Create a new stream within the Myriad system with a given id. The
117 * id that you provide will be the new id of the stream unless it's
118 * already used, in which case an error is thrown. This is primarilly
119 * useful when copying an old Myriad file into a new one.
120 */
121 int createStreamWithId( int iId, int iPreAllocate=1 );
122
123 /**
124 * Delete a stream that's already within the Myriad.
125 */
126 void deleteStream( int iId );
127
128 /**
129 * Return a new Stream object assosiated with the given stream ID.
130 */
131 MyriadStream openStream( int iId );
132
133 Bu::Array<int> getStreamIds();
134 int getStreamSize( int iId );
135 bool hasStream( int iId );
136
137 int getNumStreams();
138 int getBlockSize();
139 int getNumBlocks();
140 int getNumUsedBlocks();
141 int getTotalUsedBytes();
142 int getTotalUnusedBytes();
143 int getTotalUnusedBytes( int iFakeBlockSize );
144
145 /**
146 * Syncronize the header data, etc. with the storage stream. It's not
147 * a bad idea to call this periodically.
148 */
149 void sync();
150
151 /**
152 * Read the first few bytes from the given stream and return true/false
153 * depending on weather or not it's a Myriad stream. This will throw
154 * an exception if the stream is empty, or is not random access.
155 */
156 static bool isMyriad( Bu::Stream &sStore );
157
158 const Bu::BitString &getBlocksUsed() const;
159
160 private:
161 /**
162 * Initialize this object based on the data already in the assosiated
163 * stream. This will be called automatically for you if you forget,
164 * but if you want to pre-initialize for some reason, just call this
165 * once before you actually start doing anything with your Myriad.
166 */
167 void initialize();
168
169 enum
170 {
171 blockUnused = 0xFFFFFFFFUL
172 };
173
174 typedef Bu::Array<int> BlockArray;
175 class Stream
176 {
177 public:
178 int iId;
179 int iSize;
180 BlockArray aBlocks;
181 };
182 typedef Bu::Array<Stream *> StreamArray;
183
184 class Block
185 {
186 public:
187 char *pData;
188 bool bChanged;
189 int iBlockIndex;
190 };
191
192 void updateHeader();
193 int findEmptyBlock();
194
195 /**
196 *@todo Change this to use a binary search, it's nicer.
197 */
198 Stream *findStream( int iId );
199
200 Block *getBlock( int iBlock );
201 void releaseBlock( Block *pBlock );
202 void syncBlock( Block *pBlock );
203
204 int streamAddBlock( Stream *pStream );
205 void setStreamSize( Stream *pStream, long iSize );
206
207 void headerChanged();
208
209 private:
210 Bu::Stream &sStore;
211 int iBlockSize;
212 int iBlocks;
213 int iUsed;
214 Bu::BitString bsBlockUsed;
215 StreamArray aStreams;
216 typedef Bu::Hash<int, Block *> BlockHash;
217 BlockHash hActiveBlocks;
218 bool bHeaderChanged;
219 };
220};
221
222#endif