/ Check-in [7214dab7]
Login

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

Overview
Comment:Also merge the WAL blocking lock tests that were somehow missed on the previous check-in.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7214dab7443d35c105904dd69635c1f8b45b2fc8
User & Date: drh 2015-03-17 17:08:35
Context
2015-03-17
20:39
Clarify the documentation on sqlite3_errcode(). No changes to code. check-in: 2c0e0d87 user: drh tags: trunk
18:54
Merge all recent trunk enhancements into the sessions branch. check-in: 1d1c57c3 user: drh tags: sessions
18:35
Merge all recent trunk changes, and in particular the blocking WAL lock change, into the apple-osx branch. check-in: 8abbeadb user: drh tags: apple-osx
17:08
Also merge the WAL blocking lock tests that were somehow missed on the previous check-in. check-in: 7214dab7 user: drh tags: trunk
16:59
Transient locks in WAL mode can now block in order to resolve priority inversions. check-in: ec2f46de user: drh tags: trunk
16:01
Add a test for the change on this branch. Closed-Leaf check-in: e22dde18 user: dan tags: wal-blocking-lock
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/test_vfs.c.

962
963
964
965
966
967
968





969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
....
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544

  return rc;
}

static void tvfsShmBarrier(sqlite3_file *pFile){
  TestvfsFd *pFd = tvfsGetFd(pFile);
  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);






  if( p->isFullshm ){
    sqlite3OsShmBarrier(pFd->pReal);
    return;
  }

  if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
    tvfsExecTcl(p, "xShmBarrier", 
        Tcl_NewStringObj(pFd->pShm->zFile, -1), pFd->pShmId, 0, 0
    );
  }
}

static int tvfsShmUnmap(
  sqlite3_file *pFile,
  int deleteFlag
){
  int rc = SQLITE_OK;
................................................................................
  p->mask = TESTVFS_ALL_MASK;

  sqlite3_vfs_register(pVfs, isDefault);

  return TCL_OK;

 bad_args:
  Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
  return TCL_ERROR;
}

int Sqlitetestvfs_Init(Tcl_Interp *interp){
  Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
  return TCL_OK;
}

#endif







>
>
>
>
>





<
<
<
<
<
<







 







|









962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978






979
980
981
982
983
984
985
....
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543

  return rc;
}

static void tvfsShmBarrier(sqlite3_file *pFile){
  TestvfsFd *pFd = tvfsGetFd(pFile);
  Testvfs *p = (Testvfs *)(pFd->pVfs->pAppData);

  if( p->pScript && p->mask&TESTVFS_SHMBARRIER_MASK ){
    const char *z = pFd->pShm ? pFd->pShm->zFile : "";
    tvfsExecTcl(p, "xShmBarrier", Tcl_NewStringObj(z, -1), pFd->pShmId, 0, 0);
  }

  if( p->isFullshm ){
    sqlite3OsShmBarrier(pFd->pReal);
    return;
  }






}

static int tvfsShmUnmap(
  sqlite3_file *pFile,
  int deleteFlag
){
  int rc = SQLITE_OK;
................................................................................
  p->mask = TESTVFS_ALL_MASK;

  sqlite3_vfs_register(pVfs, isDefault);

  return TCL_OK;

 bad_args:
  Tcl_WrongNumArgs(interp, 1, objv, "VFSNAME ?-noshm BOOL? ?-fullshm BOOL? ?-default BOOL? ?-mxpathname INT? ?-szosfile INT? ?-iversion INT?");
  return TCL_ERROR;
}

int Sqlitetestvfs_Init(Tcl_Interp *interp){
  Tcl_CreateObjCommand(interp, "testvfs", testvfs_cmd, 0, 0);
  return TCL_OK;
}

#endif

Changes to test/lock_common.tcl.

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
  }
  return $chan
}

# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
#
proc testfixture {chan cmd} {



  puts $chan $cmd
  puts $chan OVER

  set r ""
  while { 1 } {
    set line [gets $chan]
    if { $line == "OVER" } { 
      set res [lindex $r 1]
      if { [lindex $r 0] } { error $res }
      return $res
    }
    if {[eof $chan]} {
      return "ERROR: Child process hung up"
    }
    append r $line


























  }
}

proc testfixture_nb_cb {varname chan} {
  if {[eof $chan]} {
    append ::tfnb($chan) "ERROR: Child process hung up"
    set line "OVER"







|
>
>
>
|
|
>
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  }
  return $chan
}

# Execute a command in a child testfixture process, connected by two-way
# channel $chan. Return the result of the command, or an error message.
#
proc testfixture {chan cmd args} {

  if {[llength $args] == 0} {
    fconfigure $chan -blocking 1
    puts $chan $cmd
    puts $chan OVER

    set r ""
    while { 1 } {
      set line [gets $chan]
      if { $line == "OVER" } { 
        set res [lindex $r 1]
        if { [lindex $r 0] } { error $res }
        return $res
      }
      if {[eof $chan]} {
        return "ERROR: Child process hung up"
      }
      append r $line
    }
    return $r
  } else {
    set ::tfnb($chan) ""
    fconfigure $chan -blocking 0 -buffering none
    puts $chan $cmd
    puts $chan OVER
    fileevent $chan readable [list testfixture_script_cb $chan [lindex $args 0]]
    return ""
  }
}

proc testfixture_script_cb {chan script} {
  if {[eof $chan]} {
    append ::tfnb($chan) "ERROR: Child process hung up"
    set line "OVER"
  } else {
    set line [gets $chan]
  }

  if { $line == "OVER" } {
    uplevel #0 $script [list [lindex $::tfnb($chan) 1]]
    unset ::tfnb($chan)
    fileevent $chan readable ""
  } else {
    append ::tfnb($chan) $line
  }
}

proc testfixture_nb_cb {varname chan} {
  if {[eof $chan]} {
    append ::tfnb($chan) "ERROR: Child process hung up"
    set line "OVER"

Added test/walblock.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
116
117
# 2015 Mar 17
#
# 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.
#
#***********************************************************************
#

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

ifcapable !wal {finish_test ; return }
if {$::tcl_platform(platform)!="unix"} { finish_test ; return }
set testprefix walblock

catch { db close }
testvfs tvfs -fullshm 1
foreach f [glob test.db*] { forcedelete $f }

sqlite3 db test.db -vfs tvfs
do_execsql_test 1.1.0 {
  CREATE TABLE t1(x, y);
  INSERT INTO t1 VALUES(1, 2);
  INSERT INTO t1 VALUES(3, 4);
  INSERT INTO t1 VALUES(5, 6);
  PRAGMA journal_mode = wal;
  INSERT INTO t1 VALUES(7, 8);
} {wal}

do_test 1.1.1 { 
  lsort [glob test.db*] 
} {test.db test.db-shm test.db-wal}

do_test 1.1.2 { 
  set C [launch_testfixture]
  testfixture $C {
    sqlite3 db test.db
    db eval { SELECT * FROM t1 }
  }
} {1 2 3 4 5 6 7 8}

do_test 1.1.3 { 
  set ::out [list]
  testfixture $C {
    db eval { SELECT * FROM t1 }
  } [list set ::out]
  set ::out
} {}

do_test 1.1.4 { 
  vwait ::out
  set ::out
} {1 2 3 4 5 6 7 8}

#
# Test that if a read client cannot read the wal-index header because a
# write client is in the middle of updating it, the reader blocks until
# the writer finishes.
#
#   1. Open a write transaction using client [db] in this process.
#
#   2. Attempt to commit the write transaction. Intercept the xShmBarrier()
#      call made by the writer between updating the two copies of the
#      wal-index header.
#
#   3. Within the xShmBarrier() callback, make an asynchronous request to
#      the other process to read from the database. It should block, as it
#      cannot get read the wal-index header.
#
#   4. Still in xShmBarrier(), wait for 5 seconds. Check that the other
#      process has not answered the request.
#
#   5: Finish committing the transaction. Then wait for 0.5 seconds more.
#      Ensure that the second process has by this stage read the database
#      and that the snapshot it read included the transaction committed in
#      step (4).
#
do_execsql_test 1.2.1 {
  BEGIN;
    INSERT INTO t1 VALUES(9, 10);
} {}

tvfs script barrier_callback
tvfs filter xShmBarrier
proc barrier_callback {method args} {
  set ::out ""
  testfixture $::C { db eval { SELECT * FROM t1 } } {set ::out}

  do_test "1.2.2.(blocking 5 seconds)" { 
    set ::continue 0
    after 5000 {set ::continue 1}
    vwait ::continue
    set ::out 
  } {}
}

execsql COMMIT

do_test "1.2.3.(blocking 0.5 seconds)" { 
  set ::continue 0
  after 500 {set ::continue 1}
  vwait ::continue
  set ::out 
} {1 2 3 4 5 6 7 8 9 10}


finish_test