wasCSharpSQLite – Blame information for rev
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | using System; |
2 | using System.Diagnostics; |
||
3 | using System.Text; |
||
4 | |||
5 | using Bitmask = System.UInt64; |
||
6 | using u8 = System.Byte; |
||
7 | using u16 = System.UInt16; |
||
8 | using u32 = System.UInt32; |
||
9 | |||
10 | namespace Community.CsharpSqlite |
||
11 | { |
||
12 | using sqlite3_int64 = System.Int64; |
||
13 | using MemJournal = Sqlite3.sqlite3_file; |
||
14 | |||
15 | public partial class Sqlite3 |
||
16 | { |
||
17 | /* |
||
18 | ** 2007 August 22 |
||
19 | ** |
||
20 | ** The author disclaims copyright to this source code. In place of |
||
21 | ** a legal notice, here is a blessing: |
||
22 | ** |
||
23 | ** May you do good and not evil. |
||
24 | ** May you find forgiveness for yourself and forgive others. |
||
25 | ** May you share freely, never taking more than you give. |
||
26 | ** |
||
27 | ************************************************************************* |
||
28 | ** |
||
29 | ** This file contains code use to implement an in-memory rollback journal. |
||
30 | ** The in-memory rollback journal is used to journal transactions for |
||
31 | ** ":memory:" databases and when the journal_mode=MEMORY pragma is used. |
||
32 | ************************************************************************* |
||
33 | ** Included in SQLite3 port to C#-SQLite; 2008 Noah B Hart |
||
34 | ** C#-SQLite is an independent reimplementation of the SQLite software library |
||
35 | ** |
||
36 | ** SQLITE_SOURCE_ID: 2010-12-07 20:14:09 a586a4deeb25330037a49df295b36aaf624d0f45 |
||
37 | ** |
||
38 | ************************************************************************* |
||
39 | */ |
||
40 | |||
41 | //#include "sqliteInt.h" |
||
42 | |||
43 | /* Forward references to internal structures */ |
||
44 | //typedef struct MemJournal MemJournal; |
||
45 | //typedef struct FilePoint FilePoint; |
||
46 | //typedef struct FileChunk FileChunk; |
||
47 | |||
48 | /* Space to hold the rollback journal is allocated in increments of |
||
49 | ** this many bytes. |
||
50 | ** |
||
51 | ** The size chosen is a little less than a power of two. That way, |
||
52 | ** the FileChunk object will have a size that almost exactly fills |
||
53 | ** a power-of-two allocation. This mimimizes wasted space in power-of-two |
||
54 | ** memory allocators. |
||
55 | */ |
||
56 | //#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*))) |
||
57 | const int JOURNAL_CHUNKSIZE = 4096; |
||
58 | |||
59 | /* Macro to find the minimum of two numeric values. |
||
60 | */ |
||
61 | //#if !MIN |
||
62 | //# define MIN(x,y) ((x)<(y)?(x):(y)) |
||
63 | //#endif |
||
64 | static int MIN( int x, int y ) |
||
65 | { |
||
66 | return ( x < y ) ? x : y; |
||
67 | } |
||
68 | static int MIN( int x, u32 y ) |
||
69 | { |
||
70 | return ( x < y ) ? x : (int)y; |
||
71 | } |
||
72 | |||
73 | /* |
||
74 | ** The rollback journal is composed of a linked list of these structures. |
||
75 | */ |
||
76 | public class FileChunk |
||
77 | { |
||
78 | public FileChunk pNext; /* Next chunk in the journal */ |
||
79 | public byte[] zChunk = new byte[JOURNAL_CHUNKSIZE]; /* Content of this chunk */ |
||
80 | }; |
||
81 | |||
82 | /* |
||
83 | ** An instance of this object serves as a cursor into the rollback journal. |
||
84 | ** The cursor can be either for reading or writing. |
||
85 | */ |
||
86 | public class FilePoint |
||
87 | { |
||
88 | public long iOffset; /* Offset from the beginning of the file */ |
||
89 | public FileChunk pChunk; /* Specific chunk into which cursor points */ |
||
90 | }; |
||
91 | |||
92 | /* |
||
93 | ** This subclass is a subclass of sqlite3_file. Each open memory-journal |
||
94 | ** is an instance of this class. |
||
95 | */ |
||
96 | public partial class sqlite3_file |
||
97 | { |
||
98 | //public sqlite3_io_methods pMethods; /* Parent class. MUST BE FIRST */ |
||
99 | public FileChunk pFirst; /* Head of in-memory chunk-list */ |
||
100 | public FilePoint endpoint; /* Pointer to the end of the file */ |
||
101 | public FilePoint readpoint; /* Pointer to the end of the last xRead() */ |
||
102 | }; |
||
103 | |||
104 | /* |
||
105 | ** Read data from the in-memory journal file. This is the implementation |
||
106 | ** of the sqlite3_vfs.xRead method. |
||
107 | */ |
||
108 | static int memjrnlRead( |
||
109 | sqlite3_file pJfd, /* The journal file from which to read */ |
||
110 | byte[] zBuf, /* Put the results here */ |
||
111 | int iAmt, /* Number of bytes to read */ |
||
112 | sqlite3_int64 iOfst /* Begin reading at this offset */ |
||
113 | ) |
||
114 | { |
||
115 | MemJournal p = (MemJournal)pJfd; |
||
116 | byte[] zOut = zBuf; |
||
117 | int nRead = iAmt; |
||
118 | int iChunkOffset; |
||
119 | FileChunk pChunk; |
||
120 | |||
121 | /* SQLite never tries to read past the end of a rollback journal file */ |
||
122 | Debug.Assert( iOfst + iAmt <= p.endpoint.iOffset ); |
||
123 | |||
124 | if ( p.readpoint.iOffset != iOfst || iOfst == 0 ) |
||
125 | { |
||
126 | int iOff = 0; |
||
127 | for ( pChunk = p.pFirst; |
||
128 | ALWAYS( pChunk != null ) && ( iOff + JOURNAL_CHUNKSIZE ) <= iOfst; |
||
129 | pChunk = pChunk.pNext |
||
130 | ) |
||
131 | { |
||
132 | iOff += JOURNAL_CHUNKSIZE; |
||
133 | } |
||
134 | } |
||
135 | else |
||
136 | { |
||
137 | pChunk = p.readpoint.pChunk; |
||
138 | } |
||
139 | |||
140 | iChunkOffset = (int)( iOfst % JOURNAL_CHUNKSIZE ); |
||
141 | int izOut = 0; |
||
142 | do |
||
143 | { |
||
144 | int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset; |
||
145 | int nCopy = MIN( nRead, ( JOURNAL_CHUNKSIZE - iChunkOffset ) ); |
||
146 | Buffer.BlockCopy( pChunk.zChunk, iChunkOffset, zOut, izOut, nCopy ); //memcpy( zOut, pChunk.zChunk[iChunkOffset], nCopy ); |
||
147 | izOut += nCopy;// zOut += nCopy; |
||
148 | nRead -= iSpace; |
||
149 | iChunkOffset = 0; |
||
150 | } while ( nRead >= 0 && ( pChunk = pChunk.pNext ) != null && nRead > 0 ); |
||
151 | p.readpoint.iOffset = (int)( iOfst + iAmt ); |
||
152 | p.readpoint.pChunk = pChunk; |
||
153 | |||
154 | return SQLITE_OK; |
||
155 | } |
||
156 | |||
157 | /* |
||
158 | ** Write data to the file. |
||
159 | */ |
||
160 | static int memjrnlWrite( |
||
161 | sqlite3_file pJfd, /* The journal file into which to write */ |
||
162 | byte[] zBuf, /* Take data to be written from here */ |
||
163 | int iAmt, /* Number of bytes to write */ |
||
164 | sqlite3_int64 iOfst /* Begin writing at this offset into the file */ |
||
165 | ) |
||
166 | { |
||
167 | MemJournal p = (MemJournal)pJfd; |
||
168 | int nWrite = iAmt; |
||
169 | byte[] zWrite = zBuf; |
||
170 | int izWrite = 0; |
||
171 | |||
172 | /* An in-memory journal file should only ever be appended to. Random |
||
173 | ** access writes are not required by sqlite. |
||
174 | */ |
||
175 | Debug.Assert( iOfst == p.endpoint.iOffset ); |
||
176 | UNUSED_PARAMETER( iOfst ); |
||
177 | |||
178 | while ( nWrite > 0 ) |
||
179 | { |
||
180 | FileChunk pChunk = p.endpoint.pChunk; |
||
181 | int iChunkOffset = (int)( p.endpoint.iOffset % JOURNAL_CHUNKSIZE ); |
||
182 | int iSpace = MIN( nWrite, JOURNAL_CHUNKSIZE - iChunkOffset ); |
||
183 | |||
184 | if ( iChunkOffset == 0 ) |
||
185 | { |
||
186 | /* New chunk is required to extend the file. */ |
||
187 | FileChunk pNew = new FileChunk();// sqlite3_malloc( sizeof( FileChunk ) ); |
||
188 | if ( null == pNew ) |
||
189 | { |
||
190 | return SQLITE_IOERR_NOMEM; |
||
191 | } |
||
192 | pNew.pNext = null; |
||
193 | if ( pChunk != null ) |
||
194 | { |
||
195 | Debug.Assert( p.pFirst != null ); |
||
196 | pChunk.pNext = pNew; |
||
197 | } |
||
198 | else |
||
199 | { |
||
200 | Debug.Assert( null == p.pFirst ); |
||
201 | p.pFirst = pNew; |
||
202 | } |
||
203 | p.endpoint.pChunk = pNew; |
||
204 | } |
||
205 | |||
206 | Buffer.BlockCopy( zWrite, izWrite, p.endpoint.pChunk.zChunk, iChunkOffset, iSpace ); //memcpy( &p.endpoint.pChunk.zChunk[iChunkOffset], zWrite, iSpace ); |
||
207 | izWrite += iSpace;//zWrite += iSpace; |
||
208 | nWrite -= iSpace; |
||
209 | p.endpoint.iOffset += iSpace; |
||
210 | } |
||
211 | |||
212 | return SQLITE_OK; |
||
213 | } |
||
214 | |||
215 | /* |
||
216 | ** Truncate the file. |
||
217 | */ |
||
218 | static int memjrnlTruncate( sqlite3_file pJfd, sqlite3_int64 size ) |
||
219 | { |
||
220 | MemJournal p = (MemJournal)pJfd; |
||
221 | FileChunk pChunk; |
||
222 | Debug.Assert( size == 0 ); |
||
223 | UNUSED_PARAMETER( size ); |
||
224 | pChunk = p.pFirst; |
||
225 | while ( pChunk != null ) |
||
226 | { |
||
227 | ////FileChunk pTmp = pChunk; |
||
228 | pChunk = pChunk.pNext; |
||
229 | //sqlite3_free( ref pTmp ); |
||
230 | } |
||
231 | sqlite3MemJournalOpen( pJfd ); |
||
232 | return SQLITE_OK; |
||
233 | } |
||
234 | |||
235 | /* |
||
236 | ** Close the file. |
||
237 | */ |
||
238 | static int memjrnlClose( MemJournal pJfd ) |
||
239 | { |
||
240 | memjrnlTruncate( pJfd, 0 ); |
||
241 | return SQLITE_OK; |
||
242 | } |
||
243 | |||
244 | |||
245 | /* |
||
246 | ** Sync the file. |
||
247 | ** |
||
248 | ** Syncing an in-memory journal is a no-op. And, in fact, this routine |
||
249 | ** is never called in a working implementation. This implementation |
||
250 | ** exists purely as a contingency, in case some malfunction in some other |
||
251 | ** part of SQLite causes Sync to be called by mistake. |
||
252 | */ |
||
253 | static int memjrnlSync( sqlite3_file NotUsed, int NotUsed2 ) |
||
254 | { |
||
255 | UNUSED_PARAMETER2( NotUsed, NotUsed2 ); |
||
256 | return SQLITE_OK; |
||
257 | } |
||
258 | |||
259 | /* |
||
260 | ** Query the size of the file in bytes. |
||
261 | */ |
||
262 | static int memjrnlFileSize( sqlite3_file pJfd, ref long pSize ) |
||
263 | { |
||
264 | MemJournal p = (MemJournal)pJfd; |
||
265 | pSize = p.endpoint.iOffset; |
||
266 | return SQLITE_OK; |
||
267 | } |
||
268 | |||
269 | /* |
||
270 | ** Table of methods for MemJournal sqlite3_file object. |
||
271 | */ |
||
272 | static sqlite3_io_methods MemJournalMethods = new sqlite3_io_methods( |
||
273 | 1, /* iVersion */ |
||
274 | (dxClose)memjrnlClose, /* xClose */ |
||
275 | (dxRead)memjrnlRead, /* xRead */ |
||
276 | (dxWrite)memjrnlWrite, /* xWrite */ |
||
277 | (dxTruncate)memjrnlTruncate, /* xTruncate */ |
||
278 | (dxSync)memjrnlSync, /* xSync */ |
||
279 | (dxFileSize)memjrnlFileSize, /* xFileSize */ |
||
280 | null, /* xLock */ |
||
281 | null, /* xUnlock */ |
||
282 | null, /* xCheckReservedLock */ |
||
283 | null, /* xFileControl */ |
||
284 | null, /* xSectorSize */ |
||
285 | null, /* xDeviceCharacteristics */ |
||
286 | null, /* xShmMap */ |
||
287 | null, /* xShmLock */ |
||
288 | null, /* xShmBarrier */ |
||
289 | null /* xShmUnlock */ |
||
290 | ); |
||
291 | |||
292 | /* |
||
293 | ** Open a journal file. |
||
294 | */ |
||
295 | static void sqlite3MemJournalOpen( sqlite3_file pJfd ) |
||
296 | { |
||
297 | MemJournal p = (MemJournal)pJfd; |
||
298 | //memset( p, 0, sqlite3MemJournalSize() ); |
||
299 | p.pFirst = null; |
||
300 | p.endpoint = new FilePoint(); |
||
301 | p.readpoint = new FilePoint(); |
||
302 | p.pMethods = MemJournalMethods;//(sqlite3_io_methods*)&MemJournalMethods; |
||
303 | } |
||
304 | |||
305 | /* |
||
306 | ** Return true if the file-handle passed as an argument is |
||
307 | ** an in-memory journal |
||
308 | */ |
||
309 | static bool sqlite3IsMemJournal( sqlite3_file pJfd ) |
||
310 | { |
||
311 | return pJfd.pMethods == MemJournalMethods; |
||
312 | } |
||
313 | |||
314 | /* |
||
315 | ** Return the number of bytes required to store a MemJournal file descriptor. |
||
316 | */ |
||
317 | static int sqlite3MemJournalSize() |
||
318 | { |
||
319 | return 3096; // sizeof( MemJournal ); |
||
320 | } |
||
321 | } |
||
322 | } |