SQLite

Check-in [1928f15b78]
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
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1928f15b78eee0fbf0a8ecdbbdd38dbbde2942b8
User & Date: danielk1977 2008-08-28 08:31:48.000
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: 473c09fac2 user: danielk1977 tags: trunk)
08:31
Fix a threads/mutex problem in pcache.c. (CVS 5630) (check-in: 1928f15b78 user: danielk1977 tags: trunk)
02:26
Miscellaneous cleanup in the new pcache code. (CVS 5629) (check-in: da1777259f user: drh tags: trunk)
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to src/pcache.c.
1
2
3
4
5
6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17
18
19
20
21













-
+







/*
** 2008 August 05
**
** 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 implements that page cache.
**
** @(#) $Id: pcache.c,v 1.19 2008/08/28 02:26:07 drh Exp $
** @(#) $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
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
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







+




-

-






+



+







  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) ){
            pcacheEnterMutex();
            pcacheRemoveFromLruList(pPage);
            pcacheExitMutex();
            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.
1
2
3
4
5
6
7
8
9

10
11
12
13
14
15
16
1
2
3
4
5
6
7
8

9
10
11
12
13
14
15
16








-
+







#
#    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 $
# $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
}
72
73
74
75
76
77
78

79
80
81
82
83
84
85
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86







+







  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