]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Have OTA maintain a small LRU cache of UPDATE statements. This reduces the amount...
authordan <dan@noemail.net>
Thu, 23 Apr 2015 18:14:21 +0000 (18:14 +0000)
committerdan <dan@noemail.net>
Thu, 23 Apr 2015 18:14:21 +0000 (18:14 +0000)
FossilOrigin-Name: baee3556ea10d96f1623cf4dce112fa1a1070820

ext/ota/ota13.test [new file with mode: 0644]
ext/ota/sqlite3ota.c
manifest
manifest.uuid

diff --git a/ext/ota/ota13.test b/ext/ota/ota13.test
new file mode 100644 (file)
index 0000000..42911a0
--- /dev/null
@@ -0,0 +1,65 @@
+# 2015 February 16
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+#
+# Test an OTA update that features lots of different ota_control strings
+# for UPDATE statements. This tests OTA's internal UPDATE statement cache.
+#
+
+if {![info exists testdir]} {
+  set testdir [file join [file dirname [info script]] .. .. test]
+}
+source $testdir/tester.tcl
+source $testdir/lock_common.tcl
+set ::testprefix ota13
+
+do_execsql_test 1.0 {
+  CREATE TABLE t1(a PRIMARY KEY, b, c, d, e, f, g, h);
+  WITH ii(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM ii WHERE i<127)
+  INSERT INTO t1 SELECT i, 0, 0, 0, 0, 0, 0, 0 FROM ii;
+}
+
+forcedelete ota.db
+do_execsql_test 1.1 {
+  ATTACH 'ota.db' AS ota;
+  CREATE TABLE ota.data_t1(a, b, c, d, e, f, g, h, ota_control);
+}
+
+do_test 1.2 {
+  for {set i 0} {$i<128} {incr i} {
+    set control "."
+    for {set bit 6} {$bit>=0} {incr bit -1} {
+      if { $i & (1<<$bit) } {
+        append control "x"
+      } else {
+        append control "."
+      }
+    }
+    execsql { INSERT INTO data_t1 VALUES($i, 1, 1, 1, 1, 1, 1, 1, $control) }
+  }
+} {}
+
+do_test 1.3 {
+  sqlite3ota ota test.db ota.db
+  while 1 {
+    set rc [ota step]
+    if {$rc!="SQLITE_OK"} break
+  }
+  ota close
+} {SQLITE_DONE}
+
+do_execsql_test 1.4 {
+  SELECT count(*) FROM t1 WHERE
+  a == ( (b<<6) + (c<<5) + (d<<4) + (e<<3) + (f<<2) + (g<<1) + (h<<0) )
+} {128}
+
+
+finish_test
+
index c2fa993d44178257e60271f5c7c547e4bee9004c..9f74e561dbb33b0c2529bb1953a7f5b051e2452d 100644 (file)
@@ -90,6 +90,9 @@
 #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_OTA)
 #include "sqlite3ota.h"
 
+/* Maximum number of prepared UPDATE statements held by this module */
+#define SQLITE_OTA_UPDATE_CACHESIZE 16
+
 /*
 ** Swap two objects of type TYPE.
 */
@@ -165,6 +168,7 @@ typedef struct OtaObjIter OtaObjIter;
 typedef struct OtaState OtaState;
 typedef struct ota_vfs ota_vfs;
 typedef struct ota_file ota_file;
+typedef struct OtaUpdateStmt OtaUpdateStmt;
 
 #if !defined(SQLITE_AMALGAMATION)
 typedef unsigned int u32;
@@ -195,6 +199,12 @@ struct OtaState {
   i64 iOalSz;
 };
 
+struct OtaUpdateStmt {
+  char *zMask;                    /* Copy of update mask used with pUpdate */
+  sqlite3_stmt *pUpdate;          /* Last update statement (or NULL) */
+  OtaUpdateStmt *pNext;
+};
+
 /*
 ** An iterator of this type is used to iterate through all objects in
 ** the target database that require updating. For each such table, the
@@ -239,8 +249,7 @@ struct OtaObjIter {
   sqlite3_stmt *pTmpInsert;       /* Insert into ota_tmp_$zTbl */
 
   /* Last UPDATE used (for PK b-tree updates only), or NULL. */
-  char *zMask;                    /* Copy of update mask used with pUpdate */
-  sqlite3_stmt *pUpdate;          /* Last update statement (or NULL) */
+  OtaUpdateStmt *pOtaUpdate;
 };
 
 /*
@@ -436,8 +445,6 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){
   pIter->abTblPk = 0;
   pIter->abNotNull = 0;
   pIter->nTblCol = 0;
-  sqlite3_free(pIter->zMask);
-  pIter->zMask = 0;
   pIter->eType = 0;               /* Invalid value */
 }
 
@@ -446,15 +453,24 @@ static void otaObjIterFreeCols(OtaObjIter *pIter){
 ** the current object (table/index pair).
 */
 static void otaObjIterClearStatements(OtaObjIter *pIter){
+  OtaUpdateStmt *pUp;
+
   sqlite3_finalize(pIter->pSelect);
   sqlite3_finalize(pIter->pInsert);
   sqlite3_finalize(pIter->pDelete);
-  sqlite3_finalize(pIter->pUpdate);
   sqlite3_finalize(pIter->pTmpInsert);
+  pUp = pIter->pOtaUpdate;
+  while( pUp ){
+    OtaUpdateStmt *pTmp = pUp->pNext;
+    sqlite3_finalize(pUp->pUpdate);
+    sqlite3_free(pUp);
+    pUp = pTmp;
+  }
+  
   pIter->pSelect = 0;
   pIter->pInsert = 0;
   pIter->pDelete = 0;
-  pIter->pUpdate = 0;
+  pIter->pOtaUpdate = 0;
   pIter->pTmpInsert = 0;
   pIter->nCol = 0;
 }
@@ -1709,9 +1725,6 @@ static int otaObjIterPrepareAll(
         otaObjIterPrepareTmpInsert(p, pIter, zCollist, zOtaRowid);
       }
 
-      /* Allocate space required for the zMask field. */
-      pIter->zMask = (char*)otaMalloc(p, pIter->nTblCol+1);
-
       sqlite3_free(zWhere);
       sqlite3_free(zOldlist);
       sqlite3_free(zNewlist);
@@ -1729,6 +1742,9 @@ static int otaObjIterPrepareAll(
 ** be used to update the imposter table for the main table b-tree of the
 ** table object that pIter currently points to, assuming that the 
 ** ota_control column of the data_xyz table contains zMask.
+** 
+** If the zMask string does not specify any columns to update, then this
+** is not an error. Output variable *ppStmt is set to NULL in this case.
 */
 static int otaGetUpdateStmt(
   sqlite3ota *p,                  /* OTA handle */
@@ -1736,15 +1752,50 @@ static int otaGetUpdateStmt(
   const char *zMask,              /* ota_control value ('x.x.') */
   sqlite3_stmt **ppStmt           /* OUT: UPDATE statement handle */
 ){
-  if( pIter->pUpdate && strcmp(zMask, pIter->zMask)==0 ){
-    *ppStmt = pIter->pUpdate;
+  OtaUpdateStmt **pp;
+  OtaUpdateStmt *pUp = 0;
+  int nUp = 0;
+
+  /* In case an error occurs */
+  *ppStmt = 0;
+
+  /* Search for an existing statement. If one is found, shift it to the front
+  ** of the LRU queue and return immediately. Otherwise, leave nUp pointing
+  ** to the number of statements currently in the cache and pUp to the
+  ** last object in the list.  */
+  for(pp=&pIter->pOtaUpdate; *pp; pp=&((*pp)->pNext)){
+    pUp = *pp;
+    if( strcmp(pUp->zMask, zMask)==0 ){
+      *pp = pUp->pNext;
+      pUp->pNext = pIter->pOtaUpdate;
+      pIter->pOtaUpdate = pUp;
+      *ppStmt = pUp->pUpdate; 
+      return SQLITE_OK;
+    }
+    nUp++;
+  }
+  assert( pUp==0 || pUp->pNext==0 );
+
+  if( nUp>=SQLITE_OTA_UPDATE_CACHESIZE ){
+    for(pp=&pIter->pOtaUpdate; *pp!=pUp; pp=&((*pp)->pNext));
+    *pp = 0;
+    sqlite3_finalize(pUp->pUpdate);
+    pUp->pUpdate = 0;
   }else{
+    pUp = (OtaUpdateStmt*)otaMalloc(p, sizeof(OtaUpdateStmt)+pIter->nTblCol+1);
+  }
+
+  if( pUp ){
     char *zWhere = otaObjIterGetWhere(p, pIter);
     char *zSet = otaObjIterGetSetlist(p, pIter, zMask);
     char *zUpdate = 0;
-    sqlite3_finalize(pIter->pUpdate);
-    pIter->pUpdate = 0;
-    if( p->rc==SQLITE_OK ){
+
+    pUp->zMask = (char*)&pUp[1];
+    memcpy(pUp->zMask, zMask, pIter->nTblCol);
+    pUp->pNext = pIter->pOtaUpdate;
+    pIter->pOtaUpdate = pUp;
+
+    if( zSet ){
       const char *zPrefix = "";
 
       if( pIter->eType!=OTA_PK_VTAB ) zPrefix = "ota_imp_";
@@ -1752,16 +1803,14 @@ static int otaGetUpdateStmt(
           zPrefix, pIter->zTbl, zSet, zWhere
       );
       p->rc = prepareFreeAndCollectError(
-          p->dbMain, &pIter->pUpdate, &p->zErrmsg, zUpdate
+          p->dbMain, &pUp->pUpdate, &p->zErrmsg, zUpdate
       );
-      *ppStmt = pIter->pUpdate;
-    }
-    if( p->rc==SQLITE_OK ){
-      memcpy(pIter->zMask, zMask, pIter->nTblCol);
+      *ppStmt = pUp->pUpdate;
     }
     sqlite3_free(zWhere);
     sqlite3_free(zSet);
   }
+
   return p->rc;
 }
 
@@ -1857,7 +1906,7 @@ static void otaFileSuffix3(const char *zBase, char *z){
 ** blob starting at byte offset 40.
 */
 static i64 otaShmChecksum(sqlite3ota *p){
-  i64 iRet;
+  i64 iRet = 0;
   if( p->rc==SQLITE_OK ){
     sqlite3_file *pDb = p->pTargetFd->pReal;
     u32 volatile *ptr;
index 96272c5c228751c8da9cc3966b5f8dea58b3c0b3..f64a8df91a1bd4baecea4e4a83e5e2fda3b4078c 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\scomments\srelated\sto\sdatabase\slocking\sto\ssqlite3ota.h.
-D 2015-04-22T11:34:38.145
+C Have\sOTA\smaintain\sa\ssmall\sLRU\scache\sof\sUPDATE\sstatements.\sThis\sreduces\sthe\samount\sof\stime\sit\sspends\scompiling\sUPDATE\sif\sa\ssingle\sdata_xxx\stable\scontains\smany\sdifferent\sota_control\sstrings.
+D 2015-04-23T18:14:21.590
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 79b306896135a2305cfb7e6d88990fc4820fb917
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -128,6 +128,7 @@ F ext/ota/ota1.test 960418e4171a989426f8b1ad8ee31770e0f94fb8
 F ext/ota/ota10.test 85e0f6e7964db5007590c1b299e75211ed4240d4
 F ext/ota/ota11.test 2f606cd2b4af260a86b549e91b9f395450fc75cb
 F ext/ota/ota12.test 0dff44474de448fb4b0b28c20da63273a4149abb
+F ext/ota/ota13.test f7a3d73fa5d3fabf2755b569f125fce7390a874c
 F ext/ota/ota3.test 3fe3521fbdce32d0e4e116a60999c3cba47712c5
 F ext/ota/ota5.test ad0799daf8923ddebffe75ae8c5504ca90b7fadb
 F ext/ota/ota6.test 3bde7f69a894748b27206b6753462ec3b75b6bb6
@@ -138,7 +139,7 @@ F ext/ota/otaA.test ab67f7f53670b81c750dcc946c5b704f51c429a4
 F ext/ota/otacrash.test 8346192b2d46cbe7787d5d65904d81d3262a3cbf
 F ext/ota/otafault.test 8c43586c2b96ca16bbce00b5d7e7d67316126db8
 F ext/ota/otafault2.test fa202a98ca221faec318f3e5c5f39485b1256561
-F ext/ota/sqlite3ota.c b45d73607b78eba89ca224fb0d10e10d1b32b6b0
+F ext/ota/sqlite3ota.c 3b53197166b08bae980ea9b3b668f7eb0580fe8c
 F ext/ota/sqlite3ota.h c0d32e46aa52cce3b16899399639deaff1f27b2f
 F ext/ota/test_ota.c e34c801c665d64b4b9e00b71f1acf8c652404b2b
 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
@@ -1269,7 +1270,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 352fa09efd8240567b8f9487944e8c3ade4e664a
-R 7514208e376f1404350994ff3e1120f2
+P 77242965e77446313a8f0a65a39fccb67fe4cabf
+R a8ed618fd0d0e5a18750e29ca6db9e19
 U dan
-Z aab2f59acbc2b3195f57173b44acb17c
+Z 00cb71982fa5d2b70e9c222c1f403ddb
index 511df81b1dc3e47deacb4d51e399ee90aa972a08..a2366aee89d737aee46c46d5fcea9bab47790394 100644 (file)
@@ -1 +1 @@
-77242965e77446313a8f0a65a39fccb67fe4cabf
\ No newline at end of file
+baee3556ea10d96f1623cf4dce112fa1a1070820
\ No newline at end of file