1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Merge the POWERSAFE_OVERWRITE features and the use of statvfs() from the

statvfs branch into trunk.

FossilOrigin-Name: 2370d70eb51d2259aaa8073d861ab79d6637cbd9
This commit is contained in:
drh
2011-12-23 02:07:10 +00:00
23 changed files with 568 additions and 254 deletions

View File

@@ -1,5 +1,5 @@
C Add\sinterfaces\ssqlite3_uri_boolean()\sand\ssqlite3_uri_int64()\swhich\sare\nwrappers\saround\ssqlite3_uri_parameter()\scombined\swith\sinternal\sroutines\sfor\nconverting\sstrings\sto\sbooleans\sand\s64-bit\sintegers. C Merge\sthe\sPOWERSAFE_OVERWRITE\sfeatures\sand\sthe\suse\sof\sstatvfs()\sfrom\sthe\nstatvfs\sbranch\sinto\strunk.
D 2011-12-23T00:07:33.075 D 2011-12-23T02:07:10.640
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07 F Makefile.in 5b4a3e12a850b021547e43daf886b25133b44c07
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -166,9 +166,9 @@ F src/os.c 28bbdab2170dfce84d86c45456a18eab1d0f99a9
F src/os.h 549b1a2e5e0ed1e1499f252dac126c4973e7379c F src/os.h 549b1a2e5e0ed1e1499f252dac126c4973e7379c
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440 F src/os_os2.c 4a75888ba3dfc820ad5e8177025972d74d7f2440
F src/os_unix.c ee4ea557de196798bafba1ac69f76a755035ebbb F src/os_unix.c 3a441671f35569df4b72641e928fdb1ab5cd8576
F src/os_win.c 197d23ce8a0dff748e766e034bf95ff756dd3884 F src/os_win.c 569fe7448e781bfb8116aa79081df0eadf576fc6
F src/pager.c 523c64f6ca707e820d5cf10ed8371238ecac8333 F src/pager.c d03fb1de7bd724f0cdcae0aab0a733d89c94ac2f
F src/pager.h 5cd760857707529b403837d813d86b68938d6183 F src/pager.h 5cd760857707529b403837d813d86b68938d6183
F src/parse.y fabb2e7047417d840e6fdb3ef0988a86849a08ba F src/parse.y fabb2e7047417d840e6fdb3ef0988a86849a08ba
F src/pcache.c 1fdd77978c1525d1ca4b9ef48eb80abca710cb4c F src/pcache.c 1fdd77978c1525d1ca4b9ef48eb80abca710cb4c
@@ -182,19 +182,19 @@ F src/resolve.c 3d3e80a98f203ac6b9329e9621e29eda85ddfd40
F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697 F src/rowset.c 69afa95a97c524ba6faf3805e717b5b7ae85a697
F src/select.c a1d075db66a0ea42807353501b62997969e5be79 F src/select.c a1d075db66a0ea42807353501b62997969e5be79
F src/shell.c aa4183d4a5243d8110b1d3d77faa4aea7e9c9c2d F src/shell.c aa4183d4a5243d8110b1d3d77faa4aea7e9c9c2d
F src/sqlite.h.in db834f87316a1422051a97cba5beac31c0cb1b2d F src/sqlite.h.in 3d1a77e27b9d9979fb7ec84834a8423602d29dc5
F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477 F src/sqlite3ext.h 6904f4aadf976f95241311fbffb00823075d9477
F src/sqliteInt.h 165409fa8adc8701148830804febeded3f2e4448 F src/sqliteInt.h b8fdd9c39c8d7f5c794f4ea917293d9c75b9aff2
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a F src/status.c 4568e72dfd36b6a5911f93457364deb072e0b03a
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c de581e2e71f5e7f98366156afad83b4742ac6fe0 F src/tclsqlite.c bd86070f52ae3f77a2e6b3b065ff03adb9140bfa
F src/test1.c 33b9c49f728cf28937eea7b246c28e89e3cf5e9e F src/test1.c 1b1e514e85ffe7152b02cba38bd0a1ce8cd56113
F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432 F src/test3.c 124ff9735fb6bb7d41de180d6bac90e7b1509432
F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7 F src/test4.c d1e5a5e904d4b444cf572391fdcb017638e36ff7
F src/test5.c e1a19845625144caf038031234a12185e40d315c F src/test5.c e1a19845625144caf038031234a12185e40d315c
F src/test6.c 3191b4ab964a144230ff9ef96c093520375c7b2a F src/test6.c cf6ab27a59e1ab64b011bb251ba600131e803e59
F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843 F src/test7.c 2e0781754905c8adc3268d8f0967e7633af58843
F src/test8.c 99f70341d6ec480313775127f4cd14b4a47db557 F src/test8.c 99f70341d6ec480313775127f4cd14b4a47db557
F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60 F src/test9.c bea1e8cf52aa93695487badedd6e1886c321ea60
@@ -230,7 +230,7 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c 35022393dd54d147b998b6b7f7e945b01114d666 F src/test_thread.c 35022393dd54d147b998b6b7f7e945b01114d666
F src/test_vfs.c 27b7d9de40630f603b9e2cf9ef2a7c81d31c4515 F src/test_vfs.c 07157a0bbfe161cb5e32cad2079abd26cd611c4b
F src/test_vfstrace.c 065c7270a614254b2c68fbc7ba8d1fb1d5cbc823 F src/test_vfstrace.c 065c7270a614254b2c68fbc7ba8d1fb1d5cbc823
F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290 F src/test_wholenumber.c 6129adfbe7c7444f2e60cc785927f3aa74e12290
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
@@ -250,7 +250,7 @@ F src/vdbemem.c 2fc78b3e0fabcc1eaa23cd79dd2e30e6dcfe1e56
F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790 F src/vdbesort.c 468d43c057063e54da4f1988b38b4f46d60e7790
F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843 F src/vdbetrace.c d6e50e04e1ec498150e519058f617d91b8f5c843
F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a F src/vtab.c e9318d88feac85be8e27ee783ac8f5397933fc8a
F src/wal.c 5525f049dffd47ee860bf4ffbb8da4ebef78637d F src/wal.c 66e2afeec77933f80c8098cfb3c0b29bc875de0f
F src/wal.h 42f8313f7aaf8913e2d1fdf7b47025c23491ea1d F src/wal.h 42f8313f7aaf8913e2d1fdf7b47025c23491ea1d
F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f
F src/where.c af623942514571895818b9b7ae11db95ae3b3d88 F src/where.c af623942514571895818b9b7ae11db95ae3b3d88
@@ -515,7 +515,7 @@ F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7
F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597 F test/incrblob_err.test d2562d2771ebffd4b3af89ef64c140dd44371597
F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0 F test/incrblobfault.test 917c0292224c64a56ef7215fd633a3a82f805be0
F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32 F test/incrvacuum.test d2a6ddf5e429720b5fe502766af747915ccf6c32
F test/incrvacuum2.test 62fbeb85459fe4e501684d8fb5b6e98a23e3b0c0 F test/incrvacuum2.test 379eeb8740b0ef60c372c439ad4cbea20b34bb9b
F test/incrvacuum_ioerr.test 22f208d01c528403240e05beecc41dc98ed01637 F test/incrvacuum_ioerr.test 22f208d01c528403240e05beecc41dc98ed01637
F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097 F test/index.test b5429732b3b983fa810e3ac867d7ca85dae35097
F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6 F test/index2.test ee83c6b5e3173a3d7137140d945d9a5d4fdfb9d6
@@ -545,7 +545,7 @@ F test/join4.test 1a352e4e267114444c29266ce79e941af5885916
F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe F test/join5.test 86675fc2919269aa923c84dd00ee4249b97990fe
F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901 F test/join6.test bf82cf3f979e9eade83ad0d056a66c5ed71d1901
F test/journal1.test 8b71ef1ed5798bdc0e6eb616d8694e2c2c188d4d F test/journal1.test 8b71ef1ed5798bdc0e6eb616d8694e2c2c188d4d
F test/journal2.test 29937bdbb253bbfd92057610120bdc0aa7e84a0a F test/journal2.test ae06f566c28552c313ded3fee79a6c69e6d049b1
F test/journal3.test 6fd28532c88b447db844186bc190523108b6dbb4 F test/journal3.test 6fd28532c88b447db844186bc190523108b6dbb4
F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36 F test/jrnlmode.test 9ee3a78f53d52cca737db69293d15dc41c0cbd36
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
@@ -620,7 +620,7 @@ F test/notnull.test cc7c78340328e6112a13c3e311a9ab3127114347
F test/null.test a8b09b8ed87852742343b33441a9240022108993 F test/null.test a8b09b8ed87852742343b33441a9240022108993
F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394
F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test b936e80553652002fc47d89bfde7018801d8257d F test/pager1.test 9e9f5f1c6d4df4831dbff213b1262ef94bf72118
F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1
F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f
F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442 F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442
@@ -704,9 +704,9 @@ F test/subquery.test b524f57c9574b2c0347045b4510ef795d4686796
F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd F test/subquery2.test edcad5c118f0531c2e21bf16a09bbb105252d4cd
F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4 F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 7b1167925e9d30a5d1f0701d24812fdda42c3a86 F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test 2a922050dbee032f587249b070fb42692f5e1e22 F test/syscall.test 265cda616f56a297406728ee1e74c9b4a93aa6dd
F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2 F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
@@ -872,7 +872,7 @@ F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84 F test/types2.test 3555aacf8ed8dc883356e59efc314707e6247a84
F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2 F test/unique.test 083c7fff74695bcc27a71d75699deba3595bc9c2
F test/unixexcl.test 892937c53d0c16e76631674e38a0fce052ae5e9c F test/unixexcl.test c82934b3fda907573c7dfccc4f4c9506e5537f36
F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb F test/unordered.test f53095cee37851bf30130fa1bf299a8845e837bb
F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172 F test/update.test 8bc86fd7ef1a00014f76dc6a6a7c974df4aef172
F test/uri.test 0d289d32396bdbc491e9dc845f1a52e13f861e0b F test/uri.test 0d289d32396bdbc491e9dc845f1a52e13f861e0b
@@ -902,11 +902,11 @@ F test/vtabF.test fd5ad376f5a34fe0891df1f3cddb4fe7c3eb077e
F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5 F test/vtab_alter.test 9e374885248f69e251bdaacf480b04a197f125e5
F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8 F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d F test/vtab_shared.test 0eff9ce4f19facbe0a3e693f6c14b80711a4222d
F test/wal.test c743be787e60c1242fa6cdf73b410e64b2977e25 F test/wal.test edefe316b4125d7f68004ea53c5e73c398d436cc
F test/wal2.test 29e2cbe840582fc6efd0487b4f6337caed4b3e80 F test/wal2.test f11883dd3cb7f647c5d2acfd7b5c6d4ba5770cc9
F test/wal3.test 29a6e8843e5f5fd13f33cb0407d2923107020d32 F test/wal3.test 6504bbf348b2d6dfade64a064f1050fd617e8706
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 1bbfaa316dc2a1d0d1fac3f4500c38a90055a41b F test/wal5.test f58ed4b8b542f71c7441da12fbd769d99b362437
F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3 F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe F test/wal_common.tcl a98f17fba96206122eff624db0ab13ec377be4fe
@@ -941,6 +941,7 @@ F test/whereC.test 13ff5ec0dba407c0e0c075980c75b3275a6774e5
F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9 F test/win32lock.test b2a539e85ae6b2d78475e016a9636b4451dc7fb9
F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
F test/zerodamage.test 7ef0680559163118705975be132933898d349674
F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac F tool/build-shell.sh 12aa4391073a777fcb6dcc490b219a018ae98bac
F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b F tool/diffdb.c 7524b1b5df217c20cd0431f6789851a4e0cb191b
F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2 F tool/extract.c 054069d81b095fbdc189a6f5d4466e40380505e2
@@ -985,7 +986,7 @@ F tool/tostr.awk e75472c2f98dd76e06b8c9c1367f4ab07e122d06
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a F tool/warnings-clang.sh 9f406d66e750e8ac031c63a9ef3248aaa347ef2a
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
P 1c27d842163e27c39bbe9409f50657b9de9ade6e P 83d26b9a9115eadac9e59a33d608bca0ab2519e3 6191c5e45175f5c6040e891843b0725a929d6dd7
R 712ad6ea662046687d3fa2e6906d477a R 9e1524ff0804966ed866a28455ef991b
U drh U drh
Z dfef488f9835a38d5955098b906ef223 Z 88029f358469c654bea2978d031e29f2

View File

@@ -1 +1 @@
83d26b9a9115eadac9e59a33d608bca0ab2519e3 2370d70eb51d2259aaa8073d861ab79d6637cbd9

View File

@@ -122,6 +122,10 @@
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
#include <sys/mman.h> #include <sys/mman.h>
#endif #endif
#ifndef MISSING_STATVFS
#include <sys/statvfs.h>
#endif
#if SQLITE_ENABLE_LOCKING_STYLE #if SQLITE_ENABLE_LOCKING_STYLE
# include <sys/ioctl.h> # include <sys/ioctl.h>
@@ -211,6 +215,7 @@ struct unixFile {
int h; /* The file descriptor */ int h; /* The file descriptor */
unsigned char eFileLock; /* The type of lock held on this fd */ unsigned char eFileLock; /* The type of lock held on this fd */
unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */ unsigned char ctrlFlags; /* Behavioral bits. UNIXFILE_* flags */
unsigned char szSector; /* Sectorsize/512 */
int lastErrno; /* The unix errno from last I/O error */ int lastErrno; /* The unix errno from last I/O error */
void *lockingContext; /* Locking style specific state */ void *lockingContext; /* Locking style specific state */
UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */
@@ -258,6 +263,7 @@ struct unixFile {
#else #else
# define UNIXFILE_DIRSYNC 0x00 # define UNIXFILE_DIRSYNC 0x00
#endif #endif
#define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
/* /*
** Include code that is common to all os_*.c files ** Include code that is common to all os_*.c files
@@ -414,6 +420,14 @@ static struct unix_syscall {
{ "rmdir", (sqlite3_syscall_ptr)rmdir, 0 }, { "rmdir", (sqlite3_syscall_ptr)rmdir, 0 },
#define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent) #define osRmdir ((int(*)(const char*))aSyscall[19].pCurrent)
#if defined(MISSING_STATVFS)
{ "statvfs", (sqlite3_syscall_ptr)0, 0 },
#define osStatvfs ((int(*)(const char*,void*))aSyscall[20].pCurrent)
#else
{ "statvfs", (sqlite3_syscall_ptr)statvfs, 0 },
#define osStatvfs ((int(*)(const char*,struct statvfs*))aSyscall[20].pCurrent)
#endif
}; /* End of the overrideable system calls */ }; /* End of the overrideable system calls */
/* /*
@@ -3498,6 +3512,22 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** If *pArg is inititially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
*/
static void unixModeBit(unixFile *pFile, unsigned char mask, int *pArg){
if( *pArg<0 ){
*pArg = (pFile->ctrlFlags & mask)!=0;
}else if( (*pArg)==0 ){
pFile->ctrlFlags &= ~mask;
}else{
pFile->ctrlFlags |= mask;
}
}
/* /*
** Information and control of an open file handle. ** Information and control of an open file handle.
*/ */
@@ -3524,14 +3554,11 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
return rc; return rc;
} }
case SQLITE_FCNTL_PERSIST_WAL: { case SQLITE_FCNTL_PERSIST_WAL: {
int bPersist = *(int*)pArg; unixModeBit(pFile, UNIXFILE_PERSIST_WAL, (int*)pArg);
if( bPersist<0 ){ return SQLITE_OK;
*(int*)pArg = (pFile->ctrlFlags & UNIXFILE_PERSIST_WAL)!=0; }
}else if( bPersist==0 ){ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
pFile->ctrlFlags &= ~UNIXFILE_PERSIST_WAL; unixModeBit(pFile, UNIXFILE_PSOW, (int*)pArg);
}else{
pFile->ctrlFlags |= UNIXFILE_PERSIST_WAL;
}
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_VFSNAME: { case SQLITE_FCNTL_VFSNAME: {
@@ -3572,17 +3599,46 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
** a database and its journal file) that the sector size will be the ** a database and its journal file) that the sector size will be the
** same for both. ** same for both.
*/ */
static int unixSectorSize(sqlite3_file *NotUsed){ static int unixSectorSize(sqlite3_file *pFile){
UNUSED_PARAMETER(NotUsed); unixFile *p = (unixFile*)pFile;
return SQLITE_DEFAULT_SECTOR_SIZE; if( p->szSector==0 ){
#ifdef MISSING_STATVFS
p->szSector = SQLITE_DEFAULT_SECTOR_SIZE/512;
#else
struct statvfs x;
int sz;
memset(&x, 0, sizeof(x));
osStatvfs(p->zPath, &x);
sz = (int)x.f_frsize;
if( sz<512 || sz>65536 || (sz&(sz-1))!=0 ){
sz = SQLITE_DEFAULT_SECTOR_SIZE;
}
p->szSector = sz/512;
#endif
}
return p->szSector*512;
} }
/* /*
** Return the device characteristics for the file. This is always 0 for unix. ** Return the device characteristics for the file.
**
** This VFS is set up to return SQLITE_IOCAP_POWERSAFE_OVERWRITE by default.
** However, that choice is contraversial since technically the underlying
** file system does not always provide powersafe overwrites. (In other
** words, after a power-loss event, parts of the file that were never
** written might end up being altered.) However, non-PSOW behavior is very,
** very rare. And asserting PSOW makes a large reduction in the amount
** of required I/O for journaling, since a lot of padding is eliminated.
** Hence, while POWERSAFE_OVERWRITE is on by default, there is a file-control
** available to turn it off and URI query parameter available to turn it off.
*/ */
static int unixDeviceCharacteristics(sqlite3_file *NotUsed){ static int unixDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(NotUsed); unixFile *p = (unixFile*)id;
return 0; if( p->ctrlFlags & UNIXFILE_PSOW ){
return SQLITE_IOCAP_POWERSAFE_OVERWRITE;
}else{
return 0;
}
} }
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
@@ -4565,10 +4621,12 @@ static int fillInUnixFile(
pNew->h = h; pNew->h = h;
pNew->pVfs = pVfs; pNew->pVfs = pVfs;
pNew->zPath = zFilename; pNew->zPath = zFilename;
pNew->ctrlFlags = 0;
if( sqlite3_uri_boolean(zFilename, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW;
}
if( memcmp(pVfs->zName,"unix-excl",10)==0 ){ if( memcmp(pVfs->zName,"unix-excl",10)==0 ){
pNew->ctrlFlags = UNIXFILE_EXCL; pNew->ctrlFlags |= UNIXFILE_EXCL;
}else{
pNew->ctrlFlags = 0;
} }
if( isReadOnly ){ if( isReadOnly ){
pNew->ctrlFlags |= UNIXFILE_RDONLY; pNew->ctrlFlags |= UNIXFILE_RDONLY;
@@ -6775,7 +6833,7 @@ int sqlite3_os_init(void){
/* Double-check that the aSyscall[] array has been constructed /* Double-check that the aSyscall[] array has been constructed
** correctly. See ticket [bb3a86e890c8e96ab] */ ** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==20 ); assert( ArraySize(aSyscall)==21 );
/* Register all VFSes defined in the aVfs[] array */ /* Register all VFSes defined in the aVfs[] array */
for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){

View File

@@ -59,7 +59,7 @@ struct winFile {
HANDLE h; /* Handle for accessing the file */ HANDLE h; /* Handle for accessing the file */
u8 locktype; /* Type of lock currently held on this file */ u8 locktype; /* Type of lock currently held on this file */
short sharedLockByte; /* Randomly chosen byte used as a shared lock */ short sharedLockByte; /* Randomly chosen byte used as a shared lock */
u8 bPersistWal; /* True to persist WAL files */ u8 ctrlFlags; /* Flags. See WINFILE_* below */
DWORD lastErrno; /* The Windows errno from the last I/O error */ DWORD lastErrno; /* The Windows errno from the last I/O error */
DWORD sectorSize; /* Sector size of the device file is on */ DWORD sectorSize; /* Sector size of the device file is on */
winShm *pShm; /* Instance of shared memory on this file */ winShm *pShm; /* Instance of shared memory on this file */
@@ -74,6 +74,12 @@ struct winFile {
#endif #endif
}; };
/*
** Allowed values for winFile.ctrlFlags
*/
#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
/* /*
* If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the * If compiled with SQLITE_WIN32_MALLOC on Windows, we will use the
* various Win32 API heap functions instead of our own. * various Win32 API heap functions instead of our own.
@@ -2125,6 +2131,22 @@ static int winUnlock(sqlite3_file *id, int locktype){
return rc; return rc;
} }
/*
** If *pArg is inititially negative then this is a query. Set *pArg to
** 1 or 0 depending on whether or not bit mask of pFile->ctrlFlags is set.
**
** If *pArg is 0 or 1, then clear or set the mask bit of pFile->ctrlFlags.
*/
static void winModeBit(winFile *pFile, unsigned char mask, int *pArg){
if( *pArg<0 ){
*pArg = (pFile->ctrlFlags & mask)!=0;
}else if( (*pArg)==0 ){
pFile->ctrlFlags &= ~mask;
}else{
pFile->ctrlFlags |= mask;
}
}
/* /*
** Control and query of the open file handle. ** Control and query of the open file handle.
*/ */
@@ -2160,12 +2182,11 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_PERSIST_WAL: { case SQLITE_FCNTL_PERSIST_WAL: {
int bPersist = *(int*)pArg; winModeBit(pFile, WINFILE_PERSIST_WAL, (int*)pArg);
if( bPersist<0 ){ return SQLITE_OK;
*(int*)pArg = pFile->bPersistWal; }
}else{ case SQLITE_FCNTL_POWERSAFE_OVERWRITE: {
pFile->bPersistWal = bPersist!=0; winModeBit(pFile, WINFILE_PSOW, (int*)pArg);
}
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_VFSNAME: { case SQLITE_FCNTL_VFSNAME: {
@@ -2212,8 +2233,9 @@ static int winSectorSize(sqlite3_file *id){
** Return a vector of device characteristics. ** Return a vector of device characteristics.
*/ */
static int winDeviceCharacteristics(sqlite3_file *id){ static int winDeviceCharacteristics(sqlite3_file *id){
UNUSED_PARAMETER(id); winFile *p = (winFile*)id;
return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN; return SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN |
((p->ctrlFlags & WINFILE_PSOW)?SQLITE_IOCAP_POWERSAFE_OVERWRITE:0);
} }
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
@@ -3178,6 +3200,9 @@ static int winOpen(
pFile->pVfs = pVfs; pFile->pVfs = pVfs;
pFile->pShm = 0; pFile->pShm = 0;
pFile->zPath = zName; pFile->zPath = zName;
if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
pFile->ctrlFlags |= WINFILE_PSOW;
}
pFile->sectorSize = getSectorSize(pVfs, zUtf8Name); pFile->sectorSize = getSectorSize(pVfs, zUtf8Name);
#if SQLITE_OS_WINCE #if SQLITE_OS_WINCE

View File

@@ -2515,23 +2515,36 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
** the value returned by the xSectorSize() method rounded up to 32 if ** the value returned by the xSectorSize() method rounded up to 32 if
** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it ** it is less than 32, or rounded down to MAX_SECTOR_SIZE if it
** is greater than MAX_SECTOR_SIZE. ** is greater than MAX_SECTOR_SIZE.
**
** If the file has the SQLITE_IOCAP_POWERSAFE_OVERWRITE property, then set
** the effective sector size to its minimum value (512). The purpose of
** pPager->sectorSize is to define the "blast radius" of bytes that
** might change if a crash occurs while writing to a single byte in
** that range. But with POWERSAFE_OVERWRITE, the blast radius is zero
** (that is what POWERSAFE_OVERWRITE means), so we minimize the sector
** size. For backwards compatibility of the rollback journal file format,
** we cannot reduce the effective sector size below 512.
*/ */
static void setSectorSize(Pager *pPager){ static void setSectorSize(Pager *pPager){
assert( isOpen(pPager->fd) || pPager->tempFile ); assert( isOpen(pPager->fd) || pPager->tempFile );
if( !pPager->tempFile ){ if( pPager->tempFile
|| (sqlite3OsDeviceCharacteristics(pPager->fd) &
SQLITE_IOCAP_POWERSAFE_OVERWRITE)!=0
){
/* Sector size doesn't matter for temporary files. Also, the file /* Sector size doesn't matter for temporary files. Also, the file
** may not have been opened yet, in which case the OsSectorSize() ** may not have been opened yet, in which case the OsSectorSize()
** call will segfault. ** call will segfault. */
*/
pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
}
if( pPager->sectorSize<32 ){
pPager->sectorSize = 512; pPager->sectorSize = 512;
} }else{
if( pPager->sectorSize>MAX_SECTOR_SIZE ){ pPager->sectorSize = sqlite3OsSectorSize(pPager->fd);
assert( MAX_SECTOR_SIZE>=512 ); if( pPager->sectorSize<32 ){
pPager->sectorSize = MAX_SECTOR_SIZE; pPager->sectorSize = 512;
}
if( pPager->sectorSize>MAX_SECTOR_SIZE ){
assert( MAX_SECTOR_SIZE>=512 );
pPager->sectorSize = MAX_SECTOR_SIZE;
}
} }
} }

View File

@@ -504,7 +504,14 @@ int sqlite3_exec(
** first then the size of the file is extended, never the other ** first then the size of the file is extended, never the other
** way around. The SQLITE_IOCAP_SEQUENTIAL property means that ** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
** information is written to disk in the same order as calls ** information is written to disk in the same order as calls
** to xWrite(). ** to xWrite(). The SQLITE_IOCAP_POWERSAFE_OVERWRITE property means that
** after reboot following a crash or power loss, the value of
** each byte in a file is a value that was actually written
** into that byte at some point. In other words, a crash will
** not cause unwritten bytes of the file to change nor introduce
** randomness into a file nor zero out parts of the file, and any byte of
** a file that are never written will not change values due to
** writes to nearby bytes.
*/ */
#define SQLITE_IOCAP_ATOMIC 0x00000001 #define SQLITE_IOCAP_ATOMIC 0x00000001
#define SQLITE_IOCAP_ATOMIC512 0x00000002 #define SQLITE_IOCAP_ATOMIC512 0x00000002
@@ -518,6 +525,7 @@ int sqlite3_exec(
#define SQLITE_IOCAP_SAFE_APPEND 0x00000200 #define SQLITE_IOCAP_SAFE_APPEND 0x00000200
#define SQLITE_IOCAP_SEQUENTIAL 0x00000400 #define SQLITE_IOCAP_SEQUENTIAL 0x00000400
#define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800 #define SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN 0x00000800
#define SQLITE_IOCAP_POWERSAFE_OVERWRITE 0x00001000
/* /*
** CAPI3REF: File Locking Levels ** CAPI3REF: File Locking Levels
@@ -767,6 +775,15 @@ struct sqlite3_io_methods {
** WAL mode. If the integer is -1, then it is overwritten with the current ** WAL mode. If the integer is -1, then it is overwritten with the current
** WAL persistence setting. ** WAL persistence setting.
** **
** ^The [SQLITE_FCNTL_POWERSAFE_OVERWRITE] opcode is used to set or query the
** persistent "powersafe-overwrite" or "PSOW" setting. The PSOW setting
** determines the [SQLITE_IOCAP_POWERSAFE_OVERWRITE] bit of the
** xDeviceCharacteristics methods. The fourth parameter to
** [sqlite3_file_control()] for this opcode should be a pointer to an integer.
** That integer is 0 to disable zero-damage mode or 1 to enable zero-damage
** mode. If the integer is -1, then it is overwritten with the current
** zero-damage mode setting.
**
** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening ** ^The [SQLITE_FCNTL_OVERWRITE] opcode is invoked by SQLite after opening
** a write transaction to indicate that, unless it is rolled back for some ** a write transaction to indicate that, unless it is rolled back for some
** reason, the entire database file will be overwritten by the current ** reason, the entire database file will be overwritten by the current
@@ -783,18 +800,19 @@ struct sqlite3_io_methods {
** pointer in case this file-control is not implemented. This file-control ** pointer in case this file-control is not implemented. This file-control
** is intended for diagnostic use only. ** is intended for diagnostic use only.
*/ */
#define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_LOCKSTATE 1
#define SQLITE_GET_LOCKPROXYFILE 2 #define SQLITE_GET_LOCKPROXYFILE 2
#define SQLITE_SET_LOCKPROXYFILE 3 #define SQLITE_SET_LOCKPROXYFILE 3
#define SQLITE_LAST_ERRNO 4 #define SQLITE_LAST_ERRNO 4
#define SQLITE_FCNTL_SIZE_HINT 5 #define SQLITE_FCNTL_SIZE_HINT 5
#define SQLITE_FCNTL_CHUNK_SIZE 6 #define SQLITE_FCNTL_CHUNK_SIZE 6
#define SQLITE_FCNTL_FILE_POINTER 7 #define SQLITE_FCNTL_FILE_POINTER 7
#define SQLITE_FCNTL_SYNC_OMITTED 8 #define SQLITE_FCNTL_SYNC_OMITTED 8
#define SQLITE_FCNTL_WIN32_AV_RETRY 9 #define SQLITE_FCNTL_WIN32_AV_RETRY 9
#define SQLITE_FCNTL_PERSIST_WAL 10 #define SQLITE_FCNTL_PERSIST_WAL 10
#define SQLITE_FCNTL_OVERWRITE 11 #define SQLITE_FCNTL_OVERWRITE 11
#define SQLITE_FCNTL_VFSNAME 12 #define SQLITE_FCNTL_VFSNAME 12
#define SQLITE_FCNTL_POWERSAFE_OVERWRITE 13
/* /*
** CAPI3REF: Mutex Handle ** CAPI3REF: Mutex Handle

View File

@@ -125,6 +125,14 @@
#endif #endif
#endif #endif
/*
** Powersafe overwrite is on by default. But can be turned off using
** the -DSQLITE_POWERSAFE_OVERWRITE=0 command-line option.
*/
#ifndef SQLITE_POWERSAFE_OVERWRITE
# define SQLITE_POWERSAFE_OVERWRITE 1
#endif
/* /*
** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1. ** The SQLITE_DEFAULT_MEMSTATUS macro must be defined as either 0 or 1.
** It determines whether or not the features related to ** It determines whether or not the features related to

View File

@@ -3001,6 +3001,14 @@ static int DbMain(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
}else{ }else{
flags &= ~SQLITE_OPEN_FULLMUTEX; flags &= ~SQLITE_OPEN_FULLMUTEX;
} }
}else if( strcmp(zArg, "-uri")==0 ){
int b;
if( Tcl_GetBooleanFromObj(interp, objv[i+1], &b) ) return TCL_ERROR;
if( b ){
flags |= SQLITE_OPEN_URI;
}else{
flags &= ~SQLITE_OPEN_URI;
}
}else{ }else{
Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0);
return TCL_ERROR; return TCL_ERROR;

View File

@@ -5235,6 +5235,38 @@ static int file_control_persist_wal(
return TCL_OK; return TCL_OK;
} }
/*
** tclcmd: file_control_powersafe_overwrite DB PSOW-FLAG
**
** This TCL command runs the sqlite3_file_control interface with
** the SQLITE_FCNTL_POWERSAFE_OVERWRITE opcode.
*/
static int file_control_powersafe_overwrite(
ClientData clientData, /* Pointer to sqlite3_enable_XXX function */
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
int objc, /* Number of arguments */
Tcl_Obj *CONST objv[] /* Command arguments */
){
sqlite3 *db;
int rc;
int b;
char z[100];
if( objc!=3 ){
Tcl_AppendResult(interp, "wrong # args: should be \"",
Tcl_GetStringFromObj(objv[0], 0), " DB FLAG", 0);
return TCL_ERROR;
}
if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ){
return TCL_ERROR;
}
if( Tcl_GetIntFromObj(interp, objv[2], &b) ) return TCL_ERROR;
rc = sqlite3_file_control(db,NULL,SQLITE_FCNTL_POWERSAFE_OVERWRITE,(void*)&b);
sqlite3_snprintf(sizeof(z), z, "%d %d", rc, b);
Tcl_AppendResult(interp, z, (char*)0);
return TCL_OK;
}
/* /*
** tclcmd: file_control_vfsname DB ?AUXDB? ** tclcmd: file_control_vfsname DB ?AUXDB?
@@ -6093,6 +6125,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "file_control_sizehint_test", file_control_sizehint_test, 0 }, { "file_control_sizehint_test", file_control_sizehint_test, 0 },
{ "file_control_win32_av_retry", file_control_win32_av_retry, 0 }, { "file_control_win32_av_retry", file_control_win32_av_retry, 0 },
{ "file_control_persist_wal", file_control_persist_wal, 0 }, { "file_control_persist_wal", file_control_persist_wal, 0 },
{ "file_control_powersafe_overwrite",file_control_powersafe_overwrite,0},
{ "file_control_vfsname", file_control_vfsname, 0 }, { "file_control_vfsname", file_control_vfsname, 0 },
{ "sqlite3_vfs_list", vfs_list, 0 }, { "sqlite3_vfs_list", vfs_list, 0 },
{ "sqlite3_create_function_v2", test_create_function_v2, 0 }, { "sqlite3_create_function_v2", test_create_function_v2, 0 },

View File

@@ -705,17 +705,18 @@ static int processDevSymArgs(
char *zName; char *zName;
int iValue; int iValue;
} aFlag[] = { } aFlag[] = {
{ "atomic", SQLITE_IOCAP_ATOMIC }, { "atomic", SQLITE_IOCAP_ATOMIC },
{ "atomic512", SQLITE_IOCAP_ATOMIC512 }, { "atomic512", SQLITE_IOCAP_ATOMIC512 },
{ "atomic1k", SQLITE_IOCAP_ATOMIC1K }, { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
{ "atomic2k", SQLITE_IOCAP_ATOMIC2K }, { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
{ "atomic4k", SQLITE_IOCAP_ATOMIC4K }, { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
{ "atomic8k", SQLITE_IOCAP_ATOMIC8K }, { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
{ "atomic16k", SQLITE_IOCAP_ATOMIC16K }, { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
{ "atomic32k", SQLITE_IOCAP_ATOMIC32K }, { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
{ "atomic64k", SQLITE_IOCAP_ATOMIC64K }, { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
{ "sequential", SQLITE_IOCAP_SEQUENTIAL }, { "sequential", SQLITE_IOCAP_SEQUENTIAL },
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND }, { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
{ 0, 0 } { 0, 0 }
}; };

View File

@@ -1162,18 +1162,19 @@ static int testvfs_obj_cmd(
int iValue; int iValue;
} aFlag[] = { } aFlag[] = {
{ "default", -1 }, { "default", -1 },
{ "atomic", SQLITE_IOCAP_ATOMIC }, { "atomic", SQLITE_IOCAP_ATOMIC },
{ "atomic512", SQLITE_IOCAP_ATOMIC512 }, { "atomic512", SQLITE_IOCAP_ATOMIC512 },
{ "atomic1k", SQLITE_IOCAP_ATOMIC1K }, { "atomic1k", SQLITE_IOCAP_ATOMIC1K },
{ "atomic2k", SQLITE_IOCAP_ATOMIC2K }, { "atomic2k", SQLITE_IOCAP_ATOMIC2K },
{ "atomic4k", SQLITE_IOCAP_ATOMIC4K }, { "atomic4k", SQLITE_IOCAP_ATOMIC4K },
{ "atomic8k", SQLITE_IOCAP_ATOMIC8K }, { "atomic8k", SQLITE_IOCAP_ATOMIC8K },
{ "atomic16k", SQLITE_IOCAP_ATOMIC16K }, { "atomic16k", SQLITE_IOCAP_ATOMIC16K },
{ "atomic32k", SQLITE_IOCAP_ATOMIC32K }, { "atomic32k", SQLITE_IOCAP_ATOMIC32K },
{ "atomic64k", SQLITE_IOCAP_ATOMIC64K }, { "atomic64k", SQLITE_IOCAP_ATOMIC64K },
{ "sequential", SQLITE_IOCAP_SEQUENTIAL }, { "sequential", SQLITE_IOCAP_SEQUENTIAL },
{ "safe_append", SQLITE_IOCAP_SAFE_APPEND }, { "safe_append", SQLITE_IOCAP_SAFE_APPEND },
{ "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN }, { "undeletable_when_open", SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN },
{ "powersafe_overwrite", SQLITE_IOCAP_POWERSAFE_OVERWRITE },
{ 0, 0 } { 0, 0 }
}; };
Tcl_Obj *pRet; Tcl_Obj *pRet;
@@ -1207,7 +1208,7 @@ static int testvfs_obj_cmd(
iNew |= aFlag[idx].iValue; iNew |= aFlag[idx].iValue;
} }
p->iDevchar = iNew; p->iDevchar = iNew| 0x10000000;
} }
pRet = Tcl_NewObj(); pRet = Tcl_NewObj();

226
src/wal.c
View File

@@ -424,7 +424,8 @@ struct Wal {
u8 ckptLock; /* True if holding a checkpoint lock */ u8 ckptLock; /* True if holding a checkpoint lock */
u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */ u8 readOnly; /* WAL_RDWR, WAL_RDONLY, or WAL_SHM_RDONLY */
u8 truncateOnCommit; /* True to truncate WAL file on commit */ u8 truncateOnCommit; /* True to truncate WAL file on commit */
u8 noSyncHeader; /* Avoid WAL header fsyncs if true */ u8 syncHeader; /* Fsync the WAL header if true */
u8 padToSectorBoundary; /* Pad transactions out to the next sector */
WalIndexHdr hdr; /* Wal-index header for current transaction */ WalIndexHdr hdr; /* Wal-index header for current transaction */
const char *zWalName; /* Name of WAL file */ const char *zWalName; /* Name of WAL file */
u32 nCkpt; /* Checkpoint sequence counter in the wal-header */ u32 nCkpt; /* Checkpoint sequence counter in the wal-header */
@@ -1153,7 +1154,6 @@ static int walIndexRecover(Wal *pWal){
/* Read all frames from the log file. */ /* Read all frames from the log file. */
iFrame = 0; iFrame = 0;
isValid = 1;
for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){ for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
u32 pgno; /* Database page number for frame */ u32 pgno; /* Database page number for frame */
u32 nTruncate; /* dbsize field from frame header */ u32 nTruncate; /* dbsize field from frame header */
@@ -1162,15 +1162,8 @@ static int walIndexRecover(Wal *pWal){
iFrame++; iFrame++;
rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset); rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
if( rc!=SQLITE_OK ) break; if( rc!=SQLITE_OK ) break;
if( sqlite3Get4byte(&aFrame[8]) ==
1+sqlite3Get4byte((u8*)&pWal->hdr.aSalt[0]) ){
pWal->hdr.mxFrame = 0;
pWal->hdr.nPage = 0;
break;
}
if( !isValid ) continue;
isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame); isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
if( !isValid ) continue; if( !isValid ) break;
rc = walIndexAppend(pWal, iFrame, pgno); rc = walIndexAppend(pWal, iFrame, pgno);
if( rc!=SQLITE_OK ) break; if( rc!=SQLITE_OK ) break;
@@ -1294,6 +1287,8 @@ int sqlite3WalOpen(
pRet->readLock = -1; pRet->readLock = -1;
pRet->mxWalSize = mxWalSize; pRet->mxWalSize = mxWalSize;
pRet->zWalName = zWalName; pRet->zWalName = zWalName;
pRet->syncHeader = 1;
pRet->padToSectorBoundary = 1;
pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE);
/* Open file handle on the write-ahead log file. */ /* Open file handle on the write-ahead log file. */
@@ -1309,7 +1304,10 @@ int sqlite3WalOpen(
sqlite3_free(pRet); sqlite3_free(pRet);
}else{ }else{
int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd); int iDC = sqlite3OsDeviceCharacteristics(pRet->pWalFd);
if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->noSyncHeader = 1; } if( iDC & SQLITE_IOCAP_SEQUENTIAL ){ pRet->syncHeader = 0; }
if( iDC & SQLITE_IOCAP_POWERSAFE_OVERWRITE ){
pRet->padToSectorBoundary = 0;
}
*ppWal = pRet; *ppWal = pRet;
WALTRACE(("WAL%d: opened\n", pRet)); WALTRACE(("WAL%d: opened\n", pRet));
} }
@@ -2631,41 +2629,71 @@ static int walRestartLog(Wal *pWal){
return rc; return rc;
} }
/*
** Information about the current state of the WAL file and where
** the next fsync should occur - passed from sqlite3WalFrames() into
** walWriteToLog().
*/
typedef struct WalWriter {
Wal *pWal; /* The complete WAL information */
sqlite3_file *pFd; /* The WAL file to which we write */
sqlite3_int64 iSyncPoint; /* Fsync at this offset */
int syncFlags; /* Flags for the fsync */
int szPage; /* Size of one page */
} WalWriter;
/* /*
** Write iAmt bytes of content into the WAL file beginning at iOffset. ** Write iAmt bytes of content into the WAL file beginning at iOffset.
** Do a sync when crossing the p->iSyncPoint boundary.
** **
** When crossing the boundary between the first and second sectors of the ** In other words, if iSyncPoint is in between iOffset and iOffset+iAmt,
** file, first write all of the first sector content, then fsync(), then ** first write the part before iSyncPoint, then sync, then write the
** continue writing content for the second sector. This ensures that ** rest.
** the WAL header is overwritten before the first commit mark.
*/ */
static int walWriteToLog( static int walWriteToLog(
Wal *pWal, /* WAL to write to */ WalWriter *p, /* WAL to write to */
void *pContent, /* Content to be written */ void *pContent, /* Content to be written */
int iAmt, /* Number of bytes to write */ int iAmt, /* Number of bytes to write */
sqlite3_int64 iOffset /* Start writing at this offset */ sqlite3_int64 iOffset /* Start writing at this offset */
){ ){
int rc; int rc;
if( iOffset>=pWal->szFirstBlock if( iOffset<p->iSyncPoint && iOffset+iAmt>=p->iSyncPoint ){
|| iOffset+iAmt<pWal->szFirstBlock int iFirstAmt = (int)(p->iSyncPoint - iOffset);
|| pWal->syncFlags==0 rc = sqlite3OsWrite(p->pFd, pContent, iFirstAmt, iOffset);
){
/* The common and fast case. Just write the data. */
rc = sqlite3OsWrite(pWal->pWalFd, pContent, iAmt, iOffset);
}else{
/* If this write will cross the first sector boundary, it has to
** be split it two with a sync in between. */
int iFirstAmt = pWal->szFirstBlock - iOffset;
assert( iFirstAmt>0 && iFirstAmt<iAmt );
rc = sqlite3OsWrite(pWal->pWalFd, pContent, iFirstAmt, iOffset);
if( rc ) return rc;
assert( pWal->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
rc = sqlite3OsSync(pWal->pWalFd, pWal->syncFlags);
if( rc ) return rc; if( rc ) return rc;
iOffset += iFirstAmt;
iAmt -= iFirstAmt;
pContent = (void*)(iFirstAmt + (char*)pContent); pContent = (void*)(iFirstAmt + (char*)pContent);
rc = sqlite3OsWrite(pWal->pWalFd, pContent, assert( p->syncFlags & (SQLITE_SYNC_NORMAL|SQLITE_SYNC_FULL) );
iAmt-iFirstAmt, iOffset+iFirstAmt); rc = sqlite3OsSync(p->pFd, p->syncFlags);
if( iAmt==0 || rc ) return rc;
} }
rc = sqlite3OsWrite(p->pFd, pContent, iAmt, iOffset);
return rc;
}
/*
** Write out a single frame of the WAL
*/
static int walWriteOneFrame(
WalWriter *p, /* Where to write the frame */
PgHdr *pPage, /* The page of the frame to be written */
int nTruncate, /* The commit flag. Usually 0. >0 for commit */
sqlite3_int64 iOffset /* Byte offset at which to write */
){
int rc; /* Result code from subfunctions */
void *pData; /* Data actually written */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
#if defined(SQLITE_HAS_CODEC)
if( (pData = sqlite3PagerCodec(pPage))==0 ) return SQLITE_NOMEM;
#else
pData = pPage->pData;
#endif
walEncodeFrame(p->pWal, pPage->pgno, nTruncate, pData, aFrame);
rc = walWriteToLog(p, aFrame, sizeof(aFrame), iOffset);
if( rc ) return rc;
/* Write the page data */
rc = walWriteToLog(p, pData, p->szPage, iOffset+sizeof(aFrame));
return rc; return rc;
} }
@@ -2683,10 +2711,12 @@ int sqlite3WalFrames(
){ ){
int rc; /* Used to catch return codes */ int rc; /* Used to catch return codes */
u32 iFrame; /* Next frame address */ u32 iFrame; /* Next frame address */
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-header in */
PgHdr *p; /* Iterator to run through pList with. */ PgHdr *p; /* Iterator to run through pList with. */
PgHdr *pLast = 0; /* Last frame in list */ PgHdr *pLast = 0; /* Last frame in list */
int nLast = 0; /* Number of extra copies of last page */ int nExtra = 0; /* Number of extra copies of last page */
int szFrame; /* The size of a single frame */
i64 iOffset; /* Next byte to write in WAL file */
WalWriter w; /* The writer */
assert( pList ); assert( pList );
assert( pWal->writeLock ); assert( pWal->writeLock );
@@ -2739,86 +2769,78 @@ int sqlite3WalFrames(
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
/* Sync the header (unless SQLITE_IOCAP_SEQUENTIAL is true or unless
** all syncing is turned off by PRAGMA synchronous=OFF). Otherwise
** an out-of-order write following a WAL restart could result in
** database corruption. See the ticket:
**
** http://localhost:591/sqlite/info/ff5be73dee
*/
if( pWal->syncHeader && sync_flags ){
rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
if( rc ) return rc;
}
} }
assert( (int)pWal->szPage==szPage ); assert( (int)pWal->szPage==szPage );
/* Setup information needed to do the WAL header sync */ /* Setup information needed to write frames into the WAL */
if( pWal->noSyncHeader ){ w.pWal = pWal;
assert( pWal->szFirstBlock==0 ); w.pFd = pWal->pWalFd;
assert( pWal->syncFlags==0 ); w.iSyncPoint = 0;
}else{ w.syncFlags = sync_flags;
pWal->szFirstBlock = sqlite3OsSectorSize(pWal->pWalFd); w.szPage = szPage;
if( szPage>pWal->szFirstBlock ) pWal->szFirstBlock = szPage; iOffset = walFrameOffset(iFrame+1, szPage);
pWal->syncFlags = sync_flags & SQLITE_SYNC_MASK; szFrame = szPage + WAL_FRAME_HDRSIZE;
}
/* Write the log file. */ /* Write all frames into the log file exactly once */
for(p=pList; p; p=p->pDirty){ for(p=pList; p; p=p->pDirty){
u32 nDbsize; /* Db-size field for frame header */ int nDbSize; /* 0 normally. Positive == commit flag */
i64 iOffset; /* Write offset in log file */ iFrame++;
void *pData; assert( iOffset==walFrameOffset(iFrame, szPage) );
nDbSize = (isCommit && p->pDirty==0) ? nTruncate : 0;
iOffset = walFrameOffset(++iFrame, szPage); rc = walWriteOneFrame(&w, p, nDbSize, iOffset);
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */ if( rc ) return rc;
/* Populate and write the frame header */
nDbsize = (isCommit && p->pDirty==0) ? nTruncate : 0;
#if defined(SQLITE_HAS_CODEC)
if( (pData = sqlite3PagerCodec(p))==0 ) return SQLITE_NOMEM;
#else
pData = p->pData;
#endif
walEncodeFrame(pWal, p->pgno, nDbsize, pData, aFrame);
rc = walWriteToLog(pWal, aFrame, sizeof(aFrame), iOffset);
if( rc!=SQLITE_OK ){
return rc;
}
/* Write the page data */
rc = walWriteToLog(pWal, pData, szPage, iOffset+sizeof(aFrame));
if( rc!=SQLITE_OK ){
return rc;
}
pLast = p; pLast = p;
iOffset += szFrame;
} }
/* Sync the log file if the 'isSync' flag was specified. */ /* If this is the end of a transaction, then we might need to pad
** the transaction and/or sync the WAL file.
**
** Padding and syncing only occur if this set of frames complete a
** transaction and if PRAGMA synchronous=FULL. If synchronous==NORMAL
** or synchonous==OFF, then no padding or syncing are needed.
**
** If SQLITE_IOCAP_POWERSAFE_OVERWRITE is defined, then padding is not
** needed and only the sync is done. If padding is needed, then the
** final frame is repeated (with its commit mark) until the next sector
** boundary is crossed. Only the part of the WAL prior to the last
** sector boundary is synced; the part of the last frame that extends
** past the sector boundary is written after the sync.
*/
if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){ if( isCommit && (sync_flags & WAL_SYNC_TRANSACTIONS)!=0 ){
i64 iSegment = sqlite3OsSectorSize(pWal->pWalFd); if( pWal->padToSectorBoundary ){
i64 iOffset = walFrameOffset(iFrame+1, szPage); int sectorSize = sqlite3OsSectorSize(pWal->pWalFd);
w.iSyncPoint = ((iOffset+sectorSize-1)/sectorSize)*sectorSize;
assert( iSegment>0 ); while( iOffset<w.iSyncPoint ){
rc = walWriteOneFrame(&w, pLast, nTruncate, iOffset);
iSegment = (((iOffset+iSegment-1)/iSegment) * iSegment); if( rc ) return rc;
while( iOffset<iSegment ){ iOffset += szFrame;
void *pData; nExtra++;
#if defined(SQLITE_HAS_CODEC)
if( (pData = sqlite3PagerCodec(pLast))==0 ) return SQLITE_NOMEM;
#else
pData = pLast->pData;
#endif
walEncodeFrame(pWal, pLast->pgno, nTruncate, pData, aFrame);
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
rc = walWriteToLog(pWal, aFrame, sizeof(aFrame), iOffset);
if( rc!=SQLITE_OK ){
return rc;
} }
iOffset += WAL_FRAME_HDRSIZE;
rc = walWriteToLog(pWal, pData, szPage, iOffset);
if( rc!=SQLITE_OK ){
return rc;
}
nLast++;
iOffset += szPage;
} }
rc = sqlite3OsSync(w.pFd, sync_flags & SQLITE_SYNC_MASK);
rc = sqlite3OsSync(pWal->pWalFd, sync_flags & SQLITE_SYNC_MASK);
} }
/* If this frame set completes the first transaction in the WAL and
** if PRAGMA journal_size_limit is set, then truncate the WAL to the
** journal size limit, if possible.
*/
if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){ if( isCommit && pWal->truncateOnCommit && pWal->mxWalSize>=0 ){
i64 sz = pWal->mxWalSize; i64 sz = pWal->mxWalSize;
if( walFrameOffset(iFrame+nLast+1, szPage)>pWal->mxWalSize ){ if( walFrameOffset(iFrame+nExtra+1, szPage)>pWal->mxWalSize ){
sz = walFrameOffset(iFrame+nLast+1, szPage); sz = walFrameOffset(iFrame+nExtra+1, szPage);
} }
walLimitSize(pWal, sz); walLimitSize(pWal, sz);
pWal->truncateOnCommit = 0; pWal->truncateOnCommit = 0;
@@ -2834,9 +2856,9 @@ int sqlite3WalFrames(
iFrame++; iFrame++;
rc = walIndexAppend(pWal, iFrame, p->pgno); rc = walIndexAppend(pWal, iFrame, p->pgno);
} }
while( nLast>0 && rc==SQLITE_OK ){ while( nExtra>0 && rc==SQLITE_OK ){
iFrame++; iFrame++;
nLast--; nExtra--;
rc = walIndexAppend(pWal, iFrame, pLast->pgno); rc = walIndexAppend(pWal, iFrame, pLast->pgno);
} }

View File

@@ -191,7 +191,7 @@ ifcapable wal {
PRAGMA wal_checkpoint; PRAGMA wal_checkpoint;
} }
file size test.db-wal file size test.db-wal
} {1640} } [expr {32+2*(512+24)}]
do_test 4.3 { do_test 4.3 {
db close db close
@@ -205,7 +205,7 @@ ifcapable wal {
if {$newsz>$maxsz} {set maxsz $newsz} if {$newsz>$maxsz} {set maxsz $newsz}
} }
set maxsz set maxsz
} {2176} } [expr {32+3*(512+24)}]
} }
finish_test finish_test

View File

@@ -34,7 +34,7 @@ proc a_string {n} {
# characteristics flags to "SAFE_DELETE". # characteristics flags to "SAFE_DELETE".
# #
testvfs tvfs -default 1 testvfs tvfs -default 1
tvfs devchar undeletable_when_open tvfs devchar {undeletable_when_open powersafe_overwrite}
# Set up a hook so that each time a journal file is opened, closed or # 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 # deleted, the method name ("xOpen", "xClose" or "xDelete") and the final
@@ -231,4 +231,3 @@ ifcapable wal {
tvfs delete tvfs delete
finish_test finish_test

View File

@@ -1331,6 +1331,7 @@ foreach sectorsize {
4096 8192 16384 32768 65536 131072 262144 4096 8192 16384 32768 65536 131072 262144
} { } {
tv sectorsize $sectorsize tv sectorsize $sectorsize
tv devchar {}
set eff $sectorsize set eff $sectorsize
if {$sectorsize < 512} { set eff 512 } if {$sectorsize < 512} { set eff 512 }
if {$sectorsize > 65536} { set eff 65536 } if {$sectorsize > 65536} { set eff 65536 }

View File

@@ -76,7 +76,10 @@ do_catchsql_test 3.4 { INSERT INTO t1 VALUES(5, 6)} {1 {database is locked}}
do_catchsql_test 3.5 { PRAGMA wal_checkpoint } {0 {1 -1 -1}} do_catchsql_test 3.5 { PRAGMA wal_checkpoint } {0 {1 -1 -1}}
do_test 3.6 { unlock } {} do_test 3.6 { unlock } {}
do_execsql_test 4.1 { PRAGMA wal_checkpoint } {0 2 2} # At this point the WAL file consists of a single frame only - written
# by test case 3.1. If the ZERO_DAMAGE flag were not set, it would consist
# of two frames - the frame written by 3.1 and a padding frame.
do_execsql_test 4.1 { PRAGMA wal_checkpoint } {0 1 1}
do_test 4.2 { sqlite3demo_superlock unlock test.db } {unlock} do_test 4.2 { sqlite3demo_superlock unlock test.db } {unlock}
do_catchsql_test 4.3 { SELECT * FROM t1 } {1 {database is locked}} do_catchsql_test 4.3 { SELECT * FROM t1 } {1 {database is locked}}

View File

@@ -59,7 +59,8 @@ do_test 2.1.2 { test_syscall exists nosuchcall } 0
foreach s { foreach s {
open close access getcwd stat fstat ftruncate open close access getcwd stat fstat ftruncate
fcntl read pread write pwrite fchmod fallocate fcntl read pread write pwrite fchmod fallocate
pread64 pwrite64 unlink openDirectory mkdir rmdir pread64 pwrite64 unlink openDirectory mkdir rmdir
statvfs
} { } {
if {[test_syscall exists $s]} {lappend syscall_list $s} if {[test_syscall exists $s]} {lappend syscall_list $s}
} }

View File

@@ -82,8 +82,8 @@ do_multiclient_test tn {
do_multiclient_test tn { do_multiclient_test tn {
do_test unixexcl-3.$tn.1 { do_test unixexcl-3.$tn.1 {
code1 { db close; sqlite3 db test.db -vfs unix-excl } code1 { db close; sqlite3 db file:test.db?psow=0 -vfs unix-excl -uri 1 }
code2 { db2 close; sqlite3 db2 test.db -vfs unix-excl } code2 { db2 close; sqlite3 db2 file:test.db?psow=0 -vfs unix-excl -uri 1 }
sql1 { sql1 {
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
CREATE TABLE t1(a, b); CREATE TABLE t1(a, b);
@@ -108,7 +108,7 @@ do_multiclient_test tn {
} {1 2} } {1 2}
do_test unixexcl-3.$tn.3 { do_test unixexcl-3.$tn.3 {
sql1 { PRAGMA wal_checkpoint; INSERT INTO t1 VALUES(3, 4); } sql1 { PRAGMA wal_checkpoint; INSERT INTO t1 VALUES(3, 4); }
} {0 5 5} } {0 3 3}
do_test unixexcl-3.$tn.4 { do_test unixexcl-3.$tn.4 {
sql2 { SELECT * FROM t1; } sql2 { SELECT * FROM t1; }
} {1 2} } {1 2}
@@ -120,7 +120,7 @@ do_multiclient_test tn {
} {1 2 3 4} } {1 2 3 4}
do_test unixexcl-3.$tn.7 { do_test unixexcl-3.$tn.7 {
sql1 { PRAGMA wal_checkpoint; } sql1 { PRAGMA wal_checkpoint; }
} {0 7 7} } {0 4 4}
} }
} }

View File

@@ -546,7 +546,7 @@ do_multiclient_test tn {
} {1 2 3 4 5 6 7 8 9 10} } {1 2 3 4 5 6 7 8 9 10}
do_test wal-10.$tn.12 { do_test wal-10.$tn.12 {
catchsql { PRAGMA wal_checkpoint } catchsql { PRAGMA wal_checkpoint }
} {0 {0 13 13}} ;# Reader no longer block checkpoints } {0 {0 7 7}} ;# Reader no longer block checkpoints
do_test wal-10.$tn.13 { do_test wal-10.$tn.13 {
execsql { INSERT INTO t1 VALUES(11, 12) } execsql { INSERT INTO t1 VALUES(11, 12) }
sql2 {SELECT * FROM t1} sql2 {SELECT * FROM t1}
@@ -556,7 +556,7 @@ do_multiclient_test tn {
# #
do_test wal-10.$tn.14 { do_test wal-10.$tn.14 {
catchsql { PRAGMA wal_checkpoint } catchsql { PRAGMA wal_checkpoint }
} {0 {0 15 13}} } {0 {0 8 7}}
# The following series of test cases used to verify another blocking # The following series of test cases used to verify another blocking
# case in WAL - a case which no longer blocks. # case in WAL - a case which no longer blocks.
@@ -566,10 +566,10 @@ do_multiclient_test tn {
} {1 2 3 4 5 6 7 8 9 10 11 12} } {1 2 3 4 5 6 7 8 9 10 11 12}
do_test wal-10.$tn.16 { do_test wal-10.$tn.16 {
catchsql { PRAGMA wal_checkpoint } catchsql { PRAGMA wal_checkpoint }
} {0 {0 15 15}} } {0 {0 8 8}}
do_test wal-10.$tn.17 { do_test wal-10.$tn.17 {
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 15 15} } {0 8 8}
do_test wal-10.$tn.18 { do_test wal-10.$tn.18 {
sql3 { BEGIN; SELECT * FROM t1 } sql3 { BEGIN; SELECT * FROM t1 }
} {1 2 3 4 5 6 7 8 9 10 11 12} } {1 2 3 4 5 6 7 8 9 10 11 12}
@@ -592,13 +592,13 @@ do_multiclient_test tn {
# #
do_test wal-10.$tn.23 { do_test wal-10.$tn.23 {
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 17 17} } {0 9 9}
do_test wal-10.$tn.24 { do_test wal-10.$tn.24 {
sql2 { BEGIN; SELECT * FROM t1; } sql2 { BEGIN; SELECT * FROM t1; }
} {1 2 3 4 5 6 7 8 9 10 11 12 13 14} } {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
do_test wal-10.$tn.25 { do_test wal-10.$tn.25 {
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 17 17} } {0 9 9}
do_test wal-10.$tn.26 { do_test wal-10.$tn.26 {
catchsql { INSERT INTO t1 VALUES(15, 16) } catchsql { INSERT INTO t1 VALUES(15, 16) }
} {0 {}} } {0 {}}
@@ -615,11 +615,11 @@ do_multiclient_test tn {
do_test wal-10.$tn.29 { do_test wal-10.$tn.29 {
execsql { INSERT INTO t1 VALUES(19, 20) } execsql { INSERT INTO t1 VALUES(19, 20) }
catchsql { PRAGMA wal_checkpoint } catchsql { PRAGMA wal_checkpoint }
} {0 {0 6 0}} } {0 {0 3 0}}
do_test wal-10.$tn.30 { do_test wal-10.$tn.30 {
code3 { sqlite3_finalize $::STMT } code3 { sqlite3_finalize $::STMT }
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 6 0} } {0 3 0}
# At one point, if a reader failed to upgrade to a writer because it # At one point, if a reader failed to upgrade to a writer because it
# was reading an old snapshot, the write-locks were not being released. # was reading an old snapshot, the write-locks were not being released.
@@ -658,7 +658,7 @@ do_multiclient_test tn {
} {a b c d} } {a b c d}
do_test wal-10.$tn.36 { do_test wal-10.$tn.36 {
catchsql { PRAGMA wal_checkpoint } catchsql { PRAGMA wal_checkpoint }
} {0 {0 16 16}} } {0 {0 8 8}}
do_test wal-10.$tn.36 { do_test wal-10.$tn.36 {
sql3 { INSERT INTO t1 VALUES('e', 'f') } sql3 { INSERT INTO t1 VALUES('e', 'f') }
sql2 { SELECT * FROM t1 } sql2 { SELECT * FROM t1 }
@@ -666,7 +666,7 @@ do_multiclient_test tn {
do_test wal-10.$tn.37 { do_test wal-10.$tn.37 {
sql2 COMMIT sql2 COMMIT
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 18 18} } {0 9 9}
} }
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@@ -1040,7 +1040,7 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
5 {sqlite3_wal_checkpoint db aux} SQLITE_OK 0 1 5 {sqlite3_wal_checkpoint db aux} SQLITE_OK 0 1
6 {sqlite3_wal_checkpoint db temp} SQLITE_OK 0 0 6 {sqlite3_wal_checkpoint db temp} SQLITE_OK 0 0
7 {db eval "PRAGMA main.wal_checkpoint"} {0 10 10} 1 0 7 {db eval "PRAGMA main.wal_checkpoint"} {0 10 10} 1 0
8 {db eval "PRAGMA aux.wal_checkpoint"} {0 16 16} 0 1 8 {db eval "PRAGMA aux.wal_checkpoint"} {0 13 13} 0 1
9 {db eval "PRAGMA temp.wal_checkpoint"} {0 -1 -1} 0 0 9 {db eval "PRAGMA temp.wal_checkpoint"} {0 -1 -1} 0 0
} { } {
do_test wal-16.$tn.1 { do_test wal-16.$tn.1 {
@@ -1054,7 +1054,8 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
PRAGMA aux.auto_vacuum = 0; PRAGMA aux.auto_vacuum = 0;
PRAGMA main.journal_mode = WAL; PRAGMA main.journal_mode = WAL;
PRAGMA aux.journal_mode = WAL; PRAGMA aux.journal_mode = WAL;
PRAGMA synchronous = NORMAL; PRAGMA main.synchronous = NORMAL;
PRAGMA aux.synchronous = NORMAL;
} }
} {wal wal} } {wal wal}
@@ -1072,7 +1073,7 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
} [list [expr 1*1024] [wal_file_size 10 1024]] } [list [expr 1*1024] [wal_file_size 10 1024]]
do_test wal-16.$tn.3 { do_test wal-16.$tn.3 {
list [file size test2.db] [file size test2.db-wal] list [file size test2.db] [file size test2.db-wal]
} [list [expr 1*1024] [wal_file_size 16 1024]] } [list [expr 1*1024] [wal_file_size 13 1024]]
do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res do_test wal-16.$tn.4 [list eval $ckpt_cmd] $ckpt_res
@@ -1082,7 +1083,7 @@ foreach {tn ckpt_cmd ckpt_res ckpt_main ckpt_aux} {
do_test wal-16.$tn.6 { do_test wal-16.$tn.6 {
list [file size test2.db] [file size test2.db-wal] list [file size test2.db] [file size test2.db-wal]
} [list [expr ($ckpt_aux ? 7 : 1)*1024] [wal_file_size 16 1024]] } [list [expr ($ckpt_aux ? 7 : 1)*1024] [wal_file_size 13 1024]]
catch { db close } catch { db close }
} }
@@ -1552,9 +1553,13 @@ ifcapable autovacuum {
} }
file size test.db file size test.db
} [expr 3 * 1024] } [expr 3 * 1024]
# WAL file now contains a single frame - the new root page for table t1.
# It would be two frames (the new root page and a padding frame) if the
# ZERO_DAMAGE flag were not set.
do_test 24.5 { do_test 24.5 {
file size test.db-wal file size test.db-wal
} 2128 } [wal_file_size 1 1024]
} }
db close db close

View File

@@ -361,7 +361,9 @@ do_test wal2-4.1 {
INSERT INTO data VALUES('need xShmOpen to see this'); INSERT INTO data VALUES('need xShmOpen to see this');
PRAGMA wal_checkpoint; PRAGMA wal_checkpoint;
} }
} {wal 0 5 5} # Three pages in the WAL file at this point: One copy of page 1 and two
# of the root page for table "data".
} {wal 0 3 3}
do_test wal2-4.2 { do_test wal2-4.2 {
db close db close
testvfs tvfs -noshm 1 testvfs tvfs -noshm 1
@@ -730,7 +732,7 @@ do_test wal2-6.5.1 {
INSERT INTO t2 VALUES('I', 'II'); INSERT INTO t2 VALUES('I', 'II');
PRAGMA journal_mode; PRAGMA journal_mode;
} }
} {wal exclusive 0 3 3 wal} } {wal exclusive 0 2 2 wal}
do_test wal2-6.5.2 { do_test wal2-6.5.2 {
execsql { execsql {
PRAGMA locking_mode = normal; PRAGMA locking_mode = normal;
@@ -741,7 +743,7 @@ do_test wal2-6.5.2 {
} {normal exclusive I II III IV} } {normal exclusive I II III IV}
do_test wal2-6.5.3 { do_test wal2-6.5.3 {
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 4 4} } {0 2 2}
db close db close
proc lock_control {method filename handle spec} { proc lock_control {method filename handle spec} {
@@ -1184,6 +1186,7 @@ foreach {tn sql reslist} {
execsql {PRAGMA auto_vacuum = 0} execsql {PRAGMA auto_vacuum = 0}
execsql $sql execsql $sql
do_execsql_test wal2-14.$tn.0 { PRAGMA page_size = 4096 } {}
do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal} do_execsql_test wal2-14.$tn.1 { PRAGMA journal_mode = WAL } {wal}
set sqlite_sync_count 0 set sqlite_sync_count 0
@@ -1199,7 +1202,7 @@ foreach {tn sql reslist} {
INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(5, 6);
COMMIT; -- 2 wal sync COMMIT; -- 2 wal sync
PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync PRAGMA wal_checkpoint; -- 1 wal sync, 1 db sync
} {10 0 5 5 0 2 2} } {10 0 3 3 0 1 1}
do_test wal2-14.$tn.3 { do_test wal2-14.$tn.3 {
cond_incr_sync_count 1 cond_incr_sync_count 1
@@ -1261,6 +1264,7 @@ foreach {tn settings restart_sync commit_sync ckpt_sync} {
sqlite3 db test.db sqlite3 db test.db
do_execsql_test 15.$tn.1 " do_execsql_test 15.$tn.1 "
PRAGMA page_size = 4096;
CREATE TABLE t1(x); CREATE TABLE t1(x);
PRAGMA wal_autocheckpoint = OFF; PRAGMA wal_autocheckpoint = OFF;
PRAGMA journal_mode = WAL; PRAGMA journal_mode = WAL;
@@ -1269,6 +1273,7 @@ foreach {tn settings restart_sync commit_sync ckpt_sync} {
PRAGMA synchronous = [lindex $settings 2]; PRAGMA synchronous = [lindex $settings 2];
" {0 wal} " {0 wal}
if { $tn==2} breakpoint
do_test 15.$tn.2 { do_test 15.$tn.2 {
set sync(normal) 0 set sync(normal) 0
set sync(full) 0 set sync(full) 0

View File

@@ -429,7 +429,7 @@ do_test wal3-6.1.2 {
} {o t t f} } {o t t f}
do_test wal3-6.1.3 { do_test wal3-6.1.3 {
execsql { PRAGMA wal_checkpoint } db2 execsql { PRAGMA wal_checkpoint } db2
} {0 7 7} } {0 4 4}
# At this point the log file has been fully checkpointed. However, # At this point the log file has been fully checkpointed. However,
# connection [db3] holds a lock that prevents the log from being wrapped. # connection [db3] holds a lock that prevents the log from being wrapped.
@@ -518,7 +518,7 @@ proc lock_callback {method file handle spec} {
} }
do_test wal3-6.2.2 { do_test wal3-6.2.2 {
execsql { PRAGMA wal_checkpoint } execsql { PRAGMA wal_checkpoint }
} {0 7 7} } {0 4 4}
do_test wal3-6.2.3 { do_test wal3-6.2.3 {
set ::R set ::R
} {h h l b} } {h h l b}
@@ -628,7 +628,7 @@ do_test wal3-8.1 {
INSERT INTO b VALUES('Markazi'); INSERT INTO b VALUES('Markazi');
PRAGMA wal_checkpoint; PRAGMA wal_checkpoint;
} }
} {wal 0 9 9} } {wal 0 5 5}
do_test wal3-8.2 { do_test wal3-8.2 {
execsql { SELECT * FROM b } execsql { SELECT * FROM b }
} {Tehran Qom Markazi} } {Tehran Qom Markazi}

View File

@@ -197,9 +197,9 @@ foreach {testprefix do_wal_checkpoint} {
INSERT INTO t2 VALUES(1, 2); INSERT INTO t2 VALUES(1, 2);
} }
} {} } {}
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 5} do_test 2.2.$tn.2 { file_page_counts } {1 3 1 3}
do_test 2.1.$tn.3 { code1 { do_wal_checkpoint db } } {0 5 5} do_test 2.1.$tn.3 { code1 { do_wal_checkpoint db } } {0 3 3}
do_test 2.1.$tn.4 { file_page_counts } {2 5 2 5} do_test 2.1.$tn.4 { file_page_counts } {2 3 2 3}
} }
do_multiclient_test tn { do_multiclient_test tn {
@@ -213,10 +213,10 @@ foreach {testprefix do_wal_checkpoint} {
INSERT INTO t2 VALUES(3, 4); INSERT INTO t2 VALUES(3, 4);
} }
} {} } {}
do_test 2.2.$tn.2 { file_page_counts } {1 5 1 7} do_test 2.2.$tn.2 { file_page_counts } {1 3 1 4}
do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2} do_test 2.2.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
do_test 2.2.$tn.4 { code1 { do_wal_checkpoint db -mode restart } } {1 5 5} do_test 2.2.$tn.4 { code1 { do_wal_checkpoint db -mode restart } } {1 3 3}
do_test 2.2.$tn.5 { file_page_counts } {2 5 2 7} do_test 2.2.$tn.5 { file_page_counts } {2 3 2 4}
} }
do_multiclient_test tn { do_multiclient_test tn {
@@ -229,13 +229,13 @@ foreach {testprefix do_wal_checkpoint} {
INSERT INTO t2 VALUES(1, 2); INSERT INTO t2 VALUES(1, 2);
} }
} {} } {}
do_test 2.3.$tn.2 { file_page_counts } {1 5 1 5} do_test 2.3.$tn.2 { file_page_counts } {1 3 1 3}
do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2} do_test 2.3.$tn.3 { sql2 { BEGIN; SELECT * FROM t1 } } {1 2}
do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {} do_test 2.3.$tn.4 { sql1 { INSERT INTO t1 VALUES(3, 4) } } {}
do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {} do_test 2.3.$tn.5 { sql1 { INSERT INTO t2 VALUES(3, 4) } } {}
do_test 2.3.$tn.6 { file_page_counts } {1 7 1 7} do_test 2.3.$tn.6 { file_page_counts } {1 4 1 4}
do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 7 5} do_test 2.3.$tn.7 { code1 { do_wal_checkpoint db -mode full } } {1 4 3}
do_test 2.3.$tn.8 { file_page_counts } {1 7 2 7} do_test 2.3.$tn.8 { file_page_counts } {1 4 2 4}
} }
# Check that checkpoints block on the correct locks. And respond correctly # Check that checkpoints block on the correct locks. And respond correctly
@@ -256,18 +256,18 @@ foreach {testprefix do_wal_checkpoint} {
# processes holding all three types of locks. # processes holding all three types of locks.
# #
foreach {tn1 checkpoint busy_on ckpt_expected expected} { foreach {tn1 checkpoint busy_on ckpt_expected expected} {
1 PASSIVE - {0 5 5} - 1 PASSIVE - {0 3 3} -
2 TYPO - {0 5 5} - 2 TYPO - {0 3 3} -
3 FULL - {0 7 7} 2 3 FULL - {0 4 4} 2
4 FULL 1 {1 5 5} 1 4 FULL 1 {1 3 3} 1
5 FULL 2 {1 7 5} 2 5 FULL 2 {1 4 3} 2
6 FULL 3 {0 7 7} 2 6 FULL 3 {0 4 4} 2
7 RESTART - {0 7 7} 3 7 RESTART - {0 4 4} 3
8 RESTART 1 {1 5 5} 1 8 RESTART 1 {1 3 3} 1
9 RESTART 2 {1 7 5} 2 9 RESTART 2 {1 4 3} 2
10 RESTART 3 {1 7 7} 3 10 RESTART 3 {1 4 4} 3
} { } {
do_multiclient_test tn { do_multiclient_test tn {

112
test/zerodamage.test Normal file
View File

@@ -0,0 +1,112 @@
# 2011 December 21
#
# 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 tests of the SQLITE_IOCAP_POWERSAFE_OVERWRITE property
# and the SQLITE_FCNTL_POWERSAFE_OVERWRITE file-control for manipulating it.
#
# The name of this file comes from the fact that we used to call the
# POWERSAFE_OVERWRITE property ZERO_DAMAGE.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix wal5
# POWERSAFE_OVERWRITE defaults to true
#
do_test zerodamage-1.0 {
file_control_powersafe_overwrite db -1
} {0 1}
# Check the ability to turn zero-damage on and off.
#
do_test zerodamage-1.1 {
file_control_powersafe_overwrite db 0
file_control_powersafe_overwrite db -1
} {0 0}
do_test zerodamage-1.2 {
file_control_powersafe_overwrite db 1
file_control_powersafe_overwrite db -1
} {0 1}
# Run a transaction with zero-damage on, a small page size and a much larger
# sectorsize. Verify that the maximum journal size is small - that the
# rollback journal is not being padded.
#
do_test zerodamage-2.0 {
db close
testvfs tv -default 1
tv sectorsize 8192
sqlite3 db file:test.db?psow=TRUE -uri 1
unset -nocomplain ::max_journal_size
set ::max_journal_size 0
proc xDeleteCallback {method file args} {
set sz [file size $file]
if {$sz>$::max_journal_size} {set ::max_journal_size $sz}
}
tv filter xDelete
tv script xDeleteCallback
register_wholenumber_module db
db eval {
PRAGMA page_size=1024;
PRAGMA journal_mode=DELETE;
PRAGMA cache_size=5;
CREATE VIRTUAL TABLE nums USING wholenumber;
CREATE TABLE t1(x, y);
INSERT INTO t1 SELECT value, randomblob(100) FROM nums
WHERE value BETWEEN 1 AND 400;
}
set ::max_journal_size 0
db eval {
UPDATE t1 SET y=randomblob(50) WHERE x=123;
}
concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} {0 1 2576}
# Repeat the previous step with zero-damage turned off. This time the
# maximum rollback journal size should be much larger.
#
do_test zerodamage-2.1 {
set ::max_journal_size 0
db close
sqlite3 db file:test.db?psow=FALSE -uri 1
db eval {
UPDATE t1 SET y=randomblob(50) WHERE x=124;
}
concat [file_control_powersafe_overwrite db -1] [set ::max_journal_size]
} {0 0 24704}
# Run a WAL-mode transaction with POWERSAFE_OVERWRITE on to verify that the
# WAL file does not get too big.
#
do_test zerodamage-3.0 {
db eval {
PRAGMA journal_mode=WAL;
}
db close
sqlite3 db file:test.db?psow=TRUE -uri 1
db eval {
UPDATE t1 SET y=randomblob(50) WHERE x=124;
}
file size test.db-wal
} {1080}
# Repeat the previous with POWERSAFE_OVERWRITE off. Verify that the WAL file
# is padded.
#
do_test zerodamage-3.1 {
db close
sqlite3 db file:test.db?psow=FALSE -uri 1
db eval {
UPDATE t1 SET y=randomblob(50) WHERE x=124;
}
file size test.db-wal
} {8416}