/ Check-in [6242f113]
Login

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

Overview
Comment:Make sure mutexes are fully enabled for thread001.test. Take steps to ensure that the thread tests run during regression testing. (CVS 6193)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:6242f113eb40d472b78685c296fecf9f749a11cd
User & Date: drh 2009-01-19 17:40:12
Context
2009-01-19
18:18
Fix the --enable-tempstore option on the configure script. Ticket #3599 (CVS 6194) check-in: c2eabb99 user: drh tags: trunk
17:40
Make sure mutexes are fully enabled for thread001.test. Take steps to ensure that the thread tests run during regression testing. (CVS 6193) check-in: 6242f113 user: drh tags: trunk
2009-01-17
16:59
Fix a bug that was preventing SQLite from releasing locks properly under obscure circumstances. (CVS 6192) check-in: 502c66df user: danielk1977 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test1.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
176
177
178
179
180
181
182

183
184
185
186
187
188
189
190
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.342 2009/01/10 13:24:51 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
#define StmtToDb(X)   sqlite3_db_handle(X)

/*
** Check a return value to make sure it agrees with the results
** from sqlite3_errcode.
*/
int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){

  if( rc!=SQLITE_MISUSE && rc!=SQLITE_OK && sqlite3_errcode(db)!=rc ){
    char zBuf[200];
    int r2 = sqlite3_errcode(db);
    sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
       t1ErrorName(rc), rc, t1ErrorName(r2), r2);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, zBuf, 0);
    return 1;







|







 







>
|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing all sorts of SQLite interfaces.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.343 2009/01/19 17:40:12 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include <stdlib.h>
#include <string.h>

/*
................................................................................
#define StmtToDb(X)   sqlite3_db_handle(X)

/*
** Check a return value to make sure it agrees with the results
** from sqlite3_errcode.
*/
int sqlite3TestErrCode(Tcl_Interp *interp, sqlite3 *db, int rc){
  if( sqlite3_threadsafe()==0 && rc!=SQLITE_MISUSE && rc!=SQLITE_OK
   && sqlite3_errcode(db)!=rc ){
    char zBuf[200];
    int r2 = sqlite3_errcode(db);
    sprintf(zBuf, "error code %s (%d) does not match sqlite3_errcode %s (%d)",
       t1ErrorName(rc), rc, t1ErrorName(r2), r2);
    Tcl_ResetResult(interp);
    Tcl_AppendResult(interp, zBuf, 0);
    return 1;

Changes to src/test_mutex.c.

6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
359
360
361
362
363
364
365
366
367
368

369
370
371
372
373
374
375
376
377
**
**    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.
**
*************************************************************************
** 
** $Id: test_mutex.c,v 1.12 2008/11/04 14:55:47 danielk1977 Exp $
*/

#include "tcl.h"
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
................................................................................
  return TCL_OK;
}

static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
  sqlite3 *db;
  Tcl_CmdInfo info;
  char *zCmd = Tcl_GetString(pObj);
  if( 1!=Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
    Tcl_AppendResult(pInterp, "No such db-handle: \"", zCmd, "\"", 0);
    return 0;

  }
  db = *((sqlite3 **)info.objClientData);
  assert( db );
  return db;
}

static int test_enter_db_mutex(
  void * clientData,
  Tcl_Interp *interp,







|







 







|
|
|
>

<







6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
...
359
360
361
362
363
364
365
366
367
368
369
370

371
372
373
374
375
376
377
**
**    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.
**
*************************************************************************
** 
** $Id: test_mutex.c,v 1.13 2009/01/19 17:40:12 drh Exp $
*/

#include "tcl.h"
#include "sqlite3.h"
#include "sqliteInt.h"
#include <stdlib.h>
#include <assert.h>
................................................................................
  return TCL_OK;
}

static sqlite3 *getDbPointer(Tcl_Interp *pInterp, Tcl_Obj *pObj){
  sqlite3 *db;
  Tcl_CmdInfo info;
  char *zCmd = Tcl_GetString(pObj);
  if( Tcl_GetCommandInfo(pInterp, zCmd, &info) ){
    db = *((sqlite3 **)info.objClientData);
  }else{
    db = (sqlite3*)sqlite3TestTextToPtr(zCmd);
  }

  assert( db );
  return db;
}

static int test_enter_db_mutex(
  void * clientData,
  Tcl_Interp *interp,

Changes to src/test_thread.c.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
92
93
94
95
96
97
98
99
100

101
102
103
104
105

106
107
108
109
110
111
112
**
*************************************************************************
**
** This file contains the implementation of some Tcl commands used to
** test that sqlite3 database handles may be concurrently accessed by 
** multiple threads. Right now this only works on unix.
**
** $Id: test_thread.c,v 1.8 2008/08/28 13:55:10 danielk1977 Exp $
*/

#include "sqliteInt.h"
#include <tcl.h>

#if SQLITE_THREADSAFE && defined(TCL_THREADS)

#include <errno.h>
#include <unistd.h>

/*
** One of these is allocated for each thread created by [sqlthread spawn].
*/
................................................................................
** The main function for threads created with [sqlthread spawn].
*/
static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
  Tcl_Interp *interp;
  Tcl_Obj *pRes;
  Tcl_Obj *pList;
  int rc;

  SqlThread *p = (SqlThread *)pSqlThread;


  interp = Tcl_CreateInterp();
  Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
  Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0);
  Sqlitetest1_Init(interp);


  rc = Tcl_Eval(interp, p->zScript);
  pRes = Tcl_GetObjResult(interp);
  pList = Tcl_NewObj();
  Tcl_IncrRefCount(pList);
  Tcl_IncrRefCount(pRes);








|





|







 







<

>





>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
..
92
93
94
95
96
97
98

99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
**
*************************************************************************
**
** This file contains the implementation of some Tcl commands used to
** test that sqlite3 database handles may be concurrently accessed by 
** multiple threads. Right now this only works on unix.
**
** $Id: test_thread.c,v 1.9 2009/01/19 17:40:12 drh Exp $
*/

#include "sqliteInt.h"
#include <tcl.h>

#if SQLITE_THREADSAFE

#include <errno.h>
#include <unistd.h>

/*
** One of these is allocated for each thread created by [sqlthread spawn].
*/
................................................................................
** The main function for threads created with [sqlthread spawn].
*/
static Tcl_ThreadCreateType tclScriptThread(ClientData pSqlThread){
  Tcl_Interp *interp;
  Tcl_Obj *pRes;
  Tcl_Obj *pList;
  int rc;

  SqlThread *p = (SqlThread *)pSqlThread;
  extern int Sqlitetest_mutex_Init(Tcl_Interp*);

  interp = Tcl_CreateInterp();
  Tcl_CreateObjCommand(interp, "clock_seconds", clock_seconds_proc, 0, 0);
  Tcl_CreateObjCommand(interp, "sqlthread", sqlthread_proc, pSqlThread, 0);
  Sqlitetest1_Init(interp);
  Sqlitetest_mutex_Init(interp);

  rc = Tcl_Eval(interp, p->zScript);
  pRes = Tcl_GetObjResult(interp);
  pList = Tcl_NewObj();
  Tcl_IncrRefCount(pList);
  Tcl_IncrRefCount(pRes);

Changes to test/thread001.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
25
26
27
28
29
30
31


32
33
34
35
36
37
38
..
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
..
70
71
72
73
74
75
76
77
78

79
80
81

82
83
84
85
86
87
88
..
93
94
95
96
97
98
99

100
101

102
103
104
105
106
107
108
#
#    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.
#
#***********************************************************************
#
# $Id: thread001.test,v 1.6 2008/10/07 15:25:49 drh Exp $

set testdir [file dirname $argv0]

source $testdir/tester.tcl
ifcapable !mutex {
  return
}
................................................................................
set ::NTHREAD 10

# Run this test three times: 
# 
#    1) All threads use the same database handle.
#    2) All threads use their own database handles.
#    3) All threads use their own database handles, shared-cache is enabled.


#
foreach {tn same_db shared_cache} [list \
         1  1       0                   \
         2  0       0                   \
         3  0       1                   \
] {
  # Empty the database.
................................................................................
  catchsql { DROP TABLE ab; }

  do_test thread001.$tn.0 {
    db close
    sqlite3_enable_shared_cache $shared_cache
    sqlite3_enable_shared_cache $shared_cache
  } $shared_cache
  sqlite3 db test.db

  set dbconfig ""
  if {$same_db} {
    set dbconfig [list set ::DB [sqlite3_connection_pointer db]]
  }

  # Set up a database and a schema. The database contains a single
................................................................................
        (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) ==
        (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab))
    }
  } {1}
  do_test thread001.$tn.3 {
    execsql { PRAGMA integrity_check }
  } {ok}
  
  set thread_program {

    set needToClose 0
    if {![info exists ::DB]} {
      set ::DB [sqlthread open test.db]

      set needToClose 1
    }
  
    for {set i 0} {$i < 100} {incr i} {
      # Test that the invariant is true.
      do_test t1 {
        execsql {
................................................................................
      } {1}
  
      # Add another row to the database.
      execsql { INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab }
    }
  
    if {$needToClose} {

      sqlite3_close $::DB
    }

  
    list OK
  }
  
  # Kick off $::NTHREAD threads:
  #
  array unset finished







|







 







>
>







 







|







 







|

>



>







 







>


>







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
..
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
..
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#
#    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.
#
#***********************************************************************
#
# $Id: thread001.test,v 1.7 2009/01/19 17:40:12 drh Exp $

set testdir [file dirname $argv0]

source $testdir/tester.tcl
ifcapable !mutex {
  return
}
................................................................................
set ::NTHREAD 10

# Run this test three times: 
# 
#    1) All threads use the same database handle.
#    2) All threads use their own database handles.
#    3) All threads use their own database handles, shared-cache is enabled.
#
#
#
foreach {tn same_db shared_cache} [list \
         1  1       0                   \
         2  0       0                   \
         3  0       1                   \
] {
  # Empty the database.
................................................................................
  catchsql { DROP TABLE ab; }

  do_test thread001.$tn.0 {
    db close
    sqlite3_enable_shared_cache $shared_cache
    sqlite3_enable_shared_cache $shared_cache
  } $shared_cache
  sqlite3 db test.db -fullmutex 1

  set dbconfig ""
  if {$same_db} {
    set dbconfig [list set ::DB [sqlite3_connection_pointer db]]
  }

  # Set up a database and a schema. The database contains a single
................................................................................
        (SELECT md5sum(a, b) FROM ab WHERE a < (SELECT max(a) FROM ab)) ==
        (SELECT b FROM ab WHERE a = (SELECT max(a) FROM ab))
    }
  } {1}
  do_test thread001.$tn.3 {
    execsql { PRAGMA integrity_check }
  } {ok}

  set thread_program {
    #sqlthread parent {puts STARTING..}
    set needToClose 0
    if {![info exists ::DB]} {
      set ::DB [sqlthread open test.db]
      #sqlthread parent "puts \"OPEN $::DB\""
      set needToClose 1
    }
  
    for {set i 0} {$i < 100} {incr i} {
      # Test that the invariant is true.
      do_test t1 {
        execsql {
................................................................................
      } {1}
  
      # Add another row to the database.
      execsql { INSERT INTO ab SELECT NULL, md5sum(a, b) FROM ab }
    }
  
    if {$needToClose} {
      #sqlthread parent "puts \"CLOSE $::DB\""
      sqlite3_close $::DB
    }
    #sqlthread parent "puts \"DONE\""
  
    list OK
  }
  
  # Kick off $::NTHREAD threads:
  #
  array unset finished

Changes to test/thread_common.tcl.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
33
34
35
36
37
38
39

40
41
42
43
44
45
46
..
55
56
57
58
59
60
61


62


63
64
65

66


67
68
69
70
71
72
73
74
75
76
77
78
#
#    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.
#
#***********************************************************************
#
# $Id: thread_common.tcl,v 1.2 2007/09/10 10:53:02 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info commands sqlthread] eq ""} {
  puts -nonewline "Skipping thread-safety tests - "
  puts            " not running a threadsafe sqlite/tcl build"
................................................................................

    set rc SQLITE_LOCKED
    while {$rc eq "SQLITE_LOCKED" 
        || $rc eq "SQLITE_BUSY" 
        || $rc eq "SQLITE_SCHEMA"} {
      set res [list]


      set err [catch {
        set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 dummy_tail]
      } msg]

      if {$err == 0} {
        while {[set rc [sqlite3_step $::STMT]] eq "SQLITE_ROW"} {
          for {set i 0} {$i < [sqlite3_column_count $::STMT]} {incr i} {
................................................................................
          set rc SQLITE_ERROR
        }
      }

      if {[string first locked [sqlite3_errmsg $::DB]]>=0} {
        set rc SQLITE_LOCKED
      }





      if {$rc eq "SQLITE_LOCKED" || $rc eq "SQLITE_BUSY"} {
 #puts -nonewline "([sqlthread id] $rc)"
 #flush stdout

        after 20


      }
    }

    if {$rc ne "SQLITE_OK"} {
      error "$rc - [sqlite3_errmsg $::DB]"
    }
    set res
  }

  proc do_test {name script result} {
    set res [eval $script]
    if {$res ne $result} {







|







 







>







 







>
>
|
>
>

<
<
>
|
>
>




|







5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
..
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
#
#    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.
#
#***********************************************************************
#
# $Id: thread_common.tcl,v 1.3 2009/01/19 17:40:12 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

if {[info commands sqlthread] eq ""} {
  puts -nonewline "Skipping thread-safety tests - "
  puts            " not running a threadsafe sqlite/tcl build"
................................................................................

    set rc SQLITE_LOCKED
    while {$rc eq "SQLITE_LOCKED" 
        || $rc eq "SQLITE_BUSY" 
        || $rc eq "SQLITE_SCHEMA"} {
      set res [list]

      enter_db_mutex $::DB
      set err [catch {
        set ::STMT [sqlite3_prepare_v2 $::DB $sql -1 dummy_tail]
      } msg]

      if {$err == 0} {
        while {[set rc [sqlite3_step $::STMT]] eq "SQLITE_ROW"} {
          for {set i 0} {$i < [sqlite3_column_count $::STMT]} {incr i} {
................................................................................
          set rc SQLITE_ERROR
        }
      }

      if {[string first locked [sqlite3_errmsg $::DB]]>=0} {
        set rc SQLITE_LOCKED
      }
      if {$rc ne "SQLITE_OK"} {
        set errtxt "$rc - [sqlite3_errmsg $::DB] (debug1)"
      }
      leave_db_mutex $::DB

      if {$rc eq "SQLITE_LOCKED" || $rc eq "SQLITE_BUSY"} {


        #sqlthread parent "puts \"thread [sqlthread id] is busy.  rc=$rc\""
        after 200
      } else {
        #sqlthread parent "puts \"thread [sqlthread id] ran $sql\""
      }
    }

    if {$rc ne "SQLITE_OK"} {
      error $errtxt
    }
    set res
  }

  proc do_test {name script result} {
    set res [eval $script]
    if {$res ne $result} {