mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Fix for bug #94: Be sure to journal pages that are added to the freelist then
removed from the freelist and reused during the same transaction. (CVS 660) FossilOrigin-Name: db178646a01483d59e6f9af302e9bbe394956d93
This commit is contained in:
30
src/pager.c
30
src/pager.c
@@ -18,7 +18,7 @@
|
||||
** file simultaneously, or one process from reading the database while
|
||||
** another is writing.
|
||||
**
|
||||
** @(#) $Id: pager.c,v 1.47 2002/06/25 14:43:58 drh Exp $
|
||||
** @(#) $Id: pager.c,v 1.48 2002/07/06 16:28:48 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "pager.h"
|
||||
@@ -77,6 +77,7 @@ struct PgHdr {
|
||||
char inJournal; /* TRUE if has been written to journal */
|
||||
char inCkpt; /* TRUE if written to the checkpoint journal */
|
||||
char dirty; /* TRUE if we need to write back changes */
|
||||
char alwaysRollback; /* Ignore dont_rollback() calls if true */
|
||||
/* SQLITE_PAGE_SIZE bytes of page data follow this header */
|
||||
/* Pager.nExtra bytes of local data follow the page data */
|
||||
};
|
||||
@@ -252,14 +253,21 @@ static int pager_unwritelock(Pager *pPager){
|
||||
pPager->journalOpen = 0;
|
||||
sqliteOsDelete(pPager->zJournal);
|
||||
rc = sqliteOsReadLock(&pPager->fd);
|
||||
assert( rc==SQLITE_OK );
|
||||
sqliteFree( pPager->aInJournal );
|
||||
pPager->aInJournal = 0;
|
||||
for(pPg=pPager->pAll; pPg; pPg=pPg->pNextAll){
|
||||
pPg->inJournal = 0;
|
||||
pPg->dirty = 0;
|
||||
}
|
||||
pPager->state = SQLITE_READLOCK;
|
||||
if( rc==SQLITE_OK ){
|
||||
pPager->state = SQLITE_READLOCK;
|
||||
}else{
|
||||
/* This can only happen if a process does a BEGIN, then forks and the
|
||||
** child process does the COMMIT. Because of the semantics of unix
|
||||
** file locking, the unlock will fail.
|
||||
*/
|
||||
pPager->state = SQLITE_UNLOCK;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -1038,7 +1046,7 @@ int sqlitepager_begin(void *pData){
|
||||
sqliteOsReadLock(&pPager->fd);
|
||||
return SQLITE_NOMEM;
|
||||
}
|
||||
rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd, 0);
|
||||
rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd,pPager->tempFile);
|
||||
if( rc!=SQLITE_OK ){
|
||||
sqliteFree(pPager->aInJournal);
|
||||
pPager->aInJournal = 0;
|
||||
@@ -1190,10 +1198,23 @@ int sqlitepager_iswriteable(void *pData){
|
||||
** Tests show that this optimization, together with the
|
||||
** sqlitepager_dont_rollback() below, more than double the speed
|
||||
** of large INSERT operations and quadruple the speed of large DELETEs.
|
||||
**
|
||||
** When this routine is called, set the alwaysRollback flag to true.
|
||||
** Subsequent calls to sqlitepager_dont_rollback() for the same page
|
||||
** will thereafter be ignored. This is necessary to avoid a problem
|
||||
** where a page with data is added to the freelist during one part of
|
||||
** a transaction then removed from the freelist during a later part
|
||||
** of the same transaction and reused for some other purpose. When it
|
||||
** is first added to the freelist, this routine is called. When reused,
|
||||
** the dont_rollback() routine is called. But because the page contains
|
||||
** critical data, we still need to be sure it gets rolled back in spite
|
||||
** of the dont_rollback() call.
|
||||
*/
|
||||
void sqlitepager_dont_write(Pager *pPager, Pgno pgno){
|
||||
PgHdr *pPg;
|
||||
|
||||
pPg = pager_lookup(pPager, pgno);
|
||||
pPg->alwaysRollback = 1;
|
||||
if( pPg && pPg->dirty ){
|
||||
if( pPager->dbSize==(int)pPg->pgno && pPager->origDbSize<pPager->dbSize ){
|
||||
/* If this pages is the last page in the file and the file has grown
|
||||
@@ -1221,6 +1242,7 @@ void sqlitepager_dont_rollback(void *pData){
|
||||
Pager *pPager = pPg->pPager;
|
||||
|
||||
if( pPager->state!=SQLITE_WRITELOCK || pPager->journalOpen==0 ) return;
|
||||
if( pPg->alwaysRollback ) return;
|
||||
if( !pPg->inJournal && (int)pPg->pgno <= pPager->origDbSize ){
|
||||
assert( pPager->aInJournal!=0 );
|
||||
pPager->aInJournal[pPg->pgno/8] |= 1<<(pPg->pgno&7);
|
||||
|
Reference in New Issue
Block a user