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:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
39
src/test1.c
39
src/test1.c
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user