Backport of all batch-atomic-write changes through check-in

[67bad7fb9b]

FossilOrigin-Name: def55027b1f1db9c083830019dbcc3daed94f6cc70a76b285ac1af9d82f81695
This commit is contained in:
drh
2017-07-28 02:02:45 +00:00
18 changed files with 684 additions and 182 deletions
+24 -20
View File
@@ -1,5 +1,5 @@
C Do\snow\sallow\sthe\sgeometry\sobject\sin\sthe\sright\soperand\sof\sa\sMATCH\soperator\sin\nthe\sRTREE\sextension\sto\sbe\sinpersonated\sby\sa\sBLOB\sliteral.
D 2017-07-27T00:27:57.692
C Backport\sof\sall\sbatch-atomic-write\schanges\sthrough\scheck-in\n[67bad7fb9b]
D 2017-07-28T02:02:45.191
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 8eeb80162074004e906b53d7340a12a14c471a83743aab975947e95ce061efcc
@@ -352,7 +352,7 @@ F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f61
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
F src/ctime.c 9793c9128901afbaa7561c9dcb510c96c6187225680ef644577bd74e2551b3a6
F src/date.c cc42a41c7422389860d40419a5e3bce5eaf6e7835c3ba2677751dc653550a5c7
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c 665e705641e5815c3f32d05820d1a5aa630274e568af73f377fdbc614fcf40b4
@@ -375,7 +375,7 @@ F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
F src/mem2.c f1940d9e91948dd6a908fbb9ce3835c36b5d83c3
F src/mem3.c 8768ac94694f31ffaf8b4d0ea5dc08af7010a35a
F src/mem5.c 9bf955937b07f8c32541c8a9991f33ce3173d944
F src/memjournal.c 95752936c11dc6995672d1dd783cd633eea0cc95
F src/memjournal.c 9b9e579226341e891a4657dc76fe2cec69734abcd23be0e42aa8764d88131f12
F src/msvc.h 4942752b6a253116baaa8de75256c51a459a5e81
F src/mutex.c 8e45800ee78e0cd1f1f3fe8e398853307f4a085c
F src/mutex.h 779d588e3b7756ec3ecf7d78cde1d84aba414f85
@@ -387,10 +387,10 @@ F src/os.c add02933b1dce7a39a005b00a2f5364b763e9a24
F src/os.h 8e976e59eb4ca1c0fca6d35ee803e38951cb0343
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c 30e2c43e4955db990e5b5a81e901f8aa74cc8820
F src/os_unix.c 9aa19db965d574cbaf74405cd51c58b87fdbfe045b8bbfc01b18bdeeda3c4305
F src/os_win.c 2a6c73eef01c51a048cc4ddccd57f981afbec18a
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
F src/pager.c 80893c0860199aebc6efa4f102ab11eebde338b7fdbb0c04d4b04647c2fd62d1
F src/pager.c 930dace8819cf569331bca24be8fe362d337208bc6e12dc4acb19c596630f1f4
F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
F src/parse.y 0513387ce02fea97897d8caef82d45f347818593f24f1bdc48e0c530a8af122d
F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
@@ -405,20 +405,20 @@ F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c c444ca057d48cf1a4eb8f6a58fbc13418a7f83ae94a6bd6f29f7ad6c704a9e4c
F src/shell.c a37d96b20b3644d0eb905df5aa7a0fcf9f6e73c15898337230c760a24a8df794
F src/sqlite.h.in 8dd468837a4f6d76713e3a4cc65bea48095009038593d41040ab46c1b351197f
F src/sqlite.h.in d603987eee5f7a2fa81d4baf5ec70b67b214bd34f7e1819653f5ec3b9c982eee
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
F src/sqliteInt.h aea3aa1b81e0d07d5b1c39b8c5a54a1dc5e4f10136cb63da392aef9eb2a5108b
F src/sqliteInt.h 40785f84fc3d3b25b54f4325d42992f41a73e81de57b354271bd2de0ae377625
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
F src/tclsqlite.c c8cf60d0c5411d5e70e7c136470d29dbe760d250f55198b71682c67086524e4a
F src/test1.c c99f0442918a7a5d5b68a95d6024c211989e6c782c15ced5a558994baaf76a5e
F src/test1.c 4856c3d776e11d0975bf56ad41626b467af6af6443a937c36c3d9d4643029f7c
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
@@ -431,7 +431,7 @@ F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c edcba290248dc18736dd814c9b95863c6762e0b35753048d8cbe5bf65f7abfbb
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
F src/test_devsym.c 4e58dec2602d8e139ca08659f62a62450587cb58
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
F src/test_fs.c e16cbe68d3b107e00a907c20a9a02629870eb69b
F src/test_func.c a4fdab3363b436c1b12660e9362ce3f3782b7b5e
F src/test_hexio.c 1d4469ca61ab202a1fcec6543f584d2407205e8d
@@ -703,7 +703,7 @@ F test/exists.test 79a75323c78f02bbe9c251ea502a092f9ef63dac
F test/expr.test 66a2c9ac34f74f036faa4092f5402c7d3162fc93
F test/extension01.test 00d13cec817f331a687a243e0e5a2d87b0e358c9
F test/extraquick.test cb254400bd42bfb777ff675356aabf3287978f79
F test/fallocate.test 3e979af17dfa7e5e9dda5eba1a696c04fa9d47f7
F test/fallocate.test 87b5e43c872b7e69cd80b7b8813eb102b571a75d45dda24e38b65537bcc85733
F test/filectrl.test 6e871c2d35dead1d9a88e176e8d2ca094fec6bb3
F test/filefmt.test e4edbdc637ca9576ccf4337a3cce627d9df7a56c
F test/fkey1.test ba64806ff9a04eecab2679caad377ae99a5e94e4
@@ -977,7 +977,7 @@ F test/minmax.test 6751e87b409fe11b02e70a306d846fa544e25a41
F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc
F test/minmax3.test cc1e8b010136db0d01a6f2a29ba5a9f321034354
F test/minmax4.test 936941484ebdceb8adec7c86b6cd9b6e5e897c1f
F test/misc1.test 6430dabfb4b4fa480633590118964201f94d3ccc
F test/misc1.test 51ec3f56a2a7965de226964cff856695e743186826561536647f1e8b7d1d0eb3
F test/misc2.test 00d7de54eda90e237fc9a38b9e5ccc769ebf6d4d
F test/misc3.test cf3dda47d5dda3e53fc5804a100d3c82be736c9d
F test/misc4.test 0d8be3466adf123a7791a66ba2bc8e8d229e87f3
@@ -1035,7 +1035,7 @@ F test/parser1.test 391b9bf9a229547a129c61ac345ed1a6f5eb1854
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
F test/permutations.test 8aaa22a0f428a7e6b8446b97bc7691a273eaeff5dc290fb9129bf79fa9813a6e
F test/permutations.test 0672e2db670217b156ae6d32c7de3abcda50a305743e7d45d1063ede31159bd0
F test/pragma.test 1e94755164a3a3264cd39836de4bebcb7809e5f8
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
@@ -1061,7 +1061,7 @@ F test/regexp2.test 40e894223b3d6672655481493f1be12012f2b33c
F test/reindex.test 44edd3966b474468b823d481eafef0c305022254
F test/releasetest.tcl 936c8b9c72d46a86d0f9d65c536e883c2d79a8f53a5324283757bfc9d8b5a656 x
F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb
F test/rollback.test 458fe73eb3ffdfdf9f6ba3e9b7350a6220414dea
F test/rollback.test f580934279800d480a19176c6b44909df31ce7ad45267ea475a541daa522f3d3
F test/rollback2.test 8435d6ff0f13f51d2a4181c232e706005fa90fc5
F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a
F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc
@@ -1179,7 +1179,7 @@ F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
F test/syscall.test f59ba4e25f7ba4a4c031026cc2ef8b6e4b4c639c
F test/syscall.test 26f05bc237853a7588b9a4c9111aacb8cdd32d2562c36fee7d9dfc4731c6c329
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
F test/tabfunc01.test 699251cb99651415218a891384510a685c7ab012
F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
@@ -1193,7 +1193,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
F test/tester.tcl eb7ec55fe074a909423c1de701f7c545417b8aa96787b8c3e7a79203f2cebec8
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
@@ -1487,6 +1487,7 @@ F test/without_rowid4.test 4e08bcbaee0399f35d58b5581881e7a6243d458a
F test/without_rowid5.test 89b1c587bd92a0590e440da33e7666bf4891572a
F test/without_rowid6.test 1f99644e6508447fb050f73697350c7ceca3392e
F test/wordcount.c 06efb84b7c48a4973c2c24ea06c93d00bce24389
F test/writecrash.test e6dc9d470d43710c3f780a50d29cce1c3884ca34ff50e737bc9ab8724c7c2398
F test/zeroblob.test 3857870fe681b8185654414a9bccfde80b62a0fa
F test/zerodamage.test e59a56443d6298ecf7435f618f0b27654f0c849e
F tool/GetFile.cs a15e08acb5dd7539b75ba23501581d7c2b462cb5
@@ -1580,7 +1581,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 0ee482a1e0eae22e08edc8978c9733a96603d4509645f348ebf55b579e89636b
R 5aba315ce772ced25c1b87936307ec42
P 24c9cd460051781f7e6417b7e205274319258f061ae1191a6c5ff5af615439c9 67bad7fb9b2fdb29b63308f22062444084dc28191a542e08076dc2e39caf6f62
R 52d5da1e6c65e285a15752ad8c60b72a
T *branch * batch-atomic-write-3.19
T *sym-batch-atomic-write-3.19 *
T -sym-branch-3.19 *
U drh
Z c0ec9b17a9a0e51afaa3dc2485cf6a08
Z db5307b269591715fdc95cf9a91a4aa8
+1 -1
View File
@@ -1 +1 @@
24c9cd460051781f7e6417b7e205274319258f061ae1191a6c5ff5af615439c9
def55027b1f1db9c083830019dbcc3daed94f6cc70a76b285ac1af9d82f81695
+3
View File
@@ -90,6 +90,9 @@ static const char * const azCompileOpt[] = {
#if SQLITE_ENABLE_ATOMIC_WRITE
"ENABLE_ATOMIC_WRITE",
#endif
#if SQLITE_ENABLE_BATCH_ATOMIC_WRITE
"ENABLE_BATCH_ATOMIC_WRITE",
#endif
#if SQLITE_ENABLE_CEROD
"ENABLE_CEROD",
#endif
+16 -8
View File
@@ -96,7 +96,8 @@ static int memjrnlRead(
int iChunkOffset;
FileChunk *pChunk;
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( (iAmt+iOfst)>p->endpoint.iOffset ){
return SQLITE_IOERR_SHORT_READ;
}
@@ -215,7 +216,8 @@ static int memjrnlWrite(
** atomic-write optimization. In this case the first 28 bytes of the
** journal file may be written as part of committing the transaction. */
assert( iOfst==p->endpoint.iOffset || iOfst==0 );
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
if( iOfst==0 && p->pFirst ){
assert( p->nChunkSize>iAmt );
memcpy((u8*)p->pFirst->zChunk, zBuf, iAmt);
@@ -384,17 +386,23 @@ void sqlite3MemJournalOpen(sqlite3_file *pJfd){
sqlite3JournalOpen(0, 0, pJfd, 0, -1);
}
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
/*
** If the argument p points to a MemJournal structure that is not an
** in-memory-only journal file (i.e. is one that was opened with a +ve
** nSpill parameter), and the underlying file has not yet been created,
** create it now.
** nSpill parameter or as SQLITE_OPEN_MAIN_JOURNAL), and the underlying
** file has not yet been created, create it now.
*/
int sqlite3JournalCreate(sqlite3_file *p){
int sqlite3JournalCreate(sqlite3_file *pJfd){
int rc = SQLITE_OK;
if( p->pMethods==&MemJournalMethods && ((MemJournal*)p)->nSpill>0 ){
rc = memjrnlCreateFile((MemJournal*)p);
MemJournal *p = (MemJournal*)pJfd;
if( p->pMethod==&MemJournalMethods && (p->nSpill>0
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
|| (p->flags & SQLITE_OPEN_MAIN_JOURNAL)
#endif
)){
rc = memjrnlCreateFile(p);
}
return rc;
}
+84 -34
View File
@@ -90,6 +90,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
@@ -220,10 +221,8 @@ struct unixFile {
sqlite3_int64 mmapSizeMax; /* Configured FCNTL_MMAP_SIZE value */
void *pMapRegion; /* Memory mapped region */
#endif
#ifdef __QNXNTO__
int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */
#endif
#if SQLITE_ENABLE_LOCKING_STYLE
int openFlags; /* The flags specified at open() */
#endif
@@ -328,6 +327,20 @@ static pid_t randomnessPid = 0;
# define lseek lseek64
#endif
#ifdef __linux__
/*
** Linux-specific IOCTL magic numbers used for controlling F2FS
*/
#define F2FS_IOCTL_MAGIC 0xf5
#define F2FS_IOC_START_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 1)
#define F2FS_IOC_COMMIT_ATOMIC_WRITE _IO(F2FS_IOCTL_MAGIC, 2)
#define F2FS_IOC_START_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 3)
#define F2FS_IOC_ABORT_VOLATILE_WRITE _IO(F2FS_IOCTL_MAGIC, 5)
#define F2FS_IOC_GET_FEATURES _IOR(F2FS_IOCTL_MAGIC, 12, u32)
#define F2FS_FEATURE_ATOMIC_WRITE 0x0004
#endif /* __linux__ */
/*
** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...).
@@ -500,6 +513,9 @@ static struct unix_syscall {
#endif
#define osLstat ((int(*)(const char*,struct stat*))aSyscall[27].pCurrent)
{ "ioctl", (sqlite3_syscall_ptr)ioctl, 0 },
#define osIoctl ((int(*)(int,int,...))aSyscall[28].pCurrent)
}; /* End of the overrideable system calls */
@@ -3777,6 +3793,21 @@ static int unixGetTempname(int nBuf, char *zBuf);
static int unixFileControl(sqlite3_file *id, int op, void *pArg){
unixFile *pFile = (unixFile*)id;
switch( op ){
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
case SQLITE_FCNTL_BEGIN_ATOMIC_WRITE: {
int rc = osIoctl(pFile->h, F2FS_IOC_START_ATOMIC_WRITE);
return rc ? SQLITE_ERROR : SQLITE_OK;
}
case SQLITE_FCNTL_COMMIT_ATOMIC_WRITE: {
int rc = osIoctl(pFile->h, F2FS_IOC_COMMIT_ATOMIC_WRITE);
return rc ? SQLITE_ERROR : SQLITE_OK;
}
case SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE: {
int rc = osIoctl(pFile->h, F2FS_IOC_ABORT_VOLATILE_WRITE);
return rc ? SQLITE_ERROR : SQLITE_OK;
}
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
case SQLITE_FCNTL_LOCKSTATE: {
*(int*)pArg = pFile->eFileLock;
return SQLITE_OK;
@@ -3860,30 +3891,41 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
}
/*
** Return the sector size in bytes of the underlying block device for
** the specified file. This is almost always 512 bytes, but may be
** larger for some devices.
** If pFd->sectorSize is non-zero when this function is called, it is a
** no-op. Otherwise, the values of pFd->sectorSize and
** pFd->deviceCharacteristics are set according to the file-system
** characteristics.
**
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
** There are two versions of this function. One for QNX and one for all
** other systems.
*/
#ifndef __QNXNTO__
static int unixSectorSize(sqlite3_file *NotUsed){
UNUSED_PARAMETER(NotUsed);
return SQLITE_DEFAULT_SECTOR_SIZE;
}
#endif
#ifndef __QNXNTO__
static void setDeviceCharacteristics(unixFile *pFd){
assert( pFd->deviceCharacteristics==0 || pFd->sectorSize!=0 );
if( pFd->sectorSize==0 ){
#if defined(__linux__) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
int res;
u32 f = 0;
/*
** The following version of unixSectorSize() is optimized for QNX.
*/
#ifdef __QNXNTO__
/* Check for support for F2FS atomic batch writes. */
res = osIoctl(pFd->h, F2FS_IOC_GET_FEATURES, &f);
if( res==0 && (f & F2FS_FEATURE_ATOMIC_WRITE) ){
pFd->deviceCharacteristics = SQLITE_IOCAP_BATCH_ATOMIC;
}
#endif /* __linux__ && SQLITE_ENABLE_BATCH_ATOMIC_WRITE */
/* Set the POWERSAFE_OVERWRITE flag if requested. */
if( pFd->ctrlFlags & UNIXFILE_PSOW ){
pFd->deviceCharacteristics |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
pFd->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
}
#else
#include <sys/dcmd_blk.h>
#include <sys/statvfs.h>
static int unixSectorSize(sqlite3_file *id){
unixFile *pFile = (unixFile*)id;
static void setDeviceCharacteristics(unixFile *pFile){
if( pFile->sectorSize == 0 ){
struct statvfs fsInfo;
@@ -3952,9 +3994,24 @@ static int unixSectorSize(sqlite3_file *id){
pFile->deviceCharacteristics = 0;
pFile->sectorSize = SQLITE_DEFAULT_SECTOR_SIZE;
}
return pFile->sectorSize;
}
#endif /* __QNXNTO__ */
#endif
/*
** Return the sector size in bytes of the underlying block device for
** the specified file. This is almost always 512 bytes, but may be
** larger for some devices.
**
** SQLite code assumes this function cannot fail. It also assumes that
** if two files are created in the same file-system directory (i.e.
** a database and its journal file) that the sector size will be the
** same for both.
*/
static int unixSectorSize(sqlite3_file *id){
unixFile *pFd = (unixFile*)id;
setDeviceCharacteristics(pFd);
return pFd->sectorSize;
}
/*
** Return the device characteristics for the file.
@@ -3970,16 +4027,9 @@ static int unixSectorSize(sqlite3_file *id){
** available to turn it off and URI query parameter available to turn it off.
*/
static int unixDeviceCharacteristics(sqlite3_file *id){
unixFile *p = (unixFile*)id;
int rc = 0;
#ifdef __QNXNTO__
if( p->sectorSize==0 ) unixSectorSize(id);
rc = p->deviceCharacteristics;
#endif
if( p->ctrlFlags & UNIXFILE_PSOW ){
rc |= SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}
return rc;
unixFile *pFd = (unixFile*)id;
setDeviceCharacteristics(pFd);
return pFd->deviceCharacteristics;
}
#if !defined(SQLITE_OMIT_WAL) || SQLITE_MAX_MMAP_SIZE>0
@@ -7598,7 +7648,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==28 );
assert( ArraySize(aSyscall)==29 );
/* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){
+106 -46
View File
@@ -947,6 +947,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
assert( pPager->dbOrigSize<=pPager->dbHintSize );
break;
@@ -958,6 +959,7 @@ static int assert_pager_state(Pager *p){
assert( isOpen(p->jfd)
|| p->journalMode==PAGER_JOURNALMODE_OFF
|| p->journalMode==PAGER_JOURNALMODE_WAL
|| (sqlite3OsDeviceCharacteristics(p->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
break;
@@ -1168,34 +1170,45 @@ static int pagerLockDb(Pager *pPager, int eLock){
}
/*
** This function determines whether or not the atomic-write optimization
** can be used with this pager. The optimization can be used if:
** This function determines whether or not the atomic-write or
** atomic-batch-write optimizations can be used with this pager. The
** atomic-write optimization can be used if:
**
** (a) the value returned by OsDeviceCharacteristics() indicates that
** a database page may be written atomically, and
** (b) the value returned by OsSectorSize() is less than or equal
** to the page size.
**
** The optimization is also always enabled for temporary files. It is
** an error to call this function if pPager is opened on an in-memory
** database.
** If it can be used, then the value returned is the size of the journal
** file when it contains rollback data for exactly one page.
**
** If the optimization cannot be used, 0 is returned. If it can be used,
** then the value returned is the size of the journal file when it
** contains rollback data for exactly one page.
** The atomic-batch-write optimization can be used if OsDeviceCharacteristics()
** returns a value with the SQLITE_IOCAP_BATCH_ATOMIC bit set. -1 is
** returned in this case.
**
** If neither optimization can be used, 0 is returned.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
static int jrnlBufferSize(Pager *pPager){
assert( !MEMDB );
if( !pPager->tempFile ){
int dc; /* Device characteristics */
int nSector; /* Sector size */
int szPage; /* Page size */
assert( isOpen(pPager->fd) );
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
nSector = pPager->sectorSize;
szPage = pPager->pageSize;
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
int dc; /* Device characteristics */
assert( isOpen(pPager->fd) );
dc = sqlite3OsDeviceCharacteristics(pPager->fd);
#endif
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( dc&SQLITE_IOCAP_BATCH_ATOMIC ){
return -1;
}
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
{
int nSector = pPager->sectorSize;
int szPage = pPager->pageSize;
assert(SQLITE_IOCAP_ATOMIC512==(512>>8));
assert(SQLITE_IOCAP_ATOMIC64K==(65536>>8));
@@ -1205,11 +1218,11 @@ static int jrnlBufferSize(Pager *pPager){
}
return JOURNAL_HDR_SZ(pPager) + JOURNAL_PG_SZ(pPager);
}
#else
# define jrnlBufferSize(x) 0
#endif
return 0;
}
/*
** If SQLITE_CHECK_PAGES is defined then we do some sanity checking
** on the cache using a hash function. This is used for testing
@@ -2012,7 +2025,9 @@ static int pager_end_transaction(Pager *pPager, int hasMaster, int bCommit){
}
releaseAllSavepoints(pPager);
assert( isOpen(pPager->jfd) || pPager->pInJournal==0 );
assert( isOpen(pPager->jfd) || pPager->pInJournal==0
|| (sqlite3OsDeviceCharacteristics(pPager->fd)&SQLITE_IOCAP_BATCH_ATOMIC)
);
if( isOpen(pPager->jfd) ){
assert( !pagerUseWal(pPager) );
@@ -4569,6 +4584,13 @@ static int pagerStress(void *p, PgHdr *pPg){
rc = pagerWalFrames(pPager, pPg, 0, 0);
}
}else{
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( pPager->tempFile==0 ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) return pager_error(pPager, rc);
}
#endif
/* Sync the journal file if required. */
if( pPg->flags&PGHDR_NEED_SYNC
@@ -6354,6 +6376,21 @@ int sqlite3PagerCommitPhaseOne(
sqlite3PcacheCleanAll(pPager->pPCache);
}
}else{
/* The bBatch boolean is true if the batch-atomic-write commit method
** should be used. No rollback journal is created if batch-atomic-write
** is enabled.
*/
sqlite3_file *fd = pPager->fd;
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
const int bBatch = zMaster==0 /* An SQLITE_IOCAP_BATCH_ATOMIC commit */
&& (sqlite3OsDeviceCharacteristics(fd) & SQLITE_IOCAP_BATCH_ATOMIC)
&& !pPager->noSync
&& sqlite3JournalIsInMemory(pPager->jfd);
#else
# define bBatch 0
#endif
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
/* The following block updates the change-counter. Exactly how it
** does this depends on whether or not the atomic-update optimization
** was enabled at compile time, and if this transaction meets the
@@ -6377,33 +6414,40 @@ int sqlite3PagerCommitPhaseOne(
** in 'direct' mode. In this case the journal file will never be
** created for this transaction.
*/
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
PgHdr *pPg;
assert( isOpen(pPager->jfd)
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (0==(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
if( bBatch==0 ){
PgHdr *pPg;
assert( isOpen(pPager->jfd)
|| pPager->journalMode==PAGER_JOURNALMODE_OFF
|| pPager->journalMode==PAGER_JOURNALMODE_WAL
);
if( !zMaster && isOpen(pPager->jfd)
&& pPager->journalOff==jrnlBufferSize(pPager)
&& pPager->dbSize>=pPager->dbOrigSize
&& (!(pPg = sqlite3PcacheDirtyList(pPager->pPCache)) || 0==pPg->pDirty)
){
/* Update the db file change counter via the direct-write method. The
** following call will modify the in-memory representation of page 1
** to include the updated change counter and then write page 1
** directly to the database file. Because of the atomic-write
** property of the host file-system, this is safe.
*/
rc = pager_incr_changecounter(pPager, 1);
}else{
rc = sqlite3JournalCreate(pPager->jfd);
if( rc==SQLITE_OK ){
rc = pager_incr_changecounter(pPager, 0);
}
}
}
#else
#else
#ifdef SQLITE_ENABLE_BATCH_ATOMIC_WRITE
if( zMaster ){
rc = sqlite3JournalCreate(pPager->jfd);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
#endif
rc = pager_incr_changecounter(pPager, 0);
#endif
#endif
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
/* Write the master journal name into the journal file. If a master
@@ -6426,8 +6470,24 @@ int sqlite3PagerCommitPhaseOne(
*/
rc = syncJournal(pPager, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
if( bBatch ){
/* The pager is now in DBMOD state. But regardless of what happens
** next, attempting to play the journal back into the database would
** be unsafe. Close it now to make sure that does not happen. */
sqlite3OsClose(pPager->jfd);
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE, 0);
if( rc!=SQLITE_OK ) goto commit_phase_one_exit;
}
rc = pager_write_pagelist(pPager,sqlite3PcacheDirtyList(pPager->pPCache));
if( bBatch ){
if( rc==SQLITE_OK ){
rc = sqlite3OsFileControl(fd, SQLITE_FCNTL_COMMIT_ATOMIC_WRITE, 0);
}else{
sqlite3OsFileControl(fd, SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE, 0);
}
}
if( rc!=SQLITE_OK ){
assert( rc!=SQLITE_IOERR_BLOCKED );
goto commit_phase_one_exit;
+44
View File
@@ -580,6 +580,11 @@ int sqlite3_exec(
** SQLITE_IOCAP_IMMUTABLE flag indicates that the file is on
** read-only media and cannot be changed even by processes with
** elevated privileges.
**
** The SQLITE_IOCAP_BATCH_ATOMIC property means that the underlying
** filesystem supports doing multiple write operations atomically when those
** write operations are bracketed by [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] and
** [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE].
*/
#define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -595,6 +600,7 @@ int sqlite3_exec(
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
#define SQLITE_IOCAP_IMMUTABLE 0x00002000
#define SQLITE_IOCAP_BATCH_ATOMIC 0x00004000
/*
** CAPI3REF: File Locking Levels
@@ -729,6 +735,7 @@ struct sqlite3_file {
** <li> [SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN]
** <li> [SQLITE_IOCAP_POWERSAFE_OVERWRITE]
** <li> [SQLITE_IOCAP_IMMUTABLE]
** <li> [SQLITE_IOCAP_BATCH_ATOMIC]
** </ul>
**
** The SQLITE_IOCAP_ATOMIC property means that all writes of
@@ -1012,6 +1019,40 @@ struct sqlite3_io_methods {
** The [SQLITE_FCNTL_RBU] opcode is implemented by the special VFS used by
** the RBU extension only. All other VFS should return SQLITE_NOTFOUND for
** this opcode.
**
** <li>[[SQLITE_FCNTL_BEGIN_ATOMIC_WRITE]]
** If the [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] opcode returns SQLITE_OK, then
** the file descriptor is placed in "batch write mode", which
** means all subsequent write operations will be deferred and done
** atomically at the next [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]. Systems
** that do not support batch atomic writes will return SQLITE_NOTFOUND.
** ^Following a successful SQLITE_FCNTL_BEGIN_ATOMIC_WRITE and prior to
** the closing [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] or
** [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE], SQLite will make
** no VFS interface calls on the same [sqlite3_file] file descriptor
** except for calls to the xWrite method and the xFileControl method
** with [SQLITE_FCNTL_SIZE_HINT].
**
** <li>[[SQLITE_FCNTL_COMMIT_ATOMIC_WRITE]]
** The [SQLITE_FCNTL_COMMIT_ATOMIC_WRITE] opcode causes all write
** operations since the previous successful call to
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be performed atomically.
** This file control returns [SQLITE_OK] if and only if the writes were
** all performed successfully and have been committed to persistent storage.
** ^Regardless of whether or not it is successful, this file control takes
** the file descriptor out of batch write mode so that all subsequent
** write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_COMMIT_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
**
** <li>[[SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE]]
** The [SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE] opcode causes all write
** operations since the previous successful call to
** [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE] to be rolled back.
** ^This file control takes the file descriptor out of batch write mode
** so that all subsequent write operations are independent.
** ^SQLite will never invoke SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE without
** a prior successful call to [SQLITE_FCNTL_BEGIN_ATOMIC_WRITE].
** </ul>
*/
#define SQLITE_FCNTL_LOCKSTATE 1
@@ -1043,6 +1084,9 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_JOURNAL_POINTER 28
#define SQLITE_FCNTL_WIN32_GET_HANDLE 29
#define SQLITE_FCNTL_PDB 30
#define SQLITE_FCNTL_BEGIN_ATOMIC_WRITE 31
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
/* deprecated names */
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
+11 -1
View File
@@ -625,6 +625,15 @@
# define SQLITE_DEFAULT_PCACHE_INITSZ 20
#endif
/*
** The compile-time options SQLITE_MMAP_READWRITE and
** SQLITE_ENABLE_BATCH_ATOMIC_WRITE are not compatible with one another.
** You must choose one or the other (or neither) but not both.
*/
#if defined(SQLITE_MMAP_READWRITE) && defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
#error Cannot use both SQLITE_MMAP_READWRITE and SQLITE_ENABLE_BATCH_ATOMIC_WRITE
#endif
/*
** GCC does not define the offsetof() macro so we'll have to do it
** ourselves.
@@ -4256,7 +4265,8 @@ int sqlite3FindInIndex(Parse *, Expr *, u32, int*, int*);
int sqlite3JournalOpen(sqlite3_vfs *, const char *, sqlite3_file *, int, int);
int sqlite3JournalSize(sqlite3_vfs *);
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
#if defined(SQLITE_ENABLE_ATOMIC_WRITE) \
|| defined(SQLITE_ENABLE_BATCH_ATOMIC_WRITE)
int sqlite3JournalCreate(sqlite3_file *);
#endif
+41
View File
@@ -2550,6 +2550,46 @@ static int SQLITE_TCLAPI test_delete_database(
return TCL_OK;
}
/*
** Usage: atomic_batch_write PATH
*/
static int SQLITE_TCLAPI test_atomic_batch_write(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char *zFile = 0; /* Path to file to test */
sqlite3 *db = 0; /* Database handle */
sqlite3_file *pFd = 0; /* SQLite fd open on zFile */
int bRes = 0; /* Integer result of this command */
int dc = 0; /* Device-characteristics mask */
int rc; /* sqlite3_open() return code */
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "PATH");
return TCL_ERROR;
}
zFile = Tcl_GetString(objv[1]);
rc = sqlite3_open(zFile, &db);
if( rc!=SQLITE_OK ){
Tcl_AppendResult(interp, sqlite3_errmsg(db), 0);
sqlite3_close(db);
return TCL_ERROR;
}
rc = sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, (void*)&pFd);
dc = pFd->pMethods->xDeviceCharacteristics(pFd);
if( dc & SQLITE_IOCAP_BATCH_ATOMIC ){
bRes = 1;
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(bRes));
sqlite3_close(db);
return TCL_OK;
}
/*
** Usage: sqlite3_next_stmt DB STMT
**
@@ -7639,6 +7679,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "sqlite3_snapshot_cmp_blob", test_snapshot_cmp_blob, 0 },
#endif
{ "sqlite3_delete_database", test_delete_database, 0 },
{ "atomic_batch_write", test_atomic_batch_write, 0 },
};
static int bitmask_size = sizeof(Bitmask)*8;
static int longdouble_size = sizeof(LONGDOUBLE_TYPE);
+25
View File
@@ -736,6 +736,7 @@ static int processDevSymArgs(
{ "sequential", SQLITE_IOCAP_SEQUENTIAL },
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
{ "batch-atomic", SQLITE_IOCAP_BATCH_ATOMIC },
{ 0, 0 }
};
@@ -976,7 +977,30 @@ static int SQLITE_TCLAPI devSymObjCmd(
devsym_register(iDc, iSectorSize);
return TCL_OK;
}
/*
** tclcmd: sqlite3_crash_on_write N
*/
static int SQLITE_TCLAPI writeCrashObjCmd(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
void devsym_crash_on_write(int);
int nWrite = 0;
if( objc!=2 ){
Tcl_WrongNumArgs(interp, 1, objv, "NWRITE");
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[1], &nWrite) ){
return TCL_ERROR;
}
devsym_crash_on_write(nWrite);
return TCL_OK;
}
/*
@@ -1068,6 +1092,7 @@ int Sqlitetest6_Init(Tcl_Interp *interp){
Tcl_CreateObjCommand(interp, "sqlite3_crashparams", crashParamsObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_crash_now", crashNowCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_simulate_device", devSymObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "sqlite3_crash_on_write", writeCrashObjCmd,0,0);
Tcl_CreateObjCommand(interp, "unregister_devsim", dsUnregisterObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "register_jt_vfs", jtObjCmd, 0, 0);
Tcl_CreateObjCommand(interp, "unregister_jt_vfs", jtUnregisterObjCmd, 0, 0);
+168 -50
View File
@@ -28,6 +28,7 @@
** Name used to identify this VFS.
*/
#define DEVSYM_VFS_NAME "devsym"
#define WRITECRASH_NAME "writecrash"
typedef struct devsym_file devsym_file;
struct devsym_file {
@@ -72,61 +73,13 @@ static int devsymRandomness(sqlite3_vfs*, int nByte, char *zOut);
static int devsymSleep(sqlite3_vfs*, int microseconds);
static int devsymCurrentTime(sqlite3_vfs*, double*);
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
DEVSYM_VFS_NAME, /* zName */
0, /* pAppData */
devsymOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
static sqlite3_io_methods devsym_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
struct DevsymGlobal {
sqlite3_vfs *pVfs;
int iDeviceChar;
int iSectorSize;
int nWriteCrash;
};
struct DevsymGlobal g = {0, 0, 512};
struct DevsymGlobal g = {0, 0, 512, 0};
/*
** Close an devsym-file.
@@ -271,6 +224,26 @@ static int devsymOpen(
int flags,
int *pOutFlags
){
static sqlite3_io_methods devsym_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
devsymWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
devsymSectorSize, /* xSectorSize */
devsymDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
@@ -372,6 +345,137 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
return g.pVfs->xCurrentTime(g.pVfs, pTimeOut);
}
/*
** Return the sector-size in bytes for an writecrash-file.
*/
static int writecrashSectorSize(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsSectorSize(p->pReal);
}
/*
** Return the device characteristic flags supported by an writecrash-file.
*/
static int writecrashDeviceCharacteristics(sqlite3_file *pFile){
devsym_file *p = (devsym_file *)pFile;
return sqlite3OsDeviceCharacteristics(p->pReal);
}
/*
** Write data to an writecrash-file.
*/
static int writecrashWrite(
sqlite3_file *pFile,
const void *zBuf,
int iAmt,
sqlite_int64 iOfst
){
devsym_file *p = (devsym_file *)pFile;
if( g.nWriteCrash>0 ){
g.nWriteCrash--;
if( g.nWriteCrash==0 ) abort();
}
return sqlite3OsWrite(p->pReal, zBuf, iAmt, iOfst);
}
/*
** Open an writecrash file handle.
*/
static int writecrashOpen(
sqlite3_vfs *pVfs,
const char *zName,
sqlite3_file *pFile,
int flags,
int *pOutFlags
){
static sqlite3_io_methods writecrash_io_methods = {
2, /* iVersion */
devsymClose, /* xClose */
devsymRead, /* xRead */
writecrashWrite, /* xWrite */
devsymTruncate, /* xTruncate */
devsymSync, /* xSync */
devsymFileSize, /* xFileSize */
devsymLock, /* xLock */
devsymUnlock, /* xUnlock */
devsymCheckReservedLock, /* xCheckReservedLock */
devsymFileControl, /* xFileControl */
writecrashSectorSize, /* xSectorSize */
writecrashDeviceCharacteristics, /* xDeviceCharacteristics */
devsymShmMap, /* xShmMap */
devsymShmLock, /* xShmLock */
devsymShmBarrier, /* xShmBarrier */
devsymShmUnmap /* xShmUnmap */
};
int rc;
devsym_file *p = (devsym_file *)pFile;
p->pReal = (sqlite3_file *)&p[1];
rc = sqlite3OsOpen(g.pVfs, zName, p->pReal, flags, pOutFlags);
if( p->pReal->pMethods ){
pFile->pMethods = &writecrash_io_methods;
}
return rc;
}
static sqlite3_vfs devsym_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
DEVSYM_VFS_NAME, /* zName */
0, /* pAppData */
devsymOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
static sqlite3_vfs writecrash_vfs = {
2, /* iVersion */
sizeof(devsym_file), /* szOsFile */
DEVSYM_MAX_PATHNAME, /* mxPathname */
0, /* pNext */
WRITECRASH_NAME, /* zName */
0, /* pAppData */
writecrashOpen, /* xOpen */
devsymDelete, /* xDelete */
devsymAccess, /* xAccess */
devsymFullPathname, /* xFullPathname */
#ifndef SQLITE_OMIT_LOAD_EXTENSION
devsymDlOpen, /* xDlOpen */
devsymDlError, /* xDlError */
devsymDlSym, /* xDlSym */
devsymDlClose, /* xDlClose */
#else
0, /* xDlOpen */
0, /* xDlError */
0, /* xDlSym */
0, /* xDlClose */
#endif /* SQLITE_OMIT_LOAD_EXTENSION */
devsymRandomness, /* xRandomness */
devsymSleep, /* xSleep */
devsymCurrentTime, /* xCurrentTime */
0, /* xGetLastError */
0 /* xCurrentTimeInt64 */
};
/*
** This procedure registers the devsym vfs with SQLite. If the argument is
@@ -379,10 +483,13 @@ static int devsymCurrentTime(sqlite3_vfs *pVfs, double *pTimeOut){
** available function in this file.
*/
void devsym_register(int iDeviceChar, int iSectorSize){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
if( iDeviceChar>=0 ){
g.iDeviceChar = iDeviceChar;
@@ -403,4 +510,15 @@ void devsym_unregister(){
g.iSectorSize = 0;
}
void devsym_crash_on_write(int nWrite){
if( g.pVfs==0 ){
g.pVfs = sqlite3_vfs_find(0);
devsym_vfs.szOsFile += g.pVfs->szOsFile;
writecrash_vfs.szOsFile += g.pVfs->szOsFile;
sqlite3_vfs_register(&devsym_vfs, 0);
sqlite3_vfs_register(&writecrash_vfs, 0);
}
g.nWriteCrash = nWrite;
}
#endif
+3 -1
View File
@@ -59,7 +59,9 @@ do_test fallocate-1.6 {
#
do_test fallocate-1.7 {
execsql { BEGIN; INSERT INTO t1 VALUES(1, 2); }
if {[permutation] != "inmemory_journal"} {
if {[permutation] != "inmemory_journal"
&& [permutation] != "atomic-batch-write"
} {
hexio_get_int [hexio_read test.db-journal 16 4]
} else {
set {} 1024
+22 -20
View File
@@ -479,26 +479,28 @@ ifcapable curdir {
# Make sure a database connection still works after changing the
# working directory.
#
do_test misc1-14.1 {
file mkdir tempdir
cd tempdir
execsql {BEGIN}
file exists ./test.db-journal
} {0}
do_test misc1-14.2a {
execsql {UPDATE t1 SET a=a||'x' WHERE 0}
file exists ../test.db-journal
} {0}
do_test misc1-14.2b {
execsql {UPDATE t1 SET a=a||'y' WHERE 1}
file exists ../test.db-journal
} {1}
do_test misc1-14.3 {
cd ..
forcedelete tempdir
execsql {COMMIT}
file exists ./test.db-journal
} {0}
if {[atomic_batch_write test.db]==0} {
do_test misc1-14.1 {
file mkdir tempdir
cd tempdir
execsql {BEGIN}
file exists ./test.db-journal
} {0}
do_test misc1-14.2a {
execsql {UPDATE t1 SET a=a||'x' WHERE 0}
file exists ../test.db-journal
} {0}
do_test misc1-14.2b {
execsql {UPDATE t1 SET a=a||'y' WHERE 1}
file exists ../test.db-journal
} {1}
do_test misc1-14.3 {
cd ..
forcedelete tempdir
execsql {COMMIT}
file exists ./test.db-journal
} {0}
}
}
# A failed create table should not leave the table in the internal
+24
View File
@@ -384,6 +384,30 @@ test_suite "vfslog" -prefix "" -description {
wal* mmap*
]
test_suite "atomic-batch-write" -prefix "" -description {
Like veryquick.test, but must be run on a file-system that supports
atomic-batch-writes. Tests that depend on the journal file being present
are omitted.
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* *bigfile* *_err* \
*fts5corrupt* *fts5big* *fts5aj* \
crash8.test delete_db.test \
exclusive.test journal3.test \
journal1.test \
jrnlmode.test jrnlmode2.test \
lock4.test pager1.test \
pager3.test sharedA.test \
symlink.test stmt.test \
sync.test sync2.test \
tempdb.test tkt3457.test \
vacuum5.test wal2.test \
walmode.test zerodamage.test
] -initialize {
if {[atomic_batch_write test.db]==0} {
error "File system does NOT support atomic-batch-write"
}
}
lappend ::testsuitelist xxx
#-------------------------------------------------------------------------
# Define the coverage related test suites:
+1
View File
@@ -82,6 +82,7 @@ do_test rollback-1.9 {
if {$tcl_platform(platform) == "unix"
&& [permutation] ne "onefile"
&& [permutation] ne "inmemory_journal"
&& [permutation] ne "atomic-batch-write"
} {
do_test rollback-2.1 {
execsql {
+1 -1
View File
@@ -61,7 +61,7 @@ foreach s {
fcntl read pread write pwrite fchmod fallocate
pread64 pwrite64 unlink openDirectory mkdir rmdir
statvfs fchown geteuid umask mmap munmap mremap
getpagesize readlink lstat
getpagesize readlink lstat ioctl
} {
if {[test_syscall exists $s]} {lappend syscall_list $s}
}
+48
View File
@@ -1608,6 +1608,54 @@ proc crashsql {args} {
lappend r $msg
}
# crash_on_write ?-devchar DEVCHAR? CRASHDELAY SQL
#
proc crash_on_write {args} {
set nArg [llength $args]
if {$nArg<2 || $nArg%2} {
error "bad args: $args"
}
set zSql [lindex $args end]
set nDelay [lindex $args end-1]
set devchar {}
for {set ii 0} {$ii < $nArg-2} {incr ii 2} {
set opt [lindex $args $ii]
switch -- [lindex $args $ii] {
-devchar {
set devchar [lindex $args [expr $ii+1]]
}
default { error "unrecognized option: $opt" }
}
}
set f [open crash.tcl w]
puts $f "sqlite3_crash_on_write $nDelay"
puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
puts $f "sqlite3 db test.db -vfs writecrash"
puts $f "db eval {$zSql}"
puts $f "set {} {}"
close $f
set r [catch {
exec [info nameofexec] crash.tcl >@stdout
} msg]
# Windows/ActiveState TCL returns a slightly different
# error message. We map that to the expected message
# so that we don't have to change all of the test
# cases.
if {$::tcl_platform(platform)=="windows"} {
if {$msg=="child killed: unknown signal"} {
set msg "child process exited abnormally"
}
}
lappend r $msg
}
proc run_ioerr_prep {} {
set ::sqlite_io_error_pending 0
catch {db close}
+62
View File
@@ -0,0 +1,62 @@
# 2009 January 8
#
# 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.
#
#***********************************************************************
#
# Test the outcome of a writer crashing within a call to the VFS
# xWrite function.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix writecrash
do_not_use_codec
do_execsql_test 1.0 {
CREATE TABLE t1(a INTEGER PRIMARY KEY, b BLOB UNIQUE);
WITH s(i) AS (
VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100
)
INSERT INTO t1 SELECT NULL, randomblob(900) FROM s;
} {}
set bGo 1
for {set tn 1} {$bGo} {incr tn} {
db close
sqlite3 db test.db
do_test 1.$tn.1 {
set res [crash_on_write $tn {
UPDATE t1 SET b = randomblob(899) WHERE (a%3)==0
}]
set bGo 0
if {[string match {1 {child killed:*}} $res]} {
set res {0 {}}
set bGo 1
}
set res
} {0 {}}
#db close
#sqlite3 db test.db
do_execsql_test 1.$tn.2 { PRAGMA integrity_check } {ok}
db close
sqlite3 db test.db
do_execsql_test 1.$tn.3 { PRAGMA integrity_check } {ok}
}
finish_test