]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Detect database file changes using a 128-bit segment of the file header
authordrh <drh@noemail.net>
Mon, 16 Apr 2007 15:02:19 +0000 (15:02 +0000)
committerdrh <drh@noemail.net>
Mon, 16 Apr 2007 15:02:19 +0000 (15:02 +0000)
that includes the change counter.  Ticket #2303. (CVS 3844)

FossilOrigin-Name: e44995debf2456e55b502783849e93a045a527c8

manifest
manifest.uuid
src/pager.c
test/exclusive2.test
test/speed2.test

index 59ec2cac1701848d682832a9e5ce10749ec99f50..32d99e17a2077aa1fc85200d909f3ff9b265d0ad 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Update\sthe\swhentouse.html\sdocument\sto\smention\sthat\sless\sbitmap\smemory\nis\sused\sfor\slarger\spage\ssizes.\s(CVS\s3843)
-D 2007-04-14T12:04:39
+C Detect\sdatabase\sfile\schanges\susing\sa\s128-bit\ssegment\sof\sthe\sfile\sheader\nthat\sincludes\sthe\schange\scounter.\s\sTicket\s#2303.\s(CVS\s3844)
+D 2007-04-16T15:02:19
 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -86,7 +86,7 @@ F src/os_unix.c 426b4c03c304ad78746d65d9ba101e0b72e18e23
 F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
 F src/os_win.c e94903c7dc1c0599c8ddce42efa0b6928068ddc5
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
-F src/pager.c 4fb7253edc2377b12f16fa33adffda79f070c1b4
+F src/pager.c 33c632ce9c228d87f14879a139fa123d43e4bf25
 F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c
 F src/parse.y b6cfbadb6d5b21b5087d30698ee5af0ebb098767
 F src/pragma.c 3b992b5b2640d6ae25cef05aa6a42cd1d6c43234
@@ -204,7 +204,7 @@ F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
 F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797
 F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
 F test/exclusive.test 5bc520ba366ae3d242420af025ab64d465b04706
-F test/exclusive2.test dcb10d527722eb066ef7d060a0d47d7e59070d2e
+F test/exclusive2.test 6ef76efd3b442c95819446f8d15e6a63a1e95a4e
 F test/exclusive3.test 0e49c35b7e7cb8e7280b4ce3f0359d30b207d2ff
 F test/expr.test ab21e2fc3613595131efd7d8bbca4b95ed5cc608
 F test/filefmt.test 053b622009fbbb74dd37921ffad374d852c13cd8
@@ -316,7 +316,7 @@ F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
 F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
 F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a
-F test/speed2.test 9b93b93681f82f320caa4b2c9f15c0de4f3a3d33
+F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
 F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
 F test/subselect.test 974e87f8fc91c5f00dd565316d396a5a6c3106c4
 F test/sync.test d05397b8f89f423dd6dba528692019ab036bc1c3
@@ -458,7 +458,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P cfc6f933dc60ca88ae848f7f0c402e820437c2ff
-R 28caddcdc5058b3369c1c52b75efe638
+P 2c8e2a5be34cdfe11ef22bd6f78ec0519f497392
+R 814512695981b3392256843a965db823
 U drh
-Z 5805ea2bb38918a004e8fa50c9627a61
+Z 2bdc95de39af6db85ea861709e0ec935
index a0c9a728d9115aaa7a99fe9bc41ac20a77bf8d20..b7da5c7fd8f62900e3a95e8e3655d21f139c6e2f 100644 (file)
@@ -1 +1 @@
-2c8e2a5be34cdfe11ef22bd6f78ec0519f497392
\ No newline at end of file
+e44995debf2456e55b502783849e93a045a527c8
\ No newline at end of file
index 57cf9a63737facf698c74ffb797bf760b5ee0960..b7fae8ed877e537ccfb9b177005e714286bf7c58 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.328 2007/04/13 04:01:59 drh Exp $
+** @(#) $Id: pager.c,v 1.329 2007/04/16 15:02:19 drh Exp $
 */
 #ifndef SQLITE_OMIT_DISKIO
 #include "sqliteInt.h"
@@ -294,7 +294,7 @@ struct Pager {
   Pager *pNext;               /* Linked list of pagers in this thread */
 #endif
   char *pTmpSpace;            /* Pager.pageSize bytes of space for tmp use */
-  u32 iChangeCount;           /* Db change-counter for which cache is valid */
+  char dbFileVers[16];        /* Changes whenever database file changes */
 };
 
 /*
@@ -1131,12 +1131,14 @@ static int pager_playback_one_page(Pager *pPager, OsFile *jfd, int useCksum){
 #ifdef SQLITE_CHECK_PAGES
     pPg->pageHash = pager_pagehash(pPg);
 #endif
-    CODEC1(pPager, pData, pPg->pgno, 3);
-
-    /* If this was page 1, then restore the value of Pager.iChangeCount */
+    /* If this was page 1, then restore the value of Pager.dbFileVers.
+    ** Do this before any decoding. */
     if( pgno==1 ){
-      pPager->iChangeCount = retrieve32bits(pPg, 24);
+      memcpy(&pPager->dbFileVers, &((u8*)pData)[24],sizeof(pPager->dbFileVers));
     }
+
+    /* Decode the page just read from disk */
+    CODEC1(pPager, pData, pPg->pgno, 3);
   }
   return rc;
 }
@@ -2441,6 +2443,9 @@ static int pager_write_pagelist(PgHdr *pList){
       rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
       PAGER_INCR(sqlite3_pager_writedb_count);
       PAGER_INCR(pPager->nWrite);
+      if( pList->pgno==1 ){
+        memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
+      }
     }
 #ifndef NDEBUG
     else{
@@ -2680,6 +2685,10 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
   PAGER_INCR(pPager->nRead);
   IOTRACE(("PGIN %p %d\n", pPager, pgno));
   PAGERTRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->pgno);
+  if( pgno==1 ){
+    memcpy(&pPager->dbFileVers, &((u8*)PGHDR_TO_DATA(pPg))[24],
+                                              sizeof(pPager->dbFileVers));
+  }
   CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
   return rc;
 }
@@ -2780,16 +2789,21 @@ static int pagerSharedLock(Pager *pPager){
       if( pPager->pAll ){
         /* The shared-lock has just been acquired on the database file
         ** and there are already pages in the cache (from a previous
-        ** read or write transaction). If the value of the change-counter
-        ** stored in Pager.iChangeCount matches that found on page 1 of
-        ** the database file, then no database changes have occured since
-        ** the cache was last valid and it is safe to retain the cached
-        ** pages. Otherwise, if Pager.iChangeCount does not match the
-        ** change-counter on page 1 of the file, the current cache contents
-        ** must be discarded.
+        ** read or write transaction).  Check to see if the database
+        ** has been modified.  If the database has changed, flush the
+        ** cache.
+        **
+        ** Database changes is detected by looking at 15 bytes beginning
+        ** at offset 24 into the file.  The first 4 of these 16 bytes are
+        ** a 32-bit counter that is incremented with each change.  The
+        ** other bytes change randomly with each file change when
+        ** a codec is in use.
+        ** 
+        ** There is a vanishingly small chance that a change will not be 
+        ** deteched.  The chance of an undetected change is so small that
+        ** it can be neglected.
         */
-        u8 zC[4];
-        u32 iChangeCounter = 0;
+        char dbFileVers[sizeof(pPager->dbFileVers)];
         sqlite3PagerPagecount(pPager);
 
         if( pPager->errCode ){
@@ -2797,21 +2811,20 @@ static int pagerSharedLock(Pager *pPager){
         }
 
         if( pPager->dbSize>0 ){
-          /* Read the 4-byte change counter directly from the file. */
           rc = sqlite3OsSeek(pPager->fd, 24);
           if( rc!=SQLITE_OK ){
             return rc;
           }
-          rc = sqlite3OsRead(pPager->fd, zC, 4);
+          rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
           if( rc!=SQLITE_OK ){
             return rc;
           }
-          iChangeCounter = (zC[0]<<24) + (zC[1]<<16) + (zC[2]<<8) + zC[3];
+        }else{
+          memset(dbFileVers, 0, sizeof(dbFileVers));
         }
 
-        if( iChangeCounter!=pPager->iChangeCount ){
+        if( memcmp(pPager->dbFileVers, dbFileVers, sizeof(dbFileVers))!=0 ){
           pager_reset(pPager);
-          pPager->iChangeCount = iChangeCounter;
         }
       }
     }
@@ -3029,10 +3042,6 @@ int sqlite3PagerAcquire(
         return rc;
       }
     }
-    /* If this was page 1, then restore the value of Pager.iChangeCount */
-    if( pgno==1 ){
-      pPager->iChangeCount = retrieve32bits(pPg, 24);
-    }
 
     /* Link the page into the page hash table */
     h = pgno & (pPager->nHash-1);
@@ -3722,7 +3731,6 @@ static int pager_incr_changecounter(Pager *pPager){
     /* Increment the value just read and write it back to byte 24. */
     change_counter++;
     put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
-    pPager->iChangeCount = change_counter;
   
     /* Release the page reference. */
     sqlite3PagerUnref(pPgHdr);
index 17f42b5f084cf6a343d3e6b606268f8a7c3b3d5c..a9c9dd0467d85f3684abf04ed6783e69edcb1706 100644 (file)
@@ -10,7 +10,7 @@
 #***********************************************************************
 # This file implements regression tests for SQLite library.
 #
-# $Id: exclusive2.test,v 1.3 2007/04/08 16:52:22 drh Exp $
+# $Id: exclusive2.test,v 1.4 2007/04/16 15:02:20 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -56,8 +56,9 @@ do_test exclusive2-1.0 {
 # The following tests - exclusive2-1.X - check that:
 #
 # 1-3:   Build a database with connection 1, calculate a signature.
-# 4-9:   Modify the database using a second connection, then reset
-#        the pager change-counter to the value it had before the modifications.
+# 4-9:   Modify the database using a second connection in a way that
+#        does not modify the freelist, then reset the pager change-counter
+#        to the value it had before the modifications.
 # 8:     Check that using the first connection, the database signature
 #        is still the same. This is because it uses the in-memory cache.
 #        It can't tell the db has changed because we reset the change-counter.
@@ -69,14 +70,14 @@ do_test exclusive2-1.0 {
 do_test exclusive2-1.1 {
   execsql {
     BEGIN;
-    CREATE TABLE t1(a UNIQUE);
-    INSERT INTO t1 VALUES(randstr(10, 400));
-    INSERT INTO t1 VALUES(randstr(10, 400));
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    CREATE TABLE t1(a, b);
+    INSERT INTO t1(a) VALUES(randstr(10, 400));
+    INSERT INTO t1(a) VALUES(randstr(10, 400));
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
     COMMIT;
     SELECT count(*) FROM t1;
   }
@@ -94,7 +95,7 @@ do_test exclusive2-1.4 {
 } $::sig
 do_test exclusive2-1.5 {
   execsql {
-    DELETE FROM t1;
+    UPDATE t1 SET b=a, a=NULL;
   } db2
   expr {[t1sig db2] eq $::sig}
 } 0
@@ -135,13 +136,14 @@ do_test exclusive2-2.1 {
   execsql {PRAGMA locking_mode = exclusive;}
   execsql {
     BEGIN;
-    INSERT INTO t1 VALUES(randstr(10, 400));
-    INSERT INTO t1 VALUES(randstr(10, 400));
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
-    INSERT INTO t1 SELECT randstr(10, 400) FROM t1;
+    DELETE FROM t1;
+    INSERT INTO t1(a) VALUES(randstr(10, 400));
+    INSERT INTO t1(a) VALUES(randstr(10, 400));
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
+    INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
     COMMIT;
     SELECT count(*) FROM t1;
   }
index 08ddb15f462487fb1fd2f1cc9af7fdffb299381a..f6d1a4c8ab6e20add3f932d9e9aa4017f05fac20 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script is measuring executing speed.
 #
-# $Id: speed2.test,v 1.6 2007/03/31 22:34:16 drh Exp $
+# $Id: speed2.test,v 1.7 2007/04/16 15:02:20 drh Exp $
 #
 
 set testdir [file dirname $argv0]
@@ -67,7 +67,7 @@ do_test speed2-1.0 {
   execsql {
     PRAGMA page_size=1024;
     PRAGMA cache_size=8192;
---    PRAGMA locking_mode=EXCLUSIVE;
+    PRAGMA locking_mode=EXCLUSIVE;
     CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT);
     CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT);
     CREATE INDEX i2a ON t2(a);