Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 859 lines (785 sloc) 26.477 kb
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
1 /*
2 ** 2008 Jan 22
3 **
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 **
13 ** This file contains code for a VFS layer that acts as a wrapper around
14 ** an existing VFS. The code in this file attempts to verify that SQLite
15 ** correctly populates and syncs a journal file before writing to a
16 ** corresponding database file.
17 */
18 #if SQLITE_TEST /* This file is used for testing only */
19
20 #include "sqlite3.h"
21 #include "sqliteInt.h"
22
23 /*
24 ** INTERFACE
25 **
26 ** The public interface to this wrapper VFS is two functions:
27 **
28 ** jt_register()
29 ** jt_unregister()
30 **
31 ** See header comments associated with those two functions below for
32 ** details.
33 **
34 ** LIMITATIONS
35 **
36 ** This wrapper will not work if "PRAGMA synchronous = off" is used.
37 **
38 ** OPERATION
39 **
40 ** Starting a Transaction:
41 **
42 ** When a write-transaction is started, the contents of the database is
43 ** inspected and the following data stored as part of the database file
44 ** handle (type struct jt_file):
45 **
46 ** a) The page-size of the database file.
47 ** b) The number of pages that are in the database file.
48 ** c) The set of page numbers corresponding to free-list leaf pages.
49 ** d) A check-sum for every page in the database file.
50 **
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
51 ** The start of a write-transaction is deemed to have occurred when a
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
52 ** 28-byte journal header is written to byte offset 0 of the journal
53 ** file.
54 **
55 ** Syncing the Journal File:
56 **
57 ** Whenever the xSync method is invoked to sync a journal-file, the
58 ** contents of the journal file are read. For each page written to
59 ** the journal file, a check-sum is calculated and compared to the
60 ** check-sum calculated for the corresponding database page when the
61 ** write-transaction was initialized. The success of the comparison
62 ** is assert()ed. So if SQLite has written something other than the
63 ** original content to the database file, an assert() will fail.
64 **
65 ** Additionally, the set of page numbers for which records exist in
66 ** the journal file is added to (unioned with) the set of page numbers
67 ** corresponding to free-list leaf pages collected when the
68 ** write-transaction was initialized. This set comprises the page-numbers
69 ** corresponding to those pages that SQLite may now safely modify.
70 **
71 ** Writing to the Database File:
72 **
73 ** When a block of data is written to a database file, the following
74 ** invariants are asserted:
75 **
76 ** a) That the block of data is an aligned block of page-size bytes.
77 **
78 ** b) That if the page being written did not exist when the
79 ** transaction was started (i.e. the database file is growing), then
80 ** the journal-file must have been synced at least once since
81 ** the start of the transaction.
82 **
83 ** c) That if the page being written did exist when the transaction
84 ** was started, then the page must have either been a free-list
85 ** leaf page at the start of the transaction, or else must have
86 ** been stored in the journal file prior to the most recent sync.
87 **
88 ** Closing a Transaction:
89 **
90 ** When a transaction is closed, all data collected at the start of
91 ** the transaction, or following an xSync of a journal-file, is
92 ** discarded. The end of a transaction is recognized when any one
93 ** of the following occur:
94 **
95 ** a) A block of zeroes (or anything else that is not a valid
96 ** journal-header) is written to the start of the journal file.
97 **
98 ** b) A journal file is truncated to zero bytes in size using xTruncate.
99 **
100 ** c) The journal file is deleted using xDelete.
101 */
102
103 /*
104 ** Maximum pathname length supported by the jt backend.
105 */
106 #define JT_MAX_PATHNAME 512
107
108 /*
109 ** Name used to identify this VFS.
110 */
111 #define JT_VFS_NAME "jt"
112
113 typedef struct jt_file jt_file;
114 struct jt_file {
115 sqlite3_file base;
116 const char *zName; /* Name of open file */
117 int flags; /* Flags the file was opened with */
118
119 /* The following are only used by database file file handles */
120 int eLock; /* Current lock held on the file */
121 u32 nPage; /* Size of file in pages when transaction started */
122 u32 nPagesize; /* Page size when transaction started */
123 Bitvec *pWritable; /* Bitvec of pages that may be written to the file */
124 u32 *aCksum; /* Checksum for first nPage pages */
125 int nSync; /* Number of times journal file has been synced */
126
127 /* Only used by journal file-handles */
128 sqlite3_int64 iMaxOff; /* Maximum offset written to this transaction */
129
130 jt_file *pNext; /* All files are stored in a linked list */
131 sqlite3_file *pReal; /* The file handle for the underlying vfs */
132 };
133
134 /*
135 ** Method declarations for jt_file.
136 */
137 static int jtClose(sqlite3_file*);
138 static int jtRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
139 static int jtWrite(sqlite3_file*,const void*,int iAmt, sqlite3_int64 iOfst);
140 static int jtTruncate(sqlite3_file*, sqlite3_int64 size);
141 static int jtSync(sqlite3_file*, int flags);
142 static int jtFileSize(sqlite3_file*, sqlite3_int64 *pSize);
143 static int jtLock(sqlite3_file*, int);
144 static int jtUnlock(sqlite3_file*, int);
145 static int jtCheckReservedLock(sqlite3_file*, int *);
146 static int jtFileControl(sqlite3_file*, int op, void *pArg);
147 static int jtSectorSize(sqlite3_file*);
148 static int jtDeviceCharacteristics(sqlite3_file*);
149
150 /*
151 ** Method declarations for jt_vfs.
152 */
153 static int jtOpen(sqlite3_vfs*, const char *, sqlite3_file*, int , int *);
154 static int jtDelete(sqlite3_vfs*, const char *zName, int syncDir);
155 static int jtAccess(sqlite3_vfs*, const char *zName, int flags, int *);
156 static int jtFullPathname(sqlite3_vfs*, const char *zName, int, char *zOut);
157 static void *jtDlOpen(sqlite3_vfs*, const char *zFilename);
158 static void jtDlError(sqlite3_vfs*, int nByte, char *zErrMsg);
159 static void (*jtDlSym(sqlite3_vfs*,void*, const char *zSymbol))(void);
160 static void jtDlClose(sqlite3_vfs*, void*);
161 static int jtRandomness(sqlite3_vfs*, int nByte, char *zOut);
162 static int jtSleep(sqlite3_vfs*, int microseconds);
163 static int jtCurrentTime(sqlite3_vfs*, double*);
7b63a4e Stephen Lombardo track 3.7.0
sjlombardo authored
164 static int jtCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
165
166 static sqlite3_vfs jt_vfs = {
7b63a4e Stephen Lombardo track 3.7.0
sjlombardo authored
167 2, /* iVersion */
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
168 sizeof(jt_file), /* szOsFile */
169 JT_MAX_PATHNAME, /* mxPathname */
170 0, /* pNext */
171 JT_VFS_NAME, /* zName */
172 0, /* pAppData */
173 jtOpen, /* xOpen */
174 jtDelete, /* xDelete */
175 jtAccess, /* xAccess */
176 jtFullPathname, /* xFullPathname */
177 jtDlOpen, /* xDlOpen */
178 jtDlError, /* xDlError */
179 jtDlSym, /* xDlSym */
180 jtDlClose, /* xDlClose */
181 jtRandomness, /* xRandomness */
182 jtSleep, /* xSleep */
7b63a4e Stephen Lombardo track 3.7.0
sjlombardo authored
183 jtCurrentTime, /* xCurrentTime */
184 0, /* xGetLastError */
185 jtCurrentTimeInt64 /* xCurrentTimeInt64 */
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
186 };
187
188 static sqlite3_io_methods jt_io_methods = {
189 1, /* iVersion */
190 jtClose, /* xClose */
191 jtRead, /* xRead */
192 jtWrite, /* xWrite */
193 jtTruncate, /* xTruncate */
194 jtSync, /* xSync */
195 jtFileSize, /* xFileSize */
196 jtLock, /* xLock */
197 jtUnlock, /* xUnlock */
198 jtCheckReservedLock, /* xCheckReservedLock */
199 jtFileControl, /* xFileControl */
200 jtSectorSize, /* xSectorSize */
201 jtDeviceCharacteristics /* xDeviceCharacteristics */
202 };
203
204 struct JtGlobal {
205 sqlite3_vfs *pVfs; /* Parent VFS */
206 jt_file *pList; /* List of all open files */
207 };
208 static struct JtGlobal g = {0, 0};
209
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
210 /*
211 ** Functions to obtain and relinquish a mutex to protect g.pList. The
212 ** STATIC_PRNG mutex is reused, purely for the sake of convenience.
213 */
214 static void enterJtMutex(void){
215 sqlite3_mutex_enter(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
216 }
217 static void leaveJtMutex(void){
218 sqlite3_mutex_leave(sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_PRNG));
219 }
220
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
221 extern int sqlite3_io_error_pending;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
222 extern int sqlite3_io_error_hit;
223 static void stop_ioerr_simulation(int *piSave, int *piSave2){
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
224 *piSave = sqlite3_io_error_pending;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
225 *piSave2 = sqlite3_io_error_hit;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
226 sqlite3_io_error_pending = -1;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
227 sqlite3_io_error_hit = 0;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
228 }
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
229 static void start_ioerr_simulation(int iSave, int iSave2){
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
230 sqlite3_io_error_pending = iSave;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
231 sqlite3_io_error_hit = iSave2;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
232 }
233
234 /*
235 ** The jt_file pointed to by the argument may or may not be a file-handle
236 ** open on a main database file. If it is, and a transaction is currently
237 ** opened on the file, then discard all transaction related data.
238 */
239 static void closeTransaction(jt_file *p){
240 sqlite3BitvecDestroy(p->pWritable);
241 sqlite3_free(p->aCksum);
242 p->pWritable = 0;
243 p->aCksum = 0;
244 p->nSync = 0;
245 }
246
247 /*
248 ** Close an jt-file.
249 */
250 static int jtClose(sqlite3_file *pFile){
251 jt_file **pp;
252 jt_file *p = (jt_file *)pFile;
253
254 closeTransaction(p);
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
255 enterJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
256 if( p->zName ){
257 for(pp=&g.pList; *pp!=p; pp=&(*pp)->pNext);
258 *pp = p->pNext;
259 }
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
260 leaveJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
261 return sqlite3OsClose(p->pReal);
262 }
263
264 /*
265 ** Read data from an jt-file.
266 */
267 static int jtRead(
268 sqlite3_file *pFile,
269 void *zBuf,
270 int iAmt,
271 sqlite_int64 iOfst
272 ){
273 jt_file *p = (jt_file *)pFile;
274 return sqlite3OsRead(p->pReal, zBuf, iAmt, iOfst);
275 }
276
277 /*
278 ** Parameter zJournal is the name of a journal file that is currently
279 ** open. This function locates and returns the handle opened on the
280 ** corresponding database file by the pager that currently has the
281 ** journal file opened. This file-handle is identified by the
282 ** following properties:
283 **
284 ** a) SQLITE_OPEN_MAIN_DB was specified when the file was opened.
285 **
286 ** b) The file-name specified when the file was opened matches
287 ** all but the final 8 characters of the journal file name.
288 **
289 ** c) There is currently a reserved lock on the file.
290 **/
291 static jt_file *locateDatabaseHandle(const char *zJournal){
292 jt_file *pMain = 0;
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
293 enterJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
294 for(pMain=g.pList; pMain; pMain=pMain->pNext){
295 int nName = strlen(zJournal) - strlen("-journal");
296 if( (pMain->flags&SQLITE_OPEN_MAIN_DB)
297 && (strlen(pMain->zName)==nName)
298 && 0==memcmp(pMain->zName, zJournal, nName)
299 && (pMain->eLock>=SQLITE_LOCK_RESERVED)
300 ){
301 break;
302 }
303 }
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
304 leaveJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
305 return pMain;
306 }
307
308 /*
309 ** Parameter z points to a buffer of 4 bytes in size containing a
310 ** unsigned 32-bit integer stored in big-endian format. Decode the
311 ** integer and return its value.
312 */
313 static u32 decodeUint32(const unsigned char *z){
314 return (z[0]<<24) + (z[1]<<16) + (z[2]<<8) + z[3];
315 }
316
317 /*
318 ** Calculate a checksum from the buffer of length n bytes pointed to
319 ** by parameter z.
320 */
321 static u32 genCksum(const unsigned char *z, int n){
322 int i;
323 u32 cksum = 0;
324 for(i=0; i<n; i++){
325 cksum = cksum + z[i] + (cksum<<3);
326 }
327 return cksum;
328 }
329
330 /*
331 ** The first argument, zBuf, points to a buffer containing a 28 byte
332 ** serialized journal header. This function deserializes four of the
333 ** integer fields contained in the journal header and writes their
334 ** values to the output variables.
335 **
336 ** SQLITE_OK is returned if the journal-header is successfully
337 ** decoded. Otherwise, SQLITE_ERROR.
338 */
339 static int decodeJournalHdr(
340 const unsigned char *zBuf, /* Input: 28 byte journal header */
341 u32 *pnRec, /* Out: Number of journalled records */
342 u32 *pnPage, /* Out: Original database page count */
343 u32 *pnSector, /* Out: Sector size in bytes */
344 u32 *pnPagesize /* Out: Page size in bytes */
345 ){
346 unsigned char aMagic[] = { 0xd9, 0xd5, 0x05, 0xf9, 0x20, 0xa1, 0x63, 0xd7 };
347 if( memcmp(aMagic, zBuf, 8) ) return SQLITE_ERROR;
348 if( pnRec ) *pnRec = decodeUint32(&zBuf[8]);
349 if( pnPage ) *pnPage = decodeUint32(&zBuf[16]);
350 if( pnSector ) *pnSector = decodeUint32(&zBuf[20]);
351 if( pnPagesize ) *pnPagesize = decodeUint32(&zBuf[24]);
352 return SQLITE_OK;
353 }
354
355 /*
356 ** This function is called when a new transaction is opened, just after
357 ** the first journal-header is written to the journal file.
358 */
359 static int openTransaction(jt_file *pMain, jt_file *pJournal){
360 unsigned char *aData;
361 sqlite3_file *p = pMain->pReal;
362 int rc = SQLITE_OK;
363
92bc322 Stephen Lombardo track 3.7.2
sjlombardo authored
364 closeTransaction(pMain);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
365 aData = sqlite3_malloc(pMain->nPagesize);
366 pMain->pWritable = sqlite3BitvecCreate(pMain->nPage);
367 pMain->aCksum = sqlite3_malloc(sizeof(u32) * (pMain->nPage + 1));
368 pJournal->iMaxOff = 0;
369
370 if( !pMain->pWritable || !pMain->aCksum || !aData ){
371 rc = SQLITE_IOERR_NOMEM;
372 }else if( pMain->nPage>0 ){
373 u32 iTrunk;
374 int iSave;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
375 int iSave2;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
376
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
377 stop_ioerr_simulation(&iSave, &iSave2);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
378
379 /* Read the database free-list. Add the page-number for each free-list
380 ** leaf to the jt_file.pWritable bitvec.
381 */
382 rc = sqlite3OsRead(p, aData, pMain->nPagesize, 0);
92bc322 Stephen Lombardo track 3.7.2
sjlombardo authored
383 if( rc==SQLITE_OK ){
384 u32 nDbsize = decodeUint32(&aData[28]);
385 if( nDbsize>0 && memcmp(&aData[24], &aData[92], 4)==0 ){
386 u32 iPg;
387 for(iPg=nDbsize+1; iPg<=pMain->nPage; iPg++){
388 sqlite3BitvecSet(pMain->pWritable, iPg);
389 }
390 }
391 }
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
392 iTrunk = decodeUint32(&aData[32]);
393 while( rc==SQLITE_OK && iTrunk>0 ){
394 u32 nLeaf;
395 u32 iLeaf;
396 sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize;
397 rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff);
398 nLeaf = decodeUint32(&aData[4]);
399 for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){
400 u32 pgno = decodeUint32(&aData[8+4*iLeaf]);
401 sqlite3BitvecSet(pMain->pWritable, pgno);
402 }
403 iTrunk = decodeUint32(aData);
404 }
405
406 /* Calculate and store a checksum for each page in the database file. */
407 if( rc==SQLITE_OK ){
408 int ii;
409 for(ii=0; rc==SQLITE_OK && ii<pMain->nPage; ii++){
410 i64 iOff = (i64)(pMain->nPagesize) * (i64)ii;
411 if( iOff==PENDING_BYTE ) continue;
412 rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff);
413 pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize);
414 }
415 }
416
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
417 start_ioerr_simulation(iSave, iSave2);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
418 }
419
420 sqlite3_free(aData);
421 return rc;
422 }
423
424 /*
425 ** The first argument to this function is a handle open on a journal file.
426 ** This function reads the journal file and adds the page number for each
427 ** page in the journal to the Bitvec object passed as the second argument.
428 */
429 static int readJournalFile(jt_file *p, jt_file *pMain){
430 int rc = SQLITE_OK;
431 unsigned char zBuf[28];
432 sqlite3_file *pReal = p->pReal;
433 sqlite3_int64 iOff = 0;
434 sqlite3_int64 iSize = p->iMaxOff;
435 unsigned char *aPage;
436 int iSave;
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
437 int iSave2;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
438
439 aPage = sqlite3_malloc(pMain->nPagesize);
440 if( !aPage ){
441 return SQLITE_IOERR_NOMEM;
442 }
443
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
444 stop_ioerr_simulation(&iSave, &iSave2);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
445
446 while( rc==SQLITE_OK && iOff<iSize ){
447 u32 nRec, nPage, nSector, nPagesize;
448 u32 ii;
449
450 /* Read and decode the next journal-header from the journal file. */
451 rc = sqlite3OsRead(pReal, zBuf, 28, iOff);
452 if( rc!=SQLITE_OK
453 || decodeJournalHdr(zBuf, &nRec, &nPage, &nSector, &nPagesize)
454 ){
455 goto finish_rjf;
456 }
457 iOff += nSector;
458
459 if( nRec==0 ){
460 /* A trick. There might be another journal-header immediately
461 ** following this one. In this case, 0 records means 0 records,
462 ** not "read until the end of the file". See also ticket #2565.
463 */
464 if( iSize>=(iOff+nSector) ){
465 rc = sqlite3OsRead(pReal, zBuf, 28, iOff);
466 if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){
467 continue;
468 }
469 }
470 nRec = (iSize-iOff) / (pMain->nPagesize+8);
471 }
472
473 /* Read all the records that follow the journal-header just read. */
474 for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){
475 u32 pgno;
476 rc = sqlite3OsRead(pReal, zBuf, 4, iOff);
477 if( rc==SQLITE_OK ){
478 pgno = decodeUint32(zBuf);
479 if( pgno>0 && pgno<=pMain->nPage ){
480 if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){
481 rc = sqlite3OsRead(pReal, aPage, pMain->nPagesize, iOff+4);
482 if( rc==SQLITE_OK ){
483 u32 cksum = genCksum(aPage, pMain->nPagesize);
484 assert( cksum==pMain->aCksum[pgno-1] );
485 }
486 }
487 sqlite3BitvecSet(pMain->pWritable, pgno);
488 }
489 iOff += (8 + pMain->nPagesize);
490 }
491 }
492
493 iOff = ((iOff + (nSector-1)) / nSector) * nSector;
494 }
495
496 finish_rjf:
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
497 start_ioerr_simulation(iSave, iSave2);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
498 sqlite3_free(aPage);
499 if( rc==SQLITE_IOERR_SHORT_READ ){
500 rc = SQLITE_OK;
501 }
502 return rc;
503 }
504
db1d641 Stephen Lombardo update to upstream sqlite 3.6.17
sjlombardo authored
505 /*
506 ** Write data to an jt-file.
507 */
508 static int jtWrite(
509 sqlite3_file *pFile,
510 const void *zBuf,
511 int iAmt,
512 sqlite_int64 iOfst
513 ){
514 int rc;
515 jt_file *p = (jt_file *)pFile;
516 if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
517 if( iOfst==0 ){
518 jt_file *pMain = locateDatabaseHandle(p->zName);
519 assert( pMain );
520
521 if( iAmt==28 ){
522 /* Zeroing the first journal-file header. This is the end of a
523 ** transaction. */
524 closeTransaction(pMain);
525 }else if( iAmt!=12 ){
526 /* Writing the first journal header to a journal file. This happens
527 ** when a transaction is first started. */
528 u8 *z = (u8 *)zBuf;
529 pMain->nPage = decodeUint32(&z[16]);
530 pMain->nPagesize = decodeUint32(&z[24]);
531 if( SQLITE_OK!=(rc=openTransaction(pMain, p)) ){
532 return rc;
533 }
534 }
535 }
536 if( p->iMaxOff<(iOfst + iAmt) ){
537 p->iMaxOff = iOfst + iAmt;
538 }
539 }
540
541 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
542 if( iAmt<p->nPagesize
543 && p->nPagesize%iAmt==0
544 && iOfst>=(PENDING_BYTE+512)
545 && iOfst+iAmt<=PENDING_BYTE+p->nPagesize
546 ){
547 /* No-op. This special case is hit when the backup code is copying a
548 ** to a database with a larger page-size than the source database and
549 ** it needs to fill in the non-locking-region part of the original
550 ** pending-byte page.
551 */
552 }else{
553 u32 pgno = iOfst/p->nPagesize + 1;
554 assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 );
555 assert( pgno<=p->nPage || p->nSync>0 );
556 assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) );
557 }
558 }
559
560 rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
561 if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){
562 jt_file *pMain = locateDatabaseHandle(p->zName);
563 int rc2 = readJournalFile(p, pMain);
564 if( rc==SQLITE_OK ) rc = rc2;
565 }
566 return rc;
567 }
568
569 /*
570 ** Truncate an jt-file.
571 */
572 static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){
573 jt_file *p = (jt_file *)pFile;
574 if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){
575 /* Truncating a journal file. This is the end of a transaction. */
576 jt_file *pMain = locateDatabaseHandle(p->zName);
577 closeTransaction(pMain);
578 }
579 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){
580 u32 pgno;
581 u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1);
582 for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){
583 assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) );
584 }
585 }
586 return sqlite3OsTruncate(p->pReal, size);
587 }
588
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
589 /*
590 ** Sync an jt-file.
591 */
592 static int jtSync(sqlite3_file *pFile, int flags){
593 jt_file *p = (jt_file *)pFile;
594
595 if( p->flags&SQLITE_OPEN_MAIN_JOURNAL ){
596 int rc;
597 jt_file *pMain; /* The associated database file */
598
599 /* The journal file is being synced. At this point, we inspect the
600 ** contents of the file up to this point and set each bit in the
601 ** jt_file.pWritable bitvec of the main database file associated with
602 ** this journal file.
603 */
604 pMain = locateDatabaseHandle(p->zName);
605 assert(pMain);
606
607 /* Set the bitvec values */
608 if( pMain->pWritable ){
609 pMain->nSync++;
610 rc = readJournalFile(p, pMain);
611 if( rc!=SQLITE_OK ){
612 return rc;
613 }
614 }
615 }
616
617 return sqlite3OsSync(p->pReal, flags);
618 }
619
620 /*
621 ** Return the current file-size of an jt-file.
622 */
623 static int jtFileSize(sqlite3_file *pFile, sqlite_int64 *pSize){
624 jt_file *p = (jt_file *)pFile;
625 return sqlite3OsFileSize(p->pReal, pSize);
626 }
627
628 /*
629 ** Lock an jt-file.
630 */
631 static int jtLock(sqlite3_file *pFile, int eLock){
632 int rc;
633 jt_file *p = (jt_file *)pFile;
634 rc = sqlite3OsLock(p->pReal, eLock);
635 if( rc==SQLITE_OK && eLock>p->eLock ){
636 p->eLock = eLock;
637 }
638 return rc;
639 }
640
641 /*
642 ** Unlock an jt-file.
643 */
644 static int jtUnlock(sqlite3_file *pFile, int eLock){
645 int rc;
646 jt_file *p = (jt_file *)pFile;
647 rc = sqlite3OsUnlock(p->pReal, eLock);
648 if( rc==SQLITE_OK && eLock<p->eLock ){
649 p->eLock = eLock;
650 }
651 return rc;
652 }
653
654 /*
655 ** Check if another file-handle holds a RESERVED lock on an jt-file.
656 */
657 static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){
658 jt_file *p = (jt_file *)pFile;
659 return sqlite3OsCheckReservedLock(p->pReal, pResOut);
660 }
661
662 /*
663 ** File control method. For custom operations on an jt-file.
664 */
665 static int jtFileControl(sqlite3_file *pFile, int op, void *pArg){
666 jt_file *p = (jt_file *)pFile;
667 return sqlite3OsFileControl(p->pReal, op, pArg);
668 }
669
670 /*
671 ** Return the sector-size in bytes for an jt-file.
672 */
673 static int jtSectorSize(sqlite3_file *pFile){
674 jt_file *p = (jt_file *)pFile;
675 return sqlite3OsSectorSize(p->pReal);
676 }
677
678 /*
679 ** Return the device characteristic flags supported by an jt-file.
680 */
681 static int jtDeviceCharacteristics(sqlite3_file *pFile){
682 jt_file *p = (jt_file *)pFile;
683 return sqlite3OsDeviceCharacteristics(p->pReal);
684 }
685
686 /*
687 ** Open an jt file handle.
688 */
689 static int jtOpen(
690 sqlite3_vfs *pVfs,
691 const char *zName,
692 sqlite3_file *pFile,
693 int flags,
694 int *pOutFlags
695 ){
696 int rc;
697 jt_file *p = (jt_file *)pFile;
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
698 pFile->pMethods = 0;
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
699 p->pReal = (sqlite3_file *)&p[1];
700 p->pReal->pMethods = 0;
701 rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
702 assert( rc==SQLITE_OK || p->pReal->pMethods==0 );
703 if( rc==SQLITE_OK ){
704 pFile->pMethods = &jt_io_methods;
705 p->eLock = 0;
706 p->zName = zName;
707 p->flags = flags;
708 p->pNext = 0;
709 p->pWritable = 0;
710 p->aCksum = 0;
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
711 enterJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
712 if( zName ){
713 p->pNext = g.pList;
714 g.pList = p;
715 }
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
716 leaveJtMutex();
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
717 }
718 return rc;
719 }
720
721 /*
722 ** Delete the file located at zPath. If the dirSync argument is true,
723 ** ensure the file-system modifications are synced to disk before
724 ** returning.
725 */
726 static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){
727 int nPath = strlen(zPath);
728 if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){
729 /* Deleting a journal file. The end of a transaction. */
730 jt_file *pMain = locateDatabaseHandle(zPath);
731 if( pMain ){
732 closeTransaction(pMain);
733 }
734 }
735
736 return sqlite3OsDelete(g.pVfs, zPath, dirSync);
737 }
738
739 /*
740 ** Test for access permissions. Return true if the requested permission
741 ** is available, or false otherwise.
742 */
743 static int jtAccess(
744 sqlite3_vfs *pVfs,
745 const char *zPath,
746 int flags,
747 int *pResOut
748 ){
749 return sqlite3OsAccess(g.pVfs, zPath, flags, pResOut);
750 }
751
752 /*
753 ** Populate buffer zOut with the full canonical pathname corresponding
754 ** to the pathname in zPath. zOut is guaranteed to point to a buffer
755 ** of at least (JT_MAX_PATHNAME+1) bytes.
756 */
757 static int jtFullPathname(
758 sqlite3_vfs *pVfs,
759 const char *zPath,
760 int nOut,
761 char *zOut
762 ){
763 return sqlite3OsFullPathname(g.pVfs, zPath, nOut, zOut);
764 }
765
766 /*
767 ** Open the dynamic library located at zPath and return a handle.
768 */
769 static void *jtDlOpen(sqlite3_vfs *pVfs, const char *zPath){
770 return g.pVfs->xDlOpen(g.pVfs, zPath);
771 }
772
773 /*
774 ** Populate the buffer zErrMsg (size nByte bytes) with a human readable
775 ** utf-8 string describing the most recent error encountered associated
776 ** with dynamic libraries.
777 */
778 static void jtDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg){
779 g.pVfs->xDlError(g.pVfs, nByte, zErrMsg);
780 }
781
782 /*
783 ** Return a pointer to the symbol zSymbol in the dynamic library pHandle.
784 */
785 static void (*jtDlSym(sqlite3_vfs *pVfs, void *p, const char *zSym))(void){
786 return g.pVfs->xDlSym(g.pVfs, p, zSym);
787 }
788
789 /*
790 ** Close the dynamic library handle pHandle.
791 */
792 static void jtDlClose(sqlite3_vfs *pVfs, void *pHandle){
793 g.pVfs->xDlClose(g.pVfs, pHandle);
794 }
795
796 /*
797 ** Populate the buffer pointed to by zBufOut with nByte bytes of
798 ** random data.
799 */
800 static int jtRandomness(sqlite3_vfs *pVfs, int nByte, char *zBufOut){
801 return sqlite3OsRandomness(g.pVfs, nByte, zBufOut);
802 }
803
804 /*
805 ** Sleep for nMicro microseconds. Return the number of microseconds
806 ** actually slept.
807 */
808 static int jtSleep(sqlite3_vfs *pVfs, int nMicro){
809 return sqlite3OsSleep(g.pVfs, nMicro);
810 }
811
812 /*
813 ** Return the current time as a Julian Day number in *pTimeOut.
814 */
815 static int jtCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
7b63a4e Stephen Lombardo track 3.7.0
sjlombardo authored
816 return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
817 }
818 /*
819 ** Return the current time as a Julian Day number in *pTimeOut.
820 */
821 static int jtCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *pTimeOut){
822 return g.pVfs->xCurrentTimeInt64(g.pVfs, pTimeOut);
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
823 }
824
825 /**************************************************************************
826 ** Start of public API.
827 */
828
829 /*
830 ** Configure the jt VFS as a wrapper around the VFS named by parameter
831 ** zWrap. If the isDefault parameter is true, then the jt VFS is installed
832 ** as the new default VFS for SQLite connections. If isDefault is not
833 ** true, then the jt VFS is installed as non-default. In this case it
834 ** is available via its name, "jt".
835 */
836 int jt_register(char *zWrap, int isDefault){
837 g.pVfs = sqlite3_vfs_find(zWrap);
838 if( g.pVfs==0 ){
839 return SQLITE_ERROR;
840 }
841 jt_vfs.szOsFile = sizeof(jt_file) + g.pVfs->szOsFile;
7b63a4e Stephen Lombardo track 3.7.0
sjlombardo authored
842 if( g.pVfs->iVersion==1 ){
843 jt_vfs.iVersion = 1;
844 }else if( g.pVfs->xCurrentTimeInt64==0 ){
845 jt_vfs.xCurrentTimeInt64 = 0;
846 }
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
847 sqlite3_vfs_register(&jt_vfs, isDefault);
848 return SQLITE_OK;
849 }
850
851 /*
852 ** Uninstall the jt VFS, if it is installed.
853 */
81f606f Stephen Lombardo track 3.6.13
sjlombardo authored
854 void jt_unregister(void){
6e36436 Stephen Lombardo track sqlite 3.6.11
sjlombardo authored
855 sqlite3_vfs_unregister(&jt_vfs);
856 }
857
858 #endif
Something went wrong with that request. Please try again.