1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-29 08:01:23 +03:00

Try to use mmap() to speed access to the database file on windows, linux,

and mac.

FossilOrigin-Name: fff2be60779571c8fb89158db976ec3755e9a223
This commit is contained in:
drh
2013-04-04 00:40:17 +00:00
40 changed files with 1693 additions and 171 deletions

View File

@ -1,5 +1,5 @@
C If\sthe\sSQLITE_TRACE_SIZE_LIMIT\scompile-time\sparameter\sis\sset\sto\sa\spositive\ninteger\sthen\slimit\sthe\sexpansion\sof\sstrings\sand\sblobs\sin\strace\soutput\sto\napproximately\sthat\smany\sbytes. C Try\sto\suse\smmap()\sto\sspeed\saccess\sto\sthe\sdatabase\sfile\son\swindows,\slinux,\nand\smac.
D 2013-04-02T13:56:53.795 D 2013-04-04T00:40:17.148
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in aafa71d66bab7e87fb2f348152340645f79f0244 F Makefile.in aafa71d66bab7e87fb2f348152340645f79f0244
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -118,23 +118,23 @@ F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168
F src/analyze.c d5f895810e8ff9737c9ec7b76abc3dcff5860335 F src/analyze.c d5f895810e8ff9737c9ec7b76abc3dcff5860335
F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704 F src/attach.c 1816f5a9eea8d2010fc2b22b44f0f63eb3a62704
F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34
F src/backup.c b2cac9f7993f3f9588827b824b1501d0c820fa68 F src/backup.c b266767351ae2d847716c56fcb2a1fea7c761c03
F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb
F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 62ba5954765efc711c873a20a53f60d9fc2843ba F src/btree.c 5f2c4fe72f663bba837c5d01a732799c1d1c93f8
F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd F src/btree.h d9490cd37aaeb530a41b07f06e1262950b1be916
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176 F src/build.c 083da8466fd7e481cb8bd5264398f537507f6176
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 2a5f251fcd7393808df77ccfc817e7058df08c4c F src/ctime.c 16658a257bc6a3ca8d8961f574cf61a57e4d6faf
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4 F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778 F src/delete.c aeabdabeeeaa0584127f291baa9617153d334778
F src/expr.c 48048fca951eedbc74aa32262154410d56c83812 F src/expr.c 48048fca951eedbc74aa32262154410d56c83812
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179 F src/fkey.c e16942bd5c8a868ac53287886464a5ed0e72b179
F src/func.c 48987c025d69399f59a1c2a553cea5da41bf105d F src/func.c 48987c025d69399f59a1c2a553cea5da41bf105d
F src/global.c e59ecd2c553ad0d4bfbc84ca71231336f8993a7a F src/global.c d2494a1cea8f66a2cab8258449df07f8f0ae6330
F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
@ -143,7 +143,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f F src/legacy.c a199d7683d60cef73089e892409113e69c23a99f
F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
F src/loadext.c 1422eba4aa2b1fb5f7b3aef574752272477d21e2 F src/loadext.c 1422eba4aa2b1fb5f7b3aef574752272477d21e2
F src/main.c 379160ec3680e3009aa4978eac47027c3ef27ac5 F src/main.c 54a841854734b6731c4d026834788cac6a19f3d1
F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa
@ -157,34 +157,34 @@ F src/mutex_noop.c 7682796b7d8d39bf1c138248858efcd10c9e1553
F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc F src/mutex_unix.c c3a4e00f96ba068a8dbef34084465979aaf369cc
F src/mutex_w32.c 32a9b3841e2d757355f0012b860b1bc5e01eafa0 F src/mutex_w32.c 32a9b3841e2d757355f0012b860b1bc5e01eafa0
F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30 F src/notify.c 976dd0f6171d4588e89e874fcc765e92914b6d30
F src/os.c e1acdc09ff3ac2412945cca9766e2dcf4675f31c F src/os.c 809d0707cec693e1b9b376ab229271ad74c3d35d
F src/os.h 027491c77d2404c0a678bb3fb06286f331eb9b57 F src/os.h ae08bcc5f6ec6b339f4a2adf3931bb88cc14c3e4
F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04
F src/os_unix.c 21a36fa0b3753609b6606b30d9338d4bb6b24696 F src/os_unix.c f0ecce40d92469d5cc737ae883e776eb3e5c0af5
F src/os_win.c 9fe5356f943425ab8431237bd3a4297044928b70 F src/os_win.c 3265df8c762e0b8caf8d02b3352fa8c22e91ae6b
F src/pager.c 3e9a15939684b0af441325f05335331b15979c9d F src/pager.c 2e68df46d4086027cb6b527d47a6dedbf1a6b7ec
F src/pager.h 1109a06578ec5574dc2c74cf8d9f69daf36fe3e0 F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1
F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95 F src/parse.y 5d5e12772845805fdfeb889163516b84fbb9ae95
F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
F src/pcache.h 1b5dcc3dc8103d03e625b177023ee67764fa6b7c F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9 F src/pcache1.c 9fd22671c270b35131ef480bbc00392b8b5f8ab9
F src/pragma.c 9f0ee3d74a7f33eeeff40a4b014fc3abf8182ce2 F src/pragma.c 682e97f3e3b77fd6c9b569eabfbf4a14c987aca3
F src/prepare.c 310eaff1ee5f3c700b3545afb095cfe9346efc3a F src/prepare.c 310eaff1ee5f3c700b3545afb095cfe9346efc3a
F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f F src/printf.c 4a9f882f1c1787a8b494a2987765acf9d97ac21f
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 9079da7d59aed2bb14ec8315bc7f720dd85b5b65 F src/resolve.c 9079da7d59aed2bb14ec8315bc7f720dd85b5b65
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 01540bcd3df3c8f1187158e77986028b1c667258 F src/select.c 01540bcd3df3c8f1187158e77986028b1c667258
F src/shell.c 7c41bfcd9e5bf9d96b9215f79b03a5b2b44a3bca F src/shell.c 319b7791cee6c763b60fde1b590bfaf62613cf37
F src/sqlite.h.in 8d9e83d965f364ff99ebf4b653d0683d05df3900 F src/sqlite.h.in faeb6b3470193e599d79289f77f984b8a78136e1
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 7183ab832e23db0f934494f16928da127a571d75 F src/sqlite3ext.h 7183ab832e23db0f934494f16928da127a571d75
F src/sqliteInt.h 0f8f05ee4db4ba9120b38f7a3992b325698f6e8a F src/sqliteInt.h 1664dc5ad6f8d4dab871416628aa3271044d66c0
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/sqliteLimit.h 1097d2c541147d303e66515040067c6bfcf8cf21
F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
F src/tclsqlite.c 9a716c737590d2f129d71c8fc7065e5aba0e7222 F src/tclsqlite.c 9a716c737590d2f129d71c8fc7065e5aba0e7222
F src/test1.c ff3e68eedfbd858c9b89cf03e3db233cd29be1d0 F src/test1.c 26e66b839f42c2eed6833f9023e0098f0d863f35
F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf F src/test2.c 4178056dd1e7d70f954ad8a1e3edb71a2a784daf
F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d F src/test3.c 3c3c2407fa6ec7a19e24ae23f7cb439d0275a60d
F src/test4.c bf9fa9bece01de08e6f5e02314e4af5c13590dfa F src/test4.c bf9fa9bece01de08e6f5e02314e4af5c13590dfa
@ -226,7 +226,7 @@ F src/test_spellfix.c 56dfa6d583ac34f61af0834d7b58d674e7e18e13
F src/test_sqllog.c bc50e5afeb7fb50e77b4594e42302df9d05446aa F src/test_sqllog.c bc50e5afeb7fb50e77b4594e42302df9d05446aa
F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935 F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935
F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd
F src/test_syscall.c a992d8c80ea91fbf21fb2dd570db40e77dd7e6ae F src/test_syscall.c 7e8293e4e6971b0f44c7f7f37b1315a8cc9f6018
F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa
F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4 F src/test_thread.c e286f2173563f2a1747c24bcda6b9d030bf4f4e4
F src/test_vfs.c fb16b2d9938cf0c1afc5a423b55b952fcc024275 F src/test_vfs.c fb16b2d9938cf0c1afc5a423b55b952fcc024275
@ -249,8 +249,8 @@ F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
F src/vdbesort.c 4fad64071ae120c25f39dcac572d716b9cadeb7f F src/vdbesort.c 4fad64071ae120c25f39dcac572d716b9cadeb7f
F src/vdbetrace.c a22263ab47f6ba4fcd176515cec1e732866b25f0 F src/vdbetrace.c a22263ab47f6ba4fcd176515cec1e732866b25f0
F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83
F src/wal.c f5c7b5027d0ed0e9bc9afeb4a3a8dfea762ec7d2 F src/wal.c 94b5fed2df988fb12f5bf17256e2840e56957a85
F src/wal.h 29c197540b19044e6cd73487017e5e47a1d3dac6 F src/wal.h a4d3da523d55a226a0b28e9058ef88d0a8051887
F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b F src/walker.c 3d75ba73de15e0f8cd0737643badbeb0e002f07b
F src/where.c 4ad2329c439a30ddb915a780f6f80bdffafe3a64 F src/where.c 4ad2329c439a30ddb915a780f6f80bdffafe3a64
F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823 F test/8_3_names.test 631ea964a3edb091cf73c3b540f6bcfdb36ce823
@ -314,6 +314,7 @@ F test/boundary3.tcl 8901d6a503d0bf64251dd81cc74e5ad3add4b119
F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45
F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983
F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b
F test/btreefault.test 06899a377f31a8c1a3048ec69831522d4e5c6045
F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0 F test/busy.test 76b4887f8b9160ba903c1ac22e8ff406ad6ae2f0
F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de F test/cache.test 13bc046b26210471ca6f2889aceb1ea52dc717de
F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a
@ -369,7 +370,7 @@ F test/cse.test 277350a26264495e86b1785f34d2d0c8600e021c
F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47 F test/ctime.test 7bd009071e242aac4f18521581536b652b789a47
F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9 F test/date.test f3228180c87bbe5d39c9397bf001c0095c3821b9
F test/dbstatus.test 207e5b63fcb7b9c3bb8e1fdf38ebd4654ad0e54b F test/dbstatus.test 207e5b63fcb7b9c3bb8e1fdf38ebd4654ad0e54b
F test/dbstatus2.test bf7396af964b89e39435babbcdf296ae8fc5f10a F test/dbstatus2.test f329941d5f4a8bc0ba6ec5735897ef0cf34e2f5f
F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc F test/default.test 6faf23ccb300114924353007795aa9a8ec0aa9dc
F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701 F test/delete.test a065b05d2ebf60fd16639c579a4adfb7c381c701
F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa F test/delete2.test 3a03f2cca1f9a67ec469915cb8babd6485db43fa
@ -403,7 +404,7 @@ F test/eqp.test 46aa946dd55c90635327898275d3e533d23a9845
F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a F test/errmsg.test 050717f1c6a5685de9c79f5f9f6b83d7c592f73a
F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3 F test/eval.test bc269c365ba877554948441e91ad5373f9f91be3
F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb F test/exclusive.test a1b324cb21834a490cd052d409d34789cfef57cb
F test/exclusive2.test 372be98f6de44dd78734e364b7b626ea211761a6 F test/exclusive2.test 354bdabe299a2546c898dff42f79079ff1590d88
F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7 F test/exec.test e949714dc127eaa5ecc7d723efec1ec27118fdd7
F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30 F test/exists.test 8f7b27b61c2fbe5822f0a1f899c715d14e416e30
F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d F test/expr.test 67c9fd6f8f829e239dc8b0f4a08a73c08b09196d
@ -508,7 +509,7 @@ F test/fts4merge2.test 5faa558d1b672f82b847d2a337465fa745e46891
F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7 F test/fts4merge3.test aab02a09f50fe6baaddc2e159c3eabc116d45fc7
F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40 F test/fts4unicode.test 25ccad45896f8e50f6a694cff738a35f798cdb40
F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d
F test/func.test b058483c17952eff7797b837bbb61e27e6b05606 F test/func.test a4f24707e6af0bcd4cb5b856af4462db40b047b1
F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f
F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a F test/func3.test 001021e5b88bd02a3b365a5c5fd8f6f49d39744a
F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74 F test/fuzz-oss1.test 4912e528ec9cf2f42134456933659d371c9e0d74
@ -526,7 +527,7 @@ F test/in2.test 5d4c61d17493c832f7d2d32bef785119e87bde75
F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0 F test/in3.test 3cbf58c87f4052cee3a58b37b6389777505aa0c0
F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617 F test/in4.test 64f3cc1acde1b9161ccdd8e5bde3daefdb5b2617
F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3 F test/in5.test 99f9a40af01711b06d2d614ecfe96129f334fba3
F test/incrblob.test e7ef2a6094d9b5eb7284c21af2c07644eefffe7d F test/incrblob.test 2100cb8964e4a106e5ca9bf80e2c5c3e8be33f77
F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19 F test/incrblob2.test edc3a96e557bd61fb39acc8d2edd43371fbbaa19
F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7 F test/incrblob3.test aedbb35ea1b6450c33b98f2b6ed98e5020be8dc7
F test/incrblob4.test 09be37d3dd996a31ea6993bba7837ece549414a8 F test/incrblob4.test 09be37d3dd996a31ea6993bba7837ece549414a8
@ -611,7 +612,7 @@ F test/mallocH.test 79b65aed612c9b3ed2dcdaa727c85895fd1bfbdb
F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6 F test/mallocI.test a88c2b9627c8506bf4703d8397420043a786cdb6
F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e F test/mallocJ.test b5d1839da331d96223e5f458856f8ffe1366f62e
F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9 F test/mallocK.test d79968641d1b70d88f6c01bdb9a7eb4a55582cc9
F test/malloc_common.tcl 2930895b0962823ec679853e67e58dd6d8198b3c F test/malloc_common.tcl 9a98856549bfb3fab205edbc1317216edc52e70d
F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e
F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f
F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6 F test/memdb.test 708a028d6d373e5b3842e4bdc8ba80998c9a4da6
@ -630,6 +631,8 @@ F test/misc5.test 528468b26d03303b1f047146e5eefc941b9069f5
F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91
F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3 F test/misc7.test dd82ec9250b89178b96cd28b2aca70639d21e5b3
F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054
F test/mmap1.test df5105f08e6000e57b4de7e748f8c2ae3fed75da
F test/mmap2.test 62dbb5d718e66d654d232116c5a2d96e26a071a5
F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256
F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a
F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101
@ -651,14 +654,14 @@ F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3
F test/pager1.test 31c04bec797dda1bde337810b52efa08d1f1f08e F test/pager1.test 31c04bec797dda1bde337810b52efa08d1f1f08e
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 fc2e37b2da626826dd54bb13720b4d721719b660
F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401 F test/pagerfault2.test 1f79ea40d1133b2683a2f811b00f2399f7ec2401
F test/pagerfault3.test f16e2efcb5fc9996d1356f7cbc44c998318ae1d7 F test/pagerfault3.test f16e2efcb5fc9996d1356f7cbc44c998318ae1d7
F test/pageropt.test 9191867ed19a2b3db6c42d1b36b6fbc657cd1ab0 F test/pageropt.test 32cb5a6ed7ccddf8e8c842cb44240bd9340223ce
F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0
F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16
F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025
F test/permutations.test 360b92859c0af814b3fe10b68746936389606501 F test/permutations.test b6cb45ce4d3193b831231025c9d30c77317dd240
F test/pragma.test 60d29cd3d8098a2c20bf4c072810f99e3bf2757a F test/pragma.test 60d29cd3d8098a2c20bf4c072810f99e3bf2757a
F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947
F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552 F test/printf.test ec9870c4dce8686a37818e0bf1aba6e6a1863552
@ -731,7 +734,7 @@ F test/softheap1.test c16709a16ad79fa43b32929b2e623d1d117ccf53
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/speed1.test f2974a91d79f58507ada01864c0e323093065452 F test/speed1.test f2974a91d79f58507ada01864c0e323093065452
F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb F test/speed1p.explain d841e650a04728b39e6740296b852dccdca9b2cb
F test/speed1p.test c4a469f29f135f4d76c55b1f2a52f36e209466cc F test/speed1p.test b180e98609c7677382cf618c0ec9b69f789033a8
F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523
F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715
@ -747,8 +750,8 @@ F test/subselect.test d24fd8757daf97dafd2e889c73ea4c4272dcf4e4
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2 F test/superlock.test 1cde669f68d2dd37d6c9bd35eee1d95491ae3fc2
F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85 F test/sync.test a34cd43e98b7fb84eabbf38f7ed8f7349b3f3d85
F test/syscall.test bea9bf329bff733c791310244617c2a76974e64a F test/syscall.test a653783d985108c4912cc64d341ffbbb55ad2806
F test/sysfault.test c79441d88d23696fbec7b147dba98d42a04f523f F test/sysfault.test 503f72712b2b21cb80dc9899e53c2e39484d0313
F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2 F test/table.test a59d985ca366e39b17b175f387f9d5db5a18d4e2
F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126 F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43 F test/tclsqlite.test 37a61c2da7e3bfe3b8c1a2867199f6b860df5d43
@ -952,11 +955,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 82f463886e18d7f8395a4b6167c91815efe54839 F test/vtab_shared.test 82f463886e18d7f8395a4b6167c91815efe54839
F test/wal.test a040047d7f2b9f34bc4d597964e5e7c09609c635 F test/wal.test 62454b2cf00b311e9e65f898aad0fef536ed561a
F test/wal2.test d4b470f13c87f6d8268b004380afa04c3c67cb90 F test/wal2.test d4b470f13c87f6d8268b004380afa04c3c67cb90
F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test f58ed4b8b542f71c7441da12fbd769d99b362437 F test/wal5.test f4d0aee6a2cf09e326ed2459011d396b4fdf661a
F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3 F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3
F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd
F test/wal8.test b3ee739fe8f7586aaebdc2367f477ebcf3e3b034 F test/wal8.test b3ee739fe8f7586aaebdc2367f477ebcf3e3b034
@ -1041,7 +1044,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 5687e5ee7bafa00d2b353c3eda1e5dfb219cb185 P e5b710849dd66673ba0e0d935b103cb29abfcc4b b2a72be9bab77f050bef75477a278a6294d3e854
R b688b887865b3d8981922c40426941a0 R 60af9b4d9e73e7757090b3abb77cbb41
U drh U drh
Z 66f86621cb15eccea274cb5b5e71ec26 Z d05e425b384f57133414b300483bca27

View File

@ -1 +1 @@
e5b710849dd66673ba0e0d935b103cb29abfcc4b fff2be60779571c8fb89158db976ec3755e9a223

View File

@ -397,7 +397,8 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){
const Pgno iSrcPg = p->iNext; /* Source page number */ const Pgno iSrcPg = p->iNext; /* Source page number */
if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){ if( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) ){
DbPage *pSrcPg; /* Source page object */ DbPage *pSrcPg; /* Source page object */
rc = sqlite3PagerGet(pSrcPager, iSrcPg, &pSrcPg); rc = sqlite3PagerAcquire(pSrcPager, iSrcPg, &pSrcPg,
PAGER_ACQUIRE_READONLY);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0); rc = backupOnePage(p, iSrcPg, sqlite3PagerGetData(pSrcPg), 0);
sqlite3PagerUnref(pSrcPg); sqlite3PagerUnref(pSrcPg);

View File

@ -1581,13 +1581,17 @@ static int btreeGetPage(
BtShared *pBt, /* The btree */ BtShared *pBt, /* The btree */
Pgno pgno, /* Number of the page to fetch */ Pgno pgno, /* Number of the page to fetch */
MemPage **ppPage, /* Return the page in this parameter */ MemPage **ppPage, /* Return the page in this parameter */
int noContent /* Do not load page content if true */ int noContent, /* Do not load page content if true */
int bReadonly /* True if a read-only (mmap) page is ok */
){ ){
int rc; int rc;
DbPage *pDbPage; DbPage *pDbPage;
int flags = (noContent ? PAGER_ACQUIRE_NOCONTENT : 0)
| (bReadonly ? PAGER_ACQUIRE_READONLY : 0);
assert( noContent==0 || bReadonly==0 );
assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(pBt->mutex) );
rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent); rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, flags);
if( rc ) return rc; if( rc ) return rc;
*ppPage = btreePageFromDbPage(pDbPage, pgno, pBt); *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);
return SQLITE_OK; return SQLITE_OK;
@ -1630,9 +1634,10 @@ u32 sqlite3BtreeLastPage(Btree *p){
** may remain unchanged, or it may be set to an invalid value. ** may remain unchanged, or it may be set to an invalid value.
*/ */
static int getAndInitPage( static int getAndInitPage(
BtShared *pBt, /* The database file */ BtShared *pBt, /* The database file */
Pgno pgno, /* Number of the page to get */ Pgno pgno, /* Number of the page to get */
MemPage **ppPage /* Write the page pointer here */ MemPage **ppPage, /* Write the page pointer here */
int bReadonly /* True if a read-only (mmap) page is ok */
){ ){
int rc; int rc;
assert( sqlite3_mutex_held(pBt->mutex) ); assert( sqlite3_mutex_held(pBt->mutex) );
@ -1640,7 +1645,7 @@ static int getAndInitPage(
if( pgno>btreePagecount(pBt) ){ if( pgno>btreePagecount(pBt) ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else{ }else{
rc = btreeGetPage(pBt, pgno, ppPage, 0); rc = btreeGetPage(pBt, pgno, ppPage, 0, bReadonly);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = btreeInitPage(*ppPage); rc = btreeInitPage(*ppPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -1871,6 +1876,7 @@ int sqlite3BtreeOpen(
rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename, rc = sqlite3PagerOpen(pVfs, &pBt->pPager, zFilename,
EXTRA_SIZE, flags, vfsFlags, pageReinit); EXTRA_SIZE, flags, vfsFlags, pageReinit);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
sqlite3PagerSetMmapLimit(pBt->pPager, db->mxMmap);
rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader); rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);
} }
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -2137,6 +2143,19 @@ int sqlite3BtreeSetCacheSize(Btree *p, int mxPage){
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Change the limit on the amount of the database file that may be
** memory mapped.
*/
int sqlite3BtreeSetMmapLimit(Btree *p, sqlite3_int64 mxMmap){
BtShared *pBt = p->pBt;
assert( sqlite3_mutex_held(p->db->mutex) );
sqlite3BtreeEnter(p);
sqlite3PagerSetMmapLimit(pBt->pPager, mxMmap);
sqlite3BtreeLeave(p);
return SQLITE_OK;
}
/* /*
** Change the way data is synced to disk in order to increase or decrease ** Change the way data is synced to disk in order to increase or decrease
** how well the database resists damage due to OS crashes and power ** how well the database resists damage due to OS crashes and power
@ -2362,7 +2381,7 @@ static int lockBtree(BtShared *pBt){
assert( pBt->pPage1==0 ); assert( pBt->pPage1==0 );
rc = sqlite3PagerSharedLock(pBt->pPager); rc = sqlite3PagerSharedLock(pBt->pPager);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
rc = btreeGetPage(pBt, 1, &pPage1, 0); rc = btreeGetPage(pBt, 1, &pPage1, 0, 0);
if( rc!=SQLITE_OK ) return rc; if( rc!=SQLITE_OK ) return rc;
/* Do some checking to help insure the file we opened really is /* Do some checking to help insure the file we opened really is
@ -2921,7 +2940,7 @@ static int relocatePage(
** iPtrPage. ** iPtrPage.
*/ */
if( eType!=PTRMAP_ROOTPAGE ){ if( eType!=PTRMAP_ROOTPAGE ){
rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0); rc = btreeGetPage(pBt, iPtrPage, &pPtrPage, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@ -3005,7 +3024,7 @@ static int incrVacuumStep(BtShared *pBt, Pgno nFin, Pgno iLastPg, int bCommit){
u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */ u8 eMode = BTALLOC_ANY; /* Mode parameter for allocateBtreePage() */
Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */ Pgno iNear = 0; /* nearby parameter for allocateBtreePage() */
rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0); rc = btreeGetPage(pBt, iLastPg, &pLastPg, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@ -3097,8 +3116,11 @@ int sqlite3BtreeIncrVacuum(Btree *p){
if( nOrig<nFin ){ if( nOrig<nFin ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else if( nFree>0 ){ }else if( nFree>0 ){
invalidateAllOverflowCache(pBt); rc = saveAllCursors(pBt, 0, 0);
rc = incrVacuumStep(pBt, nFin, nOrig, 0); if( rc==SQLITE_OK ){
invalidateAllOverflowCache(pBt);
rc = incrVacuumStep(pBt, nFin, nOrig, 0);
}
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
put4byte(&pBt->pPage1->aData[28], pBt->nPage); put4byte(&pBt->pPage1->aData[28], pBt->nPage);
@ -3146,7 +3168,9 @@ static int autoVacuumCommit(BtShared *pBt){
nFree = get4byte(&pBt->pPage1->aData[36]); nFree = get4byte(&pBt->pPage1->aData[36]);
nFin = finalDbSize(pBt, nOrig, nFree); nFin = finalDbSize(pBt, nOrig, nFree);
if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT; if( nFin>nOrig ) return SQLITE_CORRUPT_BKPT;
if( nFin<nOrig ){
rc = saveAllCursors(pBt, 0, 0);
}
for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){ for(iFree=nOrig; iFree>nFin && rc==SQLITE_OK; iFree--){
rc = incrVacuumStep(pBt, nFin, iFree, 1); rc = incrVacuumStep(pBt, nFin, iFree, 1);
} }
@ -3163,7 +3187,7 @@ static int autoVacuumCommit(BtShared *pBt){
} }
} }
assert( nRef==sqlite3PagerRefcount(pPager) ); assert( nRef>=sqlite3PagerRefcount(pPager) );
return rc; return rc;
} }
@ -3419,7 +3443,7 @@ int sqlite3BtreeRollback(Btree *p, int tripCode){
/* The rollback may have destroyed the pPage1->aData value. So /* The rollback may have destroyed the pPage1->aData value. So
** call btreeGetPage() on page 1 again to make ** call btreeGetPage() on page 1 again to make
** sure pPage1->aData is set correctly. */ ** sure pPage1->aData is set correctly. */
if( btreeGetPage(pBt, 1, &pPage1, 0)==SQLITE_OK ){ if( btreeGetPage(pBt, 1, &pPage1, 0, 0)==SQLITE_OK ){
int nPage = get4byte(28+(u8*)pPage1->aData); int nPage = get4byte(28+(u8*)pPage1->aData);
testcase( nPage==0 ); testcase( nPage==0 );
if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage); if( nPage==0 ) sqlite3PagerPagecount(pBt->pPager, &nPage);
@ -3853,7 +3877,7 @@ static int getOverflowPage(
assert( next==0 || rc==SQLITE_DONE ); assert( next==0 || rc==SQLITE_DONE );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = btreeGetPage(pBt, ovfl, &pPage, 0); rc = btreeGetPage(pBt, ovfl, &pPage, 0, (ppPage==0));
assert( rc==SQLITE_OK || pPage==0 ); assert( rc==SQLITE_OK || pPage==0 );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
next = get4byte(pPage->aData); next = get4byte(pPage->aData);
@ -4074,7 +4098,9 @@ static int accessPayload(
{ {
DbPage *pDbPage; DbPage *pDbPage;
rc = sqlite3PagerGet(pBt->pPager, nextPage, &pDbPage); rc = sqlite3PagerAcquire(pBt->pPager, nextPage, &pDbPage,
(eOp==0 ? PAGER_ACQUIRE_READONLY : 0)
);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
aPayload = sqlite3PagerGetData(pDbPage); aPayload = sqlite3PagerGetData(pDbPage);
nextPage = get4byte(aPayload); nextPage = get4byte(aPayload);
@ -4253,10 +4279,11 @@ static int moveToChild(BtCursor *pCur, u32 newPgno){
assert( cursorHoldsMutex(pCur) ); assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_VALID ); assert( pCur->eState==CURSOR_VALID );
assert( pCur->iPage<BTCURSOR_MAX_DEPTH ); assert( pCur->iPage<BTCURSOR_MAX_DEPTH );
assert( pCur->iPage>=0 );
if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){ if( pCur->iPage>=(BTCURSOR_MAX_DEPTH-1) ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, newPgno, &pNewPage); rc = getAndInitPage(pBt, newPgno, &pNewPage, (pCur->wrFlag==0));
if( rc ) return rc; if( rc ) return rc;
pCur->apPage[i+1] = pNewPage; pCur->apPage[i+1] = pNewPage;
pCur->aiIdx[i+1] = 0; pCur->aiIdx[i+1] = 0;
@ -4373,7 +4400,7 @@ static int moveToRoot(BtCursor *pCur){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return SQLITE_OK; return SQLITE_OK;
}else{ }else{
rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0]); rc = getAndInitPage(pBt, pCur->pgnoRoot, &pCur->apPage[0], pCur->wrFlag==0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pCur->eState = CURSOR_INVALID; pCur->eState = CURSOR_INVALID;
return rc; return rc;
@ -4987,7 +5014,7 @@ static int allocateBtreePage(
if( iTrunk>mxPage ){ if( iTrunk>mxPage ){
rc = SQLITE_CORRUPT_BKPT; rc = SQLITE_CORRUPT_BKPT;
}else{ }else{
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
} }
if( rc ){ if( rc ){
pTrunk = 0; pTrunk = 0;
@ -5051,7 +5078,7 @@ static int allocateBtreePage(
goto end_allocate_page; goto end_allocate_page;
} }
testcase( iNewTrunk==mxPage ); testcase( iNewTrunk==mxPage );
rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0); rc = btreeGetPage(pBt, iNewTrunk, &pNewTrunk, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto end_allocate_page; goto end_allocate_page;
} }
@ -5131,7 +5158,7 @@ static int allocateBtreePage(
} }
put4byte(&aData[4], k-1); put4byte(&aData[4], k-1);
noContent = !btreeGetHasContent(pBt, *pPgno); noContent = !btreeGetHasContent(pBt, *pPgno);
rc = btreeGetPage(pBt, *pPgno, ppPage, noContent); rc = btreeGetPage(pBt, *pPgno, ppPage, noContent, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -5179,7 +5206,7 @@ static int allocateBtreePage(
MemPage *pPg = 0; MemPage *pPg = 0;
TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage)); TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) ); assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent); rc = btreeGetPage(pBt, pBt->nPage, &pPg, bNoContent, 0);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerWrite(pPg->pDbPage); rc = sqlite3PagerWrite(pPg->pDbPage);
releasePage(pPg); releasePage(pPg);
@ -5193,7 +5220,7 @@ static int allocateBtreePage(
*pPgno = pBt->nPage; *pPgno = pBt->nPage;
assert( *pPgno!=PENDING_BYTE_PAGE(pBt) ); assert( *pPgno!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent); rc = btreeGetPage(pBt, *pPgno, ppPage, bNoContent, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3PagerWrite((*ppPage)->pDbPage); rc = sqlite3PagerWrite((*ppPage)->pDbPage);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -5261,7 +5288,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
/* If the secure_delete option is enabled, then /* If the secure_delete option is enabled, then
** always fully overwrite deleted information with zeros. ** always fully overwrite deleted information with zeros.
*/ */
if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0) ) if( (!pPage && ((rc = btreeGetPage(pBt, iPage, &pPage, 0, 0))!=0) )
|| ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0) || ((rc = sqlite3PagerWrite(pPage->pDbPage))!=0)
){ ){
goto freepage_out; goto freepage_out;
@ -5288,7 +5315,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
u32 nLeaf; /* Initial number of leaf cells on trunk page */ u32 nLeaf; /* Initial number of leaf cells on trunk page */
iTrunk = get4byte(&pPage1->aData[32]); iTrunk = get4byte(&pPage1->aData[32]);
rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0); rc = btreeGetPage(pBt, iTrunk, &pTrunk, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto freepage_out; goto freepage_out;
} }
@ -5334,7 +5361,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
** first trunk in the free-list is full. Either way, the page being freed ** first trunk in the free-list is full. Either way, the page being freed
** will become the new first trunk page in the free-list. ** will become the new first trunk page in the free-list.
*/ */
if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0)) ){ if( pPage==0 && SQLITE_OK!=(rc = btreeGetPage(pBt, iPage, &pPage, 0, 0)) ){
goto freepage_out; goto freepage_out;
} }
rc = sqlite3PagerWrite(pPage->pDbPage); rc = sqlite3PagerWrite(pPage->pDbPage);
@ -6135,7 +6162,7 @@ static int balance_nonroot(
} }
pgno = get4byte(pRight); pgno = get4byte(pRight);
while( 1 ){ while( 1 ){
rc = getAndInitPage(pBt, pgno, &apOld[i]); rc = getAndInitPage(pBt, pgno, &apOld[i], 0);
if( rc ){ if( rc ){
memset(apOld, 0, (i+1)*sizeof(MemPage*)); memset(apOld, 0, (i+1)*sizeof(MemPage*));
goto balance_cleanup; goto balance_cleanup;
@ -7223,10 +7250,17 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
u8 eType = 0; u8 eType = 0;
Pgno iPtrPage = 0; Pgno iPtrPage = 0;
/* Save the positions of any open cursors. This is required in
** case they are holding a reference to an xFetch reference
** corresponding to page pgnoRoot. */
rc = saveAllCursors(pBt, 0, 0);
releasePage(pPageMove); releasePage(pPageMove);
if( rc!=SQLITE_OK ){
return rc;
}
/* Move the page currently at pgnoRoot to pgnoMove. */ /* Move the page currently at pgnoRoot to pgnoMove. */
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@ -7247,7 +7281,7 @@ static int btreeCreateTable(Btree *p, int *piTable, int createTabFlags){
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0); rc = btreeGetPage(pBt, pgnoRoot, &pRoot, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@ -7323,7 +7357,7 @@ static int clearDatabasePage(
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
} }
rc = getAndInitPage(pBt, pgno, &pPage); rc = getAndInitPage(pBt, pgno, &pPage, 0);
if( rc ) return rc; if( rc ) return rc;
for(i=0; i<pPage->nCell; i++){ for(i=0; i<pPage->nCell; i++){
pCell = findCell(pPage, i); pCell = findCell(pPage, i);
@ -7425,7 +7459,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return SQLITE_LOCKED_SHAREDCACHE; return SQLITE_LOCKED_SHAREDCACHE;
} }
rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0); rc = btreeGetPage(pBt, (Pgno)iTable, &pPage, 0, 0);
if( rc ) return rc; if( rc ) return rc;
rc = sqlite3BtreeClearTable(p, iTable, 0); rc = sqlite3BtreeClearTable(p, iTable, 0);
if( rc ){ if( rc ){
@ -7460,7 +7494,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
*/ */
MemPage *pMove; MemPage *pMove;
releasePage(pPage); releasePage(pPage);
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
@ -7470,7 +7504,7 @@ static int btreeDropTable(Btree *p, Pgno iTable, int *piMoved){
return rc; return rc;
} }
pMove = 0; pMove = 0;
rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0); rc = btreeGetPage(pBt, maxRootPgno, &pMove, 0, 0);
freePage(pMove, &rc); freePage(pMove, &rc);
releasePage(pMove); releasePage(pMove);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
@ -7882,7 +7916,7 @@ static int checkTreePage(
usableSize = pBt->usableSize; usableSize = pBt->usableSize;
if( iPage==0 ) return 0; if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage, zParentContext) ) return 0; if( checkRef(pCheck, iPage, zParentContext) ) return 0;
if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0))!=0 ){ if( (rc = btreeGetPage(pBt, (Pgno)iPage, &pPage, 0, 0))!=0 ){
checkAppendMsg(pCheck, zContext, checkAppendMsg(pCheck, zContext,
"unable to get the page. error code=%d", rc); "unable to get the page. error code=%d", rc);
return 0; return 0;
@ -8354,6 +8388,17 @@ int sqlite3BtreePutData(BtCursor *pCsr, u32 offset, u32 amt, void *z){
return SQLITE_ABORT; return SQLITE_ABORT;
} }
/* Save the positions of all other cursors open on this table. This is
** required in case any of them are holding references to an xFetch
** version of the b-tree page modified by the accessPayload call below.
**
** Note that pCsr must be open on a BTREE_INTKEY table and saveCursorPosition()
** and hence saveAllCursors() cannot fail on a BTREE_INTKEY table, hence
** saveAllCursors can only return SQLITE_OK.
*/
VVA_ONLY(rc =) saveAllCursors(pCsr->pBt, pCsr->pgnoRoot, pCsr);
assert( rc==SQLITE_OK );
/* Check some assumptions: /* Check some assumptions:
** (a) the cursor is open for writing, ** (a) the cursor is open for writing,
** (b) there is a read/write transaction open, ** (b) there is a read/write transaction open,

View File

@ -63,6 +63,7 @@ int sqlite3BtreeOpen(
int sqlite3BtreeClose(Btree*); int sqlite3BtreeClose(Btree*);
int sqlite3BtreeSetCacheSize(Btree*,int); int sqlite3BtreeSetCacheSize(Btree*,int);
int sqlite3BtreeSetMmapLimit(Btree*,sqlite3_int64);
int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int); int sqlite3BtreeSetSafetyLevel(Btree*,int,int,int);
int sqlite3BtreeSyncDisabled(Btree*); int sqlite3BtreeSyncDisabled(Btree*);
int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix); int sqlite3BtreeSetPageSize(Btree *p, int nPagesize, int nReserve, int eFix);

View File

@ -57,6 +57,9 @@ static const char * const azCompileOpt[] = {
#ifdef SQLITE_DEFAULT_LOCKING_MODE #ifdef SQLITE_DEFAULT_LOCKING_MODE
"DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE), "DEFAULT_LOCKING_MODE=" CTIMEOPT_VAL(SQLITE_DEFAULT_LOCKING_MODE),
#endif #endif
#ifdef SQLITE_DEFAULT_MMAP_LIMIT
"DEFAULT_MMAP_LIMIT=" CTIMEOPT_VAL(SQLITE_DEFAULT_MMAP_LIMIT),
#endif
#ifdef SQLITE_DISABLE_DIRSYNC #ifdef SQLITE_DISABLE_DIRSYNC
"DISABLE_DIRSYNC", "DISABLE_DIRSYNC",
#endif #endif

View File

@ -156,6 +156,7 @@ SQLITE_WSD struct Sqlite3Config sqlite3Config = {
(void*)0, /* pHeap */ (void*)0, /* pHeap */
0, /* nHeap */ 0, /* nHeap */
0, 0, /* mnHeap, mxHeap */ 0, 0, /* mnHeap, mxHeap */
SQLITE_DEFAULT_MMAP_LIMIT, /* mxMmap */
(void*)0, /* pScratch */ (void*)0, /* pScratch */
0, /* szScratch */ 0, /* szScratch */
0, /* nScratch */ 0, /* nScratch */

View File

@ -496,6 +496,13 @@ int sqlite3_config(int op, ...){
} }
#endif #endif
case SQLITE_CONFIG_MMAP_LIMIT: {
sqlite3_int64 mxMmap = va_arg(ap, sqlite3_int64);
if( mxMmap<0 ) mxMmap = SQLITE_DEFAULT_MMAP_LIMIT;
sqlite3GlobalConfig.mxMmap = mxMmap;
break;
}
default: { default: {
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
break; break;
@ -2316,6 +2323,7 @@ static int openDatabase(
memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
db->autoCommit = 1; db->autoCommit = 1;
db->nextAutovac = -1; db->nextAutovac = -1;
db->mxMmap = sqlite3GlobalConfig.mxMmap;
db->nextPagesize = 0; db->nextPagesize = 0;
db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger
#if SQLITE_DEFAULT_FILE_FORMAT<4 #if SQLITE_DEFAULT_FILE_FORMAT<4

View File

@ -141,6 +141,14 @@ int sqlite3OsShmMap(
return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp); return id->pMethods->xShmMap(id, iPage, pgsz, bExtend, pp);
} }
int sqlite3OsFetch(sqlite3_file *id, i64 iOff, int iAmt, void **pp){
DO_OS_MALLOC_TEST(id);
return id->pMethods->xFetch(id, iOff, iAmt, pp);
}
int sqlite3OsUnfetch(sqlite3_file *id, i64 iOff, void *p){
return id->pMethods->xUnfetch(id, iOff, p);
}
/* /*
** The next group of routines are convenience wrappers around the ** The next group of routines are convenience wrappers around the
** VFS methods. ** VFS methods.

View File

@ -259,6 +259,8 @@ int sqlite3OsShmMap(sqlite3_file *,int,int,int,void volatile **);
int sqlite3OsShmLock(sqlite3_file *id, int, int, int); int sqlite3OsShmLock(sqlite3_file *id, int, int, int);
void sqlite3OsShmBarrier(sqlite3_file *id); void sqlite3OsShmBarrier(sqlite3_file *id);
int sqlite3OsShmUnmap(sqlite3_file *id, int); int sqlite3OsShmUnmap(sqlite3_file *id, int);
int sqlite3OsFetch(sqlite3_file *id, i64, int, void **);
int sqlite3OsUnfetch(sqlite3_file *, i64, void *);
/* /*

View File

@ -225,6 +225,11 @@ struct unixFile {
const char *zPath; /* Name of the file */ const char *zPath; /* Name of the file */
unixShm *pShm; /* Shared memory segment information */ unixShm *pShm; /* Shared memory segment information */
int szChunk; /* Configured by FCNTL_CHUNK_SIZE */ int szChunk; /* Configured by FCNTL_CHUNK_SIZE */
int nFetchOut; /* Number of outstanding xFetch refs */
sqlite3_int64 mmapSize; /* Usable size of mapping at pMapRegion */
sqlite3_int64 mmapOrigsize; /* Actual size of mapping at pMapRegion */
sqlite3_int64 mmapLimit; /* Configured FCNTL_MMAP_LIMIT value */
void *pMapRegion; /* Memory mapped region */
#ifdef __QNXNTO__ #ifdef __QNXNTO__
int sectorSize; /* Device sector size */ int sectorSize; /* Device sector size */
int deviceCharacteristics; /* Precomputed device characteristics */ int deviceCharacteristics; /* Precomputed device characteristics */
@ -249,7 +254,9 @@ struct unixFile {
unsigned char transCntrChng; /* True if the transaction counter changed */ unsigned char transCntrChng; /* True if the transaction counter changed */
unsigned char dbUpdate; /* True if any part of database file changed */ unsigned char dbUpdate; /* True if any part of database file changed */
unsigned char inNormalWrite; /* True if in a normal write operation */ unsigned char inNormalWrite; /* True if in a normal write operation */
#endif #endif
#ifdef SQLITE_TEST #ifdef SQLITE_TEST
/* In test mode, increase the size of this structure a bit so that /* In test mode, increase the size of this structure a bit so that
** it is larger than the struct CrashFile defined in test6.c. ** it is larger than the struct CrashFile defined in test6.c.
@ -306,6 +313,17 @@ struct unixFile {
#define threadid 0 #define threadid 0
#endif #endif
/*
** HAVE_MREMAP defaults to true on Linux and false everywhere else.
*/
#if !defined(HAVE_MREMAP)
# if defined(__linux__) && defined(_GNU_SOURCE)
# define HAVE_MREMAP 1
# else
# define HAVE_MREMAP 0
# endif
#endif
/* /*
** Different Unix systems declare open() in different ways. Same use ** Different Unix systems declare open() in different ways. Same use
** open(const char*,int,mode_t). Others use open(const char*,int,...). ** open(const char*,int,mode_t). Others use open(const char*,int,...).
@ -437,6 +455,19 @@ static struct unix_syscall {
{ "fchown", (sqlite3_syscall_ptr)posixFchown, 0 }, { "fchown", (sqlite3_syscall_ptr)posixFchown, 0 },
#define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent) #define osFchown ((int(*)(int,uid_t,gid_t))aSyscall[20].pCurrent)
{ "mmap", (sqlite3_syscall_ptr)mmap, 0 },
#define osMmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[21].pCurrent)
{ "munmap", (sqlite3_syscall_ptr)munmap, 0 },
#define osMunmap ((void*(*)(void*,size_t))aSyscall[22].pCurrent)
#if HAVE_MREMAP
{ "mremap", (sqlite3_syscall_ptr)mremap, 0 },
#else
{ "mremap", (sqlite3_syscall_ptr)0, 0 },
#endif
#define osMremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[23].pCurrent)
}; /* End of the overrideable system calls */ }; /* End of the overrideable system calls */
/* /*
@ -1104,7 +1135,6 @@ static int unixLogErrorAtLine(
zErr = strerror(iErrno); zErr = strerror(iErrno);
#endif #endif
assert( errcode!=SQLITE_OK );
if( zPath==0 ) zPath = ""; if( zPath==0 ) zPath = "";
sqlite3_log(errcode, sqlite3_log(errcode,
"os_unix.c:%d: (%d) %s(%s) - %s", "os_unix.c:%d: (%d) %s(%s) - %s",
@ -1800,9 +1830,13 @@ end_unlock:
** the requested locking level, this routine is a no-op. ** the requested locking level, this routine is a no-op.
*/ */
static int unixUnlock(sqlite3_file *id, int eFileLock){ static int unixUnlock(sqlite3_file *id, int eFileLock){
assert( eFileLock==SHARED_LOCK || ((unixFile *)id)->nFetchOut==0 );
return posixUnlock(id, eFileLock, 0); return posixUnlock(id, eFileLock, 0);
} }
static int unixMapfile(unixFile *pFd, i64 nByte);
static void unixUnmapfile(unixFile *pFd);
/* /*
** This function performs the parts of the "close file" operation ** This function performs the parts of the "close file" operation
** common to all locking schemes. It closes the directory and file ** common to all locking schemes. It closes the directory and file
@ -1815,6 +1849,7 @@ static int unixUnlock(sqlite3_file *id, int eFileLock){
*/ */
static int closeUnixFile(sqlite3_file *id){ static int closeUnixFile(sqlite3_file *id){
unixFile *pFile = (unixFile*)id; unixFile *pFile = (unixFile*)id;
unixUnmapfile(pFile);
if( pFile->h>=0 ){ if( pFile->h>=0 ){
robust_close(pFile, pFile->h, __LINE__); robust_close(pFile, pFile->h, __LINE__);
pFile->h = -1; pFile->h = -1;
@ -3082,6 +3117,21 @@ static int unixRead(
); );
#endif #endif
/* Deal with as much of this read request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
return SQLITE_OK;
}else{
int nCopy = pFile->mmapSize - offset;
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
got = seekAndRead(pFile, offset, pBuf, amt); got = seekAndRead(pFile, offset, pBuf, amt);
if( got==amt ){ if( got==amt ){
return SQLITE_OK; return SQLITE_OK;
@ -3186,6 +3236,21 @@ static int unixWrite(
} }
#endif #endif
/* Deal with as much of this write request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
return SQLITE_OK;
}else{
int nCopy = pFile->mmapSize - offset;
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){
amt -= wrote; amt -= wrote;
offset += wrote; offset += wrote;
@ -3468,6 +3533,14 @@ static int unixTruncate(sqlite3_file *id, i64 nByte){
} }
#endif #endif
/* If the file was just truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
*/
if( nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
}
return SQLITE_OK; return SQLITE_OK;
} }
} }
@ -3556,6 +3629,19 @@ static int fcntlSizeHint(unixFile *pFile, i64 nByte){
} }
} }
if( pFile->mmapLimit>0 && nByte>pFile->mmapSize ){
int rc;
if( pFile->szChunk<=0 ){
if( robust_ftruncate(pFile->h, nByte) ){
pFile->lastErrno = errno;
return unixLogError(SQLITE_IOERR_TRUNCATE, "ftruncate", pFile->zPath);
}
}
rc = unixMapfile(pFile, nByte);
return rc;
}
return SQLITE_OK; return SQLITE_OK;
} }
@ -3623,6 +3709,12 @@ static int unixFileControl(sqlite3_file *id, int op, void *pArg){
} }
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_MMAP_LIMIT: {
i64 newLimit = *(i64*)pArg;
*(i64*)pArg = pFile->mmapLimit;
if( newLimit>=0 ) pFile->mmapLimit = newLimit;
return SQLITE_OK;
}
#ifdef SQLITE_DEBUG #ifdef SQLITE_DEBUG
/* The pager calls this method to signal that it has done /* The pager calls this method to signal that it has done
** a rollback and that the database is therefore unchanged and ** a rollback and that the database is therefore unchanged and
@ -3935,7 +4027,7 @@ static void unixShmPurge(unixFile *pFd){
sqlite3_mutex_free(p->mutex); sqlite3_mutex_free(p->mutex);
for(i=0; i<p->nRegion; i++){ for(i=0; i<p->nRegion; i++){
if( p->h>=0 ){ if( p->h>=0 ){
munmap(p->apRegion[i], p->szRegion); osMunmap(p->apRegion[i], p->szRegion);
}else{ }else{
sqlite3_free(p->apRegion[i]); sqlite3_free(p->apRegion[i]);
} }
@ -4208,7 +4300,7 @@ static int unixShmMap(
while(pShmNode->nRegion<=iRegion){ while(pShmNode->nRegion<=iRegion){
void *pMem; void *pMem;
if( pShmNode->h>=0 ){ if( pShmNode->h>=0 ){
pMem = mmap(0, szRegion, pMem = osMmap(0, szRegion,
pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE,
MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion
); );
@ -4425,6 +4517,223 @@ static int unixShmUnmap(
# define unixShmUnmap 0 # define unixShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */ #endif /* #ifndef SQLITE_OMIT_WAL */
/*
** If it is currently memory mapped, unmap file pFd.
*/
static void unixUnmapfile(unixFile *pFd){
assert( pFd->nFetchOut==0 );
if( pFd->pMapRegion ){
osMunmap(pFd->pMapRegion, pFd->mmapOrigsize);
pFd->pMapRegion = 0;
pFd->mmapSize = 0;
pFd->mmapOrigsize = 0;
}
}
/*
** Return the system page size.
*/
static int unixGetPagesize(void){
#if HAVE_MREMAP
return 512;
#elif defined(_BSD_SOURCE)
return getpagesize();
#else
return (int)sysconf(_SC_PAGESIZE);
#endif
}
/*
** Attempt to set the size of the memory mapping maintained by file
** descriptor pFd to nNew bytes. Any existing mapping is discarded.
**
** If successful, this function sets the following variables:
**
** unixFile.pMapRegion
** unixFile.mmapSize
** unixFile.mmapOrigsize
**
** If unsuccessful, an error message is logged via sqlite3_log() and
** the three variables above are zeroed. In this case SQLite should
** continue accessing the database using the xRead() and xWrite()
** methods.
*/
static void unixRemapfile(
unixFile *pFd, /* File descriptor object */
i64 nNew /* Required mapping size */
){
const char *zErr = "mmap";
int h = pFd->h; /* File descriptor open on db file */
u8 *pOrig = (u8 *)pFd->pMapRegion; /* Pointer to current file mapping */
i64 nOrig = pFd->mmapOrigsize; /* Size of pOrig region in bytes */
u8 *pNew = 0; /* Location of new mapping */
int flags = PROT_READ; /* Flags to pass to mmap() */
assert( pFd->nFetchOut==0 );
assert( nNew>pFd->mmapSize );
assert( nNew<=pFd->mmapLimit );
assert( nNew>0 );
assert( pFd->mmapOrigsize>=pFd->mmapSize );
assert( MAP_FAILED!=0 );
if( (pFd->ctrlFlags & UNIXFILE_RDONLY)==0 ) flags |= PROT_WRITE;
if( pOrig ){
const int szSyspage = unixGetPagesize();
i64 nReuse = (pFd->mmapSize & ~(szSyspage-1));
u8 *pReq = &pOrig[nReuse];
/* Unmap any pages of the existing mapping that cannot be reused. */
if( nReuse!=nOrig ){
osMunmap(pReq, nOrig-nReuse);
}
#if HAVE_MREMAP
pNew = osMremap(pOrig, nReuse, nNew, MREMAP_MAYMOVE);
zErr = "mremap";
#else
pNew = osMmap(pReq, nNew-nReuse, flags, MAP_SHARED, h, nReuse);
if( pNew!=MAP_FAILED ){
if( pNew!=pReq ){
osMunmap(pNew, nNew - nReuse);
pNew = 0;
}else{
pNew = pOrig;
}
}
#endif
/* The attempt to extend the existing mapping failed. Free it. */
if( pNew==MAP_FAILED || pNew==0 ){
osMunmap(pOrig, nReuse);
}
}
/* If pNew is still NULL, try to create an entirely new mapping. */
if( pNew==0 ){
pNew = osMmap(0, nNew, flags, MAP_SHARED, h, 0);
}
if( pNew==MAP_FAILED ){
pNew = 0;
nNew = 0;
unixLogError(SQLITE_OK, zErr, pFd->zPath);
/* If the mmap() above failed, assume that all subsequent mmap() calls
** will probably fail too. Fall back to using xRead/xWrite exclusively
** in this case. */
pFd->mmapLimit = 0;
}
pFd->pMapRegion = (void *)pNew;
pFd->mmapSize = pFd->mmapOrigsize = nNew;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if
** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of
** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int unixMapfile(unixFile *pFd, i64 nByte){
i64 nMap = nByte;
int rc;
assert( nMap>=0 || pFd->nFetchOut==0 );
if( pFd->nFetchOut>0 ) return SQLITE_OK;
if( nMap<0 ){
struct stat statbuf; /* Low-level file information */
rc = osFstat(pFd->h, &statbuf);
if( rc!=SQLITE_OK ){
return SQLITE_IOERR_FSTAT;
}
nMap = statbuf.st_size;
}
if( nMap>pFd->mmapLimit ){
nMap = pFd->mmapLimit;
}
if( nMap!=pFd->mmapSize ){
if( nMap>0 ){
unixRemapfile(pFd, nMap);
}else{
unixUnmapfile(pFd);
}
}
return SQLITE_OK;
}
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int unixFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
*pp = 0;
if( pFd->mmapLimit>0 ){
if( pFd->pMapRegion==0 ){
int rc = unixMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
if( pFd->mmapSize >= iOff+nAmt ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
}
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int unixUnfetch(sqlite3_file *fd, i64 iOff, void *p){
unixFile *pFd = (unixFile *)fd; /* The underlying database file */
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
if( p ){
pFd->nFetchOut--;
}else{
unixUnmapfile(pFd);
}
assert( pFd->nFetchOut>=0 );
return SQLITE_OK;
}
/* /*
** Here ends the implementation of all sqlite3_file methods. ** Here ends the implementation of all sqlite3_file methods.
** **
@ -4483,7 +4792,9 @@ static const sqlite3_io_methods METHOD = { \
unixShmMap, /* xShmMap */ \ unixShmMap, /* xShmMap */ \
unixShmLock, /* xShmLock */ \ unixShmLock, /* xShmLock */ \
unixShmBarrier, /* xShmBarrier */ \ unixShmBarrier, /* xShmBarrier */ \
unixShmUnmap /* xShmUnmap */ \ unixShmUnmap, /* xShmUnmap */ \
unixFetch, /* xFetch */ \
unixUnfetch, /* xUnfetch */ \
}; \ }; \
static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \ static const sqlite3_io_methods *FINDER##Impl(const char *z, unixFile *p){ \
UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \ UNUSED_PARAMETER(z); UNUSED_PARAMETER(p); \
@ -4500,7 +4811,7 @@ static const sqlite3_io_methods *(*const FINDER)(const char*,unixFile *p) \
IOMETHODS( IOMETHODS(
posixIoFinder, /* Finder function name */ posixIoFinder, /* Finder function name */
posixIoMethods, /* sqlite3_io_methods object name */ posixIoMethods, /* sqlite3_io_methods object name */
2, /* shared memory is enabled */ 3, /* shared memory and mmap are enabled */
unixClose, /* xClose method */ unixClose, /* xClose method */
unixLock, /* xLock method */ unixLock, /* xLock method */
unixUnlock, /* xUnlock method */ unixUnlock, /* xUnlock method */
@ -4751,6 +5062,7 @@ static int fillInUnixFile(
pNew->pVfs = pVfs; pNew->pVfs = pVfs;
pNew->zPath = zFilename; pNew->zPath = zFilename;
pNew->ctrlFlags = (u8)ctrlFlags; pNew->ctrlFlags = (u8)ctrlFlags;
pNew->mmapLimit = sqlite3GlobalConfig.mxMmap;
if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0), if( sqlite3_uri_boolean(((ctrlFlags & UNIXFILE_URI) ? zFilename : 0),
"psow", SQLITE_POWERSAFE_OVERWRITE) ){ "psow", SQLITE_POWERSAFE_OVERWRITE) ){
pNew->ctrlFlags |= UNIXFILE_PSOW; pNew->ctrlFlags |= UNIXFILE_PSOW;
@ -6988,7 +7300,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)==21 ); assert( ArraySize(aSyscall)==24 );
/* 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

@ -150,11 +150,18 @@ struct winFile {
winceLock local; /* Locks obtained by this instance of winFile */ winceLock local; /* Locks obtained by this instance of winFile */
winceLock *shared; /* Global shared lock memory for the file */ winceLock *shared; /* Global shared lock memory for the file */
#endif #endif
int nFetchOut; /* Number of outstanding xFetch references */
HANDLE hMap; /* Handle for accessing memory mapping */
void *pMapRegion; /* Area memory mapped */
sqlite3_int64 mmapSize; /* Usable size of mapped region */
sqlite3_int64 mmapOrigsize; /* Actual size of mapped region */
sqlite3_int64 mmapLimit; /* Configured FCNTL_MMAP_LIMIT value */
}; };
/* /*
** Allowed values for winFile.ctrlFlags ** Allowed values for winFile.ctrlFlags
*/ */
#define WINFILE_RDONLY 0x02 /* Connection is read only */
#define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ #define WINFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */
#define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ #define WINFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */
@ -2061,6 +2068,9 @@ static int seekWinFile(winFile *pFile, sqlite3_int64 iOffset){
#endif #endif
} }
/* Forward references to VFS methods */
static int winUnmapfile(winFile*);
/* /*
** Close a file. ** Close a file.
** **
@ -2082,6 +2092,10 @@ static int winClose(sqlite3_file *id){
#endif #endif
OSTRACE(("CLOSE %d\n", pFile->h)); OSTRACE(("CLOSE %d\n", pFile->h));
assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE ); assert( pFile->h!=NULL && pFile->h!=INVALID_HANDLE_VALUE );
rc = winUnmapfile(pFile);
if( rc!=SQLITE_OK ) return rc;
do{ do{
rc = osCloseHandle(pFile->h); rc = osCloseHandle(pFile->h);
/* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */ /* SimulateIOError( rc=0; cnt=MX_CLOSE_ATTEMPT; ); */
@ -2130,9 +2144,25 @@ static int winRead(
int nRetry = 0; /* Number of retrys */ int nRetry = 0; /* Number of retrys */
assert( id!=0 ); assert( id!=0 );
assert( amt>0 );
SimulateIOError(return SQLITE_IOERR_READ); SimulateIOError(return SQLITE_IOERR_READ);
OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype)); OSTRACE(("READ %d lock=%d\n", pFile->h, pFile->locktype));
/* Deal with as much of this read request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], amt);
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
memcpy(pBuf, &((u8 *)(pFile->pMapRegion))[offset], nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#if SQLITE_OS_WINCE #if SQLITE_OS_WINCE
if( seekWinFile(pFile, offset) ){ if( seekWinFile(pFile, offset) ){
return SQLITE_FULL; return SQLITE_FULL;
@ -2182,6 +2212,21 @@ static int winWrite(
OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype)); OSTRACE(("WRITE %d lock=%d\n", pFile->h, pFile->locktype));
/* Deal with as much of this write request as possible by transfering
** data from the memory mapping using memcpy(). */
if( offset<pFile->mmapSize ){
if( offset+amt <= pFile->mmapSize ){
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, amt);
return SQLITE_OK;
}else{
int nCopy = (int)(pFile->mmapSize - offset);
memcpy(&((u8 *)(pFile->pMapRegion))[offset], pBuf, nCopy);
pBuf = &((u8 *)pBuf)[nCopy];
amt -= nCopy;
offset += nCopy;
}
}
#if SQLITE_OS_WINCE #if SQLITE_OS_WINCE
rc = seekWinFile(pFile, offset); rc = seekWinFile(pFile, offset);
if( rc==0 ){ if( rc==0 ){
@ -2249,6 +2294,7 @@ static int winWrite(
static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
winFile *pFile = (winFile*)id; /* File handle object */ winFile *pFile = (winFile*)id; /* File handle object */
int rc = SQLITE_OK; /* Return code for this function */ int rc = SQLITE_OK; /* Return code for this function */
DWORD lastErrno;
assert( pFile ); assert( pFile );
@ -2267,11 +2313,20 @@ static int winTruncate(sqlite3_file *id, sqlite3_int64 nByte){
/* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */
if( seekWinFile(pFile, nByte) ){ if( seekWinFile(pFile, nByte) ){
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
"winTruncate1", pFile->zPath); "winTruncate1", pFile->zPath);
}else if( 0==osSetEndOfFile(pFile->h) ){ }else if( 0==osSetEndOfFile(pFile->h) &&
pFile->lastErrno = osGetLastError(); ((lastErrno = osGetLastError())!=ERROR_USER_MAPPED_FILE) ){
pFile->lastErrno = lastErrno;
rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno, rc = winLogError(SQLITE_IOERR_TRUNCATE, pFile->lastErrno,
"winTruncate2", pFile->zPath); "winTruncate2", pFile->zPath);
}
/* If the file was truncated to a size smaller than the currently
** mapped region, reduce the effective mapping size as well. SQLite will
** use read() and write() to access data beyond this point from now on.
*/
if( pFile->pMapRegion && nByte<pFile->mmapSize ){
pFile->mmapSize = nByte;
} }
OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok")); OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok"));
@ -2781,6 +2836,12 @@ static int winFileControl(sqlite3_file *id, int op, void *pArg){
} }
return SQLITE_OK; return SQLITE_OK;
} }
case SQLITE_FCNTL_MMAP_LIMIT: {
i64 newLimit = *(i64*)pArg;
*(i64*)pArg = pFile->mmapLimit;
if( newLimit>=0 ) pFile->mmapLimit = newLimit;
return SQLITE_OK;
}
} }
return SQLITE_NOTFOUND; return SQLITE_NOTFOUND;
} }
@ -3451,6 +3512,184 @@ shmpage_out:
# define winShmUnmap 0 # define winShmUnmap 0
#endif /* #ifndef SQLITE_OMIT_WAL */ #endif /* #ifndef SQLITE_OMIT_WAL */
/*
** Cleans up the mapped region of the specified file, if any.
*/
static int winUnmapfile(winFile *pFile){
assert( pFile!=0 );
if( pFile->pMapRegion ){
if( !osUnmapViewOfFile(pFile->pMapRegion) ){
pFile->lastErrno = osGetLastError();
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
"winUnmap1", pFile->zPath);
}
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
pFile->mmapOrigsize = 0;
}
if( pFile->hMap!=NULL ){
if( !osCloseHandle(pFile->hMap) ){
pFile->lastErrno = osGetLastError();
return winLogError(SQLITE_IOERR_MMAP, pFile->lastErrno,
"winUnmap2", pFile->zPath);
}
pFile->hMap = NULL;
}
return SQLITE_OK;
}
/*
** Memory map or remap the file opened by file-descriptor pFd (if the file
** is already mapped, the existing mapping is replaced by the new). Or, if
** there already exists a mapping for this file, and there are still
** outstanding xFetch() references to it, this function is a no-op.
**
** If parameter nByte is non-negative, then it is the requested size of
** the mapping to create. Otherwise, if nByte is less than zero, then the
** requested size is the size of the file on disk. The actual size of the
** created mapping is either the requested size or the value configured
** using SQLITE_FCNTL_MMAP_LIMIT, whichever is smaller.
**
** SQLITE_OK is returned if no error occurs (even if the mapping is not
** recreated as a result of outstanding references) or an SQLite error
** code otherwise.
*/
static int winMapfile(winFile *pFd, sqlite3_int64 nByte){
sqlite3_int64 nMap = nByte;
int rc;
assert( nMap>=0 || pFd->nFetchOut==0 );
if( pFd->nFetchOut>0 ) return SQLITE_OK;
if( nMap<0 ){
rc = winFileSize((sqlite3_file*)pFd, &nMap);
if( rc ){
return SQLITE_IOERR_FSTAT;
}
}
if( nMap>pFd->mmapLimit ){
nMap = pFd->mmapLimit;
}
nMap &= ~(sqlite3_int64)(winSysInfo.dwPageSize - 1);
if( nMap==0 && pFd->mmapSize>0 ){
winUnmapfile(pFd);
}
if( nMap!=pFd->mmapSize ){
void *pNew = 0;
DWORD protect = PAGE_READONLY;
DWORD flags = FILE_MAP_READ;
winUnmapfile(pFd);
if( (pFd->ctrlFlags & WINFILE_RDONLY)==0 ){
protect = PAGE_READWRITE;
flags |= FILE_MAP_WRITE;
}
#if SQLITE_OS_WINRT
pFd->hMap = osCreateFileMappingFromApp(pFd->h, NULL, protect, nMap, NULL);
#elif defined(SQLITE_WIN32_HAS_WIDE)
pFd->hMap = osCreateFileMappingW(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
#elif defined(SQLITE_WIN32_HAS_ANSI)
pFd->hMap = osCreateFileMappingA(pFd->h, NULL, protect,
(DWORD)((nMap>>32) & 0xffffffff),
(DWORD)(nMap & 0xffffffff), NULL);
#endif
if( pFd->hMap==NULL ){
pFd->lastErrno = osGetLastError();
rc = winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile", pFd->zPath);
/* Log the error, but continue normal operation using xRead/xWrite */
return SQLITE_OK;
}
assert( (nMap % winSysInfo.dwPageSize)==0 );
#if SQLITE_OS_WINRT
pNew = osMapViewOfFileFromApp(pFd->hMap, flags, 0, nMap);
#else
assert( sizeof(SIZE_T)==sizeof(sqlite3_int64) || nMap<=0xffffffff );
pNew = osMapViewOfFile(pFd->hMap, flags, 0, 0, (SIZE_T)nMap);
#endif
if( pNew==NULL ){
osCloseHandle(pFd->hMap);
pFd->hMap = NULL;
pFd->lastErrno = osGetLastError();
winLogError(SQLITE_IOERR_MMAP, pFd->lastErrno,
"winMapfile", pFd->zPath);
return SQLITE_OK;
}
pFd->pMapRegion = pNew;
pFd->mmapSize = nMap;
pFd->mmapOrigsize = nMap;
}
return SQLITE_OK;
}
/*
** If possible, return a pointer to a mapping of file fd starting at offset
** iOff. The mapping must be valid for at least nAmt bytes.
**
** If such a pointer can be obtained, store it in *pp and return SQLITE_OK.
** Or, if one cannot but no error occurs, set *pp to 0 and return SQLITE_OK.
** Finally, if an error does occur, return an SQLite error code. The final
** value of *pp is undefined in this case.
**
** If this function does return a pointer, the caller must eventually
** release the reference by calling unixUnfetch().
*/
static int winFetch(sqlite3_file *fd, i64 iOff, int nAmt, void **pp){
winFile *pFd = (winFile*)fd; /* The underlying database file */
*pp = 0;
if( pFd->mmapLimit>0 ){
if( pFd->pMapRegion==0 ){
int rc = winMapfile(pFd, -1);
if( rc!=SQLITE_OK ) return rc;
}
if( pFd->mmapSize >= iOff+nAmt ){
*pp = &((u8 *)pFd->pMapRegion)[iOff];
pFd->nFetchOut++;
}
}
return SQLITE_OK;
}
/*
** If the third argument is non-NULL, then this function releases a
** reference obtained by an earlier call to unixFetch(). The second
** argument passed to this function must be the same as the corresponding
** argument that was passed to the unixFetch() invocation.
**
** Or, if the third argument is NULL, then this function is being called
** to inform the VFS layer that, according to POSIX, any existing mapping
** may now be invalid and should be unmapped.
*/
static int winUnfetch(sqlite3_file *fd, i64 iOff, void *p){
winFile *pFd = (winFile*)fd; /* The underlying database file */
/* If p==0 (unmap the entire file) then there must be no outstanding
** xFetch references. Or, if p!=0 (meaning it is an xFetch reference),
** then there must be at least one outstanding. */
assert( (p==0)==(pFd->nFetchOut==0) );
/* If p!=0, it must match the iOff value. */
assert( p==0 || p==&((u8 *)pFd->pMapRegion)[iOff] );
if( p ){
pFd->nFetchOut--;
}else{
/* FIXME: If Windows truly always prevents truncating or deleting a
** file while a mapping is held, then the following winUnmapfile() call
** is unnecessary can can be omitted - potentially improving
** performance. */
winUnmapfile(pFd);
}
assert( pFd->nFetchOut>=0 );
return SQLITE_OK;
}
/* /*
** Here ends the implementation of all sqlite3_file methods. ** Here ends the implementation of all sqlite3_file methods.
** **
@ -3462,7 +3701,7 @@ shmpage_out:
** sqlite3_file for win32. ** sqlite3_file for win32.
*/ */
static const sqlite3_io_methods winIoMethod = { static const sqlite3_io_methods winIoMethod = {
2, /* iVersion */ 3, /* iVersion */
winClose, /* xClose */ winClose, /* xClose */
winRead, /* xRead */ winRead, /* xRead */
winWrite, /* xWrite */ winWrite, /* xWrite */
@ -3478,7 +3717,9 @@ static const sqlite3_io_methods winIoMethod = {
winShmMap, /* xShmMap */ winShmMap, /* xShmMap */
winShmLock, /* xShmLock */ winShmLock, /* xShmLock */
winShmBarrier, /* xShmBarrier */ winShmBarrier, /* xShmBarrier */
winShmUnmap /* xShmUnmap */ winShmUnmap, /* xShmUnmap */
winFetch, /* xFetch */
winUnfetch /* xUnfetch */
}; };
/**************************************************************************** /****************************************************************************
@ -3654,9 +3895,7 @@ static int winOpen(
int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE); int isExclusive = (flags & SQLITE_OPEN_EXCLUSIVE);
int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE); int isDelete = (flags & SQLITE_OPEN_DELETEONCLOSE);
int isCreate = (flags & SQLITE_OPEN_CREATE); int isCreate = (flags & SQLITE_OPEN_CREATE);
#ifndef NDEBUG
int isReadonly = (flags & SQLITE_OPEN_READONLY); int isReadonly = (flags & SQLITE_OPEN_READONLY);
#endif
int isReadWrite = (flags & SQLITE_OPEN_READWRITE); int isReadWrite = (flags & SQLITE_OPEN_READWRITE);
#ifndef NDEBUG #ifndef NDEBUG
@ -3867,11 +4106,19 @@ static int winOpen(
pFile->pMethod = &winIoMethod; pFile->pMethod = &winIoMethod;
pFile->pVfs = pVfs; pFile->pVfs = pVfs;
pFile->h = h; pFile->h = h;
if( isReadonly ){
pFile->ctrlFlags |= WINFILE_RDONLY;
}
if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){ if( sqlite3_uri_boolean(zName, "psow", SQLITE_POWERSAFE_OVERWRITE) ){
pFile->ctrlFlags |= WINFILE_PSOW; pFile->ctrlFlags |= WINFILE_PSOW;
} }
pFile->lastErrno = NO_ERROR; pFile->lastErrno = NO_ERROR;
pFile->zPath = zName; pFile->zPath = zName;
pFile->hMap = NULL;
pFile->pMapRegion = 0;
pFile->mmapSize = 0;
pFile->mmapOrigsize = 0;
pFile->mmapLimit = sqlite3GlobalConfig.mxMmap;
OpenCounter(+1); OpenCounter(+1);
return rc; return rc;
@ -4500,7 +4747,6 @@ int sqlite3_os_init(void){
** correctly. See ticket [bb3a86e890c8e96ab] */ ** correctly. See ticket [bb3a86e890c8e96ab] */
assert( ArraySize(aSyscall)==74 ); assert( ArraySize(aSyscall)==74 );
#ifndef SQLITE_OMIT_WAL
/* get memory map allocation granularity */ /* get memory map allocation granularity */
memset(&winSysInfo, 0, sizeof(SYSTEM_INFO)); memset(&winSysInfo, 0, sizeof(SYSTEM_INFO));
#if SQLITE_OS_WINRT #if SQLITE_OS_WINRT
@ -4508,8 +4754,8 @@ int sqlite3_os_init(void){
#else #else
osGetSystemInfo(&winSysInfo); osGetSystemInfo(&winSysInfo);
#endif #endif
assert(winSysInfo.dwAllocationGranularity > 0); assert( winSysInfo.dwAllocationGranularity>0 );
#endif assert( winSysInfo.dwPageSize>0 );
sqlite3_vfs_register(&winVfs, 1); sqlite3_vfs_register(&winVfs, 1);
return SQLITE_OK; return SQLITE_OK;

View File

@ -655,6 +655,11 @@ struct Pager {
PagerSavepoint *aSavepoint; /* Array of active savepoints */ PagerSavepoint *aSavepoint; /* Array of active savepoints */
int nSavepoint; /* Number of elements in aSavepoint[] */ int nSavepoint; /* Number of elements in aSavepoint[] */
char dbFileVers[16]; /* Changes whenever database file changes */ char dbFileVers[16]; /* Changes whenever database file changes */
u8 bUseFetch; /* True to use xFetch() */
int nMmapOut; /* Number of mmap pages currently outstanding */
sqlite3_int64 mxMmap; /* Desired maximum mmap size */
PgHdr *pMmapFreelist; /* List of free mmap page headers (pDirty) */
/* /*
** End of the routinely-changing class members ** End of the routinely-changing class members
***************************************************************************/ ***************************************************************************/
@ -2252,7 +2257,7 @@ static int pager_playback_one_page(
i64 ofst = (pgno-1)*(i64)pPager->pageSize; i64 ofst = (pgno-1)*(i64)pPager->pageSize;
testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 ); testcase( !isSavepnt && pPg!=0 && (pPg->flags&PGHDR_NEED_SYNC)!=0 );
assert( !pagerUseWal(pPager) ); assert( !pagerUseWal(pPager) );
rc = sqlite3OsWrite(pPager->fd, (u8*)aData, pPager->pageSize, ofst); rc = sqlite3OsWrite(pPager->fd, (u8 *)aData, pPager->pageSize, ofst);
if( pgno>pPager->dbFileSize ){ if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno; pPager->dbFileSize = pgno;
} }
@ -2834,11 +2839,10 @@ end_playback:
** If an IO error occurs, then the IO error is returned to the caller. ** If an IO error occurs, then the IO error is returned to the caller.
** Otherwise, SQLITE_OK is returned. ** Otherwise, SQLITE_OK is returned.
*/ */
static int readDbPage(PgHdr *pPg){ static int readDbPage(PgHdr *pPg, u32 iFrame){
Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */ Pager *pPager = pPg->pPager; /* Pager object associated with page pPg */
Pgno pgno = pPg->pgno; /* Page number to read */ Pgno pgno = pPg->pgno; /* Page number to read */
int rc = SQLITE_OK; /* Return code */ int rc = SQLITE_OK; /* Return code */
int isInWal = 0; /* True if page is in log file */
int pgsz = pPager->pageSize; /* Number of bytes to read */ int pgsz = pPager->pageSize; /* Number of bytes to read */
assert( pPager->eState>=PAGER_READER && !MEMDB ); assert( pPager->eState>=PAGER_READER && !MEMDB );
@ -2850,11 +2854,10 @@ static int readDbPage(PgHdr *pPg){
return SQLITE_OK; return SQLITE_OK;
} }
if( pagerUseWal(pPager) ){ if( iFrame ){
/* Try to pull the page from the write-ahead log. */ /* Try to pull the page from the write-ahead log. */
rc = sqlite3WalRead(pPager->pWal, pgno, &isInWal, pgsz, pPg->pData); rc = sqlite3WalReadFrame(pPager->pWal, iFrame, pgsz, pPg->pData);
} }else{
if( rc==SQLITE_OK && !isInWal ){
i64 iOffset = (pgno-1)*(i64)pPager->pageSize; i64 iOffset = (pgno-1)*(i64)pPager->pageSize;
rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset); rc = sqlite3OsRead(pPager->fd, pPg->pData, pgsz, iOffset);
if( rc==SQLITE_IOERR_SHORT_READ ){ if( rc==SQLITE_IOERR_SHORT_READ ){
@ -2933,12 +2936,17 @@ static int pagerUndoCallback(void *pCtx, Pgno iPg){
Pager *pPager = (Pager *)pCtx; Pager *pPager = (Pager *)pCtx;
PgHdr *pPg; PgHdr *pPg;
assert( pagerUseWal(pPager) );
pPg = sqlite3PagerLookup(pPager, iPg); pPg = sqlite3PagerLookup(pPager, iPg);
if( pPg ){ if( pPg ){
if( sqlite3PcachePageRefcount(pPg)==1 ){ if( sqlite3PcachePageRefcount(pPg)==1 ){
sqlite3PcacheDrop(pPg); sqlite3PcacheDrop(pPg);
}else{ }else{
rc = readDbPage(pPg); u32 iFrame = 0;
rc = sqlite3WalFindFrame(pPager->pWal, pPg->pgno, &iFrame);
if( rc==SQLITE_OK ){
rc = readDbPage(pPg, iFrame);
}
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
pPager->xReiniter(pPg); pPager->xReiniter(pPg);
} }
@ -3082,6 +3090,7 @@ static int pagerBeginReadTransaction(Pager *pPager){
rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed); rc = sqlite3WalBeginReadTransaction(pPager->pWal, &changed);
if( rc!=SQLITE_OK || changed ){ if( rc!=SQLITE_OK || changed ){
pager_reset(pPager); pager_reset(pPager);
if( pPager->bUseFetch ) sqlite3OsUnfetch(pPager->fd, 0, 0);
} }
return rc; return rc;
@ -3343,6 +3352,27 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){
sqlite3PcacheSetCachesize(pPager->pPCache, mxPage); sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);
} }
/*
** Invoke SQLITE_FCNTL_MMAP_LIMIT based on the current value of mxMmap.
*/
static void pagerFixMaplimit(Pager *pPager){
sqlite3_file *fd = pPager->fd;
if( isOpen(fd) ){
sqlite3_int64 mx;
pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->mxMmap>0;
mx = pPager->mxMmap;
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_LIMIT, &mx);
}
}
/*
** Change the maximum size of any memory mapping made of the database file.
*/
void sqlite3PagerSetMmapLimit(Pager *pPager, sqlite3_int64 mxMmap){
pPager->mxMmap = mxMmap;
pagerFixMaplimit(pPager);
}
/* /*
** Free as much memory as possible from the pager. ** Free as much memory as possible from the pager.
*/ */
@ -3578,6 +3608,7 @@ int sqlite3PagerSetPagesize(Pager *pPager, u32 *pPageSize, int nReserve){
assert( nReserve>=0 && nReserve<1000 ); assert( nReserve>=0 && nReserve<1000 );
pPager->nReserve = (i16)nReserve; pPager->nReserve = (i16)nReserve;
pagerReportSize(pPager); pagerReportSize(pPager);
pagerFixMaplimit(pPager);
} }
return rc; return rc;
} }
@ -3803,6 +3834,81 @@ static int pagerSyncHotJournal(Pager *pPager){
return rc; return rc;
} }
/*
** Obtain a reference to a memory mapped page object for page number pgno.
** The new object will use the pointer pData, obtained from xFetch().
** If successful, set *ppPage to point to the new page reference
** and return SQLITE_OK. Otherwise, return an SQLite error code and set
** *ppPage to zero.
**
** Page references obtained by calling this function should be released
** by calling pagerReleaseMapPage().
*/
static int pagerAcquireMapPage(
Pager *pPager, /* Pager object */
Pgno pgno, /* Page number */
void *pData, /* xFetch()'d data for this page */
PgHdr **ppPage /* OUT: Acquired page object */
){
PgHdr *p; /* Memory mapped page to return */
if( pPager->pMmapFreelist ){
*ppPage = p = pPager->pMmapFreelist;
pPager->pMmapFreelist = p->pDirty;
p->pDirty = 0;
memset(p->pExtra, 0, pPager->nExtra);
}else{
*ppPage = p = (PgHdr *)sqlite3MallocZero(sizeof(PgHdr) + pPager->nExtra);
if( p==0 ){
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1) * pPager->pageSize, pData);
return SQLITE_NOMEM;
}
p->pExtra = (void *)&p[1];
p->flags = PGHDR_MMAP;
p->nRef = 1;
p->pPager = pPager;
}
assert( p->pExtra==(void *)&p[1] );
assert( p->pPage==0 );
assert( p->flags==PGHDR_MMAP );
assert( p->pPager==pPager );
assert( p->nRef==1 );
p->pgno = pgno;
p->pData = pData;
pPager->nMmapOut++;
return SQLITE_OK;
}
/*
** Release a reference to page pPg. pPg must have been returned by an
** earlier call to pagerAcquireMapPage().
*/
static void pagerReleaseMapPage(PgHdr *pPg){
Pager *pPager = pPg->pPager;
pPager->nMmapOut--;
pPg->pDirty = pPager->pMmapFreelist;
pPager->pMmapFreelist = pPg;
assert( pPager->fd->pMethods->iVersion>=3 );
sqlite3OsUnfetch(pPager->fd, (i64)(pPg->pgno-1)*pPager->pageSize, pPg->pData);
}
/*
** Free all PgHdr objects stored in the Pager.pMmapFreelist list.
*/
static void pagerFreeMapHdrs(Pager *pPager){
PgHdr *p;
PgHdr *pNext;
for(p=pPager->pMmapFreelist; p; p=pNext){
pNext = p->pDirty;
sqlite3_free(p);
}
}
/* /*
** Shutdown the page cache. Free all memory and close all files. ** Shutdown the page cache. Free all memory and close all files.
** **
@ -3823,6 +3929,7 @@ int sqlite3PagerClose(Pager *pPager){
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
disable_simulated_io_errors(); disable_simulated_io_errors();
sqlite3BeginBenignMalloc(); sqlite3BeginBenignMalloc();
pagerFreeMapHdrs(pPager);
/* pPager->errCode = 0; */ /* pPager->errCode = 0; */
pPager->exclusiveMode = 0; pPager->exclusiveMode = 0;
#ifndef SQLITE_OMIT_WAL #ifndef SQLITE_OMIT_WAL
@ -4084,7 +4191,9 @@ static int pager_write_pagelist(Pager *pPager, PgHdr *pList){
** file size will be. ** file size will be.
*/ */
assert( rc!=SQLITE_OK || isOpen(pPager->fd) ); assert( rc!=SQLITE_OK || isOpen(pPager->fd) );
if( rc==SQLITE_OK && pPager->dbSize>pPager->dbHintSize ){ if( rc==SQLITE_OK
&& (pList->pDirty ? pPager->dbSize : pList->pgno+1)>pPager->dbHintSize
){
sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize; sqlite3_int64 szFile = pPager->pageSize * (sqlite3_int64)pPager->dbSize;
sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_SIZE_HINT, &szFile);
pPager->dbHintSize = pPager->dbSize; pPager->dbHintSize = pPager->dbSize;
@ -4638,6 +4747,7 @@ int sqlite3PagerOpen(
/* pPager->pBusyHandlerArg = 0; */ /* pPager->pBusyHandlerArg = 0; */
pPager->xReiniter = xReinit; pPager->xReiniter = xReinit;
/* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */
/* pPager->mxMmap = SQLITE_DEFAULT_MMAP_LIMIT // will be set by btree.c */
*ppPager = pPager; *ppPager = pPager;
return SQLITE_OK; return SQLITE_OK;
@ -4929,9 +5039,11 @@ int sqlite3PagerSharedLock(Pager *pPager){
); );
} }
if( !pPager->tempFile if( !pPager->tempFile && (
&& (pPager->pBackup || sqlite3PcachePagecount(pPager->pPCache)>0) pPager->pBackup
){ || sqlite3PcachePagecount(pPager->pPCache)>0
|| pPager->bUseFetch
)){
/* The shared-lock has just been acquired on the database file /* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous ** and there are already pages in the cache (from a previous
** read or write transaction). Check to see if the database ** read or write transaction). Check to see if the database
@ -4957,7 +5069,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( nPage>0 ){ if( nPage>0 ){
IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers))); IOTRACE(("CKVERS %p %d\n", pPager, sizeof(dbFileVers)));
rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers), 24);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK && rc!=SQLITE_IOERR_SHORT_READ ){
goto failed; goto failed;
} }
}else{ }else{
@ -4966,6 +5078,16 @@ int sqlite3PagerSharedLock(Pager *pPager){
if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){ if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
pager_reset(pPager); pager_reset(pPager);
/* Unmap the database file. It is possible that external processes
** may have truncated the database file and then extended it back
** to its original size while this process was not holding a lock.
** In this case there may exist a Pager.pMap mapping that appears
** to be the right size but is not actually valid. Avoid this
** possibility by unmapping the db here. */
if( pPager->bUseFetch ){
sqlite3OsUnfetch(pPager->fd, 0, 0);
}
} }
} }
@ -5007,7 +5129,7 @@ int sqlite3PagerSharedLock(Pager *pPager){
** nothing to rollback, so this routine is a no-op. ** nothing to rollback, so this routine is a no-op.
*/ */
static void pagerUnlockIfUnused(Pager *pPager){ static void pagerUnlockIfUnused(Pager *pPager){
if( (sqlite3PcacheRefCount(pPager->pPCache)==0) ){ if( pPager->nMmapOut==0 && (sqlite3PcacheRefCount(pPager->pPCache)==0) ){
pagerUnlockAndRollback(pPager); pagerUnlockAndRollback(pPager);
} }
} }
@ -5066,13 +5188,24 @@ int sqlite3PagerAcquire(
Pager *pPager, /* The pager open on the database file */ Pager *pPager, /* The pager open on the database file */
Pgno pgno, /* Page number to fetch */ Pgno pgno, /* Page number to fetch */
DbPage **ppPage, /* Write a pointer to the page here */ DbPage **ppPage, /* Write a pointer to the page here */
int noContent /* Do not bother reading content from disk if true */ int flags /* PAGER_ACQUIRE_XXX flags */
){ ){
int rc; int rc = SQLITE_OK;
PgHdr *pPg; PgHdr *pPg = 0;
u32 iFrame = 0; /* Frame to read from WAL file */
const int noContent = (flags & PAGER_ACQUIRE_NOCONTENT);
/* It is acceptable to use a read-only (mmap) page for any page except
** page 1 if there is no write-transaction open or the ACQUIRE_READONLY
** flag was specified by the caller. And so long as the db is not a
** temporary or in-memory database. */
const int bMmapOk = (pgno!=1 && pPager->bUseFetch
&& (pPager->eState==PAGER_READER || (flags & PAGER_ACQUIRE_READONLY))
);
assert( pPager->eState>=PAGER_READER ); assert( pPager->eState>=PAGER_READER );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
assert( noContent==0 || bMmapOk==0 );
if( pgno==0 ){ if( pgno==0 ){
return SQLITE_CORRUPT_BKPT; return SQLITE_CORRUPT_BKPT;
@ -5083,6 +5216,39 @@ int sqlite3PagerAcquire(
if( pPager->errCode!=SQLITE_OK ){ if( pPager->errCode!=SQLITE_OK ){
rc = pPager->errCode; rc = pPager->errCode;
}else{ }else{
if( bMmapOk && pagerUseWal(pPager) ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
if( iFrame==0 && bMmapOk ){
void *pData = 0;
rc = sqlite3OsFetch(pPager->fd,
(i64)(pgno-1) * pPager->pageSize, pPager->pageSize, &pData
);
if( rc==SQLITE_OK && pData ){
if( pPager->eState>PAGER_READER ){
(void)sqlite3PcacheFetch(pPager->pPCache, pgno, 0, &pPg);
}
if( pPg==0 ){
rc = pagerAcquireMapPage(pPager, pgno, pData, &pPg);
}else{
sqlite3OsUnfetch(pPager->fd, (i64)(pgno-1)*pPager->pageSize, pData);
}
if( pPg ){
assert( rc==SQLITE_OK );
*ppPage = pPg;
return SQLITE_OK;
}
}
if( rc!=SQLITE_OK ){
goto pager_acquire_err;
}
}
rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage); rc = sqlite3PcacheFetch(pPager->pPCache, pgno, 1, ppPage);
} }
@ -5141,9 +5307,13 @@ int sqlite3PagerAcquire(
memset(pPg->pData, 0, pPager->pageSize); memset(pPg->pData, 0, pPager->pageSize);
IOTRACE(("ZERO %p %d\n", pPager, pgno)); IOTRACE(("ZERO %p %d\n", pPager, pgno));
}else{ }else{
if( pagerUseWal(pPager) && bMmapOk==0 ){
rc = sqlite3WalFindFrame(pPager->pWal, pgno, &iFrame);
if( rc!=SQLITE_OK ) goto pager_acquire_err;
}
assert( pPg->pPager==pPager ); assert( pPg->pPager==pPager );
pPager->aStat[PAGER_STAT_MISS]++; pPager->aStat[PAGER_STAT_MISS]++;
rc = readDbPage(pPg); rc = readDbPage(pPg, iFrame);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
goto pager_acquire_err; goto pager_acquire_err;
} }
@ -5196,7 +5366,11 @@ DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
void sqlite3PagerUnref(DbPage *pPg){ void sqlite3PagerUnref(DbPage *pPg){
if( pPg ){ if( pPg ){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
sqlite3PcacheRelease(pPg); if( pPg->flags & PGHDR_MMAP ){
pagerReleaseMapPage(pPg);
}else{
sqlite3PcacheRelease(pPg);
}
pagerUnlockIfUnused(pPager); pagerUnlockIfUnused(pPager);
} }
} }
@ -5531,6 +5705,7 @@ int sqlite3PagerWrite(DbPage *pDbPage){
Pager *pPager = pPg->pPager; Pager *pPager = pPg->pPager;
Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize); Pgno nPagePerSector = (pPager->sectorSize/pPager->pageSize);
assert( (pPg->flags & PGHDR_MMAP)==0 );
assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( pPager->eState>=PAGER_WRITER_LOCKED );
assert( pPager->eState!=PAGER_ERROR ); assert( pPager->eState!=PAGER_ERROR );
assert( assert_pager_state(pPager) ); assert( assert_pager_state(pPager) );
@ -6087,7 +6262,7 @@ int sqlite3PagerRollback(Pager *pPager){
} }
assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK ); assert( pPager->eState==PAGER_READER || rc!=SQLITE_OK );
assert( rc==SQLITE_OK || rc==SQLITE_FULL assert( rc==SQLITE_OK || rc==SQLITE_FULL || rc==SQLITE_CORRUPT
|| rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR ); || rc==SQLITE_NOMEM || (rc&0xFF)==SQLITE_IOERR );
/* If an error occurs during a ROLLBACK, we can no longer trust the pager /* If an error occurs during a ROLLBACK, we can no longer trust the pager
@ -6821,11 +6996,12 @@ static int pagerOpenWal(Pager *pPager){
** (e.g. due to malloc() failure), return an error code. ** (e.g. due to malloc() failure), return an error code.
*/ */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3WalOpen(pPager->pVfs, rc = sqlite3WalOpen(pPager->pVfs,
pPager->fd, pPager->zWal, pPager->exclusiveMode, pPager->fd, pPager->zWal, pPager->exclusiveMode,
pPager->journalSizeLimit, &pPager->pWal pPager->journalSizeLimit, &pPager->pWal
); );
} }
pagerFixMaplimit(pPager);
return rc; return rc;
} }
@ -6916,6 +7092,7 @@ int sqlite3PagerCloseWal(Pager *pPager){
rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags, rc = sqlite3WalClose(pPager->pWal, pPager->ckptSyncFlags,
pPager->pageSize, (u8*)pPager->pTmpSpace); pPager->pageSize, (u8*)pPager->pTmpSpace);
pPager->pWal = 0; pPager->pWal = 0;
pagerFixMaplimit(pPager);
} }
} }
return rc; return rc;

View File

@ -78,6 +78,12 @@ typedef struct PgHdr DbPage;
#define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */ #define PAGER_JOURNALMODE_MEMORY 4 /* In-memory journal file */
#define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */ #define PAGER_JOURNALMODE_WAL 5 /* Use write-ahead logging */
/*
** Flags that make up the mask passed to sqlite3PagerAcquire().
*/
#define PAGER_ACQUIRE_NOCONTENT 0x01 /* Do not load data from disk */
#define PAGER_ACQUIRE_READONLY 0x02 /* Read-only page is acceptable */
/* /*
** The remainder of this file contains the declarations of the functions ** The remainder of this file contains the declarations of the functions
** that make up the Pager sub-system API. See source code comments for ** that make up the Pager sub-system API. See source code comments for
@ -102,6 +108,7 @@ void sqlite3PagerSetBusyhandler(Pager*, int(*)(void *), void *);
int sqlite3PagerSetPagesize(Pager*, u32*, int); int sqlite3PagerSetPagesize(Pager*, u32*, int);
int sqlite3PagerMaxPageCount(Pager*, int); int sqlite3PagerMaxPageCount(Pager*, int);
void sqlite3PagerSetCachesize(Pager*, int); void sqlite3PagerSetCachesize(Pager*, int);
void sqlite3PagerSetMmapLimit(Pager *, sqlite3_int64);
void sqlite3PagerShrink(Pager*); void sqlite3PagerShrink(Pager*);
void sqlite3PagerSetSafetyLevel(Pager*,int,int,int); void sqlite3PagerSetSafetyLevel(Pager*,int,int,int);
int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerLockingMode(Pager *, int);

View File

@ -53,6 +53,8 @@ struct PgHdr {
#define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */ #define PGHDR_REUSE_UNLIKELY 0x010 /* A hint that reuse is unlikely */
#define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */ #define PGHDR_DONT_WRITE 0x020 /* Do not write content to disk */
#define PGHDR_MMAP 0x040 /* This is an mmap page object */
/* Initialize and shutdown the page cache subsystem */ /* Initialize and shutdown the page cache subsystem */
int sqlite3PcacheInitialize(void); int sqlite3PcacheInitialize(void);
void sqlite3PcacheShutdown(void); void sqlite3PcacheShutdown(void);

View File

@ -744,6 +744,40 @@ void sqlite3Pragma(
} }
}else }else
/*
** PRAGMA [database.]mmap_limit(N)
**
** Used to set mapping size limit. The mapping size limit is
** used to limit the aggregate size of all memory mapped regions of the
** database file. If this parameter is set to zero, then memory mapping
** is not used at all. If N is negative, then the default memory map
** limit determined by sqlite3_config(SQLITE_CONFIG_MMAP_LIMIT) is set.
** The parameter N is measured in bytes.
**
** This value is advisory. The underlying VFS is free to memory map
** as little or as much as it wants. Except, if N is set to 0 then the
** upper layers will never invoke the xFetch interfaces to the VFS.
*/
if( sqlite3StrICmp(zLeft,"mmap_limit")==0 ){
sqlite3_int64 mx;
assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
if( zRight ){
int ii;
sqlite3Atoi64(zRight, &mx, 1000, SQLITE_UTF8);
if( mx<0 ) mx = sqlite3GlobalConfig.mxMmap;
if( pId2->n==0 ) db->mxMmap = mx;
for(ii=db->nDb-1; ii>=0; ii--){
if( db->aDb[ii].pBt && (ii==iDb || pId2->n==0) ){
sqlite3BtreeSetMmapLimit(db->aDb[ii].pBt, mx);
}
}
}
mx = -1;
if( sqlite3_file_control(db,zDb,SQLITE_FCNTL_MMAP_LIMIT,&mx)==SQLITE_OK ){
returnSingleInt(pParse, "mmap_limit", mx);
}
}else
/* /*
** PRAGMA temp_store ** PRAGMA temp_store
** PRAGMA temp_store = "default"|"memory"|"file" ** PRAGMA temp_store = "default"|"memory"|"file"

View File

@ -1552,6 +1552,43 @@ static int booleanValue(char *zArg){
return 0; return 0;
} }
/*
** Interpret zArg as an integer value, possibly with suffixes.
*/
static sqlite3_int64 integerValue(const char *zArg){
sqlite3_int64 v = 0;
static const struct { char *zSuffix; int iMult; } aMult[] = {
{ "KiB", 1024 },
{ "MiB", 1024*1024 },
{ "GiB", 1024*1024*1024 },
{ "KB", 1000 },
{ "MB", 1000000 },
{ "GB", 1000000000 },
{ "K", 1000 },
{ "M", 1000000 },
{ "G", 1000000000 },
};
int i;
int isNeg = 0;
if( zArg[0]=='-' ){
isNeg = 1;
zArg++;
}else if( zArg[0]=='+' ){
zArg++;
}
while( isdigit(zArg[0]) ){
v = v*10 + zArg[0] - '0';
zArg++;
}
for(i=0; i<sizeof(aMult)/sizeof(aMult[0]); i++){
if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){
v *= aMult[i].iMult;
break;
}
}
return isNeg? -v : v;
}
/* /*
** Close an output file, assuming it is not stderr or stdout ** Close an output file, assuming it is not stderr or stdout
*/ */
@ -2469,7 +2506,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
/* sqlite3_test_control(int, uint) */ /* sqlite3_test_control(int, uint) */
case SQLITE_TESTCTRL_PENDING_BYTE: case SQLITE_TESTCTRL_PENDING_BYTE:
if( nArg==3 ){ if( nArg==3 ){
unsigned int opt = (unsigned int)atoi(azArg[2]); unsigned int opt = (unsigned int)integerValue(azArg[2]);
rc = sqlite3_test_control(testctrl, opt); rc = sqlite3_test_control(testctrl, opt);
printf("%d (0x%08x)\n", rc, rc); printf("%d (0x%08x)\n", rc, rc);
} else { } else {
@ -2561,7 +2598,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){
#if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE) #if defined(SQLITE_DEBUG) && defined(SQLITE_ENABLE_WHERETRACE)
if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){ if( c=='w' && strncmp(azArg[0], "wheretrace", n)==0 ){
extern int sqlite3WhereTrace; extern int sqlite3WhereTrace;
sqlite3WhereTrace = atoi(azArg[1]); sqlite3WhereTrace = booleanValue(azArg[1]);
}else }else
#endif #endif
@ -2882,6 +2919,7 @@ static const char zOptions[] =
" -interactive force interactive I/O\n" " -interactive force interactive I/O\n"
" -line set output mode to 'line'\n" " -line set output mode to 'line'\n"
" -list set output mode to 'list'\n" " -list set output mode to 'list'\n"
" -mmap N default mmap size set to N\n"
#ifdef SQLITE_ENABLE_MULTIPLEX #ifdef SQLITE_ENABLE_MULTIPLEX
" -multiplex enable the multiplexor VFS\n" " -multiplex enable the multiplexor VFS\n"
#endif #endif
@ -3001,12 +3039,7 @@ int main(int argc, char **argv){
sqlite3_int64 szHeap; sqlite3_int64 szHeap;
zSize = cmdline_option_value(argc, argv, ++i); zSize = cmdline_option_value(argc, argv, ++i);
szHeap = atoi(zSize); szHeap = integerValue(zSize);
for(j=0; (c = zSize[j])!=0; j++){
if( c=='M' ){ szHeap *= 1000000; break; }
if( c=='K' ){ szHeap *= 1000; break; }
if( c=='G' ){ szHeap *= 1000000000; break; }
}
if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000; if( szHeap>0x7fff0000 ) szHeap = 0x7fff0000;
sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64); sqlite3_config(SQLITE_CONFIG_HEAP, malloc((int)szHeap), (int)szHeap, 64);
#endif #endif
@ -3026,6 +3059,8 @@ int main(int argc, char **argv){
extern int sqlite3_multiple_initialize(const char*,int); extern int sqlite3_multiple_initialize(const char*,int);
sqlite3_multiplex_initialize(0, 1); sqlite3_multiplex_initialize(0, 1);
#endif #endif
}else if( strcmp(z,"-mmap")==0 ){
sqlite3_config(SQLITE_CONFIG_MMAP_LIMIT, integerValue(cmdline_option_value(argc,argv,++i)));
}else if( strcmp(z,"-vfs")==0 ){ }else if( strcmp(z,"-vfs")==0 ){
sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i)); sqlite3_vfs *pVfs = sqlite3_vfs_find(cmdline_option_value(argc,argv,++i));
if( pVfs ){ if( pVfs ){
@ -3111,6 +3146,8 @@ int main(int argc, char **argv){
stdin_is_interactive = 0; stdin_is_interactive = 0;
}else if( strcmp(z,"-heap")==0 ){ }else if( strcmp(z,"-heap")==0 ){
i++; i++;
}else if( strcmp(z,"-mmap")==0 ){
i++;
}else if( strcmp(z,"-vfs")==0 ){ }else if( strcmp(z,"-vfs")==0 ){
i++; i++;
#ifdef SQLITE_ENABLE_VFSTRACE #ifdef SQLITE_ENABLE_VFSTRACE

View File

@ -470,6 +470,7 @@ int sqlite3_exec(
#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8))
#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8))
#define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8)) #define SQLITE_IOERR_DELETE_NOENT (SQLITE_IOERR | (23<<8))
#define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8))
#define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8))
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
@ -728,6 +729,9 @@ struct sqlite3_io_methods {
void (*xShmBarrier)(sqlite3_file*); void (*xShmBarrier)(sqlite3_file*);
int (*xShmUnmap)(sqlite3_file*, int deleteFlag); int (*xShmUnmap)(sqlite3_file*, int deleteFlag);
/* Methods above are valid for version 2 */ /* Methods above are valid for version 2 */
int (*xFetch)(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void **pp);
int (*xUnfetch)(sqlite3_file*, sqlite3_int64 iOfst, void *p);
/* Methods above are valid for version 3 */
/* Additional methods may be added in future releases */ /* Additional methods may be added in future releases */
}; };
@ -882,6 +886,12 @@ struct sqlite3_io_methods {
** written into memory obtained from [sqlite3_malloc()]. The caller should ** written into memory obtained from [sqlite3_malloc()]. The caller should
** invoke [sqlite3_free()] on the result to avoid a memory leak. ** invoke [sqlite3_free()] on the result to avoid a memory leak.
** **
** <li>[[SQLITE_FCNTL_MMAP_LIMIT]]
** The argument is assumed to pointer to a value of type sqlite3_int64 that
** is an advisory maximum number of bytes in the file to memory map. The
** pointer is overwritten with the old value. The limit is not changed if
** the original value pointed to is negative.
**
** </ul> ** </ul>
*/ */
#define SQLITE_FCNTL_LOCKSTATE 1 #define SQLITE_FCNTL_LOCKSTATE 1
@ -900,6 +910,7 @@ struct sqlite3_io_methods {
#define SQLITE_FCNTL_PRAGMA 14 #define SQLITE_FCNTL_PRAGMA 14
#define SQLITE_FCNTL_BUSYHANDLER 15 #define SQLITE_FCNTL_BUSYHANDLER 15
#define SQLITE_FCNTL_TEMPFILENAME 16 #define SQLITE_FCNTL_TEMPFILENAME 16
#define SQLITE_FCNTL_MMAP_LIMIT 18
/* /*
** CAPI3REF: Mutex Handle ** CAPI3REF: Mutex Handle
@ -1628,6 +1639,19 @@ struct sqlite3_mem_methods {
** points to has just been executed. Or, if the fourth parameter is 2, then ** points to has just been executed. Or, if the fourth parameter is 2, then
** the connection being passed as the second parameter is being closed. The ** the connection being passed as the second parameter is being closed. The
** third parameter is passed NULL In this case. ** third parameter is passed NULL In this case.
**
** [[SQLITE_CONFIG_MMAP_LIMIT]]
** <dt>SQLITE_CONFIG_MMAP_LIMIT
** <dd>The sole argument should be a 64-bit integer (an sqlite3_int64) that
** is the default maximum number of bytes of process address space that
** should be used for accessing each database file using memory mapping.
** The default setting can be overridden by each database connection using
** either the [PRAGMA mmap_limit] command or the "mmaplimit" query parameter
** on the [URI filename] when opening the databaes file or by using the
** [SQLITE_FCNTL_MMAP_LIMIT] file control. The value set here overrides the
** compile-time default that is set using the [SQLITE_DEFAULT_MMAP_LIMIT]
** compile-time option. If the argument to this option is negative, then
** the memory map limit is set to the compile-time default.
** </dl> ** </dl>
*/ */
#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
@ -1651,6 +1675,7 @@ struct sqlite3_mem_methods {
#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */ #define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */ #define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */ #define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
#define SQLITE_CONFIG_MMAP_LIMIT 22 /* sqlite3_int64 */
/* /*
** CAPI3REF: Database Connection Configuration Options ** CAPI3REF: Database Connection Configuration Options

View File

@ -834,6 +834,7 @@ struct sqlite3 {
int nDb; /* Number of backends currently in use */ int nDb; /* Number of backends currently in use */
int flags; /* Miscellaneous flags. See below */ int flags; /* Miscellaneous flags. See below */
i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 lastRowid; /* ROWID of most recent insert (see above) */
i64 mxMmap; /* Default mmap_limit setting */
unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */
int errCode; /* Most recent error code (SQLITE_*) */ int errCode; /* Most recent error code (SQLITE_*) */
int errMask; /* & result codes with this before returning */ int errMask; /* & result codes with this before returning */
@ -2505,6 +2506,7 @@ struct Sqlite3Config {
void *pHeap; /* Heap storage space */ void *pHeap; /* Heap storage space */
int nHeap; /* Size of pHeap[] */ int nHeap; /* Size of pHeap[] */
int mnReq, mxReq; /* Min and max heap requests sizes */ int mnReq, mxReq; /* Min and max heap requests sizes */
sqlite3_int64 mxMmap; /* Maximum mmap() space per open file */
void *pScratch; /* Scratch memory */ void *pScratch; /* Scratch memory */
int szScratch; /* Size of each scratch buffer */ int szScratch; /* Size of each scratch buffer */
int nScratch; /* Number of scratch buffers */ int nScratch; /* Number of scratch buffers */

View File

@ -206,3 +206,23 @@
#ifndef SQLITE_MAX_TRIGGER_DEPTH #ifndef SQLITE_MAX_TRIGGER_DEPTH
# define SQLITE_MAX_TRIGGER_DEPTH 1000 # define SQLITE_MAX_TRIGGER_DEPTH 1000
#endif #endif
/*
** Default maximum size of memory used by xFetch in the VFS.
*/
#ifdef __APPLE__
# include <TargetConditionals.h>
# if TARGET_OS_IPHONE
# define SQLITE_DEFAULT_MMAP_LIMIT 0
# endif
#endif
#ifndef SQLITE_DEFAULT_MMAP_LIMIT
# if defined(__linux__) \
|| defined(_WIN32) \
|| (defined(__APPLE__) && defined(__MACH__)) \
|| defined(__sun)
# define SQLITE_DEFAULT_MMAP_LIMIT 268435456 /* = 256*1024*1024 */
# else
# define SQLITE_DEFAULT_MMAP_LIMIT 0
# endif
#endif

View File

@ -5844,6 +5844,31 @@ static int test_test_control(
return TCL_OK; return TCL_OK;
} }
#if SQLITE_OS_UNIX
#include <sys/time.h>
#include <sys/resource.h>
static int test_getrusage(
void * clientData,
Tcl_Interp *interp,
int objc,
Tcl_Obj *CONST objv[]
){
char buf[1024];
struct rusage r;
memset(&r, 0, sizeof(r));
getrusage(RUSAGE_SELF, &r);
sprintf(buf, "ru_utime=%d.%06d ru_stime=%d.%06d ru_minflt=%d ru_majflt=%d",
(int)r.ru_utime.tv_sec, (int)r.ru_utime.tv_usec,
(int)r.ru_stime.tv_sec, (int)r.ru_stime.tv_usec,
(int)r.ru_minflt, (int)r.ru_majflt
);
Tcl_SetObjResult(interp, Tcl_NewStringObj(buf, -1));
return TCL_OK;
}
#endif
#if SQLITE_OS_WIN #if SQLITE_OS_WIN
/* /*
** Information passed from the main thread into the windows file locker ** Information passed from the main thread into the windows file locker
@ -6233,6 +6258,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
{ "print_explain_query_plan", test_print_eqp, 0 }, { "print_explain_query_plan", test_print_eqp, 0 },
#endif #endif
{ "sqlite3_test_control", test_test_control }, { "sqlite3_test_control", test_test_control },
#if SQLITE_OS_UNIX
{ "getrusage", test_getrusage },
#endif
}; };
static int bitmask_size = sizeof(Bitmask)*8; static int bitmask_size = sizeof(Bitmask)*8;
int i; int i;

View File

@ -23,7 +23,7 @@
** **
** open close access getcwd stat fstat ** open close access getcwd stat fstat
** ftruncate fcntl read pread pread64 write ** ftruncate fcntl read pread pread64 write
** pwrite pwrite64 fchmod fallocate ** pwrite pwrite64 fchmod fallocate mmap
** **
** test_syscall uninstall ** test_syscall uninstall
** Uninstall all wrapper functions. ** Uninstall all wrapper functions.
@ -81,6 +81,7 @@
/* From test1.c */ /* From test1.c */
extern const char *sqlite3TestErrorName(int); extern const char *sqlite3TestErrorName(int);
#include <sys/mman.h>
#include <sys/types.h> #include <sys/types.h>
#include <errno.h> #include <errno.h>
@ -106,7 +107,8 @@ static int ts_pwrite(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off); static int ts_pwrite64(int fd, const void *aBuf, size_t nBuf, off_t off);
static int ts_fchmod(int fd, mode_t mode); static int ts_fchmod(int fd, mode_t mode);
static int ts_fallocate(int fd, off_t off, off_t len); static int ts_fallocate(int fd, off_t off, off_t len);
static void *ts_mmap(void *, size_t, int, int, int, off_t);
static void *ts_mremap(void*, size_t, size_t, int, ...);
struct TestSyscallArray { struct TestSyscallArray {
const char *zName; const char *zName;
@ -131,6 +133,8 @@ struct TestSyscallArray {
/* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 }, /* 13 */ { "pwrite64", (sqlite3_syscall_ptr)ts_pwrite64, 0, 0, 0 },
/* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 }, /* 14 */ { "fchmod", (sqlite3_syscall_ptr)ts_fchmod, 0, 0, 0 },
/* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 }, /* 15 */ { "fallocate", (sqlite3_syscall_ptr)ts_fallocate, 0, 0, 0 },
/* 16 */ { "mmap", (sqlite3_syscall_ptr)ts_mmap, 0, 0, 0 },
/* 17 */ { "mremap", (sqlite3_syscall_ptr)ts_mremap, 0, 0, 0 },
{ 0, 0, 0, 0, 0 } { 0, 0, 0, 0, 0 }
}; };
@ -152,6 +156,8 @@ struct TestSyscallArray {
aSyscall[13].xOrig) aSyscall[13].xOrig)
#define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig) #define orig_fchmod ((int(*)(int,mode_t))aSyscall[14].xOrig)
#define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig) #define orig_fallocate ((int(*)(int,off_t,off_t))aSyscall[15].xOrig)
#define orig_mmap ((void*(*)(void*,size_t,int,int,int,off_t))aSyscall[16].xOrig)
#define orig_mremap ((void*(*)(void*,size_t,size_t,int,...))aSyscall[17].xOrig)
/* /*
** This function is called exactly once from within each invocation of a ** This function is called exactly once from within each invocation of a
@ -377,6 +383,31 @@ static int ts_fallocate(int fd, off_t off, off_t len){
return orig_fallocate(fd, off, len); return orig_fallocate(fd, off, len);
} }
static void *ts_mmap(
void *pAddr,
size_t nByte,
int prot,
int flags,
int fd,
off_t iOff
){
if( tsIsFailErrno("mmap") ){
return MAP_FAILED;
}
return orig_mmap(pAddr, nByte, prot, flags, fd, iOff);
}
static void *ts_mremap(void *a, size_t b, size_t c, int d, ...){
va_list ap;
void *pArg;
if( tsIsFailErrno("mremap") ){
return MAP_FAILED;
}
va_start(ap, d);
pArg = va_arg(ap, void *);
return orig_mremap(a, b, c, d, pArg);
}
static int test_syscall_install( static int test_syscall_install(
void * clientData, void * clientData,
Tcl_Interp *interp, Tcl_Interp *interp,

View File

@ -1208,7 +1208,7 @@ finished:
*/ */
if( pWal->hdr.nPage ){ if( pWal->hdr.nPage ){
sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s", sqlite3_log(SQLITE_OK, "Recovered %d frames from WAL file %s",
pWal->hdr.nPage, pWal->zWalName pWal->hdr.mxFrame, pWal->zWalName
); );
} }
} }
@ -1722,8 +1722,8 @@ static int walCheckpoint(
rc = sqlite3OsSync(pWal->pWalFd, sync_flags); rc = sqlite3OsSync(pWal->pWalFd, sync_flags);
} }
/* If the database file may grow as a result of this checkpoint, hint /* If the database may grow as a result of this checkpoint, hint
** about the eventual size of the db file to the VFS layer. ** about the eventual size of the db file to the VFS layer.
*/ */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
i64 nReq = ((i64)mxPage * szPage); i64 nReq = ((i64)mxPage * szPage);
@ -1733,6 +1733,7 @@ static int walCheckpoint(
} }
} }
/* Iterate through the contents of the WAL, copying data to the db file. */ /* Iterate through the contents of the WAL, copying data to the db file. */
while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){ while( rc==SQLITE_OK && 0==walIteratorNext(pIter, &iDbpage, &iFrame) ){
i64 iOffset; i64 iOffset;
@ -2287,19 +2288,17 @@ void sqlite3WalEndReadTransaction(Wal *pWal){
} }
/* /*
** Read a page from the WAL, if it is present in the WAL and if the ** Search the wal file for page pgno. If found, set *piRead to the frame that
** current read transaction is configured to use the WAL. ** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
** to zero.
** **
** The *pInWal is set to 1 if the requested page is in the WAL and ** Return SQLITE_OK if successful, or an error code if an error occurs. If an
** has been loaded. Or *pInWal is set to 0 if the page was not in ** error does occur, the final value of *piRead is undefined.
** the WAL and needs to be read out of the database.
*/ */
int sqlite3WalRead( int sqlite3WalFindFrame(
Wal *pWal, /* WAL handle */ Wal *pWal, /* WAL handle */
Pgno pgno, /* Database page number to read data for */ Pgno pgno, /* Database page number to read data for */
int *pInWal, /* OUT: True if data is read from WAL */ u32 *piRead /* OUT: Frame number (or zero) */
int nOut, /* Size of buffer pOut in bytes */
u8 *pOut /* Buffer to write page data to */
){ ){
u32 iRead = 0; /* If !=0, WAL frame to return data from */ u32 iRead = 0; /* If !=0, WAL frame to return data from */
u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */ u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
@ -2315,7 +2314,7 @@ int sqlite3WalRead(
** WAL were empty. ** WAL were empty.
*/ */
if( iLast==0 || pWal->readLock==0 ){ if( iLast==0 || pWal->readLock==0 ){
*pInWal = 0; *piRead = 0;
return SQLITE_OK; return SQLITE_OK;
} }
@ -2386,26 +2385,31 @@ int sqlite3WalRead(
} }
#endif #endif
/* If iRead is non-zero, then it is the log frame number that contains the *piRead = iRead;
** required page. Read and return data from the log file.
*/
if( iRead ){
int sz;
i64 iOffset;
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
*pInWal = 1;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
*pInWal = 0;
return SQLITE_OK; return SQLITE_OK;
} }
/*
** Read the contents of frame iRead from the wal file into buffer pOut
** (which is nOut bytes in size). Return SQLITE_OK if successful, or an
** error code otherwise.
*/
int sqlite3WalReadFrame(
Wal *pWal, /* WAL handle */
u32 iRead, /* Frame to read */
int nOut, /* Size of buffer pOut in bytes */
u8 *pOut /* Buffer to write page data to */
){
int sz;
i64 iOffset;
sz = pWal->hdr.szPage;
sz = (sz&0xfe00) + ((sz&0x0001)<<16);
testcase( sz<=32768 );
testcase( sz>=65536 );
iOffset = walFrameOffset(iRead, sz) + WAL_FRAME_HDRSIZE;
/* testcase( IS_BIG_INT(iOffset) ); // requires a 4GiB WAL */
return sqlite3OsRead(pWal->pWalFd, pOut, (nOut>sz ? sz : nOut), iOffset);
}
/* /*
** Return the size of the database in pages (or zero, if unknown). ** Return the size of the database in pages (or zero, if unknown).
@ -2952,6 +2956,9 @@ int sqlite3WalCheckpoint(
/* Read the wal-index header. */ /* Read the wal-index header. */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = walIndexReadHdr(pWal, &isChanged); rc = walIndexReadHdr(pWal, &isChanged);
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
}
} }
/* Copy data from the log to the database file. */ /* Copy data from the log to the database file. */

View File

@ -31,7 +31,6 @@
# define sqlite3WalClose(w,x,y,z) 0 # define sqlite3WalClose(w,x,y,z) 0
# define sqlite3WalBeginReadTransaction(y,z) 0 # define sqlite3WalBeginReadTransaction(y,z) 0
# define sqlite3WalEndReadTransaction(z) # define sqlite3WalEndReadTransaction(z)
# define sqlite3WalRead(v,w,x,y,z) 0
# define sqlite3WalDbsize(y) 0 # define sqlite3WalDbsize(y) 0
# define sqlite3WalBeginWriteTransaction(y) 0 # define sqlite3WalBeginWriteTransaction(y) 0
# define sqlite3WalEndWriteTransaction(x) 0 # define sqlite3WalEndWriteTransaction(x) 0
@ -71,7 +70,8 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *);
void sqlite3WalEndReadTransaction(Wal *pWal); void sqlite3WalEndReadTransaction(Wal *pWal);
/* Read a page from the write-ahead log, if it is present. */ /* Read a page from the write-ahead log, if it is present. */
int sqlite3WalRead(Wal *pWal, Pgno pgno, int *pInWal, int nOut, u8 *pOut); int sqlite3WalFindFrame(Wal *, Pgno, u32 *);
int sqlite3WalReadFrame(Wal *, u32, int, u8 *);
/* If the WAL is not empty, return the size of the database. */ /* If the WAL is not empty, return the size of the database. */
Pgno sqlite3WalDbsize(Wal *pWal); Pgno sqlite3WalDbsize(Wal *pWal);

50
test/btreefault.test Normal file
View File

@ -0,0 +1,50 @@
# 2013 April 02
#
# 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 contains fault injection tests designed to test the btree.c
# module.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
set testprefix btreefault
do_test 1-pre1 {
execsql {
PRAGMA auto_vacuum = incremental;
PRAGMA journal_mode = DELETE;
CREATE TABLE t1(a PRIMARY KEY, b);
INSERT INTO t1 VALUES(randomblob(1000), randomblob(100));
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
DELETE FROM t1 WHERE rowid%2;
}
faultsim_save_and_close
} {}
do_faultsim_test 1 -prep {
faultsim_restore_and_reopen
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY]
sqlite3_step $::STMT
sqlite3_step $::STMT
} -body {
execsql { PRAGMA incremental_vacuum = 10 }
} -test {
sqlite3_finalize $::STMT
faultsim_test_result {0 {}}
faultsim_integrity_check
}
finish_test

View File

@ -40,6 +40,7 @@ proc db_write {db {reset 0}} {
do_test 1.1 { do_test 1.1 {
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { PRAGMA mmap_limit = 0 }
expr {[file size test.db] / 1024} expr {[file size test.db] / 1024}
} 6 } 6

View File

@ -25,6 +25,14 @@ ifcapable {!pager_pragmas} {
return return
} }
# Tests in this file verify that locking_mode=exclusive causes SQLite to
# use cached pages even if the database is changed on disk. This doesn't
# work with mmap.
if {[permutation]!="nommap"} {
finish_test
return
}
# This module does not work right if the cache spills at unexpected # This module does not work right if the cache spills at unexpected
# moments. So disable the soft-heap-limit. # moments. So disable the soft-heap-limit.
# #

View File

@ -1273,11 +1273,13 @@ do_test func-29.3 {
sqlite3_db_status db CACHE_MISS 1 sqlite3_db_status db CACHE_MISS 1
db eval {SELECT typeof(+x) FROM t29 ORDER BY id} db eval {SELECT typeof(+x) FROM t29 ORDER BY id}
} {integer null real blob text} } {integer null real blob text}
do_test func-29.4 { if {[permutation] == "nommap"} {
set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1] do_test func-29.4 {
if {$x>100} {set x many} set x [lindex [sqlite3_db_status db CACHE_MISS 1] 1]
set x if {$x>100} {set x many}
} {many} set x
} {many}
}
do_test func-29.5 { do_test func-29.5 {
db close db close
sqlite3 db test.db sqlite3 db test.db

View File

@ -123,6 +123,7 @@ foreach AutoVacuumMode [list 0 1] {
forcedelete test.db test.db-journal forcedelete test.db test.db-journal
sqlite3 db test.db sqlite3 db test.db
execsql "PRAGMA mmap_limit = 0"
execsql "PRAGMA auto_vacuum = $AutoVacuumMode" execsql "PRAGMA auto_vacuum = $AutoVacuumMode"
do_test incrblob-2.$AutoVacuumMode.1 { do_test incrblob-2.$AutoVacuumMode.1 {
@ -149,6 +150,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty. # Open and close the db to make sure the page cache is empty.
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql "PRAGMA mmap_limit = 0"
# Read the last 20 bytes of the blob via a blob handle. # Read the last 20 bytes of the blob via a blob handle.
set ::blob [db incrblob blobs v 1] set ::blob [db incrblob blobs v 1]
@ -171,6 +173,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty. # Open and close the db to make sure the page cache is empty.
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql "PRAGMA mmap_limit = 0"
# Write the second-to-last 20 bytes of the blob via a blob handle. # Write the second-to-last 20 bytes of the blob via a blob handle.
# #
@ -200,6 +203,7 @@ foreach AutoVacuumMode [list 0 1] {
# Open and close the db to make sure the page cache is empty. # Open and close the db to make sure the page cache is empty.
db close db close
sqlite3 db test.db sqlite3 db test.db
execsql { PRAGMA mmap_limit = 0 }
execsql { SELECT i FROM blobs } execsql { SELECT i FROM blobs }
} {45} } {45}

View File

@ -264,7 +264,7 @@ proc faultsim_test_result_int {args} {
set t [list $testrc $testresult] set t [list $testrc $testresult]
set r $args set r $args
if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } { if { ($testnfail==0 && $t != [lindex $r 0]) || [lsearch $r $t]<0 } {
error "nfail=$testnfail rc=$testrc result=$testresult" error "nfail=$testnfail rc=$testrc result=$testresult list=$r"
} }
} }

250
test/mmap1.test Normal file
View File

@ -0,0 +1,250 @@
# 2013 March 20
#
# 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.
#
#***********************************************************************
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/lock_common.tcl
set testprefix mmap1
proc nRead {db} {
set bt [btree_from_db $db]
db_enter $db
array set stats [btree_pager_stats $bt]
db_leave $db
# puts [array get stats]
return $stats(read)
}
foreach {t mmap_limit nRead c2init} {
1.1 { PRAGMA mmap_limit = 67108864 } 4 {}
1.2 { PRAGMA mmap_limit = 53248 } 150 {}
1.3 { PRAGMA mmap_limit = 0 } 344 {}
1.4 { PRAGMA mmap_limit = 67108864 } 4 {PRAGMA mmap_limit = 67108864 }
1.5 { PRAGMA mmap_limit = 53248 } 150 {PRAGMA mmap_limit = 67108864 }
1.6 { PRAGMA mmap_limit = 0 } 344 {PRAGMA mmap_limit = 67108864 }
} {
do_multiclient_test tn {
sql1 {PRAGMA page_size=1024}
sql1 $mmap_limit
sql2 $c2init
code2 {
set ::rcnt 0
proc rblob {n} {
set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
string range [string repeat $str [expr $n/4]] 1 $n
}
db2 func rblob rblob
}
sql2 {
PRAGMA page_size=1024;
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
}
do_test $t.$tn.1 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {32 ok 77}
# Have connection 2 shrink the file. Check connection 1 can still read it.
sql2 { DELETE FROM t1 WHERE rowid%2; }
do_test $t.$tn.2 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {16 ok 42}
# Have connection 2 grow the file. Check connection 1 can still read it.
sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
do_test $t.$tn.3 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {32 ok 79}
# Have connection 2 grow the file again. Check connection 1 is still ok.
sql2 { INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1 }
do_test $t.$tn.4 {
sql1 "SELECT count(*) FROM t1; PRAGMA integrity_check ; PRAGMA page_count"
} {64 ok 149}
# Check that the number of pages read by connection 1 indicates that the
# "PRAGMA mmap_limit" command worked.
do_test $t.$tn.5 { nRead db } $nRead
}
}
set ::rcnt 0
proc rblob {n} {
set ::rcnt [expr (($::rcnt << 3) + $::rcnt + 456) & 0xFFFFFFFF]
set str [format %.8x [expr $::rcnt ^ 0xbdf20da3]]
string range [string repeat $str [expr $n/4]] 1 $n
}
reset_db
db func rblob rblob
do_execsql_test 2.1 {
PRAGMA auto_vacuum = 1;
PRAGMA mmap_limit = 67108864;
PRAGMA journal_mode = wal;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 32
PRAGMA wal_checkpoint;
} {67108864 wal 0 103 103}
do_execsql_test 2.2 {
PRAGMA auto_vacuum;
SELECT count(*) FROM t1;
} {1 32}
do_test 2.3 {
sqlite3 db2 test.db
db2 func rblob rblob
db2 eval {
DELETE FROM t1 WHERE (rowid%4);
PRAGMA wal_checkpoint;
}
db2 eval {
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 16
SELECT count(*) FROM t1;
}
} {16}
do_execsql_test 2.4 {
PRAGMA wal_checkpoint;
} {0 24 24}
db2 close
reset_db
db func rblob rblob
do_execsql_test 3.1 {
PRAGMA auto_vacuum = 1;
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(rblob(500), rblob(500));
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 2
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 4
INSERT INTO t1 SELECT rblob(500), rblob(500) FROM t1; -- 8
CREATE TABLE t2(a, b, UNIQUE(a, b));
INSERT INTO t2 SELECT * FROM t1;
} {}
do_test 3.2 {
set nRow 0
db eval {SELECT * FROM t2 ORDER BY a, b} {
if {$nRow==4} { db eval { DELETE FROM t1 } }
incr nRow
}
set nRow
} {8}
#-------------------------------------------------------------------------
# Ensure that existing cursors using xFetch() pages see changes made
# to rows using the incrblob API.
#
reset_db
set aaa [string repeat a 400]
set bbb [string repeat b 400]
set ccc [string repeat c 400]
set ddd [string repeat d 400]
set eee [string repeat e 400]
do_execsql_test 4.1 {
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES($aaa);
INSERT INTO t1 VALUES($bbb);
INSERT INTO t1 VALUES($ccc);
INSERT INTO t1 VALUES($ddd);
SELECT * FROM t1;
BEGIN;
} [list $aaa $bbb $ccc $ddd]
do_test 4.2 {
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $aaa
do_test 4.3 {
foreach r {2 3 4} {
set fd [db incrblob t1 x $r]
puts -nonewline $fd $eee
close $fd
}
set res [list]
while {"SQLITE_ROW" == [sqlite3_step $::STMT]} {
lappend res [sqlite3_column_text $::STMT 0]
}
set res
} [list $eee $eee $eee]
do_test 4.4 {
sqlite3_finalize $::STMT
} SQLITE_OK
do_execsql_test 4.5 { COMMIT }
#-------------------------------------------------------------------------
# Ensure that existing cursors holding xFetch() references are not
# confused if those pages are moved to make way for the root page of a
# new table or index.
#
reset_db
do_execsql_test 5.1 {
PRAGMA auto_vacuum = 2;
PRAGMA page_size = 1024;
CREATE TABLE t1(x);
INSERT INTO t1 VALUES($aaa);
INSERT INTO t1 VALUES($bbb);
INSERT INTO t1 VALUES($ccc);
INSERT INTO t1 VALUES($ddd);
PRAGMA auto_vacuum;
SELECT * FROM t1;
} [list 2 $aaa $bbb $ccc $ddd]
do_test 5.2 {
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY rowid" -1 dummy]
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $aaa
do_execsql_test 5.3 {
CREATE TABLE t2(x);
INSERT INTO t2 VALUES('tricked you!');
INSERT INTO t2 VALUES('tricked you!');
}
do_test 5.4 {
sqlite3_step $::STMT
sqlite3_column_text $::STMT 0
} $bbb
do_test 5.5 {
sqlite3_finalize $::STMT
} SQLITE_OK
finish_test

82
test/mmap2.test Normal file
View File

@ -0,0 +1,82 @@
# 2013 March 20
#
# 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 tests the effect of the mmap() or mremap() system calls
# returning an error on the library.
#
# If either mmap() or mremap() fails, SQLite should log an error
# message, then continue accessing the database using read() and
# write() exclusively.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix mmap2
if {$::tcl_platform(platform)!="unix" || [test_syscall defaultvfs] != "unix"} {
finish_test
return
}
db close
sqlite3_shutdown
test_sqlite3_log xLog
proc xLog {error_code msg} {
if {[string match os_unix.c* $msg]} {
lappend ::log $msg
}
}
foreach syscall {mmap mremap} {
test_syscall uninstall
if {[catch {test_syscall install $syscall}]} continue
for {set i 1} {$i < 20} {incr i} {
reset_db
test_syscall fault $i 1
test_syscall errno $syscall ENOMEM
set ::log ""
do_execsql_test 1.$syscall.$i.1 {
CREATE TABLE t1(a, b, UNIQUE(a, b));
INSERT INTO t1 VALUES(randomblob(1000), randomblob(1000));
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
INSERT INTO t1 SELECT randomblob(1000), randomblob(1000) FROM t1;
}
set nFail [test_syscall fault 0 0]
do_execsql_test 1.$syscall.$i.2 {
SELECT count(*) FROM t1;
PRAGMA integrity_check;
} {64 ok}
do_test 1.$syscall.$i.3 {
expr {$nFail==0 || $nFail==1}
} {1}
do_test 1.$syscall.$i.4.nFail=$nFail {
regexp ".*${syscall}.*" $::log
} [expr $nFail>0]
}
}
db close
test_syscall uninstall
sqlite3_shutdown
test_sqlite3_log
sqlite3_initialize
finish_test

View File

@ -1246,5 +1246,62 @@ do_faultsim_test pagerfault-27 -faults ioerr-persistent -prep {
faultsim_integrity_check faultsim_integrity_check
} }
#-------------------------------------------------------------------------
#
do_test pagerfault-28-pre {
faultsim_delete_and_reopen
db func a_string a_string
execsql {
PRAGMA page_size = 512;
PRAGMA journal_mode = wal;
PRAGMA wal_autocheckpoint = 0;
PRAGMA cache_size = 100000;
BEGIN;
CREATE TABLE t2(a UNIQUE, b UNIQUE);
INSERT INTO t2 VALUES( a_string(800), a_string(800) );
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
INSERT INTO t2 SELECT a_string(800), a_string(800) FROM t2;
COMMIT;
CREATE TABLE t1(a PRIMARY KEY, b);
}
expr {[file size test.db-shm] >= 96*1024}
} {1}
faultsim_save_and_close
do_faultsim_test pagerfault-28 -faults oom* -prep {
faultsim_restore_and_reopen
execsql { PRAGMA mmap_limit=0 }
sqlite3 db2 test.db
db2 eval { SELECT count(*) FROM t2 }
db func a_string a_string
execsql {
BEGIN;
INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
INSERT INTO t1 VALUES(a_string(2000), a_string(2000));
}
set ::STMT [sqlite3_prepare db "SELECT * FROM t1 ORDER BY a" -1 DUMMY]
sqlite3_step $::STMT
} -body {
execsql { ROLLBACK }
} -test {
db2 close
sqlite3_finalize $::STMT
catchsql { ROLLBACK }
faultsim_integrity_check
}
finish_test finish_test

View File

@ -92,7 +92,7 @@ do_test pageropt-1.5 {
pagercount_sql { pagercount_sql {
SELECT hex(x) FROM t1 SELECT hex(x) FROM t1
} }
} [list 6 0 0 $blobcontent] } [list [expr {[permutation]=="nommap" ? 6 : 1}] 0 0 $blobcontent]
do_test pageropt-1.6 { do_test pageropt-1.6 {
pagercount_sql { pagercount_sql {
SELECT hex(x) FROM t1 SELECT hex(x) FROM t1

View File

@ -138,6 +138,14 @@ test_suite "veryquick" -prefix "" -description {
test_set $allquicktests -exclude *malloc* *ioerr* *fault* test_set $allquicktests -exclude *malloc* *ioerr* *fault*
] ]
test_suite "nommap" -prefix "nomm-" -description {
Similar to veryquick. Except with memory mapping disabled.
} -presql {
pragma mmap_limit = 0;
} -files [
test_set $allquicktests -exclude *malloc* *ioerr* *fault* -include malloc.test
]
test_suite "valgrind" -prefix "" -description { test_suite "valgrind" -prefix "" -description {
Run the "veryquick" test suite with a couple of multi-process tests (that Run the "veryquick" test suite with a couple of multi-process tests (that
fail under valgrind) omitted. fail under valgrind) omitted.

View File

@ -24,6 +24,8 @@ set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
speed_trial_init speed1 speed_trial_init speed1
sqlite3_memdebug_vfs_oom_test 0
# Set a uniform random seed # Set a uniform random seed
expr srand(0) expr srand(0)
@ -78,7 +80,6 @@ do_test speed1p-1.0 {
} }
} {i2a i2b t1 t2} } {i2a i2b t1 t2}
# 50000 INSERTs on an unindexed table # 50000 INSERTs on an unindexed table
# #
set list {} set list {}

View File

@ -60,7 +60,7 @@ 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 fchown umask statvfs fchown umask mmap munmap mremap
} { } {
if {[test_syscall exists $s]} {lappend syscall_list $s} if {[test_syscall exists $s]} {lappend syscall_list $s}
} }

View File

@ -243,5 +243,35 @@ do_faultsim_test 3 -faults vfsfault-* -prep {
faultsim_test_result {0 20000} faultsim_test_result {0 20000}
} }
finish_test #-------------------------------------------------------------------------
# Test errors in mmap().
#
proc vfsfault_install {} {
test_syscall reset
test_syscall install {mmap}
}
faultsim_delete_and_reopen
execsql {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 2);
}
faultsim_save_and_close
do_faultsim_test 4 -faults vfsfault-* -prep {
faultsim_restore_and_reopen
file_control_chunksize_test db main 8192
execsql {
PRAGMA mmap_limit = 1000000;
}
} -body {
test_syscall errno mmap EACCES
execsql {
SELECT * FROM t1;
}
} -test {
faultsim_test_result {0 {1 2}} {1 {disk I/O error}}
}
finish_test

View File

@ -727,6 +727,8 @@ do_test wal-11.9 {
list [expr [file size test.db]/1024] [log_deleted test.db-wal] list [expr [file size test.db]/1024] [log_deleted test.db-wal]
} {37 1} } {37 1}
sqlite3_wal db test.db sqlite3_wal db test.db
set nWal 39
if {[permutation]=="nommap"} {set nWal 37}
do_test wal-11.10 { do_test wal-11.10 {
execsql { execsql {
PRAGMA cache_size = 10; PRAGMA cache_size = 10;
@ -735,7 +737,7 @@ do_test wal-11.10 {
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
} }
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]] } [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.11 { do_test wal-11.11 {
execsql { execsql {
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
@ -745,7 +747,7 @@ do_test wal-11.11 {
} {32 16} } {32 16}
do_test wal-11.12 { do_test wal-11.12 {
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]] } [list 37 [wal_file_size $nWal 1024]]
do_test wal-11.13 { do_test wal-11.13 {
execsql { execsql {
INSERT INTO t1 VALUES( blob(900) ); INSERT INTO t1 VALUES( blob(900) );
@ -755,7 +757,7 @@ do_test wal-11.13 {
} {17 ok} } {17 ok}
do_test wal-11.14 { do_test wal-11.14 {
list [expr [file size test.db]/1024] [file size test.db-wal] list [expr [file size test.db]/1024] [file size test.db-wal]
} [list 37 [wal_file_size 37 1024]] } [list 37 [wal_file_size $nWal 1024]]
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -1567,6 +1569,26 @@ ifcapable autovacuum {
} [wal_file_size 1 1024] } [wal_file_size 1 1024]
} }
reset_db
do_test 25 {
sqlite3 db test.db
execsql {
CREATE TABLE t1(x, y);
PRAGMA journal_mode = WAL;
INSERT INTO t1 VALUES(1, 2);
}
execsql {
BEGIN;
CREATE TABLE t2(a, b);
}
hexio_write test.db-shm [expr 16*1024] [string repeat 0055 8192]
catchsql ROLLBACK
} {0 {}}
db close db close
sqlite3_shutdown sqlite3_shutdown
test_sqlite3_log test_sqlite3_log

View File

@ -235,7 +235,15 @@ foreach {testprefix do_wal_checkpoint} {
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 4 1 4} 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 4 3} 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 4 2 4}
# The checkpoint above only writes page 1 of the db file. The other
# page (page 2) is locked by the read-transaction opened by the
# [sql2] commmand above. So normally, the db is 1 page in size here.
# However, in mmap() mode, the db is pre-allocated to 2 pages at the
# start of the checkpoint, even though page 2 cannot be written.
set nDb 2
if {[permutation]=="no-mmap"} {set nDb 1}
do_test 2.3.$tn.8 { file_page_counts } [list $nDb 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
@ -343,4 +351,3 @@ foreach {testprefix do_wal_checkpoint} {
finish_test finish_test