1
0
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:
dan
2010-06-16 19:04:23 +00:00
parent 53f04f3b3f
commit 2a321c7547
6 changed files with 400 additions and 38 deletions

View File

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

View File

@@ -1 +1 @@
ad3209572d0e6afe5c8b52313e334509661045e2
bede8c8a148fb9be5ffbf38df7fa733e35cc68c3

View File

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

View File

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

View File

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