diff --git a/manifest b/manifest index 3165948ba0..ff742b0cd2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scomment\sin\sbtree.c.\sNo\scode\schanges.\s(CVS\s5756) -D 2008-09-30T16:48:11 +C Add\ssome\stestcase()\sand\sassert()\smacros\sto\sbtree.c\sto\said\swith\stesting\nrecent\schanges.\s(CVS\s5757) +D 2008-09-30T17:18:17 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in e4ab842f9a64ef61d57093539a8aab76b12810db F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -99,9 +99,9 @@ F src/attach.c db3f4a60538733c1e4dcb9d0217a6e0d6ccd615b F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53 -F src/btree.c d1720e1e26bc6304737aa0bf86fdc8557f2c39d3 +F src/btree.c 64a38df6f0a9997563418ed194984b81e4ab3694 F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107 -F src/btreeInt.h 3e93c0a6f363bbf68fdd975620f4d3671b6cf7bc +F src/btreeInt.h e38e9b2b285f40f5bc0a6664f630d4a141622f16 F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe F src/callback.c 7a40fd44da3eb89e7f6eff30aa6f940c45d73a97 F src/complete.c cb14e06dbe79dee031031f0d9e686ff306afe07c @@ -637,7 +637,7 @@ F tool/speedtest16.c c8a9c793df96db7e4933f0852abb7a03d48f2e81 F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 1dbced29de5f59ba2ebf877edcadf171540374d1 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e -P 4e536463c1aa9991de85c7efc826c28896ca61d3 -R d230b8ef533fbafc7b1b9585de11f133 -U danielk1977 -Z 11a16b730f49b9e3f152c7fd36e76118 +P 0f3c56330b43fb7c9dc43a444ca38bace9397ede +R 5a3edf18f89485bee6c0db5078617fd9 +U drh +Z 6d8b0066d3b484307b936dd03d86c312 diff --git a/manifest.uuid b/manifest.uuid index 10ccebfc46..73ec9a101e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f3c56330b43fb7c9dc43a444ca38bace9397ede \ No newline at end of file +fb461b78dfc2501fafa8bce03da5487fdfdff959 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index dedbdbabf0..eae118ef8f 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.523 2008/09/30 16:48:11 danielk1977 Exp $ +** $Id: btree.c,v 1.524 2008/09/30 17:18:17 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -34,6 +34,20 @@ int sqlite3BtreeTrace=0; /* True to enable tracing */ # define TRACE(X) #endif +/* +** Sometimes we need a small amount of code such as a variable initialization +** to setup for a later assert() statement. We do not want this code to +** appear when assert() is disabled. The following macro is therefore +** used to contain that setup code. The "VVA" acronym stands for +** "Verification, Validation, and Accreditation". In other words, the +** code within VVA_ONLY() will only run during verification processes. +*/ +#ifndef NDEBUG +# define VVA_ONLY(X) X +#else +# define VVA_ONLY(X) +#endif + #ifndef SQLITE_OMIT_SHARED_CACHE @@ -2356,9 +2370,7 @@ int sqlite3BtreeIncrVacuum(Btree *p){ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ int rc = SQLITE_OK; Pager *pPager = pBt->pPager; -#ifndef NDEBUG - int nRef = sqlite3PagerRefcount(pPager); -#endif + VVA_ONLY( int nRef = sqlite3PagerRefcount(pPager) ); assert( sqlite3_mutex_held(pBt->mutex) ); invalidateAllOverflowCache(pBt); @@ -4910,6 +4922,7 @@ static int balance_nonroot(BtCursor *pCur){ pPage = pCur->apPage[pCur->iPage]; assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + VVA_ONLY( pCur->pagesShuffled = 1 ); /* ** Find the parent page. @@ -5492,6 +5505,7 @@ static int balance_shallower(BtCursor *pCur){ ** for the right-pointer to the child page. The child page becomes ** the virtual root of the tree. */ + VVA_ONLY( pCur->pagesShuffled = 1 ); pgnoChild = get4byte(&pPage->aData[pPage->hdrOffset+8]); assert( pgnoChild>0 ); assert( pgnoChild<=pagerPagecount(pPage->pBt->pPager) ); @@ -5566,6 +5580,7 @@ static int balance_deeper(BtCursor *pCur){ assert( pCur->iPage==0 ); assert( pCur->apPage[0]->nOverflow>0 ); + VVA_ONLY( pCur->pagesShuffled = 1 ); pPage = pCur->apPage[0]; pBt = pPage->pBt; assert( sqlite3_mutex_held(pBt->mutex) ); @@ -5814,7 +5829,7 @@ end_insert: /* ** Delete the entry that the cursor is pointing to. The cursor -** is left pointing at a random location. +** is left pointing at a arbitrary location. */ int sqlite3BtreeDelete(BtCursor *pCur){ MemPage *pPage = pCur->apPage[pCur->iPage]; @@ -5913,11 +5928,30 @@ int sqlite3BtreeDelete(BtCursor *pCur){ rc = insertCell(pPage, idx, pNext-4, szNext+4, tempCell, 0); } + + /* The "if" statement in the next code block is critical. The + ** slightest error in that statement would allow SQLite to operate + ** correctly most of the time but produce very rare failures. To + ** guard against this, the following macros help to verify that + ** the "if" statement is well tested. + */ + testcase( pPage->nOverflow==0 && pPage->nFreeusableSize*2/3 + && pLeafPage->nFree+2+szNext > pBt->usableSize*2/3 ); + testcase( pPage->nOverflow==0 && pPage->nFree==pBt->usableSize*2/3 + && pLeafPage->nFree+2+szNext > pBt->usableSize*2/3 ); + testcase( pPage->nOverflow==0 && pPage->nFree==pBt->usableSize*2/3+1 + && pLeafPage->nFree+2+szNext > pBt->usableSize*2/3 ); + testcase( pPage->nOverflow>0 && pPage->nFree<=pBt->usableSize*2/3 + && pLeafPage->nFree+2+szNext > pBt->usableSize*2/3 ); + testcase( (pPage->nOverflow>0 || (pPage->nFree > pBt->usableSize*2/3)) + && pLeafPage->nFree+2+szNext == pBt->usableSize*2/3 ); + + if( (pPage->nOverflow>0 || (pPage->nFree > pBt->usableSize*2/3)) && (pLeafPage->nFree+2+szNext > pBt->usableSize*2/3) ){ - /* This branch is taken if the internal node is now either over or - ** underfull and the leaf node will be underfull after the just cell + /* This branch is taken if the internal node is now either overflowing + ** or underfull and the leaf node will be underfull after the just cell ** copied to the internal node is deleted from it. This is a special ** case because the call to balance() to correct the internal node ** may change the tree structure and invalidate the contents of @@ -5928,11 +5962,14 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** The formula used in the expression above are based on facets of ** the SQLite file-format that do not change over time. */ + testcase( pPage->nFree==pBt->usableSize*2/3+1 ); + testcase( pLeafPage->nFree+2+szNext==pBt->usableSize*2/3+1 ); leafCursorInvalid = 1; } if( rc==SQLITE_OK ){ put4byte(findOverflowCell(pPage, idx), pgnoChild); + VVA_ONLY( pCur->pagesShuffled = 0 ); rc = balance(pCur, 0); } @@ -5960,9 +5997,7 @@ int sqlite3BtreeDelete(BtCursor *pCur){ ** that needs to be removed, and the leafCur.apPage[] and ** leafCur.aiIdx[] arrays are correct. */ - #ifndef NDEBUG - Pgno leafPgno = pLeafPage->pgno; - #endif + VVA_ONLY( Pgno leafPgno = pLeafPage->pgno ); rc = saveCursorPosition(&leafCur); if( rc==SQLITE_OK ){ rc = sqlite3BtreeNext(&leafCur, ¬Used); @@ -5974,7 +6009,10 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( rc==SQLITE_OK ){ dropCell(pLeafPage, 0, szNext); + VVA_ONLY( leafCur.pagesShuffled = 0 ); rc = balance(&leafCur, 0); + assert( leafCursorInvalid || !leafCur.pagesShuffled + || !pCur->pagesShuffled ); } } sqlite3BtreeReleaseTempCursor(&leafCur); diff --git a/src/btreeInt.h b/src/btreeInt.h index 14b852bc97..92eca75c11 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btreeInt.h,v 1.33 2008/09/29 15:53:26 danielk1977 Exp $ +** $Id: btreeInt.h,v 1.34 2008/09/30 17:18:17 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -454,7 +454,9 @@ struct BtCursor { u8 isIncrblobHandle; /* True if this cursor is an incr. io handle */ Pgno *aOverflow; /* Cache of overflow page locations */ #endif - +#ifndef NDEBUG + u8 pagesShuffled; /* True if Btree pages are rearranged by balance()*/ +#endif i16 iPage; /* Index of current page in apPage */ MemPage *apPage[BTCURSOR_MAX_DEPTH]; /* Pages from root to current page */ u16 aiIdx[BTCURSOR_MAX_DEPTH]; /* Current index in apPage[i] */