From 8e298f92f61c161ce128c0d2b520ddb17dbd9748 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 6 Jul 2002 16:28:47 +0000 Subject: [PATCH] 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 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pager.c | 30 ++++++++++++++++++++++++++---- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index e8849d23c3..a068e3ead7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C All\sthe\scode\sis\snow\sin\splace\sfor\sSQLite\sto\sdistinguish\sbetween\sNUMERIC\sand\nTEXT\sdatatypes.\s\sStill\sneed\sto\sturn\son\sthe\snew\scode\sand\stest\sit.\s(CVS\s659) -D 2002-07-05T21:42:36 +C Fix\sfor\sbug\s#94:\sBe\ssure\sto\sjournal\spages\sthat\sare\sadded\sto\sthe\sfreelist\sthen\nremoved\sfrom\sthe\sfreelist\sand\sreused\sduring\sthe\ssame\stransaction.\s(CVS\s660) +D 2002-07-06T16:28:48 F Makefile.in 6291a33b87d2a395aafd7646ee1ed562c6f2c28c F Makefile.template 4e11752e0b5c7a043ca50af4296ec562857ba495 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -32,7 +32,7 @@ F src/main.c 6ac32ca71ab4728212c5b44aed25e26dc6cfe73c F src/md5.c 0ae1f3e2cac92d06fc6246d1b4b8f61a2fe66d3b F src/os.c 9cc40c5384baba4a85e160e67807645ca98ba3cc F src/os.h 4a361fccfbc4e7609b3e1557f604f94c1e96ad10 -F src/pager.c 58ae9f569b3c664ea9205c6f6da432e3ae180f56 +F src/pager.c 103341600b4044e41b5bd95cd3850f046b976ff2 F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e F src/parse.y 35437ac29441ce2d34904d8e93f40b7d112147a9 F src/printf.c 236ed7a79386feed4456fa728fff8be793f1547c @@ -137,7 +137,7 @@ F www/speed.tcl da8afcc1d3ccc5696cfb388a68982bc3d9f7f00f F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098 F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 85793a4f03250166c21007cab3525709592d0866 -R f77acd757b229f1cdb42ab7cac78b933 +P b4737a16c997a6c139d616211fb6bc4b0fae181c +R 253a44e4b92ce398170a14aa4989c608 U drh -Z 6c4c383ead0a1302c4ea68955c9a4a90 +Z 4750e3634de2bc1c9f7bbad93ace444e diff --git a/manifest.uuid b/manifest.uuid index 24b731aef6..35f6982e26 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -b4737a16c997a6c139d616211fb6bc4b0fae181c \ No newline at end of file +db178646a01483d59e6f9af302e9bbe394956d93 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index ef8847ba29..8b93d21326 100644 --- a/src/pager.c +++ b/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->origDbSizedbSize ){ /* 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);