blob: 04780df99c20963707dcbedc5b3522ead68d0478 [file] [log] [blame]
danielk197739281b42008-10-17 19:13:04 +00001/*
drh27c3bd72008-10-28 18:12:36 +00002** 2008 October 7
danielk197739281b42008-10-17 19:13:04 +00003**
4** The author disclaims copyright to this source code. In place of
5** a legal notice, here is a blessing:
6**
7** May you do good and not evil.
8** May you find forgiveness for yourself and forgive others.
9** May you share freely, never taking more than you give.
10**
11*************************************************************************
12**
drh27c3bd72008-10-28 18:12:36 +000013** This file contains code use to implement an in-memory rollback journal.
14** The in-memory rollback journal is used to journal transactions for
15** ":memory:" databases and when the journal_mode=MEMORY pragma is used.
danielk197739281b42008-10-17 19:13:04 +000016*/
danielk197739281b42008-10-17 19:13:04 +000017#include "sqliteInt.h"
18
drh27c3bd72008-10-28 18:12:36 +000019/* Forward references to internal structures */
danielk197739281b42008-10-17 19:13:04 +000020typedef struct MemJournal MemJournal;
21typedef struct FilePoint FilePoint;
22typedef struct FileChunk FileChunk;
23
drh27c3bd72008-10-28 18:12:36 +000024/*
25** The rollback journal is composed of a linked list of these structures.
dan2491de22016-02-27 20:14:55 +000026**
27** The zChunk array is always at least 8 bytes in size - usually much more.
28** Its actual size is stored in the MemJournal.nChunkSize variable.
drh27c3bd72008-10-28 18:12:36 +000029*/
danielk197739281b42008-10-17 19:13:04 +000030struct FileChunk {
drh27c3bd72008-10-28 18:12:36 +000031 FileChunk *pNext; /* Next chunk in the journal */
dan2491de22016-02-27 20:14:55 +000032 u8 zChunk[8]; /* Content of this chunk */
danielk197739281b42008-10-17 19:13:04 +000033};
34
drh27c3bd72008-10-28 18:12:36 +000035/*
dan2491de22016-02-27 20:14:55 +000036** By default, allocate this many bytes of memory for each FileChunk object.
37*/
38#define MEMJOURNAL_DFLT_FILECHUNKSIZE 1024
39
40/*
41** For chunk size nChunkSize, return the number of bytes that should
42** be allocated for each FileChunk structure.
43*/
44#define fileChunkSize(nChunkSize) (sizeof(FileChunk) + ((nChunkSize)-8))
45
46/*
drh27c3bd72008-10-28 18:12:36 +000047** An instance of this object serves as a cursor into the rollback journal.
48** The cursor can be either for reading or writing.
49*/
danielk197739281b42008-10-17 19:13:04 +000050struct FilePoint {
drh27c3bd72008-10-28 18:12:36 +000051 sqlite3_int64 iOffset; /* Offset from the beginning of the file */
52 FileChunk *pChunk; /* Specific chunk into which cursor points */
danielk197739281b42008-10-17 19:13:04 +000053};
54
drh27c3bd72008-10-28 18:12:36 +000055/*
dan2491de22016-02-27 20:14:55 +000056** This structure is a subclass of sqlite3_file. Each open memory-journal
drh27c3bd72008-10-28 18:12:36 +000057** is an instance of this class.
58*/
danielk197739281b42008-10-17 19:13:04 +000059struct MemJournal {
dan2491de22016-02-27 20:14:55 +000060 const sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
61 int nChunkSize; /* In-memory chunk-size */
62
drhc2f18ad2016-03-05 15:35:09 +000063 int nSpill; /* Bytes of data before flushing */
dan2491de22016-02-27 20:14:55 +000064 int nSize; /* Bytes of data currently in memory */
danielk197739281b42008-10-17 19:13:04 +000065 FileChunk *pFirst; /* Head of in-memory chunk-list */
66 FilePoint endpoint; /* Pointer to the end of the file */
67 FilePoint readpoint; /* Pointer to the end of the last xRead() */
dan2491de22016-02-27 20:14:55 +000068
69 int flags; /* xOpen flags */
70 sqlite3_vfs *pVfs; /* The "real" underlying VFS */
71 const char *zJournal; /* Name of the journal file */
72 sqlite3_file *pReal; /* The "real" underlying file descriptor */
danielk197739281b42008-10-17 19:13:04 +000073};
74
75/*
drh2206a2b2009-04-01 23:09:43 +000076** Read data from the in-memory journal file. This is the implementation
77** of the sqlite3_vfs.xRead method.
danielk197739281b42008-10-17 19:13:04 +000078*/
79static int memjrnlRead(
80 sqlite3_file *pJfd, /* The journal file from which to read */
81 void *zBuf, /* Put the results here */
82 int iAmt, /* Number of bytes to read */
83 sqlite_int64 iOfst /* Begin reading at this offset */
84){
85 MemJournal *p = (MemJournal *)pJfd;
dan2491de22016-02-27 20:14:55 +000086 if( p->pReal ){
87 return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
88 }else if( (iAmt+iOfst)>p->endpoint.iOffset ){
89 return SQLITE_IOERR_SHORT_READ;
danielk197739281b42008-10-17 19:13:04 +000090 }else{
dan2491de22016-02-27 20:14:55 +000091 u8 *zOut = zBuf;
92 int nRead = iAmt;
93 int iChunkOffset;
94 FileChunk *pChunk;
danielk197739281b42008-10-17 19:13:04 +000095
dan2491de22016-02-27 20:14:55 +000096 if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
97 sqlite3_int64 iOff = 0;
98 for(pChunk=p->pFirst;
99 ALWAYS(pChunk) && (iOff+p->nChunkSize)<=iOfst;
100 pChunk=pChunk->pNext
101 ){
102 iOff += p->nChunkSize;
103 }
104 }else{
105 pChunk = p->readpoint.pChunk;
106 }
107
108 iChunkOffset = (int)(iOfst%p->nChunkSize);
109 do {
110 int iSpace = p->nChunkSize - iChunkOffset;
111 int nCopy = MIN(nRead, (p->nChunkSize - iChunkOffset));
drh65a7e762016-03-05 15:03:31 +0000112 memcpy(zOut, (u8*)pChunk->zChunk + iChunkOffset, nCopy);
dan2491de22016-02-27 20:14:55 +0000113 zOut += nCopy;
114 nRead -= iSpace;
115 iChunkOffset = 0;
116 } while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
117 p->readpoint.iOffset = iOfst+iAmt;
118 p->readpoint.pChunk = pChunk;
119 }
danielk197739281b42008-10-17 19:13:04 +0000120
121 return SQLITE_OK;
122}
123
124/*
dan2491de22016-02-27 20:14:55 +0000125** Free the list of FileChunk structures headed at MemJournal.pFirst.
126*/
127static void memjrnlFreeChunks(MemJournal *p){
128 FileChunk *pIter;
129 FileChunk *pNext;
130 for(pIter=p->pFirst; pIter; pIter=pNext){
131 pNext = pIter->pNext;
132 sqlite3_free(pIter);
133 }
134 p->pFirst = 0;
135}
136
137/*
138** Flush the contents of memory to a real file on disk.
139*/
drhc2f18ad2016-03-05 15:35:09 +0000140static int memjrnlCreateFile(MemJournal *p){
dan2491de22016-02-27 20:14:55 +0000141 int rc = SQLITE_OK;
142 if( !p->pReal ){
143 sqlite3_file *pReal = (sqlite3_file *)&p[1];
144 rc = sqlite3OsOpen(p->pVfs, p->zJournal, pReal, p->flags, 0);
145 if( rc==SQLITE_OK ){
146 int nChunk = p->nChunkSize;
147 i64 iOff = 0;
148 FileChunk *pIter;
149 p->pReal = pReal;
150 for(pIter=p->pFirst; pIter && rc==SQLITE_OK; pIter=pIter->pNext){
151 int nWrite = nChunk;
152 if( pIter==p->endpoint.pChunk ){
153 nWrite = p->endpoint.iOffset % p->nChunkSize;
154 if( nWrite==0 ) nWrite = p->nChunkSize;
155 }
drh65a7e762016-03-05 15:03:31 +0000156 rc = sqlite3OsWrite(pReal, (u8*)pIter->zChunk, nWrite, iOff);
dan2491de22016-02-27 20:14:55 +0000157 iOff += nWrite;
158 }
159 if( rc!=SQLITE_OK ){
160 /* If an error occurred while writing to the file, close it before
161 ** returning. This way, SQLite uses the in-memory journal data to
162 ** roll back changes made to the internal page-cache before this
163 ** function was called. */
164 sqlite3OsClose(pReal);
165 p->pReal = 0;
166 }else{
167 /* No error has occurred. Free the in-memory buffers. */
168 memjrnlFreeChunks(p);
169 }
170 }
171 }
172 return rc;
173}
174
175
176/*
danielk197739281b42008-10-17 19:13:04 +0000177** Write data to the file.
178*/
179static int memjrnlWrite(
180 sqlite3_file *pJfd, /* The journal file into which to write */
181 const void *zBuf, /* Take data to be written from here */
182 int iAmt, /* Number of bytes to write */
183 sqlite_int64 iOfst /* Begin writing at this offset into the file */
184){
185 MemJournal *p = (MemJournal *)pJfd;
186 int nWrite = iAmt;
187 u8 *zWrite = (u8 *)zBuf;
188
dan2491de22016-02-27 20:14:55 +0000189 /* If the file has already been created on disk. */
190 if( p->pReal ){
191 return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
192 }
danielk197739281b42008-10-17 19:13:04 +0000193
dan2491de22016-02-27 20:14:55 +0000194 /* If the file should be created now. */
drhc2f18ad2016-03-05 15:35:09 +0000195 else if( p->nSpill>0 && (iAmt+iOfst)>p->nSpill ){
196 int rc = memjrnlCreateFile(p);
dan2491de22016-02-27 20:14:55 +0000197 if( rc==SQLITE_OK ){
198 rc = memjrnlWrite(pJfd, zBuf, iAmt, iOfst);
danielk197739281b42008-10-17 19:13:04 +0000199 }
dan2491de22016-02-27 20:14:55 +0000200 return rc;
201 }
danielk197739281b42008-10-17 19:13:04 +0000202
dan2491de22016-02-27 20:14:55 +0000203 /* If the contents of this write should be stored in memory */
204 else{
205 /* An in-memory journal file should only ever be appended to. Random
206 ** access writes are not required. The only exception to this is when
207 ** the in-memory journal is being used by a connection using the
208 ** atomic-write optimization. In this case the first 28 bytes of the
209 ** journal file may be written as part of committing the transaction. */
210 assert( iOfst==p->endpoint.iOffset || iOfst==0 );
211 if( iOfst==0 && p->pFirst ){
212 assert( p->nChunkSize>iAmt );
drh65a7e762016-03-05 15:03:31 +0000213 memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
dan2491de22016-02-27 20:14:55 +0000214 }else{
215 while( nWrite>0 ){
216 FileChunk *pChunk = p->endpoint.pChunk;
217 int iChunkOffset = (int)(p->endpoint.iOffset%p->nChunkSize);
218 int iSpace = MIN(nWrite, p->nChunkSize - iChunkOffset);
219
220 if( iChunkOffset==0 ){
221 /* New chunk is required to extend the file. */
222 FileChunk *pNew = sqlite3_malloc(fileChunkSize(p->nChunkSize));
223 if( !pNew ){
224 return SQLITE_IOERR_NOMEM_BKPT;
225 }
226 pNew->pNext = 0;
227 if( pChunk ){
228 assert( p->pFirst );
229 pChunk->pNext = pNew;
230 }else{
231 assert( !p->pFirst );
232 p->pFirst = pNew;
233 }
234 p->endpoint.pChunk = pNew;
235 }
236
drh65a7e762016-03-05 15:03:31 +0000237 memcpy((u8*)p->endpoint.pChunk->zChunk + iChunkOffset, zWrite, iSpace);
dan2491de22016-02-27 20:14:55 +0000238 zWrite += iSpace;
239 nWrite -= iSpace;
240 p->endpoint.iOffset += iSpace;
241 }
242 p->nSize = iAmt + iOfst;
243 }
danielk197739281b42008-10-17 19:13:04 +0000244 }
245
246 return SQLITE_OK;
247}
248
249/*
250** Truncate the file.
dan5f37ed52016-02-29 20:00:13 +0000251**
252** If the journal file is already on disk, truncate it there. Or, if it
253** is still in main memory but is being truncated to zero bytes in size,
254** ignore
danielk197739281b42008-10-17 19:13:04 +0000255*/
256static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
257 MemJournal *p = (MemJournal *)pJfd;
dan2491de22016-02-27 20:14:55 +0000258 if( p->pReal ){
259 return sqlite3OsTruncate(p->pReal, size);
260 }else if( size==0 ){
261 memjrnlFreeChunks(p);
262 p->nSize = 0;
263 p->endpoint.pChunk = 0;
264 p->endpoint.iOffset = 0;
265 p->readpoint.pChunk = 0;
266 p->readpoint.iOffset = 0;
danielk197739281b42008-10-17 19:13:04 +0000267 }
danielk197739281b42008-10-17 19:13:04 +0000268 return SQLITE_OK;
269}
270
271/*
272** Close the file.
273*/
274static int memjrnlClose(sqlite3_file *pJfd){
dan2491de22016-02-27 20:14:55 +0000275 MemJournal *p = (MemJournal *)pJfd;
276 memjrnlFreeChunks(p);
277 if( p->pReal ) sqlite3OsClose(p->pReal);
danielk197739281b42008-10-17 19:13:04 +0000278 return SQLITE_OK;
279}
280
danielk197739281b42008-10-17 19:13:04 +0000281/*
282** Sync the file.
drh2206a2b2009-04-01 23:09:43 +0000283**
dan2491de22016-02-27 20:14:55 +0000284** If the real file has been created, call its xSync method. Otherwise,
285** syncing an in-memory journal is a no-op.
danielk197739281b42008-10-17 19:13:04 +0000286*/
dan2491de22016-02-27 20:14:55 +0000287static int memjrnlSync(sqlite3_file *pJfd, int flags){
288 MemJournal *p = (MemJournal *)pJfd;
289 if( p->pReal ){
290 return sqlite3OsSync(p->pReal, flags);
291 }
drh09c0f6d2010-04-12 19:44:22 +0000292 return SQLITE_OK;
293}
danielk197739281b42008-10-17 19:13:04 +0000294
295/*
296** Query the size of the file in bytes.
297*/
298static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
299 MemJournal *p = (MemJournal *)pJfd;
dan2491de22016-02-27 20:14:55 +0000300 if( p->pReal ){
301 return sqlite3OsFileSize(p->pReal, pSize);
302 }
danielk197739281b42008-10-17 19:13:04 +0000303 *pSize = (sqlite_int64) p->endpoint.iOffset;
304 return SQLITE_OK;
305}
306
307/*
308** Table of methods for MemJournal sqlite3_file object.
309*/
drhf83dc1e2010-06-03 12:09:52 +0000310static const struct sqlite3_io_methods MemJournalMethods = {
danielk197739281b42008-10-17 19:13:04 +0000311 1, /* iVersion */
312 memjrnlClose, /* xClose */
313 memjrnlRead, /* xRead */
314 memjrnlWrite, /* xWrite */
315 memjrnlTruncate, /* xTruncate */
316 memjrnlSync, /* xSync */
317 memjrnlFileSize, /* xFileSize */
318 0, /* xLock */
319 0, /* xUnlock */
320 0, /* xCheckReservedLock */
321 0, /* xFileControl */
322 0, /* xSectorSize */
drhff828942010-06-26 21:34:06 +0000323 0, /* xDeviceCharacteristics */
drhff828942010-06-26 21:34:06 +0000324 0, /* xShmMap */
drh6e1f4822010-07-13 23:41:40 +0000325 0, /* xShmLock */
drhff828942010-06-26 21:34:06 +0000326 0, /* xShmBarrier */
drhda8caa02013-04-22 23:38:50 +0000327 0, /* xShmUnmap */
328 0, /* xFetch */
329 0 /* xUnfetch */
danielk197739281b42008-10-17 19:13:04 +0000330};
331
332/*
dan2491de22016-02-27 20:14:55 +0000333** Open a journal file.
334**
335** The behaviour of the journal file depends on the value of parameter
drhc2f18ad2016-03-05 15:35:09 +0000336** nSpill. If nSpill is 0, then the journal file is always create and
337** accessed using the underlying VFS. If nSpill is less than zero, then
338** all content is always stored in main-memory. Finally, if nSpill is a
dan2491de22016-02-27 20:14:55 +0000339** positive value, then the journal file is initially created in-memory
340** but may be flushed to disk later on. In this case the journal file is
drhc2f18ad2016-03-05 15:35:09 +0000341** flushed to disk either when it grows larger than nSpill bytes in size,
dan2491de22016-02-27 20:14:55 +0000342** or when sqlite3JournalCreate() is called.
danielk197739281b42008-10-17 19:13:04 +0000343*/
dan2491de22016-02-27 20:14:55 +0000344int sqlite3JournalOpen(
345 sqlite3_vfs *pVfs, /* The VFS to use for actual file I/O */
346 const char *zName, /* Name of the journal file */
347 sqlite3_file *pJfd, /* Preallocated, blank file handle */
348 int flags, /* Opening flags */
drhc2f18ad2016-03-05 15:35:09 +0000349 int nSpill /* Bytes buffered before opening the file */
dan2491de22016-02-27 20:14:55 +0000350){
351 MemJournal *p = (MemJournal*)pJfd;
352
drhc2f18ad2016-03-05 15:35:09 +0000353 /* Zero the file-handle object. If nSpill was passed zero, initialize
dan2491de22016-02-27 20:14:55 +0000354 ** it using the sqlite3OsOpen() function of the underlying VFS. In this
355 ** case none of the code in this module is executed as a result of calls
356 ** made on the journal file-handle. */
dan6e763262016-02-29 20:18:21 +0000357 memset(p, 0, sizeof(MemJournal) + (pVfs ? pVfs->szOsFile : 0));
drhc2f18ad2016-03-05 15:35:09 +0000358 if( nSpill==0 ){
dan2491de22016-02-27 20:14:55 +0000359 return sqlite3OsOpen(pVfs, zName, pJfd, flags, 0);
360 }
361
drhc2f18ad2016-03-05 15:35:09 +0000362 if( nSpill>0 ){
363 p->nChunkSize = nSpill;
dan2491de22016-02-27 20:14:55 +0000364 }else{
365 p->nChunkSize = 8 + MEMJOURNAL_DFLT_FILECHUNKSIZE - sizeof(FileChunk);
366 assert( MEMJOURNAL_DFLT_FILECHUNKSIZE==fileChunkSize(p->nChunkSize) );
367 }
368
369 p->pMethod = (const sqlite3_io_methods*)&MemJournalMethods;
drhc2f18ad2016-03-05 15:35:09 +0000370 p->nSpill = nSpill;
dan2491de22016-02-27 20:14:55 +0000371 p->flags = flags;
372 p->zJournal = zName;
373 p->pVfs = pVfs;
374 return SQLITE_OK;
danielk197739281b42008-10-17 19:13:04 +0000375}
376
377/*
dan2491de22016-02-27 20:14:55 +0000378** Open an in-memory journal file.
379*/
380void sqlite3MemJournalOpen(sqlite3_file *pJfd){
381 sqlite3JournalOpen(0, 0, pJfd, 0, -1);
382}
383
drhff6b8262016-03-04 00:13:29 +0000384#ifdef SQLITE_ENABLE_ATOMIC_WRITE
dan2491de22016-02-27 20:14:55 +0000385/*
dan2491de22016-02-27 20:14:55 +0000386** If the argument p points to a MemJournal structure that is not an
dan5f37ed52016-02-29 20:00:13 +0000387** in-memory-only journal file (i.e. is one that was opened with a +ve
drhc2f18ad2016-03-05 15:35:09 +0000388** nSpill parameter), and the underlying file has not yet been created,
dan5f37ed52016-02-29 20:00:13 +0000389** create it now.
dan2491de22016-02-27 20:14:55 +0000390*/
391int sqlite3JournalCreate(sqlite3_file *p){
392 int rc = SQLITE_OK;
drhc2f18ad2016-03-05 15:35:09 +0000393 if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
394 rc = memjrnlCreateFile((MemJournal*)p);
dan2491de22016-02-27 20:14:55 +0000395 }
396 return rc;
397}
drhff6b8262016-03-04 00:13:29 +0000398#endif
dan2491de22016-02-27 20:14:55 +0000399
400/*
dan5f37ed52016-02-29 20:00:13 +0000401** The file-handle passed as the only argument is open on a journal file.
402** Return true if this "journal file" is currently stored in heap memory,
dan2491de22016-02-27 20:14:55 +0000403** or false otherwise.
404*/
405int sqlite3JournalIsInMemory(sqlite3_file *p){
406 return p->pMethods==&MemJournalMethods && ((MemJournal*)p)->pReal==0;
danielk197739281b42008-10-17 19:13:04 +0000407}
408
409/*
dan2491de22016-02-27 20:14:55 +0000410** Return the number of bytes required to store a JournalFile that uses vfs
411** pVfs to create the underlying on-disk files.
danielk197739281b42008-10-17 19:13:04 +0000412*/
dan2491de22016-02-27 20:14:55 +0000413int sqlite3JournalSize(sqlite3_vfs *pVfs){
414 return pVfs->szOsFile + sizeof(MemJournal);
danielk197739281b42008-10-17 19:13:04 +0000415}