1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Detect database file changes using a 128-bit segment of the file header

that includes the change counter.  Ticket #2303. (CVS 3844)

FossilOrigin-Name: e44995debf2456e55b502783849e93a045a527c8
This commit is contained in:
drh
2007-04-16 15:02:19 +00:00
parent 9e4e6e502f
commit 86a88114fa
5 changed files with 65 additions and 55 deletions

View File

@@ -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) 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-14T12:04:39 D 2007-04-16T15:02:19
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -86,7 +86,7 @@ F src/os_unix.c 426b4c03c304ad78746d65d9ba101e0b72e18e23
F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e F src/os_unix.h 5768d56d28240d3fe4537fac08cc85e4fb52279e
F src/os_win.c e94903c7dc1c0599c8ddce42efa0b6928068ddc5 F src/os_win.c e94903c7dc1c0599c8ddce42efa0b6928068ddc5
F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
F src/pager.c 4fb7253edc2377b12f16fa33adffda79f070c1b4 F src/pager.c 33c632ce9c228d87f14879a139fa123d43e4bf25
F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c F src/pager.h d652ddf092d2318d00e41f8539760fe8e57c157c
F src/parse.y b6cfbadb6d5b21b5087d30698ee5af0ebb098767 F src/parse.y b6cfbadb6d5b21b5087d30698ee5af0ebb098767
F src/pragma.c 3b992b5b2640d6ae25cef05aa6a42cd1d6c43234 F src/pragma.c 3b992b5b2640d6ae25cef05aa6a42cd1d6c43234
@@ -204,7 +204,7 @@ F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52
F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797 F test/enc2.test 45710bacfa9df29720bc84c067dfdf8c8ddfb797
F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030 F test/enc3.test 890508efff6677345e93bf2a8adb0489b30df030
F test/exclusive.test 5bc520ba366ae3d242420af025ab64d465b04706 F test/exclusive.test 5bc520ba366ae3d242420af025ab64d465b04706
F test/exclusive2.test dcb10d527722eb066ef7d060a0d47d7e59070d2e F test/exclusive2.test 6ef76efd3b442c95819446f8d15e6a63a1e95a4e
F test/exclusive3.test 0e49c35b7e7cb8e7280b4ce3f0359d30b207d2ff F test/exclusive3.test 0e49c35b7e7cb8e7280b4ce3f0359d30b207d2ff
F test/expr.test ab21e2fc3613595131efd7d8bbca4b95ed5cc608 F test/expr.test ab21e2fc3613595131efd7d8bbca4b95ed5cc608
F test/filefmt.test 053b622009fbbb74dd37921ffad374d852c13cd8 F test/filefmt.test 053b622009fbbb74dd37921ffad374d852c13cd8
@@ -316,7 +316,7 @@ F test/shared3.test 01e3e124dbb3859788aabc7cfb82f7ea04421749
F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821 F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a
F test/speed2.test 9b93b93681f82f320caa4b2c9f15c0de4f3a3d33 F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797 F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
F test/subselect.test 974e87f8fc91c5f00dd565316d396a5a6c3106c4 F test/subselect.test 974e87f8fc91c5f00dd565316d396a5a6c3106c4
F test/sync.test d05397b8f89f423dd6dba528692019ab036bc1c3 F test/sync.test d05397b8f89f423dd6dba528692019ab036bc1c3
@@ -458,7 +458,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P cfc6f933dc60ca88ae848f7f0c402e820437c2ff P 2c8e2a5be34cdfe11ef22bd6f78ec0519f497392
R 28caddcdc5058b3369c1c52b75efe638 R 814512695981b3392256843a965db823
U drh U drh
Z 5805ea2bb38918a004e8fa50c9627a61 Z 2bdc95de39af6db85ea861709e0ec935

View File

@@ -1 +1 @@
2c8e2a5be34cdfe11ef22bd6f78ec0519f497392 e44995debf2456e55b502783849e93a045a527c8

View File

@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while ** file simultaneously, or one process from reading the database while
** another is writing. ** 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 #ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h" #include "sqliteInt.h"
@@ -294,7 +294,7 @@ struct Pager {
Pager *pNext; /* Linked list of pagers in this thread */ Pager *pNext; /* Linked list of pagers in this thread */
#endif #endif
char *pTmpSpace; /* Pager.pageSize bytes of space for tmp use */ 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 #ifdef SQLITE_CHECK_PAGES
pPg->pageHash = pager_pagehash(pPg); pPg->pageHash = pager_pagehash(pPg);
#endif #endif
CODEC1(pPager, pData, pPg->pgno, 3); /* If this was page 1, then restore the value of Pager.dbFileVers.
** Do this before any decoding. */
/* If this was page 1, then restore the value of Pager.iChangeCount */
if( pgno==1 ){ 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; return rc;
} }
@@ -2441,6 +2443,9 @@ static int pager_write_pagelist(PgHdr *pList){
rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize); rc = sqlite3OsWrite(pPager->fd, pData, pPager->pageSize);
PAGER_INCR(sqlite3_pager_writedb_count); PAGER_INCR(sqlite3_pager_writedb_count);
PAGER_INCR(pPager->nWrite); PAGER_INCR(pPager->nWrite);
if( pList->pgno==1 ){
memcpy(&pPager->dbFileVers, &pData[24], sizeof(pPager->dbFileVers));
}
} }
#ifndef NDEBUG #ifndef NDEBUG
else{ else{
@@ -2680,6 +2685,10 @@ static int readDbPage(Pager *pPager, PgHdr *pPg, Pgno pgno){
PAGER_INCR(pPager->nRead); PAGER_INCR(pPager->nRead);
IOTRACE(("PGIN %p %d\n", pPager, pgno)); IOTRACE(("PGIN %p %d\n", pPager, pgno));
PAGERTRACE3("FETCH %d page %d\n", PAGERID(pPager), pPg->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); CODEC1(pPager, PGHDR_TO_DATA(pPg), pPg->pgno, 3);
return rc; return rc;
} }
@@ -2780,16 +2789,21 @@ static int pagerSharedLock(Pager *pPager){
if( pPager->pAll ){ if( pPager->pAll ){
/* The shared-lock has just been acquired on the database file /* The shared-lock has just been acquired on the database file
** and there are already pages in the cache (from a previous ** and there are already pages in the cache (from a previous
** read or write transaction). If the value of the change-counter ** read or write transaction). Check to see if the database
** stored in Pager.iChangeCount matches that found on page 1 of ** has been modified. If the database has changed, flush the
** the database file, then no database changes have occured since ** cache.
** the cache was last valid and it is safe to retain the cached **
** pages. Otherwise, if Pager.iChangeCount does not match the ** Database changes is detected by looking at 15 bytes beginning
** change-counter on page 1 of the file, the current cache contents ** at offset 24 into the file. The first 4 of these 16 bytes are
** must be discarded. ** 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]; char dbFileVers[sizeof(pPager->dbFileVers)];
u32 iChangeCounter = 0;
sqlite3PagerPagecount(pPager); sqlite3PagerPagecount(pPager);
if( pPager->errCode ){ if( pPager->errCode ){
@@ -2797,21 +2811,20 @@ static int pagerSharedLock(Pager *pPager){
} }
if( pPager->dbSize>0 ){ if( pPager->dbSize>0 ){
/* Read the 4-byte change counter directly from the file. */
rc = sqlite3OsSeek(pPager->fd, 24); rc = sqlite3OsSeek(pPager->fd, 24);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; return rc;
} }
rc = sqlite3OsRead(pPager->fd, zC, 4); rc = sqlite3OsRead(pPager->fd, &dbFileVers, sizeof(dbFileVers));
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
return rc; 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); pager_reset(pPager);
pPager->iChangeCount = iChangeCounter;
} }
} }
} }
@@ -3029,10 +3042,6 @@ int sqlite3PagerAcquire(
return rc; 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 */ /* Link the page into the page hash table */
h = pgno & (pPager->nHash-1); 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. */ /* Increment the value just read and write it back to byte 24. */
change_counter++; change_counter++;
put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter); put32bits(((char*)PGHDR_TO_DATA(pPgHdr))+24, change_counter);
pPager->iChangeCount = change_counter;
/* Release the page reference. */ /* Release the page reference. */
sqlite3PagerUnref(pPgHdr); sqlite3PagerUnref(pPgHdr);

View File

@@ -10,7 +10,7 @@
#*********************************************************************** #***********************************************************************
# This file implements regression tests for SQLite library. # 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] set testdir [file dirname $argv0]
source $testdir/tester.tcl source $testdir/tester.tcl
@@ -56,8 +56,9 @@ do_test exclusive2-1.0 {
# The following tests - exclusive2-1.X - check that: # The following tests - exclusive2-1.X - check that:
# #
# 1-3: Build a database with connection 1, calculate a signature. # 1-3: Build a database with connection 1, calculate a signature.
# 4-9: Modify the database using a second connection, then reset # 4-9: Modify the database using a second connection in a way that
# the pager change-counter to the value it had before the modifications. # 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 # 8: Check that using the first connection, the database signature
# is still the same. This is because it uses the in-memory cache. # 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. # 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 { do_test exclusive2-1.1 {
execsql { execsql {
BEGIN; BEGIN;
CREATE TABLE t1(a UNIQUE); CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1(a) VALUES(randstr(10, 400));
INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1(a) VALUES(randstr(10, 400));
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
COMMIT; COMMIT;
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
} }
@@ -94,7 +95,7 @@ do_test exclusive2-1.4 {
} $::sig } $::sig
do_test exclusive2-1.5 { do_test exclusive2-1.5 {
execsql { execsql {
DELETE FROM t1; UPDATE t1 SET b=a, a=NULL;
} db2 } db2
expr {[t1sig db2] eq $::sig} expr {[t1sig db2] eq $::sig}
} 0 } 0
@@ -135,13 +136,14 @@ do_test exclusive2-2.1 {
execsql {PRAGMA locking_mode = exclusive;} execsql {PRAGMA locking_mode = exclusive;}
execsql { execsql {
BEGIN; BEGIN;
INSERT INTO t1 VALUES(randstr(10, 400)); DELETE FROM t1;
INSERT INTO t1 VALUES(randstr(10, 400)); INSERT INTO t1(a) VALUES(randstr(10, 400));
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) VALUES(randstr(10, 400));
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 SELECT randstr(10, 400) FROM t1; INSERT INTO t1(a) SELECT randstr(10, 400) FROM t1;
INSERT INTO t1 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; COMMIT;
SELECT count(*) FROM t1; SELECT count(*) FROM t1;
} }

View File

@@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The # This file implements regression tests for SQLite library. The
# focus of this script is measuring executing speed. # 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] set testdir [file dirname $argv0]
@@ -67,7 +67,7 @@ do_test speed2-1.0 {
execsql { execsql {
PRAGMA page_size=1024; PRAGMA page_size=1024;
PRAGMA cache_size=8192; PRAGMA cache_size=8192;
-- PRAGMA locking_mode=EXCLUSIVE; PRAGMA locking_mode=EXCLUSIVE;
CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT); CREATE TABLE t1(a INTEGER, b INTEGER, c TEXT);
CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT); CREATE TABLE t2(a INTEGER, b INTEGER, c TEXT);
CREATE INDEX i2a ON t2(a); CREATE INDEX i2a ON t2(a);