mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-22 20:22:44 +03:00
Changes to avoid deadlock in SQLITE_ENABLE_SETLK_TIMEOUT builds.
FossilOrigin-Name: 652e4b23fffbff128b177697d7217b7d5aad8baf2364df1646b268ce6774e0fb
This commit is contained in:
1
main.mk
1
main.mk
@@ -423,6 +423,7 @@ TESTSRC2 = \
|
|||||||
$(TOP)/src/vdbeaux.c \
|
$(TOP)/src/vdbeaux.c \
|
||||||
$(TOP)/src/vdbe.c \
|
$(TOP)/src/vdbe.c \
|
||||||
$(TOP)/src/vdbemem.c \
|
$(TOP)/src/vdbemem.c \
|
||||||
|
$(TOP)/src/vdbevtab.c \
|
||||||
$(TOP)/src/where.c \
|
$(TOP)/src/where.c \
|
||||||
$(TOP)/src/wherecode.c \
|
$(TOP)/src/wherecode.c \
|
||||||
$(TOP)/src/whereexpr.c \
|
$(TOP)/src/whereexpr.c \
|
||||||
|
|||||||
35
manifest
35
manifest
@@ -1,5 +1,5 @@
|
|||||||
C Fix\sthe\shandling\sof\sreserve-bytes\sso\sthat\sthe\smaximum\svalue\sof\s255\scan\sbe\sused.
|
C Changes\sto\savoid\sdeadlock\sin\sSQLITE_ENABLE_SETLK_TIMEOUT\sbuilds.
|
||||||
D 2020-05-07T01:56:57.057
|
D 2020-05-07T14:39:56.994
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||||
@@ -455,7 +455,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865
|
|||||||
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
|
||||||
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
|
||||||
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
|
||||||
F main.mk 0c20162946c82e216ae3abab6334d52f1c9b09035c13619ade404b5e7fe3ce21
|
F main.mk addd0a300e90ad090dc4a934df8a6f1b6c52c057a1aebb93682aed29fb68a345
|
||||||
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
|
||||||
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
|
||||||
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
|
||||||
@@ -474,7 +474,7 @@ F src/auth.c a3d5bfdba83d25abed1013a8c7a5f204e2e29b0c25242a56bc02bb0c07bf1e06
|
|||||||
F src/backup.c b1c90cd4110248c8e1273ff4578d3a84c0c34725e1b96dacd4a6294a908702de
|
F src/backup.c b1c90cd4110248c8e1273ff4578d3a84c0c34725e1b96dacd4a6294a908702de
|
||||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||||
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
|
||||||
F src/btree.c b7b9b444d083f135ad0bfe973ba118916a25085160bae4afcbc232886aeb153a
|
F src/btree.c f14e415fcfd0b52b4e4ebd193ba5fadac5e8252c30f023389af682813af44025
|
||||||
F src/btree.h 989ef3c33413549e3e148f3dcb46c030f317dac130dc86809ba6b9aa4b16c72a
|
F src/btree.h 989ef3c33413549e3e148f3dcb46c030f317dac130dc86809ba6b9aa4b16c72a
|
||||||
F src/btreeInt.h 5c8b8749805787313ecf49eb5be3ced1e94bbf8ef54bb01470ce6bd0d5185c67
|
F src/btreeInt.h 5c8b8749805787313ecf49eb5be3ced1e94bbf8ef54bb01470ce6bd0d5185c67
|
||||||
F src/build.c 5566b570435d3511a0fd57388c124491b1f74e59561f0c1679fabe74c4c54b7a
|
F src/build.c 5566b570435d3511a0fd57388c124491b1f74e59561f0c1679fabe74c4c54b7a
|
||||||
@@ -497,7 +497,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
|||||||
F src/insert.c 8e4211d04eb460c0694d486c6ba1c068d468c6f653c3f237869a802ad82854de
|
F src/insert.c 8e4211d04eb460c0694d486c6ba1c068d468c6f653c3f237869a802ad82854de
|
||||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||||
F src/loadext.c 421310045bd78afefb772294a99e50f37d87ae578786a6169074e6291e30d969
|
F src/loadext.c 421310045bd78afefb772294a99e50f37d87ae578786a6169074e6291e30d969
|
||||||
F src/main.c d832077d7a1e269c7c0e15ae845fcf80690a2880cb6520ef61f182c6631644f1
|
F src/main.c 266393c10ff58d0919941f3187b54c0144b27d2f3fab8ae849eefbb89c48c451
|
||||||
F src/malloc.c a3e13b001f988ecec6bdb90c0ea8912c8c786e623724d7098da623d8d01d19b1
|
F src/malloc.c a3e13b001f988ecec6bdb90c0ea8912c8c786e623724d7098da623d8d01d19b1
|
||||||
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
|
||||||
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
|
||||||
@@ -517,11 +517,11 @@ F src/os.c 669cc3839cc35d20f81faf0be1ab6d4581cea35e9d8f3a9d48a98d6571f7c285
|
|||||||
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
|
||||||
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
|
||||||
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
||||||
F src/os_unix.c 7ef8b60222558a373d89c18d0c3bc44365b45273a528183d40bec5bb76ce23fc
|
F src/os_unix.c 13f983da988b6460ef3c4c22099c67ab0938291e543644ac4d99eccc8ba604f1
|
||||||
F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
|
F src/os_win.c 035a813cbd17f355bdcad7ab894af214a9c13a1db8aeac902365350b98cd45a7
|
||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c 52cee2f72710be47b5b13ff66b339ca3855e5bc48e92a94114d2affedc70041f
|
F src/pager.c 96436cb1920074d4ade120a1a8a9d0ae3f52df06651e21b7eccc5eae2f02b111
|
||||||
F src/pager.h 3b33619a90180e0874c7eca31d6f6ceb464d9322c6fb4e9a7bbb318c8a17bdb3
|
F src/pager.h 8d1dc9a2c3fc5eb6eeed75f48a076f425e77706f8935f05817fa05a308f587b5
|
||||||
F src/parse.y c8eff38606f443d5ba245263fa7abc05e4116d95656e050c4b78e9bfbf931add
|
F src/parse.y c8eff38606f443d5ba245263fa7abc05e4116d95656e050c4b78e9bfbf931add
|
||||||
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
F src/pcache.c 385ff064bca69789d199a98e2169445dc16e4291fa807babd61d4890c3b34177
|
||||||
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
|
||||||
@@ -535,10 +535,10 @@ F src/resolve.c d36a2b1639e1c33d7b508abfd3452a63e7fd81737f6f3940bfef085fca6f21f4
|
|||||||
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
|
||||||
F src/select.c 1720bff2168491ca79af81a03bd18c0383f61d845c6e17caff9d25aabc4ab435
|
F src/select.c 1720bff2168491ca79af81a03bd18c0383f61d845c6e17caff9d25aabc4ab435
|
||||||
F src/shell.c.in cf2d24f54412c06e5fb34af7fabc748651125e1dceac29b740e91f06d23447b6
|
F src/shell.c.in cf2d24f54412c06e5fb34af7fabc748651125e1dceac29b740e91f06d23447b6
|
||||||
F src/sqlite.h.in fa97fb128377b8fd8398a498eda3d48646b08519c4176adb1457243fdc5bb09a
|
F src/sqlite.h.in a42bae930f462294801f24468dd56832b09de01072a26dc0df60ddc3c5602210
|
||||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||||
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
|
F src/sqlite3ext.h 2d1af80082edffd71c6f96f70ad1ce6a4fb46615ad10291fc77fe0dea9ff0197
|
||||||
F src/sqliteInt.h 1f6909cd268d1cda2f04914d150997b17afd8ff7e5cf1930cc1f88d337a49f74
|
F src/sqliteInt.h 9d2caeaee7a317af536a60fcd828425da5d64c4f26aac5356f13dce1de3cb066
|
||||||
F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032
|
F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032
|
||||||
F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
|
F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278
|
||||||
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
|
||||||
@@ -617,8 +617,8 @@ F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143
|
|||||||
F src/vdbevtab.c 8094dfc28dad82d60a1c832020a1b201a5381dc185c14638affc6d4e9d54c653
|
F src/vdbevtab.c 8094dfc28dad82d60a1c832020a1b201a5381dc185c14638affc6d4e9d54c653
|
||||||
F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
|
F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515
|
||||||
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
|
||||||
F src/wal.c 8efa749ff1e84fb69127bdab1d0f3545afc1706f4dde6f19f2f6237d7dc9c2d2
|
F src/wal.c fdbf7641be6fa6e57f86484e8b5ffe816dffae176c4fd72a9b76e5e0b99bf6dd
|
||||||
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
|
F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a
|
||||||
F src/walker.c 7c429c694abd12413a5c17aec9f47cfe9eba6807e6b0a32df883e8e3a14835ed
|
F src/walker.c 7c429c694abd12413a5c17aec9f47cfe9eba6807e6b0a32df883e8e3a14835ed
|
||||||
F src/where.c 9546c82056e8cdb27291f98cf1adca5d271240b399bb97b32f77fc2bea6146c9
|
F src/where.c 9546c82056e8cdb27291f98cf1adca5d271240b399bb97b32f77fc2bea6146c9
|
||||||
F src/whereInt.h 6b874aa15f94e43a2cec1080be64d955b04deeafeac90ffb5d6975c0d511be3c
|
F src/whereInt.h 6b874aa15f94e43a2cec1080be64d955b04deeafeac90ffb5d6975c0d511be3c
|
||||||
@@ -1658,7 +1658,7 @@ F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c37
|
|||||||
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
|
F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
|
||||||
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
|
||||||
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12
|
||||||
F test/wal.test cdf0ca6cc0447520d19ef1c83287824ebeb3e82d75af856511ba96841a79fc9b
|
F test/wal.test 16180bc4becda176428ad02eaea437b4b8f5ae099314de443a4e12b2dcc007a2
|
||||||
F test/wal2.test 537f59e5c5932e3b45bf3591ae3e48a2601360c2e52821b633e222fe6ebd5b09
|
F test/wal2.test 537f59e5c5932e3b45bf3591ae3e48a2601360c2e52821b633e222fe6ebd5b09
|
||||||
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
|
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
|
||||||
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
|
||||||
@@ -1689,6 +1689,7 @@ F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db8
|
|||||||
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
|
F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20
|
||||||
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
|
F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768
|
||||||
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
|
F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
|
||||||
|
F test/walsetlk.test 11f7fe792fdce54cf09874dab824e0627f2eedecfb9f7983e325606ec5184e0c
|
||||||
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417
|
||||||
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
F test/walslow.test c05c68d4dc2700a982f89133ce103a1a84cc285f
|
||||||
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
|
F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
|
||||||
@@ -1863,7 +1864,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 63e659d9a793227604aa95685a8d83cd08305f1d01e135407a3ffc6d54482ab8
|
P 99749d4fd4930ccf15227f67c732266af9e09dd3cabdc0834fb450ef98196441 49e4dc72f7a4b28e4b49d7b91030bc986aea3ff44dac38cb6e68305800cd1de5
|
||||||
R 40c51b3c9fb1a999bf30ad6cc83f2430
|
R 22b4478e3cf3c244a4ab3e6943ce3c12
|
||||||
U drh
|
U dan
|
||||||
Z 4244c9fee796a92a9333ce7d1083a8fb
|
Z cc31196848103ce16439278453597677
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
99749d4fd4930ccf15227f67c732266af9e09dd3cabdc0834fb450ef98196441
|
652e4b23fffbff128b177697d7217b7d5aad8baf2364df1646b268ce6774e0fb
|
||||||
28
src/btree.c
28
src/btree.c
@@ -2304,8 +2304,7 @@ static int btreeInvokeBusyHandler(void *pArg){
|
|||||||
BtShared *pBt = (BtShared*)pArg;
|
BtShared *pBt = (BtShared*)pArg;
|
||||||
assert( pBt->db );
|
assert( pBt->db );
|
||||||
assert( sqlite3_mutex_held(pBt->db->mutex) );
|
assert( sqlite3_mutex_held(pBt->db->mutex) );
|
||||||
return sqlite3InvokeBusyHandler(&pBt->db->busyHandler,
|
return sqlite3InvokeBusyHandler(&pBt->db->busyHandler);
|
||||||
sqlite3PagerFile(pBt->pPager));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -3372,6 +3371,7 @@ int sqlite3BtreeNewDb(Btree *p){
|
|||||||
*/
|
*/
|
||||||
int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
||||||
BtShared *pBt = p->pBt;
|
BtShared *pBt = p->pBt;
|
||||||
|
Pager *pPager = pBt->pPager;
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
|
|
||||||
sqlite3BtreeEnter(p);
|
sqlite3BtreeEnter(p);
|
||||||
@@ -3387,7 +3387,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
|||||||
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
|
assert( pBt->inTransaction==TRANS_WRITE || IfNotOmitAV(pBt->bDoTruncate)==0 );
|
||||||
|
|
||||||
if( (p->db->flags & SQLITE_ResetDatabase)
|
if( (p->db->flags & SQLITE_ResetDatabase)
|
||||||
&& sqlite3PagerIsreadonly(pBt->pPager)==0
|
&& sqlite3PagerIsreadonly(pPager)==0
|
||||||
){
|
){
|
||||||
pBt->btsFlags &= ~BTS_READ_ONLY;
|
pBt->btsFlags &= ~BTS_READ_ONLY;
|
||||||
}
|
}
|
||||||
@@ -3435,6 +3435,18 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
|||||||
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
|
pBt->btsFlags &= ~BTS_INITIALLY_EMPTY;
|
||||||
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
|
if( pBt->nPage==0 ) pBt->btsFlags |= BTS_INITIALLY_EMPTY;
|
||||||
do {
|
do {
|
||||||
|
sqlite3PagerWalDb(pPager, p->db);
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/* If transitioning from no transaction directly to a write transaction,
|
||||||
|
** block for the WRITER lock first if possible. */
|
||||||
|
if( pBt->pPage1==0 && wrflag ){
|
||||||
|
assert( pBt->inTransaction==TRANS_NONE );
|
||||||
|
rc = sqlite3PagerWalWriteLock(pPager, 1);
|
||||||
|
if( rc!=SQLITE_BUSY && rc!=SQLITE_OK ) break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Call lockBtree() until either pBt->pPage1 is populated or
|
/* Call lockBtree() until either pBt->pPage1 is populated or
|
||||||
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
** lockBtree() returns something other than SQLITE_OK. lockBtree()
|
||||||
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
** may return SQLITE_OK but leave pBt->pPage1 set to 0 if after
|
||||||
@@ -3448,7 +3460,7 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
|||||||
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
|
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 ){
|
||||||
rc = SQLITE_READONLY;
|
rc = SQLITE_READONLY;
|
||||||
}else{
|
}else{
|
||||||
rc = sqlite3PagerBegin(pBt->pPager,wrflag>1,sqlite3TempInMemory(p->db));
|
rc = sqlite3PagerBegin(pPager, wrflag>1, sqlite3TempInMemory(p->db));
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
rc = newDatabase(pBt);
|
rc = newDatabase(pBt);
|
||||||
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
|
}else if( rc==SQLITE_BUSY_SNAPSHOT && pBt->inTransaction==TRANS_NONE ){
|
||||||
@@ -3461,11 +3473,15 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
|
(void)sqlite3PagerWalWriteLock(pPager, 0);
|
||||||
unlockBtreeIfUnused(pBt);
|
unlockBtreeIfUnused(pBt);
|
||||||
}
|
}
|
||||||
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
}while( (rc&0xFF)==SQLITE_BUSY && pBt->inTransaction==TRANS_NONE &&
|
||||||
btreeInvokeBusyHandler(pBt) );
|
btreeInvokeBusyHandler(pBt) );
|
||||||
sqlite3PagerResetLockTimeout(pBt->pPager);
|
sqlite3PagerWalDb(pPager, 0);
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
||||||
|
#endif
|
||||||
|
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
if( p->inTrans==TRANS_NONE ){
|
if( p->inTrans==TRANS_NONE ){
|
||||||
@@ -3517,7 +3533,7 @@ trans_begun:
|
|||||||
** open savepoints. If the second parameter is greater than 0 and
|
** open savepoints. If the second parameter is greater than 0 and
|
||||||
** the sub-journal is not already open, then it will be opened here.
|
** the sub-journal is not already open, then it will be opened here.
|
||||||
*/
|
*/
|
||||||
rc = sqlite3PagerOpenSavepoint(pBt->pPager, p->db->nSavepoint);
|
rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
44
src/main.c
44
src/main.c
@@ -1614,8 +1614,7 @@ const char *sqlite3ErrStr(int rc){
|
|||||||
*/
|
*/
|
||||||
static int sqliteDefaultBusyCallback(
|
static int sqliteDefaultBusyCallback(
|
||||||
void *ptr, /* Database connection */
|
void *ptr, /* Database connection */
|
||||||
int count, /* Number of times table has been busy */
|
int count /* Number of times table has been busy */
|
||||||
sqlite3_file *pFile /* The file on which the lock occurred */
|
|
||||||
){
|
){
|
||||||
#if SQLITE_OS_WIN || HAVE_USLEEP
|
#if SQLITE_OS_WIN || HAVE_USLEEP
|
||||||
/* This case is for systems that have support for sleeping for fractions of
|
/* This case is for systems that have support for sleeping for fractions of
|
||||||
@@ -1629,31 +1628,6 @@ static int sqliteDefaultBusyCallback(
|
|||||||
int tmout = db->busyTimeout;
|
int tmout = db->busyTimeout;
|
||||||
int delay, prior;
|
int delay, prior;
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
if( sqlite3OsFileControl(pFile,SQLITE_FCNTL_LOCK_TIMEOUT,&tmout)==SQLITE_OK ){
|
|
||||||
if( count ){
|
|
||||||
/* If this is the second or later invocation of the busy-handler,
|
|
||||||
** but tmout==0, then code in wal.c must have disabled the blocking
|
|
||||||
** lock before the SQLITE_BUSY error was hit. In this case, no delay
|
|
||||||
** occurred while waiting for the lock, so fall through to the xSleep()
|
|
||||||
** code below to delay a while before retrying the lock.
|
|
||||||
**
|
|
||||||
** Alternatively, if tmout!=0, then SQLite has already waited
|
|
||||||
** sqlite3.busyTimeout ms for a lock. In this case, return 0 to
|
|
||||||
** indicate that the lock should not be retried and the SQLITE_BUSY
|
|
||||||
** error returned to the application. */
|
|
||||||
if( tmout ){
|
|
||||||
tmout = 0;
|
|
||||||
sqlite3OsFileControl(pFile, SQLITE_FCNTL_LOCK_TIMEOUT, &tmout);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
UNUSED_PARAMETER(pFile);
|
|
||||||
#endif
|
|
||||||
assert( count>=0 );
|
assert( count>=0 );
|
||||||
if( count < NDELAY ){
|
if( count < NDELAY ){
|
||||||
delay = delays[count];
|
delay = delays[count];
|
||||||
@@ -1673,7 +1647,6 @@ static int sqliteDefaultBusyCallback(
|
|||||||
** must be done in increments of whole seconds */
|
** must be done in increments of whole seconds */
|
||||||
sqlite3 *db = (sqlite3 *)ptr;
|
sqlite3 *db = (sqlite3 *)ptr;
|
||||||
int tmout = ((sqlite3 *)ptr)->busyTimeout;
|
int tmout = ((sqlite3 *)ptr)->busyTimeout;
|
||||||
UNUSED_PARAMETER(pFile);
|
|
||||||
if( (count+1)*1000 > tmout ){
|
if( (count+1)*1000 > tmout ){
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1691,19 +1664,10 @@ static int sqliteDefaultBusyCallback(
|
|||||||
** If this routine returns non-zero, the lock is retried. If it
|
** If this routine returns non-zero, the lock is retried. If it
|
||||||
** returns 0, the operation aborts with an SQLITE_BUSY error.
|
** returns 0, the operation aborts with an SQLITE_BUSY error.
|
||||||
*/
|
*/
|
||||||
int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
|
int sqlite3InvokeBusyHandler(BusyHandler *p){
|
||||||
int rc;
|
int rc;
|
||||||
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
|
if( p->xBusyHandler==0 || p->nBusy<0 ) return 0;
|
||||||
if( p->bExtraFileArg ){
|
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
||||||
/* Add an extra parameter with the pFile pointer to the end of the
|
|
||||||
** callback argument list */
|
|
||||||
int (*xTra)(void*,int,sqlite3_file*);
|
|
||||||
xTra = (int(*)(void*,int,sqlite3_file*))p->xBusyHandler;
|
|
||||||
rc = xTra(p->pBusyArg, p->nBusy, pFile);
|
|
||||||
}else{
|
|
||||||
/* Legacy style busy handler callback */
|
|
||||||
rc = p->xBusyHandler(p->pBusyArg, p->nBusy);
|
|
||||||
}
|
|
||||||
if( rc==0 ){
|
if( rc==0 ){
|
||||||
p->nBusy = -1;
|
p->nBusy = -1;
|
||||||
}else{
|
}else{
|
||||||
@@ -1728,7 +1692,6 @@ int sqlite3_busy_handler(
|
|||||||
db->busyHandler.xBusyHandler = xBusy;
|
db->busyHandler.xBusyHandler = xBusy;
|
||||||
db->busyHandler.pBusyArg = pArg;
|
db->busyHandler.pBusyArg = pArg;
|
||||||
db->busyHandler.nBusy = 0;
|
db->busyHandler.nBusy = 0;
|
||||||
db->busyHandler.bExtraFileArg = 0;
|
|
||||||
db->busyTimeout = 0;
|
db->busyTimeout = 0;
|
||||||
sqlite3_mutex_leave(db->mutex);
|
sqlite3_mutex_leave(db->mutex);
|
||||||
return SQLITE_OK;
|
return SQLITE_OK;
|
||||||
@@ -1779,7 +1742,6 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
|
|||||||
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
|
sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
|
||||||
(void*)db);
|
(void*)db);
|
||||||
db->busyTimeout = ms;
|
db->busyTimeout = ms;
|
||||||
db->busyHandler.bExtraFileArg = 1;
|
|
||||||
}else{
|
}else{
|
||||||
sqlite3_busy_handler(db, 0, 0);
|
sqlite3_busy_handler(db, 0, 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1565,8 +1565,9 @@ static int osSetPosixAdvisoryLock(
|
|||||||
struct flock *pLock, /* The description of the lock */
|
struct flock *pLock, /* The description of the lock */
|
||||||
unixFile *pFile /* Structure holding timeout value */
|
unixFile *pFile /* Structure holding timeout value */
|
||||||
){
|
){
|
||||||
|
int tm = pFile->iBusyTimeout;
|
||||||
int rc = osFcntl(h,F_SETLK,pLock);
|
int rc = osFcntl(h,F_SETLK,pLock);
|
||||||
while( rc<0 && pFile->iBusyTimeout>0 ){
|
while( rc<0 && tm>0 ){
|
||||||
/* On systems that support some kind of blocking file lock with a timeout,
|
/* On systems that support some kind of blocking file lock with a timeout,
|
||||||
** make appropriate changes here to invoke that blocking file lock. On
|
** make appropriate changes here to invoke that blocking file lock. On
|
||||||
** generic posix, however, there is no such API. So we simply try the
|
** generic posix, however, there is no such API. So we simply try the
|
||||||
@@ -1574,7 +1575,7 @@ static int osSetPosixAdvisoryLock(
|
|||||||
** the lock is obtained. */
|
** the lock is obtained. */
|
||||||
usleep(1000);
|
usleep(1000);
|
||||||
rc = osFcntl(h,F_SETLK,pLock);
|
rc = osFcntl(h,F_SETLK,pLock);
|
||||||
pFile->iBusyTimeout--;
|
tm--;
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -4316,13 +4317,20 @@ static int unixShmSystemLock(
|
|||||||
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
assert( n>=1 && n<=SQLITE_SHM_NLOCK );
|
||||||
|
|
||||||
if( pShmNode->hShm>=0 ){
|
if( pShmNode->hShm>=0 ){
|
||||||
|
int res;
|
||||||
/* Initialize the locking parameters */
|
/* Initialize the locking parameters */
|
||||||
f.l_type = lockType;
|
f.l_type = lockType;
|
||||||
f.l_whence = SEEK_SET;
|
f.l_whence = SEEK_SET;
|
||||||
f.l_start = ofst;
|
f.l_start = ofst;
|
||||||
f.l_len = n;
|
f.l_len = n;
|
||||||
rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
res = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile);
|
||||||
rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY;
|
if( res==-1 ){
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
rc = (pFile->iBusyTimeout ? SQLITE_BUSY_TIMEOUT : SQLITE_BUSY);
|
||||||
|
#else
|
||||||
|
rc = SQLITE_BUSY;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the global lock state and do debug tracing */
|
/* Update the global lock state and do debug tracing */
|
||||||
@@ -4819,22 +4827,23 @@ static int unixShmLock(
|
|||||||
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 );
|
||||||
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 );
|
||||||
|
|
||||||
/* Check that, if this to be a blocking lock, that locks have been
|
/* Check that, if this to be a blocking lock, no locks that occur later
|
||||||
** obtained in the following order.
|
** in the following list than the lock being obtained are already held:
|
||||||
**
|
**
|
||||||
** 1. Checkpointer lock (ofst==1).
|
** 1. Checkpointer lock (ofst==1).
|
||||||
** 2. Recover lock (ofst==2).
|
** 2. Write lock (ofst==0).
|
||||||
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
** 3. Read locks (ofst>=3 && ofst<SQLITE_SHM_NLOCK).
|
||||||
** 4. Write lock (ofst==0).
|
|
||||||
**
|
**
|
||||||
** In other words, if this is a blocking lock, none of the locks that
|
** In other words, if this is a blocking lock, none of the locks that
|
||||||
** occur later in the above list than the lock being obtained may be
|
** occur later in the above list than the lock being obtained may be
|
||||||
** held. */
|
** held. */
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
assert( pDbFd->iBusyTimeout==0
|
assert( (flags & SQLITE_SHM_UNLOCK) || pDbFd->iBusyTimeout==0 || (
|
||||||
|| (flags & SQLITE_SHM_UNLOCK) || ofst==0
|
(ofst!=2) /* not RECOVER */
|
||||||
|| ((p->exclMask|p->sharedMask)&~((1<<ofst)-2))==0
|
&& (ofst!=1 || (p->exclMask|p->sharedMask)==0)
|
||||||
);
|
&& (ofst!=0 || (p->exclMask|p->sharedMask)<3)
|
||||||
|
&& (ofst<3 || (p->exclMask|p->sharedMask)<(1<<ofst))
|
||||||
|
));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mask = (1<<(ofst+n)) - (1<<ofst);
|
mask = (1<<(ofst+n)) - (1<<ofst);
|
||||||
|
|||||||
41
src/pager.c
41
src/pager.c
@@ -5705,7 +5705,6 @@ void sqlite3PagerUnrefPageOne(DbPage *pPg){
|
|||||||
assert( pPg->pgno==1 );
|
assert( pPg->pgno==1 );
|
||||||
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
|
assert( (pPg->flags & PGHDR_MMAP)==0 ); /* Page1 is never memory mapped */
|
||||||
pPager = pPg->pPager;
|
pPager = pPg->pPager;
|
||||||
sqlite3PagerResetLockTimeout(pPager);
|
|
||||||
sqlite3PcacheRelease(pPg);
|
sqlite3PcacheRelease(pPg);
|
||||||
pagerUnlockIfUnused(pPager);
|
pagerUnlockIfUnused(pPager);
|
||||||
}
|
}
|
||||||
@@ -6998,16 +6997,6 @@ sqlite3_file *sqlite3PagerFile(Pager *pPager){
|
|||||||
return pPager->fd;
|
return pPager->fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
/*
|
|
||||||
** Reset the lock timeout for pager.
|
|
||||||
*/
|
|
||||||
void sqlite3PagerResetLockTimeout(Pager *pPager){
|
|
||||||
int x = 0;
|
|
||||||
sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_LOCK_TIMEOUT, &x);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Return the file handle for the journal file (if it exists).
|
** Return the file handle for the journal file (if it exists).
|
||||||
** This will be either the rollback journal or the WAL file.
|
** This will be either the rollback journal or the WAL file.
|
||||||
@@ -7421,7 +7410,6 @@ int sqlite3PagerCheckpoint(
|
|||||||
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
|
pPager->walSyncFlags, pPager->pageSize, (u8 *)pPager->pTmpSpace,
|
||||||
pnLog, pnCkpt
|
pnLog, pnCkpt
|
||||||
);
|
);
|
||||||
sqlite3PagerResetLockTimeout(pPager);
|
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -7586,7 +7574,31 @@ int sqlite3PagerCloseWal(Pager *pPager, sqlite3 *db){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/*
|
||||||
|
** If pager pPager is a wal-mode database not in exclusive locking mode,
|
||||||
|
** invoke the sqlite3WalWriteLock() function on the associated Wal object
|
||||||
|
** with the same db and bLock parameters as were passed to this function.
|
||||||
|
** Return an SQLite error code if an error occurs, or SQLITE_OK otherwise.
|
||||||
|
*/
|
||||||
|
int sqlite3PagerWalWriteLock(Pager *pPager, int bLock){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
if( pagerUseWal(pPager) && pPager->exclusiveMode==0 ){
|
||||||
|
rc = sqlite3WalWriteLock(pPager->pWal, bLock);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Set the database handle used by the wal layer to determine if
|
||||||
|
** blocking locks are required.
|
||||||
|
*/
|
||||||
|
void sqlite3PagerWalDb(Pager *pPager, sqlite3 *db){
|
||||||
|
if( pagerUseWal(pPager) ){
|
||||||
|
sqlite3WalDb(pPager->pWal, db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||||
/*
|
/*
|
||||||
@@ -7606,7 +7618,10 @@ int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot){
|
|||||||
** read transaction is opened, attempt to read from the snapshot it
|
** read transaction is opened, attempt to read from the snapshot it
|
||||||
** identifies. If this is not a WAL database, return an error.
|
** identifies. If this is not a WAL database, return an error.
|
||||||
*/
|
*/
|
||||||
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot){
|
int sqlite3PagerSnapshotOpen(
|
||||||
|
Pager *pPager,
|
||||||
|
sqlite3_snapshot *pSnapshot
|
||||||
|
){
|
||||||
int rc = SQLITE_OK;
|
int rc = SQLITE_OK;
|
||||||
if( pPager->pWal ){
|
if( pPager->pWal ){
|
||||||
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
|
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot);
|
||||||
|
|||||||
17
src/pager.h
17
src/pager.h
@@ -177,14 +177,22 @@ int sqlite3PagerSharedLock(Pager *pPager);
|
|||||||
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
int sqlite3PagerOpenWal(Pager *pPager, int *pisOpen);
|
||||||
int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
int sqlite3PagerCloseWal(Pager *pPager, sqlite3*);
|
||||||
# ifdef SQLITE_ENABLE_SNAPSHOT
|
# ifdef SQLITE_ENABLE_SNAPSHOT
|
||||||
int sqlite3PagerSnapshotGet(Pager *pPager, sqlite3_snapshot **ppSnapshot);
|
int sqlite3PagerSnapshotGet(Pager*, sqlite3_snapshot **ppSnapshot);
|
||||||
int sqlite3PagerSnapshotOpen(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
int sqlite3PagerSnapshotOpen(Pager*, sqlite3_snapshot *pSnapshot);
|
||||||
int sqlite3PagerSnapshotRecover(Pager *pPager);
|
int sqlite3PagerSnapshotRecover(Pager *pPager);
|
||||||
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
int sqlite3PagerSnapshotCheck(Pager *pPager, sqlite3_snapshot *pSnapshot);
|
||||||
void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
void sqlite3PagerSnapshotUnlock(Pager *pPager);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SQLITE_OMIT_WAL) && defined(SQLITE_ENABLE_SETLK_TIMEOUT)
|
||||||
|
int sqlite3PagerWalWriteLock(Pager*, int);
|
||||||
|
void sqlite3PagerWalDb(Pager*, sqlite3*);
|
||||||
|
#else
|
||||||
|
# define sqlite3PagerWalWriteLock(y,z) SQLITE_OK
|
||||||
|
# define sqlite3PagerWalDb(x,y)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
#ifdef SQLITE_DIRECT_OVERFLOW_READ
|
||||||
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
int sqlite3PagerDirectReadOk(Pager *pPager, Pgno pgno);
|
||||||
#endif
|
#endif
|
||||||
@@ -210,11 +218,6 @@ int sqlite3PagerIsMemdb(Pager*);
|
|||||||
void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
void sqlite3PagerCacheStat(Pager *, int, int, int *);
|
||||||
void sqlite3PagerClearCache(Pager*);
|
void sqlite3PagerClearCache(Pager*);
|
||||||
int sqlite3SectorSize(sqlite3_file *);
|
int sqlite3SectorSize(sqlite3_file *);
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
void sqlite3PagerResetLockTimeout(Pager *pPager);
|
|
||||||
#else
|
|
||||||
# define sqlite3PagerResetLockTimeout(X)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Functions used to truncate the database file. */
|
/* Functions used to truncate the database file. */
|
||||||
void sqlite3PagerTruncateImage(Pager*,Pgno);
|
void sqlite3PagerTruncateImage(Pager*,Pgno);
|
||||||
|
|||||||
@@ -508,6 +508,7 @@ int sqlite3_exec(
|
|||||||
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
#define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8))
|
||||||
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
#define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8))
|
||||||
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8))
|
||||||
|
#define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8))
|
||||||
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
#define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8))
|
||||||
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
||||||
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
||||||
|
|||||||
@@ -994,7 +994,6 @@ struct BusyHandler {
|
|||||||
int (*xBusyHandler)(void *,int); /* The busy callback */
|
int (*xBusyHandler)(void *,int); /* The busy callback */
|
||||||
void *pBusyArg; /* First arg to busy callback */
|
void *pBusyArg; /* First arg to busy callback */
|
||||||
int nBusy; /* Incremented with each busy call */
|
int nBusy; /* Incremented with each busy call */
|
||||||
u8 bExtraFileArg; /* Include sqlite3_file as callback arg */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -4585,7 +4584,7 @@ void sqlite3RenameExprlistUnmap(Parse*, ExprList*);
|
|||||||
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
|
||||||
char sqlite3AffinityType(const char*, Column*);
|
char sqlite3AffinityType(const char*, Column*);
|
||||||
void sqlite3Analyze(Parse*, Token*, Token*);
|
void sqlite3Analyze(Parse*, Token*, Token*);
|
||||||
int sqlite3InvokeBusyHandler(BusyHandler*, sqlite3_file*);
|
int sqlite3InvokeBusyHandler(BusyHandler*);
|
||||||
int sqlite3FindDb(sqlite3*, Token*);
|
int sqlite3FindDb(sqlite3*, Token*);
|
||||||
int sqlite3FindDbName(sqlite3 *, const char *);
|
int sqlite3FindDbName(sqlite3 *, const char *);
|
||||||
int sqlite3AnalysisLoad(sqlite3*,int iDB);
|
int sqlite3AnalysisLoad(sqlite3*,int iDB);
|
||||||
|
|||||||
335
src/wal.c
335
src/wal.c
@@ -467,6 +467,9 @@ struct Wal {
|
|||||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||||
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
|
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
sqlite3 *db;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -840,7 +843,7 @@ static int walLockShared(Wal *pWal, int lockIdx){
|
|||||||
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
|
SQLITE_SHM_LOCK | SQLITE_SHM_SHARED);
|
||||||
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
|
WALTRACE(("WAL%p: acquire SHARED-%s %s\n", pWal,
|
||||||
walLockName(lockIdx), rc ? "failed" : "ok"));
|
walLockName(lockIdx), rc ? "failed" : "ok"));
|
||||||
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
|
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
static void walUnlockShared(Wal *pWal, int lockIdx){
|
static void walUnlockShared(Wal *pWal, int lockIdx){
|
||||||
@@ -856,7 +859,7 @@ static int walLockExclusive(Wal *pWal, int lockIdx, int n){
|
|||||||
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
|
SQLITE_SHM_LOCK | SQLITE_SHM_EXCLUSIVE);
|
||||||
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
|
WALTRACE(("WAL%p: acquire EXCLUSIVE-%s cnt=%d %s\n", pWal,
|
||||||
walLockName(lockIdx), n, rc ? "failed" : "ok"));
|
walLockName(lockIdx), n, rc ? "failed" : "ok"));
|
||||||
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && rc!=SQLITE_BUSY); )
|
VVA_ONLY( pWal->lockError = (u8)(rc!=SQLITE_OK && (rc&0xFF)!=SQLITE_BUSY); )
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
static void walUnlockExclusive(Wal *pWal, int lockIdx, int n){
|
||||||
@@ -1128,11 +1131,6 @@ static int walIndexRecover(Wal *pWal){
|
|||||||
u32 aFrameCksum[2] = {0, 0};
|
u32 aFrameCksum[2] = {0, 0};
|
||||||
int iLock; /* Lock offset to lock for checkpoint */
|
int iLock; /* Lock offset to lock for checkpoint */
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
int tmout = 0;
|
|
||||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Obtain an exclusive lock on all byte in the locking range not already
|
/* Obtain an exclusive lock on all byte in the locking range not already
|
||||||
** locked by the caller. The caller is guaranteed to have locked the
|
** locked by the caller. The caller is guaranteed to have locked the
|
||||||
** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
|
** WAL_WRITE_LOCK byte, and may have also locked the WAL_CKPT_LOCK byte.
|
||||||
@@ -1681,6 +1679,89 @@ static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/*
|
||||||
|
** Attempt to enable blocking locks. Blocking locks are enabled only if (a)
|
||||||
|
** they are supported by the VFS, and (b) the database handle is configured
|
||||||
|
** with a busy-timeout. Return 1 if blocking locks are successfully enabled,
|
||||||
|
** or 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int walEnableBlocking(Wal *pWal){
|
||||||
|
int res = 0;
|
||||||
|
if( pWal->db ){
|
||||||
|
int tmout = pWal->db->busyTimeout;
|
||||||
|
if( tmout ){
|
||||||
|
int rc;
|
||||||
|
rc = sqlite3OsFileControl(
|
||||||
|
pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout
|
||||||
|
);
|
||||||
|
res = (rc==SQLITE_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Disable blocking locks.
|
||||||
|
*/
|
||||||
|
static void walDisableBlocking(Wal *pWal){
|
||||||
|
int tmout = 0;
|
||||||
|
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If parameter bLock is true, attempt to enable blocking locks, take
|
||||||
|
** the WRITER lock, and then disable blocking locks. If blocking locks
|
||||||
|
** cannot be enabled, no attempt to obtain the WRITER lock is made. Return
|
||||||
|
** an SQLite error code if an error occurs, or SQLITE_OK otherwise. It is not
|
||||||
|
** an error if blocking locks can not be enabled.
|
||||||
|
**
|
||||||
|
** If the bLock parameter is false and the WRITER lock is held, release it.
|
||||||
|
*/
|
||||||
|
int sqlite3WalWriteLock(Wal *pWal, int bLock){
|
||||||
|
int rc = SQLITE_OK;
|
||||||
|
assert( pWal->readLock<0 || bLock==0 );
|
||||||
|
if( bLock ){
|
||||||
|
assert( pWal->db );
|
||||||
|
if( walEnableBlocking(pWal) ){
|
||||||
|
rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
pWal->writeLock = 1;
|
||||||
|
}
|
||||||
|
walDisableBlocking(pWal);
|
||||||
|
}
|
||||||
|
}else if( pWal->writeLock ){
|
||||||
|
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||||
|
pWal->writeLock = 0;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Set the database handle used to determine if blocking locks are required.
|
||||||
|
*/
|
||||||
|
void sqlite3WalDb(Wal *pWal, sqlite3 *db){
|
||||||
|
pWal->db = db;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Take an exclusive WRITE lock. Blocking if so configured.
|
||||||
|
*/
|
||||||
|
static int walLockWriter(Wal *pWal){
|
||||||
|
int rc;
|
||||||
|
walEnableBlocking(pWal);
|
||||||
|
rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||||
|
walDisableBlocking(pWal);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define walEnableBlocking(x) 0
|
||||||
|
# define walDisableBlocking(x)
|
||||||
|
# define walLockWriter(pWal) walLockExclusive((pWal), WAL_WRITE_LOCK, 1)
|
||||||
|
# define sqlite3WalDb(pWal, db)
|
||||||
|
#endif /* ifdef SQLITE_ENABLE_SETLK_TIMEOUT */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
|
** Attempt to obtain the exclusive WAL lock defined by parameters lockIdx and
|
||||||
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
|
** n. If the attempt fails and parameter xBusy is not NULL, then it is a
|
||||||
@@ -1698,6 +1779,12 @@ static int walBusyLock(
|
|||||||
do {
|
do {
|
||||||
rc = walLockExclusive(pWal, lockIdx, n);
|
rc = walLockExclusive(pWal, lockIdx, n);
|
||||||
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
|
}while( xBusy && rc==SQLITE_BUSY && xBusy(pBusyArg) );
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
if( rc==SQLITE_BUSY_TIMEOUT ){
|
||||||
|
walDisableBlocking(pWal);
|
||||||
|
rc = SQLITE_BUSY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2177,28 +2264,32 @@ static int walIndexReadHdr(Wal *pWal, int *pChanged){
|
|||||||
/* If the first attempt failed, it might have been due to a race
|
/* If the first attempt failed, it might have been due to a race
|
||||||
** with a writer. So get a WRITE lock and try again.
|
** with a writer. So get a WRITE lock and try again.
|
||||||
*/
|
*/
|
||||||
assert( badHdr==0 || pWal->writeLock==0 );
|
|
||||||
if( badHdr ){
|
if( badHdr ){
|
||||||
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
|
if( pWal->bShmUnreliable==0 && (pWal->readOnly & WAL_SHM_RDONLY) ){
|
||||||
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
if( SQLITE_OK==(rc = walLockShared(pWal, WAL_WRITE_LOCK)) ){
|
||||||
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
walUnlockShared(pWal, WAL_WRITE_LOCK);
|
||||||
rc = SQLITE_READONLY_RECOVERY;
|
rc = SQLITE_READONLY_RECOVERY;
|
||||||
}
|
}
|
||||||
}else if( SQLITE_OK==(rc = walLockExclusive(pWal, WAL_WRITE_LOCK, 1)) ){
|
}else{
|
||||||
pWal->writeLock = 1;
|
int bWriteLock = pWal->writeLock;
|
||||||
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
if( bWriteLock || SQLITE_OK==(rc = walLockWriter(pWal)) ){
|
||||||
badHdr = walIndexTryHdr(pWal, pChanged);
|
pWal->writeLock = 1;
|
||||||
if( badHdr ){
|
if( SQLITE_OK==(rc = walIndexPage(pWal, 0, &page0)) ){
|
||||||
/* If the wal-index header is still malformed even while holding
|
badHdr = walIndexTryHdr(pWal, pChanged);
|
||||||
** a WRITE lock, it can only mean that the header is corrupted and
|
if( badHdr ){
|
||||||
** needs to be reconstructed. So run recovery to do exactly that.
|
/* If the wal-index header is still malformed even while holding
|
||||||
*/
|
** a WRITE lock, it can only mean that the header is corrupted and
|
||||||
rc = walIndexRecover(pWal);
|
** needs to be reconstructed. So run recovery to do exactly that.
|
||||||
*pChanged = 1;
|
*/
|
||||||
|
rc = walIndexRecover(pWal);
|
||||||
|
*pChanged = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( bWriteLock==0 ){
|
||||||
|
pWal->writeLock = 0;
|
||||||
|
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pWal->writeLock = 0;
|
|
||||||
walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2750,22 +2841,34 @@ int sqlite3WalSnapshotRecover(Wal *pWal){
|
|||||||
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
||||||
int rc; /* Return code */
|
int rc; /* Return code */
|
||||||
int cnt = 0; /* Number of TryBeginRead attempts */
|
int cnt = 0; /* Number of TryBeginRead attempts */
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
int tmout = 0;
|
assert( pWal->ckptLock==0 );
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||||
int bChanged = 0;
|
int bChanged = 0;
|
||||||
WalIndexHdr *pSnapshot = pWal->pSnapshot;
|
WalIndexHdr *pSnapshot = pWal->pSnapshot;
|
||||||
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
if( pSnapshot ){
|
||||||
bChanged = 1;
|
if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
||||||
}
|
bChanged = 1;
|
||||||
#endif
|
}
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
/* It is possible that there is a checkpointer thread running
|
||||||
/* Disable blocking locks. They are not useful when trying to open a
|
** concurrent with this code. If this is the case, it may be that the
|
||||||
** read-transaction, and blocking may cause deadlock anyway. */
|
** checkpointer has already determined that it will checkpoint
|
||||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
|
** snapshot X, where X is later in the wal file than pSnapshot, but
|
||||||
|
** has not yet set the pInfo->nBackfillAttempted variable to indicate
|
||||||
|
** its intent. To avoid the race condition this leads to, ensure that
|
||||||
|
** there is no checkpointer process by taking a shared CKPT lock
|
||||||
|
** before checking pInfo->nBackfillAttempted. */
|
||||||
|
(void)walEnableBlocking(pWal);
|
||||||
|
rc = walLockShared(pWal, WAL_CKPT_LOCK);
|
||||||
|
walDisableBlocking(pWal);
|
||||||
|
|
||||||
|
if( rc!=SQLITE_OK ){
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
pWal->ckptLock = 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
do{
|
do{
|
||||||
@@ -2776,16 +2879,6 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
|||||||
testcase( rc==SQLITE_PROTOCOL );
|
testcase( rc==SQLITE_PROTOCOL );
|
||||||
testcase( rc==SQLITE_OK );
|
testcase( rc==SQLITE_OK );
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
|
||||||
/* If they were disabled earlier and the read-transaction has been
|
|
||||||
** successfully opened, re-enable blocking locks. This is because the
|
|
||||||
** connection may attempt to upgrade to a write-transaction, which does
|
|
||||||
** benefit from using blocking locks. */
|
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SQLITE_ENABLE_SNAPSHOT
|
#ifdef SQLITE_ENABLE_SNAPSHOT
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
if( pSnapshot && memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
|
||||||
@@ -2807,48 +2900,42 @@ int sqlite3WalBeginReadTransaction(Wal *pWal, int *pChanged){
|
|||||||
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
|
assert( pWal->readLock>0 || pWal->hdr.mxFrame==0 );
|
||||||
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
|
assert( pInfo->aReadMark[pWal->readLock]<=pSnapshot->mxFrame );
|
||||||
|
|
||||||
/* It is possible that there is a checkpointer thread running
|
/* Check that the wal file has not been wrapped. Assuming that it has
|
||||||
** concurrent with this code. If this is the case, it may be that the
|
** not, also check that no checkpointer has attempted to checkpoint any
|
||||||
** checkpointer has already determined that it will checkpoint
|
** frames beyond pSnapshot->mxFrame. If either of these conditions are
|
||||||
** snapshot X, where X is later in the wal file than pSnapshot, but
|
** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
|
||||||
** has not yet set the pInfo->nBackfillAttempted variable to indicate
|
** with *pSnapshot and set *pChanged as appropriate for opening the
|
||||||
** its intent. To avoid the race condition this leads to, ensure that
|
** snapshot. */
|
||||||
** there is no checkpointer process by taking a shared CKPT lock
|
if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|
||||||
** before checking pInfo->nBackfillAttempted.
|
&& pSnapshot->mxFrame>=pInfo->nBackfillAttempted
|
||||||
**
|
){
|
||||||
** TODO: Does the aReadMark[] lock prevent a checkpointer from doing
|
assert( pWal->readLock>0 );
|
||||||
** this already?
|
memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
|
||||||
*/
|
*pChanged = bChanged;
|
||||||
rc = walLockShared(pWal, WAL_CKPT_LOCK);
|
}else{
|
||||||
|
rc = SQLITE_ERROR_SNAPSHOT;
|
||||||
if( rc==SQLITE_OK ){
|
|
||||||
/* Check that the wal file has not been wrapped. Assuming that it has
|
|
||||||
** not, also check that no checkpointer has attempted to checkpoint any
|
|
||||||
** frames beyond pSnapshot->mxFrame. If either of these conditions are
|
|
||||||
** true, return SQLITE_ERROR_SNAPSHOT. Otherwise, overwrite pWal->hdr
|
|
||||||
** with *pSnapshot and set *pChanged as appropriate for opening the
|
|
||||||
** snapshot. */
|
|
||||||
if( !memcmp(pSnapshot->aSalt, pWal->hdr.aSalt, sizeof(pWal->hdr.aSalt))
|
|
||||||
&& pSnapshot->mxFrame>=pInfo->nBackfillAttempted
|
|
||||||
){
|
|
||||||
assert( pWal->readLock>0 );
|
|
||||||
memcpy(&pWal->hdr, pSnapshot, sizeof(WalIndexHdr));
|
|
||||||
*pChanged = bChanged;
|
|
||||||
}else{
|
|
||||||
rc = SQLITE_ERROR_SNAPSHOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release the shared CKPT lock obtained above. */
|
|
||||||
walUnlockShared(pWal, WAL_CKPT_LOCK);
|
|
||||||
pWal->minFrame = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* A client using a non-current snapshot may not ignore any frames
|
||||||
|
** from the start of the wal file. This is because, for a system
|
||||||
|
** where (minFrame < iSnapshot < maxFrame), a checkpointer may
|
||||||
|
** have omitted to checkpoint a frame earlier than minFrame in
|
||||||
|
** the file because there exists a frame after iSnapshot that
|
||||||
|
** is the same database page. */
|
||||||
|
pWal->minFrame = 1;
|
||||||
|
|
||||||
if( rc!=SQLITE_OK ){
|
if( rc!=SQLITE_OK ){
|
||||||
sqlite3WalEndReadTransaction(pWal);
|
sqlite3WalEndReadTransaction(pWal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Release the shared CKPT lock obtained above. */
|
||||||
|
if( pWal->ckptLock ){
|
||||||
|
assert( pSnapshot );
|
||||||
|
walUnlockShared(pWal, WAL_CKPT_LOCK);
|
||||||
|
pWal->ckptLock = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -3019,6 +3106,16 @@ Pgno sqlite3WalDbsize(Wal *pWal){
|
|||||||
int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
int sqlite3WalBeginWriteTransaction(Wal *pWal){
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
/* If the write-lock is already held, then it was obtained before the
|
||||||
|
** read-transaction was even opened, making this call a no-op.
|
||||||
|
** Return early. */
|
||||||
|
if( pWal->writeLock ){
|
||||||
|
assert( !memcmp(&pWal->hdr,(void *)walIndexHdr(pWal),sizeof(WalIndexHdr)) );
|
||||||
|
return SQLITE_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Cannot start a write transaction without first holding a read
|
/* Cannot start a write transaction without first holding a read
|
||||||
** transaction. */
|
** transaction. */
|
||||||
assert( pWal->readLock>=0 );
|
assert( pWal->readLock>=0 );
|
||||||
@@ -3595,45 +3692,52 @@ int sqlite3WalCheckpoint(
|
|||||||
if( pWal->readOnly ) return SQLITE_READONLY;
|
if( pWal->readOnly ) return SQLITE_READONLY;
|
||||||
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
WALTRACE(("WAL%p: checkpoint begins\n", pWal));
|
||||||
|
|
||||||
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
|
/* Enable blocking locks, if possible. If blocking locks are successfully
|
||||||
** "checkpoint" lock on the database file. */
|
** enabled, set xBusy2=0 so that the busy-handler is never invoked. */
|
||||||
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
sqlite3WalDb(pWal, db);
|
||||||
if( rc ){
|
(void)walEnableBlocking(pWal);
|
||||||
/* EVIDENCE-OF: R-10421-19736 If any other process is running a
|
|
||||||
** checkpoint operation at the same time, the lock cannot be obtained and
|
|
||||||
** SQLITE_BUSY is returned.
|
|
||||||
** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
|
|
||||||
** it will not be invoked in this case.
|
|
||||||
*/
|
|
||||||
testcase( rc==SQLITE_BUSY );
|
|
||||||
testcase( xBusy!=0 );
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
pWal->ckptLock = 1;
|
|
||||||
|
|
||||||
/* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
|
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
|
||||||
** TRUNCATE modes also obtain the exclusive "writer" lock on the database
|
** "checkpoint" lock on the database file.
|
||||||
** file.
|
** EVIDENCE-OF: R-10421-19736 If any other process is running a
|
||||||
**
|
** checkpoint operation at the same time, the lock cannot be obtained and
|
||||||
** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
|
** SQLITE_BUSY is returned.
|
||||||
** immediately, and a busy-handler is configured, it is invoked and the
|
** EVIDENCE-OF: R-53820-33897 Even if there is a busy-handler configured,
|
||||||
** writer lock retried until either the busy-handler returns 0 or the
|
** it will not be invoked in this case.
|
||||||
** lock is successfully obtained.
|
|
||||||
*/
|
*/
|
||||||
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||||
rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
|
testcase( rc==SQLITE_BUSY );
|
||||||
if( rc==SQLITE_OK ){
|
testcase( rc!=SQLITE_OK && xBusy2!=0 );
|
||||||
pWal->writeLock = 1;
|
if( rc==SQLITE_OK ){
|
||||||
}else if( rc==SQLITE_BUSY ){
|
pWal->ckptLock = 1;
|
||||||
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
|
|
||||||
xBusy2 = 0;
|
/* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
|
||||||
rc = SQLITE_OK;
|
** TRUNCATE modes also obtain the exclusive "writer" lock on the database
|
||||||
|
** file.
|
||||||
|
**
|
||||||
|
** EVIDENCE-OF: R-60642-04082 If the writer lock cannot be obtained
|
||||||
|
** immediately, and a busy-handler is configured, it is invoked and the
|
||||||
|
** writer lock retried until either the busy-handler returns 0 or the
|
||||||
|
** lock is successfully obtained.
|
||||||
|
*/
|
||||||
|
if( eMode!=SQLITE_CHECKPOINT_PASSIVE ){
|
||||||
|
rc = walBusyLock(pWal, xBusy2, pBusyArg, WAL_WRITE_LOCK, 1);
|
||||||
|
if( rc==SQLITE_OK ){
|
||||||
|
pWal->writeLock = 1;
|
||||||
|
}else if( rc==SQLITE_BUSY ){
|
||||||
|
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
|
||||||
|
xBusy2 = 0;
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Read the wal-index header. */
|
/* Read the wal-index header. */
|
||||||
if( rc==SQLITE_OK ){
|
if( rc==SQLITE_OK ){
|
||||||
|
walDisableBlocking(pWal);
|
||||||
rc = walIndexReadHdr(pWal, &isChanged);
|
rc = walIndexReadHdr(pWal, &isChanged);
|
||||||
|
(void)walEnableBlocking(pWal);
|
||||||
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
|
if( isChanged && pWal->pDbFd->pMethods->iVersion>=3 ){
|
||||||
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
|
sqlite3OsUnfetch(pWal->pDbFd, 0, 0);
|
||||||
}
|
}
|
||||||
@@ -3665,11 +3769,19 @@ int sqlite3WalCheckpoint(
|
|||||||
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
|
memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
walDisableBlocking(pWal);
|
||||||
|
sqlite3WalDb(pWal, 0);
|
||||||
|
|
||||||
/* Release the locks. */
|
/* Release the locks. */
|
||||||
sqlite3WalEndWriteTransaction(pWal);
|
sqlite3WalEndWriteTransaction(pWal);
|
||||||
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
if( pWal->ckptLock ){
|
||||||
pWal->ckptLock = 0;
|
walUnlockExclusive(pWal, WAL_CKPT_LOCK, 1);
|
||||||
|
pWal->ckptLock = 0;
|
||||||
|
}
|
||||||
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
|
WALTRACE(("WAL%p: checkpoint %s\n", pWal, rc ? "failed" : "ok"));
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
if( rc==SQLITE_BUSY_TIMEOUT ) rc = SQLITE_BUSY;
|
||||||
|
#endif
|
||||||
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
|
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3786,7 +3898,10 @@ int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot){
|
|||||||
|
|
||||||
/* Try to open on pSnapshot when the next read-transaction starts
|
/* Try to open on pSnapshot when the next read-transaction starts
|
||||||
*/
|
*/
|
||||||
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot){
|
void sqlite3WalSnapshotOpen(
|
||||||
|
Wal *pWal,
|
||||||
|
sqlite3_snapshot *pSnapshot
|
||||||
|
){
|
||||||
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
|
pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,5 +146,10 @@ int sqlite3WalFramesize(Wal *pWal);
|
|||||||
/* Return the sqlite3_file object for the WAL file */
|
/* Return the sqlite3_file object for the WAL file */
|
||||||
sqlite3_file *sqlite3WalFile(Wal *pWal);
|
sqlite3_file *sqlite3WalFile(Wal *pWal);
|
||||||
|
|
||||||
|
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
|
||||||
|
int sqlite3WalWriteLock(Wal *pWal, int bLock);
|
||||||
|
void sqlite3WalDb(Wal *pWal, sqlite3 *db);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* ifndef SQLITE_OMIT_WAL */
|
#endif /* ifndef SQLITE_OMIT_WAL */
|
||||||
#endif /* SQLITE_WAL_H */
|
#endif /* SQLITE_WAL_H */
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ proc sqlite3_wal {args} {
|
|||||||
[lindex $args 0] eval { PRAGMA journal_mode = wal }
|
[lindex $args 0] eval { PRAGMA journal_mode = wal }
|
||||||
[lindex $args 0] eval { PRAGMA synchronous = normal }
|
[lindex $args 0] eval { PRAGMA synchronous = normal }
|
||||||
[lindex $args 0] function blob blob
|
[lindex $args 0] function blob blob
|
||||||
|
db timeout 1000
|
||||||
}
|
}
|
||||||
|
|
||||||
proc log_deleted {logfile} {
|
proc log_deleted {logfile} {
|
||||||
|
|||||||
198
test/walsetlk.test
Normal file
198
test/walsetlk.test
Normal file
@@ -0,0 +1,198 @@
|
|||||||
|
# 2020 May 06
|
||||||
|
#
|
||||||
|
# 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 walsetlk
|
||||||
|
|
||||||
|
ifcapable !wal {finish_test ; return }
|
||||||
|
db timeout 1000
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# 1.*: Test that nothing goes wrong if recovery is forced while opening
|
||||||
|
# a write transaction or performing a checkpoint with blocking locks.
|
||||||
|
#
|
||||||
|
|
||||||
|
do_execsql_test 1.0 {
|
||||||
|
CREATE TABLE t1(x, y);
|
||||||
|
PRAGMA journal_mode = wal;
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
INSERT INTO t1 VALUES(3, 4);
|
||||||
|
INSERT INTO t1 VALUES(5, 6);
|
||||||
|
INSERT INTO t1 VALUES(7, 8);
|
||||||
|
} {wal}
|
||||||
|
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
db2 timeout 1000
|
||||||
|
|
||||||
|
do_execsql_test -db db2 1.1 {
|
||||||
|
SELECT * FROM t1
|
||||||
|
} {1 2 3 4 5 6 7 8}
|
||||||
|
|
||||||
|
set fd [open test.db-shm r+]
|
||||||
|
puts $fd "blahblahblahblah"
|
||||||
|
flush $fd
|
||||||
|
|
||||||
|
do_execsql_test 1.2 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(9, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
do_execsql_test -db db2 1.3 {
|
||||||
|
SELECT * FROM t1
|
||||||
|
} {1 2 3 4 5 6 7 8}
|
||||||
|
|
||||||
|
do_test 1.4 {
|
||||||
|
list [catch {db2 eval { BEGIN EXCLUSIVE }} msg] $msg
|
||||||
|
} {1 {database is locked}}
|
||||||
|
|
||||||
|
do_execsql_test 1.5 { COMMIT }
|
||||||
|
do_execsql_test -db db2 1.6 {
|
||||||
|
SELECT * FROM t1
|
||||||
|
} {1 2 3 4 5 6 7 8 9 10}
|
||||||
|
|
||||||
|
puts $fd "blahblahblahblah"
|
||||||
|
flush $fd
|
||||||
|
|
||||||
|
do_execsql_test -db db2 1.7 {
|
||||||
|
PRAGMA wal_checkpoint = TRUNCATE
|
||||||
|
} {0 0 0}
|
||||||
|
|
||||||
|
do_test 1.8 {
|
||||||
|
file size test.db-wal
|
||||||
|
} 0
|
||||||
|
|
||||||
|
close $fd
|
||||||
|
db close
|
||||||
|
db2 close
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
|
do_multiclient_test tn {
|
||||||
|
do_test 2.$tn.1 {
|
||||||
|
sql1 {
|
||||||
|
PRAGMA journal_mode = wal;
|
||||||
|
CREATE TABLE t1(s, v);
|
||||||
|
INSERT INTO t1 VALUES(1, 2);
|
||||||
|
INSERT INTO t1 VALUES(3, 4);
|
||||||
|
INSERT INTO t1 VALUES(5, 6);
|
||||||
|
}
|
||||||
|
code1 { db timeout 2000 }
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.2 {
|
||||||
|
sql2 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(7, 8);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.3 {
|
||||||
|
set us [lindex [time { catch {db eval "BEGIN EXCLUSIVE"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_test 2.$tn.4 {
|
||||||
|
sql2 { COMMIT }
|
||||||
|
sql1 { SELECT * FROM t1 }
|
||||||
|
} {1 2 3 4 5 6 7 8}
|
||||||
|
|
||||||
|
do_test 2.$tn.5 {
|
||||||
|
sql2 {
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO t1 VALUES(9, 10);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.6 {
|
||||||
|
set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_test 2.$tn.7 {
|
||||||
|
sql2 {
|
||||||
|
COMMIT;
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
} {1 2 3 4 5 6 7 8 9 10}
|
||||||
|
|
||||||
|
do_test 2.$tn.8 {
|
||||||
|
set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_test 2.$tn.9 {
|
||||||
|
sql3 {
|
||||||
|
INSERT INTO t1 VALUES(11, 12);
|
||||||
|
}
|
||||||
|
sql2 {
|
||||||
|
COMMIT;
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
sql3 {
|
||||||
|
INSERT INTO t1 VALUES(13, 14);
|
||||||
|
}
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.10 {
|
||||||
|
set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_test 2.$tn.11 {
|
||||||
|
sql3 {
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
sql1 { INSERT INTO t1 VALUES(15, 16); }
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.12 {
|
||||||
|
set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
do_test 2.$tn.13 {
|
||||||
|
sql2 {
|
||||||
|
COMMIT;
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
}
|
||||||
|
sql1 { INSERT INTO t1 VALUES(17, 18); }
|
||||||
|
} {}
|
||||||
|
|
||||||
|
do_test 2.$tn.14 {
|
||||||
|
set us [lindex [time { catch {db eval "PRAGMA wal_checkpoint=RESTART"} }] 0]
|
||||||
|
expr $us>1000000 && $us<4000000
|
||||||
|
} {1}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
reset_db
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
db2 timeout 1000
|
||||||
|
do_execsql_test 3.0 {
|
||||||
|
PRAGMA journal_mode = wal;
|
||||||
|
CREATE TABLE x1(x, y);
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO x1 VALUES(1, 2);
|
||||||
|
} {wal}
|
||||||
|
|
||||||
|
do_test 3.1 {
|
||||||
|
list [catch { db2 eval {BEGIN EXCLUSIVE} } msg] $msg
|
||||||
|
} {1 {database is locked}}
|
||||||
|
|
||||||
|
finish_test
|
||||||
|
|
||||||
Reference in New Issue
Block a user