Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | On a ROLLBACK, if there page cache entries which are dirty but not in the rollback journal, make sure they get reinitialized in the btree layer. (CVS 5936) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
faded96f36229ee85039276db693391d |
User & Date: | drh 2008-11-21 03:23:43.000 |
Context
2008-11-21
| ||
08:50 | Add another test case to tkt35xx.test showing that a statement rollback can also trigger the problem. (CVS 5937) (check-in: 74c08b8dd9 user: danielk1977 tags: trunk) | |
03:23 | On a ROLLBACK, if there page cache entries which are dirty but not in the rollback journal, make sure they get reinitialized in the btree layer. (CVS 5936) (check-in: faded96f36 user: drh tags: trunk) | |
00:24 | Fixes to the proxy locking so that os_unix.c compiles on linux with proxy locking omitted. (CVS 5935) (check-in: 6f910b7036 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.507 2008/11/21 03:23:43 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" /* ** Macros for troubleshooting. Normally turned off */ |
︙ | ︙ | |||
1057 1058 1059 1060 1061 1062 1063 | while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } | < < < | 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 | while( i>0 ){ cksum += aData[i]; i -= 200; } return cksum; } /* ** Read a single page from the journal file opened on file descriptor ** jfd. Playback this one page. ** ** The isMainJrnl flag is true if this is the main rollback journal and ** false for the statement journal. The main rollback journal uses ** checksums - the statement journal does not. |
︙ | ︙ | |||
1169 1170 1171 1172 1173 1174 1175 | */ void *pData; pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); if( pPager->xReiniter ){ pPager->xReiniter(pPg); } | | > > | 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 | */ void *pData; pData = pPg->pData; memcpy(pData, aData, pPager->pageSize); if( pPager->xReiniter ){ pPager->xReiniter(pPg); } if( isMainJrnl ){ sqlite3PcacheMakeClean(pPg); } #ifdef SQLITE_CHECK_PAGES pPg->pageHash = pager_pagehash(pPg); #endif /* If this was page 1, then restore the value of Pager.dbFileVers. ** Do this before any decoding. */ if( pgno==1 ){ memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers)); |
︙ | ︙ | |||
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | } } } /*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, zMaster[0]!='\0'); } | > > > > > > > > > > > > > > | 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 | } } } /*NOTREACHED*/ assert( 0 ); end_playback: /* There may be pages in cache that are dirty but which were not in ** the rollback journal. Such pages would have been taken out of the ** freelist (and hence marked as DontRollback). All such pages must ** be reinitialized. */ if( rc==SQLITE_OK && pPager->xReiniter ){ PgHdr *pDirty; /* List of page that are still dirty */ pDirty = sqlite3PcacheDirtyList(pPager->pPCache); while( pDirty ){ pPager->xReiniter(pDirty); sqlite3PcacheMakeClean(pDirty); pDirty = pDirty->pDirty; } } 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, zMaster[0]!='\0'); } |
︙ | ︙ | |||
3089 3090 3091 3092 3093 3094 3095 | pPager->origDbSize = pPager->dbSize; rc = writeJournalHdr(pPager); } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); return rc; } | < < < < < < < < < < < < < < < < < | 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 | pPager->origDbSize = pPager->dbSize; rc = writeJournalHdr(pPager); } } assert( !pPager->journalOpen || pPager->journalOff>0 || rc!=SQLITE_OK ); return rc; } /* ** Mark a data page as writeable. The page is written into the journal ** if it is not there already. This routine must be called before making ** changes to a page. ** ** The first time this routine is called, the pager creates a new |
︙ | ︙ | |||
3158 3159 3160 3161 3162 3163 3164 | if( rc ){ return rc; } /* Mark the page as dirty. If the page has already been written ** to the journal then we can return right away. */ | | | 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 | if( rc ){ return rc; } /* Mark the page as dirty. If the page has already been written ** to the journal then we can return right away. */ sqlite3PcacheMakeDirty(pPg); if( pageInJournal(pPg) && (pageInStatement(pPg) || pPager->stmtInUse==0) ){ pPager->dirtyCache = 1; pPager->dbModified = 1; }else{ /* If we get this far, it means that the page needs to be ** written to the transaction journal or the ckeckpoint journal |
︙ | ︙ | |||
4087 4088 4089 4090 4091 4092 4093 | } sqlite3PcacheMove(pPg, pgno); if( pPgOld ){ sqlite3PcacheDrop(pPgOld); } | | | 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 | } sqlite3PcacheMove(pPg, pgno); if( pPgOld ){ sqlite3PcacheDrop(pPgOld); } sqlite3PcacheMakeDirty(pPg); pPager->dirtyCache = 1; pPager->dbModified = 1; if( needSyncPgno ){ /* If needSyncPgno is non-zero, then the journal file needs to be ** sync()ed before any data is written to database file page needSyncPgno. ** Currently, no such page exists in the page-cache and the |
︙ | ︙ | |||
4122 4123 4124 4125 4126 4127 4128 | sqlite3BitvecClear(pPager->pInJournal, needSyncPgno); } return rc; } pPager->needSync = 1; assert( pPager->noSync==0 && !MEMDB ); pPgHdr->flags |= PGHDR_NEED_SYNC; | | | 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 | sqlite3BitvecClear(pPager->pInJournal, needSyncPgno); } return rc; } pPager->needSync = 1; assert( pPager->noSync==0 && !MEMDB ); pPgHdr->flags |= PGHDR_NEED_SYNC; sqlite3PcacheMakeDirty(pPgHdr); sqlite3PagerUnref(pPgHdr); } return SQLITE_OK; } #endif |
︙ | ︙ |
Added test/tkt35xx.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 | # 2008 November 20 # # 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. # #*********************************************************************** # This file implements regression tests for SQLite library. # # When a transaction rolls back, make sure that dirty pages in the # page cache which are not in the rollback journal are reinitialized # in the btree layer. # # $Id: tkt35xx.test,v 1.1 2008/11/21 03:23:43 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl do_test tkt35xx-1.1 { execsql { PRAGMA auto_vacuum = 0; CREATE TABLE t1(a,b,c); CREATE INDEX i1 ON t1(c); INSERT INTO t1 VALUES(0, 0, zeroblob(676)); INSERT INTO t1 VALUES(1, 1, zeroblob(676)); DELETE FROM t1; BEGIN; INSERT INTO t1 VALUES(0, 0, zeroblob(676)); INSERT INTO t1 VALUES(1, 1, zeroblob(676)); ROLLBACK; INSERT INTO t1 VALUES(0, 0, zeroblob(676)); } execsql { INSERT INTO t1 VALUES(1, 1, zeroblob(676)); } } {} |