1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-12-03 08:01:19 +03:00

Add experimental unix-only file-control to grow and truncate the database file by a configurable chunk size.

FossilOrigin-Name: 7cf0e851d4c5e826ea22ed08291b7c91d7b1abc7
This commit is contained in:
dan
2010-07-27 18:34:15 +00:00
parent d2de9f4e68
commit 6e09d69c92
6 changed files with 169 additions and 25 deletions

View File

@@ -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;

View File

@@ -696,6 +696,7 @@ struct sqlite3_io_methods {
#define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6
/*
** CAPI3REF: Mutex Handle

View File

@@ -4613,6 +4613,44 @@ static int file_control_lasterrno_test(
return TCL_OK;
}
/*
** tclcmd: file_control_chunksize_test DB DBNAME SIZE
**
** This TCL command runs the sqlite3_file_control interface and
** verifies correct operation of the SQLITE_GET_LOCKPROXYFILE and
** SQLITE_SET_LOCKPROXYFILE verbs.
*/
static int file_control_chunksize_test(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
int nSize; /* New chunk size */
char *zDb; /* Db name ("main", "temp" etc.) */
sqlite3 *db; /* Database handle */
int rc; /* file_control() return code */
if( objc!=4 ){
Tcl_WrongNumArgs(interp, 1, objv, "DB DBNAME SIZE");
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db)
|| Tcl_GetIntFromObj(interp, objv[3], &nSize)
){
return TCL_ERROR;
}
zDb = Tcl_GetString(objv[2]);
if( zDb[0]=='\0' ) zDb = NULL;
rc = sqlite3_file_control(db, zDb, SQLITE_FCNTL_CHUNK_SIZE, (void *)&nSize);
if( rc ){
Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
/*
** tclcmd: file_control_lockproxy_test DB PWD
**
@@ -5106,6 +5144,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_test", file_control_test, 0 },
{ "file_control_lasterrno_test", file_control_lasterrno_test, 0 },
{ "file_control_lockproxy_test", file_control_lockproxy_test, 0 },
{ "file_control_chunksize_test", file_control_chunksize_test, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 },
/* Functions from os.h */