| 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 |