-C Bug\sfix\sin\sthe\smemory\sleak\strace\soutput.\s(CVS\s4283)
-D 2007-08-24T04:15:00
+C Add\stests\sto\ssimulate\spower-failure\son\sdevices\sthat\ssupport\sIOCAP_SEQUENTIAL\sor\sIOCAP_SAFE_APPEND.\s(CVS\s4284)
+D 2007-08-24T08:15:54
F Makefile.in 0c0e53720f658c7a551046442dd7afba0b72bfbe
F Makefile.linux-gcc 65241babba6faf1152bf86574477baab19190499
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/hash.c 2f322979071dd2bdba7503b5276d66f028744382
F src/hash.h 3ad3da76bfb954978d227bf495568b0e6da2c19e
F src/insert.c 633322aef1799f6604fa805e12488bc628570b0c
-F src/journal.c 03d6b5cc1afe7c5e3cd0af55415f5168eb094398
+F src/journal.c 573911e274738b3fda813d4f0a6e319f8a9ecd36
F src/legacy.c 7e1b1c57694e49cbadf561e2a7d9cd984dc743b5
F src/limits.h 71ab25f17e35e0a9f3f6f234b8ed49cc56731d35
F src/loadext.c 8b31e2e0e961918fa045515459aee1c122d8c266
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c 1cb94dd33d38e01de82d77bef107c7f3323463ec
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 89dfc6a0bd72898d147264517a43bdf35348dd2c
+F src/pager.c a46c807f6c00d8172ea7f17b8bfd2c870d2e9d98
F src/pager.h 53087c6fb9db01aed17c7fd044662a27507e89b8
F src/parse.y 2d2ce439dc6184621fb0b86f4fc5aca7f391a590
F src/pragma.c 9b989506a1b7c8aecd6befb8235e2f57a4aba7e5
F src/shell.c ac29402b538515fa4697282387be9c1205e6e9eb
F src/sqlite.h.in 09a5256ee80dfc7cb4353739f78e4267be323574
F src/sqlite3ext.h 9a26028378c288af500d8b94ed079666fed5806b
-F src/sqliteInt.h 951229c727f14f12f1c5555d2ed079bd2201415c
+F src/sqliteInt.h ea7a14a33c0a03479d2d98ce9ac83fe5e7f4bb55
F src/sqliteLimit.h f14609c27636ebc217c9603ade26dbdd7d0f6afa
F src/table.c c725e47f6f3092b9a7b569fc58e408e2173ee008
F src/tclsqlite.c d76af53f45c9e9f7f7d39531fa4c7bee7d0adad6
F src/test3.c a7d011c51d6b2e2a73c43983d5c2b731d69c74d7
F src/test4.c c2c0f5dc907f1346f5d4b65eb5799f11eb9e4071
F src/test5.c 3a6a5717a149d7ca2e6d14f5be72cf7555d54dc4
-F src/test6.c de2dbcd67401f00bfa0affc044ba671aa62384a5
+F src/test6.c 37caea087882ecce1cbc6c83f9f1d457bd42b731
F src/test7.c a9d509d0e9ad214b4772696f49f6e61be26213d1
F src/test8.c e6a543c8b248efe120ae33a6859fcd55dcf46a96
F src/test9.c b46c8fe02ac7cca1a7316436d8d38d50c66f4b2f
F test/corrupt3.test 263e8bb04e2728df832fddf6973cf54c91db0c32
F test/crash.test 24020168cc42977a4dd83ff78d2b5eb6577715db
F test/crash2.test 423c6ec404d15b7d7d0e40aef0a26740cce6075f
-F test/crash3.test caa79052f29ee5cb17ecede2c386251eb932c05f
+F test/crash3.test 96eee2301b000264d355591fe650a9ad5ac01be9
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
F test/createtab.test b562aba1a65be49935fc43a04e90766e39231804
F test/date.test 4834d022b2fa5982cafed20938f7523a7475e4cd
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 3a68fcddfa9184e4b310ce0a21312c54b9462ec8
-R 8577d385c536daf1df94ce55e3096cab
-U drh
-Z 81d0ac074a196345faf13b53e0789aed
+P a1b495c28a092c7eb79ffeeb6a217749acb4c12c
+R 9e378d30b0d2403f2a8c2ca36386519e
+U danielk1977
+Z cedf0a8ddde877cdc3adcde56bbd62a1
-a1b495c28a092c7eb79ffeeb6a217749acb4c12c
\ No newline at end of file
+bdf5cb8d25d93d48220ce46acad2ccf967a87843
\ No newline at end of file
**
*************************************************************************
**
-** @(#) $Id: journal.c,v 1.2 2007/08/23 08:06:45 danielk1977 Exp $
+** @(#) $Id: journal.c,v 1.3 2007/08/24 08:15:54 danielk1977 Exp $
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
return SQLITE_OK;
}
+/*
+** If the argument p points to a JournalFile structure, and the underlying
+** file has not yet been created, create it now.
+*/
+int sqlite3JournalCreate(sqlite3_file *p){
+ if( p->pMethods!=&JournalFileMethods ){
+ return SQLITE_OK;
+ }
+ return createFile((JournalFile *)p);
+}
+
/*
** Return the number of bytes required to store a JournalFile that uses vfs
** pVfs to create the underlying on-disk files.
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.372 2007/08/24 03:51:34 drh Exp $
+** @(#) $Id: pager.c,v 1.373 2007/08/24 08:15:54 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
*/
if( pPager->state!=PAGER_SYNCED && !MEMDB && pPager->dirtyCache ){
PgHdr *pPg;
- assert( pPager->journalOpen );
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/* The atomic-write optimization can be used if all of the
** If the optimization can be used, then the journal file will never
** be created for this transaction.
*/
- if( !zMaster && pPager->journalOff==jrnlBufferSize(pPager) && nTrunc==0
- && (0==pPager->pDirty || 0==pPager->pDirty->pDirty)
- ){
+ int useAtomicWrite = (
+ !zMaster &&
+ pPager->journalOff==jrnlBufferSize(pPager) &&
+ nTrunc==0 &&
+ (0==pPager->pDirty || 0==pPager->pDirty->pDirty)
+ );
+ if( useAtomicWrite ){
/* Update the nRec field in the journal file. */
int offset = pPager->journalHdr + sizeof(aJournalMagic);
assert(pPager->nRec==1);
** this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
- }else
+ }else{
+ rc = sqlite3JournalCreate(pPager->jfd);
+ if( rc!=SQLITE_OK ) goto sync_exit;
+ }
+
+ if( !useAtomicWrite )
#endif
/* If a master journal file name has already been written to the
** transaction the m-j name will have already been written.
*/
if( !pPager->setMaster ){
+ assert( pPager->journalOpen );
rc = pager_incr_changecounter(pPager, 0);
if( rc!=SQLITE_OK ) goto sync_exit;
#ifndef SQLITE_OMIT_AUTOVACUUM
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.598 2007/08/23 02:47:53 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.599 2007/08/24 08:15:54 danielk1977 Exp $
*/
#ifndef _SQLITEINT_H_
#define _SQLITEINT_H_
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
+ int sqlite3JournalCreate(sqlite3_file *);
#else
#define sqlite3JournalSize(pVfs) ((pVfs)->szOsFile)
#endif
** the effect on the database file of an OS crash or power failure. This
** is used to test the ability of SQLite to recover from those situations.
*/
-#if SQLITE_TEST /* This file is used for the testing only */
+#if SQLITE_TEST /* This file is used for testing only */
#include "sqliteInt.h"
#include "tcl.h"
static int writeListSync(CrashFile *pFile, int isCrash){
int rc = SQLITE_OK;
int iDc = g.iDeviceCharacteristics;
- i64 iSize;
WriteBuffer *pWrite;
WriteBuffer **ppPtr;
- /* Set pFinal to point to the last element of the write-list that
- ** is associated with file handle pFile.
+ /* If this is not a crash simulation, set pFinal to point to the
+ ** last element of the write-list that is associated with file handle
+ ** pFile.
+ **
+ ** If this is a crash simulation, set pFinal to an arbitrarily selected
+ ** element of the write-list.
*/
WriteBuffer *pFinal = 0;
if( !isCrash ){
pFinal = pWrite;
}
}
+ }else if( iDc&(SQLITE_IOCAP_SEQUENTIAL|SQLITE_IOCAP_SAFE_APPEND) ){
+ int nWrite = 0;
+ int iFinal;
+ for(pWrite=g.pWriteList; pWrite; pWrite=pWrite->pNext) nWrite++;
+ sqlite3Randomness(sizeof(int), &iFinal);
+ iFinal = ((iFinal<0)?-1*iFinal:iFinal)%nWrite;
+ for(pWrite=g.pWriteList; iFinal>0; pWrite=pWrite->pNext) iFinal--;
+ pFinal = pWrite;
}
#ifdef TRACE_CRASHTEST
printf("Sync %s (is %s crash)\n", pFile->zName, (isCrash?"a":"not a"));
#endif
- sqlite3OsFileSize((sqlite3_file *)pFile, &iSize);
-
ppPtr = &g.pWriteList;
for(pWrite=*ppPtr; rc==SQLITE_OK && pWrite; pWrite=*ppPtr){
sqlite3_file *pRealFile = pWrite->pFile->pRealFile;
char random;
sqlite3Randomness(1, &random);
- if( iDc&SQLITE_IOCAP_ATOMIC || pWrite->zBuf==0 ){
+ /* Do not select option 3 (sector trashing) if the IOCAP_ATOMIC flag
+ ** is set or this is an OsTruncate(), not an Oswrite().
+ */
+ if( (iDc&SQLITE_IOCAP_ATOMIC) || (pWrite->zBuf==0) ){
random &= 0x01;
}
+ /* If IOCAP_SEQUENTIAL is set and this is not the final entry
+ ** in the truncated write-list, always select option 1 (write
+ ** out correctly).
+ */
+ if( (iDc&SQLITE_IOCAP_SEQUENTIAL && pWrite!=pFinal) ){
+ random = 0;
+ }
+
+ /* If IOCAP_SAFE_APPEND is set and this OsWrite() operation is
+ ** an append (first byte of the written region is 1 byte past the
+ ** current EOF), always select option 1 (write out correctly).
+ */
+ if( iDc&SQLITE_IOCAP_SAFE_APPEND && pWrite->zBuf ){
+ i64 iSize;
+ sqlite3OsFileSize(pRealFile, &iSize);
+ if( iSize==pWrite->iOffset ){
+ random = 0;
+ }
+ }
+
if( (random&0x06)==0x06 ){
eAction = 3;
}else{
*ppPtr = pWrite->pNext;
#ifdef TRACE_CRASHTEST
if( isCrash ){
- printf("Writing %d bytes @ %d\n", pWrite->nBuf, (int)pWrite->iOffset);
+ printf("Writing %d bytes @ %d (%s)\n",
+ pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
+ );
}
#endif
sqlite3_free(pWrite);
ppPtr = &pWrite->pNext;
#ifdef TRACE_CRASHTEST
if( isCrash ){
- printf("Omiting %d bytes @ %d\n", pWrite->nBuf, (int)pWrite->iOffset);
+ printf("Omiting %d bytes @ %d (%s)\n",
+ pWrite->nBuf, (int)pWrite->iOffset, pWrite->pFile->zName
+ );
}
#endif
break;
assert(pWrite->zBuf);
#ifdef TRACE_CRASHTEST
- printf("Trashing %d sectors @ sector %d\n", 1+iLast-iFirst, iFirst);
+ printf("Trashing %d sectors @ sector %d (%s)\n",
+ 1+iLast-iFirst, iFirst, pWrite->pFile->zName
+ );
#endif
zGarbage = sqlite3_malloc(g.iSectorSize);
** equal or greater than sizeof(CrashFile).
*/
static int cfOpen(
- void *pAppData,
+ sqlite3_vfs *pCfVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
int rc;
CrashFile *pWrapper = (CrashFile *)pFile;
sqlite3_file *pReal = (sqlite3_file*)&pWrapper[1];
return rc;
}
-static int cfDelete(void *pAppData, const char *zPath, int dirSync){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xDelete(pVfs->pAppData, zPath, dirSync);
+static int cfDelete(sqlite3_vfs *pCfVfs, const char *zPath, int dirSync){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xDelete(pVfs, zPath, dirSync);
}
-static int cfAccess(void *pAppData, const char *zPath, int flags){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xAccess(pVfs->pAppData, zPath, flags);
+static int cfAccess(sqlite3_vfs *pCfVfs, const char *zPath, int flags){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xAccess(pVfs, zPath, flags);
}
-static int cfGetTempName(void *pAppData, char *zBufOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xGetTempName(pVfs->pAppData, zBufOut);
+static int cfGetTempName(sqlite3_vfs *pCfVfs, char *zBufOut){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xGetTempName(pVfs, zBufOut);
}
-static int cfFullPathname(void *pAppData, const char *zPath, char *zPathOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xFullPathname(pVfs->pAppData, zPath, zPathOut);
+static int cfFullPathname(sqlite3_vfs *pCfVfs, const char *zPath, char *zPathOut){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xFullPathname(pVfs, zPath, zPathOut);
}
-static void *cfDlOpen(void *pAppData, const char *zPath){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xDlOpen(pVfs->pAppData, zPath);
+static void *cfDlOpen(sqlite3_vfs *pCfVfs, const char *zPath){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xDlOpen(pVfs, zPath);
}
-static int cfRandomness(void *pAppData, int nByte, char *zBufOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xRandomness(pVfs->pAppData, nByte, zBufOut);
+static int cfRandomness(sqlite3_vfs *pCfVfs, int nByte, char *zBufOut){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xRandomness(pVfs, nByte, zBufOut);
}
-static int cfSleep(void *pAppData, int nMicro){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xSleep(pVfs->pAppData, nMicro);
+static int cfSleep(sqlite3_vfs *pCfVfs, int nMicro){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xSleep(pVfs, nMicro);
}
-static int cfCurrentTime(void *pAppData, double *pTimeOut){
- sqlite3_vfs *pVfs = (sqlite3_vfs *)pAppData;
- return pVfs->xCurrentTime(pVfs->pAppData, pTimeOut);
+static int cfCurrentTime(sqlite3_vfs *pCfVfs, double *pTimeOut){
+ sqlite3_vfs *pVfs = (sqlite3_vfs *)pCfVfs->pAppData;
+ return pVfs->xCurrentTime(pVfs, pTimeOut);
}
static int processDevSymArgs(
#
#***********************************************************************
#
-# $Id: crash3.test,v 1.1 2007/08/23 11:07:10 danielk1977 Exp $
+# This file contains tests that verify that SQLite can correctly rollback
+# databases after crashes when using the special IO modes triggered
+# by device IOCAP flags.
+#
+# $Id: crash3.test,v 1.2 2007/08/24 08:15:54 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
uplevel $script
}
+# This block tests crash-recovery when the IOCAP_ATOMIC flags is set.
+#
# Each iteration of the following loop sets up the database to contain
# the following schema and data:
#
}
}
+# This block tests both the IOCAP_SEQUENTIAL and IOCAP_SAFE_APPEND flags.
+#
+db close
+file delete -force test.db test.db-journal
+sqlite3 db test.db
+do_test crash3-2.0 {
+ execsql {
+ BEGIN;
+ CREATE TABLE abc(a PRIMARY KEY, b, c);
+ CREATE TABLE def(d PRIMARY KEY, e, f);
+ PRAGMA default_cache_size = 10;
+ INSERT INTO abc VALUES(randstr(10,1000),randstr(10,1000),randstr(10,1000));
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000) FROM abc;
+ COMMIT;
+ }
+} {}
+
+set tn 1
+foreach {::crashfile ::delay ::char} {
+ test.db 1 sequential
+ test.db 1 safe_append
+ test.db-journal 1 sequential
+ test.db-journal 1 safe_append
+ test.db-journal 2 safe_append
+ test.db-journal 2 sequential
+ test.db-journal 3 sequential
+ test.db-journal 3 safe_append
+} {
+ for {set ii 0} {$ii < 100} {incr ii} {
+ set ::SQL [subst {
+ SELECT randstr($ii,$ii+10);
+ BEGIN;
+ DELETE FROM abc WHERE random()%5;
+ INSERT INTO abc
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000)
+ FROM abc
+ WHERE (random()%5)==0;
+ DELETE FROM def WHERE random()%5;
+ INSERT INTO def
+ SELECT randstr(10,1000),randstr(10,1000),randstr(10,1000)
+ FROM def
+ WHERE (random()%5)==0;
+ COMMIT;
+ }]
+
+ do_test crash3-2.$tn.$ii {
+ crashsql -file $::crashfile -delay $::delay -char $::char $::SQL
+ db close
+ sqlite3 db test.db
+ execsql {PRAGMA integrity_check}
+ } {ok}
+ }
+ incr tn
+}
+
+# The following block tests an interaction between IOCAP_ATOMIC and
+# IOCAP_SEQUENTIAL. At one point, if both flags were set, small
+# journal files that contained only a single page, but were required
+# for some other reason (i.e. nTrunk) were not being written to
+# disk.
+#
+for {set ii 0} {$ii < 10} {incr ii} {
+ db close
+ file delete -force test.db test.db-journal
+ crashsql -file test.db -char {sequential atomic} {
+ CREATE TABLE abc(a, b, c);
+ }
+ sqlite3 db test.db
+ do_test crash3-3.$ii {
+ execsql {PRAGMA integrity_check}
+ } {ok}
+}
+
finish_test