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)
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

View File

@ -1 +1 @@
2c8e2a5be34cdfe11ef22bd6f78ec0519f497392
e44995debf2456e55b502783849e93a045a527c8

View 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);

View 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;
}

View 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);