4
** The author disclaims copyright to this source code. In place of
5
** a legal notice, here is a blessing:
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.
11
*************************************************************************
13
** 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.
17
#include "sqliteInt.h"
19
/* Forward references to internal structures */
20
typedef struct MemJournal MemJournal;
21
typedef struct FilePoint FilePoint;
22
typedef struct FileChunk FileChunk;
24
/* Space to hold the rollback journal is allocated in increments of
27
** The size chosen is a little less than a power of two. That way,
28
** the FileChunk object will have a size that almost exactly fills
29
** a power-of-two allocation. This mimimizes wasted space in power-of-two
32
#define JOURNAL_CHUNKSIZE ((int)(1024-sizeof(FileChunk*)))
34
/* Macro to find the minimum of two numeric values.
37
# define MIN(x,y) ((x)<(y)?(x):(y))
41
** The rollback journal is composed of a linked list of these structures.
44
FileChunk *pNext; /* Next chunk in the journal */
45
u8 zChunk[JOURNAL_CHUNKSIZE]; /* Content of this chunk */
49
** An instance of this object serves as a cursor into the rollback journal.
50
** The cursor can be either for reading or writing.
53
sqlite3_int64 iOffset; /* Offset from the beginning of the file */
54
FileChunk *pChunk; /* Specific chunk into which cursor points */
58
** This subclass is a subclass of sqlite3_file. Each open memory-journal
59
** is an instance of this class.
62
sqlite3_io_methods *pMethod; /* Parent class. MUST BE FIRST */
63
FileChunk *pFirst; /* Head of in-memory chunk-list */
64
FilePoint endpoint; /* Pointer to the end of the file */
65
FilePoint readpoint; /* Pointer to the end of the last xRead() */
69
** Read data from the in-memory journal file. This is the implementation
70
** of the sqlite3_vfs.xRead method.
72
static int memjrnlRead(
73
sqlite3_file *pJfd, /* The journal file from which to read */
74
void *zBuf, /* Put the results here */
75
int iAmt, /* Number of bytes to read */
76
sqlite_int64 iOfst /* Begin reading at this offset */
78
MemJournal *p = (MemJournal *)pJfd;
84
/* SQLite never tries to read past the end of a rollback journal file */
85
assert( iOfst+iAmt<=p->endpoint.iOffset );
87
if( p->readpoint.iOffset!=iOfst || iOfst==0 ){
88
sqlite3_int64 iOff = 0;
90
ALWAYS(pChunk) && (iOff+JOURNAL_CHUNKSIZE)<=iOfst;
93
iOff += JOURNAL_CHUNKSIZE;
96
pChunk = p->readpoint.pChunk;
99
iChunkOffset = (int)(iOfst%JOURNAL_CHUNKSIZE);
101
int iSpace = JOURNAL_CHUNKSIZE - iChunkOffset;
102
int nCopy = MIN(nRead, (JOURNAL_CHUNKSIZE - iChunkOffset));
103
memcpy(zOut, &pChunk->zChunk[iChunkOffset], nCopy);
107
} while( nRead>=0 && (pChunk=pChunk->pNext)!=0 && nRead>0 );
108
p->readpoint.iOffset = iOfst+iAmt;
109
p->readpoint.pChunk = pChunk;
115
** Write data to the file.
117
static int memjrnlWrite(
118
sqlite3_file *pJfd, /* The journal file into which to write */
119
const void *zBuf, /* Take data to be written from here */
120
int iAmt, /* Number of bytes to write */
121
sqlite_int64 iOfst /* Begin writing at this offset into the file */
123
MemJournal *p = (MemJournal *)pJfd;
125
u8 *zWrite = (u8 *)zBuf;
127
/* An in-memory journal file should only ever be appended to. Random
128
** access writes are not required by sqlite.
130
assert( iOfst==p->endpoint.iOffset );
131
UNUSED_PARAMETER(iOfst);
134
FileChunk *pChunk = p->endpoint.pChunk;
135
int iChunkOffset = (int)(p->endpoint.iOffset%JOURNAL_CHUNKSIZE);
136
int iSpace = MIN(nWrite, JOURNAL_CHUNKSIZE - iChunkOffset);
138
if( iChunkOffset==0 ){
139
/* New chunk is required to extend the file. */
140
FileChunk *pNew = sqlite3_malloc(sizeof(FileChunk));
142
return SQLITE_IOERR_NOMEM;
147
pChunk->pNext = pNew;
149
assert( !p->pFirst );
152
p->endpoint.pChunk = pNew;
155
memcpy(&p->endpoint.pChunk->zChunk[iChunkOffset], zWrite, iSpace);
158
p->endpoint.iOffset += iSpace;
165
** Truncate the file.
167
static int memjrnlTruncate(sqlite3_file *pJfd, sqlite_int64 size){
168
MemJournal *p = (MemJournal *)pJfd;
171
UNUSED_PARAMETER(size);
174
FileChunk *pTmp = pChunk;
175
pChunk = pChunk->pNext;
178
sqlite3MemJournalOpen(pJfd);
185
static int memjrnlClose(sqlite3_file *pJfd){
186
memjrnlTruncate(pJfd, 0);
194
** Syncing an in-memory journal is a no-op. And, in fact, this routine
195
** is never called in a working implementation. This implementation
196
** exists purely as a contingency, in case some malfunction in some other
197
** part of SQLite causes Sync to be called by mistake.
199
static int memjrnlSync(sqlite3_file *NotUsed, int NotUsed2){ /*NO_TEST*/
200
UNUSED_PARAMETER2(NotUsed, NotUsed2); /*NO_TEST*/
201
assert( 0 ); /*NO_TEST*/
202
return SQLITE_OK; /*NO_TEST*/
206
** Query the size of the file in bytes.
208
static int memjrnlFileSize(sqlite3_file *pJfd, sqlite_int64 *pSize){
209
MemJournal *p = (MemJournal *)pJfd;
210
*pSize = (sqlite_int64) p->endpoint.iOffset;
215
** Table of methods for MemJournal sqlite3_file object.
217
static struct sqlite3_io_methods MemJournalMethods = {
219
memjrnlClose, /* xClose */
220
memjrnlRead, /* xRead */
221
memjrnlWrite, /* xWrite */
222
memjrnlTruncate, /* xTruncate */
223
memjrnlSync, /* xSync */
224
memjrnlFileSize, /* xFileSize */
227
0, /* xCheckReservedLock */
228
0, /* xFileControl */
230
0 /* xDeviceCharacteristics */
234
** Open a journal file.
236
void sqlite3MemJournalOpen(sqlite3_file *pJfd){
237
MemJournal *p = (MemJournal *)pJfd;
238
assert( EIGHT_BYTE_ALIGNMENT(p) );
239
memset(p, 0, sqlite3MemJournalSize());
240
p->pMethod = &MemJournalMethods;
244
** Return true if the file-handle passed as an argument is
245
** an in-memory journal
247
int sqlite3IsMemJournal(sqlite3_file *pJfd){
248
return pJfd->pMethods==&MemJournalMethods;
252
** Return the number of bytes required to store a MemJournal that uses vfs
253
** pVfs to create the underlying on-disk files.
255
int sqlite3MemJournalSize(void){
256
return sizeof(MemJournal);