From b0ea9432a12c01597951967a18e530df1b4bffd1 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 9 Feb 2019 21:06:40 +0000 Subject: [PATCH 1/7] Defer computing the MemPage.nFree value of an in-memory btree page until it is actually needed, since for many pages it is never needed. This checkin works sufficiently to prove the concept, but still has issues with exception handling. FossilOrigin-Name: 1d43ee4000b71f5c6d49244dee96358c567f09ba3451b9d22895a796d3f61ad6 --- manifest | 19 +++-- manifest.uuid | 2 +- src/btree.c | 221 ++++++++++++++++++++++++++++++++----------------- src/btreeInt.h | 2 +- 4 files changed, 159 insertions(+), 85 deletions(-) diff --git a/manifest b/manifest index 01727ffac6..dc017b8c18 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sa\sfew\sassert()\sstatements\sin\sfts3\sthat\smight\sfail\sif\sthe\sdatabase\sis\scorrupt. -D 2019-02-09T19:23:54.418 +C Defer\scomputing\sthe\sMemPage.nFree\svalue\sof\san\sin-memory\sbtree\spage\nuntil\sit\sis\sactually\sneeded,\ssince\sfor\smany\spages\sit\sis\snever\sneeded.\nThis\scheckin\sworks\ssufficiently\sto\sprove\sthe\sconcept,\sbut\sstill\shas\sissues\nwith\sexception\shandling. +D 2019-02-09T21:06:40.308 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,9 +455,9 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 18046bf14f0e3fa294ef3f7c2dc30ca7e95f3ac11ec222ad906e40b150051bde +F src/btree.c b2bb677fa5d2f18b7c38869761e0d7d1d66ff3a7bdac509865e0606b281d32bc F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 -F src/btreeInt.h cd82f0f08886078bf99b29e1a7045960b1ca5d9d5829c38607e1299c508eaf00 +F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -1804,7 +1804,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1969372ac72d25cc642a0268f4bb0ae4b59f2dca568c119ef61b67183b3a8bd9 -R 337fdf56fb6120be7b5570f5a6b13c97 -U dan -Z 3ee700c86d7982301bd59c67543d08c0 +P db74a56af73d92b7a9d43ceda7e4540915c580c68a0266b4ddefb9e0d5cbcbeb +R 6351a98578ba74f863fbe86b96b0dce9 +T *branch * deferred-free-space +T *sym-deferred-free-space * +T -sym-trunk * +U drh +Z 38c6e8e54a38cca2a22ac1c0553f905f diff --git a/manifest.uuid b/manifest.uuid index 63a146afab..db390c0838 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -db74a56af73d92b7a9d43ceda7e4540915c580c68a0266b4ddefb9e0d5cbcbeb \ No newline at end of file +1d43ee4000b71f5c6d49244dee96358c567f09ba3451b9d22895a796d3f61ad6 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index e4086ed0f5..375d891898 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1506,6 +1506,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ data[hdr+7] = 0; defragment_out: + assert( pPage->nFree>=0 ); if( data[hdr+7]+cbrk-iCellFirst!=pPage->nFree ){ return SQLITE_CORRUPT_PAGE(pPage); } @@ -1657,6 +1658,7 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ testcase( gap+2+nByte==top ); if( gap+2+nByte>top ){ assert( pPage->nCell>0 || CORRUPT_DB ); + assert( pPage->nFree>=0 ); rc = defragmentPage(pPage, MIN(4, pPage->nFree - (2+nByte))); if( rc ) return rc; top = get2byteNotZero(&data[hdr+5]); @@ -1846,21 +1848,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){ } /* -** Initialize the auxiliary information for a disk block. -** -** Return SQLITE_OK on success. If we see that the page does -** not contain a well-formed database page, then return -** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not -** guarantee that the page is well-formed. It only shows that -** we failed to detect any corruption. +** Compute the amount of freespace on the page. In other words, fill +** in the pPage->nFree field. */ -static int btreeInitPage(MemPage *pPage){ +static int btreeComputeFreeSpace(MemPage *pPage){ int pc; /* Address of a freeblock within pPage->aData[] */ u8 hdr; /* Offset to beginning of page header */ u8 *data; /* Equal to pPage->aData */ - BtShared *pBt; /* The main btree structure */ int usableSize; /* Amount of usable space on each page */ - u16 cellOffset; /* Offset from start of page to first cell pointer */ int nFree; /* Number of unused bytes on the page */ int top; /* First byte of the cell content area */ int iCellFirst; /* First allowable cell or freeblock offset */ @@ -1872,71 +1867,18 @@ static int btreeInitPage(MemPage *pPage){ assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); - assert( pPage->isInit==0 ); + assert( pPage->isInit==1 ); + assert( pPage->nFree<0 ); - pBt = pPage->pBt; + usableSize = pPage->pBt->usableSize; hdr = pPage->hdrOffset; data = pPage->aData; - /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating - ** the b-tree page type. */ - if( decodeFlags(pPage, data[hdr]) ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); - pPage->maskPage = (u16)(pBt->pageSize - 1); - pPage->nOverflow = 0; - usableSize = pBt->usableSize; - pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; - pPage->aDataEnd = &data[usableSize]; - pPage->aCellIdx = &data[cellOffset]; - pPage->aDataOfst = &data[pPage->childPtrSize]; /* EVIDENCE-OF: R-58015-48175 The two-byte integer at offset 5 designates ** the start of the cell content area. A zero value for this integer is ** interpreted as 65536. */ top = get2byteNotZero(&data[hdr+5]); - /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the - ** number of cells on the page. */ - pPage->nCell = get2byte(&data[hdr+3]); - if( pPage->nCell>MX_CELL(pBt) ){ - /* To many cells for a single page. The page must be corrupt */ - return SQLITE_CORRUPT_PAGE(pPage); - } - testcase( pPage->nCell==MX_CELL(pBt) ); - /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only - ** possible for a root page of a table that contains no rows) then the - ** offset to the cell content area will equal the page size minus the - ** bytes of reserved space. */ - assert( pPage->nCell>0 || top==usableSize || CORRUPT_DB ); - - /* A malformed database page might cause us to read past the end - ** of page when parsing a cell. - ** - ** The following block of code checks early to see if a cell extends - ** past the end of a page boundary and causes SQLITE_CORRUPT to be - ** returned if it does. - */ - iCellFirst = cellOffset + 2*pPage->nCell; + iCellFirst = hdr + 8 + pPage->childPtrSize + 2*pPage->nCell; iCellLast = usableSize - 4; - if( pBt->db->flags & SQLITE_CellSizeCk ){ - int i; /* Index into the cell pointer array */ - int sz; /* Size of a cell */ - - if( !pPage->leaf ) iCellLast--; - for(i=0; inCell; i++){ - pc = get2byteAligned(&data[cellOffset+i*2]); - testcase( pc==iCellFirst ); - testcase( pc==iCellLast ); - if( pciCellLast ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - sz = pPage->xCellSize(pPage, &data[pc]); - testcase( pc+sz==usableSize ); - if( pc+sz>usableSize ){ - return SQLITE_CORRUPT_PAGE(pPage); - } - } - if( !pPage->leaf ) iCellLast++; - } /* Compute the total free space on the page ** EVIDENCE-OF: R-23588-34450 The two-byte integer at offset 1 gives the @@ -1984,6 +1926,98 @@ static int btreeInitPage(MemPage *pPage){ return SQLITE_CORRUPT_PAGE(pPage); } pPage->nFree = (u16)(nFree - iCellFirst); + return SQLITE_OK; +} + +/* +** Initialize the auxiliary information for a disk block. +** +** Return SQLITE_OK on success. If we see that the page does +** not contain a well-formed database page, then return +** SQLITE_CORRUPT. Note that a return of SQLITE_OK does not +** guarantee that the page is well-formed. It only shows that +** we failed to detect any corruption. +*/ +static int btreeInitPage(MemPage *pPage){ + int pc; /* Address of a freeblock within pPage->aData[] */ + u8 hdr; /* Offset to beginning of page header */ + u8 *data; /* Equal to pPage->aData */ + BtShared *pBt; /* The main btree structure */ + int usableSize; /* Amount of usable space on each page */ + u16 cellOffset; /* Offset from start of page to first cell pointer */ + int iCellFirst; /* First allowable cell or freeblock offset */ + int iCellLast; /* Last possible cell or freeblock offset */ + + assert( pPage->pBt!=0 ); + assert( pPage->pBt->db!=0 ); + assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) ); + assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) ); + assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) ); + assert( pPage->isInit==0 ); + + pBt = pPage->pBt; + hdr = pPage->hdrOffset; + data = pPage->aData; + /* EVIDENCE-OF: R-28594-02890 The one-byte flag at offset 0 indicating + ** the b-tree page type. */ + if( decodeFlags(pPage, data[hdr]) ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + assert( pBt->pageSize>=512 && pBt->pageSize<=65536 ); + pPage->maskPage = (u16)(pBt->pageSize - 1); + pPage->nOverflow = 0; + usableSize = pBt->usableSize; + pPage->cellOffset = cellOffset = hdr + 8 + pPage->childPtrSize; + pPage->aDataEnd = &data[usableSize]; + pPage->aCellIdx = &data[cellOffset]; + pPage->aDataOfst = &data[pPage->childPtrSize]; + /* EVIDENCE-OF: R-37002-32774 The two-byte integer at offset 3 gives the + ** number of cells on the page. */ + pPage->nCell = get2byte(&data[hdr+3]); + if( pPage->nCell>MX_CELL(pBt) ){ + /* To many cells for a single page. The page must be corrupt */ + return SQLITE_CORRUPT_PAGE(pPage); + } + testcase( pPage->nCell==MX_CELL(pBt) ); + /* EVIDENCE-OF: R-24089-57979 If a page contains no cells (which is only + ** possible for a root page of a table that contains no rows) then the + ** offset to the cell content area will equal the page size minus the + ** bytes of reserved space. */ + assert( pPage->nCell>0 + || get2byteNotZero(&data[hdr+5])==usableSize + || CORRUPT_DB ); + + /* A malformed database page might cause us to read past the end + ** of page when parsing a cell. + ** + ** The following block of code checks early to see if a cell extends + ** past the end of a page boundary and causes SQLITE_CORRUPT to be + ** returned if it does. + */ + iCellFirst = cellOffset + 2*pPage->nCell; + iCellLast = usableSize - 4; + if( pBt->db->flags & SQLITE_CellSizeCk ){ + int i; /* Index into the cell pointer array */ + int sz; /* Size of a cell */ + + if( !pPage->leaf ) iCellLast--; + for(i=0; inCell; i++){ + pc = get2byteAligned(&data[cellOffset+i*2]); + testcase( pc==iCellFirst ); + testcase( pc==iCellLast ); + if( pciCellLast ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + sz = pPage->xCellSize(pPage, &data[pc]); + testcase( pc+sz==usableSize ); + if( pc+sz>usableSize ){ + return SQLITE_CORRUPT_PAGE(pPage); + } + } + if( !pPage->leaf ) iCellLast++; + } + pPage->nFree = -1; /* Indicate that this value is yet uncomputed */ pPage->isInit = 1; return SQLITE_OK; } @@ -2127,19 +2161,18 @@ static int getAndInitPage( if( pgno>btreePagecount(pBt) ){ rc = SQLITE_CORRUPT_BKPT; - goto getAndInitPage_error; + goto getAndInitPage_error1; } rc = sqlite3PagerGet(pBt->pPager, pgno, (DbPage**)&pDbPage, bReadOnly); if( rc ){ - goto getAndInitPage_error; + goto getAndInitPage_error1; } *ppPage = (MemPage*)sqlite3PagerGetExtra(pDbPage); if( (*ppPage)->isInit==0 ){ btreePageFromDbPage(pDbPage, pgno, pBt); rc = btreeInitPage(*ppPage); if( rc!=SQLITE_OK ){ - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } } assert( (*ppPage)->pgno==pgno ); @@ -2149,12 +2182,13 @@ static int getAndInitPage( ** compatible with the root page. */ if( pCur && ((*ppPage)->nCell<1 || (*ppPage)->intKey!=pCur->curIntKey) ){ rc = SQLITE_CORRUPT_PGNO(pgno); - releasePage(*ppPage); - goto getAndInitPage_error; + goto getAndInitPage_error2; } return SQLITE_OK; -getAndInitPage_error: +getAndInitPage_error2: + releasePage(*ppPage); +getAndInitPage_error1: if( pCur ){ pCur->iPage--; pCur->pPage = pCur->apPage[pCur->iPage]; @@ -6566,6 +6600,7 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){ assert( CORRUPT_DB || sz==cellSize(pPage, idx) ); assert( sqlite3PagerIswriteable(pPage->pDbPage) ); assert( sqlite3_mutex_held(pPage->pBt->mutex) ); + assert( pPage->nFree>=0 ); data = pPage->aData; ptr = &pPage->aCellIdx[2*idx]; pc = get2byte(ptr); @@ -6636,6 +6671,7 @@ static void insertCell( ** might be less than 8 (leaf-size + pointer) on the interior node. Hence ** the term after the || in the following assert(). */ assert( sz==pPage->xCellSize(pPage, pCell) || (sz==8 && iChild>0) ); + assert( pPage->nFree>=0 ); if( pPage->nOverflow || sz+2>pPage->nFree ){ if( pTemp ){ memcpy(pTemp, pCell, sz); @@ -7187,8 +7223,17 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( sqlite3_mutex_held(pPage->pBt->mutex) ); assert( sqlite3PagerIswriteable(pParent->pDbPage) ); assert( pPage->nOverflow==1 ); - + if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) return rc; + } + if( pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + if( rc ) return rc; + } + /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -7466,6 +7511,10 @@ static int balance_nonroot( if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } + if( pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + if( rc ) return rc; + } /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on @@ -7501,6 +7550,9 @@ static int balance_nonroot( pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); + if( rc==0 && apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; @@ -7704,6 +7756,7 @@ static int balance_nonroot( b.apEnd[k] = pParent->aDataEnd; b.ixNx[k] = cntOld[i]+1; } + assert( p->nFree>=0 ); szNew[i] = usableSpace - p->nFree; for(j=0; jnOverflow; j++){ szNew[i] += 2 + p->xCellSize(p, p->apOvfl[j]); @@ -8247,6 +8300,10 @@ static int balance(BtCursor *pCur){ int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) break; + } if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the @@ -8621,6 +8678,10 @@ int sqlite3BtreeInsert( pPage = pCur->pPage; assert( pPage->intKey || pX->nKey>=0 ); assert( pPage->leaf || !pPage->intKey ); + if( pPage->nFree<0 ){ + rc = btreeComputeFreeSpace(pPage); + if( rc ) return rc; + } TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno, @@ -8771,6 +8832,7 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ iCellIdx = pCur->ix; pPage = pCur->pPage; pCell = findCell(pPage, iCellIdx); + if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ) return SQLITE_CORRUPT; /* If the bPreserve flag is set to true, then the cursor position must ** be preserved following this delete operation. If the current delete @@ -8841,6 +8903,10 @@ int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){ Pgno n; unsigned char *pTmp; + if( pLeaf->nFree<0 ){ + rc = btreeComputeFreeSpace(pLeaf); + if( rc ) return rc; + } if( iCellDepthiPage-1 ){ n = pCur->apPage[iCellDepth+1]->pgno; }else{ @@ -9732,6 +9798,11 @@ static int checkTreePage( "btreeInitPage() returns error code %d", rc); goto end_of_check; } + if( (rc = btreeComputeFreeSpace(pPage))!=0 ){ + assert( rc==SQLITE_CORRUPT ); + checkAppendMsg(pCheck, "free space corruption", rc); + goto end_of_check; + } data = pPage->aData; hdr = pPage->hdrOffset; diff --git a/src/btreeInt.h b/src/btreeInt.h index ea5e0815a1..1f7a436b3e 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -286,7 +286,7 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - u16 nFree; /* Number of free bytes on the page */ + int nFree; /* Number of free bytes on the page */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th From 85a379b74b4229f9d6bf54936d2bc71c009929b9 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 9 Feb 2019 22:33:44 +0000 Subject: [PATCH 2/7] Fix a page-cache reference leak in the btree balancer when there is a corrupt database. FossilOrigin-Name: 9285899120dec24ff2944431ad455d7ae217ef408ae2f1a3e7bdfb897099028c --- manifest | 15 ++++++--------- manifest.uuid | 2 +- src/btree.c | 10 +++++++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index dc017b8c18..194a8307a0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Defer\scomputing\sthe\sMemPage.nFree\svalue\sof\san\sin-memory\sbtree\spage\nuntil\sit\sis\sactually\sneeded,\ssince\sfor\smany\spages\sit\sis\snever\sneeded.\nThis\scheckin\sworks\ssufficiently\sto\sprove\sthe\sconcept,\sbut\sstill\shas\sissues\nwith\sexception\shandling. -D 2019-02-09T21:06:40.308 +C Fix\sa\spage-cache\sreference\sleak\sin\sthe\sbtree\sbalancer\swhen\sthere\sis\sa\scorrupt\ndatabase. +D 2019-02-09T22:33:44.636 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c b2bb677fa5d2f18b7c38869761e0d7d1d66ff3a7bdac509865e0606b281d32bc +F src/btree.c 0c9455de1fea43ac2d1384383ae0034c59a9b2a60f12b7eeb934ba27abc91f2b F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 @@ -1804,10 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P db74a56af73d92b7a9d43ceda7e4540915c580c68a0266b4ddefb9e0d5cbcbeb -R 6351a98578ba74f863fbe86b96b0dce9 -T *branch * deferred-free-space -T *sym-deferred-free-space * -T -sym-trunk * +P 1d43ee4000b71f5c6d49244dee96358c567f09ba3451b9d22895a796d3f61ad6 +R b28deed0efae0448ead27e80a7ddacc4 U drh -Z 38c6e8e54a38cca2a22ac1c0553f905f +Z 26932f3ade712321f925e8e95108ce1e diff --git a/manifest.uuid b/manifest.uuid index db390c0838..a414673e10 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1d43ee4000b71f5c6d49244dee96358c567f09ba3451b9d22895a796d3f61ad6 \ No newline at end of file +9285899120dec24ff2944431ad455d7ae217ef408ae2f1a3e7bdfb897099028c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 375d891898..1085bcc725 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7550,13 +7550,17 @@ static int balance_nonroot( pgno = get4byte(pRight); while( 1 ){ rc = getAndInitPage(pBt, pgno, &apOld[i], 0, 0); - if( rc==0 && apOld[i]->nFree<0 ){ - rc = btreeComputeFreeSpace(apOld[i]); - } if( rc ){ memset(apOld, 0, (i+1)*sizeof(MemPage*)); goto balance_cleanup; } + if( apOld[i]->nFree<0 ){ + rc = btreeComputeFreeSpace(apOld[i]); + if( rc ){ + memset(apOld, 0, (i)*sizeof(MemPage*)); + goto balance_cleanup; + } + } nMaxCells += 1+apOld[i]->nCell+apOld[i]->nOverflow; if( (i--)==0 ) break; From c01f41cfa63e413767101a0e71f54f888e446ab4 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 11 Feb 2019 12:51:39 +0000 Subject: [PATCH 3/7] Updates to a comment to keep it in alignment to the changes on this branch. FossilOrigin-Name: 7499f74351415e601eb48eff6b6fccd3a78d137f5ea9cd7cac46b904772966de --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btree.c | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 194a8307a0..e02fc96147 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\spage-cache\sreference\sleak\sin\sthe\sbtree\sbalancer\swhen\sthere\sis\sa\scorrupt\ndatabase. -D 2019-02-09T22:33:44.636 +C Updates\sto\sa\scomment\sto\skeep\sit\sin\salignment\sto\sthe\schanges\son\sthis\sbranch. +D 2019-02-11T12:51:39.303 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 0c9455de1fea43ac2d1384383ae0034c59a9b2a60f12b7eeb934ba27abc91f2b +F src/btree.c 85d49318710ff322811c6f0664cecab1c9d6646175d34878e8b299e9d169a474 F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 @@ -1804,7 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1d43ee4000b71f5c6d49244dee96358c567f09ba3451b9d22895a796d3f61ad6 -R b28deed0efae0448ead27e80a7ddacc4 +P 9285899120dec24ff2944431ad455d7ae217ef408ae2f1a3e7bdfb897099028c +R 53dbac70400c0535df6c7379dea2a735 U drh -Z 26932f3ade712321f925e8e95108ce1e +Z 0c6f69e2cd78e095467b69c3a20fd016 diff --git a/manifest.uuid b/manifest.uuid index a414673e10..603606eaa8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9285899120dec24ff2944431ad455d7ae217ef408ae2f1a3e7bdfb897099028c \ No newline at end of file +7499f74351415e601eb48eff6b6fccd3a78d137f5ea9cd7cac46b904772966de \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 1085bcc725..d3805823ad 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1433,8 +1433,8 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){ if( (int)data[hdr+7]<=nMaxFrag ){ int iFree = get2byte(&data[hdr+1]); - /* If the initial freeblock offset were out of bounds, that would - ** have been detected by btreeInitPage() when it was computing the + /* If the initial freeblock offset were out of bounds, that would have + ** been detected by btreeComputeFreeSpace() when it was computing the ** number of free bytes on the page. */ assert( iFree<=usableSize-4 ); if( iFree ){ From 6813350966beba60f4ede1a4e25372fae926ca3d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 11 Feb 2019 17:22:30 +0000 Subject: [PATCH 4/7] Fix test cases. Avoid unnecessary tests for MemPage.nFree less than zero. FossilOrigin-Name: 480a5090befdc29eaeb6f0b22831c980d6ee92438d9b2e766de68b037ded38b8 --- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/btree.c | 19 ++++++------------- test/corrupt2.test | 18 ++++++++---------- test/corruptD.test | 5 +++-- test/corruptK.test | 6 ++++++ 6 files changed, 33 insertions(+), 35 deletions(-) diff --git a/manifest b/manifest index e02fc96147..2326789bea 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sa\scomment\sto\skeep\sit\sin\salignment\sto\sthe\schanges\son\sthis\sbranch. -D 2019-02-11T12:51:39.303 +C Fix\stest\scases.\s\sAvoid\sunnecessary\stests\sfor\sMemPage.nFree\sless\sthan\szero. +D 2019-02-11T17:22:30.984 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 85d49318710ff322811c6f0664cecab1c9d6646175d34878e8b299e9d169a474 +F src/btree.c aa182a9b5ac74db26086c8cb004d64de3fba4a5970ca788e324bebb256393479 F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 @@ -738,7 +738,7 @@ F test/conflict2.test bb0b94cf7196c64a3cbd815c66d3ee98c2fecd9c F test/conflict3.test a83db76a6c3503b2fa057c7bfb08c318d8a422202d8bc5b86226e078e5b49ff9 F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4 F test/corrupt.test d7cb0300e4a297147b6a05e92a1684bc8973635c3bcaa3d66e983c9cbdbf47a3 -F test/corrupt2.test a7f95356d19a4e8bf9423622ad865cabf48ae49dad40eb7a17a0b39f1cdd6948 +F test/corrupt2.test bb50042cf9a1f1023d73af325d47eb02a6bb11e3c52f8812644b220c5d4bca35 F test/corrupt3.test f95d7bf78109e0b84eb285a787ce91a3fd6a2dd7d0cb55882abff3bdc081a57e F test/corrupt4.test 8d1d86b850fcc43e417450454f2044e52d55778a F test/corrupt5.test 387be3250795e2a86e6234745558b80efb248a357d0cd8e53bce75c7463f545d @@ -749,14 +749,14 @@ F test/corrupt9.test 730a3db08d4ab9aa43392ea30d9c2b4879cbff85 F test/corruptA.test 112f4b2ae0b95ebf3ea63718642fb969a93acea557ace3a307234d19c245989b F test/corruptB.test 73a8d6c0b9833697ecf16b63e3c5c05c945b5dec F test/corruptC.test 138ecb02188ed1a719b533d4a139568204039f72f00e07a8d30d920bd83122db -F test/corruptD.test b3c205fac7952b1de645ce44bb02335cd9e3e040 +F test/corruptD.test 33a37ce3ed56a20093ceee778cd2d7109c7085a59f3213d2baede11d952e8e50 F test/corruptE.test 82ccf4f8f543fdbedd4aa42c709cb077f7374c62 F test/corruptF.test be9fde98e4c93648f1ba52b74e5318edc8f59fe4 F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51 F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454 F test/corruptI.test a17bbf54fdde78d43cf3cc34b0057719fd4a173a3d824285b67dc5257c064c7b F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4 -F test/corruptK.test 5ef338c560ca4dfb7360828da16f1829be4deba3b378cafdc7a1cdaf027eb5c4 +F test/corruptK.test 5b4212fe346699831c5ad559a62c54e11c0611bdde1ea8423a091f9c01aa32af F test/corruptL.test 0f64242b83db6d0bd5b6e38c205bf7c2a3bc6c9f80351f49c4dee1639aca60d8 F test/cost.test 51f4fcaae6e78ad5a57096831259ed6c760e2ac6876836e91c00030fad385b34 F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c @@ -1804,7 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9285899120dec24ff2944431ad455d7ae217ef408ae2f1a3e7bdfb897099028c -R 53dbac70400c0535df6c7379dea2a735 +P 7499f74351415e601eb48eff6b6fccd3a78d137f5ea9cd7cac46b904772966de +R 2bddb3922f13e5970175a7d20955a56a U drh -Z 0c6f69e2cd78e095467b69c3a20fd016 +Z e6d6ab91319b683b695ef49a0d7e5092 diff --git a/manifest.uuid b/manifest.uuid index 603606eaa8..f2328d4d70 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7499f74351415e601eb48eff6b6fccd3a78d137f5ea9cd7cac46b904772966de \ No newline at end of file +480a5090befdc29eaeb6f0b22831c980d6ee92438d9b2e766de68b037ded38b8 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index d3805823ad..6ac0a7f134 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7225,15 +7225,8 @@ static int balance_quick(MemPage *pParent, MemPage *pPage, u8 *pSpace){ assert( pPage->nOverflow==1 ); if( pPage->nCell==0 ) return SQLITE_CORRUPT_BKPT; /* dbfuzz001.test */ - if( pPage->nFree<0 ){ - rc = btreeComputeFreeSpace(pPage); - if( rc ) return rc; - } - if( pParent->nFree<0 ){ - rc = btreeComputeFreeSpace(pParent); - if( rc ) return rc; - } - + assert( pPage->nFree>=0 ); + assert( pParent->nFree>=0 ); /* Allocate a new page. This page will become the right-sibling of ** pPage. Make the parent page writable, so that the new divider cell @@ -7511,10 +7504,7 @@ static int balance_nonroot( if( !aOvflSpace ){ return SQLITE_NOMEM_BKPT; } - if( pParent->nFree<0 ){ - rc = btreeComputeFreeSpace(pParent); - if( rc ) return rc; - } + assert( pParent->nFree>=0 ); /* Find the sibling pages to balance. Also locate the cells in pParent ** that divide the siblings. An attempt is made to find NN siblings on @@ -8336,6 +8326,9 @@ static int balance(BtCursor *pCur){ int const iIdx = pCur->aiIdx[iPage-1]; rc = sqlite3PagerWrite(pParent->pDbPage); + if( rc==SQLITE_OK && pParent->nFree<0 ){ + rc = btreeComputeFreeSpace(pParent); + } if( rc==SQLITE_OK ){ #ifndef SQLITE_OMIT_QUICKBALANCE if( pPage->intKeyLeaf diff --git a/test/corrupt2.test b/test/corrupt2.test index eee7ed322c..f97a526ef5 100644 --- a/test/corrupt2.test +++ b/test/corrupt2.test @@ -95,11 +95,11 @@ do_test corrupt2-1.4 { close $f sqlite3 db2 corrupt.db - catchsql " - $::presql - SELECT * FROM sqlite_master; - " db2 -} {1 {database disk image is malformed}} + # Note: This test is no longer meaningful due to the deferred computation + # of MemPage.nFree + catchsql {PRAGMA quick_check} db2 +} {0 {{*** in database main *** +Page 1: free space corruption}}} do_test corrupt2-1.5 { db2 close @@ -118,11 +118,9 @@ do_test corrupt2-1.5 { close $f sqlite3 db2 corrupt.db - catchsql " - $::presql - SELECT * FROM sqlite_master; - " db2 -} {1 {database disk image is malformed}} + catchsql {PRAGMA quick_check} db2 +} {0 {{*** in database main *** +Page 1: free space corruption}}} db2 close # Corrupt a database by having 2 indices of the same name: diff --git a/test/corruptD.test b/test/corruptD.test index 63474584c3..eb6ccb3fcd 100644 --- a/test/corruptD.test +++ b/test/corruptD.test @@ -111,8 +111,9 @@ proc restore_file {} { do_test corruptD-1.1.1 { incr_change_counter hexio_write test.db [expr 1024+1] FFFF - catchsql { SELECT * FROM t1 ORDER BY rowid } -} {1 {database disk image is malformed}} + catchsql { PRAGMA quick_check } +} {0 {{*** in database main *** +Page 2: free space corruption}}} do_test corruptD-1.1.2 { incr_change_counter hexio_write test.db [expr 1024+1] [hexio_render_int32 1021] diff --git a/test/corruptK.test b/test/corruptK.test index ad5b9a4718..1569afe4a8 100644 --- a/test/corruptK.test +++ b/test/corruptK.test @@ -68,9 +68,15 @@ do_test 1.2 { do_execsql_test 1.3 { INSERT INTO t1 VALUES(randomblob(20)); } + +# This test no longer functions due to the deferred computation of +# MemPage.nFree. +# +if 0 { do_catchsql_test 1.4 { INSERT INTO t1 VALUES(randomblob(90)); } {1 {database disk image is malformed}} +} #------------------------------------------------------------------------- reset_db From d4a6744b501483c7e5bb06660906f9077f0d9835 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 11 Feb 2019 19:27:36 +0000 Subject: [PATCH 5/7] Improvements to comments. No changes to code. FossilOrigin-Name: 16eb0fc8f8cce51eaa5305ebc9f3bd8c8d935dd3ebebab6820e5629f9292eec2 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btree.c | 6 +++--- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 2326789bea..1cfcf11052 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stest\scases.\s\sAvoid\sunnecessary\stests\sfor\sMemPage.nFree\sless\sthan\szero. -D 2019-02-11T17:22:30.984 +C Improvements\sto\scomments.\s\sNo\schanges\sto\scode. +D 2019-02-11T19:27:36.989 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c aa182a9b5ac74db26086c8cb004d64de3fba4a5970ca788e324bebb256393479 +F src/btree.c 47812e0c85425f27c6c51c26a43f04f3adc182ec7ead668329d4f1b1105f43ff F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 @@ -1804,7 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7499f74351415e601eb48eff6b6fccd3a78d137f5ea9cd7cac46b904772966de -R 2bddb3922f13e5970175a7d20955a56a +P 480a5090befdc29eaeb6f0b22831c980d6ee92438d9b2e766de68b037ded38b8 +R f2a2d10c39d9bff959dca395bf0124e2 U drh -Z e6d6ab91319b683b695ef49a0d7e5092 +Z eb3347596121c04ba47ec98ac52bc64e diff --git a/manifest.uuid b/manifest.uuid index f2328d4d70..5c2ee95672 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -480a5090befdc29eaeb6f0b22831c980d6ee92438d9b2e766de68b037ded38b8 \ No newline at end of file +16eb0fc8f8cce51eaa5305ebc9f3bd8c8d935dd3ebebab6820e5629f9292eec2 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 6ac0a7f134..9d76c21a51 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1634,9 +1634,9 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){ } } - /* If there is enough space between gap and top for one more cell pointer - ** array entry offset, and if the freelist is not empty, then search the - ** freelist looking for a free slot big enough to satisfy the request. + /* If there is enough space between gap and top for one more cell pointer, + ** and if the freelist is not empty, then search the + ** freelist looking for a slot big enough to satisfy the request. */ testcase( gap+2==top ); testcase( gap+1==top ); From 8357c662b3b0110b7ba0eda82d9fbb787dd20b03 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 11 Feb 2019 22:50:01 +0000 Subject: [PATCH 6/7] Do not invoke btreeComputeFreeSpace() when not necessary. FossilOrigin-Name: f11b0ed47402034378ded2c60b82841b81cd1319cdb72d1ef052faef29a5294d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/btree.c | 6 ++---- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 1cfcf11052..1a0efad9ac 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\scomments.\s\sNo\schanges\sto\scode. -D 2019-02-11T19:27:36.989 +C Do\snot\sinvoke\sbtreeComputeFreeSpace()\swhen\snot\snecessary. +D 2019-02-11T22:50:01.937 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,7 +455,7 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 47812e0c85425f27c6c51c26a43f04f3adc182ec7ead668329d4f1b1105f43ff +F src/btree.c 70ac9dc86196416147baa94969c71372d1e3dacaca54602bda9c516b02f6da82 F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 @@ -1804,7 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 480a5090befdc29eaeb6f0b22831c980d6ee92438d9b2e766de68b037ded38b8 -R f2a2d10c39d9bff959dca395bf0124e2 +P 16eb0fc8f8cce51eaa5305ebc9f3bd8c8d935dd3ebebab6820e5629f9292eec2 +R 42eb74538b26ea8a320f8b836f86ea2e U drh -Z eb3347596121c04ba47ec98ac52bc64e +Z 326f7ed87f29a92b24fc21835b66ed1d diff --git a/manifest.uuid b/manifest.uuid index 5c2ee95672..3f6605229b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -16eb0fc8f8cce51eaa5305ebc9f3bd8c8d935dd3ebebab6820e5629f9292eec2 \ No newline at end of file +f11b0ed47402034378ded2c60b82841b81cd1319cdb72d1ef052faef29a5294d \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 9d76c21a51..43d6d161a9 100644 --- a/src/btree.c +++ b/src/btree.c @@ -7396,6 +7396,7 @@ static void copyNodeContent(MemPage *pFrom, MemPage *pTo, int *pRC){ */ pTo->isInit = 0; rc = btreeInitPage(pTo); + if( rc==SQLITE_OK ) rc = btreeComputeFreeSpace(pTo); if( rc!=SQLITE_OK ){ *pRC = rc; return; @@ -8294,10 +8295,7 @@ static int balance(BtCursor *pCur){ int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; - if( pPage->nFree<0 ){ - rc = btreeComputeFreeSpace(pPage); - if( rc ) break; - } + assert( pPage->nFree>=0 ); if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the From a941ff712d465fe9eb6b7cf6fa7cf8264898dc7b Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 12 Feb 2019 00:58:10 +0000 Subject: [PATCH 7/7] Change an assert() into a NEVER(), since the condition is difficult to prove with certainty. Improved comment on the MemPage.nFree field. FossilOrigin-Name: fec071b89df2cbafda365077bb54bc9999e12086f36d6cea8d125662b36638dc --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/btree.c | 2 +- src/btreeInt.h | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 1a0efad9ac..cbed7e3fde 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sinvoke\sbtreeComputeFreeSpace()\swhen\snot\snecessary. -D 2019-02-11T22:50:01.937 +C Change\san\sassert()\sinto\sa\sNEVER(),\ssince\sthe\scondition\sis\sdifficult\sto\sprove\nwith\scertainty.\s\sImproved\scomment\son\sthe\sMemPage.nFree\sfield. +D 2019-02-12T00:58:10.125 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 178d8eb6840771149cee40b322d1b3be30d330198c522c903c1b66fb5a1bfca4 @@ -455,9 +455,9 @@ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 -F src/btree.c 70ac9dc86196416147baa94969c71372d1e3dacaca54602bda9c516b02f6da82 +F src/btree.c 7457f7813873877041ec7e04d76a041c81831704a73419882fbe1c222ce6a68c F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 -F src/btreeInt.h d7520b98e72f9a7e2a3140cc476df461fa8a34a3d56258184f8c26f70248cef9 +F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f F src/build.c 906ca6663b9dcd413e72ae9c44dd51e596d8336b04d52e678a7501e71c20cab2 F src/callback.c 25dda5e1c2334a367b94a64077b1d06b2553369f616261ca6783c48bcb6bda73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e @@ -1804,7 +1804,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 16eb0fc8f8cce51eaa5305ebc9f3bd8c8d935dd3ebebab6820e5629f9292eec2 -R 42eb74538b26ea8a320f8b836f86ea2e +P f11b0ed47402034378ded2c60b82841b81cd1319cdb72d1ef052faef29a5294d +R b9fd86c9b0e983ebe73f0426098d02c6 U drh -Z 326f7ed87f29a92b24fc21835b66ed1d +Z 3b166eeca4670760101eb14216736649 diff --git a/manifest.uuid b/manifest.uuid index 3f6605229b..de8af99627 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f11b0ed47402034378ded2c60b82841b81cd1319cdb72d1ef052faef29a5294d \ No newline at end of file +fec071b89df2cbafda365077bb54bc9999e12086f36d6cea8d125662b36638dc \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 43d6d161a9..4cbad04e4e 100644 --- a/src/btree.c +++ b/src/btree.c @@ -8295,7 +8295,7 @@ static int balance(BtCursor *pCur){ int iPage = pCur->iPage; MemPage *pPage = pCur->pPage; - assert( pPage->nFree>=0 ); + if( NEVER(pPage->nFree<0) && btreeComputeFreeSpace(pPage) ) break; if( iPage==0 ){ if( pPage->nOverflow ){ /* The root page of the b-tree is overfull. In this case call the diff --git a/src/btreeInt.h b/src/btreeInt.h index 1f7a436b3e..ddd374efc9 100644 --- a/src/btreeInt.h +++ b/src/btreeInt.h @@ -286,7 +286,7 @@ struct MemPage { u16 maxLocal; /* Copy of BtShared.maxLocal or BtShared.maxLeaf */ u16 minLocal; /* Copy of BtShared.minLocal or BtShared.minLeaf */ u16 cellOffset; /* Index in aData of first cell pointer */ - int nFree; /* Number of free bytes on the page */ + int nFree; /* Number of free bytes on the page. -1 for unknown */ u16 nCell; /* Number of cells on this page, local and ovfl */ u16 maskPage; /* Mask for page offset */ u16 aiOvfl[4]; /* Insert the i-th overflow cell before the aiOvfl-th