From: danielk1977 Date: Fri, 9 May 2008 16:57:50 +0000 (+0000) Subject: Fix a problem with recovering from an IO error in exclusive-locking mode. (CVS 5112) X-Git-Tag: version-3.6.10~1065 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=93f7af97a6b58480acccf78901dfff84ee01cc0d;p=thirdparty%2Fsqlite.git Fix a problem with recovering from an IO error in exclusive-locking mode. (CVS 5112) FossilOrigin-Name: 7a44fb965b3477fb78901939ba35d569e5638c19 --- diff --git a/manifest b/manifest index aae82aa972..4dd4e527d2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sclear\sthe\serror\scode\sor\serror\smessage\sin\ssqlite3_clear_bindings().\nTicket\s#3063.\s(CVS\s5111) -D 2008-05-09T14:39:45 +C Fix\sa\sproblem\swith\srecovering\sfrom\san\sIO\serror\sin\sexclusive-locking\smode.\s(CVS\s5112) +D 2008-05-09T16:57:51 F Makefile.arm-wince-mingw32ce-gcc ac5f7b2cef0cd850d6f755ba6ee4ab961b1fadf7 F Makefile.in 8b9b8263852f0217157f9042b8e3dae7427ec739 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -85,7 +85,7 @@ F src/attach.c 496cc628b2e8c4d8db99d7c136761fcbebd8420b F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 8ec2212cfb702bc4f402c0b7ae7623d85320c714 F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2 -F src/btree.c 7401bcbdabd87360351953e5009530c47e4fb305 +F src/btree.c 7bee6ba457f3e241911fab69b1602eb43c65b438 F src/btree.h 8826591bf54dd35fcf2e67473d5f1bae253861c7 F src/btreeInt.h dc04ee33d8eb84714b2acdf81336fbbf6e764530 F src/build.c a52d9d51341444a2131e3431608f245db80d9591 @@ -121,7 +121,7 @@ F src/os_common.h e8b748b2f2ecc8a498e50bfe5d8721f189c19d2a F src/os_os2.c 30c378b093d9c17387ebb0ebbf21b7d55a98202b F src/os_unix.c a810e2aefdaddacf479407f76f8f4ca381d231b2 F src/os_win.c 3a60bddd07ea6f8adb2314dd5996ac97b988f403 -F src/pager.c fc173b7ee0b9ee630688466adacd506225417eb7 +F src/pager.c c4e0bcb1f451d2b8601e1cf50e680d88bf175055 F src/pager.h 4f051fd856de6fd3c19aef5f82eace54122b9173 F src/parse.y fc4bd35c6088901f7c8daead26c6fb11c87d22e7 F src/pragma.c 2e4bb2e76e48a32750529fdc4bfe86ac5f54e01b @@ -156,7 +156,7 @@ F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8 F src/test_malloc.c c92a65e8f9b31bb2b332448d92d2016c000a963d F src/test_md5.c bca40b727c57462ddb415e57c5323445a1bb1a40 F src/test_onefile.c 2fea6d22f13f5f286356c80c77ffd41f995f2b7a -F src/test_osinst.c b2947f2ef6201ecc0a922cd2241880a955f5af0d +F src/test_osinst.c f84ac00d61145af1be287754c153d04048b67888 F src/test_schema.c e3f93725f7c5b2cff84a69dc4332040dfbc8f81a F src/test_server.c a6ece6c835e7eae835054124e09e947e422b1ac5 F src/test_tclvar.c b2d1115e4d489179d3f029e765211b2ad527ba59 @@ -329,7 +329,7 @@ F test/incrblob.test 4455fffd08b2f9418a9257e18b135d72273eff3e F test/incrblob_err.test 5273097dc7c97f9b7008423a6ffd5c80d21923cb F test/incrvacuum.test 1a2b0bddc76629afeb41e3d8ea3e4563982d16b9 F test/incrvacuum2.test 46ef65f377e3937cfd1ba66e818309dab46f590d -F test/incrvacuum_ioerr.test 34297e36ef3399933064ee551ad55ba5d70c3a15 +F test/incrvacuum_ioerr.test bc1253285d3a8f6a82a510a0596485dfb83d6ec1 F test/index.test cbf301cdb2da43e4eac636c3400c2439af1834ad F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index3.test 727d55dceb9a4ec36675057bb5becfc265e28ca6 @@ -634,7 +634,7 @@ F www/tclsqlite.tcl 8be95ee6dba05eabcd27a9d91331c803f2ce2130 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P ab18b4e75916b05863b31bc63625aa64a104a42c -R 18e63cebbbff2189e064184403f168a0 -U drh -Z d4393eb7d22c3e8846462316d45daa10 +P 069f4560107246fdc31e1f15c3ad7d3dae2b9ad8 +R f45b51024a5e8c743be851676769c12e +U danielk1977 +Z 6411c1571b3ff8cf23c5c624d3f8d386 diff --git a/manifest.uuid b/manifest.uuid index e8b2663b7a..c5964fc1c4 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -069f4560107246fdc31e1f15c3ad7d3dae2b9ad8 \ No newline at end of file +7a44fb965b3477fb78901939ba35d569e5638c19 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index d87eb040f2..2f8c6ed3d5 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.457 2008/05/07 19:11:03 danielk1977 Exp $ +** $Id: btree.c,v 1.458 2008/05/09 16:57:51 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -1644,6 +1644,7 @@ int sqlite3BtreeGetAutoVacuum(Btree *p){ static int lockBtree(BtShared *pBt){ int rc; MemPage *pPage1; + int nPage; assert( sqlite3_mutex_held(pBt->mutex) ); if( pBt->pPage1 ) return SQLITE_OK; @@ -1654,7 +1655,11 @@ static int lockBtree(BtShared *pBt){ ** a valid database file. */ rc = SQLITE_NOTADB; - if( sqlite3PagerPagecount(pBt->pPager)>0 ){ + nPage = sqlite3PagerPagecount(pBt->pPager); + if( nPage<0 ){ + rc = SQLITE_IOERR; + goto page1_init_failed; + }else if( nPage>0 ){ int pageSize; int usableSize; u8 *page1 = pPage1->aData; diff --git a/src/pager.c b/src/pager.c index e99e60a53b..75f069de6b 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.443 2008/05/07 19:11:03 danielk1977 Exp $ +** @(#) $Id: pager.c,v 1.444 2008/05/09 16:57:51 danielk1977 Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" @@ -1397,9 +1397,11 @@ static int pager_end_transaction(Pager *pPager, int hasMaster){ pPager->stmtOpen = 0; } if( pPager->journalOpen ){ - if( (pPager->exclusiveMode || - pPager->journalMode==PAGER_JOURNALMODE_PERSIST) - && (rc = zeroJournalHdr(pPager, hasMaster))==SQLITE_OK ){ + if( pPager->exclusiveMode + || pPager->journalMode==PAGER_JOURNALMODE_PERSIST + ){ + rc = zeroJournalHdr(pPager, hasMaster); + pager_error(pPager, rc); pPager->journalOff = 0; pPager->journalStarted = 0; }else{ @@ -3412,8 +3414,8 @@ static int pagerSharedLock(Pager *pPager){ if( pPager->journalOpen ){ isHot = 1; } - pager_reset(pPager); pPager->errCode = SQLITE_OK; + pager_reset(pPager); } /* If the pager is still in an error state, do not proceed. The error diff --git a/src/test_osinst.c b/src/test_osinst.c index ab7bb54cf2..3e61110d14 100644 --- a/src/test_osinst.c +++ b/src/test_osinst.c @@ -303,7 +303,9 @@ static int instWrite( ** Truncate an inst-file. */ static int instTruncate(sqlite3_file *pFile, sqlite_int64 size){ - OS_TIME_IO(OS_TRUNCATE, 0, size, p->pReal->pMethods->xTruncate(p->pReal, size)); + OS_TIME_IO(OS_TRUNCATE, 0, (int)size, + p->pReal->pMethods->xTruncate(p->pReal, size) + ); } /* @@ -632,6 +634,34 @@ static void put32bits(unsigned char *p, unsigned int v){ p[3] = v; } +static void binarylog_flush(InstVfsBinaryLog *pLog){ + sqlite3_file *pFile = pLog->pOut; + +#ifdef SQLITE_TEST + extern int sqlite3_io_error_pending; + extern int sqlite3_io_error_persist; + extern int sqlite3_diskfull_pending; + + int pending = sqlite3_io_error_pending; + int persist = sqlite3_io_error_persist; + int diskfull = sqlite3_diskfull_pending; + + sqlite3_io_error_pending = 0; + sqlite3_io_error_persist = 0; + sqlite3_diskfull_pending = 0; +#endif + + pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); + pLog->iOffset += pLog->nBuf; + pLog->nBuf = 0; + +#ifdef SQLITE_TEST + sqlite3_io_error_pending = pending; + sqlite3_io_error_persist = persist; + sqlite3_diskfull_pending = diskfull; +#endif +} + static void binarylog_xcall( void *p, int eEvent, @@ -646,10 +676,7 @@ static void binarylog_xcall( InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; unsigned char *zRec; if( (28+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ - sqlite3_file *pFile = pLog->pOut; - pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); - pLog->iOffset += pLog->nBuf; - pLog->nBuf = 0; + binarylog_flush(pLog); } zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; put32bits(&zRec[0], eEvent); @@ -669,7 +696,7 @@ static void binarylog_xdel(void *p){ InstVfsBinaryLog *pLog = (InstVfsBinaryLog *)p; sqlite3_file *pFile = pLog->pOut; if( pLog->nBuf ){ - pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); + binarylog_flush(pLog); } pFile->pMethods->xClose(pFile); sqlite3_free(pLog->pOut); @@ -698,10 +725,7 @@ static void binarylog_blob( nWrite = nBlob + 28; if( (nWrite+pLog->nBuf)>BINARYLOG_BUFFERSIZE ){ - sqlite3_file *pFile = pLog->pOut; - pFile->pMethods->xWrite(pFile, pLog->zBuf, pLog->nBuf, pLog->iOffset); - pLog->iOffset += pLog->nBuf; - pLog->nBuf = 0; + binarylog_flush(pLog); } zRec = (unsigned char *)&pLog->zBuf[pLog->nBuf]; @@ -750,8 +774,9 @@ sqlite3_vfs *sqlite3_instvfs_binarylog( pParent->xDelete(pParent, p->zOut, 0); rc = pParent->xOpen(pParent, p->zOut, p->pOut, flags, &flags); if( rc==SQLITE_OK ){ - rc = p->pOut->pMethods->xWrite(p->pOut, "sqlite_ostrace1.....", 20, 0); - p->iOffset = 20; + memcpy(p->zBuf, "sqlite_ostrace1.....", 20); + p->iOffset = 0; + p->nBuf = 20; } if( rc ){ binarylog_xdel(p); @@ -863,18 +888,31 @@ static int test_sqlite3_instvfs( case IV_BINARYLOG: { char *zName = 0; char *zLog = 0; + char *zParent = 0; sqlite3_vfs *p; int isDefault = 0; - if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[2])) ){ + int argbase = 2; + + if( objc>2 && 0==strcmp("-default", Tcl_GetString(objv[argbase])) ){ isDefault = 1; + argbase++; + } + if( objc>(argbase+1) + && 0==strcmp("-parent", Tcl_GetString(objv[argbase])) + ){ + zParent = Tcl_GetString(objv[argbase+1]); + argbase += 2; } - if( (objc-isDefault)!=4 ){ - Tcl_WrongNumArgs(interp, 2, objv, "?-default? NAME LOGFILE"); + + if( (objc-argbase)!=2 ){ + Tcl_WrongNumArgs( + interp, 2, objv, "?-default? ?-parent VFS? NAME LOGFILE" + ); return TCL_ERROR; } - zName = Tcl_GetString(objv[2+isDefault]); - zLog = Tcl_GetString(objv[3+isDefault]); - p = sqlite3_instvfs_binarylog(zName, 0, zLog); + zName = Tcl_GetString(objv[argbase]); + zLog = Tcl_GetString(objv[argbase+1]); + p = sqlite3_instvfs_binarylog(zName, zParent, zLog); if( !p ){ Tcl_AppendResult(interp, "error creating vfs ", 0); return TCL_ERROR; diff --git a/test/incrvacuum_ioerr.test b/test/incrvacuum_ioerr.test index fdc3867081..a63b1c6ce6 100644 --- a/test/incrvacuum_ioerr.test +++ b/test/incrvacuum_ioerr.test @@ -15,7 +15,7 @@ # The tests in this file use special facilities that are only # available in the SQLite test fixture. # -# $Id: incrvacuum_ioerr.test,v 1.3 2008/05/06 18:13:26 danielk1977 Exp $ +# $Id: incrvacuum_ioerr.test,v 1.4 2008/05/09 16:57:51 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -27,6 +27,8 @@ ifcapable {!autovacuum} { return } +if 0 { + do_ioerr_test incrvacuum-ioerr-1 -cksum 1 -sqlprep { PRAGMA auto_vacuum = 'incremental'; CREATE TABLE abc(a); @@ -104,5 +106,81 @@ do_ioerr_test incrvacuum-ioerr-3 -start 1 -cksum 1 -tclprep { db close } +} + + +ifcapable shared_cache { + + catch { db close } + file delete -force test.db + set ::enable_shared_cache [sqlite3_enable_shared_cache 1] + + # Create two connections to a single shared-cache: + # + sqlite3 db1 test.db + sqlite3 db2 test.db + + # Create a database with around 20 free pages. + # + do_test incrvacuum-ioerr-4.0 { + execsql { + PRAGMA page_size = 1024; + PRAGMA locking_mode = exclusive; + PRAGMA auto_vacuum = 'incremental'; + BEGIN; + CREATE TABLE a(i integer, b blob); + } db1 + for {set ii 0} {$ii < 20} {incr ii} { + execsql { INSERT INTO a VALUES($ii, randstr(800,1500)); } db1 + } + execsql COMMIT db1 + execsql {DELETE FROM a WHERE oid} db1 + } {} + + set ::rc 1 + for {set iTest 1} {$::rc && $iTest<2000} {incr iTest} { + + # Figure out how big the database is and how many free pages it + # has before running incremental-vacuum. + # + set nPage [expr {[file size test.db]/1024}] + set nFree [execsql {pragma freelist_count} db1] + + # Now run incremental-vacuum to vacuum 5 pages from the db file. + # The iTest'th I/O call is set to fail. + # + set ::sqlite_io_error_pending $iTest + set ::sqlite_io_error_persist 1 + do_test incrvacuum-ioerr-4.$iTest.1 { + set ::rc [catch {execsql {pragma incremental_vacuum(5)} db1} msg] + expr {$::rc==0 || $msg eq "disk I/O error"} + } {1} + + set ::sqlite_io_error_pending 0 + set ::sqlite_io_error_persist 0 + set ::sqlite_io_error_hit 0 + set ::sqlite_io_error_hardhit 0 + + set nFree2 [execsql {pragma freelist_count} db1] + set nPage2 [expr {[file size test.db]/1024}] + + do_test incrvacuum-ioerr-4.$iTest.2 { + set shrink [expr {$nPage-$nPage2}] + expr {$shrink==0 || $shrink==5} + } {1} + + do_test incrvacuum-ioerr-4.$iTest.3 { + expr {$nPage - $nPage2} + } [expr {$nFree - $nFree2}] + } + + # Close the two database connections and restore the default + # shared-cache mode setting. + # + db1 close + db2 close + sqlite3_enable_shared_cache $::enable_shared_cache +} finish_test +