From 474b7cc785c6f7e063cff96f6819e7b79638201c Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Wed, 9 Jul 2008 11:49:46 +0000 Subject: [PATCH] Coverage testing for balance_quick() and balance_deeper(). (CVS 5382) FossilOrigin-Name: 491f8f9613d2b886acad2ab8f631a4ec61ad698d --- manifest | 16 +++++----- manifest.uuid | 2 +- src/btree.c | 34 ++++++++++++---------- test/ioerr.test | 77 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 104 insertions(+), 25 deletions(-) diff --git a/manifest b/manifest index 151828c9d6..3def778a71 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\stest\scoverage\sin\sselect.c\sand\sexpr.c.\s(CVS\s5381) -D 2008-07-09T01:39:44 +C Coverage\stesting\sfor\sbalance_quick()\sand\sbalance_deeper().\s(CVS\s5382) +D 2008-07-09T11:49:47 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in a03f7cb4f7ad50bc53a788c6c544430e81f95de4 F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -95,7 +95,7 @@ F src/attach.c b18ba42c77f7d3941f5d23d2ca20fa1d841a4e91 F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/btmutex.c 483ced3c52205b04b97df69161fadbf87f4f1ea2 -F src/btree.c a52b0a1d0459e3a028a90df84a84ec1c58148574 +F src/btree.c fbc557de64457effea261699c11fc0cf7696ccd6 F src/btree.h b1bd7e0b8c2e33658aaf447cb0d1d94f74664b6b F src/btreeInt.h 8f6e0817365ac822da0afffedc664ba03047718b F src/build.c bac7233d984be3805aaa41cf500f7ee12dc97249 @@ -356,7 +356,7 @@ F test/insert5.test 509017213328147d3acdfa2c441bfd82362dda41 F test/interrupt.test 42e7cf98646fd9cb4a3b131a93ed3c50b9e149f1 F test/intpkey.test 537669fd535f62632ca64828e435b9e54e8d677f F test/io.test 833a1746518ec3005aa7792f9bcb8f01923ff544 -F test/ioerr.test f87e5be364a5938996e8741091088845eb9ce802 +F test/ioerr.test 404edbb58143b4581a6f23c2031d40db931d7b90 F test/ioerr2.test 5598405c48842c6c0187daad9eb49eff2c54f80d F test/ioerr3.test d3cec5e1a11ad6d27527d0d38573fbff14c71bdd F test/ioerr4.test fc6eddfec2efc2f1ed217b9eae4c1c1d3516ce86 @@ -600,7 +600,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P cbd3c1585b7a8f8042aa1448fe1be87de056c41a -R 9c8b6c813e587d92b499775ff9d0704e -U drh -Z 797145b83fcaf2766400631bd4924b1a +P c6cf08477cc4d622a05ad6706cb9418cf7eea432 +R 229bd421824f3bb6fb90dfe5637660e4 +U danielk1977 +Z 426328c9a228ac588ec10fbe5f06c5ef diff --git a/manifest.uuid b/manifest.uuid index 1333ce0d6c..8405a35362 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c6cf08477cc4d622a05ad6706cb9418cf7eea432 \ No newline at end of file +491f8f9613d2b886acad2ab8f631a4ec61ad698d \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 23df64f0d3..a1564ec3db 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.473 2008/07/08 19:34:07 drh Exp $ +** $Id: btree.c,v 1.474 2008/07/09 11:49:47 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -667,7 +667,7 @@ static int ptrmapPutOvfl(MemPage *pPage, int iCell){ ** big FreeBlk that occurs in between the header and cell ** pointer array and the cell content area. */ -static int defragmentPage(MemPage *pPage){ +static void defragmentPage(MemPage *pPage){ int i; /* Loop counter */ int pc; /* Address of a i-th cell */ int addr; /* Offset of first byte after cell pointer array */ @@ -712,7 +712,6 @@ static int defragmentPage(MemPage *pPage){ data[hdr+7] = 0; addr = cellOffset+2*nCell; memset(&data[addr], 0, brk-addr); - return SQLITE_OK; } /* @@ -773,7 +772,7 @@ static int allocateSpace(MemPage *pPage, int nByte){ nCell = get2byte(&data[hdr+3]); cellOffset = pPage->cellOffset; if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){ - if( defragmentPage(pPage) ) return 0; + defragmentPage(pPage); top = get2byte(&data[hdr+5]); } top -= nByte; @@ -4645,8 +4644,7 @@ static int insertCell( end = cellOffset + 2*pPage->nCell + 2; ins = cellOffset + 2*i; if( end > top - sz ){ - rc = defragmentPage(pPage); - if( rc!=SQLITE_OK ) return rc; + defragmentPage(pPage); top = get2byte(&data[hdr+5]); assert( end + sz <= top ); } @@ -4798,19 +4796,24 @@ static int balance_quick(MemPage *pPage, MemPage *pParent){ /* pPage is currently the right-child of pParent. Change this ** so that the right-child is the new page allocated above and ** pPage is the next-to-right child. + ** + ** Ignore the return value of the call to fillInCell(). fillInCell() + ** may only return other than SQLITE_OK if it is required to allocate + ** one or more overflow pages. Since an internal table B-Tree cell + ** may never spill over onto an overflow page (it is a maximum of + ** 13 bytes in size), it is not neccessary to check the return code. + ** + ** Similarly, the insertCell() function cannot fail if the page + ** being inserted into is already writable and the cell does not + ** contain an overflow pointer. So ignore this return code too. */ assert( pPage->nCell>0 ); pCell = findCell(pPage, pPage->nCell-1); sqlite3BtreeParseCellPtr(pPage, pCell, &info); - rc = fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); - if( rc!=SQLITE_OK ){ - return rc; - } + fillInCell(pParent, parentCell, 0, info.nKey, 0, 0, 0, &parentSize); assert( parentSize<64 ); - rc = insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); - if( rc!=SQLITE_OK ){ - return rc; - } + assert( sqlite3PagerIswriteable(pParent->pDbPage) ); + insertCell(pParent, parentIdx, parentCell, parentSize, 0, 4); put4byte(findOverflowCell(pParent,parentIdx), pPage->pgno); put4byte(&pParent->aData[pParent->hdrOffset+8], pgnoNew); @@ -4918,6 +4921,7 @@ static int balance_nonroot(MemPage *pPage){ if( SQLITE_OK!=(rc = sqlite3PagerWrite(pParent->pDbPage)) ){ return rc; } + TRACE(("BALANCE: begin page %d child of %d\n", pPage->pgno, pParent->pgno)); #ifndef SQLITE_OMIT_QUICKBALANCE @@ -5599,7 +5603,7 @@ static int balance_deeper(MemPage *pPage){ for(i=0; inCell; i++){ rc = ptrmapPutOvfl(pChild, i); if( rc!=SQLITE_OK ){ - return rc; + goto balancedeeper_out; } } } diff --git a/test/ioerr.test b/test/ioerr.test index ef24357490..4785ad2d8c 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -15,7 +15,7 @@ # The tests in this file use special facilities that are only # available in the SQLite test fixture. # -# $Id: ioerr.test,v 1.39 2008/07/08 17:13:59 danielk1977 Exp $ +# $Id: ioerr.test,v 1.40 2008/07/09 11:49:48 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -328,6 +328,81 @@ do_ioerr_test ioerr-12 -ckrefcount true -erc 1 -tclprep { db eval { INSERT INTO t1 VALUES(randomblob(2000)); } } sqlite3_simulate_device -char {} -sectorsize 0 +catch {db close} + +do_ioerr_test ioerr-13 -ckrefcount true -erc 1 -sqlprep { + PRAGMA auto_vacuum = incremental; + CREATE TABLE t1(x); + CREATE TABLE t2(x); + INSERT INTO t2 VALUES(randomblob(1500)); + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t1 VALUES(randomblob(20)); + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1 SELECT x FROM t1; + INSERT INTO t1 SELECT x FROM t1; /* 64 entries in t1 */ + INSERT INTO t1 SELECT x FROM t1 LIMIT 14; /* 78 entries in t1 */ + DELETE FROM t2 WHERE rowid = 3; +} -sqlbody { + -- This statement uses the balance_quick() optimization. The new page + -- is appended to the database file. But the overflow page used by + -- the new record will be positioned near the start of the database + -- file, in the gap left by the "DELETE FROM t2 WHERE rowid=3" statement + -- above. + -- + -- The point of this is that the statement wil need to update two pointer + -- map pages. Which introduces another opportunity for an IO error. + -- + INSERT INTO t1 VALUES(randomblob(2000)); +} + +do_ioerr_test ioerr-14 -ckrefcount true -erc 1 -sqlprep { + PRAGMA auto_vacuum = incremental; + CREATE TABLE t1(x); + CREATE TABLE t2(x); + INSERT INTO t2 VALUES(randomblob(1500)); + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + INSERT INTO t2 SELECT randomblob(1500) FROM t2; + + -- This statement inserts a row into t1 with an overflow page at the + -- end of the file. A long way from its parent (the root of t1). + INSERT INTO t1 VALUES(randomblob(1500)); + DELETE FROM t2 WHERE rowid<10; +} -sqlbody { + -- This transaction will cause the root-page of table t1 to divide + -- (by calling balance_deeper()). When it does, the "parent" page of the + -- overflow page inserted in the -sqlprep block above will change and + -- the corresponding pointer map page be updated. This test case attempts + -- to cause an IO error during the pointer map page update. + -- + BEGIN; + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + INSERT INTO t1 VALUES(randomblob(100)); + COMMIT; +} finish_test