OLD | NEW |
1 /* | 1 /* |
2 ** 2008 Jan 22 | 2 ** 2008 Jan 22 |
3 ** | 3 ** |
4 ** The author disclaims copyright to this source code. In place of | 4 ** The author disclaims copyright to this source code. In place of |
5 ** a legal notice, here is a blessing: | 5 ** a legal notice, here is a blessing: |
6 ** | 6 ** |
7 ** May you do good and not evil. | 7 ** May you do good and not evil. |
8 ** May you find forgiveness for yourself and forgive others. | 8 ** May you find forgiveness for yourself and forgive others. |
9 ** May you share freely, never taking more than you give. | 9 ** May you share freely, never taking more than you give. |
10 ** | 10 ** |
11 ****************************************************************************** | 11 ****************************************************************************** |
12 ** | 12 ** |
13 ** This file contains code for a VFS layer that acts as a wrapper around | 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 | 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 | 15 ** correctly populates and syncs a journal file before writing to a |
16 ** corresponding database file. | 16 ** corresponding database file. |
17 */ | 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 | 18 ** INTERFACE |
25 ** | 19 ** |
26 ** The public interface to this wrapper VFS is two functions: | 20 ** The public interface to this wrapper VFS is two functions: |
27 ** | 21 ** |
28 ** jt_register() | 22 ** jt_register() |
29 ** jt_unregister() | 23 ** jt_unregister() |
30 ** | 24 ** |
31 ** See header comments associated with those two functions below for | 25 ** See header comments associated with those two functions below for |
32 ** details. | 26 ** details. |
33 ** | 27 ** |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 ** discarded. The end of a transaction is recognized when any one | 86 ** discarded. The end of a transaction is recognized when any one |
93 ** of the following occur: | 87 ** of the following occur: |
94 ** | 88 ** |
95 ** a) A block of zeroes (or anything else that is not a valid | 89 ** 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. | 90 ** journal-header) is written to the start of the journal file. |
97 ** | 91 ** |
98 ** b) A journal file is truncated to zero bytes in size using xTruncate. | 92 ** b) A journal file is truncated to zero bytes in size using xTruncate. |
99 ** | 93 ** |
100 ** c) The journal file is deleted using xDelete. | 94 ** c) The journal file is deleted using xDelete. |
101 */ | 95 */ |
| 96 #if SQLITE_TEST /* This file is used for testing only */ |
| 97 |
| 98 #include "sqlite3.h" |
| 99 #include "sqliteInt.h" |
102 | 100 |
103 /* | 101 /* |
104 ** Maximum pathname length supported by the jt backend. | 102 ** Maximum pathname length supported by the jt backend. |
105 */ | 103 */ |
106 #define JT_MAX_PATHNAME 512 | 104 #define JT_MAX_PATHNAME 512 |
107 | 105 |
108 /* | 106 /* |
109 ** Name used to identify this VFS. | 107 ** Name used to identify this VFS. |
110 */ | 108 */ |
111 #define JT_VFS_NAME "jt" | 109 #define JT_VFS_NAME "jt" |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 ** | 283 ** |
286 ** b) The file-name specified when the file was opened matches | 284 ** b) The file-name specified when the file was opened matches |
287 ** all but the final 8 characters of the journal file name. | 285 ** all but the final 8 characters of the journal file name. |
288 ** | 286 ** |
289 ** c) There is currently a reserved lock on the file. | 287 ** c) There is currently a reserved lock on the file. |
290 **/ | 288 **/ |
291 static jt_file *locateDatabaseHandle(const char *zJournal){ | 289 static jt_file *locateDatabaseHandle(const char *zJournal){ |
292 jt_file *pMain = 0; | 290 jt_file *pMain = 0; |
293 enterJtMutex(); | 291 enterJtMutex(); |
294 for(pMain=g.pList; pMain; pMain=pMain->pNext){ | 292 for(pMain=g.pList; pMain; pMain=pMain->pNext){ |
295 int nName = strlen(zJournal) - strlen("-journal"); | 293 int nName = (int)(strlen(zJournal) - strlen("-journal")); |
296 if( (pMain->flags&SQLITE_OPEN_MAIN_DB) | 294 if( (pMain->flags&SQLITE_OPEN_MAIN_DB) |
297 && (strlen(pMain->zName)==nName) | 295 && ((int)strlen(pMain->zName)==nName) |
298 && 0==memcmp(pMain->zName, zJournal, nName) | 296 && 0==memcmp(pMain->zName, zJournal, nName) |
299 && (pMain->eLock>=SQLITE_LOCK_RESERVED) | 297 && (pMain->eLock>=SQLITE_LOCK_RESERVED) |
300 ){ | 298 ){ |
301 break; | 299 break; |
302 } | 300 } |
303 } | 301 } |
304 leaveJtMutex(); | 302 leaveJtMutex(); |
305 return pMain; | 303 return pMain; |
306 } | 304 } |
307 | 305 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
386 u32 iPg; | 384 u32 iPg; |
387 for(iPg=nDbsize+1; iPg<=pMain->nPage; iPg++){ | 385 for(iPg=nDbsize+1; iPg<=pMain->nPage; iPg++){ |
388 sqlite3BitvecSet(pMain->pWritable, iPg); | 386 sqlite3BitvecSet(pMain->pWritable, iPg); |
389 } | 387 } |
390 } | 388 } |
391 } | 389 } |
392 iTrunk = decodeUint32(&aData[32]); | 390 iTrunk = decodeUint32(&aData[32]); |
393 while( rc==SQLITE_OK && iTrunk>0 ){ | 391 while( rc==SQLITE_OK && iTrunk>0 ){ |
394 u32 nLeaf; | 392 u32 nLeaf; |
395 u32 iLeaf; | 393 u32 iLeaf; |
396 sqlite3_int64 iOff = (iTrunk-1)*pMain->nPagesize; | 394 sqlite3_int64 iOff = (i64)(iTrunk-1)*pMain->nPagesize; |
397 rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff); | 395 rc = sqlite3OsRead(p, aData, pMain->nPagesize, iOff); |
398 nLeaf = decodeUint32(&aData[4]); | 396 nLeaf = decodeUint32(&aData[4]); |
399 for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){ | 397 for(iLeaf=0; rc==SQLITE_OK && iLeaf<nLeaf; iLeaf++){ |
400 u32 pgno = decodeUint32(&aData[8+4*iLeaf]); | 398 u32 pgno = decodeUint32(&aData[8+4*iLeaf]); |
401 sqlite3BitvecSet(pMain->pWritable, pgno); | 399 sqlite3BitvecSet(pMain->pWritable, pgno); |
402 } | 400 } |
403 iTrunk = decodeUint32(aData); | 401 iTrunk = decodeUint32(aData); |
404 } | 402 } |
405 | 403 |
406 /* Calculate and store a checksum for each page in the database file. */ | 404 /* Calculate and store a checksum for each page in the database file. */ |
407 if( rc==SQLITE_OK ){ | 405 if( rc==SQLITE_OK ){ |
408 int ii; | 406 int ii; |
409 for(ii=0; rc==SQLITE_OK && ii<pMain->nPage; ii++){ | 407 for(ii=0; rc==SQLITE_OK && ii<(int)pMain->nPage; ii++){ |
410 i64 iOff = (i64)(pMain->nPagesize) * (i64)ii; | 408 i64 iOff = (i64)(pMain->nPagesize) * (i64)ii; |
411 if( iOff==PENDING_BYTE ) continue; | 409 if( iOff==PENDING_BYTE ) continue; |
412 rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff); | 410 rc = sqlite3OsRead(pMain->pReal, aData, pMain->nPagesize, iOff); |
413 pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize); | 411 pMain->aCksum[ii] = genCksum(aData, pMain->nPagesize); |
| 412 if( ii+1==pMain->nPage && rc==SQLITE_IOERR_SHORT_READ ) rc = SQLITE_OK; |
414 } | 413 } |
415 } | 414 } |
416 | 415 |
417 start_ioerr_simulation(iSave, iSave2); | 416 start_ioerr_simulation(iSave, iSave2); |
418 } | 417 } |
419 | 418 |
420 sqlite3_free(aData); | 419 sqlite3_free(aData); |
421 return rc; | 420 return rc; |
422 } | 421 } |
423 | 422 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 /* A trick. There might be another journal-header immediately | 459 /* A trick. There might be another journal-header immediately |
461 ** following this one. In this case, 0 records means 0 records, | 460 ** following this one. In this case, 0 records means 0 records, |
462 ** not "read until the end of the file". See also ticket #2565. | 461 ** not "read until the end of the file". See also ticket #2565. |
463 */ | 462 */ |
464 if( iSize>=(iOff+nSector) ){ | 463 if( iSize>=(iOff+nSector) ){ |
465 rc = sqlite3OsRead(pReal, zBuf, 28, iOff); | 464 rc = sqlite3OsRead(pReal, zBuf, 28, iOff); |
466 if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){ | 465 if( rc!=SQLITE_OK || 0==decodeJournalHdr(zBuf, 0, 0, 0, 0) ){ |
467 continue; | 466 continue; |
468 } | 467 } |
469 } | 468 } |
470 nRec = (iSize-iOff) / (pMain->nPagesize+8); | 469 nRec = (u32)((iSize-iOff) / (pMain->nPagesize+8)); |
471 } | 470 } |
472 | 471 |
473 /* Read all the records that follow the journal-header just read. */ | 472 /* Read all the records that follow the journal-header just read. */ |
474 for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){ | 473 for(ii=0; rc==SQLITE_OK && ii<nRec && iOff<iSize; ii++){ |
475 u32 pgno; | 474 u32 pgno; |
476 rc = sqlite3OsRead(pReal, zBuf, 4, iOff); | 475 rc = sqlite3OsRead(pReal, zBuf, 4, iOff); |
477 if( rc==SQLITE_OK ){ | 476 if( rc==SQLITE_OK ){ |
478 pgno = decodeUint32(zBuf); | 477 pgno = decodeUint32(zBuf); |
479 if( pgno>0 && pgno<=pMain->nPage ){ | 478 if( pgno>0 && pgno<=pMain->nPage ){ |
480 if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){ | 479 if( 0==sqlite3BitvecTest(pMain->pWritable, pgno) ){ |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 return rc; | 531 return rc; |
533 } | 532 } |
534 } | 533 } |
535 } | 534 } |
536 if( p->iMaxOff<(iOfst + iAmt) ){ | 535 if( p->iMaxOff<(iOfst + iAmt) ){ |
537 p->iMaxOff = iOfst + iAmt; | 536 p->iMaxOff = iOfst + iAmt; |
538 } | 537 } |
539 } | 538 } |
540 | 539 |
541 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ | 540 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ |
542 if( iAmt<p->nPagesize | 541 if( iAmt<(int)p->nPagesize |
543 && p->nPagesize%iAmt==0 | 542 && p->nPagesize%iAmt==0 |
544 && iOfst>=(PENDING_BYTE+512) | 543 && iOfst>=(PENDING_BYTE+512) |
545 && iOfst+iAmt<=PENDING_BYTE+p->nPagesize | 544 && iOfst+iAmt<=PENDING_BYTE+p->nPagesize |
546 ){ | 545 ){ |
547 /* No-op. This special case is hit when the backup code is copying a | 546 /* 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 | 547 ** 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 | 548 ** it needs to fill in the non-locking-region part of the original |
550 ** pending-byte page. | 549 ** pending-byte page. |
551 */ | 550 */ |
552 }else{ | 551 }else{ |
553 u32 pgno = iOfst/p->nPagesize + 1; | 552 u32 pgno = (u32)(iOfst/p->nPagesize + 1); |
554 assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); | 553 assert( (iAmt==1||iAmt==p->nPagesize) && ((iOfst+iAmt)%p->nPagesize)==0 ); |
555 assert( pgno<=p->nPage || p->nSync>0 ); | 554 assert( pgno<=p->nPage || p->nSync>0 ); |
556 assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); | 555 assert( pgno>p->nPage || sqlite3BitvecTest(p->pWritable, pgno) ); |
557 } | 556 } |
558 } | 557 } |
559 | 558 |
560 rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); | 559 rc = sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); |
561 if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ | 560 if( (p->flags&SQLITE_OPEN_MAIN_JOURNAL) && iAmt==12 ){ |
562 jt_file *pMain = locateDatabaseHandle(p->zName); | 561 jt_file *pMain = locateDatabaseHandle(p->zName); |
563 int rc2 = readJournalFile(p, pMain); | 562 int rc2 = readJournalFile(p, pMain); |
564 if( rc==SQLITE_OK ) rc = rc2; | 563 if( rc==SQLITE_OK ) rc = rc2; |
565 } | 564 } |
566 return rc; | 565 return rc; |
567 } | 566 } |
568 | 567 |
569 /* | 568 /* |
570 ** Truncate an jt-file. | 569 ** Truncate an jt-file. |
571 */ | 570 */ |
572 static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){ | 571 static int jtTruncate(sqlite3_file *pFile, sqlite_int64 size){ |
573 jt_file *p = (jt_file *)pFile; | 572 jt_file *p = (jt_file *)pFile; |
574 if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){ | 573 if( p->flags&SQLITE_OPEN_MAIN_JOURNAL && size==0 ){ |
575 /* Truncating a journal file. This is the end of a transaction. */ | 574 /* Truncating a journal file. This is the end of a transaction. */ |
576 jt_file *pMain = locateDatabaseHandle(p->zName); | 575 jt_file *pMain = locateDatabaseHandle(p->zName); |
577 closeTransaction(pMain); | 576 closeTransaction(pMain); |
578 } | 577 } |
579 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ | 578 if( p->flags&SQLITE_OPEN_MAIN_DB && p->pWritable ){ |
580 u32 pgno; | 579 u32 pgno; |
581 u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1); | 580 u32 locking_page = (u32)(PENDING_BYTE/p->nPagesize+1); |
582 for(pgno=size/p->nPagesize+1; pgno<=p->nPage; pgno++){ | 581 for(pgno=(u32)(size/p->nPagesize+1); pgno<=p->nPage; pgno++){ |
583 assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) ); | 582 assert( pgno==locking_page || sqlite3BitvecTest(p->pWritable, pgno) ); |
584 } | 583 } |
585 } | 584 } |
586 return sqlite3OsTruncate(p->pReal, size); | 585 return sqlite3OsTruncate(p->pReal, size); |
587 } | 586 } |
588 | 587 |
589 /* | 588 /* |
590 ** Sync an jt-file. | 589 ** Sync an jt-file. |
591 */ | 590 */ |
592 static int jtSync(sqlite3_file *pFile, int flags){ | 591 static int jtSync(sqlite3_file *pFile, int flags){ |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){ | 656 static int jtCheckReservedLock(sqlite3_file *pFile, int *pResOut){ |
658 jt_file *p = (jt_file *)pFile; | 657 jt_file *p = (jt_file *)pFile; |
659 return sqlite3OsCheckReservedLock(p->pReal, pResOut); | 658 return sqlite3OsCheckReservedLock(p->pReal, pResOut); |
660 } | 659 } |
661 | 660 |
662 /* | 661 /* |
663 ** File control method. For custom operations on an jt-file. | 662 ** File control method. For custom operations on an jt-file. |
664 */ | 663 */ |
665 static int jtFileControl(sqlite3_file *pFile, int op, void *pArg){ | 664 static int jtFileControl(sqlite3_file *pFile, int op, void *pArg){ |
666 jt_file *p = (jt_file *)pFile; | 665 jt_file *p = (jt_file *)pFile; |
667 return sqlite3OsFileControl(p->pReal, op, pArg); | 666 return p->pReal->pMethods->xFileControl(p->pReal, op, pArg); |
668 } | 667 } |
669 | 668 |
670 /* | 669 /* |
671 ** Return the sector-size in bytes for an jt-file. | 670 ** Return the sector-size in bytes for an jt-file. |
672 */ | 671 */ |
673 static int jtSectorSize(sqlite3_file *pFile){ | 672 static int jtSectorSize(sqlite3_file *pFile){ |
674 jt_file *p = (jt_file *)pFile; | 673 jt_file *p = (jt_file *)pFile; |
675 return sqlite3OsSectorSize(p->pReal); | 674 return sqlite3OsSectorSize(p->pReal); |
676 } | 675 } |
677 | 676 |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 } | 716 } |
718 return rc; | 717 return rc; |
719 } | 718 } |
720 | 719 |
721 /* | 720 /* |
722 ** Delete the file located at zPath. If the dirSync argument is true, | 721 ** Delete the file located at zPath. If the dirSync argument is true, |
723 ** ensure the file-system modifications are synced to disk before | 722 ** ensure the file-system modifications are synced to disk before |
724 ** returning. | 723 ** returning. |
725 */ | 724 */ |
726 static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ | 725 static int jtDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync){ |
727 int nPath = strlen(zPath); | 726 int nPath = (int)strlen(zPath); |
728 if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){ | 727 if( nPath>8 && 0==strcmp("-journal", &zPath[nPath-8]) ){ |
729 /* Deleting a journal file. The end of a transaction. */ | 728 /* Deleting a journal file. The end of a transaction. */ |
730 jt_file *pMain = locateDatabaseHandle(zPath); | 729 jt_file *pMain = locateDatabaseHandle(zPath); |
731 if( pMain ){ | 730 if( pMain ){ |
732 closeTransaction(pMain); | 731 closeTransaction(pMain); |
733 } | 732 } |
734 } | 733 } |
735 | 734 |
736 return sqlite3OsDelete(g.pVfs, zPath, dirSync); | 735 return sqlite3OsDelete(g.pVfs, zPath, dirSync); |
737 } | 736 } |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
849 } | 848 } |
850 | 849 |
851 /* | 850 /* |
852 ** Uninstall the jt VFS, if it is installed. | 851 ** Uninstall the jt VFS, if it is installed. |
853 */ | 852 */ |
854 void jt_unregister(void){ | 853 void jt_unregister(void){ |
855 sqlite3_vfs_unregister(&jt_vfs); | 854 sqlite3_vfs_unregister(&jt_vfs); |
856 } | 855 } |
857 | 856 |
858 #endif | 857 #endif |
OLD | NEW |