Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Ensure a database file is not truncated without an exclusive lock. Fix for ticket #1114. (CVS 2332) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
dcbc983355d3207615b52b0724405a02 |
User & Date: | danielk1977 2005-02-15 03:38:06.000 |
Context
2005-02-15
| ||
12:51 | Update the homepage prior to releases 2.8.16 and 3.1.2. (CVS 2333) (check-in: 603bbe47dd user: drh tags: trunk) | |
03:38 | Ensure a database file is not truncated without an exclusive lock. Fix for ticket #1114. (CVS 2332) (check-in: dcbc983355 user: danielk1977 tags: trunk) | |
02:54 | Check that read-only pages are not being modified (disabled by default). (CVS 2331) (check-in: 8514a4feb2 user: danielk1977 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.190 2005/02/15 03:38:06 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" #include "pager.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 | } /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage); } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. ** | > | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 | } /* ** Truncate the main file of the given pager to the number of pages ** indicated. */ static int pager_truncate(Pager *pPager, int nPage){ assert( pPager->state>=PAGER_EXCLUSIVE ); return sqlite3OsTruncate(&pPager->fd, pPager->pageSize*(i64)nPage); } /* ** Playback the journal and thus restore the database file to ** the state it was in before we started making changes. ** |
︙ | ︙ | |||
1252 1253 1254 1255 1256 1257 1258 | assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } /* If this is the first header read from the journal, truncate the ** database file back to it's original size. */ | > | | 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 | assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } /* If this is the first header read from the journal, truncate the ** database file back to it's original size. */ if( pPager->state>=PAGER_EXCLUSIVE && pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ assert( pPager->origDbSize==0 || pPager->origDbSize==mxPg ); rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } pPager->dbSize = mxPg; } |
︙ | ︙ | |||
1350 1351 1352 1353 1354 1355 1356 | */ hdrOff = pPager->stmtHdrOff; assert( pPager->fullSync || !hdrOff ); if( !hdrOff ){ hdrOff = szJ; } | < > | > | 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 | */ hdrOff = pPager->stmtHdrOff; assert( pPager->fullSync || !hdrOff ); if( !hdrOff ){ hdrOff = szJ; } /* Truncate the database back to its original size. */ if( pPager->state>=PAGER_EXCLUSIVE ){ rc = pager_truncate(pPager, pPager->stmtSize); } pPager->dbSize = pPager->stmtSize; /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); sqlite3OsSeek(&pPager->stfd, 0); nRec = pPager->stmtNRec; |
︙ | ︙ | |||
1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 | pPager->nPage--; } } } #else #define memoryTruncate(p) #endif /* ** Truncate the file to the number of pages specified. */ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int rc; sqlite3pager_pagecount(pPager); | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 | pPager->nPage--; } } } #else #define memoryTruncate(p) #endif /* ** Try to obtain a lock on a file. Invoke the busy callback if the lock ** is currently not available. Repeate until the busy callback returns ** false or until the lock succeeds. ** ** Return SQLITE_OK on success and an error code if we cannot obtain ** the lock. */ static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ int busy = 1; do { rc = sqlite3OsLock(&pPager->fd, locktype); }while( rc==SQLITE_BUSY && pPager->pBusyHandler && pPager->pBusyHandler->xFunc && pPager->pBusyHandler->xFunc(pPager->pBusyHandler->pArg, busy++) ); if( rc==SQLITE_OK ){ pPager->state = locktype; } } return rc; } /* ** Truncate the file to the number of pages specified. */ int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int rc; sqlite3pager_pagecount(pPager); |
︙ | ︙ | |||
1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 | memoryTruncate(pPager); return SQLITE_OK; } rc = syncJournal(pPager); if( rc!=SQLITE_OK ){ return rc; } rc = pager_truncate(pPager, nPage); if( rc==SQLITE_OK ){ pPager->dbSize = nPage; } return rc; } | > > > > > > > | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 | memoryTruncate(pPager); return SQLITE_OK; } rc = syncJournal(pPager); if( rc!=SQLITE_OK ){ return rc; } /* Get an exclusive lock on the database before truncating. */ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); if( rc!=SQLITE_OK ){ return rc; } rc = pager_truncate(pPager, nPage); if( rc==SQLITE_OK ){ pPager->dbSize = nPage; } return rc; } |
︙ | ︙ | |||
2050 2051 2052 2053 2054 2055 2056 | for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } assert( pPager->pFirstSynced==pPager->pFirst ); } #endif | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 | for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){ assert( pPg->needSync==0 ); } assert( pPager->pFirstSynced==pPager->pFirst ); } #endif return rc; } /* ** Given a list of pages (connected by the PgHdr.pDirty pointer) write ** every one of those pages out to the database file and mark them all ** as clean. |
︙ | ︙ | |||
3068 3069 3070 3071 3072 3073 3074 | if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){ if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager); } return pager_errcode(pPager); } if( pPager->state==PAGER_RESERVED ){ | | < | < | 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 | if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){ if( pPager->state>=PAGER_EXCLUSIVE ){ pager_playback(pPager); } return pager_errcode(pPager); } if( pPager->state==PAGER_RESERVED ){ int rc2; rc = pager_reload_cache(pPager); rc2 = pager_unwritelock(pPager); if( rc==SQLITE_OK ){ rc = rc2; } }else{ rc = pager_playback(pPager); } if( rc!=SQLITE_OK ){ rc = SQLITE_CORRUPT; /* bkpt-CORRUPT */ pPager->errMask |= PAGER_ERR_CORRUPT; |
︙ | ︙ |