1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-05 15:55:57 +03:00

Changes to avoid deadlock in SQLITE_ENABLE_SETLK_TIMEOUT builds.

FossilOrigin-Name: 553423c23142cf0ec219192315d57ce8a0e10c3d8678d28bc110a1a9a7c17cee
This commit is contained in:
dan
2020-05-04 19:42:35 +00:00
parent 995e1af9fa
commit 8714de97c0
10 changed files with 162 additions and 175 deletions

View File

@@ -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 \

View File

@@ -1,5 +1,5 @@
C Ensure\sthat\sthe\smaster-journal\sname\sis\sin\sa\sform\ssuitable\sto\sbe\spassed\ninto\ssqlite3_uri_parameter(). C Changes\sto\savoid\sdeadlock\sin\sSQLITE_ENABLE_SETLK_TIMEOUT\sbuilds.
D 2020-05-04T11:47:38.857 D 2020-05-04T19:42:35.009
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 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b F src/backup.c 5e617c087f1c2d6005c2ec694ce80d6e16bc68d906e1b1c556d7c7c2228b636b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6
F src/btree.c 3383ad76753193c3529318ba30db41747663639428d2f6cb7cbcd8034d4a99cd F src/btree.c 54d404ff88f1432fc056c638e4868fe66dac98cb0f89a6cae4bd6b636053af0f
F src/btree.h 989ef3c33413549e3e148f3dcb46c030f317dac130dc86809ba6b9aa4b16c72a F src/btree.h 989ef3c33413549e3e148f3dcb46c030f317dac130dc86809ba6b9aa4b16c72a
F src/btreeInt.h 887cdd2ea7f4a65143074a8a7c8928b0546f8c18dda3c06a408ce7992cbab0c0 F src/btreeInt.h 887cdd2ea7f4a65143074a8a7c8928b0546f8c18dda3c06a408ce7992cbab0c0
F src/build.c ec6c0bda1e43ef55e5f5121a77ba19fac51fc6585f95ce2da795bcedcf6e8f36 F src/build.c ec6c0bda1e43ef55e5f5121a77ba19fac51fc6585f95ce2da795bcedcf6e8f36
@@ -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 7e07ff5ec447451d28398d528fda25c272f86cce67bc59a9846ee5bdfb23e1d9 F src/main.c 28ec4d31a95affad6a6667762b55c28e67d43a195c33af03f98badc64158b916
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
@@ -520,8 +520,8 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
F src/os_unix.c 7ef8b60222558a373d89c18d0c3bc44365b45273a528183d40bec5bb76ce23fc F src/os_unix.c 7ef8b60222558a373d89c18d0c3bc44365b45273a528183d40bec5bb76ce23fc
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 8b5a3b3d12706a8692bf9b36ef0fb94029d855730f51e4615afddb9c7cc4b301
F src/pager.h 3b33619a90180e0874c7eca31d6f6ceb464d9322c6fb4e9a7bbb318c8a17bdb3 F src/pager.h eaf8bd9b78f5033a480f66d3a9b5426d04ee352586ee75b9bc7cd50670f6a5b1
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
@@ -538,7 +538,7 @@ F src/shell.c.in cf2d24f54412c06e5fb34af7fabc748651125e1dceac29b740e91f06d23447b
F src/sqlite.h.in 00fdd0a9cdcb4ca3ea6aed8466a23e158c4a2feb5c2552de62c70f40d2418289 F src/sqlite.h.in 00fdd0a9cdcb4ca3ea6aed8466a23e158c4a2feb5c2552de62c70f40d2418289
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 26de171e0adccf6e465434b9fcce18fcfcc757e9a727356b029fc1676639540c
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 b6c5fb152c9ed73017202b4ffda1ee97a8c6cc57a3596e29ab4b763207013d49
F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a F src/wal.h 642f7896526181a95dde213fe1a0a515899d8eb2fa7cb562f042b0637d11d3d7
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
@@ -1863,7 +1863,10 @@ 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 efdecb13091316aeac2722f58577cb0314e008e857f2816a2a222bac0a83e9e1 P d1ba026d882f070b351280028e2fa88a3cca59b46d4683302e24c6677e0951b9
R 6897970c2b5b2cca1a8fed26518d5a6e R 7034fe62283804a1df8fc178d6719787
U drh T *branch * setlk-deadlock-changes
Z ec3fad1620b6ab238b8dc4b9fa847a46 T *sym-setlk-deadlock-changes *
T -sym-trunk *
U dan
Z b3c62bfe3502546b0ce8fe477018d01b

View File

@@ -1 +1 @@
d1ba026d882f070b351280028e2fa88a3cca59b46d4683302e24c6677e0951b9 553423c23142cf0ec219192315d57ce8a0e10c3d8678d28bc110a1a9a7c17cee

View File

@@ -3467,7 +3467,6 @@ int sqlite3BtreeBeginTrans(Btree *p, int wrflag, int *pSchemaVersion){
} }
}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);
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
if( p->inTrans==TRANS_NONE ){ if( p->inTrans==TRANS_NONE ){

View File

@@ -1551,8 +1551,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
@@ -1566,31 +1565,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];
@@ -1610,7 +1584,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;
} }
@@ -1631,16 +1604,7 @@ static int sqliteDefaultBusyCallback(
int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){ int sqlite3InvokeBusyHandler(BusyHandler *p, sqlite3_file *pFile){
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{
@@ -1665,7 +1629,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;
@@ -1716,7 +1679,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);
} }
@@ -3359,7 +3321,7 @@ static int openDatabase(
#endif #endif
#ifdef SQLITE_ENABLE_BYTECODE_VTAB #ifdef SQLITE_ENABLE_BYTECODE_VTAB
if( !db->mallocFailed && rc==SQLITE_OK){ if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3VdbeBytecodeVtabInit(db); rc = sqlite3VdbeBytecodeVtabInit(db);
} }
#endif #endif
@@ -4520,11 +4482,11 @@ int sqlite3_snapshot_open(
rc = SQLITE_OK; rc = SQLITE_OK;
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3PagerSnapshotOpen(pPager, pSnapshot); rc = sqlite3PagerSnapshotOpen(pPager, db, pSnapshot);
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
rc = sqlite3BtreeBeginTrans(pBt, 0, 0); rc = sqlite3BtreeBeginTrans(pBt, 0, 0);
sqlite3PagerSnapshotOpen(pPager, 0); sqlite3PagerSnapshotOpen(pPager, 0, 0);
} }
if( bUnlock ){ if( bUnlock ){
sqlite3PagerSnapshotUnlock(pPager); sqlite3PagerSnapshotUnlock(pPager);

View File

@@ -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;
} }
@@ -7606,10 +7594,14 @@ 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 *db,
sqlite3_snapshot *pSnapshot
){
int rc = SQLITE_OK; int rc = SQLITE_OK;
if( pPager->pWal ){ if( pPager->pWal ){
sqlite3WalSnapshotOpen(pPager->pWal, pSnapshot); sqlite3WalSnapshotOpen(pPager->pWal, db, pSnapshot);
}else{ }else{
rc = SQLITE_ERROR; rc = SQLITE_ERROR;
} }

View File

@@ -177,8 +177,8 @@ 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*, 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);
@@ -210,11 +210,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);

View File

@@ -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 */
}; };
/* /*

222
src/wal.c
View File

@@ -466,6 +466,9 @@ struct Wal {
#endif #endif
#ifdef SQLITE_ENABLE_SNAPSHOT #ifdef SQLITE_ENABLE_SNAPSHOT
WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */ WalIndexHdr *pSnapshot; /* Start transaction here if not NULL */
# ifdef SQLITE_ENABLE_SETLK_TIMEOUT
sqlite3 *dbSnapshot;
# endif
#endif #endif
}; };
@@ -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.
@@ -2750,22 +2748,45 @@ 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;
#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; #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
} int busyTimeout = pWal->dbSnapshot->busyTimeout;
if( busyTimeout ){
int tmout = busyTimeout;
sqlite3OsFileControl(pWal->pDbFd,SQLITE_FCNTL_LOCK_TIMEOUT,(void*)&tmout);
}
#endif #endif
if( memcmp(pSnapshot, &pWal->hdr, sizeof(WalIndexHdr))!=0 ){
bChanged = 1;
}
/* It is possible that there is a checkpointer thread running
** concurrent with this code. If this is the case, it may be that the
** checkpointer has already determined that it will checkpoint
** 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. */
rc = walLockShared(pWal, WAL_CKPT_LOCK);
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
/* Disable blocking locks. They are not useful when trying to open a if( busyTimeout ){
** read-transaction, and blocking may cause deadlock anyway. */ int tmout = 0;
sqlite3OsFileControl(pWal->pDbFd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout); sqlite3OsFileControl(pWal->pDbFd,SQLITE_FCNTL_LOCK_TIMEOUT,(void*)&tmout);
}
#endif
if( rc!=SQLITE_OK ){
return rc;
}
}
#endif #endif
do{ do{
@@ -2776,16 +2797,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 +2818,40 @@ 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( pSnapshot ){
walUnlockShared(pWal, WAL_CKPT_LOCK);
}
#endif #endif
return rc; return rc;
} }
@@ -3584,6 +3587,9 @@ int sqlite3WalCheckpoint(
int isChanged = 0; /* True if a new wal-index header is loaded */ int isChanged = 0; /* True if a new wal-index header is loaded */
int eMode2 = eMode; /* Mode to pass to walCheckpoint() */ int eMode2 = eMode; /* Mode to pass to walCheckpoint() */
int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */ int (*xBusy2)(void*) = xBusy; /* Busy handler for eMode2 */
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
int bSetLk = 0;
#endif
assert( pWal->ckptLock==0 ); assert( pWal->ckptLock==0 );
assert( pWal->writeLock==0 ); assert( pWal->writeLock==0 );
@@ -3595,41 +3601,54 @@ 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 #ifdef SQLITE_ENABLE_SETLK_TIMEOUT
** "checkpoint" lock on the database file. */ if( db->busyTimeout ){
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1); int tmout = db->busyTimeout;
if( rc ){ sqlite3_file *fd = pWal->pDbFd;
/* EVIDENCE-OF: R-10421-19736 If any other process is running a if( SQLITE_OK==
** checkpoint operation at the same time, the lock cannot be obtained and sqlite3OsFileControl(fd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout)
** 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
** 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, xBusy, pBusyArg, WAL_WRITE_LOCK, 1);
if( rc==SQLITE_OK ){
pWal->writeLock = 1;
}else if( rc==SQLITE_BUSY ){
eMode2 = SQLITE_CHECKPOINT_PASSIVE;
xBusy2 = 0; xBusy2 = 0;
rc = SQLITE_OK; bSetLk = 1;
} }
} }
#endif
/* IMPLEMENTATION-OF: R-62028-47212 All calls obtain an exclusive
** "checkpoint" lock on the database 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
** 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.
*/
rc = walLockExclusive(pWal, WAL_CKPT_LOCK, 1);
testcase( rc==SQLITE_BUSY );
testcase( rc!=SQLITE_OK && xBusy2!=0 );
if( rc==SQLITE_OK ){
pWal->ckptLock = 1;
/* IMPLEMENTATION-OF: R-59782-36818 The SQLITE_CHECKPOINT_FULL, RESTART and
** 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 ){
@@ -3665,10 +3684,20 @@ int sqlite3WalCheckpoint(
memset(&pWal->hdr, 0, sizeof(WalIndexHdr)); memset(&pWal->hdr, 0, sizeof(WalIndexHdr));
} }
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
if( bSetLk ){
int tmout = 0;
sqlite3_file *fd = pWal->pDbFd;
sqlite3OsFileControl(fd, SQLITE_FCNTL_LOCK_TIMEOUT, (void*)&tmout);
}
#endif
/* 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"));
return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc); return (rc==SQLITE_OK && eMode!=eMode2 ? SQLITE_BUSY : rc);
} }
@@ -3786,8 +3815,15 @@ 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 *db,
sqlite3_snapshot *pSnapshot
){
pWal->pSnapshot = (WalIndexHdr*)pSnapshot; pWal->pSnapshot = (WalIndexHdr*)pSnapshot;
#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
pWal->dbSnapshot = db;
#endif
} }
/* /*

View File

@@ -130,7 +130,7 @@ int sqlite3WalHeapMemory(Wal *pWal);
#ifdef SQLITE_ENABLE_SNAPSHOT #ifdef SQLITE_ENABLE_SNAPSHOT
int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot); int sqlite3WalSnapshotGet(Wal *pWal, sqlite3_snapshot **ppSnapshot);
void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3_snapshot *pSnapshot); void sqlite3WalSnapshotOpen(Wal *pWal, sqlite3*, sqlite3_snapshot *pSnapshot);
int sqlite3WalSnapshotRecover(Wal *pWal); int sqlite3WalSnapshotRecover(Wal *pWal);
int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot); int sqlite3WalSnapshotCheck(Wal *pWal, sqlite3_snapshot *pSnapshot);
void sqlite3WalSnapshotUnlock(Wal *pWal); void sqlite3WalSnapshotUnlock(Wal *pWal);