aboutsummaryrefslogtreecommitdiff
path: root/src/os_unix.c
diff options
context:
space:
mode:
authordan <dan@noemail.net>2010-07-27 18:34:15 +0000
committerdan <dan@noemail.net>2010-07-27 18:34:15 +0000
commit6e09d69c92ca81c7a8ffda7a26bf74e807ad3371 (patch)
tree278b291c190ae0b5bb37dde4d9ed910955a6b4c1 /src/os_unix.c
parentd2de9f4e6802d0f3c847a6f1dd5aa49a0eef70fb (diff)
downloadsqlite-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.c64
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;