/ Check-in [1928f15b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix a threads/mutex problem in pcache.c. (CVS 5630)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1928f15b78eee0fbf0a8ecdbbdd38dbbde2942b8
User & Date: danielk1977 2008-08-28 08:31:48
Context
2008-08-28
10:21
Enable the disabled asserts added by (5629). Add extra tests to thread003.test. And the required modifications to pcache.c. (CVS 5631) check-in: 473c09fa user: danielk1977 tags: trunk
08:31
Fix a threads/mutex problem in pcache.c. (CVS 5630) check-in: 1928f15b user: danielk1977 tags: trunk
02:26
Miscellaneous cleanup in the new pcache code. (CVS 5629) check-in: da177725 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/pcache.c.

     7      7   **    May you do good and not evil.
     8      8   **    May you find forgiveness for yourself and forgive others.
     9      9   **    May you share freely, never taking more than you give.
    10     10   **
    11     11   *************************************************************************
    12     12   ** This file implements that page cache.
    13     13   **
    14         -** @(#) $Id: pcache.c,v 1.19 2008/08/28 02:26:07 drh Exp $
           14  +** @(#) $Id: pcache.c,v 1.20 2008/08/28 08:31:48 danielk1977 Exp $
    15     15   */
    16     16   #include "sqliteInt.h"
    17     17   
    18     18   /*
    19     19   ** A complete page cache is an instance of this structure.
    20     20   **
    21     21   ** A cache may only be deleted by its owner and while holding the
................................................................................
   681    681     assert( pCache!=0 );
   682    682     assert( pgno>0 );
   683    683     expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );
   684    684   
   685    685     /* Search the hash table for the requested page. Exit early if it is found. */
   686    686     if( pCache->apHash ){
   687    687       u32 h = pgno % pCache->nHash;
          688  +    pcacheEnterMutex();
   688    689       for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
   689    690         if( pPage->pgno==pgno ){
   690    691           if( pPage->nRef==0 ){
   691    692             if( 0==(pPage->flags&PGHDR_DIRTY) ){
   692         -            pcacheEnterMutex();
   693    693               pcacheRemoveFromLruList(pPage);
   694         -            pcacheExitMutex();
   695    694               pCache->nPinned++;
   696    695             }
   697    696             pCache->nRef++;
   698    697           }
   699    698           pPage->nRef++;
   700    699           *ppPage = pPage;
          700  +        pcacheExitMutex();
   701    701           return SQLITE_OK;
   702    702         }
   703    703       }
          704  +    pcacheExitMutex();
   704    705     }
   705    706   
   706    707     if( createFlag ){
   707    708       int rc = SQLITE_OK;
   708    709       if( pCache->nHash<=pCache->nPage ){
   709    710         rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2);
   710    711         if( rc!=SQLITE_OK ){

Changes to test/quick.test.

     2      2   #    May you do good and not evil.
     3      3   #    May you find forgiveness for yourself and forgive others.
     4      4   #    May you share freely, never taking more than you give.
     5      5   #
     6      6   #***********************************************************************
     7      7   # This file runs all tests.
     8      8   #
     9         -# $Id: quick.test,v 1.85 2008/08/27 18:56:36 drh Exp $
            9  +# $Id: quick.test,v 1.86 2008/08/28 08:31:48 danielk1977 Exp $
    10     10   
    11     11   proc lshift {lvar} {
    12     12     upvar $lvar l
    13     13     set ret [lindex $l 0]
    14     14     set l [lrange $l 1 end]
    15     15     return $ret
    16     16   }
................................................................................
    72     72     speed3.test
    73     73     speed4.test
    74     74     speed4p.test
    75     75     sqllimits1.test
    76     76     tkt2686.test
    77     77     thread001.test
    78     78     thread002.test
           79  +  thread003.test
    79     80     trans2.test
    80     81     vacuum3.test
    81     82   
    82     83     incrvacuum_ioerr.test
    83     84     autovacuum_crash.test
    84     85     btree8.test
    85     86     shared_err.test

Added test/thread003.test.

            1  +# 2007 September 10
            2  +#
            3  +# The author disclaims copyright to this source code.  In place of
            4  +# a legal notice, here is a blessing:
            5  +#
            6  +#    May you do good and not evil.
            7  +#    May you find forgiveness for yourself and forgive others.
            8  +#    May you share freely, never taking more than you give.
            9  +#
           10  +#***********************************************************************
           11  +#
           12  +#   This file contains tests that attempt to break the pcache module
           13  +#   by bombarding it with simultaneous requests from multiple threads.
           14  +#     
           15  +# $Id: thread003.test,v 1.1 2008/08/28 08:31:48 danielk1977 Exp $
           16  +
           17  +set testdir [file dirname $argv0]
           18  +
           19  +source $testdir/tester.tcl
           20  +source $testdir/thread_common.tcl
           21  +if {[info commands sqlthread] eq ""} {
           22  +  finish_test
           23  +  return
           24  +}
           25  +
           26  +# Set up a couple of different databases full of pseudo-randomly 
           27  +# generated data.
           28  +#
           29  +do_test thread003.1.1 {
           30  +  execsql {
           31  +    BEGIN;
           32  +    CREATE TABLE t1(a, b, c);
           33  +  }
           34  +  for {set ii 0} {$ii < 5000} {incr ii} {
           35  +    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
           36  +  }
           37  +  execsql { 
           38  +    CREATE INDEX i1 ON t1(a, b); 
           39  +    COMMIT;
           40  +  }
           41  +} {}
           42  +do_test thread003.1.2 {
           43  +  expr {([file size test.db] / 1024) > 2000}
           44  +} {1}
           45  +do_test thread003.1.3 {
           46  +  db close
           47  +  file delete -force test2.db
           48  +  sqlite3 db test2.db
           49  +} {}
           50  +do_test thread003.1.4 {
           51  +  execsql {
           52  +    BEGIN;
           53  +    CREATE TABLE t1(a, b, c);
           54  +  }
           55  +  for {set ii 0} {$ii < 5000} {incr ii} {
           56  +    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
           57  +  }
           58  +  execsql { 
           59  +    CREATE INDEX i1 ON t1(a, b); 
           60  +    COMMIT;
           61  +  }
           62  +} {}
           63  +do_test thread003.1.5 {
           64  +  expr {([file size test.db] / 1024) > 2000}
           65  +} {1}
           66  +do_test thread003.1.6 {
           67  +  db close
           68  +} {}
           69  +
           70  +
           71  +# This test opens a connection on each of the large (>2MB) database files
           72  +# created by the previous block. The connections do not share a cache.
           73  +# Both "cache_size" parameters are set to 15, so there is a maximum of
           74  +# 30 pages available globally.
           75  +#
           76  +# Then, in separate threads, the databases are randomly queried over and
           77  +# over again. This will force the connections to recycle clean pages from
           78  +# each other. If there is a thread-safety problem, a segfault or assertion
           79  +# failure may eventually occur.
           80  +#
           81  +set nSecond 30
           82  +puts "Starting thread003.2 (should run for ~$nSecond seconds)"
           83  +do_test thread003.2 {
           84  +  foreach zFile {test.db test2.db} {
           85  +    set SCRIPT [format {
           86  +      set iStart [clock seconds]
           87  +      set iEnd [expr {[clock seconds] + %d}]
           88  +      set ::DB [sqlthread open %s]
           89  +  
           90  +      # Set the cache size to 15 pages per cache. 30 available globally.
           91  +      execsql { PRAGMA cache_size = 15 }
           92  +  
           93  +      while {[clock seconds] < $iEnd} {
           94  +        set iQuery [expr {int(rand()*5000)}]
           95  +        execsql " SELECT * FROM t1 WHERE a = $iQuery "
           96  +      }
           97  +  
           98  +      sqlite3_close $::DB
           99  +      expr 1
          100  +    } $nSecond $zFile]
          101  +  
          102  +    unset -nocomplain finished($zFile)
          103  +    thread_spawn finished($zFile) $thread_procs $SCRIPT
          104  +  }
          105  +  foreach zFile {test.db test2.db} {
          106  +    if {![info exists finished($zFile)]} {
          107  +      vwait finished($zFile)
          108  +    }
          109  +  }
          110  +  expr 0
          111  +} {0}
          112  +
          113  +finish_test
          114  +
          115  +