mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
Experimental change: On systems where it is not possible to unlink a file while one or more processes has it open (i.e. not unix), avoid closing the journal file each time the database is unlocked and reopening it at the start of each transaction.
FossilOrigin-Name: bede8c8a148fb9be5ffbf38df7fa733e35cc68c3
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
||||
C Add\sextra\stest\scases\sto\spager1.test.
|
||||
D 2010-06-16T12:30:11
|
||||
C Experimental\schange:\sOn\ssystems\swhere\sit\sis\snot\spossible\sto\sunlink\sa\sfile\swhile\sone\sor\smore\sprocesses\shas\sit\sopen\s(i.e.\snot\sunix),\savoid\sclosing\sthe\sjournal\sfile\seach\stime\sthe\sdatabase\sis\sunlocked\sand\sreopening\sit\sat\sthe\sstart\sof\seach\stransaction.
|
||||
D 2010-06-16T19:04:23
|
||||
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
|
||||
F Makefile.in a5cad1f8f3e021356bfcc6c77dc16f6f1952bbc3
|
||||
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
|
||||
@@ -156,7 +156,7 @@ F src/os_common.h a8f95b81eca8a1ab8593d23e94f8a35f35d4078f
|
||||
F src/os_os2.c 665876d5eec7585226b0a1cf5e18098de2b2da19
|
||||
F src/os_unix.c ae173c9f6afaa58b2833a1c95c6cd32021755c42
|
||||
F src/os_win.c dfde7d33c446e89dd9a277c036f2c4cc564b3138
|
||||
F src/pager.c 2964185d4356d0dc159b8340e52d2538d32394e5
|
||||
F src/pager.c 133cc49da000b2685a104ed9812084c61bd7e40f
|
||||
F src/pager.h ca1f23c0cf137ac26f8908df2427c8b308361efd
|
||||
F src/parse.y ace5c7a125d9f2a410e431ee3209034105045f7e
|
||||
F src/pcache.c 1e9aa2dbc0845b52e1b51cc39753b6d1e041cb07
|
||||
@@ -170,7 +170,7 @@ F src/resolve.c ac5f1a713cd1ae77f08b83cc69581e11bf5ae6f9
|
||||
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
|
||||
F src/select.c c03d8a0565febcde8c6a12c5d77d065fddae889b
|
||||
F src/shell.c fd4ccdb37c3b68de0623eb938a649e0990710714
|
||||
F src/sqlite.h.in 46c01e55cea31b91565ae41276c6310ee4032be8
|
||||
F src/sqlite.h.in 706e41c4526ed2674fa042ab3b7ba473b20cb141
|
||||
F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
|
||||
F src/sqliteInt.h 242987ebd2366ea36650a09cdab04a9163c62109
|
||||
F src/sqliteLimit.h 196e2f83c3b444c4548fc1874f52f84fdbda40f3
|
||||
@@ -209,7 +209,7 @@ F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0
|
||||
F src/test_server.c bbba05c144b5fc4b52ff650a4328027b3fa5fcc6
|
||||
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
|
||||
F src/test_thread.c aa9919c885a1fe53eafc73492f0898ee6c0a0726
|
||||
F src/test_vfs.c 001c34e08748a4a02cd1c2d5531c160a007a84d8
|
||||
F src/test_vfs.c 687ba8db7830909955896488a66d3c6b655827f0
|
||||
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
|
||||
F src/tokenize.c 25ceb0f0a746ea1d0f9553787f3f0a56853cfaeb
|
||||
F src/trigger.c 8927588cb9e6d47f933b53bfe74200fbb504100d
|
||||
@@ -466,6 +466,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
|
||||
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
|
||||
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
|
||||
F test/journal1.test 36f2d1bb9bf03f790f43fbdb439e44c0657fab19
|
||||
F test/journal2.test 0f867f26c7f30bda2b69dc0e6451caa8fed18ef1
|
||||
F test/jrnlmode.test 76f94d61528c5ff32102a12f8cf34f4cc36f7849
|
||||
F test/jrnlmode2.test fe79ea1f0375c926b8de0362ddf94f34a64135fd
|
||||
F test/jrnlmode3.test cfcdb12b90e640a23b92785a002d96c0624c8710
|
||||
@@ -822,7 +823,10 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
|
||||
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
|
||||
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
|
||||
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
|
||||
P 6c5c04eea1f0e8d61883ee8675c249fbf895dc01
|
||||
R d490808417f08b44a0b162eb48b4aec9
|
||||
P ad3209572d0e6afe5c8b52313e334509661045e2
|
||||
R 55fd31c025a3067f63c5d2afd30242b8
|
||||
T *branch * experimental
|
||||
T *sym-experimental *
|
||||
T -sym-trunk *
|
||||
U dan
|
||||
Z 861e5ff117287c588eecf635e107e097
|
||||
Z 33e1ea27519902b3169c3c25730a3e25
|
||||
|
@@ -1 +1 @@
|
||||
ad3209572d0e6afe5c8b52313e334509661045e2
|
||||
bede8c8a148fb9be5ffbf38df7fa733e35cc68c3
|
27
src/pager.c
27
src/pager.c
@@ -336,6 +336,7 @@ struct Pager {
|
||||
u8 tempFile; /* zFilename is a temporary file */
|
||||
u8 readOnly; /* True for a read-only database */
|
||||
u8 memDb; /* True to inhibit all file I/O */
|
||||
u8 safeJrnlHandle; /* True if jrnl may be held open with no lock */
|
||||
|
||||
/* The following block contains those class members that are dynamically
|
||||
** modified during normal operations. The other variables in this structure
|
||||
@@ -1224,7 +1225,13 @@ static void pager_unlock(Pager *pPager){
|
||||
** Otherwise, another connection with journal_mode=delete might
|
||||
** delete the file out from under us.
|
||||
*/
|
||||
if( pPager->safeJrnlHandle==0
|
||||
|| (pPager->journalMode!=PAGER_JOURNALMODE_TRUNCATE
|
||||
&& pPager->journalMode!=PAGER_JOURNALMODE_PERSIST)
|
||||
){
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
|
||||
sqlite3BitvecDestroy(pPager->pInJournal);
|
||||
pPager->pInJournal = 0;
|
||||
releaseAllSavepoints(pPager);
|
||||
@@ -3089,6 +3096,7 @@ int sqlite3PagerClose(Pager *pPager){
|
||||
sqlite3BeginBenignMalloc();
|
||||
pPager->errCode = 0;
|
||||
pPager->exclusiveMode = 0;
|
||||
pPager->safeJrnlHandle = 0;
|
||||
#ifndef SQLITE_OMIT_WAL
|
||||
sqlite3WalClose(pPager->pWal,
|
||||
(pPager->noSync ? 0 : pPager->sync_flags),
|
||||
@@ -3908,17 +3916,22 @@ int sqlite3PagerOpen(
|
||||
*/
|
||||
static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
sqlite3_vfs * const pVfs = pPager->pVfs;
|
||||
int rc; /* Return code */
|
||||
int exists; /* True if a journal file is present */
|
||||
int rc = SQLITE_OK; /* Return code */
|
||||
int exists = 1; /* True if a journal file is present */
|
||||
int jrnlOpen = !!isOpen(pPager->jfd);
|
||||
|
||||
assert( pPager!=0 );
|
||||
assert( pPager->useJournal );
|
||||
assert( isOpen(pPager->fd) );
|
||||
assert( !isOpen(pPager->jfd) );
|
||||
assert( pPager->state <= PAGER_SHARED );
|
||||
assert( jrnlOpen==0
|
||||
|| sqlite3OsDeviceCharacteristics(pPager->jfd)&SQLITE_IOCAP_SAFE_DELETE
|
||||
);
|
||||
|
||||
*pExists = 0;
|
||||
if( !jrnlOpen ){
|
||||
rc = sqlite3OsAccess(pVfs, pPager->zJournal, SQLITE_ACCESS_EXISTS, &exists);
|
||||
}
|
||||
if( rc==SQLITE_OK && exists ){
|
||||
int locked; /* True if some process holds a RESERVED lock */
|
||||
|
||||
@@ -3956,15 +3969,19 @@ static int hasHotJournal(Pager *pPager, int *pExists){
|
||||
** If there is, then we consider this journal to be hot. If not,
|
||||
** it can be ignored.
|
||||
*/
|
||||
if( !jrnlOpen ){
|
||||
int f = SQLITE_OPEN_READONLY|SQLITE_OPEN_MAIN_JOURNAL;
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, f, &f);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
u8 first = 0;
|
||||
rc = sqlite3OsRead(pPager->jfd, (void *)&first, 1, 0);
|
||||
if( rc==SQLITE_IOERR_SHORT_READ ){
|
||||
rc = SQLITE_OK;
|
||||
}
|
||||
if( !jrnlOpen ){
|
||||
sqlite3OsClose(pPager->jfd);
|
||||
}
|
||||
*pExists = (first!=0);
|
||||
}else if( rc==SQLITE_CANTOPEN ){
|
||||
/* If we cannot open the rollback journal file in order to see if
|
||||
@@ -4490,6 +4507,10 @@ static int pager_open_journal(Pager *pPager){
|
||||
);
|
||||
#else
|
||||
rc = sqlite3OsOpen(pVfs, pPager->zJournal, pPager->jfd, flags, 0);
|
||||
if( rc==SQLITE_OK ){
|
||||
int iDc = sqlite3OsDeviceCharacteristics(pPager->jfd);
|
||||
pPager->safeJrnlHandle = (iDc&SQLITE_IOCAP_SAFE_DELETE)!=0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
assert( rc!=SQLITE_OK || isOpen(pPager->jfd) );
|
||||
|
@@ -508,6 +508,7 @@ int sqlite3_exec(
|
||||
#define SQLITE_IOCAP_ATOMIC64K 0x00000100
|
||||
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
|
||||
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
|
||||
#define SQLITE_IOCAP_SAFE_DELETE 0x00000800
|
||||
|
||||
/*
|
||||
** CAPI3REF: File Locking Levels
|
||||
|
190
src/test_vfs.c
190
src/test_vfs.c
@@ -58,6 +58,9 @@ struct Testvfs {
|
||||
int iIoerrCnt;
|
||||
int ioerr;
|
||||
int nIoerrFail;
|
||||
|
||||
int iDevchar;
|
||||
int iSectorsize;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -77,7 +80,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
|
||||
@@ -245,15 +251,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 +292,42 @@ 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 ){
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -376,16 +416,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -782,25 +830,37 @@ 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
|
||||
};
|
||||
struct TestvfsSubcmd {
|
||||
char *zName;
|
||||
enum DB_enum eCmd;
|
||||
} aSubcmd[] = {
|
||||
{ "shm", CMD_SHM },
|
||||
{ "delete", CMD_DELETE },
|
||||
{ "filter", CMD_FILTER },
|
||||
{ "ioerr", CMD_IOERR },
|
||||
{ "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 +917,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;
|
||||
@@ -948,6 +1011,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 },
|
||||
{ "safe_delete", SQLITE_IOCAP_SAFE_DELETE },
|
||||
{ 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 +1213,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
|
||||
|
188
test/journal2.test
Normal file
188
test/journal2.test
Normal file
@@ -0,0 +1,188 @@
|
||||
# 2010 June 16
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
source $testdir/lock_common.tcl
|
||||
source $testdir/malloc_common.tcl
|
||||
db close
|
||||
|
||||
set a_string_counter 1
|
||||
proc a_string {n} {
|
||||
global a_string_counter
|
||||
incr a_string_counter
|
||||
string range [string repeat "${a_string_counter}." $n] 1 $n
|
||||
}
|
||||
|
||||
# Create a [testvfs] and install it as the default VFS. Set the device
|
||||
# characteristics flags to "SAFE_DELETE".
|
||||
#
|
||||
testvfs tvfs -default 1
|
||||
tvfs devchar safe_delete
|
||||
|
||||
# Set up a hook so that each time a journal file is opened, closed or
|
||||
# deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
|
||||
# segment of the journal file-name (i.e. "test.db-journal") are appended to
|
||||
# global list variable $::oplog.
|
||||
#
|
||||
tvfs filter {xOpen xClose xDelete}
|
||||
tvfs script journal_op_catcher
|
||||
|
||||
proc journal_op_catcher {method filename args} {
|
||||
|
||||
# If global variable ::tvfs_error_on_write is defined, then return an
|
||||
# IO error to every attempt to modify the file-system. Otherwise, return
|
||||
# SQLITE_OK.
|
||||
#
|
||||
if {[info exists ::tvfs_error_on_write]} {
|
||||
if {$method == "xDelete" || $method == "xWrite" || $method == "xTruncate"} {
|
||||
return SQLITE_IOERR
|
||||
}
|
||||
return SQLITE_OK
|
||||
}
|
||||
|
||||
if {[string match *journal* $filename]==0} return
|
||||
|
||||
set f [file tail $filename]
|
||||
lappend ::oplog $method $f
|
||||
|
||||
if {[info exists ::open_journals($f)]==0} { set ::open_journals($f) 0 }
|
||||
switch -- $method {
|
||||
xOpen {
|
||||
incr ::open_journals($f) +1
|
||||
}
|
||||
xClose {
|
||||
incr ::open_journals($f) -1
|
||||
}
|
||||
xDelete {
|
||||
if {$::open_journals($f)>0} { return SQLITE_IOERR }
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
do_test journal2-1.1 {
|
||||
set ::oplog [list]
|
||||
sqlite3 db test.db
|
||||
execsql { CREATE TABLE t1(a, b) }
|
||||
set ::oplog
|
||||
} {xOpen test.db-journal xClose test.db-journal xDelete test.db-journal}
|
||||
do_test journal2-1.2 {
|
||||
set ::oplog [list]
|
||||
execsql {
|
||||
PRAGMA journal_mode = truncate;
|
||||
INSERT INTO t1 VALUES(1, 2);
|
||||
}
|
||||
set ::oplog
|
||||
} {xOpen test.db-journal}
|
||||
do_test journal2-1.3 {
|
||||
set ::oplog [list]
|
||||
execsql { INSERT INTO t1 VALUES(3, 4) }
|
||||
set ::oplog
|
||||
} {}
|
||||
do_test journal2-1.4 { execsql { SELECT * FROM t1 } } {1 2 3 4}
|
||||
|
||||
# Add a second connection. This connection attempts to commit data in
|
||||
# journal_mode=DELETE mode. When it tries to delete the journal file,
|
||||
# the VFS layer returns an IO error.
|
||||
#
|
||||
do_test journal2-1.5 {
|
||||
set ::oplog [list]
|
||||
sqlite3 db2 test.db
|
||||
execsql { PRAGMA journal_mode = delete } db2
|
||||
catchsql { INSERT INTO t1 VALUES(5, 6) } db2
|
||||
} {1 {disk I/O error}}
|
||||
do_test journal2-1.6 { file exists test.db-journal } 1
|
||||
do_test journal2-1.7 { execsql { SELECT * FROM t1 } } {1 2 3 4}
|
||||
do_test journal2-1.8 {
|
||||
execsql { PRAGMA journal_mode = truncate } db2
|
||||
execsql { INSERT INTO t1 VALUES(5, 6) } db2
|
||||
} {}
|
||||
do_test journal2-1.9 { execsql { SELECT * FROM t1 } } {1 2 3 4 5 6}
|
||||
|
||||
# Grow the database until it is reasonably large. Then, from a
|
||||
# journal_mode=DELETE connection, attempt to commit a large transaction (one
|
||||
# that involves upgrading to an exclusive lock and writing the database
|
||||
# before the transaction is committed).
|
||||
#
|
||||
do_test journal2-1.10 {
|
||||
db2 close
|
||||
db func a_string a_string
|
||||
execsql {
|
||||
CREATE TABLE t2(a UNIQUE, b UNIQUE);
|
||||
INSERT INTO t2 VALUES(a_string(200), a_string(300));
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 2
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 4
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 8
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 16
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 32
|
||||
INSERT INTO t2 SELECT a_string(200), a_string(300) FROM t2; -- 64
|
||||
}
|
||||
file size test.db-journal
|
||||
} {0}
|
||||
do_test journal2-1.11 {
|
||||
set sz [expr [file size test.db] / 1024]
|
||||
expr {$sz>120 && $sz<200}
|
||||
} 1
|
||||
|
||||
do_test journal2-1.12 {
|
||||
sqlite3 db2 test.db
|
||||
execsql {
|
||||
PRAGMA cache_size = 10;
|
||||
BEGIN;
|
||||
INSERT INTO t2 SELECT randomblob(200), randomblob(300) FROM t2; -- 128
|
||||
} db2
|
||||
} {}
|
||||
do_test journal2-1.13 {
|
||||
tvfs filter {xOpen xClose xDelete xWrite xTruncate}
|
||||
set ::tvfs_error_on_write 1
|
||||
catchsql { COMMIT } db2
|
||||
} {1 {disk I/O error}}
|
||||
db2 close
|
||||
unset ::tvfs_error_on_write
|
||||
file copy -force test.db testX.db
|
||||
|
||||
do_test journal2-1.14 { file exists test.db-journal } 1
|
||||
do_test journal2-1.15 {
|
||||
execsql {
|
||||
SELECT count(*) FROM t2;
|
||||
PRAGMA integrity_check;
|
||||
}
|
||||
} {64 ok}
|
||||
|
||||
# This block checks that in the test case above, connection [db2] really
|
||||
# did begin writing to the database file before it hit IO errors. If
|
||||
# this is true, then the copy of the database file made before [db]
|
||||
# rolled back the hot journal should fail the integrity-check.
|
||||
#
|
||||
do_test journal2-1.16 {
|
||||
set sz [expr [file size testX.db] / 1024]
|
||||
expr {$sz>240 && $sz<400}
|
||||
} 1
|
||||
do_test journal2-1.17 {
|
||||
expr {[catchsql { PRAGMA integrity_check } db] == "0 ok"}
|
||||
} {1}
|
||||
do_test journal2-1.20 {
|
||||
sqlite3 db2 testX.db
|
||||
expr {[catchsql { PRAGMA integrity_check } db2] == "0 ok"}
|
||||
} {0}
|
||||
do_test journal2-1.21 {
|
||||
db2 close
|
||||
} {}
|
||||
|
||||
db close
|
||||
tvfs delete
|
||||
finish_test
|
||||
|
Reference in New Issue
Block a user