diff options
author | drh <drh@noemail.net> | 2010-06-21 12:47:41 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2010-06-21 12:47:41 +0000 |
commit | 24f0f7716a8963454d77e0224c98dc76f1eebfd2 (patch) | |
tree | f76f3b8d9477bb70be62d337bd579479b4d23078 /src/test_vfs.c | |
parent | 19515c8da1df2330c7689315dcd70fc02a4b4e28 (diff) | |
parent | e08341c664e41bb084a7a95bfb47b90b13868694 (diff) | |
download | sqlite-24f0f7716a8963454d77e0224c98dc76f1eebfd2.tar.gz sqlite-24f0f7716a8963454d77e0224c98dc76f1eebfd2.zip |
Merge the experimental UNDELETABLE_WHEN_OPEN optimization into the trunk.
FossilOrigin-Name: ee0acef1faffd480fd2136f81fb2b6f6a17b5388
Diffstat (limited to 'src/test_vfs.c')
-rw-r--r-- | src/test_vfs.c | 263 |
1 files changed, 230 insertions, 33 deletions
diff --git a/src/test_vfs.c b/src/test_vfs.c index e94bef7d2..46f3a0630 100644 --- a/src/test_vfs.c +++ b/src/test_vfs.c @@ -58,6 +58,13 @@ struct Testvfs { int iIoerrCnt; int ioerr; int nIoerrFail; + + int iFullCnt; + int fullerr; + int nFullFail; + + int iDevchar; + int iSectorsize; }; /* @@ -77,7 +84,10 @@ struct Testvfs { #define TESTVFS_OPEN_MASK 0x00000100 #define TESTVFS_SYNC_MASK 0x00000200 #define TESTVFS_DELETE_MASK 0x00000400 -#define TESTVFS_ALL_MASK 0x000007FF +#define TESTVFS_CLOSE_MASK 0x00000800 +#define TESTVFS_WRITE_MASK 0x00001000 +#define TESTVFS_TRUNCATE_MASK 0x00002000 +#define TESTVFS_ALL_MASK 0x00003FFF #define TESTVFS_MAX_PAGES 256 @@ -187,6 +197,30 @@ static int tvfsResultCode(Testvfs *p, int *pRc){ return 0; } +static int tvfsInjectIoerr(Testvfs *p){ + int ret = 0; + if( p->ioerr ){ + p->iIoerrCnt--; + if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){ + ret = 1; + p->nIoerrFail++; + } + } + return ret; +} + +static int tvfsInjectFullerr(Testvfs *p){ + int ret = 0; + if( p->fullerr ){ + p->iFullCnt--; + if( p->iFullCnt<=0 ){ + ret = 1; + p->nFullFail++; + } + } + return ret; +} + static void tvfsExecTcl( Testvfs *p, @@ -245,15 +279,23 @@ static void tvfsExecTcl( ** Close an tvfs-file. */ static int tvfsClose(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - if( p->pShmId ){ - Tcl_DecrRefCount(p->pShmId); - p->pShmId = 0; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_CLOSE_MASK ){ + tvfsExecTcl(p, "xClose", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + } + + if( pFd->pShmId ){ + Tcl_DecrRefCount(pFd->pShmId); + pFd->pShmId = 0; } if( pFile->pMethods ){ ckfree((char *)pFile->pMethods); } - return sqlite3OsClose(p->pReal); + return sqlite3OsClose(pFd->pReal); } /* @@ -278,16 +320,44 @@ static int tvfsWrite( int iAmt, sqlite_int64 iOfst ){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst); + int rc = SQLITE_OK; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_WRITE_MASK ){ + tvfsExecTcl(p, "xWrite", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + tvfsResultCode(p, &rc); + } + + if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; + + if( rc==SQLITE_OK ){ + rc = sqlite3OsWrite(pFd->pReal, zBuf, iAmt, iOfst); + } + return rc; } /* ** Truncate an tvfs-file. */ static int tvfsTruncate(sqlite3_file *pFile, sqlite_int64 size){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsTruncate(p->pReal, size); + int rc = SQLITE_OK; + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + + if( p->pScript && p->mask&TESTVFS_TRUNCATE_MASK ){ + tvfsExecTcl(p, "xTruncate", + Tcl_NewStringObj(pFd->zFilename, -1), pFd->pShmId, 0 + ); + tvfsResultCode(p, &rc); + } + + if( rc==SQLITE_OK ){ + rc = sqlite3OsTruncate(pFd->pReal, size); + } + return rc; } /* @@ -325,6 +395,8 @@ static int tvfsSync(sqlite3_file *pFile, int flags){ tvfsResultCode(p, &rc); } + if( rc==SQLITE_OK && tvfsInjectFullerr(p) ) rc = SQLITE_FULL; + if( rc==SQLITE_OK ){ rc = sqlite3OsSync(pFd->pReal, flags); } @@ -376,16 +448,24 @@ static int tvfsFileControl(sqlite3_file *pFile, int op, void *pArg){ ** Return the sector-size in bytes for an tvfs-file. */ static int tvfsSectorSize(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsSectorSize(p->pReal); + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->iSectorsize>=0 ){ + return p->iSectorsize; + } + return sqlite3OsSectorSize(pFd->pReal); } /* ** Return the device characteristic flags supported by an tvfs-file. */ static int tvfsDeviceCharacteristics(sqlite3_file *pFile){ - TestvfsFile *p = (TestvfsFile *)pFile; - return sqlite3OsDeviceCharacteristics(p->pReal); + TestvfsFile *pFd = (TestvfsFile *)pFile; + Testvfs *p = (Testvfs *)pFd->pVfs->pAppData; + if( p->iDevchar>=0 ){ + return p->iDevchar; + } + return sqlite3OsDeviceCharacteristics(pFd->pReal); } /* @@ -555,18 +635,6 @@ static int tvfsCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){ return PARENTVFS(pVfs)->xCurrentTime(PARENTVFS(pVfs), pTimeOut); } -static int tvfsInjectIoerr(Testvfs *p){ - int ret = 0; - if( p->ioerr ){ - p->iIoerrCnt--; - if( p->iIoerrCnt==0 || (p->iIoerrCnt<0 && p->ioerr==2) ){ - ret = 1; - p->nIoerrFail++; - } - } - return ret; -} - static int tvfsShmOpen( sqlite3_file *pFileDes ){ @@ -782,25 +850,38 @@ static int testvfs_obj_cmd( ){ Testvfs *p = (Testvfs *)cd; - static const char *CMD_strs[] = { - "shm", "delete", "filter", "ioerr", "script", 0 - }; enum DB_enum { - CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT + CMD_SHM, CMD_DELETE, CMD_FILTER, CMD_IOERR, CMD_SCRIPT, + CMD_DEVCHAR, CMD_SECTORSIZE, CMD_FULLERR + }; + struct TestvfsSubcmd { + char *zName; + enum DB_enum eCmd; + } aSubcmd[] = { + { "shm", CMD_SHM }, + { "delete", CMD_DELETE }, + { "filter", CMD_FILTER }, + { "ioerr", CMD_IOERR }, + { "fullerr", CMD_FULLERR }, + { "script", CMD_SCRIPT }, + { "devchar", CMD_DEVCHAR }, + { "sectorsize", CMD_SECTORSIZE }, + { 0, 0 } }; - int i; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } - if( Tcl_GetIndexFromObj(interp, objv[1], CMD_strs, "subcommand", 0, &i) ){ + if( Tcl_GetIndexFromObjStruct( + interp, objv[1], aSubcmd, sizeof(aSubcmd[0]), "subcommand", 0, &i) + ){ return TCL_ERROR; } Tcl_ResetResult(interp); - switch( (enum DB_enum)i ){ + switch( aSubcmd[i].eCmd ){ case CMD_SHM: { Tcl_Obj *pObj; int i; @@ -857,7 +938,10 @@ static int testvfs_obj_cmd( { "xShmMap", TESTVFS_SHMMAP_MASK }, { "xSync", TESTVFS_SYNC_MASK }, { "xDelete", TESTVFS_DELETE_MASK }, + { "xWrite", TESTVFS_WRITE_MASK }, + { "xTruncate", TESTVFS_TRUNCATE_MASK }, { "xOpen", TESTVFS_OPEN_MASK }, + { "xClose", TESTVFS_CLOSE_MASK }, }; Tcl_Obj **apElem = 0; int nElem = 0; @@ -916,6 +1000,34 @@ static int testvfs_obj_cmd( } /* + ** TESTVFS fullerr ?IFAIL? + ** + ** Where IFAIL is an integer. + */ + case CMD_FULLERR: { + int iRet = p->nFullFail; + + p->nFullFail = 0; + p->fullerr = 0; + p->iFullCnt = 0; + + if( objc==3 ){ + int iCnt; + if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iCnt) ){ + return TCL_ERROR; + } + p->fullerr = (iCnt>0); + p->iFullCnt = iCnt; + }else if( objc!=2 ){ + Tcl_AppendResult(interp, "Bad args", 0); + return TCL_ERROR; + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(iRet)); + break; + } + + /* ** TESTVFS ioerr ?IFAIL PERSIST? ** ** Where IFAIL is an integer and PERSIST is boolean. @@ -948,6 +1060,89 @@ static int testvfs_obj_cmd( Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); break; } + + case CMD_DEVCHAR: { + struct DeviceFlag { + char *zName; + int iValue; + } aFlag[] = { + { "default", -1 }, + { "atomic", SQLITE_IOCAP_ATOMIC }, + { "atomic512", SQLITE_IOCAP_ATOMIC512 }, + { "atomic1k", SQLITE_IOCAP_ATOMIC1K }, + { "atomic2k", SQLITE_IOCAP_ATOMIC2K }, + { "atomic4k", SQLITE_IOCAP_ATOMIC4K }, + { "atomic8k", SQLITE_IOCAP_ATOMIC8K }, + { "atomic16k", SQLITE_IOCAP_ATOMIC16K }, + { "atomic32k", SQLITE_IOCAP_ATOMIC32K }, + { "atomic64k", SQLITE_IOCAP_ATOMIC64K }, + { "sequential", SQLITE_IOCAP_SEQUENTIAL }, + { "safe_append", SQLITE_IOCAP_SAFE_APPEND }, + { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN }, + { 0, 0 } + }; + Tcl_Obj *pRet; + int iFlag; + + if( objc>3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "?ATTR-LIST?"); + return TCL_ERROR; + } + if( objc==3 ){ + int j; + int iNew = 0; + Tcl_Obj **flags = 0; + int nFlags = 0; + + if( Tcl_ListObjGetElements(interp, objv[2], &nFlags, &flags) ){ + return TCL_ERROR; + } + + for(j=0; j<nFlags; j++){ + int idx = 0; + if( Tcl_GetIndexFromObjStruct(interp, flags[j], aFlag, + sizeof(aFlag[0]), "flag", 0, &idx) + ){ + return TCL_ERROR; + } + if( aFlag[idx].iValue<0 && nFlags>1 ){ + Tcl_AppendResult(interp, "bad flags: ", Tcl_GetString(objv[2]), 0); + return TCL_ERROR; + } + iNew |= aFlag[idx].iValue; + } + + p->iDevchar = iNew; + } + + pRet = Tcl_NewObj(); + for(iFlag=0; iFlag<sizeof(aFlag)/sizeof(aFlag[0]); iFlag++){ + if( p->iDevchar & aFlag[iFlag].iValue ){ + Tcl_ListObjAppendElement( + interp, pRet, Tcl_NewStringObj(aFlag[iFlag].zName, -1) + ); + } + } + Tcl_SetObjResult(interp, pRet); + + break; + } + + case CMD_SECTORSIZE: { + if( objc>3 ){ + Tcl_WrongNumArgs(interp, 2, objv, "?VALUE?"); + return TCL_ERROR; + } + if( objc==3 ){ + int iNew = 0; + if( Tcl_GetIntFromObj(interp, objv[2], &iNew) ){ + return TCL_ERROR; + } + p->iSectorsize = iNew; + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(p->iSectorsize)); + break; + } } return TCL_OK; @@ -1067,6 +1262,8 @@ static int testvfs_cmd( nByte = sizeof(Testvfs) + strlen(zVfs)+1; p = (Testvfs *)ckalloc(nByte); memset(p, 0, nByte); + p->iDevchar = -1; + p->iSectorsize = -1; /* Create the new object command before querying SQLite for a default VFS ** to use for 'real' IO operations. This is because creating the new VFS |