1# 2018 December 6
2#
3# The author disclaims copyright to this source code.  In place of
4# a legal notice, here is a blessing:
5#
6#    May you do good and not evil.
7#    May you find forgiveness for yourself and forgive others.
8#    May you share freely, never taking more than you give.
9#
10#***********************************************************************
11#
12
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15
16set testprefix shmlock
17
18ifcapable !wal {finish_test ; return }
19
20sqlite3 db2 test.db
21sqlite3 db3 test.db
22
23do_execsql_test 1.0 {
24  PRAGMA journal_mode = wal;
25  CREATE TABLE t1(a, b);
26  INSERT INTO t1 VALUES(1, 2);
27} {wal}
28do_test 1.1 { execsql { SELECT * FROM t1 } db2 } {1 2}
29do_test 1.2 { execsql { SELECT * FROM t1 } db3 } {1 2}
30
31foreach {tn dbhandle cmd res} {
32  1    db  {shared    lock   7 1}    OK
33  2    db2 {exclusive lock   7 1}    BUSY
34  3    db  {shared    unlock 7 1}    OK
35  4    db2 {exclusive lock   7 1}    OK
36  5    db  {shared    lock   7 1}    BUSY
37  6    db  {exclusive lock   7 1}    BUSY
38  7    db2 {exclusive unlock 7 1}    OK
39
40  8    db  {exclusive lock   0 8}    OK
41  9    db  {exclusive unlock 0 8}    OK
42  10   db2 {exclusive lock   0 8}    OK
43  11   db2 {exclusive unlock 0 8}    OK
44
45  12   db  {shared    lock   0 1}    OK
46  13   db2 {shared    lock   0 1}    OK
47  14   db3 {shared    lock   0 1}    OK
48  15   db3 {shared    unlock 0 1}    OK
49  16   db3 {exclusive lock   0 1}    BUSY
50  17   db2 {shared    unlock 0 1}    OK
51  18   db3 {exclusive lock   0 1}    BUSY
52  19   db  {shared    unlock 0 1}    OK
53  20   db3 {exclusive lock   0 1}    OK
54  21   db3 {exclusive unlock 0 1}    OK
55
56  22   db  {shared    lock   3 1}    OK
57  23   db2 {exclusive lock   2 2}    BUSY
58  24   db  {shared    lock   2 1}    OK
59  25   db2 {exclusive lock   0 5}    BUSY
60  26   db2 {exclusive lock   0 4}    BUSY
61  27   db2 {exclusive lock   0 3}    BUSY
62  28   db  {shared    unlock 3 1}    OK
63  29   db2 {exclusive lock   2 2}    BUSY
64  28   db  {shared    unlock 2 1}    OK
65  29   db2 {exclusive lock   2 2}    OK
66  29   db2 {exclusive unlock 2 2}    OK
67} {
68  do_test 1.3.$tn [list vfs_shmlock $dbhandle main {*}$cmd] "SQLITE_$res"
69}
70
71db  close
72db2 close
73db3 close
74
75if {[permutation]=="unix-excl"} {
76  do_test 2.0 {
77    for {set i 0} {$i < 256} {incr i} {
78      sqlite3 db$i test.db
79      execsql { SELECT * FROM t1 } db$i
80    }
81    for {set i 0} {$i < 255} {incr i} {
82      set rc [vfs_shmlock db$i main shared lock 4 1]
83      if {$rc != "SQLITE_OK"} { error $rc }
84    }
85
86    vfs_shmlock db255 main shared lock 4 1
87  } {SQLITE_BUSY}
88
89  do_test 2.1 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
90  do_test 2.2 { vfs_shmlock db0   main shared    unlock 4 1 } SQLITE_OK
91  do_test 2.3 { vfs_shmlock db255 main shared    lock   4 1 } SQLITE_OK
92  do_test 2.4 { vfs_shmlock db255 main shared    unlock 4 1 } SQLITE_OK
93  do_test 2.5 { vfs_shmlock db255 main exclusive lock   4 1 } SQLITE_BUSY
94
95  do_test 2.6 {
96    for {set i 1} {$i < 255} {incr i} {
97      set rc [vfs_shmlock db255 main exclusive lock 4 1]
98      if {$rc != "SQLITE_BUSY"} { error $rc }
99      set rc [vfs_shmlock db$i main shared unlock 4 1]
100      if {$rc != "SQLITE_OK"} { error $rc }
101    }
102
103    vfs_shmlock db255 main exclusive lock 4 1
104  } {SQLITE_OK}
105
106  vfs_shmlock db255 main exclusive unlock 4 1
107
108  for {set i 0} {$i < 256} {incr i} {
109    db$i close
110  }
111}
112
113sqlite3 db0 test.db
114sqlite3 db1 test.db
115do_test 3.1 { execsql { SELECT * FROM t1 } db0 } {1 2}
116do_test 3.2 { execsql { SELECT * FROM t1 } db1 } {1 2}
117if {$tcl_platform(platform)=="windows"} {
118  set isWindows 1
119} else {
120  set isWindows 0
121}
122
123set L(0) {n n n n n n n n}
124set L(1) {n n n n n n n n}
125proc random_lock_test {idx} {
126  global L
127  set iSlot [expr int(rand()*8)]
128  if {[expr int(rand()*2)]} {
129    # Unlock operation
130    if {[lindex $L($idx) $iSlot]!="n"} {
131      vfs_shmlock db$idx main [lindex $L($idx) $iSlot] unlock $iSlot 1
132      lset L($idx) $iSlot n
133    }
134  } else {
135    # Lock operation
136    if {[lindex $L($idx) $iSlot]=="n"} {
137      set locktype [lindex {e s} [expr int(rand()*2)]]
138      set n 1
139      if {$locktype=="e"} {
140        for {set l $iSlot} {$l<8 && [lindex $L($idx) $l]=="n"} {incr l} {}
141        set n [expr int(rand()*($l-$iSlot))+1]
142        # The LockFile() and UnlockFile() apis on windows require that
143        # every unlock correspond exactly to a prior lock.  Hence, we cannot
144        # lock arbitrary ranges in this test on windows.
145        if {$::isWindows} {set n 1}
146        # puts "iSlot=$iSlot l=$l L=$L($idx)"
147        # puts "$iSlot $n"
148      }
149      set res [vfs_shmlock db$idx main $locktype lock $iSlot $n]
150
151      set bBusy 0
152      for {set i $iSlot} {$i<($iSlot+$n)} {incr i} {
153        set other [lindex $L([expr ($idx+1)%2]) $i]
154        if {($other!="n" && $locktype=="e")||($other=="e" && $locktype=="s")} {
155          if {$res != "SQLITE_BUSY"} { error "BUSY not detected" }
156          set bBusy 1
157          break
158        }
159      }
160
161      if {$bBusy==0} {
162        if {$res != "SQLITE_OK"} { error "BUSY false-positive" }
163        for {set i $iSlot} {$i<($iSlot+$n)} {incr i} {
164          lset L($idx) $i $locktype
165        }
166      }
167    }
168  }
169}
170
171set nStep 100000
172for {set i 0} {$i < $nStep} {incr i} {
173  random_lock_test 0
174  random_lock_test 1
175}
176
177db0 close
178db1 close
179
180finish_test
181