diff options
author | drh <drh@noemail.net> | 2011-12-21 14:42:29 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2011-12-21 14:42:29 +0000 |
commit | f12b3f609f08e923833bc6c37863f11a82582c03 (patch) | |
tree | eac19e5f30021873963f5f39db83917425ab8931 /src | |
parent | f694aa6454630efdb04a7cb9f0d91c0fe5376770 (diff) | |
download | sqlite-f12b3f609f08e923833bc6c37863f11a82582c03.tar.gz sqlite-f12b3f609f08e923833bc6c37863f11a82582c03.zip |
Add the ability to enable or disable SQLITE_IOCAP_ZERO_DAMAGE using a URI
parameter for both unix and windows. Add a file-control to query or disable
the ZERO_DAMAGE setting. Add the -uri option to the "sqlite3" TCL command
in tclsqlite3.c. Allow the sqlite3_uri_parameter() interface to accept a
NULL pointer for its first parameter.
FossilOrigin-Name: c83627b73285f883719845c1b9fe85f378f28dd2
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/os_unix.c | 66 | ||||
-rw-r--r-- | src/os_win.c | 43 | ||||
-rw-r--r-- | src/sqlite.h.in | 10 | ||||
-rw-r--r-- | src/tclsqlite.c | 8 | ||||
-rw-r--r-- | src/test1.c | 33 |
6 files changed, 132 insertions, 29 deletions
diff --git a/src/main.c b/src/main.c index 690b73c2e..ea64d8be9 100644 --- a/src/main.c +++ b/src/main.c @@ -2977,6 +2977,7 @@ int sqlite3_test_control(int op, ...){ ** returns a NULL pointer. */ const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ + if( zFilename==0 ) return 0; zFilename += sqlite3Strlen30(zFilename) + 1; while( zFilename[0] ){ int x = strcmp(zFilename, zParam); diff --git a/src/os_unix.c b/src/os_unix.c index a9d7de832..4a31c8cde 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -215,13 +215,13 @@ struct unixFile { int h; /* The file descriptor */ unsigned char eFileLock; /* The type of lock held on this fd */ unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ + unsigned char szSector; /* Sectorsize/512 */ int lastErrno; /* The unix errno from last I/O error */ void *lockingContext; /* Locking style specific state */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ const char *zPath; /* Name of the file */ unixShm *pShm; /* Shared memory segment information */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ - int szSector; /* Sector size */ #if SQLITE_ENABLE_LOCKING_STYLE int openFlags; /* The flags specified at open() */ #endif @@ -263,6 +263,7 @@ struct unixFile { #else # define UNIXFILE_DIRSYNC 0x00 #endif +#define UNIXFILE_ZERO_DAMAGE 0x10 /* True if SQLITE_IOCAP_ZERO_DAMAGE */ /* ** Include code that is common to all os_*.c files @@ -3512,6 +3513,22 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){ } /* +** If *pArg is inititially negative then this is a query. Set *pArg to +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. +** +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. +*/ +static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){ + if( *pArg<0 ){ + *pArg = (pFile->ctrlFlags & mask)!=0; + }else if( (*pArg)==0 ){ + pFile->ctrlFlags &= ~mask; + }else{ + pFile->ctrlFlags |= mask; + } +} + +/* ** Information and control of an open file handle. */ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ @@ -3537,14 +3554,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){ return rc; } case SQLITE_FCNTL_PERSIST_WAL: { - int bPersist = *(int*)pArg; - if( bPersist<0 ){ - *(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0; - }else if( bPersist==0 ){ - pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL; - }else{ - pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL; - } + unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg); + return SQLITE_OK; + } + case SQLITE_FCNTL_ZERO_DAMAGE: { + unixModeBit(pFile, UNIXFILE_ZERO_DAMAGE, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { @@ -3589,27 +3603,37 @@ static int unixSectorSize(sqlite3_file *pFile){ unixFile *p = (unixFile*)pFile; if( p->szSector==0 ){ #ifdef MISSING_STATVFS - p->szSector = SQLITE_DEFAULT_SECTOR_SIZE; + p->szSector = SQLITE_DEFAULT_SECTOR_SIZE/512; #else struct statvfs x; int sz; memset(&x, 0, sizeof(x)); osStatvfs(p->zPath, &x); - p->szSector = sz = (int)x.f_frsize; + sz = (int)x.f_frsize; if( sz<512 || sz>65536 || (sz&(sz-1))!=0 ){ - p->szSector = SQLITE_DEFAULT_SECTOR_SIZE; + sz = SQLITE_DEFAULT_SECTOR_SIZE; } + p->szSector = sz/512; #endif } - return p->szSector; + return p->szSector*512; } /* -** Return the device characteristics for the file. This is always 0 for unix. +** Return the device characteristics for the file. +** +** This VFS is set up to return SQLITE_IOCAP_ZERO_DAMAGE by default. +** However, that choice is contraversial sicne technically the underlying +** file system does not always provide ZERO_DAMAGE. (In other words, after +** a power-loss event, parts of the file that were never written might end +** up being altered.) However, non-ZERO-DAMAGE behavior is very, very rare. +** And asserting ZERO_DAMAGE makes a large reduction in the amount of required +** I/O. Hence, while ZERO_DAMAGE is on by default, there is a file-control +** available to turn it off. */ -static int unixDeviceCharacteristics(sqlite3_file *NotUsed){ - UNUSED_PARAMETER(NotUsed); - return SQLITE_IOCAP_ZERO_DAMAGE; +static int unixDeviceCharacteristics(sqlite3_file *id){ + unixFile *p = (unixFile*)id; + return (p->ctrlFlags & UNIXFILE_ZERO_DAMAGE) ? SQLITE_IOCAP_ZERO_DAMAGE : 0; } #ifndef SQLITE_OMIT_WAL @@ -4568,6 +4592,7 @@ static int fillInUnixFile( const sqlite3_io_methods *pLockingStyle; unixFile *pNew = (unixFile *)pId; int rc = SQLITE_OK; + const char *zZeroDam; /* Value of the zero_damage query parameter */ assert( pNew->pInode==NULL ); @@ -4594,10 +4619,11 @@ static int fillInUnixFile( pNew->h = h; pNew->pVfs = pVfs; pNew->zPath = zFilename; + zZeroDam = sqlite3_uri_parameter(zFilename, "zero_damage"); + if( zZeroDam==0 ) zZeroDam = "1"; + pNew->ctrlFlags = atoi(zZeroDam) ? UNIXFILE_ZERO_DAMAGE : 1; if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ - pNew->ctrlFlags = UNIXFILE_EXCL; - }else{ - pNew->ctrlFlags = 0; + pNew->ctrlFlags |= UNIXFILE_EXCL; } if( isReadOnly ){ pNew->ctrlFlags |= UNIXFILE_RDONLY; diff --git a/src/os_win.c b/src/os_win.c index 5e0667d18..ec4d062f9 100644 --- a/src/os_win.c +++ b/src/os_win.c @@ -59,7 +59,7 @@ struct winFile { HANDLE h; /* Handle for accessing the file */ u8 locktype; /* Type of lock currently held on this file */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */ - u8 bPersistWal; /* True to persist WAL files */ + u8 ctrlFlags; /* Flags. See WINFILE_* below */ DWORD lastErrno; /* The Windows errno from the last I/O error */ DWORD sectorSize; /* Sector size of the device file is on */ winShm *pShm; /* Instance of shared memory on this file */ @@ -75,6 +75,12 @@ struct winFile { }; /* +** Allowed values for winFile.ctrlFlags +*/ +#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ +#define WINFILE_ZERO_DAMAGE 0x10 /* True if SQLITE_IOCAP_ZERO_DAMAGE */ + +/* * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * various Win32 API heap functions instead of our own. */ @@ -2126,6 +2132,22 @@ static int winUnlock(sqlite3_file *id, int locktype){ } /* +** If *pArg is inititially negative then this is a query. Set *pArg to +** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set. +** +** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags. +*/ +static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){ + if( *pArg<0 ){ + *pArg = (pFile->ctrlFlags & mask)!=0; + }else if( (*pArg)==0 ){ + pFile->ctrlFlags &= ~mask; + }else{ + pFile->ctrlFlags |= mask; + } +} + +/* ** Control and query of the open file handle. */ static int winFileControl(sqlite3_file *id, int op, void *pArg){ @@ -2160,12 +2182,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){ return SQLITE_OK; } case SQLITE_FCNTL_PERSIST_WAL: { - int bPersist = *(int*)pArg; - if( bPersist<0 ){ - *(int*)pArg = pFile->bPersistWal; - }else{ - pFile->bPersistWal = bPersist!=0; - } + winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg); + return SQLITE_OK; + } + case SQLITE_FCNTL_ZERO_DAMAGE: { + winModeBit(pFile, WINFILE_ZERO_DAMAGE, (int*)pArg); return SQLITE_OK; } case SQLITE_FCNTL_VFSNAME: { @@ -2212,9 +2233,9 @@ static int winSectorSize(sqlite3_file *id){ ** Return a vector of device characteristics. */ static int winDeviceCharacteristics(sqlite3_file *id){ - UNUSED_PARAMETER(id); + winFile *p = (winFile*)id; return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN | - SQLITE_IOCAP_ZERO_DAMAGE; + ((p->ctrlFlags & WINFILE_ZERO_DAMAGE)?SQLITE_IOCAP_ZERO_DAMAGE:0); } #ifndef SQLITE_OMIT_WAL @@ -3004,6 +3025,7 @@ static int winOpen( void *zConverted; /* Filename in OS encoding */ const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ int cnt = 0; + const char *zZeroDam; /* Value of zero_damage query parameter */ /* If argument zPath is a NULL pointer, this function is required to open ** a temporary file. Use this buffer to store the file name in. @@ -3179,6 +3201,9 @@ static int winOpen( pFile->pVfs = pVfs; pFile->pShm = 0; pFile->zPath = zName; + zZeroDam = sqlite3_uri_parameter(zName, "zero_damage"); + if( zZeroDam==0 ) zZeroDam = "1"; + pFile->ctrlFlags = atoi(zZeroDam) ? WINFILE_ZERO_DAMAGE : 1; pFile->sectorSize = getSectorSize(pVfs, zUtf8Name); #if SQLITE_OS_WINCE diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f7a2616ba..e036449d0 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -774,6 +774,15 @@ struct sqlite3_io_methods { ** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL persistence setting. ** +** ^The [SQLITE_FCNTL_ZERO_DAMAGE] opcode is used to set or query the +** persistent zero-damage setting. The zero-damage setting determines +** the [SQLITE_IOCAP_ZERO_DAMAGE] bit of the xDeviceCharacteristics methods. +** The fourth parameter to +** [sqlite3_file_control()] for this opcode should be a pointer to an integer. +** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage +** mode. If the integer is -1, then it is overwritten with the current +** zero-damage mode setting. +** ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** a write transaction to indicate that, unless it is rolled back for some ** reason, the entire database file will be overwritten by the current @@ -802,6 +811,7 @@ struct sqlite3_io_methods { #define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_VFSNAME 12 +#define SQLITE_FCNTL_ZERO_DAMAGE 13 /* ** CAPI3REF: Mutex Handle diff --git a/src/tclsqlite.c b/src/tclsqlite.c index c8f0fbd31..3692bef9c 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3001,6 +3001,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ }else{ flags &= ~SQLITE_OPEN_FULLMUTEX; } + }else if( strcmp(zArg, "-uri")==0 ){ + int b; + if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR; + if( b ){ + flags |= SQLITE_OPEN_URI; + }else{ + flags &= ~SQLITE_OPEN_URI; + } }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; diff --git a/src/test1.c b/src/test1.c index 798366a8c..b96b99ce8 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5235,6 +5235,38 @@ static int file_control_persist_wal( return TCL_OK; } +/* +** tclcmd: file_control_zero_damage DB ZERO-DAMAGE-FLAG +** +** This TCL command runs the sqlite3_file_control interface with +** the SQLITE_FCNTL_ZERO_DAMAGE opcode. +*/ +static int file_control_zero_damage( + 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 */ +){ + sqlite3 *db; + int rc; + int bDamage; + char z[100]; + + if( objc!=3 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){ + return TCL_ERROR; + } + if( Tcl_GetIntFromObj(interp, objv[2], &bDamage) ) return TCL_ERROR; + rc = sqlite3_file_control(db, NULL, SQLITE_FCNTL_ZERO_DAMAGE,(void*)&bDamage); + sqlite3_snprintf(sizeof(z), z, "%d %d", rc, bDamage); + Tcl_AppendResult(interp, z, (char*)0); + return TCL_OK; +} + /* ** tclcmd: file_control_vfsname DB ?AUXDB? @@ -6093,6 +6125,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_persist_wal", file_control_persist_wal, 0 }, + { "file_control_zero_damage", file_control_zero_damage, 0 }, { "file_control_vfsname", file_control_vfsname, 0 }, { "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 }, |