mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-08 14:02:16 +03:00
Avoid moving pages more than once in an incremental vacuum operation.
FossilOrigin-Name: c3939d249119b47bd57baa11a5ed7cc6014fc795
This commit is contained in:
17
manifest
17
manifest
@@ -1,5 +1,5 @@
|
|||||||
C On\sMinix,\sdisable\sthe\s".timer"\scommand\sin\sthe\sshell\sin\sorder\sto\savoid\ncalling\sgetrusage().
|
C Avoid\smoving\spages\smore\sthan\sonce\sin\san\sincremental\svacuum\soperation.
|
||||||
D 2013-02-20T00:54:21.855
|
D 2013-02-22T20:16:34.273
|
||||||
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
|
||||||
F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
|
F Makefile.in a48faa9e7dd7d556d84f5456eabe5825dd8a6282
|
||||||
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
|
||||||
@@ -121,7 +121,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
|
|||||||
F src/backup.c 32e35a3a4ea55b45c0e5f74eeb793aec71491517
|
F src/backup.c 32e35a3a4ea55b45c0e5f74eeb793aec71491517
|
||||||
F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1
|
F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1
|
||||||
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
|
||||||
F src/btree.c 7a80e4a67f32a2494c383a28a495bf3bd71cc230
|
F src/btree.c 960274cb93c1d85e82bd106094e0890d89434ab8
|
||||||
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
|
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd
|
||||||
F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621
|
F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621
|
||||||
F src/build.c 73ca65f32938e4e0d94e831b61b5749b211b79be
|
F src/build.c 73ca65f32938e4e0d94e831b61b5749b211b79be
|
||||||
@@ -1034,7 +1034,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
|
|||||||
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
|
||||||
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
|
||||||
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
|
||||||
P 06bd91305ed6752315c5224be5f89e87cafa6687
|
P 9bd9bd9cab8c804c1a51d472199459176044a633
|
||||||
R 14c0fedf89f00b14b7845aeac312ffca
|
R d336ad839cab7fc86035cb53790f3fce
|
||||||
U drh
|
T *branch * incr-vacuum-opt
|
||||||
Z 673b617e6189db9a51be1e6b0160e6d4
|
T *sym-incr-vacuum-opt *
|
||||||
|
T -sym-trunk *
|
||||||
|
U dan
|
||||||
|
Z cd58f1fbd68ec5de5d0f48d285a49284
|
||||||
|
@@ -1 +1 @@
|
|||||||
9bd9bd9cab8c804c1a51d472199459176044a633
|
c3939d249119b47bd57baa11a5ed7cc6014fc795
|
123
src/btree.c
123
src/btree.c
@@ -2909,26 +2909,28 @@ static int relocatePage(
|
|||||||
|
|
||||||
/* Forward declaration required by incrVacuumStep(). */
|
/* Forward declaration required by incrVacuumStep(). */
|
||||||
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
||||||
|
#define BTALLOC_ANY 0 /* Allocate any page */
|
||||||
|
#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
|
||||||
|
#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Perform a single step of an incremental-vacuum. If successful,
|
** Perform a single step of an incremental-vacuum. If successful, return
|
||||||
** return SQLITE_OK. If there is no work to do (and therefore no
|
** SQLITE_OK. If there is no work to do (and therefore no point in
|
||||||
** point in calling this function again), return SQLITE_DONE.
|
** calling this function again), return SQLITE_DONE. Or, if an error
|
||||||
|
** occurs, return some other error code.
|
||||||
**
|
**
|
||||||
** More specificly, this function attempts to re-organize the
|
** More specificly, this function attempts to re-organize the database so
|
||||||
** database so that the last page of the file currently in use
|
** that the last page of the file currently in use is no longer in use.
|
||||||
** is no longer in use.
|
|
||||||
**
|
**
|
||||||
** If the nFin parameter is non-zero, this function assumes
|
** Parameter nFin is the number of pages that this database would contain
|
||||||
** that the caller will keep calling incrVacuumStep() until
|
** were this function called until it returns SQLITE_DONE.
|
||||||
** it returns SQLITE_DONE or an error, and that nFin is the
|
**
|
||||||
** number of pages the database file will contain after this
|
** If the bCommit parameter is non-zero, this function assumes that the
|
||||||
** process is complete. If nFin is zero, it is assumed that
|
** caller will keep calling incrVacuumStep() until it returns SQLITE_DONE
|
||||||
** incrVacuumStep() will be called a finite amount of times
|
** or an error. bCommit is passed true for an auto-vacuum-on-commmit
|
||||||
** which may or may not empty the freelist. A full autovacuum
|
** operation, or false for an incremental vacuum.
|
||||||
** has nFin>0. A "PRAGMA incremental_vacuum" has nFin==0.
|
|
||||||
*/
|
*/
|
||||||
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
|
||||||
Pgno nFreeList; /* Number of pages still on the free-list */
|
Pgno nFreeList; /* Number of pages still on the free-list */
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -2953,15 +2955,15 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( eType==PTRMAP_FREEPAGE ){
|
if( eType==PTRMAP_FREEPAGE ){
|
||||||
if( nFin==0 ){
|
if( bCommit==0 ){
|
||||||
/* Remove the page from the files free-list. This is not required
|
/* Remove the page from the files free-list. This is not required
|
||||||
** if nFin is non-zero. In that case, the free-list will be
|
** if bCommit is non-zero. In that case, the free-list will be
|
||||||
** truncated to zero after this function returns, so it doesn't
|
** truncated to zero after this function returns, so it doesn't
|
||||||
** matter if it still contains some garbage entries.
|
** matter if it still contains some garbage entries.
|
||||||
*/
|
*/
|
||||||
Pgno iFreePg;
|
Pgno iFreePg;
|
||||||
MemPage *pFreePg;
|
MemPage *pFreePg;
|
||||||
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
|
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, BTALLOC_EXACT);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -2971,28 +2973,34 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|||||||
} else {
|
} else {
|
||||||
Pgno iFreePg; /* Index of free page to move pLastPg to */
|
Pgno iFreePg; /* Index of free page to move pLastPg to */
|
||||||
MemPage *pLastPg;
|
MemPage *pLastPg;
|
||||||
|
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
|
||||||
|
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
|
||||||
|
|
||||||
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
|
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If nFin is zero, this loop runs exactly once and page pLastPg
|
/* If bCommit is zero, this loop runs exactly once and page pLastPg
|
||||||
** is swapped with the first free page pulled off the free list.
|
** is swapped with the first free page pulled off the free list.
|
||||||
**
|
**
|
||||||
** On the other hand, if nFin is greater than zero, then keep
|
** On the other hand, if bCommit is greater than zero, then keep
|
||||||
** looping until a free-page located within the first nFin pages
|
** looping until a free-page located within the first nFin pages
|
||||||
** of the file is found.
|
** of the file is found.
|
||||||
*/
|
*/
|
||||||
|
if( bCommit==0 ){
|
||||||
|
eMode = BTALLOC_LE;
|
||||||
|
iNear = nFin;
|
||||||
|
}
|
||||||
do {
|
do {
|
||||||
MemPage *pFreePg;
|
MemPage *pFreePg;
|
||||||
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
|
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iNear, eMode);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
releasePage(pLastPg);
|
releasePage(pLastPg);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
releasePage(pFreePg);
|
releasePage(pFreePg);
|
||||||
}while( nFin!=0 && iFreePg>nFin );
|
}while( bCommit && iFreePg>nFin );
|
||||||
assert( iFreePg<iLastPg );
|
assert( iFreePg<iLastPg );
|
||||||
|
|
||||||
rc = sqlite3PagerWrite(pLastPg->pDbPage);
|
rc = sqlite3PagerWrite(pLastPg->pDbPage);
|
||||||
@@ -3006,7 +3014,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( nFin==0 ){
|
if( bCommit==0 ){
|
||||||
iLastPg--;
|
iLastPg--;
|
||||||
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
|
while( iLastPg==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||||
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
|
if( PTRMAP_ISPAGE(pBt, iLastPg) ){
|
||||||
@@ -3029,6 +3037,30 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg){
|
|||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The database opened by the first argument is an auto-vacuum database
|
||||||
|
** nOrig pages in size containing nFree free pages. Return the expected
|
||||||
|
** size of the database in pages following an auto-vacuum operation.
|
||||||
|
*/
|
||||||
|
static Pgno finalDbSize(BtShared *pBt, Pgno nOrig, Pgno nFree){
|
||||||
|
int nEntry; /* Number of entries on one ptrmap page */
|
||||||
|
Pgno nPtrmap; /* Number of PtrMap pages to be freed */
|
||||||
|
Pgno nFin; /* Return value */
|
||||||
|
|
||||||
|
nEntry = pBt->usableSize/5;
|
||||||
|
nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
|
||||||
|
nFin = nOrig - nFree - nPtrmap;
|
||||||
|
if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
|
||||||
|
nFin--;
|
||||||
|
}
|
||||||
|
while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
|
||||||
|
nFin--;
|
||||||
|
}
|
||||||
|
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
|
||||||
|
|
||||||
|
return nFin;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** A write-transaction must be opened before calling this function.
|
** A write-transaction must be opened before calling this function.
|
||||||
** It performs a single unit of work towards an incremental vacuum.
|
** It performs a single unit of work towards an incremental vacuum.
|
||||||
@@ -3046,12 +3078,20 @@ int sqlite3BtreeIncrVacuum(Btree *p){
|
|||||||
if( !pBt->autoVacuum ){
|
if( !pBt->autoVacuum ){
|
||||||
rc = SQLITE_DONE;
|
rc = SQLITE_DONE;
|
||||||
}else{
|
}else{
|
||||||
|
Pgno nOrig = btreePagecount(pBt);
|
||||||
|
Pgno nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||||
|
Pgno nFin = finalDbSize(pBt, nOrig, nFree);
|
||||||
|
|
||||||
|
if( nFin<nOrig ){
|
||||||
invalidateAllOverflowCache(pBt);
|
invalidateAllOverflowCache(pBt);
|
||||||
rc = incrVacuumStep(pBt, 0, btreePagecount(pBt));
|
rc = incrVacuumStep(pBt, nFin, nOrig, 0);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||||
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
put4byte(&pBt->pPage1->aData[28], pBt->nPage);
|
||||||
}
|
}
|
||||||
|
}else{
|
||||||
|
rc = SQLITE_DONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
sqlite3BtreeLeave(p);
|
sqlite3BtreeLeave(p);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -3077,9 +3117,7 @@ static int autoVacuumCommit(BtShared *pBt){
|
|||||||
if( !pBt->incrVacuum ){
|
if( !pBt->incrVacuum ){
|
||||||
Pgno nFin; /* Number of pages in database after autovacuuming */
|
Pgno nFin; /* Number of pages in database after autovacuuming */
|
||||||
Pgno nFree; /* Number of pages on the freelist initially */
|
Pgno nFree; /* Number of pages on the freelist initially */
|
||||||
Pgno nPtrmap; /* Number of PtrMap pages to be freed */
|
|
||||||
Pgno iFree; /* The next page to be freed */
|
Pgno iFree; /* The next page to be freed */
|
||||||
int nEntry; /* Number of entries on one ptrmap page */
|
|
||||||
Pgno nOrig; /* Database size before freeing */
|
Pgno nOrig; /* Database size before freeing */
|
||||||
|
|
||||||
nOrig = btreePagecount(pBt);
|
nOrig = btreePagecount(pBt);
|
||||||
@@ -3092,19 +3130,11 @@ static int autoVacuumCommit(BtShared *pBt){
|
|||||||
}
|
}
|
||||||
|
|
||||||
nFree = get4byte(&pBt->pPage1->aData[36]);
|
nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||||
nEntry = pBt->usableSize/5;
|
nFin = finalDbSize(pBt, nOrig, nFree);
|
||||||
nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+nEntry)/nEntry;
|
|
||||||
nFin = nOrig - nFree - nPtrmap;
|
|
||||||
if( nOrig>PENDING_BYTE_PAGE(pBt) && nFin<PENDING_BYTE_PAGE(pBt) ){
|
|
||||||
nFin--;
|
|
||||||
}
|
|
||||||
while( PTRMAP_ISPAGE(pBt, nFin) || nFin==PENDING_BYTE_PAGE(pBt) ){
|
|
||||||
nFin--;
|
|
||||||
}
|
|
||||||
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
|
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
|
||||||
|
|
||||||
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
|
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
|
||||||
rc = incrVacuumStep(pBt, nFin, iFree);
|
rc = incrVacuumStep(pBt, nFin, iFree, 1);
|
||||||
}
|
}
|
||||||
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
|
if( (rc==SQLITE_DONE || rc==SQLITE_OK) && nFree>0 ){
|
||||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||||
@@ -4867,7 +4897,7 @@ static int allocateBtreePage(
|
|||||||
MemPage **ppPage,
|
MemPage **ppPage,
|
||||||
Pgno *pPgno,
|
Pgno *pPgno,
|
||||||
Pgno nearby,
|
Pgno nearby,
|
||||||
u8 exact
|
u8 eMode
|
||||||
){
|
){
|
||||||
MemPage *pPage1;
|
MemPage *pPage1;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -4895,7 +4925,8 @@ static int allocateBtreePage(
|
|||||||
** the entire-list will be searched for that page.
|
** the entire-list will be searched for that page.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
if( exact && nearby<=mxPage ){
|
if( eMode==BTALLOC_EXACT ){
|
||||||
|
if( nearby<=mxPage ){
|
||||||
u8 eType;
|
u8 eType;
|
||||||
assert( nearby>0 );
|
assert( nearby>0 );
|
||||||
assert( pBt->autoVacuum );
|
assert( pBt->autoVacuum );
|
||||||
@@ -4904,7 +4935,9 @@ static int allocateBtreePage(
|
|||||||
if( eType==PTRMAP_FREEPAGE ){
|
if( eType==PTRMAP_FREEPAGE ){
|
||||||
searchList = 1;
|
searchList = 1;
|
||||||
}
|
}
|
||||||
*pPgno = nearby;
|
}
|
||||||
|
}else if( eMode==BTALLOC_LE ){
|
||||||
|
searchList = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -4959,11 +4992,13 @@ static int allocateBtreePage(
|
|||||||
rc = SQLITE_CORRUPT_BKPT;
|
rc = SQLITE_CORRUPT_BKPT;
|
||||||
goto end_allocate_page;
|
goto end_allocate_page;
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
}else if( searchList && nearby==iTrunk ){
|
}else if( searchList
|
||||||
|
&& (nearby==iTrunk || (iTrunk<nearby && eMode==BTALLOC_LE))
|
||||||
|
){
|
||||||
/* The list is being searched and this trunk page is the page
|
/* The list is being searched and this trunk page is the page
|
||||||
** to allocate, regardless of whether it has leaves.
|
** to allocate, regardless of whether it has leaves.
|
||||||
*/
|
*/
|
||||||
assert( *pPgno==iTrunk );
|
*pPgno = iTrunk;
|
||||||
*ppPage = pTrunk;
|
*ppPage = pTrunk;
|
||||||
searchList = 0;
|
searchList = 0;
|
||||||
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
rc = sqlite3PagerWrite(pTrunk->pDbPage);
|
||||||
@@ -5047,7 +5082,9 @@ static int allocateBtreePage(
|
|||||||
goto end_allocate_page;
|
goto end_allocate_page;
|
||||||
}
|
}
|
||||||
testcase( iPage==mxPage );
|
testcase( iPage==mxPage );
|
||||||
if( !searchList || iPage==nearby ){
|
if( !searchList
|
||||||
|
|| (iPage==nearby || (iPage<nearby && eMode==BTALLOC_LE))
|
||||||
|
){
|
||||||
int noContent;
|
int noContent;
|
||||||
*pPgno = iPage;
|
*pPgno = iPage;
|
||||||
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
|
||||||
@@ -7119,7 +7156,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
|
|||||||
** be moved to the allocated page (unless the allocated page happens
|
** be moved to the allocated page (unless the allocated page happens
|
||||||
** to reside at pgnoRoot).
|
** to reside at pgnoRoot).
|
||||||
*/
|
*/
|
||||||
rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, 1);
|
rc = allocateBtreePage(pBt, &pPageMove, &pgnoMove, pgnoRoot, BTALLOC_EXACT);
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user