mirror of https://github.com/sqlite/sqlite
Support FCNTL_CHUNK_SIZE on windows too.
FossilOrigin-Name: a038688c991435967b935946c2283707820bb5da
This commit is contained in:
parent
eb8def8449
commit
502019c8bb
22
manifest
22
manifest
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
621824092d443425c420ba9010bbe1202fe99ea2
|
||||
a038688c991435967b935946c2283707820bb5da
|
|
@ -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
|
||||
|
|
160
src/os_win.c
160
src/os_win.c
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
15
src/wal.c
15
src/wal.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue