Support FCNTL_CHUNK_SIZE on windows too.

FossilOrigin-Name: a038688c991435967b935946c2283707820bb5da
This commit is contained in:
dan 2010-07-28 14:26:17 +00:00
parent eb8def8449
commit 502019c8bb
8 changed files with 264 additions and 127 deletions

View File

@ -1,5 +1,5 @@
C Merge\strunk\schanges\sinto\sexperimental\sbranch.
D 2010-07-27T18:36:38
C Support\sFCNTL_CHUNK_SIZE\son\swindows\stoo.
D 2010-07-28T14:26:18
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in ec08dc838fd8110fe24c92e5130bcd91cbb1ff2e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -154,9 +154,9 @@ F src/os.c 60178f518c4d6c0dcb59f7292232281d7bea2dcf
F src/os.h 9dbed8c2b9c1f2f2ebabc09e49829d4777c26bf9
F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
F src/os_os2.c 72d0b2e562952a2464308c4ce5f7913ac10bef3e
F src/os_unix.c 77e963fbbed6a2ca9b7c9115ae06f05181729490
F src/os_win.c 1f8b0a1a5bcf6289e7754d0d3c16cec16d4c93ab
F src/pager.c 78ca1e1f3315c8227431c403c04d791dccf242fb
F src/os_unix.c ae5ca8a6031380708f3fec7be325233d49944914
F src/os_win.c 51cb62f76262d961ea4249489383d714501315a7
F src/pager.c 27ace2e07c8bfe2e04428eba03b2ddb5b03abd7d
F src/pager.h 879fdde5a102d2f21a3135d6f647530b21c2796c
F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
@ -170,7 +170,7 @@ F src/resolve.c 1c0f32b64f8e3f555fe1f732f9d6f501a7f05706
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c 74fef1334bec27e606ef0b19e5c41cd0a639e69c
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
F src/sqlite.h.in 2dfa3db44fd123ea5f0e20e87fa3d9db189feb98
F src/sqlite.h.in 10bd4aed244fc0eadb10ec01cedb60bafc2d7bfe
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
F src/sqliteInt.h a9be6badc6cd6a3c1ae54475a98661cf351ecad5
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
@ -227,7 +227,7 @@ F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
F src/vdbemem.c 5e579abf6532001dfbee0e640dc34eae897a9807
F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
F src/vtab.c 82200af3881fa4e1c9cf07cf31d98c09d437e3ab
F src/wal.c 0925601f3299c2941a67c9cfff41ee710f70ca82
F src/wal.c 72cb5df7f4c26f83cb661d5a607b9918da99f758
F src/wal.h 906c85760598b18584921fe08008435aa4eeeeb2
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c 79202ca81e740eeb1f54512147e29b6c518d84ca
@ -351,7 +351,7 @@ F test/exclusive.test 5fe18e10a159342dd52ca14b1554e33f98734267
F test/exclusive2.test fcbb1c9ca9739292a0a22a3763243ad6d868086b
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/expr.test 9f521ae22f00e074959f72ce2e55d46b9ed23f68
F test/fallocate.test 2aa524a237893aca5b2a7ad5d450ee4801b4abdd
F test/fallocate.test 0594314eb04268f7d0779d054fa850a36a5ae8bc
F test/filectrl.test 97003734290887566e01dded09dc9e99cb937e9e
F test/filefmt.test 5d271bf467e6557fe7499dcc8203069c9dc5825e
F test/fkey1.test 01c7de578e11747e720c2d9aeef27f239853c4da
@ -839,7 +839,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 7cf0e851d4c5e826ea22ed08291b7c91d7b1abc7 8118de2af33557f75b4f2f1b1194a21d46ccf7fe
R db6f0268ed3b851f8967be0e4ae70758
P 621824092d443425c420ba9010bbe1202fe99ea2
R d7ede0d4642b161610b7d818427c7a8c
U dan
Z d9d588012d8704dd90455874cd937598
Z 95d00fbeff8589e69f2af3194811a965

View File

@ -1 +1 @@
621824092d443425c420ba9010bbe1202fe99ea2
a038688c991435967b935946c2283707820bb5da

View File

@ -2765,42 +2765,6 @@ static int unixWrite(
SimulateIOError(( wrote=(-1), amt=1 ));
SimulateDiskfullError(( wrote=0, amt=1 ));
/* If the user has configured a chunk-size for this file, it could be
** that the file needs to be extended at this point.
*/
if( pFile->szChunk && amt==0 ){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
int rc = fstat(pFile->h, &buf);
if( rc!=0 ) return SQLITE_IOERR_FSTAT;
nSize = ((offset+amt+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
#ifdef HAVE_POSIX_FALLOCATE
if( posix_fallocate(pFile->h, buf.st_size, nSize-buf.st_size) ){
return SQLITE_IOERR_WRITE;
}
#else
/* If the OS does not have posix_fallocate(), fake it. First use
** ftruncate() to set the file size, then write a single byte to
** the last byte in each block within the extended region.
*/
int nBlk = buf.st_blksize; /* File-system block size */
i64 iWrite; /* Next offset to write to */
if( ftruncate(pFile->h, nSize) ){
pFile->lastErrno = errno;
return SQLITE_IOERR_TRUNCATE;
}
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
do {
wrote = seekAndWrite(pFile, iWrite, "", 1);
iWrite += nBlk;
} while( wrote==1 && iWrite<nSize );
if( wrote!=1 ) amt = 1;
#endif
}
}
if( amt>0 ){
if( wrote<0 ){
/* lastErrno set by seekAndWrite */
@ -3083,6 +3047,54 @@ static int unixFileSize(sqlite3_file *id, i64 *pSize){
static int proxyFileControl(sqlite3_file*,int,void*);
#endif
/*
** This function is called to handle the SQLITE_FCNTL_SIZE_HINT
** file-control operation.
**
** If the user has configured a chunk-size for this file, it could be
** that the file needs to be extended at this point. Otherwise, the
** SQLITE_FCNTL_SIZE_HINT operation is a no-op for Unix.
*/
static int fcntlSizeHint(unixFile *pFile, i64 nByte){
if( pFile->szChunk ){
i64 nSize; /* Required file size */
struct stat buf; /* Used to hold return values of fstat() */
if( fstat(pFile->h, &buf) ) return SQLITE_IOERR_FSTAT;
nSize = ((nByte+pFile->szChunk-1) / pFile->szChunk) * pFile->szChunk;
if( nSize>(i64)buf.st_size ){
#if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE
if( posix_fallocate(pFile->h, buf.st_size, nSize-buf.st_size) ){
return SQLITE_IOERR_WRITE;
}
#else
/* If the OS does not have posix_fallocate(), fake it. First use
** ftruncate() to set the file size, then write a single byte to
** the last byte in each block within the extended region. This
** is the same technique used by glibc to implement posix_fallocate()
** on systems that do not have a real fallocate() system call.
*/
int nBlk = buf.st_blksize; /* File-system block size */
i64 iWrite; /* Next offset to write to */
int nWrite; /* Return value from seekAndWrite() */
if( ftruncate(pFile->h, nSize) ){
pFile->lastErrno = errno;
return SQLITE_IOERR_TRUNCATE;
}
iWrite = ((buf.st_size + 2*nBlk - 1)/nBlk)*nBlk-1;
do {
nWrite = seekAndWrite(pFile, iWrite, "", 1);
iWrite += nBlk;
} while( nWrite==1 && iWrite<nSize );
if( nWrite!=1 ) return SQLITE_IOERR_WRITE;
#endif
}
}
return SQLITE_OK;
}
/*
** Information and control of an open file handle.
@ -3099,15 +3111,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
case SQLITE_FCNTL_CHUNK_SIZE: {
((unixFile*)id)->szChunk = *(int *)pArg;
return SQLITE_OK;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
#if 0 /* No performance advantage seen on Linux */
sqlite3_int64 szFile = *(sqlite3_int64*)pArg;
unixFile *pFile = (unixFile*)id;
ftruncate(pFile->h, szFile);
#endif
return SQLITE_OK;
return fcntlSizeHint((unixFile *)id, *(i64 *)pArg);
}
#ifndef NDEBUG
/* The pager calls this method to signal that it has done

View File

@ -108,6 +108,7 @@ struct winFile {
DWORD sectorSize; /* Sector size of the device file is on */
winShm *pShm; /* Instance of shared memory on this file */
const char *zPath; /* Full pathname of this file */
int szChunk; /* Chunk size configured by FCNTL_CHUNK_SIZE */
#if SQLITE_OS_WINCE
WCHAR *zDeleteOnClose; /* Name of file to delete when closing */
HANDLE hMutex; /* Mutex used to control access to shared lock */
@ -620,6 +621,42 @@ static BOOL winceLockFileEx(
** by the sqlite3_io_methods object.
******************************************************************************/
/*
** Some microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
** Move the current position of the file handle passed as the first
** argument to offset iOffset within the file. If successful, return 0.
** Otherwise, set pFile->lastErrno and return non-zero.
*/
static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
LONG upperBits; /* Most sig. 32 bits of new offset */
LONG lowerBits; /* Least sig. 32 bits of new offset */
DWORD dwRet; /* Value returned by SetFilePointer() */
upperBits = (LONG)((iOffset>>32) & 0x7fffffff);
lowerBits = (LONG)(iOffset & 0xffffffff);
/* API oddity: If successful, SetFilePointer() returns a dword
** containing the lower 32-bits of the new file-offset. Or, if it fails,
** it returns INVALID_SET_FILE_POINTER. However according to MSDN,
** INVALID_SET_FILE_POINTER may also be a valid new offset. So to determine
** whether an error has actually occured, it is also necessary to call
** GetLastError().
*/
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){
pFile->lastErrno = GetLastError();
return 1;
}
return 0;
}
/*
** Close a file.
**
@ -662,13 +699,6 @@ static int winClose(sqlite3_file *id){
return rc ? SQLITE_OK : SQLITE_IOERR;
}
/*
** Some microsoft compilers lack this definition.
*/
#ifndef INVALID_SET_FILE_POINTER
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
#endif
/*
** Read data from a file into a buffer. Return SQLITE_OK if all
** bytes were read successfully and SQLITE_IOERR if anything goes
@ -680,32 +710,27 @@ static int winRead(
int amt, /* Number of bytes to read */
sqlite3_int64 offset /* Begin reading at this offset */
){
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD got;
winFile *pFile = (winFile*)id; /* file handle */
DWORD nRead; /* Number of bytes actually read from file */
assert( id!=0 );
SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
if( seekWinFile(pFile, offset) ){
return SQLITE_FULL;
}
if( !ReadFile(pFile->h, pBuf, amt, &got, 0) ){
if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){
pFile->lastErrno = GetLastError();
return SQLITE_IOERR_READ;
}
if( got==(DWORD)amt ){
return SQLITE_OK;
}else{
if( nRead<(DWORD)amt ){
/* Unread parts of the buffer must be zero-filled */
memset(&((char*)pBuf)[got], 0, amt-got);
memset(&((char*)pBuf)[nRead], 0, amt-nRead);
return SQLITE_IOERR_SHORT_READ;
}
return SQLITE_OK;
}
/*
@ -713,47 +738,42 @@ static int winRead(
** or some other error code on failure.
*/
static int winWrite(
sqlite3_file *id, /* File to write into */
const void *pBuf, /* The bytes to be written */
int amt, /* Number of bytes to write */
sqlite3_int64 offset /* Offset into the file to begin writing at */
sqlite3_file *id, /* File to write into */
const void *pBuf, /* The bytes to be written */
int amt, /* Number of bytes to write */
sqlite3_int64 offset /* Offset into the file to begin writing at */
){
LONG upperBits = (LONG)((offset>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(offset & 0xffffffff);
DWORD rc;
winFile *pFile = (winFile*)id;
DWORD error;
DWORD wrote = 0;
int rc; /* True if error has occured, else false */
winFile *pFile = (winFile*)id; /* File handle */
assert( id!=0 );
assert( amt>0 );
assert( pFile );
SimulateIOError(return SQLITE_IOERR_WRITE);
SimulateDiskfullError(return SQLITE_FULL);
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
rc = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( rc==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
return SQLITE_FULL;
}else{
return SQLITE_IOERR_WRITE;
rc = seekWinFile(pFile, offset);
if( rc==0 ){
u8 *aRem = (u8 *)pBuf; /* Data yet to be written */
int nRem = amt; /* Number of bytes yet to be written */
DWORD nWrite; /* Bytes written by each WriteFile() call */
while( nRem>0 && WriteFile(pFile->h, aRem, nRem, &nWrite, 0) && nWrite>0 ){
aRem += nWrite;
nRem -= nWrite;
}
if( nRem>0 ){
pFile->lastErrno = GetLastError();
rc = 1;
}
}
assert( amt>0 );
while(
amt>0
&& (rc = WriteFile(pFile->h, pBuf, amt, &wrote, 0))!=0
&& wrote>0
){
amt -= wrote;
pBuf = &((char*)pBuf)[wrote];
}
if( !rc || amt>(int)wrote ){
pFile->lastErrno = GetLastError();
if( rc ){
if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){
return SQLITE_FULL;
}else{
return SQLITE_IOERR_WRITE;
}
return SQLITE_IOERR_WRITE;
}
return SQLITE_OK;
}
@ -762,26 +782,32 @@ static int winWrite(
** Truncate an open file to a specified size
*/
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
LONG upperBits = (LONG)((nByte>>32) & 0x7fffffff);
LONG lowerBits = (LONG)(nByte & 0xffffffff);
DWORD dwRet;
winFile *pFile = (winFile*)id;
DWORD error;
int rc = SQLITE_OK;
winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */
assert( pFile );
assert( id!=0 );
OSTRACE(("TRUNCATE %d %lld\n", pFile->h, nByte));
SimulateIOError(return SQLITE_IOERR_TRUNCATE);
dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN);
if( dwRet==INVALID_SET_FILE_POINTER && (error=GetLastError())!=NO_ERROR ){
pFile->lastErrno = error;
/* If the user has configured a chunk-size for this file, truncate the
** file so that it consists of an integer number of chunks (i.e. the
** actual file size after the operation may be larger than the requested
** size).
*/
if( pFile->szChunk ){
nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk;
}
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){
rc = SQLITE_IOERR_TRUNCATE;
/* SetEndOfFile will fail if nByte is negative */
}else if( !SetEndOfFile(pFile->h) ){
}else if( 0==SetEndOfFile(pFile->h) ){
pFile->lastErrno = GetLastError();
rc = SQLITE_IOERR_TRUNCATE;
}
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc==SQLITE_OK ? "ok" : "failed"));
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
return rc;
}
@ -1146,6 +1172,10 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
*(int*)pArg = (int)((winFile*)id)->lastErrno;
return SQLITE_OK;
}
case SQLITE_FCNTL_CHUNK_SIZE: {
((winFile*)id)->szChunk = *(int *)pArg;
return SQLITE_OK;
}
case SQLITE_FCNTL_SIZE_HINT: {
sqlite3_int64 sz = *(sqlite3_int64*)pArg;
SimulateIOErrorBenign(1);

View File

@ -3365,7 +3365,7 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
** file size will be.
*/
assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
if( rc==SQLITE_OK && pPager->dbSize>(pPager->dbOrigSize+1) ){
if( rc==SQLITE_OK && pPager->dbSize>pPager->dbOrigSize ){
sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
}

View File

@ -690,6 +690,14 @@ struct sqlite3_io_methods {
** is often close. The underlying VFS might choose to preallocate database
** file space based on this hint in order to help writes to the database
** file run faster.
**
** The [SQLITE_FCNTL_CHUNK_SIZE] opcode is used to request that the VFS
** extends and truncates the database file in chunks of a size specified
** by the user. The fourth argument to [sqlite3_file_control()] should
** point to an integer (type int) containing the new chunk-size to use
** for the nominated database. Allocating database file space in large
** chunks (say 1MB at a time), may reduce file-system fragmentation and
** improve performance on some systems.
*/
#define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2

View File

@ -1521,6 +1521,7 @@ static int walCheckpoint(
u32 iDbpage = 0; /* Next database page to write */
u32 iFrame = 0; /* Wal frame containing data for iDbpage */
u32 mxSafeFrame; /* Max frame that can be backfilled */
u32 mxPage; /* Max database page to write */
int i; /* Loop counter */
volatile WalCkptInfo *pInfo; /* The checkpoint status information */
@ -1545,6 +1546,7 @@ static int walCheckpoint(
** cannot be backfilled from the WAL.
*/
mxSafeFrame = pWal->hdr.mxFrame;
mxPage = pWal->hdr.nPage;
pInfo = walCkptInfo(pWal);
for(i=1; i<WAL_NREADER; i++){
u32 y = pInfo->aReadMark[i];
@ -1565,6 +1567,8 @@ static int walCheckpoint(
if( pInfo->nBackfill<mxSafeFrame
&& (rc = walLockExclusive(pWal, WAL_READ_LOCK(0), 1))==SQLITE_OK
){
i64 nReq; /* File size hint passed to VFS */
i64 nSize; /* Current size of database file */
u32 nBackfill = pInfo->nBackfill;
/* Sync the WAL to disk */
@ -1572,11 +1576,20 @@ static int walCheckpoint(
rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
}
/* If the database file may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer.
*/
nReq = ((i64)mxPage * szPage);
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSize<nReq ){
rc = sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
}
/* Iterate through the contents of the WAL, copying data to the db file. */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset;
assert( walFramePgno(pWal, iFrame)==iDbpage );
if( iFrame<=nBackfill || iFrame>mxSafeFrame ) continue;
if( iFrame<=nBackfill || iFrame>mxSafeFrame || iDbpage>mxPage ) continue;
iOffset = walFrameOffset(iFrame, szPage) + WAL_FRAME_HDRSIZE;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL file */
rc = sqlite3OsRead(pWal->pWalFd, zBuf, szPage, iOffset);

View File

@ -13,11 +13,6 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
if {$::tcl_platform(platform)!="unix"} {
finish_test
return
}
file_control_chunksize_test db main [expr 1024*1024]
do_test fallocate-1.1 {
@ -53,4 +48,88 @@ do_test fallocate-1.6 {
execsql { PRAGMA freelist_count }
} {0}
# Start a write-transaction and read the "database file size" field from
# the journal file. This field should be set to the number of pages in
# the database file based on the size of the file on disk, not the actual
# logical size of the database within the file.
#
# We need to check this to verify that if in the unlikely event a rollback
# causes a database file to grow, the database grows to its previous size
# on disk, not to the minimum size required to hold the database image.
#
do_test fallocate-1.7 {
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
hexio_get_int [hexio_read test.db-journal 16 4]
} {1024}
do_test fallocate-1.8 { execsql { COMMIT } } {}
#-------------------------------------------------------------------------
# The following tests - fallocate-2.* - test that things work in WAL
# mode as well.
#
db close
file delete -force test.db
sqlite3 db test.db
file_control_chunksize_test db main [expr 32*1024]
do_test fallocate-2.1 {
execsql {
PRAGMA page_size = 1024;
PRAGMA journal_mode = WAL;
CREATE TABLE t1(a, b);
}
file size test.db
} [expr 32*1024]
do_test fallocate-2.2 {
execsql { INSERT INTO t1 VALUES(1, zeroblob(35*1024)) }
execsql { PRAGMA wal_checkpoint }
file size test.db
} [expr 64*1024]
do_test fallocate-2.3 {
execsql { DELETE FROM t1 }
execsql { VACUUM }
file size test.db
} [expr 64*1024]
do_test fallocate-2.4 {
execsql { PRAGMA wal_checkpoint }
file size test.db
} [expr 32*1024]
do_test fallocate-2.5 {
execsql {
INSERT INTO t1 VALUES(2, randomblob(35*1024));
PRAGMA wal_checkpoint;
INSERT INTO t1 VALUES(3, randomblob(128));
DELETE FROM t1 WHERE a = 2;
VACUUM;
}
file size test.db
} [expr 64*1024]
do_test fallocate-2.6 {
sqlite3 db2 test.db
execsql { BEGIN ; SELECT count(a) FROM t1 } db2
execsql {
INSERT INTO t1 VALUES(4, randomblob(128));
PRAGMA wal_checkpoint;
}
file size test.db
} [expr 64*1024]
do_test fallocate-2.7 {
execsql { SELECT count(b) FROM t1 } db2
} {1}
do_test fallocate-2.8 {
execsql { COMMIT } db2
execsql { PRAGMA wal_checkpoint }
file size test.db
} [expr 32*1024]
finish_test