From 2f78fc66b5d2105a3371f479f175d0e3dabca934 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Tue, 30 Sep 2008 09:31:45 +0000 Subject: [PATCH] Fix a recently introduced problem with deleting entries from index tables. (CVS 5754) FossilOrigin-Name: 83c064cae481ca95b7107e22e98fc599fe85a2da --- manifest | 14 +++++------ manifest.uuid | 2 +- src/btree.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 68 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index 9466384151..4f48a745d1 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Misc\sclean\sup.\s\sWrapped\sa\sCE\sonly\svariable\sin\sif-defs.\sChanged\sto\sonly\sprovide\scache\shint\sfor\sCE\sbuilds\s(as\sthis\sprevents\sCE\sfrom\scompressing\sthe\sfile.)\sPerformance\stesting\son\sXP\sand\sVista\sshowed\scaching\shint\shad\slittle\seffect\swhen\sthe\sDB\ssize\swas\smuch\ssmaller\sthan\sthe\sO/S\sdisk\scache\ssize,\sand\sprovided\sonly\smarginal\sbenefit\swhen\sthe\sDB\ssize\swas\smuch\slarger\sthan\sthe\scache.\s\sOn\sVista,\soverall\ssystem\sperformance\swas\shurt\sfor\svery\slarge\sDBs.\s\sTicket\s#3387.\s(CVS\s5753) -D 2008-09-30T04:20:08 +C Fix\sa\srecently\sintroduced\sproblem\swith\sdeleting\sentries\sfrom\sindex\stables.\s(CVS\s5754) +D 2008-09-30T09:31:45 F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0 F Makefile.in e4ab842f9a64ef61d57093539a8aab76b12810db F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654 @@ -99,7 +99,7 @@ F src/attach.c db3f4a60538733c1e4dcb9d0217a6e0d6ccd615b F src/auth.c c8b2ab5c8bad4bd90ed7c294694f48269162c627 F src/bitvec.c 95c86bd18d8fedf0533f5af196192546e10a7e7d F src/btmutex.c 709cad2cdca0afd013f0f612363810e53f59ec53 -F src/btree.c df02edb06f8fcb53d607a338d77434c4a3bffe7a +F src/btree.c 2e5cf91c3f342fa611bfd6f0250c31b432fbdd90 F src/btree.h 6371c5e599fab391a150c96afbc10062b276d107 F src/btreeInt.h 3e93c0a6f363bbf68fdd975620f4d3671b6cf7bc F src/build.c 160c71acca8f643f436ed6c1ee2f684c88df4dfe @@ -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 78d075ff38d96cc58659a7097dec0e49402aa960 -R 39be9f2940749141be589318f7d2a538 -U shane -Z b381b1aa9c52e2148aadad6fea9866f7 +P 15dd0169a4c5e2ff9e3894eec10799cb89d462e5 +R 67ac196eea416fb3e08d66e37fb1b4f0 +U danielk1977 +Z 769068257f0c5361c027fdd2793aa895 diff --git a/manifest.uuid b/manifest.uuid index 192288f971..570c8a0f61 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -15dd0169a4c5e2ff9e3894eec10799cb89d462e5 \ No newline at end of file +83c064cae481ca95b7107e22e98fc599fe85a2da \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index f45a6fde0d..655a63d3f5 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.520 2008/09/29 16:41:32 danielk1977 Exp $ +** $Id: btree.c,v 1.521 2008/09/30 09:31:45 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** See the header comment on "btreeInt.h" for additional information. @@ -5883,7 +5883,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){ */ BtCursor leafCur; MemPage *pLeafPage; - int iLeafIdx; unsigned char *pNext; int notUsed; @@ -5892,16 +5891,17 @@ int sqlite3BtreeDelete(BtCursor *pCur){ sqlite3BtreeGetTempCursor(pCur, &leafCur); rc = sqlite3BtreeNext(&leafCur, ¬Used); if( rc==SQLITE_OK ){ + assert( leafCur.aiIdx[leafCur.iPage]==0 ); pLeafPage = leafCur.apPage[leafCur.iPage]; - iLeafIdx = leafCur.aiIdx[leafCur.iPage]; rc = sqlite3PagerWrite(pLeafPage->pDbPage); } if( rc==SQLITE_OK ){ + int leafCursorInvalid = 0; u16 szNext; TRACE(("DELETE: table=%d delete internal from %d replace from leaf %d\n", pCur->pgnoRoot, pPage->pgno, pLeafPage->pgno)); dropCell(pPage, idx, cellSizePtr(pPage, pCell)); - pNext = findCell(pLeafPage, iLeafIdx); + pNext = findCell(pLeafPage, 0); szNext = cellSizePtr(pLeafPage, pNext); assert( MX_CELL_SIZE(pBt)>=szNext+4 ); allocateTempSpace(pBt); @@ -5912,12 +5912,66 @@ int sqlite3BtreeDelete(BtCursor *pCur){ if( rc==SQLITE_OK ){ rc = insertCell(pPage, idx, pNext-4, szNext+4, tempCell, 0); } + + 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 + ** 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 + ** the leafCur.apPage[] and leafCur.aiIdx[] arrays, which will be + ** used by the balance() required to correct the underfull leaf + ** node. + ** + ** The formula used in the expression above are based on facets of + ** the SQLite file-format that do not change over time. + */ + leafCursorInvalid = 1; + } + if( rc==SQLITE_OK ){ put4byte(findOverflowCell(pPage, idx), pgnoChild); rc = balance(pCur, 0); } + + if( rc==SQLITE_OK && leafCursorInvalid ){ + /* The leaf-node is now underfull and so the tree needs to be + ** rebalanced. However, the balance() operation on the internal + ** node above may have modified the structure of the B-Tree and + ** so the current contents of leafCur.apPage[] and leafCur.aiIdx[] + ** may not be trusted. + ** + ** It is not possible to copy the ancestry from pCur, as the same + ** balance() call has invalidated the pCur->apPage[] and aiIdx[] + ** arrays. + ** + ** The call to saveCursorPosition() below internally saves the + ** key that leafCur is currently pointing to. Currently, there + ** are two copies of that key in the tree - one here on the leaf + ** page and one on some internal node in the tree. The copy on + ** the leaf node is always the next key in tree-order after the + ** copy on the internal node. So, the call to sqlite3BtreeNext() + ** calls restoreCursorPosition() to point the cursor to the copy + ** stored on the internal node, then advances to the next entry, + ** which happens to be the copy of the key on the internal node. + ** Net effect: leafCur is pointing back where + */ + #ifndef NDEBUG + Pgno leafPgno = pLeafPage->pgno; + #endif + rc = saveCursorPosition(&leafCur); + if( rc==SQLITE_OK ){ + rc = sqlite3BtreeNext(&leafCur, ¬Used); + } + pLeafPage = leafCur.apPage[leafCur.iPage]; + assert( pLeafPage->pgno==leafPgno ); + assert( leafCur.aiIdx[leafCur.iPage]==0 ); + } + if( rc==SQLITE_OK ){ - dropCell(pLeafPage, iLeafIdx, szNext); + dropCell(pLeafPage, 0, szNext); rc = balance(&leafCur, 0); } } @@ -7026,7 +7080,7 @@ static int btreeCopyFile(Btree *pTo, Btree *pFrom){ } memcpy(zTo, zFrom, nCopy); - sqlite3PagerUnref(pFromPage); + sqlite3PagerUnref(pFromPage); } }