diff options
author | dan <dan@noemail.net> | 2010-07-27 18:34:15 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2010-07-27 18:34:15 +0000 |
commit | 6e09d69c92ca81c7a8ffda7a26bf74e807ad3371 (patch) | |
tree | 278b291c190ae0b5bb37dde4d9ed910955a6b4c1 /src/os_unix.c | |
parent | d2de9f4e6802d0f3c847a6f1dd5aa49a0eef70fb (diff) | |
download | sqlite-6e09d69c92ca81c7a8ffda7a26bf74e807ad3371.tar.gz sqlite-6e09d69c92ca81c7a8ffda7a26bf74e807ad3371.zip |
Add experimental unix-only file-control to grow and truncate the database file by a configurable chunk size.
FossilOrigin-Name: 7cf0e851d4c5e826ea22ed08291b7c91d7b1abc7
Diffstat (limited to 'src/os_unix.c')
-rw-r--r-- | src/os_unix.c | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/src/os_unix.c b/src/os_unix.c index 9457516ca..467409b19 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -210,6 +210,7 @@ struct unixFile { int fileFlags; /* Miscellanous flags */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ + int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif @@ -2763,6 +2764,43 @@ 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 */ @@ -2772,6 +2810,7 @@ static int unixWrite( return SQLITE_FULL; } } + return SQLITE_OK; } @@ -2973,12 +3012,23 @@ static int unixSync(sqlite3_file *id, int flags){ ** Truncate an open file to a specified size */ static int unixTruncate(sqlite3_file *id, i64 nByte){ + unixFile *pFile = (unixFile *)id; int rc; - assert( id ); + assert( pFile ); SimulateIOError( return SQLITE_IOERR_TRUNCATE ); - rc = ftruncate(((unixFile*)id)->h, (off_t)nByte); + + /* 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; + } + + rc = ftruncate(pFile->h, (off_t)nByte); if( rc ){ - ((unixFile*)id)->lastErrno = errno; + pFile->lastErrno = errno; return SQLITE_IOERR_TRUNCATE; }else{ #ifndef NDEBUG @@ -2989,8 +3039,8 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){ ** when restoring a database using the backup API from a zero-length ** source. */ - if( ((unixFile*)id)->inNormalWrite && nByte==0 ){ - ((unixFile*)id)->transCntrChng = 1; + if( pFile->inNormalWrite && nByte==0 ){ + pFile->transCntrChng = 1; } #endif @@ -3047,6 +3097,10 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ *(int*)pArg = ((unixFile*)id)->lastErrno; return SQLITE_OK; } + case SQLITE_FCNTL_CHUNK_SIZE: { + ((unixFile*)id)->szChunk = *(int *)pArg; + return SQLITE_OK; + } case SQLITE_FCNTL_SIZE_HINT: { #if 0 /* No performance advantage seen on Linux */ sqlite3_int64 szFile = *(sqlite3_int64*)pArg; |