]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add the sqlite3_setlk_timeout() API. For setting the timeout used by SQLITE_ENABLE_SE...
authordan <Dan Kennedy>
Mon, 27 Jan 2025 11:50:03 +0000 (11:50 +0000)
committerdan <Dan Kennedy>
Mon, 27 Jan 2025 11:50:03 +0000 (11:50 +0000)
FossilOrigin-Name: 4a7eb492797abb47b18b7dfc557aeae43a0dea5b861efc203398d5059b10d131

manifest
manifest.uuid
src/main.c
src/sqlite.h.in
src/sqliteInt.h
src/test1.c
src/wal.c
test/walsetlk2.test

index 12481824903c0b737af23efed087dd7ba1ed20aa..728f27c15f6ec50f168be24d2cbf61080fc0b7ad 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sa\srace\scondition\scausing\sSQLite\sto\suse\sa\sbusy-handler\sfor\san\soperation\sthat\sshould\snot.
-D 2025-01-24T15:49:47.933
+C Add\sthe\ssqlite3_setlk_timeout()\sAPI.\sFor\ssetting\sthe\stimeout\sused\sby\sSQLITE_ENABLE_SETLK_TIMEOUT\sblocking\slocks\swithout\salso\ssetting\sthe\sregular\sretry-based\sbusy-timeout.
+D 2025-01-27T11:50:03.268
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
@@ -740,7 +740,7 @@ F src/insert.c f8d1a0f8ee258411009c6b7f2d93170e351bd19f5ad89d57e1180644297cbe70
 F src/json.c 68a98c020c22127f2d65f08855f7fc7460ff352a6ce0b543d8931dde83319c22
 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
 F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
-F src/main.c a19dc8b47760ed95f3fbb255cfa8d3f7146b33c263eb4af05ab05e0115d161b9
+F src/main.c 101ea590be76fda296d12e6d8d1e9cc24f350b83cbf53e68b4f04484b90452a4
 F src/malloc.c 410e570b30c26cc36e3372577df50f7a96ee3eed5b2b161c6b6b48773c650c5e
 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
 F src/mem1.c 3bb59158c38e05f6270e761a9f435bf19827a264c13d1631c58b84bdc96d73b2
@@ -779,16 +779,16 @@ F src/resolve.c c8a5372b97b2a2e972a280676f06ddb5b74e885d3b1f5ce383f839907b57ef68
 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
 F src/select.c 83e88fbb36f89b6703b348777491619554f0fd6f917c9fdf51e4c2e9cda6c04e
 F src/shell.c.in ee54de10e9bd5572f689a6bc0c8e6fa58a8870e1670978ded44412d2715fd908
-F src/sqlite.h.in 6afbcaae44140216704a6c82e4c4ea4118c46d5f6573d6c5fa4fc901ed9d369e
+F src/sqlite.h.in ae301ce156765e2601695375dfc787a53b844a2f1c5d359bb667b081d1b7d2e0
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
-F src/sqliteInt.h 3f20dfb5ae54e787b2643edc0b5bae0cecddfb89988e28afdc3c0b05892e25cc
+F src/sqliteInt.h ff8e68e74a61b4bf676d1a9503be2e6c2bc92699ec358bb5e201b1a466f1aa8e
 F src/sqliteLimit.h 1bbdbf72bd0411d003267ffebc59a262f061df5653027a75627d03f48ca30523
 F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
 F src/tclsqlite.c 90441d3cc16f966a23499d9096a3d2d971e5e8fddb4d1413b096b79c2b2cff07
 F src/tclsqlite.h 65e2c761446e1c9fa0342b7d2612a703483643c8b6a316d12a65b745a4727395
-F src/test1.c bed72f092f9aaebf50ee4919a02a26ab99a4f378ab334cb93d77e8adb82e4b77
+F src/test1.c 64df9d5ad54521eb3c103f1253bf33ceddbc5fa931658d3701027a2ac86eb5e9
 F src/test2.c 7ebc518e6735939d8979273a6f7b1d9b5702babf059f6ad62499f7f60a9eb9a3
 F src/test3.c e7573aa0f78ee4e070a4bc8c3493941c1aa64d5c66d4825c74c0f055451f432b
 F src/test4.c 13e57ae7ec7a959ee180970aef09deed141252fe9bb07c61054f0dfa4f1dfd5d
@@ -858,7 +858,7 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8
 F src/vdbevtab.c fc46b9cbd759dc013f0b3724549cc0d71379183c667df3a5988f7e2f1bd485f3
 F src/vtab.c 316cd48e9320660db3047cd306cd056e4361180cebb4d0f10a39244e10c11422
 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
-F src/wal.c 97c96c4eab27a409d2c710d8977a6b4917aebced14db2d63a451e9ca7b1f69bd
+F src/wal.c 20550245b9a82f94736e905ee7df8f549e1301ba40e9f2cb51139e36d49c3c0f
 F src/wal.h ba252daaa94f889f4b2c17c027e823d9be47ce39da1d3799886bbd51f0490452
 F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
 F src/where.c 9ad3dea8003a8913da6a4ca8322e2fe30773f46e88a0d4fbf9db13bdb999efa2
@@ -2022,7 +2022,7 @@ F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766
 F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68
 F test/walseh1.test bae700eb99519b6d5cd3f893c04759accc5a59c391d4189fe4dd6995a533442b
 F test/walsetlk.test 9c5b92f9a20252540fedf9ffa6ee3d1b8af08ea4b80d0144d9b88e6c0c1de80d
-F test/walsetlk2.test f32134c673e207e5af3c888448f925d1f92c250bb367f0e5a76e4bce9d56f0af
+F test/walsetlk2.test e80cac17de166d5c8e4e0d243452798431aceb76a0abc95bfdd09d718d7c3f3f
 F test/walshared.test 42e3808582504878af237ea02c42ca793e8a0efaa19df7df26ac573370dbc7a3
 F test/walslow.test 0c51843836c9dcf40a5ac05aa781bfb977b396ee2c872d92bd48b79d5dd9aa23
 F test/walthread.test 14b20fcfa6ae152f5d8e12f5dc8a8a724b7ef189f5d8ef1e2ceab79f2af51747
@@ -2203,8 +2203,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
 F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
 F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P daefcafe799ad7613cbdff1fb1e9d40659892906875b28fbc112abd7679e48ea
-R a5b314ee32b527d33bb7a6211f7b128a
+P 6ab9ed8eef77781898375038ab05fc6e5f46b745e4906691393b8b1d90570eb6
+R 7026d025d771964056775817385cabe6
 U dan
-Z 09f6f131877fb88e3c0a6b91e64a67d2
+Z d459230a6d531f1d8e43a532fde898d2
 # Remove this line to create a well-formed Fossil manifest.
index 1506819b57d7a08ecbdca89e574d6a443c32dab2..8adcd56dc842435ef211eb69f047aec8ec301978 100644 (file)
@@ -1 +1 @@
-6ab9ed8eef77781898375038ab05fc6e5f46b745e4906691393b8b1d90570eb6
+4a7eb492797abb47b18b7dfc557aeae43a0dea5b861efc203398d5059b10d131
index 1163deb6e3778b586dcd26cf657eb7ed8094e402..c8344b43c07ac5e891e52c1a9da72d8c533713ef 100644 (file)
@@ -1766,6 +1766,9 @@ int sqlite3_busy_handler(
   db->busyHandler.pBusyArg = pArg;
   db->busyHandler.nBusy = 0;
   db->busyTimeout = 0;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+  db->setlkTimeout = 0;
+#endif
   sqlite3_mutex_leave(db->mutex);
   return SQLITE_OK;
 }
@@ -1815,12 +1818,25 @@ int sqlite3_busy_timeout(sqlite3 *db, int ms){
     sqlite3_busy_handler(db, (int(*)(void*,int))sqliteDefaultBusyCallback,
                              (void*)db);
     db->busyTimeout = ms;
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+    db->setlkTimeout = ms;
+#endif
   }else{
     sqlite3_busy_handler(db, 0, 0);
   }
   return SQLITE_OK;
 }
 
+int sqlite3_setlk_timeout(sqlite3 *db, int ms){
+#ifdef SQLITE_ENABLE_API_ARMOR
+  if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT;
+#endif
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+  db->setlkTimeout = (ms>0 ? ms : 0);
+#endif
+  return SQLITE_OK;
+}
+
 /*
 ** Cause any pending operation to stop at its earliest opportunity.
 */
index 9a117fa54e65913ebeb0a420cdb0f785fa5059f1..c2a69bd2fc85be9ba5937bc7c1d1120758dc9b32 100644 (file)
@@ -2899,6 +2899,30 @@ int sqlite3_busy_handler(sqlite3*,int(*)(void*,int),void*);
 */
 int sqlite3_busy_timeout(sqlite3*, int ms);
 
+/*
+** CAPI3REF: Set the Setlk Timeout
+** METHOD: sqlite3
+**
+** This routine is only useful in SQLITE_ENABLE_SETLK_TIMEOUT builds. If 
+** the VFS supports blocking locks, it sets the timeout in ms used by 
+** eligible locks taken on wal mode databases by the specified database 
+** handle. In non-SQLITE_ENABLE_SETLK_TIMEOUT builds, or if the VFS does
+** not support blocking locks, this function is a no-op.
+**
+** Passing 0x7FFFFFFF to this function is interpreted by some VFS as "block
+** indefinitely". Passing zero or less than zero disables blocking locks
+** altogether.
+**
+** Internally, each SQLite database handle store two timeout values - the
+** busy-timeout (used for rollback mode databases, or if the VFS does not
+** support blocking locks) and the setlk-timeout (used for blocking locks
+** on wal-mode databases). The sqlite3_busy_timeout() method sets both
+** values, this function sets only the setlk-timeout value. Therefore,
+** to configure separate busy-timeout and setlk-timeout values for a single
+** database handle, call sqlite3_busy_timeout() followed by this function.
+*/
+int sqlite3_setlk_timeout(sqlite3*, int ms);
+
 /*
 ** CAPI3REF: Convenience Routines For Running Queries
 ** METHOD: sqlite3
index b8c9136a59e69c074609f400ad33d8f0409e17b5..aa12b89764a32241d1d746e3fc0f8b3226391c83 100644 (file)
@@ -1744,6 +1744,9 @@ struct sqlite3 {
   Savepoint *pSavepoint;        /* List of active savepoints */
   int nAnalysisLimit;           /* Number of index rows to ANALYZE */
   int busyTimeout;              /* Busy handler timeout, in msec */
+#ifdef SQLITE_ENABLE_SETLK_TIMEOUT
+  int setlkTimeout;             /* Blocking lock timeout, in msec */
+#endif
   int nSavepoint;               /* Number of non-transaction savepoints */
   int nStatement;               /* Number of nested statement-transactions  */
   i64 nDeferredCons;            /* Net deferred constraints this transaction. */
index 6a871167760ef9207a3b91d9342ab4a9aeab3f0f..fb7607f1015cdfddc2499e9cf0a6c0103d7dde5f 100644 (file)
@@ -5939,6 +5939,31 @@ static int SQLITE_TCLAPI test_busy_timeout(
   return TCL_OK;
 }
 
+/*
+** Usage: sqlite3_setlk_timeout DB MS
+**
+** Set the setlk timeout.
+*/
+static int SQLITE_TCLAPI test_setlk_timeout(
+  void * clientData,
+  Tcl_Interp *interp,
+  int argc,
+  char **argv
+){
+  int rc, ms;
+  sqlite3 *db;
+  if( argc!=3 ){
+    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], 
+        " DB", 0);
+    return TCL_ERROR;
+  }
+  if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR;
+  if( Tcl_GetInt(interp, argv[2], &ms) ) return TCL_ERROR;
+  rc = sqlite3_setlk_timeout(db, ms);
+  Tcl_AppendResult(interp, sqlite3ErrName(rc), 0);
+  return TCL_OK;
+}
+
 /*
 ** Usage:  tcl_variable_type VARIABLENAME
 **
@@ -8862,6 +8887,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){
      { "sqlite_delete_collation",       (Tcl_CmdProc*)delete_collation      },
      { "sqlite3_get_autocommit",        (Tcl_CmdProc*)get_autocommit        },
      { "sqlite3_busy_timeout",          (Tcl_CmdProc*)test_busy_timeout     },
+     { "sqlite3_setlk_timeout",         (Tcl_CmdProc*)test_setlk_timeout    },
      { "printf",                        (Tcl_CmdProc*)test_printf           },
      { "sqlite3IoTrace",              (Tcl_CmdProc*)test_io_trace         },
      { "clang_sanitize_address",        (Tcl_CmdProc*)clang_sanitize_address },
index 707acfca5a1f1a328a93549fda4c60e094eaa32d..5d6c0c62c64de4e0e1b86da71c85e704f5dee30b 100644 (file)
--- a/src/wal.c
+++ b/src/wal.c
@@ -2027,7 +2027,7 @@ static int walEnableBlockingMs(Wal *pWal, int nMs){
 static int walEnableBlocking(Wal *pWal){
   int res = 0;
   if( pWal->db ){
-    int tmout = pWal->db->busyTimeout;
+    int tmout = pWal->db->setlkTimeout;
     if( tmout ){
       res = walEnableBlockingMs(pWal, tmout);
     }
index 99366571d694f0fb7819b79226476d89d87aa857..3b8e60cd4fadb73a6fb0b7eb729c3f98b5d57648 100644 (file)
@@ -85,5 +85,87 @@ do_test 1.5.3 {
 db close
 tvfs delete
 
+#-------------------------------------------------------------------------
+# Check that if sqlite3_setlk_timeout() is used, blocking locks timeout
+# but other operations do not use the retry mechanism.
+#
+reset_db
+
+do_execsql_test 2.0 {
+  CREATE TABLE t1(a, b);
+  INSERT INTO t1 VALUES(1, 2), (3, 4);
+}
+
+sqlite3_setlk_timeout db 2000
+
+# Launch a non-blocking testfixture process to write-lock the 
+# database for 2000 ms.
+testfixture_nb done {
+  sqlite3 db test.db
+  db eval {
+    BEGIN EXCLUSIVE;
+      INSERT INTO t1 VALUES(5, 6);
+  }
+  after 2000
+  db eval {
+    COMMIT
+  }
+}
+
+after 500 {set ok 1}
+vwait ok
+
+do_catchsql_test 2.1 {
+  INSERT INTO t1 VALUES(7, 8);
+} {1 {database is locked}}
+
+sqlite3_busy_timeout db 2000
+
+do_catchsql_test 2.2 {
+  INSERT INTO t1 VALUES(7, 8);
+} {0 {}}
+
+do_execsql_test 2.3 {
+  SELECT * FROM t1
+} {1 2 3 4 5 6 7 8}
+
+do_execsql_test 2.4 {
+  PRAGMA journal_mode = wal;
+} {wal}
+
+db close
+sqlite3 db test.db
+
+do_execsql_test 2.5 {
+  INSERT INTO t1 VALUES(9, 10);
+}
+
+sqlite3_setlk_timeout db 2000
+
+# Launch a non-blocking testfixture process to write-lock the 
+# database for 2000 ms.
+testfixture_nb done {
+  sqlite3 db test.db
+  db eval {
+    BEGIN EXCLUSIVE;
+      INSERT INTO t1 VALUES(11, 12);
+  }
+  after 2000
+  db eval {
+    COMMIT
+  }
+}
+
+after 500 {set ok 1}
+vwait ok
+
+do_catchsql_test 2.6 {
+  INSERT INTO t1 VALUES(13, 14);
+} {0 {}}
+
+do_execsql_test 2.7 {
+  SELECT * FROM t1
+} {1 2 3 4 5 6 7 8 9 10 11 12 13 14}
+
 finish_test