]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the pager locking mechanism so that we don't have to write page 1
authordrh <drh@noemail.net>
Tue, 5 Mar 2002 12:41:19 +0000 (12:41 +0000)
committerdrh <drh@noemail.net>
Tue, 5 Mar 2002 12:41:19 +0000 (12:41 +0000)
to the journal and to the database unless it actually changes. (CVS 419)

FossilOrigin-Name: 480eef1a3a4f049bc0d0cbee32dc8a8d138597c6

manifest
manifest.uuid
src/btree.c
src/pager.c
src/pager.h
tool/speedtest.tcl

index 5c6840dc7ba84606b0677a8c5107018840c38fbb..7a9a10958378d2cf698811dbda6dd8d9169ed89e 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Add\sthe\sability\sto\sturn\sof\scalls\sto\sfsync()\susing\sthe\s"synchronous"\spragma.\nIncreased\sthe\sdefault\scache\ssize\sfrom\s100\sto\s2000\sand\smade\sthe\s"cache_size"\npragma\spersistent.\s(CVS\s418)
-D 2002-03-05T01:11:13
+C Change\sthe\spager\slocking\smechanism\sso\sthat\swe\sdon't\shave\sto\swrite\spage\s1\nto\sthe\sjournal\sand\sto\sthe\sdatabase\sunless\sit\sactually\schanges.\s(CVS\s419)
+D 2002-03-05T12:41:20
 F Makefile.in 50f1b3351df109b5774771350d8c1b8d3640130d
 F Makefile.template 89e373b2dad0321df00400fa968dc14b61a03296
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -19,7 +19,7 @@ F ltmain.sh e9ed72eb1d690f447c13945eaf69e28af531eda1
 F publish.sh 5b59f4aff037aafa0e4a3b6fa599495dbd73f360
 F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
-F src/btree.c d25ea795a0f7017bc2099c437e6cc01d4c31b22d
+F src/btree.c b7d1b8875113ab4061a6a8cc759f75728ae7daf0
 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
 F src/build.c 0f3c6b6482e0b74284b22661de1b813a0bfb0197
 F src/delete.c 577da499162291c1855f0b304b211bffcf9da945
@@ -32,8 +32,8 @@ F src/main.c 3015c23faeff1709b1528f07c0bfe839284090a8
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c db969ecd1bcb4fef01b0b541b8b17401b0eb7ed2
 F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
-F src/pager.c 41af87908cd76a50d7e22cf3c7a4d479e3c9a512
-F src/pager.h feb18aab2f6dea439393f23a382699b9b1053c32
+F src/pager.c e1419353e68c45aaae2555d2000f72de6525faac
+F src/pager.h 6fddfddd3b73aa8abc081b973886320e3c614f0e
 F src/parse.y f7483ccff7b8f16d3655df59775d85b62b06897e
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
@@ -108,7 +108,7 @@ F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2
 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c
 F tool/renumberOps.awk 6d067177ad5f8d711b79577b462da9b3634bd0a9
 F tool/report1.txt 9eae07f26a8fc53889b45fc833a66a33daa22816
-F tool/speedtest.tcl 31a2f06e3d2153f4311b13cd6fd5e19b7adc8373
+F tool/speedtest.tcl 1c151e27d7ca10c6a2509bf6e816116744c3199e
 F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
@@ -128,7 +128,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 36a8fe0ad0ee2a67afafc04125dcc085ec1b5a13
-R e93330a0aa7a7fa6a56e7a5c31b63757
+P 414da4af1f4aebc3936ca339fbc7932add081912
+R 0b32113f5a809c11a2af16e72cce2c93
 U drh
-Z b84940384f009522e2520b7d71139ff4
+Z d718da112d32fa4d0c0cf7ece4f5da88
index 36d2035611d9d588b57c0d3c31ce590ae5aa9036..ba69187ab8dce0c83839b99af61ee3bb9a61b230 100644 (file)
@@ -1 +1 @@
-414da4af1f4aebc3936ca339fbc7932add081912
\ No newline at end of file
+480eef1a3a4f049bc0d0cbee32dc8a8d138597c6
\ No newline at end of file
index de288f9b4595eef7e305ecf2be17d7055117429d..a3a269e315cd035848124cd88a867aab3347111e 100644 (file)
@@ -9,7 +9,7 @@
 **    May you share freely, never taking more than you give.
 **
 *************************************************************************
-** $Id: btree.c,v 1.58 2002/03/03 23:06:01 drh Exp $
+** $Id: btree.c,v 1.59 2002/03/05 12:41:20 drh Exp $
 **
 ** This file implements a external (disk-based) database using BTrees.
 ** For a detailed discussion of BTrees, refer to
@@ -762,7 +762,7 @@ int sqliteBtreeBeginTrans(Btree *pBt){
   if( sqlitepager_isreadonly(pBt->pPager) ){
     return SQLITE_READONLY;
   }
-  rc = sqlitepager_write(pBt->page1);
+  rc = sqlitepager_begin(pBt->page1);
   if( rc==SQLITE_OK ){
     rc = newDatabase(pBt);
   }
index de332cba02d1ae6ad207b7acd7c4accb53fae8b5..1f0fb3aed88b9a3a942cc17ee5fc6922994ebd14 100644 (file)
@@ -18,7 +18,7 @@
 ** file simultaneously, or one process from reading the database while
 ** another is writing.
 **
-** @(#) $Id: pager.c,v 1.42 2002/03/05 01:11:14 drh Exp $
+** @(#) $Id: pager.c,v 1.43 2002/03/05 12:41:20 drh Exp $
 */
 #include "sqliteInt.h"
 #include "pager.h"
@@ -988,6 +988,63 @@ int sqlitepager_unref(void *pData){
   return SQLITE_OK;
 }
 
+/*
+** Acquire a write-lock on the database.  The lock is removed when
+** the any of the following happen:
+**
+**   *  sqlitepager_commit() is called.
+**   *  sqlitepager_rollback() is called.
+**   *  sqlitepager_close() is called.
+**   *  sqlitepager_unref() is called to on every outstanding page.
+**
+** The parameter to this routine is a pointer to any open page of the
+** database file.  Nothing changes about the page - it is used merely
+** to acquire a pointer to the Pager structure and as proof that there
+** is already a read-lock on the database.
+**
+** If the database is already write-locked, this routine is a no-op.
+*/
+int sqlitepager_begin(void *pData){
+  PgHdr *pPg = DATA_TO_PGHDR(pData);
+  Pager *pPager = pPg->pPager;
+  int rc = SQLITE_OK;
+  assert( pPg->nRef>0 );
+  assert( pPager->state!=SQLITE_UNLOCK );
+  if( pPager->state==SQLITE_READLOCK ){
+    assert( pPager->aInJournal==0 );
+    rc = sqliteOsWriteLock(&pPager->fd);
+    if( rc!=SQLITE_OK ){
+      return rc;
+    }
+    pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
+    if( pPager->aInJournal==0 ){
+      sqliteOsReadLock(&pPager->fd);
+      return SQLITE_NOMEM;
+    }
+    rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd, 0);
+    if( rc!=SQLITE_OK ){
+      sqliteFree(pPager->aInJournal);
+      pPager->aInJournal = 0;
+      sqliteOsReadLock(&pPager->fd);
+      return SQLITE_CANTOPEN;
+    }
+    pPager->journalOpen = 1;
+    pPager->needSync = !pPager->noSync;
+    pPager->state = SQLITE_WRITELOCK;
+    sqlitepager_pagecount(pPager);
+    pPager->origDbSize = pPager->dbSize;
+    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
+    if( rc==SQLITE_OK ){
+      rc = sqliteOsWrite(&pPager->jfd, &pPager->dbSize, sizeof(Pgno));
+    }
+    if( rc!=SQLITE_OK ){
+      rc = pager_unwritelock(pPager);
+      if( rc==SQLITE_OK ) rc = SQLITE_FULL;
+    }
+  }
+  return rc;
+}
+
 /*
 ** Mark a data page as writeable.  The page is written into the journal 
 ** if it is not there already.  This routine must be called before making
@@ -1035,39 +1092,8 @@ int sqlitepager_write(void *pData){
   ** create it if it does not.
   */
   assert( pPager->state!=SQLITE_UNLOCK );
-  if( pPager->state==SQLITE_READLOCK ){
-    assert( pPager->aInJournal==0 );
-    rc = sqliteOsWriteLock(&pPager->fd);
-    if( rc!=SQLITE_OK ){
-      return rc;
-    }
-    pPager->aInJournal = sqliteMalloc( pPager->dbSize/8 + 1 );
-    if( pPager->aInJournal==0 ){
-      sqliteOsReadLock(&pPager->fd);
-      return SQLITE_NOMEM;
-    }
-    rc = sqliteOsOpenExclusive(pPager->zJournal, &pPager->jfd, 0);
-    if( rc!=SQLITE_OK ){
-      sqliteFree(pPager->aInJournal);
-      pPager->aInJournal = 0;
-      sqliteOsReadLock(&pPager->fd);
-      return SQLITE_CANTOPEN;
-    }
-    pPager->journalOpen = 1;
-    pPager->needSync = 0;
-    pPager->state = SQLITE_WRITELOCK;
-    sqlitepager_pagecount(pPager);
-    pPager->origDbSize = pPager->dbSize;
-    rc = sqliteOsWrite(&pPager->jfd, aJournalMagic, sizeof(aJournalMagic));
-    if( rc==SQLITE_OK ){
-      rc = sqliteOsWrite(&pPager->jfd, &pPager->dbSize, sizeof(Pgno));
-    }
-    if( rc!=SQLITE_OK ){
-      rc = pager_unwritelock(pPager);
-      if( rc==SQLITE_OK ) rc = SQLITE_FULL;
-      return rc;
-    }
-  }
+  rc = sqlitepager_begin(pData);
+  if( rc!=SQLITE_OK ) return rc;
   assert( pPager->state==SQLITE_WRITELOCK );
   assert( pPager->journalOpen );
 
@@ -1247,6 +1273,9 @@ commit_abort:
 int sqlitepager_rollback(Pager *pPager){
   int rc;
   if( pPager->errMask!=0 && pPager->errMask!=PAGER_ERR_FULL ){
+    if( pPager->state>=SQLITE_WRITELOCK ){
+      pager_playback(pPager);
+    }
     return pager_errcode(pPager);
   }
   if( pPager->state!=SQLITE_WRITELOCK ){
index 91b3f8b0c1dbe96a8952aae9321c52bd9924bf02..d10d0d119c205b7b6c3c180f106e10ddaf6dc3e4 100644 (file)
@@ -13,7 +13,7 @@
 ** subsystem.  The page cache subsystem reads and writes a file a page
 ** at a time and provides a journal for rollback.
 **
-** @(#) $Id: pager.h,v 1.15 2002/03/02 20:41:59 drh Exp $
+** @(#) $Id: pager.h,v 1.16 2002/03/05 12:41:20 drh Exp $
 */
 
 /*
@@ -59,6 +59,7 @@ Pgno sqlitepager_pagenumber(void*);
 int sqlitepager_write(void*);
 int sqlitepager_iswriteable(void*);
 int sqlitepager_pagecount(Pager*);
+int sqlitepager_begin(void*);
 int sqlitepager_commit(Pager*);
 int sqlitepager_rollback(Pager*);
 int sqlitepager_isreadonly(Pager*);
index 8de470249c4bef5b2df2a21cdfe446f3c044e449..420eb35e6f985a3c122c363153a5e9f54037c1bc 100644 (file)
@@ -6,11 +6,12 @@
 
 # Run a test
 #
-set cnt 0
-proc runtest {title sqlfile} {
+set cnt 1
+proc runtest {title} {
   global cnt
-  incr cnt
+  set sqlfile test$cnt.sql
   puts "<h2>Test $cnt: $title</h2>"
+  incr cnt
   set fd [open $sqlfile r]
   set sql [string trim [read $fd [file size $sqlfile]]]
   close $fd
@@ -28,11 +29,14 @@ proc runtest {title sqlfile} {
   }
   puts "<blockquote>"
   puts "$sql"
-  puts "</blockquote><table border=0 cellpadding=0 cellspacing=5>"
-  set format {<tr><td>%s</td><td align="right">%.3f</td></tr>}
+  puts "</blockquote><table border=0 cellpadding=0 cellspacing=0>"
+  set format {<tr><td>%s</td><td align="right">&nbsp;&nbsp;&nbsp;%.3f</td></tr>}
+  set delay 1000
+  exec sync; after $delay;
   set t [time "exec psql drh <$sqlfile" 1]
   set t [expr {[lindex $t 0]/1000000.0}]
   puts [format $format PostgreSQL: $t]
+  exec sync; after $delay;
   set t [time "exec mysql drh <$sqlfile" 1]
   set t [expr {[lindex $t 0]/1000000.0}]
   puts [format $format MySQL: $t]
@@ -42,12 +46,17 @@ proc runtest {title sqlfile} {
 #  set t [time "exec ./sqlite-100 s100.db <$sqlfile" 1]
 #  set t [expr {[lindex $t 0]/1000000.0}]
 #  puts [format $format {SQLite 2.4 (cache=100):} $t]
+  exec sync; after $delay;
   set t [time "exec ./sqlite240 s2k.db <$sqlfile" 1]
   set t [expr {[lindex $t 0]/1000000.0}]
-  puts [format $format {SQLite 2.4 (cache=2000):} $t]
+  puts [format $format {SQLite 2.4:} $t]
+  exec sync; after $delay;
   set t [time "exec ./sqlite240 sns.db <$sqlfile" 1]
   set t [expr {[lindex $t 0]/1000000.0}]
   puts [format $format {SQLite 2.4 (nosync):} $t]
+#  set t [time "exec ./sqlite-t1 st1.db <$sqlfile" 1]
+#  set t [expr {[lindex $t 0]/1000000.0}]
+#  puts [format $format {SQLite 2.4 (test):} $t]
   puts "</table>"
 }
 
@@ -67,6 +76,7 @@ set fd [open 2kinit.sql w]
 puts $fd {PRAGMA cache_size=2000; PRAGMA synchronous=on;}
 close $fd
 exec ./sqlite240 s2k.db <2kinit.sql
+exec ./sqlite-t1 st1.db <2kinit.sql
 set fd [open nosync-init.sql w]
 puts $fd {PRAGMA cache_size=2000; PRAGMA synchronous=off;}
 close $fd
@@ -82,11 +92,11 @@ proc number_name {n} {
   } else {
     set txt {}
   }
-  if {$n>100} {
+  if {$n>=100} {
     append txt " [lindex $::ones [expr {$n/100}]] hundred"
     set n [expr {$n%100}]
   }
-  if {$n>19} {
+  if {$n>=20} {
     append txt " [lindex $::tens [expr {$n/10}]]"
     set n [expr {$n%10}]
   }
@@ -98,20 +108,20 @@ proc number_name {n} {
   return $txt
 }
 
-# TEST 1
-#
-set fd [open test1.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd "CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100));"
 for {set i 1} {$i<=1000} {incr i} {
   set r [expr {int(rand()*100000)}]
   puts $fd "INSERT INTO t1 VALUES($i,$r,'[number_name $r]');"
 }
 close $fd
-runtest {1000 INSERTs} test1.sql
+runtest {1000 INSERTs}
 
-# TEST 2
-#
-set fd [open test2.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd "BEGIN;"
 puts $fd "CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100));"
 for {set i 1} {$i<=25000} {incr i} {
@@ -120,41 +130,50 @@ for {set i 1} {$i<=25000} {incr i} {
 }
 puts $fd "COMMIT;"
 close $fd
-runtest {25000 INSERTs in a transaction} test2.sql
+runtest {25000 INSERTs in a transaction}
 
-# TEST 3
-#
-set fd [open test3.sql w]
+
+
+set fd [open test$cnt.sql w]
 for {set i 0} {$i<100} {incr i} {
   set lwr [expr {$i*100}]
   set upr [expr {($i+10)*100}]
   puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;"
 }
 close $fd
-runtest {100 SELECTs without an index} test3.sql
+runtest {100 SELECTs without an index}
 
-# TEST 4
-#
-set fd [open test4.sql w]
+
+
+set fd [open test$cnt.sql w]
+for {set i 1} {$i<=100} {incr i} {
+  puts $fd "SELECT count(*), avg(b) FROM t2 WHERE c LIKE '%[number_name $i]%';"
+}
+close $fd
+runtest {100 SELECTs on a string comparison}
+
+
+
+set fd [open test$cnt.sql w]
 puts $fd {CREATE INDEX i2a ON t2(a);}
 puts $fd {CREATE INDEX i2b ON t2(b);}
 close $fd
-runtest {Creating an index} test4.sql
+runtest {Creating an index}
 
-# TEST 5
-#
-set fd [open test5.sql w]
+
+
+set fd [open test$cnt.sql w]
 for {set i 0} {$i<5000} {incr i} {
   set lwr [expr {$i*100}]
   set upr [expr {($i+1)*100}]
   puts $fd "SELECT count(*), avg(b) FROM t2 WHERE b>=$lwr AND b<$upr;"
 }
 close $fd
-runtest {5000 SELECTs with an index} test5.sql
+runtest {5000 SELECTs with an index}
 
-# TEST 6
-#
-set fd [open test6.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd "BEGIN;"
 for {set i 0} {$i<100} {incr i} {
   set lwr [expr {$i*10}]
@@ -163,52 +182,53 @@ for {set i 0} {$i<100} {incr i} {
 }
 puts $fd "COMMIT;"
 close $fd
-runtest {100 UPDATEs without an index} test6.sql
+runtest {100 UPDATEs without an index}
+
 
 
-# TEST 7
-set fd [open test7.sql w]
+set fd [open test$cnt.sql w]
 puts $fd "BEGIN;"
 for {set i 1} {$i<=25000} {incr i} {
   puts $fd "UPDATE t2 SET b=b+a WHERE a=$i;"
 }
 puts $fd "COMMIT;"
 close $fd
-runtest {25000 UPDATEs with an index} test7.sql
+runtest {25000 UPDATEs with an index}
+
 
-# TEST 8
-set fd [open test8.sql w]
+
+set fd [open test$cnt.sql w]
 puts $fd "BEGIN;"
 puts $fd "INSERT INTO t1 SELECT * FROM t2;"
 puts $fd "INSERT INTO t2 SELECT * FROM t1;"
 puts $fd "COMMIT;"
 close $fd
-runtest {INSERTs from a SELECT} test8.sql
+runtest {INSERTs from a SELECT}
 
-# TEST 9
-#
-set fd [open test9.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd {DELETE FROM t2 WHERE c LIKE '%fifty%';}
 close $fd
-runtest {DELETE without an index} test9.sql
+runtest {DELETE without an index}
 
-# TEST 10
-#
-set fd [open test10.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd {DELETE FROM t2 WHERE a>10 AND a<20000;}
 close $fd
-runtest {DELETE with an index} test10.sql
+runtest {DELETE with an index}
 
-# TEST 11
-#
-set fd [open test11.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd {INSERT INTO t2 SELECT * FROM t1;}
 close $fd
-runtest {A big INSERT after a big DELETE} test11.sql
+runtest {A big INSERT after a big DELETE}
 
-# TEST 12
-#
-set fd [open test12.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd {BEGIN;}
 puts $fd {DELETE FROM t1;}
 for {set i 1} {$i<=1000} {incr i} {
@@ -217,12 +237,12 @@ for {set i 1} {$i<=1000} {incr i} {
 }
 puts $fd {COMMIT;}
 close $fd
-runtest {A big DELETE followed by many small INSERTs} test12.sql
+runtest {A big DELETE followed by many small INSERTs}
 
-# TEST 13
-#
-set fd [open test13.sql w]
+
+
+set fd [open test$cnt.sql w]
 puts $fd {DROP TABLE t1;}
 puts $fd {DROP TABLE t2;}
 close $fd
-runtest {DROP TABLE} test13.sql
+runtest {DROP TABLE}