Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add tests for malloc() failure when the atomic-write optimization is being used. Also fix things so that rollback can occur without a malloc(), even if there is a master journal file. (CVS 4330) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
481fd3a89e50e329596d96565170e3d9 |
User & Date: | danielk1977 2007-08-30 08:08:17.000 |
Context
2007-08-30
| ||
08:27 | Fix a bug in a test file causing malloc5.test to crash. (CVS 4331) (check-in: ab09967bd2 user: danielk1977 tags: trunk) | |
08:08 | Add tests for malloc() failure when the atomic-write optimization is being used. Also fix things so that rollback can occur without a malloc(), even if there is a master journal file. (CVS 4330) (check-in: 481fd3a89e user: danielk1977 tags: trunk) | |
02:26 | Test case fixes for fulltest. (CVS 4329) (check-in: cddce49505 user: drh tags: trunk) | |
Changes
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.381 2007/08/30 08:08:17 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include <assert.h> #include <string.h> /* |
︙ | ︙ | |||
868 869 870 871 872 873 874 | #define pager_pagehash(X) 0 #define CHECK_PAGE(x) #endif /* ** When this is called the journal file for pager pPager must be open. ** The master journal file name is read from the end of the file and | | > > | > | > > | | | > > > > < < < < | < < > | | < | < < | 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | #define pager_pagehash(X) 0 #define CHECK_PAGE(x) #endif /* ** When this is called the journal file for pager pPager must be open. ** The master journal file name is read from the end of the file and ** written into memory supplied by the caller. ** ** zMaster must point to a buffer of at least nMaster bytes allocated by ** the caller. This should be sqlite3_vfs.mxPathname+1 (to ensure there is ** enough space to write the master journal name). If the master journal ** name in the journal is longer than nMaster bytes (including a ** nul-terminator), then this is handled as if no master journal name ** were present in the journal. ** ** If no master journal file name is present zMaster[0] is set to 0 and ** SQLITE_OK returned. */ static int readMasterJournal(sqlite3_file *pJrnl, char *zMaster, int nMaster){ int rc; u32 len; i64 szJ; u32 cksum; int i; unsigned char aMagic[8]; /* A buffer to hold the magic header */ zMaster[0] = '\0'; rc = sqlite3OsFileSize(pJrnl, &szJ); if( rc!=SQLITE_OK || szJ<16 ) return rc; rc = read32bits(pJrnl, szJ-16, &len); if( rc!=SQLITE_OK ) return rc; if( len>=nMaster ){ return SQLITE_OK; } rc = read32bits(pJrnl, szJ-12, &cksum); if( rc!=SQLITE_OK ) return rc; rc = sqlite3OsRead(pJrnl, aMagic, 8, szJ-8); if( rc!=SQLITE_OK || memcmp(aMagic, aJournalMagic, 8) ) return rc; rc = sqlite3OsRead(pJrnl, zMaster, len, szJ-16-len); if( rc!=SQLITE_OK ){ return rc; } zMaster[len] = '\0'; /* See if the checksum matches the master journal name */ for(i=0; i<len; i++){ cksum -= zMaster[i]; } if( cksum ){ /* If the checksum doesn't add up, then one or more of the disk sectors ** containing the master journal filename is corrupted. This means ** definitely roll back, so just return SQLITE_OK and report a (nul) ** master-journal filename. */ zMaster[0] = '\0'; } return SQLITE_OK; } /* ** Seek the journal file descriptor to the next sector boundary where a |
︙ | ︙ | |||
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 | } /* ** Parameter zMaster is the name of a master journal file. A single journal ** file that referred to the master journal file has just been rolled back. ** This routine checks if it is possible to delete the master journal file, ** and does so if it is. ** ** The master journal file contains the names of all child journals. ** To tell if a master journal can be deleted, check to each of the ** children. If all children are either missing or do not refer to ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(Pager *pPager, const char *zMaster){ | > > > > | 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 | } /* ** Parameter zMaster is the name of a master journal file. A single journal ** file that referred to the master journal file has just been rolled back. ** This routine checks if it is possible to delete the master journal file, ** and does so if it is. ** ** Argument zMaster may point to Pager.pTmpSpace. So that buffer is not ** available for use within this function. ** ** ** The master journal file contains the names of all child journals. ** To tell if a master journal can be deleted, check to each of the ** children. If all children are either missing or do not refer to ** a different master journal, then this master journal can be deleted. */ static int pager_delmaster(Pager *pPager, const char *zMaster){ |
︙ | ︙ | |||
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 | rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. */ | > | > | | < | 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 | rc = sqlite3OsFileSize(pMaster, &nMasterJournal); if( rc!=SQLITE_OK ) goto delmaster_out; if( nMasterJournal>0 ){ char *zJournal; char *zMasterPtr = 0; int nMasterPtr = pPager->pVfs->mxPathname+1; /* Load the entire master journal file into space obtained from ** sqlite3_malloc() and pointed to by zMasterJournal. */ zMasterJournal = (char *)sqlite3_malloc(nMasterJournal + nMasterPtr); if( !zMasterJournal ){ rc = SQLITE_NOMEM; goto delmaster_out; } zMasterPtr = &zMasterJournal[nMasterJournal]; rc = sqlite3OsRead(pMaster, zMasterJournal, nMasterJournal, 0); if( rc!=SQLITE_OK ) goto delmaster_out; zJournal = zMasterJournal; while( (zJournal-zMasterJournal)<nMasterJournal ){ if( sqlite3OsAccess(pVfs, zJournal, SQLITE_ACCESS_EXISTS) ){ /* One of the journals pointed to by the master journal exists. ** Open it and check if it points at the master journal. If ** so, return without deleting the master journal file. */ int c; int flags = (SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL); rc = sqlite3OsOpen(pVfs, zJournal, pJournal, flags, 0); if( rc!=SQLITE_OK ){ goto delmaster_out; } rc = readMasterJournal(pJournal, zMasterPtr, nMasterPtr); sqlite3OsClose(pJournal); if( rc!=SQLITE_OK ){ goto delmaster_out; } c = zMasterPtr[0]!=0 && strcmp(zMasterPtr, zMaster)==0; if( c ){ /* We have a match. Do not delete the master journal file. */ goto delmaster_out; } } zJournal += (strlen(zJournal)+1); } |
︙ | ︙ | |||
1694 1695 1696 1697 1698 1699 1700 | } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. */ | > | | < > | 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 | } /* Read the master journal name from the journal, if it is present. ** If a master journal file name is specified, but the file is not ** present on disk, then the journal is not hot and does not need to be ** played back. */ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK || (zMaster[0] && !sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS)) ){ zMaster = 0; if( rc==SQLITE_DONE ) rc = SQLITE_OK; goto end_playback; } pPager->journalOff = 0; zMaster = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ while( 1 ){ /* Read the next journal header from the journal file. If there are ** not enough bytes left in the journal file for a complete header, or |
︙ | ︙ | |||
1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 | } } } /*NOTREACHED*/ assert( 0 ); end_playback: if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager); } | > > > > | < | < < | 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 | } } } /*NOTREACHED*/ assert( 0 ); end_playback: if( rc==SQLITE_OK ){ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager); } if( rc==SQLITE_OK && zMaster[0] ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); } /* The Pager.sectorSize variable may have been updated while rolling ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ setSectorSize(pPager); |
︙ | ︙ |
Added test/mallocD.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | # 2007 Aug 29 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # # $Id: mallocD.test,v 1.1 2007/08/30 08:08:17 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl source $testdir/malloc_common.tcl sqlite3_simulate_device -char atomic set PREP { PRAGMA page_size = 1024; CREATE TABLE abc(a, b, c); } do_malloc_test mallocD-1 -sqlprep $PREP -sqlbody { INSERT INTO abc VALUES(1, 2, 3); } do_malloc_test mallocD-2 -sqlprep $PREP -sqlbody { BEGIN; INSERT INTO abc VALUES(1, 2, 3); INSERT INTO abc VALUES(4, 5, 6); ROLLBACK; } do_malloc_test mallocD-3 -sqlprep $PREP -sqlbody { BEGIN; INSERT INTO abc VALUES(1, 2, 3); INSERT INTO abc VALUES(4, 5, randstr(1500,1500)); COMMIT; } do_malloc_test mallocD-4 -sqlprep $PREP -sqlbody { ATTACH 'test2.db' AS aux; BEGIN; CREATE TABLE aux.def(d, e, f); INSERT INTO abc VALUES(4, 5, 6); COMMIT; } sqlite3_simulate_device -char {} finish_test |