- C Add\snew\sextension\s"bgckpt"\sin\sext/misc/bgckpt.c.\sFor\sexperimenting\swith\nrunning\swal2\smode\scheckpoints\sin\sa\sbackground\sthread.
- D 2017-10-10T20:11:10.809
- F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff
-C Version\s3.26.0
-D 2018-12-01T12:34:55.966
++C Sync\sthis\sbranch\swith\sthe\slatest\strunk.
++D 2018-12-01T20:14:06.719
+ F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
+ F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
+ F Makefile.in a050c8670ea0d7b37b2192306cbb50d392acd9902b84e9b56f3444d006f97a6c
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
- F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f
- F README.md f5c87359573c4d255425e588a56554b50fdcc2afba4e017a2e02a43701456afd
- F VERSION f81232df28e2d3ff049feefad5fbd5489cc33697f6bd2ecf61af7f0dde3b83d0
+ F Makefile.msc 0d6831ff7951b302e888d86d4c469e2ec3c22f59eba4118b8c38d5a51d9e2d4f
+ F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee
+ F VERSION 654da1d4053fb09ffc33a3910e6d427182a7dcdc67e934fa83de2849ac83fccb
F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50
F art/sqlite370.eps aa97a671332b432a54e1d74ff5e8775be34200c2
F art/sqlite370.ico af56c1d00fee7cd4753e8631ed60703ed0fc6e90
F ext/lsm1/lsm_win32.c 0a4acbd7e8d136dd3a5753f0a9e7a9802263a9d96cef3278cf120bcaa724db7c
F ext/lsm1/test/lsm1_common.tcl 5ed4bab07c93be2e4f300ebe46007ecf4b3e20bc5fbe1dedaf04a8774a6d8d82
F ext/lsm1/test/lsm1_simple.test ca949efefa102f4644231dcd9291d8cda7699a4ce1006b26e0e3fcb72233f422
- F ext/misc/README.md 8e008c8d2b02e09096b31dfba033253ac27c6c06a18aa5826e299fa7601d90b2
- F ext/misc/amatch.c 6db4607cb17c54b853a2d7c7c36046d004853f65b9b733e6f019d543d5dfae87
+ F ext/lsm1/tool/mklsm1c.tcl f31561bbee5349f0a554d1ad7236ac1991fc09176626f529f6078e07335398b0
+ F ext/misc/README.md d6dd0fe1d8af77040216798a6a2b0c46c73054d2f0ea544fbbcdccf6f238c240
+ F ext/misc/amatch.c c0a6a807a553eaa220bf69fca0353cd1587a3bfb3d2224fa425e3e6efcacc98a
F ext/misc/anycollseq.c 5ffdfde9829eeac52219136ad6aa7cd9a4edb3b15f4f2532de52f4a22525eddb
- F ext/misc/bgckpt.c 1e0178c1d9f44d44f45c731ebff45854194ca59a41d33f078f10a3a714bf4532
+ F ext/misc/appendvfs.c 3777f22ec1057dc4e5fd89f2fbddcc7a29fbeef1ad038c736c54411bb1967af7
++F ext/misc/bgckpt.c 49ae19aa03e6da393db5d17da256374d4c4d36889fdd89d6e4bc93aca2b752e6
+ F ext/misc/btreeinfo.c 4f0ebf278f46e68e6306c667917766cebc5550fd35d5de17847988e22892d4d2
F ext/misc/carray.c ed96c218ea940b85c9a274c4d9c59fe9491c299147a38a8bba537687bd6c6005
- F ext/misc/closure.c 0d2a038df8fbae7f19de42e7c7d71f2e4dc88704
- F ext/misc/completion.c 52c3f01523e3e387eb321b4739a89d1fe47cbe6025aa1f2d8d3685e9e365df0f
- F ext/misc/compress.c 122faa92d25033d6c3f07c39231de074ab3d2e83
- F ext/misc/csv.c 1a009b93650732e22334edc92459c4630b9fa703397cbb3c8ca279921a36ca11
- F ext/misc/dbdump.c 3509fa6b8932d04e932d6b6b827b6a82ca362781b8e8f3c77336f416793e215e
- F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
- F ext/misc/fileio.c b1aa06c0f1dac277695d4529e5e976c65ab5678dcbb53a0304deaa8adc44b332
+ F ext/misc/closure.c 9f8fa11aa6c6e2f6d7296ffa88f103df4b46abd9602bcab3ea2f8fc24f334f63
+ F ext/misc/completion.c cec672d40604075bb341a7f11ac48393efdcd90a979269b8fe7977ea62d0547f
+ F ext/misc/compress.c dd4f8a6d0baccff3c694757db5b430f3bbd821d8686d1fc24df55cf9f035b189
+ F ext/misc/csv.c 88333dc9f7dcf6a8148406f10ae04261e24e3b4c721550ae33e9e71f1265c1f1
+ F ext/misc/dbdump.c 12389a10c410fadf1e68eeb382def92d5a7fa9ce7cce4fb86a736fa2bac1000a
+ F ext/misc/eval.c 6ea9b22a5fa0dd973b67ca4e53555be177bc0b7b263aadf1024429457c82c0e3
+ F ext/misc/explain.c d5c12962d79913ef774b297006872af1fccda388f61a11d37758f9179a09551f
+ F ext/misc/fileio.c e3153b04433897a18a3d17185845f286892e96fdf87f4301290d09c36ae1759f
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
- F ext/misc/json1.c dbe086615b9546c156bf32b9378fc09383b58bd17513b866cfd24c1e15281984
- F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
+ F ext/misc/json1.c 3f017d2659e531d021d015ec5d69ea0b1c71f2e15bf9768b1e149fcdf6c3e0b1
+ F ext/misc/memstat.c 941928c6104d8ed569a6c47caa756dc78b8091f7a15f87d3004f3b1e576b10da
+ F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567
F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
+ F ext/misc/normalize.c b4290464f542bae7a97b43f15bd197949b833ffd668b7c313631bd5d4610212c
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
F ext/misc/regexp.c a68d25c659bd2d893cd1215667bbf75ecb9dc7d4
F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c
F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x
F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8
F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60
- F main.mk 8dcd78e5977c6e220ec0ab9a00aa2469ca38380d1553cb3eff18469a28e04654
-F main.mk eeaa279fa6acdcfa6555058548075569a06f891fd67f5901b1e7700d18052fda
++F main.mk 1274d58d63cb050586fbe0e06b22dcc69972ccb16e57f39a033f37d294316d12
F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83
F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271
F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504
F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
- F src/alter.c cf7a8af45cb0ace672f47a1b29ab24092a9e8cd8d945a9974e3b5d925f548594
- F src/analyze.c 0d0ccf7520a201d8747ea2f02c92c26e26f801bc161f714f27b9f7630dde0421
- F src/attach.c 07b706e336fd3cedbd855e1f8266d10e82fecae07daf86717b5760cd7784c584
- F src/auth.c 6277d63837357549fe14e723490d6dc1a38768d71c795c5eb5c0f8a99f918f73
- F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
+ F src/alter.c f886160da189e4e99093cd5a2aca625652cc9b027d5100b87f81c175d1056387
+ F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9
+ F src/attach.c 92b51739a885da8bd84bc9a05485f1e48148bce5c15432f059b45af98fff75cd
+ F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df
+ F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
- F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
- F src/btree.c a559d64185c737daf64f361df40a51f35e1f9ba862ae3f4193bf5eadc549e6b2
- F src/btree.h 32ef5d3f25dc70ef1ee9cecf84a023c21378f06a57cd701d2e866e141b150f09
- F src/btreeInt.h 55b702efce17e5d1941865464227d3802cfc9c7c832fac81d4c94dced47a71fc
- F src/build.c e71e96a67daf3d1dd23188423e66cd6af38017e2ec73fead5d2b57da2d3c7e16
- F src/callback.c 28a8ede982fde4129b828350f78f2c01fe7d12c74d1a0a05d7108ab36f308688
+ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
-F src/btree.c ba7c7eef4461790f37c309936bfc5d0d6ba9b194b02d3c8ff1fd53b420ea6d3b
++F src/btree.c 3887a4f5513a831c445063ff1d81d9d6a50ad47522600dab0ef0656f4389fe5a
+ F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2
+ F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96
+ F src/build.c 127d33ad57b455a9339e9fabff41284c8b030cc6247ca7a2a6c0ad7abfc1ce85
+ F src/callback.c 789bd33d188146f66c0dd8306472a72d1c05f71924b24a91caf6bd45cf9aba73
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
- F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0
- F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74
- F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720
- F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023
- F src/expr.c 4d2d0aafd945424f638ee03e11330f03288ccf616e025498f3c8602d01609a0a
+ F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b
+ F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957
+ F src/dbpage.c 135eb3b5e74f9ef74bde5cec2571192c90c86984fa534c88bf4a055076fa19b7
+ F src/dbstat.c 3c8bd4e77f0244fd2bd7cc90acf116ad2f8e82d70e536637f35ac2bc99b726f9
+ F src/delete.c f7938125847e8ef485448db5fbad29acb2991381a02887dd854c1617315ab9fb
+ F src/expr.c 9aacc0b72348ba90010b672dcbbbe2fa56e1182043bc917a3a147b2bc57a5497
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
- F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333
- F src/func.c b4d259af627e3cd9510cf08db37f0bcc88b1887c735169c74490c3739d5cf5c6
- F src/global.c ac3094f1dc59fbeb919aef7cc0cc827a8459d1fb1adb7972ef75bd9e0c10b75b
- F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a
+ F src/fkey.c 972a4ba14296bef2303a0abbad1e3d82bc3c61f9e6ce4e8e9528bdee68748812
+ F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f
+ F src/global.c 8291eee0782b83124de14ec0389ec9fd6ae1873358a6b0d9469fe17a46ad803b
+ F src/hash.c 931ec82d7e070654a8facb42549bbb3a25720171d73ba94c3d3160580d01ef1f
F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4
F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432
F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85
F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
- F src/os_unix.c 1f9c3e771557edd248e1fcec0818739826b2a3121b609a6e3372b670236d085a
- F src/os_win.c 6892c3ff23b7886577e47f13d827ca220c0831bae3ce00eea8c258352692f8c6
-F src/os_unix.c f6e91b8fd82af7afbfd073c4974ad6cdb8e62d9f65ceddb45167835a0567fdc0
++F src/os_unix.c 711480e9152f221098ec2b0d4ef94dc798f08af649c34f5cd4dc2bbf40c4f556
+ F src/os_win.c 85d9e532d0444ab6c16d7431490c2e279e282aa0917b0e988996b1ae0de5c5a0
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
- F src/pager.c 811c1a1eed536bf30e12e69b700fb8fef254b33e8753cd5b354371bb2cf1e74f
- F src/pager.h e11e516208a460bea1b95fe3da697642306e7f350d5f96d2c1d21231ee4d2bf2
- F src/parse.y 52ef3cecd0934e9da4a45b585883a03243ad615d338ad94f44501a05891dcdfa
- F src/pcache.c 4bada070456980c3c1f16d58ec2e64e389ad77b935e3d77e0c96e7bbd397289c
- F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170
- F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880
- F src/pragma.c 49a04b2ec3199b7967c19b3239182d9c4e860726909ed80b7a3e21fe5bb9e6c4
- F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324
- F src/prepare.c 9a141a1b02dca53beaa9771699d390aafcac01f5d1f1c0ae6e23ded8dcdb709a
- F src/printf.c 40aee47ae9be4bd3dbdc8968bd07fddc027be8edec8daddf24d3391d36698a1c
-F src/pager.c 75e0f3cfa3962c714f519f8a3d1e67ecca1c91de0e010a036b988e40ce9e4c73
-F src/pager.h 217921e81eb5fe455caa5cda96061959706bcdd29ddb57166198645ef7822ac3
++F src/pager.c dd88ccf7fa519d6e325a115af28cd528713ea4d33a510d6f202386df002f2e74
++F src/pager.h 3abf6d65199fd0680b26a047c6167a96a4d6ead7535e02522b79f0fb27a3edec
+ F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179
+ F src/pcache.c 696a01f1a6370c1b50a09c15972bc3bee3333f8fcd1f2da8e9a76b1b062c59ee
+ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586
+ F src/pcache1.c bf9fcea656dce1cd2cca6b77a1d1d3552050d55a31c98bf0d9f405930a83bc95
-F src/pragma.c 4e056f042683b99c4ea0db395f68d051b1a95833ab40951c40d3ef7e1fee1354
++F src/pragma.c dbc7a8fa3e057be14ebb4f1c6b9fa78a09d77367df0dd13faf1980ff591dd373
+ F src/pragma.h fdd03d78a7497f74a3f652909f945328480089189526841ae829ce7313d98d13
+ F src/prepare.c f81f8d707e583192c28fea0b2e19385415b7d188123b23f49b038076408d7a69
+ F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
- F src/resolve.c 4324a94573b1e29286f8121e4881db59eaedc014afeb274c8d3e07ed282e0e20
- F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
- F src/select.c 42aca61e739c405ddd8a1b702977a7743c7d52a94885f7c5596bd7e73e6bff18
- F src/shell.c cbf450e75665a185c546adc702ec5fd091306ae7a08bc88b1508ac9c11acc7fe
- F src/shell.c.in e03f7d473e10b65c25836a058a3e7a1665ffb1fe712949dcd6e38c790e4eafd0
- F src/sqlite.h.in ab4f8a29d1580dfaeb6891fa1b83cff8229ba0daa56994707ceaca71495d9ab7
+ F src/resolve.c 4cfc44def0f0690ceaab8f6481f5d76284d7f9509aab6e218a679b4836a54614
+ F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93
+ F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f
+ F src/shell.c.in 482e23a370cbe5b0d4c73a0f0f5fce34f7caa08a14a8d75e12f0225c4e14915c
+ F src/sqlite.h.in cce9feede1c1c03923c091b4bbbd081dd77aaf92024cc2cdbf65f712c2f668c3
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
- F src/sqlite3ext.h a1fd3aa82f967da436164e0728a7d6841651fd0c6e27b9044e0eb9f6c8462e47
- F src/sqliteInt.h c07bc88eca1f59ce73e1f486187d0df4effe67c4579e112dfdd91c159e5c0569
+ F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683
+ F src/sqliteInt.h 1161f7579cdd6217737a66517ef27f4016426603eff492e9b31f45a7d7d4c61f
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
- F src/status.c 9737ed017279a9e0c5da748701c3c7bf1e8ae0dae459aad20dd64fcff97a7e35
+ F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
- F src/tclsqlite.c 37be19e8ea1b4ec1e632d86272ada77bbb93f20b033df258ad3ed63dc4d40fa4
- F src/test1.c 8ef15f7a357f85dfc41c6c748ce9c947b4f676e01bb5ae6a45bee4923dff8b51
+ F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6
+ F src/test1.c 5390e5afb31fed61f72d0be0cb1b322d198a6e03fc13ff245ae76d17b4dcf2e9
F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
- F src/test3.c b8434949dfb8aff8dfa082c8b592109e77844c2135ed3c492113839b6956255b
+ F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
F src/test6.c e8d839fbc552ce044bec8234561a2d5b8819b48e29548ad0ba400471697946a8
F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef
F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e
F src/test_syscall.c 1073306ba2e9bfc886771871a13d3de281ed3939
-F src/test_tclsh.c 06317648b0d85a85fd823f7973b55535c59a3156c1ef59394fe511f932cfa78d
++F src/test_tclsh.c c225ebf05d8905e204580198ffaa09847256ac58af04af632fde3fd760475d90
F src/test_tclvar.c 33ff42149494a39c5fbb0df3d25d6fafb2f668888e41c0688d07273dcb268dfc
F src/test_thread.c 911d15fb14e19c0c542bdc8aabf981c2f10a4858
- F src/test_vfs.c f0186261a24de2671d080bcd8050732f0cb64f6e
+ F src/test_vfs.c 112f1f9271c33c211812e0e681830a84262dac065da58579ff49f9cefec97d4f
F src/test_vfstrace.c bab9594adc976cbe696ff3970728830b4c5ed698
- F src/test_windirent.c 17f91f5f2aa1bb7328abb49414c363b5d2a9d3ff
- F src/test_windirent.h 5d67483a55442e31e1bde0f4a230e6e932ad5906
+ F src/test_windirent.c a895e2c068a06644eef91a7f0a32182445a893b9a0f33d0cdb4283dca2486ac1
+ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a90484215
+ F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f
F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c
- F src/tokenize.c 1003d6d90c6783206c711f0a9397656fa5b055209f4d092caa43bb3bf5215db5
- F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afef
- F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc
- F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0
+ F src/tokenize.c 9e781e1ca80eefe7b5d6a9e2cd5c678c847da55fd6f093781fad7950934d4c83
+ F src/treeview.c 7b12ac059de54c939b6eb0dbffc9410c29c80d2470cee5cbe07d5ff9ea2d9253
+ F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd
+ F src/update.c 1816d56c1bca1ba4e0ef98cac2f49be62858e9df1dc08844c7067eb41cc44274
+ F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4
F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
- F src/util.c 5168013cfd937a695d23cce8c67cb07a3dda242d4cb812530ba1148b88e0f159
- F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
- F src/vdbe.c c3c3fe95d98df8757570fb265236cfdf31536d1025bf37c232237d1e422ae39b
- F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97
- F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9
- F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1
- F src/vdbeaux.c c423065d50cee24bc8cba57764f5e9869a1bb920c50907f5dd363ebd7c5aef82
- F src/vdbeblob.c 635a79b60340a6a14a622ea8dcb081f0a66b1ac3836870c587f232eec08c0286
- F src/vdbemem.c 5c1533bf756918b4e46b2ed2bb82c29c7c651e1e37bbd0a0d8731a68787598ff
- F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f
- F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c
- F src/vtab.c 0e4885495172e1bdf54b12cce23b395ac74ef5729031f15e1bc1e3e6b360ed1a
+ F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157
+ F src/vacuum.c 836cadc922de866c849e23a75f93d344cdc143d388339305d09a3fed27e8798d
-F src/vdbe.c 005e691ea4c7d51e6c1a69d9389aeb34700884c85f51681817ddea3fdc2fc39b
++F src/vdbe.c ee46b31b88015e1ba5b38b9405cada3c8d264bc5e19764ecc751e63aeb2edf66
+ F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907
+ F src/vdbeInt.h 437e6c6af679fdf157867eb83a8adc6cf5145d6774453c2214cfd0bd01d92980
+ F src/vdbeapi.c ecccfce6f614c33a95952efeec969d163e8349eac314ee2b7b163eda921b5eb0
+ F src/vdbeaux.c f547901b1aa9e2d81c63f06893f633648e434180666a827aacb547d7d6c8a601
+ F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191
+ F src/vdbemem.c 7b3305bc4a5139f4536ac9b5f61da0f915e49d2e3fdfa87dfdfa9d7aba8bc1e9
+ F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f
+ F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392
+ F src/vtab.c 70188a745dc4e57d26e942681ff4b2912b7c8249ad5de3f60f0677b4337bcfaa
F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
- F src/wal.c c025455c9d6cf48ca55bd894be4a37a160565de9c845510a048fb9113761b2f4
- F src/wal.h b6063e6be1b03389372f3f32240e99b8ab92c32cdd05aa0e31b30a21e4e41654
- F src/walker.c 3ccfa8637f95355bff61144e01a615b8ef26f79c312880848da73f03367da1e6
- F src/where.c 049522adcf5426f1a8c3ed07be15e1ffa3266afd34e8e7bee64b63e2fbfad0b5
- F src/whereInt.h 82c04c5075308abbac59180c8bad5ecb45b07453981f60a53f3c7dee21e1e971
- F src/wherecode.c e8c2ece5843ea56e6c90277d421f2d628f3f7b7c976642369cc519f008e1d2b1
- F src/whereexpr.c afcac9cccfc0fdaccbdda94034a398947b6dc47dbf821c1b496261722832a6a4
-F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f
-F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a
++F src/wal.c e5b19ec1ce95882a2ae610d2657b441b079734427757c1a4d069f5f57bb7e9a2
++F src/wal.h fc6113057f2950fc14631176b748293e216fb385ea8df665e6d259e37f8f7d21
+ F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66
+ F src/where.c 3818e8a736a05d2cb194e64399af707e367fbcc5c251d785804d02eaf121288e
+ F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f
+ F src/wherecode.c c45f03aefc2266b990df0fc4d7acc4e27f56f881f4fc0fc355b7cbc4d7189da5
+ F src/whereexpr.c 491f0894ad9903750cdecb7894437a0cabdffdd88f574d2b1c9ac85d14fe4b9c
+ F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
F test/pcache.test c8acbedd3b6fd0f9a7ca887a83b11d24a007972b
F test/pcache2.test af7f3deb1a819f77a6d0d81534e97d1cf62cd442
F test/percentile.test 4243af26b8f3f4555abe166f723715a1f74c77ff
- F test/permutations.test 5fe80f417441ed6a69acd77f5190305dbf255cc2be214f8e36df4715c4f63f08
- F test/pragma.test c31b5e98998c160a4c85b1e04f590655c67f2daa7f73854640cd120610e3ac15
-F test/permutations.test cf0b4e498db1d0143c19641d4420df7cc27fab2c95ed0abd2c7c5753beab25b8
++F test/permutations.test 57c9f829d72c91c89ae08febe205b73ec22751f476b4dafeafb614dfd263d74c
+ F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30
+ F test/pragma.test c267bf02742c823a191960895b3d52933cebd7beee26757d1ed694f213fcd867
F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f
- F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed
- F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c
- F test/pragma5.test fd517f42ee847e126afbbbd9fd0fb9e5a4a61a962496a350adb8a22583fbdc37
+ F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9
+ F test/pragma4.test 52d8186f9e8d09b87189432cdd401dfa66d0b32445e837fa19046c8ae7621b0e
+ F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983
F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8
- F test/printf.test b3ff34e73d59124140eaf89f7672e21bc2ca5fcc
- F test/printf2.test 9e6db85f81c63f2367c34a9d7db384088bd374ad
+ F test/printf.test a3e559bc9d922e7fe44e9d05c6965fee34fe3bc28300a4248c6a063425246ffd
+ F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
F test/pushdown.test 5e72c51c5e33253ed639ccee1e01ce62d62b6eee5ca893cd82334e4ee7b1d7fc
F test/savepoint2.test 9b8543940572a2f01a18298c3135ad0c9f4f67d7
F test/savepoint4.test c8f8159ade6d2acd9128be61e1230f1c1edc6cc0
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
-F test/savepoint6.test f41279c5e137139fa5c21485773332c7adb98cd7
+F test/savepoint6.test 48a645a7bb3a59a6fcf06a7364cfe5b655c336760de39068f7c241b0fc80d963
F test/savepoint7.test cde525ea3075283eb950cdcdefe23ead4f700daa
F test/savepointfault.test f044eac64b59f09746c7020ee261734de82bf9b2
- F test/scanstatus.test 5253c219e331318a437f436268e0e82345700285
+ F test/scanstatus.test d14842d0a2757ee059bcffa365746453d60952ba1077980c9a348a9fefbd232a
F test/schema.test 8f7999be894260f151adf15c2c7540f1c6d6a481
F test/schema2.test 906408621ea881fdb496d878b1822572a34e32c5
F test/schema3.test 1bc1008e1f8cb5654b248c55f27249366eb7ed38
F test/substr.test 18f57c4ca8a598805c4d64e304c418734d843c1a
F test/subtype1.test 7fe09496352f97053af1437150751be2d0a0cae8
F test/superlock.test ec94f0556b6488d97f71c79f9061ae08d9ab8f12
- F test/swarmvtab.test 05c4ca7b6ab0cc6f4c335a510347f99d741fa71366004699cf7dfa3cff4e2d17
- F test/swarmvtab2.test 038ef9bcad6fd2fb9e395196080cf23e223ddb1219015049a61540c161bc577d
- F test/swarmvtabfault.test 73563eefe3073c6fb3bb14475fb4ef5d4f2e3a67a02947ee0ca08980ea3dd7fe
- F test/symlink.test c9ebe7330d228249e447038276bfc8a7b22f4849
- F test/sync.test 2f84bdbc2b2df1fcb0220575b4b9f8cea94b7529
- F test/sync2.test 6be8ed007fa063b147773c1982b5bdba97a32badc536bdc6077eff5cf8710ece
+ F test/swarmvtab.test 9a3fd5ab3e9b3c976ad1b3d7646aab725114f2ac26b59395d0778b33bab6cdaf
+ F test/swarmvtab2.test c948cb2fdfc5b01d85e8f6d6504854202dc1a0782ab2a0ed61538f27cbd0aa5c
+ F test/swarmvtab3.test 247aa38b6ebd2b99db2075847ae47e789ac34f1c2ab5c720dfcffd990004c544
+ F test/swarmvtabfault.test 8a67a9f27c61073a47990829e92bc0c64420a807cb642b15a25f6c788210ed95
+ F test/symlink.test 0d816670325536b8973ec08d32b45136baddb80bd45fd178e0ce7a9e8153f3e7
+ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d4333092
+ F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039
F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d
F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04
- F test/tabfunc01.test c47171c36b3d411df2bd49719dcaa5d034f8d277477fd41d253940723b969a51
- F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f
- F test/tableapi.test 2674633fa95d80da917571ebdd759a14d9819126
+ F test/tabfunc01.test 54300134f76db817685194d2f0e63e3fbf7380b45e0d426e00a9aee752497cfb
+ F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132
+ F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4
F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930
- F test/tclsqlite.test c3d7ac9449634b9f17fd048a3c0212e88a7448be810a9c5bd051acc1ffa00d2f
- F test/tempdb.test bd92eba8f20e16a9136e434e20b280794de3cdb6
- F test/tempdb2.test 27e41ed540b2f9b056c2e77e9bddc1b875358507
+ F test/tclsqlite.test dca8aa30d84175e7d8c8fc43d3ffa11fa56e23fbdac2679d03833a0f326edf34
+ F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08
+ F test/tempdb2.test 2479226e4cb96f4c663eccd2d12c077cf6bda29ca5cc69a8a58a06127105dd62
F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900
F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
- F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
+ F test/temptable2.test d2940417496e2b9548e01d09990763fbe88c316504033256d51493e1f1a5ce6a
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
- F test/tester.tcl 71d30287dd22aae0eb9b07e62574336ae6a57e7a50e5dab320a604cfcca4b173
- F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
-F test/tester.tcl fa5656391e3b477508abe12b3b81f019b2e71397399ab38a2f32d8d7f3bf8e56
++F test/tester.tcl f93080be43af7d7687e5817c62b4097e06ea2ed0f1af3ba773675a9d2f90e971
+ F test/thread001.test b61a29dd87cf669f5f6ac96124a7c97d71b0c80d9012746072055877055cf9ef
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
F test/thread004.test f51dfc3936184aaf73ee85f315224baad272a87f
F test/unique.test 93f8b2ef5ea51b9495f8d6493429b1fd0f465264
F test/unique2.test 3674e9f2a3f1fbbfd4772ac74b7a97090d0f77d2
F test/unixexcl.test d936ba2b06794018e136418addd59a2354eeae97
- F test/unordered.test ca7adce0419e4ca0c50f039885e76ed2c531eda8
- F test/update.test 6c68446b8a0a33d522a7c72b320934596a2d7d32
- F test/update2.test fffc92e72ae568fe048588762e650cd8ccbd8c8b6e4fe9099231766bfe4b51de
+ F test/unordered.test ffeea7747d5ba962a8009a20b7e53d68cbae05b063604c68702c5998eb50c981
+ F test/update.test 1148de8d913e9817717990603aadeca07aab9ddbb10a30f167cbfd8d3a3ccb60
+ F test/update2.test 5e67667e1c54017d964e626db765cf8bedcf87483c184f4c575bdb8c1dd2313e
+ F test/upsert1.test 994bde41800bb77dbe32fcd2e1f6c4b49cc9f2c6cd345731c774dff02b51c110
+ F test/upsert2.test 9c3cdbb1a890227f6504ce4b0e3de68f4cdfa16bb21d8641208a9239896c5a09
+ F test/upsert3.test 88d7d590a1948a9cb6eac1b54b0642f67a9f35a1fc0f19b200e97d5d39e3179c
+ F test/upsert4.test 25d2a1da92f149331ae0c51ca6e3eee78189577585eab92de149900d62994fa5
+ F test/upsertfault.test f21ca47740841fdb4d61acfa7b17646d773e67724fe8c185b71c018db8a94b35
-F test/uri.test 3481026f00ade6dfe8adb7acb6e1e47b04369568
+F test/uri.test a2becabcb9fe25d08d1ae49c0788f4a75dda97bfe4c8641c2d04e224faf7a6e2
F test/uri2.test 9d3ba7a53ee167572d53a298ee4a5d38ec4a8fb7
F test/userauth01.test e740a2697a7b40d7c5003a7d7edaee16acd349a9
F test/utf16align.test 54cd35a27c005a9b6e7815d887718780b6a462ae
F test/vtabI.test 751b07636700dbdea328e4265b6077ccd6811a3f
F test/vtabJ.test d7b73675708cf63cfcb9d443bb451fc01a028347275b7311e51f9fdf3ca6757f
F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783
- F test/vtab_err.test 0d4d8eb4def1d053ac7c5050df3024fd47a3fbd8
+ F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65
F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad
F test/wal.test 613efec03e517e1775d86b993a54877d2e29a477
- F test/wal2.test 6ac39b94a284ebac6efb6be93b0cdfe73ee6083f129555e3144d8a615e9900ef
+ F test/wal2.test 155b9efa999bdb38ce1cd729b9a4fcdbffd6b88be27f039bad1d2929d287d918
+F test/wal2rewrite.test 6ca6f631ffcf871240beab5f02608913fd075c6d0d31310b026c8383c65c9f9c
- F test/wal2simple.test 8719413446ca97ca88507c5b79f139b631faa5b4e177b7424008b26fc153da30
++F test/wal2simple.test 8c9dfb8f1bca01a0deb57f7074cdb83865c2292e89b13f7a51a1c160dca3f5f4
F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2
F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c
F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
- P d218d815f89cb1368fdb5e3f774b7adaaf02560a367ba0f3e54987e08dd6241a
- R 7d8085c250f90df872ed6ab275626e25
-P 23684cb841ac2cb0d69e5470253bd96feb733762a7553b952a08470834fe85fa
-R dcc394af10af6094607f56a6086fb748
-T +bgcolor * #d0c0ff
-T +sym-release *
-T +sym-version-3.26.0 *
-U drh
-Z 560a5decbb241d53eb97e72267b6e6e8
++P 63955442304052f5adddd05ccaeebe87ddc5e25af695702793518f015b4f0a87 bf8c1b2b7a5960c282e543b9c293686dccff272512d08865f4600fb58238b4f9
++R 434605294285e3da7c3ee68026e7ade7
+U dan
- Z bca32e00ecb94225e888df6bb3b83e85
++Z 6329688d1e7210750fc075a6d45758a7
# define WALTRACE(X)
#endif
+ /*
+ ** WAL mode depends on atomic aligned 32-bit loads and stores in a few
+ ** places. The following macros try to make this explicit.
+ */
+ #if GCC_VESRION>=5004000
+ # define AtomicLoad(PTR) __atomic_load_n((PTR),__ATOMIC_RELAXED)
+ # define AtomicStore(PTR,VAL) __atomic_store_n((PTR),(VAL),__ATOMIC_RELAXED)
+ #else
+ # define AtomicLoad(PTR) (*(PTR))
+ # define AtomicStore(PTR,VAL) (*(PTR) = (VAL))
+ #endif
+
/*
-** The maximum (and only) versions of the wal and wal-index formats
-** that may be interpreted by this version of SQLite.
-**
-** If a client begins recovering a WAL file and finds that (a) the checksum
-** values in the wal-header are correct and (b) the version field is not
-** WAL_MAX_VERSION, recovery fails and SQLite returns SQLITE_CANTOPEN.
-**
-** Similarly, if a client successfully reads a wal-index header (i.e. the
-** checksum test is successful) and finds that the version field is not
-** WALINDEX_MAX_VERSION, then no read-transaction is opened and SQLite
-** returns SQLITE_CANTOPEN.
+** Both the wal-file and the wal-index contain version fields
+** indicating the current version of the system. If a client
+** reads the header of a wal file (as part of recovery), or the
+** wal-index (as part of opening a read transaction) and (a) the
+** header checksum is correct but (b) the version field is not
+** recognized, the operation fails with SQLITE_CANTOPEN.
+**
+** Currently, clients support both version-1 ("journal_mode=wal") and
+** version-2 ("journal_mode=wal2"). Legacy clients may support version-1
+** only.
*/
-#define WAL_MAX_VERSION 3007000
-#define WALINDEX_MAX_VERSION 3007000
+#define WAL_VERSION1 3007000 /* For "journal_mode=wal" */
+#define WAL_VERSION2 3021000 /* For "journal_mode=wal2" */
/*
- ** Indices of various locking bytes. WAL_NREADER is the number
+ ** Index numbers for various locking bytes. WAL_NREADER is the number
** of available reader locks and should be at least 3. The default
** is SQLITE_SHM_NLOCK==8 and WAL_NREADER==5.
+ **
+ ** Technically, the various VFSes are free to implement these locks however
+ ** they see fit. However, compatibility is encouraged so that VFSes can
+ ** interoperate. The standard implemention used on both unix and windows
+ ** is for the index number to indicate a byte offset into the
+ ** WalCkptInfo.aLock[] array in the wal-index header. In other words, all
+ ** locks are on the shm file. The WALINDEX_LOCK_OFFSET constant (which
+ ** should be 120) is the location in the shm file for the first locking
+ ** byte.
*/
#define WAL_WRITE_LOCK 0
#define WAL_ALL_BUT_WRITE 1
** the entry that corresponds to frame pWal->hdr.mxFrame. It is guaranteed
** that the page said hash-table and array reside on is already mapped.
*/
- assert( pWal->nWiData>walFramePage(pWal->hdr.mxFrame) );
- assert( pWal->apWiData[walFramePage(pWal->hdr.mxFrame)] );
- walHashGet(pWal, walFramePage(pWal->hdr.mxFrame), &sLoc);
+ assert( pWal->nWiData>walFramePage(iExternal) );
+ assert( pWal->apWiData[walFramePage(iExternal)] );
- walHashGet(pWal, walFramePage(iExternal), &aHash, &aPgno, &iZero);
++ walHashGet(pWal, walFramePage(iExternal), &sLoc);
/* Zero all hash-table entries that correspond to frame numbers greater
** than pWal->hdr.mxFrame.
*/
- iLimit = iExternal - iZero;
- iLimit = pWal->hdr.mxFrame - sLoc.iZero;
++ iLimit = iExternal - sLoc.iZero;
assert( iLimit>0 );
for(i=0; i<HASHTABLE_NSLOT; i++){
- if( aHash[i]>iLimit ){
- aHash[i] = 0;
+ if( sLoc.aHash[i]>iLimit ){
+ sLoc.aHash[i] = 0;
}
}
/* Zero the entries in the aPgno array that correspond to frames with
- ** frame numbers greater than pWal->hdr.mxFrame.
- */
+ ** frame numbers greater than pWal->hdr.mxFrame. */
- nByte = (int)((char *)aHash - (char *)&aPgno[iLimit+1]);
- memset((void *)&aPgno[iLimit+1], 0, nByte);
+ nByte = (int)((char *)sLoc.aHash - (char *)&sLoc.aPgno[iLimit+1]);
+ memset((void *)&sLoc.aPgno[iLimit+1], 0, nByte);
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* Verify that the every entry in the mapping region is still reachable
** Set an entry in the wal-index that will map database page number
** pPage into WAL frame iFrame.
*/
-static int walIndexAppend(Wal *pWal, u32 iFrame, u32 iPage){
+static int walIndexAppend(Wal *pWal, int iWal, u32 iFrame, u32 iPage){
int rc; /* Return code */
- u32 iZero = 0; /* One less than frame number of aPgno[1] */
- volatile u32 *aPgno = 0; /* Page number array */
- volatile ht_slot *aHash = 0; /* Hash table */
+ WalHashLoc sLoc; /* Wal-index hash table location */
+ u32 iExternal;
+
+ if( isWalMode2(pWal) ){
+ iExternal = walExternalEncode(iWal, iFrame);
+ }else{
+ assert( iWal==0 );
+ iExternal = iFrame;
+ }
- rc = walHashGet(pWal, walFramePage(iExternal), &aHash, &aPgno, &iZero);
- rc = walHashGet(pWal, walFramePage(iFrame), &sLoc);
++ rc = walHashGet(pWal, walFramePage(iExternal), &sLoc);
/* Assuming the wal-index file was successfully mapped, populate the
** page number array and hash table entry.
int idx; /* Value to write to hash-table slot */
int nCollide; /* Number of hash collisions */
- idx = iExternal - iZero;
- idx = iFrame - sLoc.iZero;
++ idx = iExternal - sLoc.iZero;
assert( idx <= HASHTABLE_NSLOT/2 + 1 );
/* If this is the first entry to be added to this hash-table, zero the
*/
static int walIndexRecover(Wal *pWal){
int rc; /* Return Code */
- i64 nSize; /* Size of log file */
- u32 aFrameCksum[2] = {0, 0};
int iLock; /* Lock offset to lock for checkpoint */
- int nLock; /* Number of locks to hold */
+ u32 nCkpt1 = 0xFFFFFFFF;
+ u32 nCkpt2 = 0xFFFFFFFF;
+ int bZero = 0;
+ WalIndexHdr hdr;
/* 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
if( rc ){
return rc;
}
+
WALTRACE(("WAL%p: recovery begin...\n", pWal));
- memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
-
- rc = sqlite3OsFileSize(pWal->pWalFd, &nSize);
- if( rc!=SQLITE_OK ){
- goto recovery_error;
- }
-
- if( nSize>WAL_HDRSIZE ){
- u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
- u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
- int szFrame; /* Number of bytes in buffer aFrame[] */
- u8 *aData; /* Pointer to data part of aFrame buffer */
- int iFrame; /* Index of last frame read */
- i64 iOffset; /* Next offset to read from log file */
- int szPage; /* Page size according to the log */
- u32 magic; /* Magic value read from WAL header */
- u32 version; /* Magic value read from WAL header */
- int isValid; /* True if this frame is valid */
-
- /* Read in the WAL header. */
- rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
- if( rc!=SQLITE_OK ){
- goto recovery_error;
- }
-
- /* If the database page size is not a power of two, or is greater than
- ** SQLITE_MAX_PAGE_SIZE, conclude that the WAL file contains no valid
- ** data. Similarly, if the 'magic' value is invalid, ignore the whole
- ** WAL file.
- */
- magic = sqlite3Get4byte(&aBuf[0]);
- szPage = sqlite3Get4byte(&aBuf[8]);
- if( (magic&0xFFFFFFFE)!=WAL_MAGIC
- || szPage&(szPage-1)
- || szPage>SQLITE_MAX_PAGE_SIZE
- || szPage<512
- ){
- goto finished;
- }
- pWal->hdr.bigEndCksum = (u8)(magic&0x00000001);
- pWal->szPage = szPage;
- pWal->nCkpt = sqlite3Get4byte(&aBuf[12]);
- memcpy(&pWal->hdr.aSalt, &aBuf[16], 8);
-
- /* Verify that the WAL header checksum is correct */
- walChecksumBytes(pWal->hdr.bigEndCksum==SQLITE_BIGENDIAN,
- aBuf, WAL_HDRSIZE-2*4, 0, pWal->hdr.aFrameCksum
- );
- if( pWal->hdr.aFrameCksum[0]!=sqlite3Get4byte(&aBuf[24])
- || pWal->hdr.aFrameCksum[1]!=sqlite3Get4byte(&aBuf[28])
- ){
- goto finished;
+ /* Recover the *-wal file. If a valid version-1 header is recovered
+ ** from it, do not open the *-wal2 file. Even if it exists.
+ **
+ ** Otherwise, if the *-wal2 file exists or if the "wal2" flag was
+ ** specified when sqlite3WalOpen() was called, open and recover
+ ** the *-wal2 file. Except, if the *-wal file was zero bytes in size,
+ ** truncate the *-wal2 to zero bytes in size.
+ **
+ ** After this block has run, if the *-wal2 file is open the system
+ ** starts up in VERSION2 mode. In this case pWal->hdr contains the
+ ** wal-index header considering only *-wal2. Stack variable hdr
+ ** contains the wal-index header considering only *-wal. The hash
+ ** tables are populated for both.
+ **
+ ** Or, if the *-wal2 file is not open, start up in VERSION1 mode.
+ ** pWal->hdr is already populated.
+ */
+ rc = walIndexRecoverOne(pWal, 0, &nCkpt1, &bZero);
+ assert( pWal->hdr.iVersion==0
+ || pWal->hdr.iVersion==WAL_VERSION1
+ || pWal->hdr.iVersion==WAL_VERSION2
+ );
+ if( rc==SQLITE_OK && bZero ){
+ rc = walTruncateWal2(pWal);
+ }
+ if( rc==SQLITE_OK && pWal->hdr.iVersion!=WAL_VERSION1 ){
+ int bOpen = 1;
+ sqlite3_vfs *pVfs = pWal->pVfs;
+ if( pWal->hdr.iVersion==0 && pWal->bWal2==0 ){
+ rc = sqlite3OsAccess(pVfs, pWal->zWalName2, SQLITE_ACCESS_EXISTS, &bOpen);
}
-
- /* Verify that the version number on the WAL format is one that
- ** are able to understand */
- version = sqlite3Get4byte(&aBuf[4]);
- if( version!=WAL_MAX_VERSION ){
- rc = SQLITE_CANTOPEN_BKPT;
- goto finished;
+ if( rc==SQLITE_OK && bOpen ){
+ rc = walOpenWal2(pWal);
+ if( rc==SQLITE_OK ){
+ hdr = pWal->hdr;
+ rc = walIndexRecoverOne(pWal, 1, &nCkpt2, 0);
+ }
}
+ }
- /* Malloc a buffer to read frames into. */
- szFrame = szPage + WAL_FRAME_HDRSIZE;
- aFrame = (u8 *)sqlite3_malloc64(szFrame);
- if( !aFrame ){
- rc = SQLITE_NOMEM_BKPT;
- goto recovery_error;
- }
- aData = &aFrame[WAL_FRAME_HDRSIZE];
+ if( rc==SQLITE_OK ){
+ volatile WalCkptInfo *pInfo;
- /* Read all frames from the log file. */
- iFrame = 0;
- for(iOffset=WAL_HDRSIZE; (iOffset+szFrame)<=nSize; iOffset+=szFrame){
- u32 pgno; /* Database page number for frame */
- u32 nTruncate; /* dbsize field from frame header */
+ if( isOpen(pWal->apWalFd[1]) ){
+ /* The case where *-wal2 may follow *-wal */
+ if( nCkpt2<=0x0F && nCkpt2==nCkpt1+1 ){
+ if( sqlite3Get4byte((u8*)(&pWal->hdr.aSalt[0]))==hdr.aFrameCksum[0]
+ && sqlite3Get4byte((u8*)(&pWal->hdr.aSalt[1]))==hdr.aFrameCksum[1]
+ ){
+ walidxSetFile(&pWal->hdr, 1);
+ walidxSetMxFrame(&pWal->hdr, 1, pWal->hdr.mxFrame);
+ walidxSetMxFrame(&pWal->hdr, 0, hdr.mxFrame);
+ }else{
+ pWal->hdr = hdr;
+ }
+ }else
- /* Read and decode the next log frame. */
- iFrame++;
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
- if( rc!=SQLITE_OK ) break;
- isValid = walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame);
- if( !isValid ) break;
- rc = walIndexAppend(pWal, iFrame, pgno);
- if( rc!=SQLITE_OK ) break;
+ /* When *-wal may follow *-wal2 */
+ if( (nCkpt2==0x0F && nCkpt1==0) || (nCkpt2<0x0F && nCkpt2==nCkpt1-1) ){
+ if( sqlite3Get4byte((u8*)(&hdr.aSalt[0]))==pWal->hdr.aFrameCksum[0]
+ && sqlite3Get4byte((u8*)(&hdr.aSalt[1]))==pWal->hdr.aFrameCksum[1]
+ ){
+ SWAP(WalIndexHdr, pWal->hdr, hdr);
+ walidxSetMxFrame(&pWal->hdr, 1, hdr.mxFrame);
+ }else{
+ walidxSetFile(&pWal->hdr, 1);
+ walidxSetMxFrame(&pWal->hdr, 1, pWal->hdr.mxFrame);
+ walidxSetMxFrame(&pWal->hdr, 0, 0);
+ }
+ }else
- /* If nTruncate is non-zero, this is a commit record. */
- if( nTruncate ){
- pWal->hdr.mxFrame = iFrame;
- pWal->hdr.nPage = nTruncate;
- pWal->hdr.szPage = (u16)((szPage&0xff00) | (szPage>>16));
- testcase( szPage<=32768 );
- testcase( szPage>=65536 );
- aFrameCksum[0] = pWal->hdr.aFrameCksum[0];
- aFrameCksum[1] = pWal->hdr.aFrameCksum[1];
+ /* Fallback */
+ if( nCkpt1<=nCkpt2 ){
+ pWal->hdr = hdr;
+ }else{
+ walidxSetFile(&pWal->hdr, 1);
+ walidxSetMxFrame(&pWal->hdr, 1, pWal->hdr.mxFrame);
+ walidxSetMxFrame(&pWal->hdr, 0, 0);
}
+ pWal->hdr.iVersion = WAL_VERSION2;
+ }else{
+ pWal->hdr.iVersion = WAL_VERSION1;
}
- sqlite3_free(aFrame);
- }
-
-finished:
- if( rc==SQLITE_OK ){
- volatile WalCkptInfo *pInfo;
- int i;
- pWal->hdr.aFrameCksum[0] = aFrameCksum[0];
- pWal->hdr.aFrameCksum[1] = aFrameCksum[1];
walIndexWriteHdr(pWal);
/* Reset the checkpoint-header. This is safe because this thread is
}
}
-recovery_error:
WALTRACE(("WAL%p: recovery %s\n", pWal, rc ? "failed" : "ok"));
- walUnlockExclusive(pWal, iLock, nLock);
+ walUnlockExclusive(pWal, iLock, WAL_READ_LOCK(0)-iLock);
+ walUnlockExclusive(pWal, WAL_READ_LOCK(1), WAL_NREADER-1);
return rc;
}
/*
-** Close an open wal-index.
+** Close an open wal-index and wal files.
*/
static void walIndexClose(Wal *pWal, int isDelete){
- if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE ){
+ if( pWal->exclusiveMode==WAL_HEAPMEMORY_MODE || pWal->bShmUnreliable ){
int i;
for(i=0; i<pWal->nWiData; i++){
sqlite3_free((void *)pWal->apWiData[i]);
pWal->apWiData[i] = 0;
}
- }else{
+ }
+ if( pWal->exclusiveMode!=WAL_HEAPMEMORY_MODE ){
sqlite3OsShmUnmap(pWal->pDbFd, isDelete);
}
+ sqlite3OsClose(pWal->apWalFd[0]);
+ sqlite3OsClose(pWal->apWalFd[1]);
}
/*
/*
** Construct a WalInterator object that can be used to loop over all
- ** pages in the WAL in ascending order. The caller must hold the checkpoint
- ** lock.
-** pages in the WAL following frame nBackfill in ascending order. Frames
++** pages in wal file iWal following frame nBackfill in ascending order. Frames
+ ** nBackfill or earlier may be included - excluding them is an optimization
+ ** only. The caller must hold the checkpoint lock.
**
-** On success, make *pp point to the newly allocated WalInterator object
-** return SQLITE_OK. Otherwise, return an error code. If this routine
-** returns an error, the value of *pp is undefined.
+** On success, make *pp point to the newly allocated WalIterator object
+** and return SQLITE_OK. Otherwise, return an error code. If this routine
+** returns an error, the final value of *pp is undefined.
**
** The calling routine should invoke walIteratorFree() to destroy the
** WalIterator object when it has finished with it.
*/
- static int walIteratorInit(Wal *pWal, int iWal, WalIterator **pp){
-static int walIteratorInit(Wal *pWal, u32 nBackfill, WalIterator **pp){
++static int walIteratorInit(
++ Wal *pWal,
++ int iWal,
++ u32 nBackfill,
++ WalIterator **pp
++){
WalIterator *p; /* Return value */
int nSegment; /* Number of segments to merge */
u32 iLast; /* Last frame in log */
int nByte; /* Number of bytes to allocate */
int i; /* Iterator variable */
+ int iLastSeg; /* Last hash table to iterate though */
ht_slot *aTmp; /* Temp space used by merge-sort */
int rc = SQLITE_OK; /* Return Code */
+ int iMode = isWalMode2(pWal) ? 2 : 1;
+
+ assert( isWalMode2(pWal) || iWal==0 );
++ assert( 0==isWalMode2(pWal) || nBackfill==0 );
/* This routine only runs while holding the checkpoint lock. And
** it only runs if there is actually content in the log (mxFrame>0).
rc = SQLITE_NOMEM_BKPT;
}
- for(i=iWal; rc==SQLITE_OK && i<=iLastSeg; i+=iMode){
- volatile ht_slot *aHash;
- u32 iExtZero;
- volatile u32 *aPgno;
- for(i=walFramePage(nBackfill+1); rc==SQLITE_OK && i<nSegment; i++){
++ i = iMode==2 ? iWal : walFramePage(nBackfill+1);
++ for(; rc==SQLITE_OK && i<=iLastSeg; i+=iMode){
+ WalHashLoc sLoc;
- rc = walHashGet(pWal, i, &aHash, &aPgno, &iExtZero);
+ rc = walHashGet(pWal, i, &sLoc);
if( rc==SQLITE_OK ){
int j; /* Counter variable */
int nEntry; /* Number of entries in this segment */
ht_slot *aIndex; /* Sorted index for this segment */
- walExternalDecode(iExtZero+1, &iZero);
+ u32 iZero;
+
+ if( iMode==2 ){
- iZero = iExtZero;
++ walExternalDecode(sLoc.iZero+1, &iZero);
+ iZero--;
+ assert( iZero==0 || i>=2 );
+ }else{
++ iZero = sLoc.iZero;
+ }
- aPgno++;
+ sLoc.aPgno++;
- if( (i+1)==nSegment ){
- nEntry = (int)(iLast - sLoc.iZero);
+ if( i==iLastSeg ){
+ nEntry = (int)(iLast - iZero);
}else{
- nEntry = (int)((u32*)aHash - (u32*)aPgno);
+ nEntry = (int)((u32*)sLoc.aHash - (u32*)sLoc.aPgno);
}
- aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[sLoc.iZero];
- sLoc.iZero++;
+ aIndex = &((ht_slot *)&p->aSegment[p->nSegment])[iZero];
+ iZero++;
for(j=0; j<nEntry; j++){
aIndex[j] = (ht_slot)j;
}
- walMergesort((u32 *)aPgno, aTmp, aIndex, &nEntry);
- walMergesort((u32 *)sLoc.aPgno, aTmp, aIndex, &nEntry);
- p->aSegment[i].iZero = sLoc.iZero;
- p->aSegment[i].nEntry = nEntry;
- p->aSegment[i].aIndex = aIndex;
- p->aSegment[i].aPgno = (u32 *)sLoc.aPgno;
++ walMergesort((u32*)sLoc.aPgno, aTmp, aIndex, &nEntry);
+ p->aSegment[i/iMode].iZero = iZero;
+ p->aSegment[i/iMode].nEntry = nEntry;
+ p->aSegment[i/iMode].aIndex = aIndex;
- p->aSegment[i/iMode].aPgno = (u32 *)aPgno;
++ p->aSegment[i/iMode].aPgno = (u32*)sLoc.aPgno;
}
}
sqlite3_free(aTmp);
testcase( szPage<=32768 );
testcase( szPage>=65536 );
pInfo = walCkptInfo(pWal);
- if( pInfo->nBackfill<pWal->hdr.mxFrame ){
+ if( (bWal2==1 && pInfo->nBackfill==0 && mxSafeFrame)
- || (bWal2==0 && pInfo->nBackfill<mxSafeFrame)
++ || (bWal2==0 && pInfo->nBackfill<mxSafeFrame)
+ ){
+ sqlite3_file *pWalFd = pWal->apWalFd[iCkpt];
+ mxPage = pWal->hdr.nPage;
+
+ /* If this is a wal2 system, check for a reader holding a lock
+ ** preventing this checkpoint operation. If one is found, return
+ ** early. */
+ if( bWal2 ){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(1 + iCkpt*2), 1);
+ if( rc!=SQLITE_OK ) return rc;
+ }
- /* Allocate the iterator */
- rc = walIteratorInit(pWal, iCkpt, &pIter);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- assert( pIter );
-
/* EVIDENCE-OF: R-62920-47450 The busy-handler callback is never invoked
** in the SQLITE_CHECKPOINT_PASSIVE mode. */
assert( eMode!=SQLITE_CHECKPOINT_PASSIVE || xBusy==0 );
-
- /* Compute in mxSafeFrame the index of the last frame of the WAL that is
- ** safe to write into the database. Frames beyond mxSafeFrame might
- ** overwrite database pages that are in use by active readers and thus
- ** cannot be backfilled from the WAL.
+ /* If this is a wal system (not wal2), compute in mxSafeFrame the index
+ ** of the last frame of the WAL that is safe to write into the database.
+ ** Frames beyond mxSafeFrame might overwrite database pages that are in
+ ** use by active readers and thus cannot be backfilled from the WAL.
*/
- mxSafeFrame = pWal->hdr.mxFrame;
- mxPage = pWal->hdr.nPage;
- for(i=1; i<WAL_NREADER; i++){
- /* Thread-sanitizer reports that the following is an unsafe read,
- ** as some other thread may be in the process of updating the value
- ** of the aReadMark[] slot. The assumption here is that if that is
- ** happening, the other client may only be increasing the value,
- ** not decreasing it. So assuming either that either the "old" or
- ** "new" version of the value is read, and not some arbitrary value
- ** that would never be written by a real client, things are still
- ** safe. */
- u32 y = pInfo->aReadMark[i];
- if( mxSafeFrame>y ){
- assert( y<=pWal->hdr.mxFrame );
- rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
- if( rc==SQLITE_OK ){
- pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- }else if( rc==SQLITE_BUSY ){
- mxSafeFrame = y;
- xBusy = 0;
- }else{
- goto walcheckpoint_out;
+ if( bWal2==0 ){
++ mxSafeFrame = pWal->hdr.mxFrame;
++ mxPage = pWal->hdr.nPage;
+ for(i=1; i<WAL_NREADER; i++){
+ /* Thread-sanitizer reports that the following is an unsafe read,
+ ** as some other thread may be in the process of updating the value
+ ** of the aReadMark[] slot. The assumption here is that if that is
+ ** happening, the other client may only be increasing the value,
+ ** not decreasing it. So assuming either that either the "old" or
+ ** "new" version of the value is read, and not some arbitrary value
+ ** that would never be written by a real client, things are still
+ ** safe. */
+ u32 y = pInfo->aReadMark[i];
+ if( mxSafeFrame>y ){
+ assert( y<=pWal->hdr.mxFrame );
+ rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
+ pInfo->aReadMark[i] = (i==1 ? mxSafeFrame : READMARK_NOT_USED);
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ }else if( rc==SQLITE_BUSY ){
+ mxSafeFrame = y;
+ xBusy = 0;
+ }else{
+ goto walcheckpoint_out;
+ }
}
}
}
- if( bWal2 || (pInfo->nBackfill<mxSafeFrame
+ /* Allocate the iterator */
- if( pInfo->nBackfill<mxSafeFrame ){
- rc = walIteratorInit(pWal, pInfo->nBackfill, &pIter);
++ if( bWal2 || pInfo->nBackfill<mxSafeFrame ){
++ assert( bWal2==0 || pInfo->nBackfill==0 );
++ rc = walIteratorInit(pWal, iCkpt, pInfo->nBackfill, &pIter);
+ assert( rc==SQLITE_OK || pIter==0 );
+ }
+
+ if( pIter
&& (rc = walBusyLock(pWal, xBusy, pBusyArg, WAL_READ_LOCK(0),1))==SQLITE_OK
- )){
- i64 nSize; /* Current size of database file */
+ ){
u32 nBackfill = pInfo->nBackfill;
+ assert( bWal2==0 || nBackfill==0 );
pInfo->nBackfillAttempted = mxSafeFrame;
- /* Sync the WAL to disk */
- rc = sqlite3OsSync(pWal->pWalFd, CKPT_SYNC_FLAGS(sync_flags));
+ /* Sync the wal file being checkpointed to disk */
+ rc = sqlite3OsSync(pWalFd, CKPT_SYNC_FLAGS(sync_flags));
/* 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 ){
i64 nReq = ((i64)mxPage * szPage);
+ i64 nSize; /* Current size of database file */
rc = sqlite3OsFileSize(pWal->pDbFd, &nSize);
if( rc==SQLITE_OK && nSize<nReq ){
sqlite3OsFileControlHint(pWal->pDbFd, SQLITE_FCNTL_SIZE_HINT, &nReq);
if( rc!=SQLITE_OK ) break;
}
- /* Truncate the db file, sync the wal file and set the WalCkptInfo
- ** flag to indicate that it has been checkpointed. */
- /* If work was actually accomplished... */
- if( rc==SQLITE_OK ){
- if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
++ /* If work was actually accomplished, truncate the db file, sync the wal
++ ** file and set WalCkptInfo.nBackfill to indicate so. */
+ if( rc==SQLITE_OK && (bWal2 || mxSafeFrame==walIndexHdr(pWal)->mxFrame) ){
+ if( !bWal2 ){
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
rc = sqlite3OsTruncate(pWal->pDbFd, szDb);
** sure the wal-index was not constructed with some future format that
** this version of SQLite cannot understand.
*/
- if( badHdr==0 && pWal->hdr.iVersion!=WALINDEX_MAX_VERSION ){
+ if( badHdr==0
+ && pWal->hdr.iVersion!=WAL_VERSION1 && pWal->hdr.iVersion!=WAL_VERSION2
+ ){
rc = SQLITE_CANTOPEN_BKPT;
}
+ if( pWal->bShmUnreliable ){
+ if( rc!=SQLITE_OK ){
+ walIndexClose(pWal, 0);
+ pWal->bShmUnreliable = 0;
+ assert( pWal->nWiData>0 && pWal->apWiData[0]==0 );
+ /* walIndexRecover() might have returned SHORT_READ if a concurrent
+ ** writer truncated the WAL out from under it. If that happens, it
+ ** indicates that a writer has fixed the SHM file for us, so retry */
+ if( rc==SQLITE_IOERR_SHORT_READ ) rc = WAL_RETRY;
+ }
+ pWal->exclusiveMode = WAL_NORMAL_MODE;
+ }
return rc;
}
/*
- ** This is the value that walTryBeginRead returns when it needs to
- ** be retried.
+ ** Open a transaction in a connection where the shared-memory is read-only
+ ** and where we cannot verify that there is a separate write-capable connection
+ ** on hand to keep the shared-memory up-to-date with the WAL file.
+ **
+ ** This can happen, for example, when the shared-memory is implemented by
+ ** memory-mapping a *-shm file, where a prior writer has shut down and
+ ** left the *-shm file on disk, and now the present connection is trying
+ ** to use that database but lacks write permission on the *-shm file.
+ ** Other scenarios are also possible, depending on the VFS implementation.
+ **
+ ** Precondition:
+ **
+ ** The *-wal file has been read and an appropriate wal-index has been
+ ** constructed in pWal->apWiData[] using heap memory instead of shared
+ ** memory.
+ **
+ ** If this function returns SQLITE_OK, then the read transaction has
+ ** been successfully opened. In this case output variable (*pChanged)
+ ** is set to true before returning if the caller should discard the
+ ** contents of the page cache before proceeding. Or, if it returns
+ ** WAL_RETRY, then the heap memory wal-index has been discarded and
+ ** the caller should retry opening the read transaction from the
+ ** beginning (including attempting to map the *-shm file).
+ **
+ ** If an error occurs, an SQLite error code is returned.
*/
- #define WAL_RETRY (-1)
+ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){
+ i64 szWal; /* Size of wal file on disk in bytes */
+ i64 iOffset; /* Current offset when reading wal file */
+ u8 aBuf[WAL_HDRSIZE]; /* Buffer to load WAL header into */
+ u8 *aFrame = 0; /* Malloc'd buffer to load entire frame */
+ int szFrame; /* Number of bytes in buffer aFrame[] */
+ u8 *aData; /* Pointer to data part of aFrame buffer */
+ volatile void *pDummy; /* Dummy argument for xShmMap */
+ int rc; /* Return code */
+ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */
+
+ assert( pWal->bShmUnreliable );
+ assert( pWal->readOnly & WAL_SHM_RDONLY );
+ assert( pWal->nWiData>0 && pWal->apWiData[0] );
+
+ /* Take WAL_READ_LOCK(0). This has the effect of preventing any
+ ** writers from running a checkpoint, but does not stop them
+ ** from running recovery. */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ if( rc!=SQLITE_OK ){
+ if( rc==SQLITE_BUSY ) rc = WAL_RETRY;
+ goto begin_unreliable_shm_out;
+ }
+ pWal->readLock = 0;
+
+ /* Check to see if a separate writer has attached to the shared-memory area,
+ ** thus making the shared-memory "reliable" again. Do this by invoking
+ ** the xShmMap() routine of the VFS and looking to see if the return
+ ** is SQLITE_READONLY instead of SQLITE_READONLY_CANTINIT.
+ **
+ ** If the shared-memory is now "reliable" return WAL_RETRY, which will
+ ** cause the heap-memory WAL-index to be discarded and the actual
+ ** shared memory to be used in its place.
+ **
+ ** This step is important because, even though this connection is holding
+ ** the WAL_READ_LOCK(0) which prevents a checkpoint, a writer might
+ ** have already checkpointed the WAL file and, while the current
+ ** is active, wrap the WAL and start overwriting frames that this
+ ** process wants to use.
+ **
+ ** Once sqlite3OsShmMap() has been called for an sqlite3_file and has
+ ** returned any SQLITE_READONLY value, it must return only SQLITE_READONLY
+ ** or SQLITE_READONLY_CANTINIT or some error for all subsequent invocations,
+ ** even if some external agent does a "chmod" to make the shared-memory
+ ** writable by us, until sqlite3OsShmUnmap() has been called.
+ ** This is a requirement on the VFS implementation.
+ */
+ rc = sqlite3OsShmMap(pWal->pDbFd, 0, WALINDEX_PGSZ, 0, &pDummy);
+ assert( rc!=SQLITE_OK ); /* SQLITE_OK not possible for read-only connection */
+ if( rc!=SQLITE_READONLY_CANTINIT ){
+ rc = (rc==SQLITE_READONLY ? WAL_RETRY : rc);
+ goto begin_unreliable_shm_out;
+ }
+
+ /* We reach this point only if the real shared-memory is still unreliable.
+ ** Assume the in-memory WAL-index substitute is correct and load it
+ ** into pWal->hdr.
+ */
+ memcpy(&pWal->hdr, (void*)walIndexHdr(pWal), sizeof(WalIndexHdr));
+
+ /* Make sure some writer hasn't come in and changed the WAL file out
+ ** from under us, then disconnected, while we were not looking.
+ */
- rc = sqlite3OsFileSize(pWal->pWalFd, &szWal);
++ rc = sqlite3OsFileSize(pWal->apWalFd[0], &szWal);
+ if( rc!=SQLITE_OK ){
+ goto begin_unreliable_shm_out;
+ }
+ if( szWal<WAL_HDRSIZE ){
+ /* If the wal file is too small to contain a wal-header and the
+ ** wal-index header has mxFrame==0, then it must be safe to proceed
+ ** reading the database file only. However, the page cache cannot
+ ** be trusted, as a read/write connection may have connected, written
+ ** the db, run a checkpoint, truncated the wal file and disconnected
+ ** since this client's last read transaction. */
+ *pChanged = 1;
+ rc = (pWal->hdr.mxFrame==0 ? SQLITE_OK : WAL_RETRY);
+ goto begin_unreliable_shm_out;
+ }
+
+ /* Check the salt keys at the start of the wal file still match. */
- rc = sqlite3OsRead(pWal->pWalFd, aBuf, WAL_HDRSIZE, 0);
++ rc = sqlite3OsRead(pWal->apWalFd[0], aBuf, WAL_HDRSIZE, 0);
+ if( rc!=SQLITE_OK ){
+ goto begin_unreliable_shm_out;
+ }
+ if( memcmp(&pWal->hdr.aSalt, &aBuf[16], 8) ){
+ /* Some writer has wrapped the WAL file while we were not looking.
+ ** Return WAL_RETRY which will cause the in-memory WAL-index to be
+ ** rebuilt. */
+ rc = WAL_RETRY;
+ goto begin_unreliable_shm_out;
+ }
+
+ /* Allocate a buffer to read frames into */
+ szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE;
+ aFrame = (u8 *)sqlite3_malloc64(szFrame);
+ if( aFrame==0 ){
+ rc = SQLITE_NOMEM_BKPT;
+ goto begin_unreliable_shm_out;
+ }
+ aData = &aFrame[WAL_FRAME_HDRSIZE];
+
+ /* Check to see if a complete transaction has been appended to the
+ ** wal file since the heap-memory wal-index was created. If so, the
+ ** heap-memory wal-index is discarded and WAL_RETRY returned to
+ ** the caller. */
+ aSaveCksum[0] = pWal->hdr.aFrameCksum[0];
+ aSaveCksum[1] = pWal->hdr.aFrameCksum[1];
+ for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage);
+ iOffset+szFrame<=szWal;
+ iOffset+=szFrame
+ ){
+ u32 pgno; /* Database page number for frame */
+ u32 nTruncate; /* dbsize field from frame header */
+
+ /* Read and decode the next log frame. */
- rc = sqlite3OsRead(pWal->pWalFd, aFrame, szFrame, iOffset);
++ rc = sqlite3OsRead(pWal->apWalFd[0], aFrame, szFrame, iOffset);
+ if( rc!=SQLITE_OK ) break;
+ if( !walDecodeFrame(pWal, &pgno, &nTruncate, aData, aFrame) ) break;
+
+ /* If nTruncate is non-zero, then a complete transaction has been
+ ** appended to this wal file. Set rc to WAL_RETRY and break out of
+ ** the loop. */
+ if( nTruncate ){
+ rc = WAL_RETRY;
+ break;
+ }
+ }
+ pWal->hdr.aFrameCksum[0] = aSaveCksum[0];
+ pWal->hdr.aFrameCksum[1] = aSaveCksum[1];
+
+ begin_unreliable_shm_out:
+ sqlite3_free(aFrame);
+ if( rc!=SQLITE_OK ){
+ int i;
+ for(i=0; i<pWal->nWiData; i++){
+ sqlite3_free((void*)pWal->apWiData[i]);
+ pWal->apWiData[i] = 0;
+ }
+ pWal->bShmUnreliable = 0;
+ sqlite3WalEndReadTransaction(pWal);
+ *pChanged = 1;
+ }
+ return rc;
+ }
/*
** Attempt to start a read transaction. This might fail due to a race or
*/
static int walTryBeginRead(Wal *pWal, int *pChanged, int useWal, int cnt){
volatile WalCkptInfo *pInfo; /* Checkpoint information in wal-index */
- u32 mxReadMark; /* Largest aReadMark[] value */
- int mxI; /* Index of largest aReadMark[] value */
- int i; /* Loop counter */
int rc = SQLITE_OK; /* Return code */
- u32 mxFrame; /* Wal frame to lock to */
- assert( pWal->readLock<0 ); /* Not currently locked */
+ assert( pWal->readLock==WAL_LOCK_NONE ); /* Not currently locked */
+ /* useWal may only be set for read/write connections */
+ assert( (pWal->readOnly & WAL_SHM_RDONLY)==0 || useWal==0 );
+
/* Take steps to avoid spinning forever if there is a protocol error.
**
** Circumstances that cause a RETRY should only last for the briefest
if( rc!=SQLITE_OK ){
return rc;
}
+ else if( pWal->bShmUnreliable ){
+ return walBeginShmUnreliable(pWal, pChanged);
+ }
}
+ assert( pWal->nWiData>0 );
+ assert( pWal->apWiData[0]!=0 );
pInfo = walCkptInfo(pWal);
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
-#ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
-#endif
- ){
- /* The WAL has been completely backfilled (or it is empty).
- ** and can be safely ignored.
- */
- rc = walLockShared(pWal, WAL_READ_LOCK(0));
- walShmBarrier(pWal);
- if( rc==SQLITE_OK ){
- if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
- /* It is not safe to allow the reader to continue here if frames
- ** may have been appended to the log before READ_LOCK(0) was obtained.
- ** When holding READ_LOCK(0), the reader ignores the entire log file,
- ** which implies that the database file contains a trustworthy
- ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
- ** happening, this is usually correct.
- **
- ** However, if frames have been appended to the log (or if the log
- ** is wrapped and written for that matter) before the READ_LOCK(0)
- ** is obtained, that is not necessarily true. A checkpointer may
- ** have started to backfill the appended frames but crashed before
- ** it finished. Leaving a corrupt image in the database file.
- */
- walUnlockShared(pWal, WAL_READ_LOCK(0));
- return WAL_RETRY;
- }
- pWal->readLock = 0;
- return SQLITE_OK;
- }else if( rc!=SQLITE_BUSY ){
+ if( isWalMode2(pWal) ){
+ int eLock = 1 + (walidxGetFile(&pWal->hdr)*2);
+ if( pInfo->nBackfill==0 ){
+ eLock += walidxGetMxFrame(&pWal->hdr, !walidxGetFile(&pWal->hdr))>0;
+ }
+ rc = walLockReader(pWal, eLock, 1);
+ if( rc!=SQLITE_OK ){
return rc;
}
- }
- /* If we get this far, it means that the reader will want to use
- ** the WAL to get at content from recent commits. The job now is
- ** to select one of the aReadMark[] entries that is closest to
- ** but not exceeding pWal->hdr.mxFrame and lock that entry.
- */
- mxReadMark = 0;
- mxI = 0;
- mxFrame = pWal->hdr.mxFrame;
-#ifdef SQLITE_ENABLE_SNAPSHOT
- if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
- mxFrame = pWal->pSnapshot->mxFrame;
- }
-#endif
- for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
- if( mxReadMark<=thisMark && thisMark<=mxFrame ){
- assert( thisMark!=READMARK_NOT_USED );
- mxReadMark = thisMark;
- mxI = i;
+ walShmBarrier(pWal);
+ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
+ walLockReader(pWal, eLock, 0);
+ return WAL_RETRY;
+ }else{
+ pWal->readLock = eLock;
}
- }
- if( (pWal->readOnly & WAL_SHM_RDONLY)==0
- && (mxReadMark<mxFrame || mxI==0)
- ){
- for(i=1; i<WAL_NREADER; i++){
- rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ assert( pWal->minFrame==0 && walFramePage(pWal->minFrame)==0 );
+ }else{
+ u32 mxReadMark; /* Largest aReadMark[] value */
+ int mxI; /* Index of largest aReadMark[] value */
+ int i; /* Loop counter */
+ u32 mxFrame; /* Wal frame to lock to */
-
- if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
- #ifdef SQLITE_ENABLE_SNAPSHOT
- && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0
- || 0==memcmp(&pWal->hdr, pWal->pSnapshot, sizeof(WalIndexHdr)))
- #endif
- ){
++ if( !useWal && pInfo->nBackfill==pWal->hdr.mxFrame
++ #ifdef SQLITE_ENABLE_SNAPSHOT
++ && (pWal->pSnapshot==0 || pWal->hdr.mxFrame==0)
++ #endif
++ ){
+ /* The WAL has been completely backfilled (or it is empty).
+ ** and can be safely ignored.
+ */
+ rc = walLockShared(pWal, WAL_READ_LOCK(0));
+ walShmBarrier(pWal);
if( rc==SQLITE_OK ){
- if( memcmp((void*)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr)) ){
- mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame);
- mxI = i;
- walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
- break;
++ if( memcmp((void *)walIndexHdr(pWal), &pWal->hdr,sizeof(WalIndexHdr)) ){
+ /* It is not safe to allow the reader to continue here if frames
+ ** may have been appended to the log before READ_LOCK(0) was obtained.
+ ** When holding READ_LOCK(0), the reader ignores the entire log file,
+ ** which implies that the database file contains a trustworthy
+ ** snapshot. Since holding READ_LOCK(0) prevents a checkpoint from
+ ** happening, this is usually correct.
+ **
+ ** However, if frames have been appended to the log (or if the log
+ ** is wrapped and written for that matter) before the READ_LOCK(0)
+ ** is obtained, that is not necessarily true. A checkpointer may
+ ** have started to backfill the appended frames but crashed before
+ ** it finished. Leaving a corrupt image in the database file.
+ */
+ walUnlockShared(pWal, WAL_READ_LOCK(0));
+ return WAL_RETRY;
+ }
+ pWal->readLock = 0;
+ return SQLITE_OK;
}else if( rc!=SQLITE_BUSY ){
return rc;
}
}
- }
- if( mxI==0 ){
- assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
- }
--
- rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
- if( rc ){
- return rc==SQLITE_BUSY ? WAL_RETRY : rc;
- }
- /* Now that the read-lock has been obtained, check that neither the
- ** value in the aReadMark[] array or the contents of the wal-index
- ** header have changed.
- **
- ** It is necessary to check that the wal-index header did not change
- ** between the time it was read and when the shared-lock was obtained
- ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
- ** that the log file may have been wrapped by a writer, or that frames
- ** that occur later in the log than pWal->hdr.mxFrame may have been
- ** copied into the database by a checkpointer. If either of these things
- ** happened, then reading the database with the current value of
- ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
- ** instead.
- **
- ** Before checking that the live wal-index header has not changed
- ** since it was read, set Wal.minFrame to the first frame in the wal
- ** file that has not yet been checkpointed. This client will not need
- ** to read any frames earlier than minFrame from the wal file - they
- ** can be safely read directly from the database file.
- **
- ** Because a ShmBarrier() call is made between taking the copy of
- ** nBackfill and checking that the wal-header in shared-memory still
- ** matches the one cached in pWal->hdr, it is guaranteed that the
- ** checkpointer that set nBackfill was not working with a wal-index
- ** header newer than that cached in pWal->hdr. If it were, that could
- ** cause a problem. The checkpointer could omit to checkpoint
- ** a version of page X that lies before pWal->minFrame (call that version
- ** A) on the basis that there is a newer version (version B) of the same
- ** page later in the wal file. But if version B happens to like past
- ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
- ** that it can read version A from the database file. However, since
- ** we can guarantee that the checkpointer that set nBackfill could not
- ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
- */
- pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
- walShmBarrier(pWal);
- if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
- || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
- ){
- walUnlockShared(pWal, WAL_READ_LOCK(mxI));
- return WAL_RETRY;
- }else{
- assert( mxReadMark<=pWal->hdr.mxFrame );
- pWal->readLock = (i16)mxI;
++
+ /* If we get this far, it means that the reader will want to use
+ ** the WAL to get at content from recent commits. The job now is
+ ** to select one of the aReadMark[] entries that is closest to
+ ** but not exceeding pWal->hdr.mxFrame and lock that entry.
+ */
+ mxReadMark = 0;
+ mxI = 0;
+ mxFrame = pWal->hdr.mxFrame;
- #ifdef SQLITE_ENABLE_SNAPSHOT
++ #ifdef SQLITE_ENABLE_SNAPSHOT
+ if( pWal->pSnapshot && pWal->pSnapshot->mxFrame<mxFrame ){
+ mxFrame = pWal->pSnapshot->mxFrame;
+ }
- #endif
++ #endif
+ for(i=1; i<WAL_NREADER; i++){
- u32 thisMark = pInfo->aReadMark[i];
++ u32 thisMark = AtomicLoad(pInfo->aReadMark+i);
+ if( mxReadMark<=thisMark && thisMark<=mxFrame ){
+ assert( thisMark!=READMARK_NOT_USED );
+ mxReadMark = thisMark;
+ mxI = i;
+ }
+ }
+ if( (pWal->readOnly & WAL_SHM_RDONLY)==0
- && (mxReadMark<mxFrame || mxI==0)
- ){
++ && (mxReadMark<mxFrame || mxI==0)
++ ){
+ for(i=1; i<WAL_NREADER; i++){
+ rc = walLockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ if( rc==SQLITE_OK ){
- mxReadMark = pInfo->aReadMark[i] = mxFrame;
++ mxReadMark = AtomicStore(pInfo->aReadMark+i,mxFrame);
+ mxI = i;
+ walUnlockExclusive(pWal, WAL_READ_LOCK(i), 1);
+ break;
+ }else if( rc!=SQLITE_BUSY ){
+ return rc;
+ }
+ }
+ }
+ if( mxI==0 ){
+ assert( rc==SQLITE_BUSY || (pWal->readOnly & WAL_SHM_RDONLY)!=0 );
- return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTLOCK;
++ return rc==SQLITE_BUSY ? WAL_RETRY : SQLITE_READONLY_CANTINIT;
+ }
-
++
+ rc = walLockShared(pWal, WAL_READ_LOCK(mxI));
+ if( rc ){
+ return rc==SQLITE_BUSY ? WAL_RETRY : rc;
+ }
+ /* Now that the read-lock has been obtained, check that neither the
+ ** value in the aReadMark[] array or the contents of the wal-index
+ ** header have changed.
+ **
+ ** It is necessary to check that the wal-index header did not change
+ ** between the time it was read and when the shared-lock was obtained
+ ** on WAL_READ_LOCK(mxI) was obtained to account for the possibility
+ ** that the log file may have been wrapped by a writer, or that frames
+ ** that occur later in the log than pWal->hdr.mxFrame may have been
+ ** copied into the database by a checkpointer. If either of these things
+ ** happened, then reading the database with the current value of
+ ** pWal->hdr.mxFrame risks reading a corrupted snapshot. So, retry
+ ** instead.
+ **
+ ** Before checking that the live wal-index header has not changed
+ ** since it was read, set Wal.minFrame to the first frame in the wal
+ ** file that has not yet been checkpointed. This client will not need
+ ** to read any frames earlier than minFrame from the wal file - they
+ ** can be safely read directly from the database file.
+ **
+ ** Because a ShmBarrier() call is made between taking the copy of
+ ** nBackfill and checking that the wal-header in shared-memory still
+ ** matches the one cached in pWal->hdr, it is guaranteed that the
+ ** checkpointer that set nBackfill was not working with a wal-index
+ ** header newer than that cached in pWal->hdr. If it were, that could
+ ** cause a problem. The checkpointer could omit to checkpoint
+ ** a version of page X that lies before pWal->minFrame (call that version
+ ** A) on the basis that there is a newer version (version B) of the same
+ ** page later in the wal file. But if version B happens to like past
+ ** frame pWal->hdr.mxFrame - then the client would incorrectly assume
+ ** that it can read version A from the database file. However, since
+ ** we can guarantee that the checkpointer that set nBackfill could not
+ ** see any pages past pWal->hdr.mxFrame, this problem does not come up.
+ */
- pWal->minFrame = pInfo->nBackfill+1;
++ pWal->minFrame = AtomicLoad(&pInfo->nBackfill)+1;
+ walShmBarrier(pWal);
- if( pInfo->aReadMark[mxI]!=mxReadMark
- || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
- ){
++ if( AtomicLoad(pInfo->aReadMark+mxI)!=mxReadMark
++ || memcmp((void *)walIndexHdr(pWal), &pWal->hdr, sizeof(WalIndexHdr))
++ ){
+ walUnlockShared(pWal, WAL_READ_LOCK(mxI));
+ return WAL_RETRY;
+ }else{
+ assert( mxReadMark<=pWal->hdr.mxFrame );
+ pWal->readLock = (i16)mxI;
+ }
}
return rc;
}
if( iDbOff+szPage<=szDb ){
iWalOff = walFrameOffset(i, szPage) + WAL_FRAME_HDRSIZE;
-- rc = sqlite3OsRead(pWal->pWalFd, pBuf1, szPage, iWalOff);
++ rc = sqlite3OsRead(pWal->apWalFd[0], pBuf1, szPage, iWalOff);
if( rc==SQLITE_OK ){
rc = sqlite3OsRead(pWal->pDbFd, pBuf2, szPage, iDbOff);
}
}
- volatile ht_slot *aHash; /* Pointer to hash table */
- volatile u32 *aPgno; /* Pointer to array of page numbers */
- u32 iZero; /* Frame number corresponding to aPgno[0] */
+/* Search hash table iHash for an entry matching page number
+** pgno. Each call to this function searches a single hash table
+** (each hash table indexes up to HASHTABLE_NPAGE frames).
+**
+** This code might run concurrently to the code in walIndexAppend()
+** that adds entries to the wal-index (and possibly to this hash
+** table). This means the value just read from the hash
+** slot (aHash[iKey]) may have been added before or after the
+** current read transaction was opened. Values added after the
+** read transaction was opened may have been written incorrectly -
+** i.e. these slots may contain garbage data. However, we assume
+** that any slots written before the current read transaction was
+** opened remain unmodified.
+**
+** For the reasons above, the if(...) condition featured in the inner
+** loop of the following block is more stringent that would be required
+** if we had exclusive access to the hash-table:
+**
+** (aPgno[iFrame]==pgno):
+** This condition filters out normal hash-table collisions.
+**
+** (iFrame<=iLast):
+** This condition filters out entries that were added to the hash
+** table after the current read-transaction had started.
+*/
+static int walSearchHash(
+ Wal *pWal,
+ u32 iLast,
+ int iHash,
+ Pgno pgno,
+ u32 *piRead
+){
- rc = walHashGet(pWal, iHash, &aHash, &aPgno, &iZero);
++ WalHashLoc sLoc; /* Hash table location */
+ int iKey; /* Hash slot index */
+ int nCollide; /* Number of hash collisions remaining */
+ int rc; /* Error code */
+
- for(iKey=walHash(pgno); aHash[iKey]; iKey=walNextHash(iKey)){
- u32 iFrame = aHash[iKey] + iZero;
- if( iFrame<=iLast && iFrame>=pWal->minFrame && aPgno[aHash[iKey]]==pgno ){
++ rc = walHashGet(pWal, iHash, &sLoc);
+ if( rc!=SQLITE_OK ){
+ return rc;
+ }
+ nCollide = HASHTABLE_NSLOT;
++ for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
++ u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero;
++ if( iFrame<=iLast
++ && iFrame>=pWal->minFrame
++ && sLoc.aPgno[sLoc.aHash[iKey]]==pgno
++ ){
+ assert( iFrame>*piRead || CORRUPT_DB );
+ *piRead = iFrame;
+ }
+ if( (nCollide--)==0 ){
+ return SQLITE_CORRUPT_BKPT;
+ }
+ }
+
+ return SQLITE_OK;
+}
+
+static int walSearchWal(
+ Wal *pWal,
+ int iWal,
+ Pgno pgno,
+ u32 *piRead
+){
+ int rc = SQLITE_OK;
+ int bWal2 = isWalMode2(pWal);
+ u32 iLast = walidxGetMxFrame(&pWal->hdr, iWal);
+ if( iLast ){
+ int iHash;
+ int iMinHash = walFramePage(pWal->minFrame);
+ u32 iExternal = bWal2 ? walExternalEncode(iWal, iLast) : iLast;
+ assert( bWal2==0 || pWal->minFrame==0 );
+ for(iHash=walFramePage(iExternal);
+ iHash>=iMinHash && *piRead==0;
+ iHash-=(1+bWal2)
+ ){
+ rc = walSearchHash(pWal, iExternal, iHash, pgno, piRead);
+ if( rc!=SQLITE_OK ) break;
+ }
+ }
+ return rc;
+}
+
/*
** Search the wal file for page pgno. If found, set *piRead to the frame that
** contains the page. Otherwise, if pgno is not in the wal file, set *piRead
Pgno pgno, /* Database page number to read data for */
u32 *piRead /* OUT: Frame number (or zero) */
){
+ int bWal2 = isWalMode2(pWal);
+ int iApp = walidxGetFile(&pWal->hdr);
+ int rc = SQLITE_OK;
u32 iRead = 0; /* If !=0, WAL frame to return data from */
- u32 iLast = pWal->hdr.mxFrame; /* Last page in WAL for this reader */
- int iHash; /* Used to loop through N hash tables */
- int iMinHash;
/* This routine is only be called from within a read transaction. */
- assert( pWal->readLock>=0 || pWal->lockError );
+ assert( pWal->readLock!=WAL_LOCK_NONE );
- /* If the "last page" field of the wal-index header snapshot is 0, then
- ** no data will be read from the wal under any circumstances. Return early
- ** in this case as an optimization. Likewise, if pWal->readLock==0,
- ** then the WAL is ignored by the reader so return early, as if the
- ** WAL were empty.
- */
- if( iLast==0 || (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
+ /* If this is a wal2 system, the client must have a partial-wal lock
+ ** on wal file iApp. Or if it is a wal system, iApp==0 must be true. */
+ assert( bWal2==0 || iApp==1
+ || pWal->readLock==WAL_LOCK_PART1 || pWal->readLock==WAL_LOCK_PART1_FULL2
+ );
+ assert( bWal2==0 || iApp==0
+ || pWal->readLock==WAL_LOCK_PART2 || pWal->readLock==WAL_LOCK_PART2_FULL1
+ );
+ assert( bWal2 || iApp==0 );
+
- /* Search the wal file that the client holds a partial lock on first */
++ /* Return early if read-lock 0 is held. */
++ if( (pWal->readLock==0 && pWal->bShmUnreliable==0) ){
+ *piRead = 0;
+ return SQLITE_OK;
+ }
- /* Search the hash table or tables for an entry matching page number
- ** pgno. Each iteration of the following for() loop searches one
- ** hash table (each hash table indexes up to HASHTABLE_NPAGE frames).
- **
- ** This code might run concurrently to the code in walIndexAppend()
- ** that adds entries to the wal-index (and possibly to this hash
- ** table). This means the value just read from the hash
- ** slot (aHash[iKey]) may have been added before or after the
- ** current read transaction was opened. Values added after the
- ** read transaction was opened may have been written incorrectly -
- ** i.e. these slots may contain garbage data. However, we assume
- ** that any slots written before the current read transaction was
- ** opened remain unmodified.
- **
- ** For the reasons above, the if(...) condition featured in the inner
- ** loop of the following block is more stringent that would be required
- ** if we had exclusive access to the hash-table:
- **
- ** (aPgno[iFrame]==pgno):
- ** This condition filters out normal hash-table collisions.
- **
- ** (iFrame<=iLast):
- ** This condition filters out entries that were added to the hash
- ** table after the current read-transaction had started.
- */
- iMinHash = walFramePage(pWal->minFrame);
- for(iHash=walFramePage(iLast); iHash>=iMinHash; iHash--){
- WalHashLoc sLoc; /* Hash table location */
- int iKey; /* Hash slot index */
- int nCollide; /* Number of hash collisions remaining */
- int rc; /* Error code */
-
- rc = walHashGet(pWal, iHash, &sLoc);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- nCollide = HASHTABLE_NSLOT;
- for(iKey=walHash(pgno); sLoc.aHash[iKey]; iKey=walNextHash(iKey)){
- u32 iFrame = sLoc.aHash[iKey] + sLoc.iZero;
- if( iFrame<=iLast && iFrame>=pWal->minFrame
- && sLoc.aPgno[sLoc.aHash[iKey]]==pgno ){
- assert( iFrame>iRead || CORRUPT_DB );
- iRead = iFrame;
- }
- if( (nCollide--)==0 ){
- return SQLITE_CORRUPT_BKPT;
- }
- }
- if( iRead ) break;
++ /* Search the wal file that the client holds a partial lock on first */
+ rc = walSearchWal(pWal, iApp, pgno, &iRead);
+
+ /* If the requested page was not found, no error has occured, and
+ ** the client holds a full-wal lock on the other wal file, search it
+ ** too. */
+ if( rc==SQLITE_OK && bWal2 && iRead==0 && (
+ pWal->readLock==WAL_LOCK_PART1_FULL2
+ || pWal->readLock==WAL_LOCK_PART2_FULL1
+ )){
+ rc = walSearchWal(pWal, !iApp, pgno, &iRead);
}
+#if defined(SQLITE_TEST) && defined(SQLITE_DEBUG)
+ if( iRead ){
+ u32 iFrame;
+ int iWal = walExternalDecode(iRead, &iFrame);
+ WALTRACE(("WAL%p: page %d @ frame %d wal %d\n",pWal,(int)pgno,iFrame,iWal));
+ }else{
+ WALTRACE(("WAL%p: page %d not found\n", pWal, (int)pgno));
+ }
+#endif
+
#ifdef SQLITE_ENABLE_EXPENSIVE_ASSERT
/* If expensive assert() statements are available, do a linear search
** of the wal-index file content. Make sure the results agree with the
u8 aFrame[WAL_FRAME_HDRSIZE]; /* Buffer to assemble frame-headers in */
u32 iRead; /* Next frame to read from wal file */
i64 iCksumOff;
+ sqlite3_file *pWalFd = pWal->apWalFd[walidxGetFile(&pWal->hdr)];
- assert( isWalMode2(pWal)==0 );
-
aBuf = sqlite3_malloc(szPage + WAL_FRAME_HDRSIZE);
if( aBuf==0 ) return SQLITE_NOMEM_BKPT;
** locks are taken in this case). Nor should the pager attempt to
** upgrade to exclusive-mode following such an error.
*/
- assert( pWal->readLock>=0 || pWal->lockError );
- assert( pWal->readLock>=0 || (op<=0 && pWal->exclusiveMode==0) );
+ assert( pWal->readLock!=WAL_LOCK_NONE || pWal->lockError );
+ assert( pWal->readLock!=WAL_LOCK_NONE || (op<=0 && pWal->exclusiveMode==0) );
if( op==0 ){
- if( pWal->exclusiveMode!=WAL_NORMAL_MODE ){
+ if( pWal->exclusiveMode ){
pWal->exclusiveMode = WAL_NORMAL_MODE;
- if( walLockShared(pWal, WAL_READ_LOCK(pWal->readLock))!=SQLITE_OK ){
+ if( isWalMode2(pWal) ){
+ rc = walLockReader(pWal, pWal->readLock, 1);
+ }else{
+ rc = walLockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ }
+ if( rc!=SQLITE_OK ){
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
}
- rc = pWal->exclusiveMode==0;
+ rc = pWal->exclusiveMode==WAL_NORMAL_MODE;
}else{
/* Already in locking_mode=NORMAL */
rc = 0;
}
}else if( op>0 ){
- assert( pWal->exclusiveMode==0 );
+ assert( pWal->exclusiveMode==WAL_NORMAL_MODE );
assert( pWal->readLock>=0 );
- walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ if( isWalMode2(pWal) ){
+ walLockReader(pWal, pWal->readLock, 0);
+ }else{
+ walUnlockShared(pWal, WAL_READ_LOCK(pWal->readLock));
+ }
pWal->exclusiveMode = WAL_EXCLUSIVE_MODE;
rc = 1;
}else{