/ 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 Unified Diffs Ignore Whitespace Patch

Changes to src/pcache.c.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
681
682
683
684
685
686
687

688
689
690
691
692
693
694
695
696
697
698
699
700

701
702
703

704
705
706
707
708
709
710
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.19 2008/08/28 02:26:07 drh Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
**
** A cache may only be deleted by its owner and while holding the
................................................................................
  assert( pCache!=0 );
  assert( pgno>0 );
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );

  /* Search the hash table for the requested page. Exit early if it is found. */
  if( pCache->apHash ){
    u32 h = pgno % pCache->nHash;

    for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
      if( pPage->pgno==pgno ){
        if( pPage->nRef==0 ){
          if( 0==(pPage->flags&PGHDR_DIRTY) ){
            pcacheEnterMutex();
            pcacheRemoveFromLruList(pPage);
            pcacheExitMutex();
            pCache->nPinned++;
          }
          pCache->nRef++;
        }
        pPage->nRef++;
        *ppPage = pPage;

        return SQLITE_OK;
      }
    }

  }

  if( createFlag ){
    int rc = SQLITE_OK;
    if( pCache->nHash<=pCache->nPage ){
      rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2);
      if( rc!=SQLITE_OK ){







|







 







>




<

<






>



>







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
681
682
683
684
685
686
687
688
689
690
691
692

693

694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This file implements that page cache.
**
** @(#) $Id: pcache.c,v 1.20 2008/08/28 08:31:48 danielk1977 Exp $
*/
#include "sqliteInt.h"

/*
** A complete page cache is an instance of this structure.
**
** A cache may only be deleted by its owner and while holding the
................................................................................
  assert( pCache!=0 );
  assert( pgno>0 );
  expensive_assert( pCache->nPinned==pcachePinnedCount(pCache) );

  /* Search the hash table for the requested page. Exit early if it is found. */
  if( pCache->apHash ){
    u32 h = pgno % pCache->nHash;
    pcacheEnterMutex();
    for(pPage=pCache->apHash[h]; pPage; pPage=pPage->pNextHash){
      if( pPage->pgno==pgno ){
        if( pPage->nRef==0 ){
          if( 0==(pPage->flags&PGHDR_DIRTY) ){

            pcacheRemoveFromLruList(pPage);

            pCache->nPinned++;
          }
          pCache->nRef++;
        }
        pPage->nRef++;
        *ppPage = pPage;
        pcacheExitMutex();
        return SQLITE_OK;
      }
    }
    pcacheExitMutex();
  }

  if( createFlag ){
    int rc = SQLITE_OK;
    if( pCache->nHash<=pCache->nPage ){
      rc = pcacheResizeHash(pCache, pCache->nHash<256 ? 256 : pCache->nHash*2);
      if( rc!=SQLITE_OK ){

Changes to test/quick.test.

2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
72
73
74
75
76
77
78

79
80
81
82
83
84
85
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: quick.test,v 1.85 2008/08/27 18:56:36 drh Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
  speed3.test
  speed4.test
  speed4p.test
  sqllimits1.test
  tkt2686.test
  thread001.test
  thread002.test

  trans2.test
  vacuum3.test

  incrvacuum_ioerr.test
  autovacuum_crash.test
  btree8.test
  shared_err.test







|







 







>







2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
..
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
# This file runs all tests.
#
# $Id: quick.test,v 1.86 2008/08/28 08:31:48 danielk1977 Exp $

proc lshift {lvar} {
  upvar $lvar l
  set ret [lindex $l 0]
  set l [lrange $l 1 end]
  return $ret
}
................................................................................
  speed3.test
  speed4.test
  speed4p.test
  sqllimits1.test
  tkt2686.test
  thread001.test
  thread002.test
  thread003.test
  trans2.test
  vacuum3.test

  incrvacuum_ioerr.test
  autovacuum_crash.test
  btree8.test
  shared_err.test

Added test/thread003.test.







































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 2007 September 10
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
#   This file contains tests that attempt to break the pcache module
#   by bombarding it with simultaneous requests from multiple threads.
#     
# $Id: thread003.test,v 1.1 2008/08/28 08:31:48 danielk1977 Exp $

set testdir [file dirname $argv0]

source $testdir/tester.tcl
source $testdir/thread_common.tcl
if {[info commands sqlthread] eq ""} {
  finish_test
  return
}

# Set up a couple of different databases full of pseudo-randomly 
# generated data.
#
do_test thread003.1.1 {
  execsql {
    BEGIN;
    CREATE TABLE t1(a, b, c);
  }
  for {set ii 0} {$ii < 5000} {incr ii} {
    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
  }
  execsql { 
    CREATE INDEX i1 ON t1(a, b); 
    COMMIT;
  }
} {}
do_test thread003.1.2 {
  expr {([file size test.db] / 1024) > 2000}
} {1}
do_test thread003.1.3 {
  db close
  file delete -force test2.db
  sqlite3 db test2.db
} {}
do_test thread003.1.4 {
  execsql {
    BEGIN;
    CREATE TABLE t1(a, b, c);
  }
  for {set ii 0} {$ii < 5000} {incr ii} {
    execsql {INSERT INTO t1 VALUES($ii, randomblob(200), randomblob(200))}
  }
  execsql { 
    CREATE INDEX i1 ON t1(a, b); 
    COMMIT;
  }
} {}
do_test thread003.1.5 {
  expr {([file size test.db] / 1024) > 2000}
} {1}
do_test thread003.1.6 {
  db close
} {}


# This test opens a connection on each of the large (>2MB) database files
# created by the previous block. The connections do not share a cache.
# Both "cache_size" parameters are set to 15, so there is a maximum of
# 30 pages available globally.
#
# Then, in separate threads, the databases are randomly queried over and
# over again. This will force the connections to recycle clean pages from
# each other. If there is a thread-safety problem, a segfault or assertion
# failure may eventually occur.
#
set nSecond 30
puts "Starting thread003.2 (should run for ~$nSecond seconds)"
do_test thread003.2 {
  foreach zFile {test.db test2.db} {
    set SCRIPT [format {
      set iStart [clock seconds]
      set iEnd [expr {[clock seconds] + %d}]
      set ::DB [sqlthread open %s]
  
      # Set the cache size to 15 pages per cache. 30 available globally.
      execsql { PRAGMA cache_size = 15 }
  
      while {[clock seconds] < $iEnd} {
        set iQuery [expr {int(rand()*5000)}]
        execsql " SELECT * FROM t1 WHERE a = $iQuery "
      }
  
      sqlite3_close $::DB
      expr 1
    } $nSecond $zFile]
  
    unset -nocomplain finished($zFile)
    thread_spawn finished($zFile) $thread_procs $SCRIPT
  }
  foreach zFile {test.db test2.db} {
    if {![info exists finished($zFile)]} {
      vwait finished($zFile)
    }
  }
  expr 0
} {0}

finish_test