mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Add largely untested code for the incremental vacuum function. (CVS 3876)
FossilOrigin-Name: f6a6d2b8872c05089810b1e095f39011f3035408
This commit is contained in:
29
manifest
29
manifest
@@ -1,5 +1,5 @@
|
|||||||
C In\sthe\spager,\sload\sthe\scontent\sof\spages\swhich\swere\sinitialized\swith\nnoContent==1\sif\sthey\sare\ssubsequently\srequested\swith\snoContent==0.\s(CVS\s3875)
|
C Add\slargely\suntested\scode\sfor\sthe\sincremental\svacuum\sfunction.\s(CVS\s3876)
|
||||||
D 2007-04-26T12:11:28
|
D 2007-04-26T14:42:35
|
||||||
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
|
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
|
||||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -59,9 +59,9 @@ F src/alter.c 2c79ec40f65e33deaf90ca493422c74586e481a3
|
|||||||
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
|
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
|
||||||
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
|
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
|
||||||
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
|
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
|
||||||
F src/btree.c 960bf64baa4d2bdb96019698e60d0b7763bf4e7e
|
F src/btree.c d08db3a8207bf884bd891829cab84c5e4cf18d99
|
||||||
F src/btree.h 9b2cc0d113c0bc2d37d244b9a394d56948c9acbf
|
F src/btree.h 4c0b5855cef3e4e6627358aa69541d21a2015947
|
||||||
F src/build.c 1880da163d9aa404016242b8b76d69907f682cd8
|
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
|
||||||
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
|
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
|
||||||
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
|
F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
|
||||||
F src/date.c 94a6777df13d2aaacd19de080d9e8d3444364133
|
F src/date.c 94a6777df13d2aaacd19de080d9e8d3444364133
|
||||||
@@ -89,8 +89,8 @@ F src/os_win.c e94903c7dc1c0599c8ddce42efa0b6928068ddc5
|
|||||||
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
|
||||||
F src/pager.c cd2770b0f8bd1900b46121009336e7ad03fb274f
|
F src/pager.c cd2770b0f8bd1900b46121009336e7ad03fb274f
|
||||||
F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c
|
F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c
|
||||||
F src/parse.y b6cfbadb6d5b21b5087d30698ee5af0ebb098767
|
F src/parse.y a3940369e12c69c4968aa580cdc74cf73a664980
|
||||||
F src/pragma.c 3b992b5b2640d6ae25cef05aa6a42cd1d6c43234
|
F src/pragma.c 4fdefc03c3fd0ee87f8aad82bf80ba9bf1cdf416
|
||||||
F src/prepare.c 4cb9c9eb926e8baf5652ca4b4f2416f53f5b5370
|
F src/prepare.c 4cb9c9eb926e8baf5652ca4b4f2416f53f5b5370
|
||||||
F src/printf.c 0c6f40648770831341ac45ab32423a80b4c87f05
|
F src/printf.c 0c6f40648770831341ac45ab32423a80b4c87f05
|
||||||
F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
|
F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
|
||||||
@@ -99,7 +99,7 @@ F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
|
|||||||
F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1
|
F src/shell.c 3ae4654560e91220a95738a73d135d91d937cda1
|
||||||
F src/sqlite.h.in e429f66f9245c7f8675db24b230c950b8672ad1c
|
F src/sqlite.h.in e429f66f9245c7f8675db24b230c950b8672ad1c
|
||||||
F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
|
F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
|
||||||
F src/sqliteInt.h 047af0e4c38bbb8652836f72adc9e9199c51a1ba
|
F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0
|
||||||
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
|
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
|
||||||
F src/tclsqlite.c ec69eb9ad56d03fbf7570ca1ca5ea947d1ec4b6f
|
F src/tclsqlite.c ec69eb9ad56d03fbf7570ca1ca5ea947d1ec4b6f
|
||||||
F src/test1.c 53b7eb5cba0012f592b5860f6ad3b5a3f887eb1e
|
F src/test1.c 53b7eb5cba0012f592b5860f6ad3b5a3f887eb1e
|
||||||
@@ -125,7 +125,7 @@ F src/update.c 3359041db390a8f856d67272f299600e2104f350
|
|||||||
F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528
|
F src/utf.c e64a48bc21aa973eb622dd47da87d56a4cdcf528
|
||||||
F src/util.c b6344325378e75b9e18175d8b6aed1723d73dad9
|
F src/util.c b6344325378e75b9e18175d8b6aed1723d73dad9
|
||||||
F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
|
F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
|
||||||
F src/vdbe.c 814dab208a156250bc5e77f827f4e0c8ad734820
|
F src/vdbe.c a3cf3792fdbd382f756eb7eb50006b2f3f8d4283
|
||||||
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
|
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
|
||||||
F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132
|
F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132
|
||||||
F src/vdbeapi.c 245263aa2d70d87b1201753cddc881996f219843
|
F src/vdbeapi.c 245263aa2d70d87b1201753cddc881996f219843
|
||||||
@@ -238,6 +238,7 @@ F test/fts2m.test 4b30142ead6f3ed076e880a2a464064c5ad58c51
|
|||||||
F test/func.test 865febfd5b968f62b85c841c6a305b20346f7f44
|
F test/func.test 865febfd5b968f62b85c841c6a305b20346f7f44
|
||||||
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
|
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
|
||||||
F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
|
F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
|
||||||
|
F test/incrvacuum.test ee05edff95770f211fab28132291c175cd282e0c
|
||||||
F test/index.test e65df12bed94b2903ee89987115e1578687e9266
|
F test/index.test e65df12bed94b2903ee89987115e1578687e9266
|
||||||
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
|
||||||
F test/index3.test f66718cd92ce1216819d47e6a156755e4b2c4ca1
|
F test/index3.test f66718cd92ce1216819d47e6a156755e4b2c4ca1
|
||||||
@@ -394,7 +395,7 @@ F tool/lempar.c 8f998bf8d08e2123149c2cc5d0597cd5d5d1abdd
|
|||||||
F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133
|
F tool/memleak.awk 4e7690a51bf3ed757e611273d43fe3f65b510133
|
||||||
F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
|
F tool/memleak2.awk 9cc20c8e8f3c675efac71ea0721ee6874a1566e8
|
||||||
F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf
|
F tool/memleak3.tcl 7707006ee908cffff210c98158788d85bb3fcdbf
|
||||||
F tool/mkkeywordhash.c c6f797bfc698803d2afbcbfb6b42f2239b074e29
|
F tool/mkkeywordhash.c e119bdc04305adcada8856d73ad7d837c4ec123c
|
||||||
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
|
F tool/mkopts.tcl 66ac10d240cc6e86abd37dc908d50382f84ff46e x
|
||||||
F tool/mksqlite3c.tcl 2d204fc271b2e2a2139e360527dd845385c4dffa
|
F tool/mksqlite3c.tcl 2d204fc271b2e2a2139e360527dd845385c4dffa
|
||||||
F tool/mksqlite3internalh.tcl a85bb0c812db1a060e6e6dfab4e4c817f53d194b
|
F tool/mksqlite3internalh.tcl a85bb0c812db1a060e6e6dfab4e4c817f53d194b
|
||||||
@@ -462,7 +463,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 9cb0ed6ee9827bc6884a0195044d5b6ad0de698e
|
P d0745a43b6e037d16e1ec38c7c4d961a80d1ef48
|
||||||
R 654420a2ec3eb1f548ed11aa685883b0
|
R 9a772b637e3a7b43df139e14c80416c0
|
||||||
U drh
|
U danielk1977
|
||||||
Z 352203b1a39e1bdcedb9d02c8002561c
|
Z d70505e165a313929d975eb44dd8ca1a
|
||||||
|
@@ -1 +1 @@
|
|||||||
d0745a43b6e037d16e1ec38c7c4d961a80d1ef48
|
f6a6d2b8872c05089810b1e095f39011f3035408
|
348
src/btree.c
348
src/btree.c
@@ -9,7 +9,7 @@
|
|||||||
** May you share freely, never taking more than you give.
|
** May you share freely, never taking more than you give.
|
||||||
**
|
**
|
||||||
*************************************************************************
|
*************************************************************************
|
||||||
** $Id: btree.c,v 1.358 2007/04/24 17:35:59 drh Exp $
|
** $Id: btree.c,v 1.359 2007/04/26 14:42:35 danielk1977 Exp $
|
||||||
**
|
**
|
||||||
** This file implements a external (disk-based) database using BTrees.
|
** This file implements a external (disk-based) database using BTrees.
|
||||||
** For a detailed discussion of BTrees, refer to
|
** For a detailed discussion of BTrees, refer to
|
||||||
@@ -336,7 +336,9 @@ struct BtShared {
|
|||||||
u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
|
u8 minLeafFrac; /* Minimum leaf payload as % of total page size */
|
||||||
u8 pageSizeFixed; /* True if the page size can no longer be changed */
|
u8 pageSizeFixed; /* True if the page size can no longer be changed */
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
u8 autoVacuum; /* True if database supports auto-vacuum */
|
u8 autoVacuum; /* True if auto-vacuum is enabled */
|
||||||
|
u8 incrVacuum; /* True if incr-vacuum is enabled */
|
||||||
|
Pgno nTrunc; /* Non-zero if the db will be truncated (incr vacuum) */
|
||||||
#endif
|
#endif
|
||||||
u16 pageSize; /* Total number of bytes on a page */
|
u16 pageSize; /* Total number of bytes on a page */
|
||||||
u16 usableSize; /* Number of usable bytes on each page */
|
u16 usableSize; /* Number of usable bytes on each page */
|
||||||
@@ -510,7 +512,6 @@ struct BtLock {
|
|||||||
#define unlockAllTables(a)
|
#define unlockAllTables(a)
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Query to see if btree handle p may obtain a lock of type eLock
|
** Query to see if btree handle p may obtain a lock of type eLock
|
||||||
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
|
** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return
|
||||||
@@ -1506,7 +1507,7 @@ int sqlite3BtreeOpen(
|
|||||||
){
|
){
|
||||||
BtShared *pBt; /* Shared part of btree structure */
|
BtShared *pBt; /* Shared part of btree structure */
|
||||||
Btree *p; /* Handle to return */
|
Btree *p; /* Handle to return */
|
||||||
int rc;
|
int rc = SQLITE_OK;
|
||||||
int nReserve;
|
int nReserve;
|
||||||
unsigned char zDbHeader[100];
|
unsigned char zDbHeader[100];
|
||||||
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
|
#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)
|
||||||
@@ -1569,22 +1570,15 @@ int sqlite3BtreeOpen(
|
|||||||
|
|
||||||
pBt = sqliteMalloc( sizeof(*pBt) );
|
pBt = sqliteMalloc( sizeof(*pBt) );
|
||||||
if( pBt==0 ){
|
if( pBt==0 ){
|
||||||
*ppBtree = 0;
|
rc = SQLITE_NOMEM;
|
||||||
sqliteFree(p);
|
goto btree_open_out;
|
||||||
return SQLITE_NOMEM;
|
|
||||||
}
|
}
|
||||||
rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
|
rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
|
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
|
||||||
}
|
}
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
if( pBt->pPager ){
|
goto btree_open_out;
|
||||||
sqlite3PagerClose(pBt->pPager);
|
|
||||||
}
|
|
||||||
sqliteFree(pBt);
|
|
||||||
sqliteFree(p);
|
|
||||||
*ppBtree = 0;
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
p->pBt = pBt;
|
p->pBt = pBt;
|
||||||
|
|
||||||
@@ -1602,13 +1596,14 @@ int sqlite3BtreeOpen(
|
|||||||
pBt->minLeafFrac = 32; /* 12.5% */
|
pBt->minLeafFrac = 32; /* 12.5% */
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
/* If the magic name ":memory:" will create an in-memory database, then
|
/* If the magic name ":memory:" will create an in-memory database, then
|
||||||
** do not set the auto-vacuum flag, even if SQLITE_DEFAULT_AUTOVACUUM
|
** leave the autoVacuum mode at 0 (do not auto-vacuum), even if
|
||||||
** is true. On the other hand, if SQLITE_OMIT_MEMORYDB has been defined,
|
** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if
|
||||||
** then ":memory:" is just a regular file-name. Respect the auto-vacuum
|
** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a
|
||||||
** default in this case.
|
** regular file-name. In this case the auto-vacuum applies as per normal.
|
||||||
*/
|
*/
|
||||||
if( zFilename && !isMemdb ){
|
if( zFilename && !isMemdb ){
|
||||||
pBt->autoVacuum = SQLITE_DEFAULT_AUTOVACUUM;
|
pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);
|
||||||
|
pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
nReserve = 0;
|
nReserve = 0;
|
||||||
@@ -1639,7 +1634,17 @@ int sqlite3BtreeOpen(
|
|||||||
#endif
|
#endif
|
||||||
pBt->nRef = 1;
|
pBt->nRef = 1;
|
||||||
*ppBtree = p;
|
*ppBtree = p;
|
||||||
return SQLITE_OK;
|
|
||||||
|
btree_open_out:
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
if( pBt && pBt->pPager ){
|
||||||
|
sqlite3PagerClose(pBt->pPager);
|
||||||
|
}
|
||||||
|
sqliteFree(pBt);
|
||||||
|
sqliteFree(p);
|
||||||
|
*ppBtree = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1819,14 +1824,17 @@ int sqlite3BtreeGetReserve(Btree *p){
|
|||||||
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
|
** determined by the SQLITE_DEFAULT_AUTOVACUUM macro.
|
||||||
*/
|
*/
|
||||||
int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
|
int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
|
||||||
BtShared *pBt = p->pBt;;
|
|
||||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||||
return SQLITE_READONLY;
|
return SQLITE_READONLY;
|
||||||
#else
|
#else
|
||||||
if( pBt->pageSizeFixed ){
|
BtShared *pBt = p->pBt;
|
||||||
|
int av = (autoVacuum?1:0);
|
||||||
|
int iv = (autoVacuum==BTREE_AUTOVACUUM_INCR?1:0);
|
||||||
|
if( pBt->pageSizeFixed && av!=pBt->autoVacuum ){
|
||||||
return SQLITE_READONLY;
|
return SQLITE_READONLY;
|
||||||
}
|
}
|
||||||
pBt->autoVacuum = (autoVacuum?1:0);
|
pBt->autoVacuum = av;
|
||||||
|
pBt->incrVacuum = iv;
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -1837,9 +1845,13 @@ int sqlite3BtreeSetAutoVacuum(Btree *p, int autoVacuum){
|
|||||||
*/
|
*/
|
||||||
int sqlite3BtreeGetAutoVacuum(Btree *p){
|
int sqlite3BtreeGetAutoVacuum(Btree *p){
|
||||||
#ifdef SQLITE_OMIT_AUTOVACUUM
|
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||||
return 0;
|
return BTREE_AUTOVACUUM_NONE;
|
||||||
#else
|
#else
|
||||||
return p->pBt->autoVacuum;
|
return (
|
||||||
|
(!p->pBt->autoVacuum)?BTREE_AUTOVACUUM_NONE:
|
||||||
|
(!p->pBt->incrVacuum)?BTREE_AUTOVACUUM_FULL:
|
||||||
|
BTREE_AUTOVACUUM_INCR
|
||||||
|
);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1998,9 +2010,8 @@ static int newDatabase(BtShared *pBt){
|
|||||||
zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
|
zeroPage(pP1, PTF_INTKEY|PTF_LEAF|PTF_LEAFDATA );
|
||||||
pBt->pageSizeFixed = 1;
|
pBt->pageSizeFixed = 1;
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
if( pBt->autoVacuum ){
|
assert( pBt->autoVacuum==1 || pBt->autoVacuum==0 );
|
||||||
put4byte(&data[36 + 4*4], 1);
|
put4byte(&data[36 + 4*4], pBt->autoVacuum);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
}
|
}
|
||||||
@@ -2285,9 +2296,121 @@ static int relocatePage(
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Forward declaration required by autoVacuumCommit(). */
|
/* Forward declaration required by incrVacuumStep(). */
|
||||||
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Perform a single step of an incremental-vacuum. If successful,
|
||||||
|
** return SQLITE_OK. If there is no work to do (and therefore no
|
||||||
|
** point in calling this function again), return SQLITE_DONE.
|
||||||
|
**
|
||||||
|
** More specificly, this function attempts to re-organize the
|
||||||
|
** database so that the last page of the file currently in use
|
||||||
|
** is no longer in use.
|
||||||
|
**
|
||||||
|
** If the nFin parameter is non-zero, the implementation assumes
|
||||||
|
** that the caller will keep calling incrVacuumStep() until
|
||||||
|
** it returns SQLITE_DONE or an error, and that nFin is the
|
||||||
|
** number of pages the database file will contain after this
|
||||||
|
** process is complete.
|
||||||
|
*/
|
||||||
|
static int incrVacuumStep(BtShared *pBt, Pgno nFin){
|
||||||
|
Pgno iLastPg; /* Last page in the database */
|
||||||
|
Pgno nFreeList; /* Number of pages still on the free-list */
|
||||||
|
|
||||||
|
iLastPg = pBt->nTrunc;
|
||||||
|
if( iLastPg==0 ){
|
||||||
|
iLastPg = sqlite3PagerPagecount(pBt->pPager);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !PTRMAP_ISPAGE(pBt, iLastPg) && iLastPg!=PENDING_BYTE_PAGE(pBt) ){
|
||||||
|
int rc;
|
||||||
|
u8 eType;
|
||||||
|
Pgno iPtrPage;
|
||||||
|
|
||||||
|
nFreeList = get4byte(&pBt->pPage1->aData[36]);
|
||||||
|
if( nFreeList==0 || nFin==iLastPg ){
|
||||||
|
return SQLITE_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ptrmapGet(pBt, iLastPg, &eType, &iPtrPage);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
if( eType==PTRMAP_ROOTPAGE ){
|
||||||
|
return SQLITE_CORRUPT_BKPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( eType==PTRMAP_FREEPAGE ){
|
||||||
|
if( nFin==0 ){
|
||||||
|
/* Remove the page from the files free-list. This is not required
|
||||||
|
** if nFin is non-zero. In this case, the free-list will be
|
||||||
|
** truncated to zero after this function returns, so it doesn't
|
||||||
|
** matter if it still contains some garbage entries.
|
||||||
|
*/
|
||||||
|
Pgno iFreePg;
|
||||||
|
MemPage *pFreePg;
|
||||||
|
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, iLastPg, 1);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
assert( iFreePg==iLastPg );
|
||||||
|
releasePage(pFreePg);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Pgno iFreePg; /* Index of free page to move pLastPg to */
|
||||||
|
MemPage *pLastPg;
|
||||||
|
|
||||||
|
rc = getPage(pBt, iLastPg, &pLastPg, 0);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
MemPage *pFreePg;
|
||||||
|
rc = allocateBtreePage(pBt, &pFreePg, &iFreePg, 0, 0);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
releasePage(pLastPg);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
releasePage(pFreePg);
|
||||||
|
}while( nFin!=0 && iFreePg>nFin );
|
||||||
|
assert( iFreePg<iLastPg );
|
||||||
|
|
||||||
|
rc = relocatePage(pBt, pLastPg, eType, iPtrPage, iFreePg);
|
||||||
|
releasePage(pLastPg);
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pBt->nTrunc = iLastPg - 1;
|
||||||
|
while( pBt->nTrunc==PENDING_BYTE_PAGE(pBt)||PTRMAP_ISPAGE(pBt, pBt->nTrunc) ){
|
||||||
|
pBt->nTrunc--;
|
||||||
|
}
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** A write-transaction must be opened before calling this function.
|
||||||
|
** It performs a single unit of work towards an incremental vacuum.
|
||||||
|
**
|
||||||
|
** If the incremental vacuum is finished after this function has run,
|
||||||
|
** SQLITE_DONE is returned. If it is not finished, but no error occured,
|
||||||
|
** SQLITE_OK is returned. Otherwise an SQLite error code.
|
||||||
|
*/
|
||||||
|
int sqlite3BtreeIncrVacuum(Btree *p){
|
||||||
|
BtShared *pBt = p->pBt;
|
||||||
|
|
||||||
|
assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
|
||||||
|
if( !pBt->autoVacuum ){
|
||||||
|
return SQLITE_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return incrVacuumStep(p->pBt, 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This routine is called prior to sqlite3PagerCommit when a transaction
|
** This routine is called prior to sqlite3PagerCommit when a transaction
|
||||||
** is commited for an auto-vacuum database.
|
** is commited for an auto-vacuum database.
|
||||||
@@ -2298,135 +2421,65 @@ static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|||||||
** pages are in use.
|
** pages are in use.
|
||||||
*/
|
*/
|
||||||
static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
|
static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
Pager *pPager = pBt->pPager;
|
Pager *pPager = pBt->pPager;
|
||||||
Pgno nFreeList; /* Number of pages remaining on the free-list. */
|
|
||||||
int nPtrMap; /* Number of pointer-map pages deallocated */
|
|
||||||
Pgno origSize; /* Pages in the database file */
|
|
||||||
Pgno finSize; /* Pages in the database file after truncation */
|
|
||||||
int rc; /* Return code */
|
|
||||||
u8 eType;
|
|
||||||
int pgsz = pBt->pageSize; /* Page size for this database */
|
|
||||||
Pgno iDbPage; /* The database page to move */
|
|
||||||
MemPage *pDbMemPage = 0; /* "" */
|
|
||||||
Pgno iPtrPage; /* The page that contains a pointer to iDbPage */
|
|
||||||
Pgno iFreePage; /* The free-list page to move iDbPage to */
|
|
||||||
MemPage *pFreeMemPage = 0; /* "" */
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
int nRef = sqlite3PagerRefcount(pPager);
|
int nRef = sqlite3PagerRefcount(pPager);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert( pBt->autoVacuum );
|
|
||||||
if( PTRMAP_ISPAGE(pBt, sqlite3PagerPagecount(pPager)) ){
|
if( PTRMAP_ISPAGE(pBt, sqlite3PagerPagecount(pPager)) ){
|
||||||
return SQLITE_CORRUPT_BKPT;
|
return SQLITE_CORRUPT_BKPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Figure out how many free-pages are in the database. If there are no
|
assert(pBt->autoVacuum);
|
||||||
** free pages, then auto-vacuum is a no-op.
|
if( !pBt->incrVacuum ){
|
||||||
*/
|
Pgno nFin = 0;
|
||||||
nFreeList = get4byte(&pBt->pPage1->aData[36]);
|
|
||||||
if( nFreeList==0 ){
|
if( pBt->nTrunc==0 ){
|
||||||
*pnTrunc = 0;
|
Pgno nFree;
|
||||||
return SQLITE_OK;
|
Pgno nPtrmap;
|
||||||
|
const int pgsz = pBt->pageSize;
|
||||||
|
Pgno nOrig = sqlite3PagerPagecount(pBt->pPager);
|
||||||
|
if( nOrig==PENDING_BYTE_PAGE(pBt) ){
|
||||||
|
nOrig--;
|
||||||
|
}
|
||||||
|
nFree = get4byte(&pBt->pPage1->aData[36]);
|
||||||
|
nPtrmap = (nFree-nOrig+PTRMAP_PAGENO(pBt, nOrig)+pgsz/5)/(pgsz/5);
|
||||||
|
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--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This block figures out how many pages there are in the database
|
while( rc==SQLITE_OK ){
|
||||||
** now (variable origSize), and how many there will be after the
|
rc = incrVacuumStep(pBt, nFin);
|
||||||
** truncation (variable finSize).
|
|
||||||
**
|
|
||||||
** The final size is the original size, less the number of free pages
|
|
||||||
** in the database, less any pointer-map pages that will no longer
|
|
||||||
** be required, less 1 if the pending-byte page was part of the database
|
|
||||||
** but is not after the truncation.
|
|
||||||
**/
|
|
||||||
origSize = sqlite3PagerPagecount(pPager);
|
|
||||||
if( origSize==PENDING_BYTE_PAGE(pBt) ){
|
|
||||||
origSize--;
|
|
||||||
}
|
}
|
||||||
nPtrMap = (nFreeList-origSize+PTRMAP_PAGENO(pBt, origSize)+pgsz/5)/(pgsz/5);
|
if( rc==SQLITE_DONE ){
|
||||||
finSize = origSize - nFreeList - nPtrMap;
|
assert(nFin==0 || pBt->nTrunc==0 || nFin<=pBt->nTrunc);
|
||||||
if( origSize>PENDING_BYTE_PAGE(pBt) && finSize<=PENDING_BYTE_PAGE(pBt) ){
|
rc = SQLITE_OK;
|
||||||
finSize--;
|
if( pBt->nTrunc ){
|
||||||
}
|
sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
||||||
while( PTRMAP_ISPAGE(pBt, finSize) || finSize==PENDING_BYTE_PAGE(pBt) ){
|
|
||||||
finSize--;
|
|
||||||
}
|
|
||||||
TRACE(("AUTOVACUUM: Begin (db size %d->%d)\n", origSize, finSize));
|
|
||||||
|
|
||||||
/* Variable 'finSize' will be the size of the file in pages after
|
|
||||||
** the auto-vacuum has completed (the current file size minus the number
|
|
||||||
** of pages on the free list). Loop through the pages that lie beyond
|
|
||||||
** this mark, and if they are not already on the free list, move them
|
|
||||||
** to a free page earlier in the file (somewhere before finSize).
|
|
||||||
*/
|
|
||||||
for( iDbPage=finSize+1; iDbPage<=origSize; iDbPage++ ){
|
|
||||||
/* If iDbPage is a pointer map page, or the pending-byte page, skip it. */
|
|
||||||
if( PTRMAP_ISPAGE(pBt, iDbPage) || iDbPage==PENDING_BYTE_PAGE(pBt) ){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = ptrmapGet(pBt, iDbPage, &eType, &iPtrPage);
|
|
||||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
|
||||||
if( eType==PTRMAP_ROOTPAGE ){
|
|
||||||
rc = SQLITE_CORRUPT_BKPT;
|
|
||||||
goto autovacuum_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If iDbPage is free, do not swap it. */
|
|
||||||
if( eType==PTRMAP_FREEPAGE ){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
rc = getPage(pBt, iDbPage, &pDbMemPage, 0);
|
|
||||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
|
||||||
|
|
||||||
/* Find the next page in the free-list that is not already at the end
|
|
||||||
** of the file. A page can be pulled off the free list using the
|
|
||||||
** allocateBtreePage() routine.
|
|
||||||
*/
|
|
||||||
do{
|
|
||||||
if( pFreeMemPage ){
|
|
||||||
releasePage(pFreeMemPage);
|
|
||||||
pFreeMemPage = 0;
|
|
||||||
}
|
|
||||||
rc = allocateBtreePage(pBt, &pFreeMemPage, &iFreePage, 0, 0);
|
|
||||||
if( rc!=SQLITE_OK ){
|
|
||||||
releasePage(pDbMemPage);
|
|
||||||
goto autovacuum_out;
|
|
||||||
}
|
|
||||||
assert( iFreePage<=origSize );
|
|
||||||
}while( iFreePage>finSize );
|
|
||||||
releasePage(pFreeMemPage);
|
|
||||||
pFreeMemPage = 0;
|
|
||||||
|
|
||||||
/* Relocate the page into the body of the file. Note that although the
|
|
||||||
** page has moved within the database file, the pDbMemPage pointer
|
|
||||||
** remains valid. This means that this function can run without
|
|
||||||
** invalidating cursors open on the btree. This is important in
|
|
||||||
** shared-cache mode.
|
|
||||||
*/
|
|
||||||
rc = relocatePage(pBt, pDbMemPage, eType, iPtrPage, iFreePage);
|
|
||||||
releasePage(pDbMemPage);
|
|
||||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The entire free-list has been swapped to the end of the file. So
|
|
||||||
** truncate the database file to finSize pages and consider the
|
|
||||||
** free-list empty.
|
|
||||||
*/
|
|
||||||
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
||||||
if( rc!=SQLITE_OK ) goto autovacuum_out;
|
|
||||||
put4byte(&pBt->pPage1->aData[32], 0);
|
put4byte(&pBt->pPage1->aData[32], 0);
|
||||||
put4byte(&pBt->pPage1->aData[36], 0);
|
put4byte(&pBt->pPage1->aData[36], 0);
|
||||||
*pnTrunc = finSize;
|
pBt->nTrunc = nFin;
|
||||||
assert( finSize!=PENDING_BYTE_PAGE(pBt) );
|
}
|
||||||
|
}
|
||||||
autovacuum_out:
|
|
||||||
assert( nRef==sqlite3PagerRefcount(pPager) );
|
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
sqlite3PagerRollback(pPager);
|
sqlite3PagerRollback(pPager);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
*pnTrunc = pBt->nTrunc;
|
||||||
|
pBt->nTrunc = 0;
|
||||||
|
}
|
||||||
|
assert( nRef==sqlite3PagerRefcount(pPager) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2615,6 +2668,10 @@ int sqlite3BtreeRollback(Btree *p){
|
|||||||
if( p->inTrans==TRANS_WRITE ){
|
if( p->inTrans==TRANS_WRITE ){
|
||||||
int rc2;
|
int rc2;
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
pBt->nTrunc = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
assert( TRANS_WRITE==pBt->inTransaction );
|
assert( TRANS_WRITE==pBt->inTransaction );
|
||||||
rc2 = sqlite3PagerRollback(pBt->pPager);
|
rc2 = sqlite3PagerRollback(pBt->pPager);
|
||||||
if( rc2!=SQLITE_OK ){
|
if( rc2!=SQLITE_OK ){
|
||||||
@@ -3854,6 +3911,16 @@ static int allocateBtreePage(
|
|||||||
*pPgno = sqlite3PagerPagecount(pBt->pPager) + 1;
|
*pPgno = sqlite3PagerPagecount(pBt->pPager) + 1;
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_AUTOVACUUM
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
if( pBt->nTrunc ){
|
||||||
|
/* An incr-vacuum has already run within this transaction. So the
|
||||||
|
** page to allocate is not from the physical end of the file, but
|
||||||
|
** at pBt->nTrunc.
|
||||||
|
*/
|
||||||
|
*pPgno = pBt->nTrunc+1;
|
||||||
|
if( *pPgno==PENDING_BYTE_PAGE(pBt) ){
|
||||||
|
(*pPgno)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
|
if( pBt->autoVacuum && PTRMAP_ISPAGE(pBt, *pPgno) ){
|
||||||
/* If *pPgno refers to a pointer-map page, allocate two new pages
|
/* If *pPgno refers to a pointer-map page, allocate two new pages
|
||||||
** at the end of the file instead of one. The first allocated page
|
** at the end of the file instead of one. The first allocated page
|
||||||
@@ -3863,6 +3930,9 @@ static int allocateBtreePage(
|
|||||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||||
(*pPgno)++;
|
(*pPgno)++;
|
||||||
}
|
}
|
||||||
|
if( pBt->nTrunc ){
|
||||||
|
pBt->nTrunc = *pPgno;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
** subsystem. See comments in the source code for a detailed description
|
** subsystem. See comments in the source code for a detailed description
|
||||||
** of what each interface routine does.
|
** of what each interface routine does.
|
||||||
**
|
**
|
||||||
** @(#) $Id: btree.h,v 1.74 2007/03/30 14:06:34 drh Exp $
|
** @(#) $Id: btree.h,v 1.75 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _BTREE_H_
|
#ifndef _BTREE_H_
|
||||||
#define _BTREE_H_
|
#define _BTREE_H_
|
||||||
@@ -31,6 +31,10 @@
|
|||||||
#define SQLITE_DEFAULT_AUTOVACUUM 0
|
#define SQLITE_DEFAULT_AUTOVACUUM 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define BTREE_AUTOVACUUM_NONE 0 /* Do not do auto-vacuum */
|
||||||
|
#define BTREE_AUTOVACUUM_FULL 1 /* Do full auto-vacuum */
|
||||||
|
#define BTREE_AUTOVACUUM_INCR 2 /* Incremental vacuum */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Forward declarations of structure
|
** Forward declarations of structure
|
||||||
*/
|
*/
|
||||||
@@ -87,6 +91,8 @@ const char *sqlite3BtreeGetDirname(Btree *);
|
|||||||
const char *sqlite3BtreeGetJournalname(Btree *);
|
const char *sqlite3BtreeGetJournalname(Btree *);
|
||||||
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
int sqlite3BtreeCopyFile(Btree *, Btree *);
|
||||||
|
|
||||||
|
int sqlite3BtreeIncrVacuum(Btree *);
|
||||||
|
|
||||||
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
/* The flags parameter to sqlite3BtreeCreateTable can be the bitwise OR
|
||||||
** of the following flags:
|
** of the following flags:
|
||||||
*/
|
*/
|
||||||
|
19
src/build.c
19
src/build.c
@@ -22,7 +22,7 @@
|
|||||||
** COMMIT
|
** COMMIT
|
||||||
** ROLLBACK
|
** ROLLBACK
|
||||||
**
|
**
|
||||||
** $Id: build.c,v 1.421 2007/04/18 14:47:24 danielk1977 Exp $
|
** $Id: build.c,v 1.422 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -3349,3 +3349,20 @@ KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
|
|||||||
}
|
}
|
||||||
return pKey;
|
return pKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
/*
|
||||||
|
** This is called to compile a statement of the form "INCREMENTAL VACUUM".
|
||||||
|
*/
|
||||||
|
void sqlite3IncrVacuum(Parse *pParse){
|
||||||
|
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||||
|
if( v ){
|
||||||
|
int addr;
|
||||||
|
sqlite3BeginWriteOperation(pParse, 0, 0);
|
||||||
|
addr = sqlite3VdbeCurrentAddr(v);
|
||||||
|
sqlite3VdbeAddOp(v, OP_IncrVacuum, 0, addr+3);
|
||||||
|
sqlite3VdbeAddOp(v, OP_Callback, 0, 0);
|
||||||
|
sqlite3VdbeAddOp(v, OP_Goto, 0, addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* #ifndef SQLITE_OMIT_AUTOVACUUM */
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
** the parser. Lemon will also generate a header file containing
|
** the parser. Lemon will also generate a header file containing
|
||||||
** numeric codes for all of the tokens.
|
** numeric codes for all of the tokens.
|
||||||
**
|
**
|
||||||
** @(#) $Id: parse.y,v 1.218 2007/04/06 15:02:14 drh Exp $
|
** @(#) $Id: parse.y,v 1.219 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// All token codes are small integers with #defines that begin with "TK_"
|
// All token codes are small integers with #defines that begin with "TK_"
|
||||||
@@ -903,6 +903,10 @@ cmd ::= VACUUM nm. {sqlite3Vacuum(pParse);}
|
|||||||
%endif SQLITE_OMIT_ATTACH
|
%endif SQLITE_OMIT_ATTACH
|
||||||
%endif SQLITE_OMIT_VACUUM
|
%endif SQLITE_OMIT_VACUUM
|
||||||
|
|
||||||
|
%ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
cmd ::= INCREMENTAL VACUUM. {sqlite3IncrVacuum(pParse);}
|
||||||
|
%endif
|
||||||
|
|
||||||
///////////////////////////// The PRAGMA command /////////////////////////////
|
///////////////////////////// The PRAGMA command /////////////////////////////
|
||||||
//
|
//
|
||||||
%ifndef SQLITE_OMIT_PRAGMA
|
%ifndef SQLITE_OMIT_PRAGMA
|
||||||
|
24
src/pragma.c
24
src/pragma.c
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** This file contains code used to implement the PRAGMA command.
|
** This file contains code used to implement the PRAGMA command.
|
||||||
**
|
**
|
||||||
** $Id: pragma.c,v 1.132 2007/03/30 17:11:13 danielk1977 Exp $
|
** $Id: pragma.c,v 1.133 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -73,6 +73,23 @@ static int getLockingMode(const char *z){
|
|||||||
return PAGER_LOCKINGMODE_QUERY;
|
return PAGER_LOCKINGMODE_QUERY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
/*
|
||||||
|
** Interpret the given string as an auto-vacuum mode value.
|
||||||
|
**
|
||||||
|
** The following strings, "none", "full" and "incremental" are
|
||||||
|
** acceptable, as are their numeric equivalents: 0, 1 and 2 respectively.
|
||||||
|
*/
|
||||||
|
static int getAutoVacuum(const char *z){
|
||||||
|
int i;
|
||||||
|
if( 0==sqlite3StrICmp(z, "none") ) return BTREE_AUTOVACUUM_NONE;
|
||||||
|
if( 0==sqlite3StrICmp(z, "full") ) return BTREE_AUTOVACUUM_FULL;
|
||||||
|
if( 0==sqlite3StrICmp(z, "incremental") ) return BTREE_AUTOVACUUM_INCR;
|
||||||
|
i = atoi(z);
|
||||||
|
return ((i>=0&&i<=2)?i:0);
|
||||||
|
}
|
||||||
|
#endif /* ifndef SQLITE_OMIT_AUTOVACUUM */
|
||||||
|
|
||||||
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
#ifndef SQLITE_OMIT_PAGER_PRAGMAS
|
||||||
/*
|
/*
|
||||||
** Interpret the given string as a temp db location. Return 1 for file
|
** Interpret the given string as a temp db location. Return 1 for file
|
||||||
@@ -389,7 +406,10 @@ void sqlite3Pragma(
|
|||||||
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
|
pBt ? sqlite3BtreeGetAutoVacuum(pBt) : SQLITE_DEFAULT_AUTOVACUUM;
|
||||||
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
|
returnSingleInt(pParse, "auto_vacuum", auto_vacuum);
|
||||||
}else{
|
}else{
|
||||||
sqlite3BtreeSetAutoVacuum(pBt, getBoolean(zRight));
|
int eAuto = getAutoVacuum(zRight);
|
||||||
|
if( eAuto>=0 ){
|
||||||
|
sqlite3BtreeSetAutoVacuum(pBt, eAuto);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
*************************************************************************
|
*************************************************************************
|
||||||
** Internal interface definitions for SQLite.
|
** Internal interface definitions for SQLite.
|
||||||
**
|
**
|
||||||
** @(#) $Id: sqliteInt.h,v 1.552 2007/04/16 15:06:25 danielk1977 Exp $
|
** @(#) $Id: sqliteInt.h,v 1.553 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#ifndef _SQLITEINT_H_
|
#ifndef _SQLITEINT_H_
|
||||||
#define _SQLITEINT_H_
|
#define _SQLITEINT_H_
|
||||||
@@ -1913,6 +1913,7 @@ int sqlite3VtabBegin(sqlite3 *, sqlite3_vtab *);
|
|||||||
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
|
FuncDef *sqlite3VtabOverloadFunction(FuncDef*, int nArg, Expr*);
|
||||||
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
|
void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
|
||||||
int sqlite3Reprepare(Vdbe*);
|
int sqlite3Reprepare(Vdbe*);
|
||||||
|
void sqlite3IncrVacuum(Parse *pParse);
|
||||||
|
|
||||||
#ifdef SQLITE_SSE
|
#ifdef SQLITE_SSE
|
||||||
#include "sseInt.h"
|
#include "sseInt.h"
|
||||||
|
20
src/vdbe.c
20
src/vdbe.c
@@ -43,7 +43,7 @@
|
|||||||
** in this file for details. If in doubt, do not deviate from existing
|
** in this file for details. If in doubt, do not deviate from existing
|
||||||
** commenting and indentation practices when changing or adding code.
|
** commenting and indentation practices when changing or adding code.
|
||||||
**
|
**
|
||||||
** $Id: vdbe.c,v 1.601 2007/04/18 16:45:24 drh Exp $
|
** $Id: vdbe.c,v 1.602 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
@@ -4554,6 +4554,24 @@ case OP_Vacuum: { /* no-push */
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SQLITE_OMIT_AUTOVACUUM)
|
||||||
|
/* Opcode: IncrVacuum * P2 *
|
||||||
|
**
|
||||||
|
** Perform a single step of the incremental vacuum procedure on
|
||||||
|
** the main database. If the vacuum has finished, jump to instruction
|
||||||
|
** P2. Otherwise, fall through to the next instruction.
|
||||||
|
*/
|
||||||
|
case OP_IncrVacuum: { /* no-push */
|
||||||
|
Btree *pBt = db->aDb[0].pBt;
|
||||||
|
rc = sqlite3BtreeIncrVacuum(pBt);
|
||||||
|
if( rc==SQLITE_DONE ){
|
||||||
|
pc = pOp->p2 - 1;
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Opcode: Expire P1 * *
|
/* Opcode: Expire P1 * *
|
||||||
**
|
**
|
||||||
** Cause precompiled statements to become expired. An expired statement
|
** Cause precompiled statements to become expired. An expired statement
|
||||||
|
174
test/incrvacuum.test
Normal file
174
test/incrvacuum.test
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# 2007 April 26
|
||||||
|
#
|
||||||
|
# The author disclaims copyright to this source code. In place of
|
||||||
|
# a legal notice, here is a blessing:
|
||||||
|
#
|
||||||
|
# May you do good and not evil.
|
||||||
|
# May you find forgiveness for yourself and forgive others.
|
||||||
|
# May you share freely, never taking more than you give.
|
||||||
|
#
|
||||||
|
#***********************************************************************
|
||||||
|
# This file implements regression tests for SQLite library. The
|
||||||
|
# focus of this file is testing the incremental vacuum feature.
|
||||||
|
#
|
||||||
|
# $Id: incrvacuum.test,v 1.1 2007/04/26 14:42:36 danielk1977 Exp $
|
||||||
|
|
||||||
|
set testdir [file dirname $argv0]
|
||||||
|
source $testdir/tester.tcl
|
||||||
|
|
||||||
|
# If this build of the library does not support auto-vacuum, omit this
|
||||||
|
# whole file.
|
||||||
|
ifcapable {!autovacuum || !pragma} {
|
||||||
|
finish_test
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Test the pragma on an empty database.
|
||||||
|
#
|
||||||
|
do_test incrvacuum-1.1 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {0}
|
||||||
|
do_test incrvacuum-1.2 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'full';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
do_test incrvacuum-1.3 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'incremental';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {2}
|
||||||
|
do_test incrvacuum-1.4 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'invalid';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {0}
|
||||||
|
do_test incrvacuum-1.5 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 1;
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
do_test incrvacuum-1.6 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = '2';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {2}
|
||||||
|
do_test incrvacuum-1.7 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 5;
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {0}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Test the pragma on a non-empty database. It is possible to toggle
|
||||||
|
# the connection between "full" and "incremental" mode, but not to
|
||||||
|
# change from either of these to "none", or from "none" to "full" or
|
||||||
|
# "incremental".
|
||||||
|
#
|
||||||
|
do_test incrvacuum-2.1 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 1;
|
||||||
|
CREATE TABLE abc(a, b, c);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
do_test incrvacuum-2.2 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'none';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
do_test incrvacuum-2.3 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'incremental';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {2}
|
||||||
|
do_test incrvacuum-2.4 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum = 'full';
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Test that when the auto_vacuum mode is "incremental", the database
|
||||||
|
# does not shrink when pages are removed from it. But it does if
|
||||||
|
# the mode is set to "full".
|
||||||
|
#
|
||||||
|
do_test incrvacuum-3.1 {
|
||||||
|
execsql {
|
||||||
|
pragma auto_vacuum;
|
||||||
|
}
|
||||||
|
} {1}
|
||||||
|
do_test incrvacuum-3.2 {
|
||||||
|
set ::str [string repeat 1234567890 110]
|
||||||
|
execsql {
|
||||||
|
PRAGMA auto_vacuum = 2;
|
||||||
|
BEGIN;
|
||||||
|
CREATE TABLE tbl2(str);
|
||||||
|
INSERT INTO tbl2 VALUES($::str);
|
||||||
|
COMMIT;
|
||||||
|
}
|
||||||
|
# 5 pages:
|
||||||
|
#
|
||||||
|
# 1 -> database header
|
||||||
|
# 2 -> first back-pointer page
|
||||||
|
# 3 -> table abc
|
||||||
|
# 4 -> table tbl2
|
||||||
|
# 5 -> table tbl2 overflow page.
|
||||||
|
#
|
||||||
|
expr {[file size test.db] / 1024}
|
||||||
|
} {5}
|
||||||
|
do_test incrvacuum-3.3 {
|
||||||
|
execsql {
|
||||||
|
DROP TABLE abc;
|
||||||
|
DELETE FROM tbl2;
|
||||||
|
}
|
||||||
|
expr {[file size test.db] / 1024}
|
||||||
|
} {5}
|
||||||
|
do_test incrvacuum-3.4 {
|
||||||
|
execsql {
|
||||||
|
PRAGMA auto_vacuum = 1;
|
||||||
|
INSERT INTO tbl2 VALUES('hello world');
|
||||||
|
}
|
||||||
|
expr {[file size test.db] / 1024}
|
||||||
|
} {3}
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------
|
||||||
|
# Try to run a simple incremental vacuum.
|
||||||
|
#
|
||||||
|
do_test incrvacuum-4.1 {
|
||||||
|
set ::str [string repeat 1234567890 110]
|
||||||
|
execsql {
|
||||||
|
PRAGMA auto_vacuum = 2;
|
||||||
|
INSERT INTO tbl2 VALUES($::str);
|
||||||
|
CREATE TABLE tbl1(a, b, c);
|
||||||
|
}
|
||||||
|
expr {[file size test.db] / 1024}
|
||||||
|
} {5}
|
||||||
|
do_test incrvacuum-4.2 {
|
||||||
|
execsql {
|
||||||
|
DELETE FROM tbl2;
|
||||||
|
DROP TABLE tbl1;
|
||||||
|
}
|
||||||
|
expr {[file size test.db] / 1024}
|
||||||
|
} {5}
|
||||||
|
do_test incrvacuum-4.3 {
|
||||||
|
set ::nStep 0
|
||||||
|
db eval {INCREMENTAL VACUUM} {
|
||||||
|
incr ::nStep
|
||||||
|
}
|
||||||
|
list [expr {[file size test.db] / 1024}] $::nStep
|
||||||
|
} {3 2}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
@@ -15,7 +15,7 @@ static const char zHdr[] =
|
|||||||
"**\n"
|
"**\n"
|
||||||
"** The code in this file has been automatically generated by\n"
|
"** The code in this file has been automatically generated by\n"
|
||||||
"**\n"
|
"**\n"
|
||||||
"** $Header: /home/drh/sqlite/trans/cvs/sqlite/sqlite/tool/mkkeywordhash.c,v 1.27 2007/04/06 11:26:00 drh Exp $\n"
|
"** $Header: /home/drh/sqlite/trans/cvs/sqlite/sqlite/tool/mkkeywordhash.c,v 1.28 2007/04/26 14:42:36 danielk1977 Exp $\n"
|
||||||
"**\n"
|
"**\n"
|
||||||
"** The code in this file implements a function that determines whether\n"
|
"** The code in this file implements a function that determines whether\n"
|
||||||
"** or not a given identifier is really an SQL keyword. The same thing\n"
|
"** or not a given identifier is really an SQL keyword. The same thing\n"
|
||||||
@@ -114,7 +114,8 @@ struct Keyword {
|
|||||||
#else
|
#else
|
||||||
# define TRIGGER 0x00002000
|
# define TRIGGER 0x00002000
|
||||||
#endif
|
#endif
|
||||||
#if defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH)
|
#if defined(SQLITE_OMIT_AUTOVACUUM) && \
|
||||||
|
(defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH))
|
||||||
# define VACUUM 0
|
# define VACUUM 0
|
||||||
#else
|
#else
|
||||||
# define VACUUM 0x00004000
|
# define VACUUM 0x00004000
|
||||||
@@ -129,6 +130,11 @@ struct Keyword {
|
|||||||
#else
|
#else
|
||||||
# define VTAB 0x00010000
|
# define VTAB 0x00010000
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SQLITE_OMIT_AUTOVACUUM
|
||||||
|
# define AUTOVACUUM 0
|
||||||
|
#else
|
||||||
|
# define AUTOVACUUM 0x00020000
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** These are the keywords
|
** These are the keywords
|
||||||
@@ -192,6 +198,7 @@ static Keyword aKeywordTable[] = {
|
|||||||
{ "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER },
|
{ "IGNORE", "TK_IGNORE", CONFLICT|TRIGGER },
|
||||||
{ "IMMEDIATE", "TK_IMMEDIATE", ALWAYS },
|
{ "IMMEDIATE", "TK_IMMEDIATE", ALWAYS },
|
||||||
{ "IN", "TK_IN", ALWAYS },
|
{ "IN", "TK_IN", ALWAYS },
|
||||||
|
{ "INCREMENTAL", "TK_INCREMENTAL", AUTOVACUUM },
|
||||||
{ "INDEX", "TK_INDEX", ALWAYS },
|
{ "INDEX", "TK_INDEX", ALWAYS },
|
||||||
{ "INITIALLY", "TK_INITIALLY", FKEY },
|
{ "INITIALLY", "TK_INITIALLY", FKEY },
|
||||||
{ "INNER", "TK_JOIN_KW", ALWAYS },
|
{ "INNER", "TK_JOIN_KW", ALWAYS },
|
||||||
|
Reference in New Issue
Block a user