summaryrefslogtreecommitdiff
path: root/test/sql/bdb_exclusive.test
blob: c5b092e9cf825172a308e4e3e54d5ac4f209129c (plain)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#
#    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 regression tests for exclusive transactions.  In
# BDB exclusive transactions do not block the entire database, but force
# non-exclusive transactions to abort if there is ever deadlock.  If two
# exclusive transactions are created at the same time then one will block
# the other until it completes.
#

set testdir [file dirname $argv0]/../../lang/sql/sqlite/test

source $testdir/../../../../test/sql/bdb_util.tcl
if {[run_thread_tests]==0} { finish_test ; return }

sqlite3 db test.db -fullmutex 1

do_test bdb_exclusive.1.0 {
   db eval { 
   CREATE TABLE t1(a);
   CREATE TABLE t2(a);
  }
} {}

do_test bdb_exclusive.1.1 {
   db eval {
   BEGIN EXCLUSIVE;
   ROLLBACK;
   select * from t1;
  }
} {} 

# Create deadlock between an exclusive and non-exclusive 
# transactions
set exclusive_test2 {
  set key ""
  if {[sqlite -has-codec]} {
    set key "xyzzy"
  }
  set ::DB [sqlthread open test.db $key]
  set rc [
    for {set i 0} {$i < 100} {incr i} {
      do_test e1.$i {
        execsql { BEGIN EXCLUSIVE }
      } {SQLITE_OK}
      do_test e2.$i {
        execsql { INSERT INTO t2 VALUES(2) }
      } {SQLITE_OK}
      do_test e3.$i {
        execsql { INSERT INTO t1 VALUES(2) } 
      } {SQLITE_OK}
      do_test e4.$i {
        execsql { COMMIT } 
      } {SQLITE_OK}
    } 
  ]
  sqlite3_close $::DB
  set rc
}

set nonexclusive_test2 {
  set key ""
  if {[sqlite -has-codec]} {
    set key "xyzzy"
  }
  set ::DB [sqlthread open test.db $key]
  set rc [
    for {set i 0} {$i < 100} {incr i} {
      do_test n1.$i {
        execsql { BEGIN } 
      } {SQLITE_OK}
      do_test n2.$i {
        set res [ execsql {INSERT INTO t1 VALUES(2) } ] 
        if {$res eq "SQLITE_LOCKED" || $res eq "SQLITE_BUSY"} {
          execsql { ROLLBACK } 
          execsql { BEGIN }
          set res SQLITE_OK
        }
        set res
      } {SQLITE_OK}
      do_test n3.$i {
        set res [ execsql {INSERT INTO t2 VALUES(2) } ] 
        if {$res eq "SQLITE_LOCKED" || $res eq "SQLITE_BUSY"} {
          execsql { ROLLBACK } 
          execsql { BEGIN }
          set res SQLITE_OK
        }
        set res
      } {SQLITE_OK}
      do_test n4.$i {
        execsql { ROLLBACK } 
      } {SQLITE_OK}
    }
  ]
  sqlite3_close $::DB
  set rc
}

# Check that deadlock cannot occur between two exclusive
# transactions
set exclusive1_test3 {
  set key ""
  if {[sqlite -has-codec]} {
    set key "xyzzy"
  }
  set ::DB [sqlthread open test.db $key]
  set rc [
    for {set i 0} {$i < 100} {incr i} {
      do_test 1e1.$i {
        execsql { BEGIN EXCLUSIVE }
      } {SQLITE_OK}
      do_test 1e2.$i {
        execsql { INSERT INTO t2 VALUES(2) }
      } {SQLITE_OK}
      do_test 1e3.$i {
        execsql { INSERT INTO t1 VALUES(2) } 
      } {SQLITE_OK}
      do_test 1e4.$i {
        execsql { COMMIT } 
      } {SQLITE_OK}
    } 
  ]
  sqlite3_close $::DB
  set rc
}

set exclusive2_test3 {
  set key ""
  if {[sqlite -has-codec]} {
    set key "xyzzy"
  }
  set ::DB [sqlthread open test.db $key]
  set rc [
    for {set i 0} {$i < 100} {incr i} {
      do_test 2e1.$i {
        execsql { BEGIN EXCLUSIVE }
      } {SQLITE_OK}
      do_test 2e2.$i {
        execsql { INSERT INTO t1 VALUES(2) }
      } {SQLITE_OK}
      do_test 2e3.$i {
        execsql { INSERT INTO t2 VALUES(2) } 
      } {SQLITE_OK}
      do_test 2e4.$i {
        execsql { COMMIT } 
      } {SQLITE_OK}
    } 
  ]
  sqlite3_close $::DB
  set rc
}
  
# Start the exclusive and non-exclusive threads
#
array unset finished
thread_spawn finished(0) "" $bdb_thread_procs $exclusive_test2
thread_spawn finished(1) "" $bdb_thread_procs $nonexclusive_test2
  
for {set i 0} {$i < 2} {incr i} {
  if {![info exists finished($i)]} {
    vwait finished($i)
  }
  do_test exclusive_nonexclusive.2.$i {
    set ::finished($i)
  } {}
}

# Start the two exclusive threads
#
array unset finished
thread_spawn finished(0) "" $bdb_thread_procs $exclusive1_test3
thread_spawn finished(1) "" $bdb_thread_procs $exclusive2_test3
  
for {set i 0} {$i < 2} {incr i} {
  if {![info exists finished($i)]} {
    vwait finished($i)
  }
  do_test exclusive_exclusive.3.$i {
    set ::finished($i)
  } {}
}

db close

finish_test