wal3.test 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. # 2010 April 13
  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. # This file implements regression tests for SQLite library. The
  12. # focus of this file is testing the operation of the library in
  13. # "PRAGMA journal_mode=WAL" mode.
  14. #
  15. set testdir [file dirname $argv0]
  16. source $testdir/tester.tcl
  17. source $testdir/lock_common.tcl
  18. source $testdir/wal_common.tcl
  19. source $testdir/malloc_common.tcl
  20. ifcapable !wal {finish_test ; return }
  21. set a_string_counter 1
  22. proc a_string {n} {
  23. global a_string_counter
  24. incr a_string_counter
  25. string range [string repeat "${a_string_counter}." $n] 1 $n
  26. }
  27. db func a_string a_string
  28. #-------------------------------------------------------------------------
  29. # When a rollback or savepoint rollback occurs, the client may remove
  30. # elements from one of the hash tables in the wal-index. This block
  31. # of test cases tests that nothing appears to go wrong when this is
  32. # done.
  33. #
  34. do_test wal3-1.0 {
  35. execsql {
  36. PRAGMA cache_size = 2000;
  37. PRAGMA page_size = 1024;
  38. PRAGMA auto_vacuum = off;
  39. PRAGMA synchronous = normal;
  40. PRAGMA journal_mode = WAL;
  41. PRAGMA wal_autocheckpoint = 0;
  42. BEGIN;
  43. CREATE TABLE t1(x);
  44. INSERT INTO t1 VALUES( a_string(800) ); /* 1 */
  45. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2 */
  46. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 4 */
  47. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 8 */
  48. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 16 */
  49. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 32 */
  50. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 64 */
  51. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 128*/
  52. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 256 */
  53. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 512 */
  54. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 1024 */
  55. INSERT INTO t1 SELECT a_string(800) FROM t1; /* 2048 */
  56. INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 1970; /* 4018 */
  57. COMMIT;
  58. PRAGMA cache_size = 10;
  59. }
  60. wal_frame_count test.db-wal 1024
  61. } 4056
  62. for {set i 1} {$i < 50} {incr i} {
  63. do_test wal3-1.$i.1 {
  64. set str [a_string 800]
  65. execsql { UPDATE t1 SET x = $str WHERE rowid = $i }
  66. lappend L [wal_frame_count test.db-wal 1024]
  67. execsql {
  68. BEGIN;
  69. INSERT INTO t1 SELECT a_string(800) FROM t1 LIMIT 100;
  70. ROLLBACK;
  71. PRAGMA integrity_check;
  72. }
  73. } {ok}
  74. # Check that everything looks OK from the point of view of an
  75. # external connection.
  76. #
  77. sqlite3 db2 test.db
  78. do_test wal3-1.$i.2 {
  79. execsql { SELECT count(*) FROM t1 } db2
  80. } 4018
  81. do_test wal3-1.$i.3 {
  82. execsql { SELECT x FROM t1 WHERE rowid = $i }
  83. } $str
  84. do_test wal3-1.$i.4 {
  85. execsql { PRAGMA integrity_check } db2
  86. } {ok}
  87. db2 close
  88. # Check that the file-system in its current state can be recovered.
  89. #
  90. forcecopy test.db test2.db
  91. forcecopy test.db-wal test2.db-wal
  92. forcedelete test2.db-journal
  93. sqlite3 db2 test2.db
  94. do_test wal3-1.$i.5 {
  95. execsql { SELECT count(*) FROM t1 } db2
  96. } 4018
  97. do_test wal3-1.$i.6 {
  98. execsql { SELECT x FROM t1 WHERE rowid = $i }
  99. } $str
  100. do_test wal3-1.$i.7 {
  101. execsql { PRAGMA integrity_check } db2
  102. } {ok}
  103. db2 close
  104. }
  105. proc byte_is_zero {file offset} {
  106. if {[file size test.db] <= $offset} { return 1 }
  107. expr { [hexio_read $file $offset 1] == "00" }
  108. }
  109. do_multiclient_test i {
  110. set testname(1) multiproc
  111. set testname(2) singleproc
  112. set tn $testname($i)
  113. do_test wal3-2.$tn.1 {
  114. sql1 {
  115. PRAGMA page_size = 1024;
  116. PRAGMA journal_mode = WAL;
  117. }
  118. sql1 {
  119. CREATE TABLE t1(a, b);
  120. INSERT INTO t1 VALUES(1, 'one');
  121. BEGIN;
  122. SELECT * FROM t1;
  123. }
  124. } {1 one}
  125. do_test wal3-2.$tn.2 {
  126. sql2 {
  127. CREATE TABLE t2(a, b);
  128. INSERT INTO t2 VALUES(2, 'two');
  129. BEGIN;
  130. SELECT * FROM t2;
  131. }
  132. } {2 two}
  133. do_test wal3-2.$tn.3 {
  134. sql3 {
  135. CREATE TABLE t3(a, b);
  136. INSERT INTO t3 VALUES(3, 'three');
  137. BEGIN;
  138. SELECT * FROM t3;
  139. }
  140. } {3 three}
  141. # Try to checkpoint the database using [db]. It should be possible to
  142. # checkpoint everything except the table added by [db3] (checkpointing
  143. # these frames would clobber the snapshot currently being used by [db2]).
  144. #
  145. # After [db2] has committed, a checkpoint can copy the entire log to the
  146. # database file. Checkpointing after [db3] has committed is therefore a
  147. # no-op, as the entire log has already been backfilled.
  148. #
  149. do_test wal3-2.$tn.4 {
  150. sql1 {
  151. COMMIT;
  152. PRAGMA wal_checkpoint;
  153. }
  154. byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]
  155. } {1}
  156. do_test wal3-2.$tn.5 {
  157. sql2 {
  158. COMMIT;
  159. PRAGMA wal_checkpoint;
  160. }
  161. list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]] \
  162. [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]]
  163. } {0 1}
  164. do_test wal3-2.$tn.6 {
  165. sql3 {
  166. COMMIT;
  167. PRAGMA wal_checkpoint;
  168. }
  169. list [byte_is_zero test.db [expr $AUTOVACUUM ? 4*1024 : 3*1024]] \
  170. [byte_is_zero test.db [expr $AUTOVACUUM ? 5*1024 : 4*1024]]
  171. } {0 1}
  172. }
  173. catch {db close}
  174. #-------------------------------------------------------------------------
  175. # Test that that for the simple test:
  176. #
  177. # CREATE TABLE x(y);
  178. # INSERT INTO x VALUES('z');
  179. # PRAGMA wal_checkpoint;
  180. #
  181. # in WAL mode the xSync method is invoked as expected for each of
  182. # synchronous=off, synchronous=normal and synchronous=full.
  183. #
  184. foreach {tn syncmode synccount} {
  185. 1 off
  186. {}
  187. 2 normal
  188. {test.db-wal normal test.db normal}
  189. 3 full
  190. {test.db-wal normal test.db-wal normal test.db-wal normal test.db normal}
  191. } {
  192. proc sync_counter {args} {
  193. foreach {method filename id flags} $args break
  194. lappend ::syncs [file tail $filename] $flags
  195. }
  196. do_test wal3-3.$tn {
  197. forcedelete test.db test.db-wal test.db-journal
  198. testvfs T
  199. T filter {}
  200. T script sync_counter
  201. sqlite3 db test.db -vfs T
  202. execsql "PRAGMA synchronous = $syncmode"
  203. execsql { PRAGMA journal_mode = WAL }
  204. execsql { CREATE TABLE filler(a,b,c); }
  205. set ::syncs [list]
  206. T filter xSync
  207. execsql {
  208. CREATE TABLE x(y);
  209. INSERT INTO x VALUES('z');
  210. PRAGMA wal_checkpoint;
  211. }
  212. T filter {}
  213. set ::syncs
  214. } $synccount
  215. db close
  216. T delete
  217. }
  218. #-------------------------------------------------------------------------
  219. # When recovering the contents of a WAL file, a process obtains the WRITER
  220. # lock, then locks all other bytes before commencing recovery. If it fails
  221. # to lock all other bytes (because some other process is holding a read
  222. # lock) it should retry up to 100 times. Then return SQLITE_PROTOCOL to the
  223. # caller. Test this (test case wal3-4.3).
  224. #
  225. # Also test the effect of hitting an SQLITE_BUSY while attempting to obtain
  226. # the WRITER lock (should be the same). Test case wal3-4.4.
  227. #
  228. proc lock_callback {method filename handle lock} {
  229. lappend ::locks $lock
  230. }
  231. do_test wal3-4.1 {
  232. testvfs T
  233. T filter xShmLock
  234. T script lock_callback
  235. set ::locks [list]
  236. sqlite3 db test.db -vfs T
  237. execsql { SELECT * FROM x }
  238. lrange $::locks 0 3
  239. } [list {0 1 lock exclusive} {1 7 lock exclusive} \
  240. {1 7 unlock exclusive} {0 1 unlock exclusive} \
  241. ]
  242. do_test wal3-4.2 {
  243. db close
  244. set ::locks [list]
  245. sqlite3 db test.db -vfs T
  246. execsql { SELECT * FROM x }
  247. lrange $::locks 0 3
  248. } [list {0 1 lock exclusive} {1 7 lock exclusive} \
  249. {1 7 unlock exclusive} {0 1 unlock exclusive} \
  250. ]
  251. proc lock_callback {method filename handle lock} {
  252. if {$lock == "1 7 lock exclusive"} { return SQLITE_BUSY }
  253. return SQLITE_OK
  254. }
  255. puts " Warning: This next test case causes SQLite to call xSleep(1) 100 times."
  256. puts " Normally this equates to a 100ms delay, but if SQLite is built on unix"
  257. puts " without HAVE_USLEEP defined, it may be 100 seconds."
  258. do_test wal3-4.3 {
  259. db close
  260. set ::locks [list]
  261. sqlite3 db test.db -vfs T
  262. catchsql { SELECT * FROM x }
  263. } {1 {locking protocol}}
  264. puts " Warning: Same again!"
  265. proc lock_callback {method filename handle lock} {
  266. if {$lock == "0 1 lock exclusive"} { return SQLITE_BUSY }
  267. return SQLITE_OK
  268. }
  269. do_test wal3-4.4 {
  270. db close
  271. set ::locks [list]
  272. sqlite3 db test.db -vfs T
  273. catchsql { SELECT * FROM x }
  274. } {1 {locking protocol}}
  275. db close
  276. T delete
  277. #-------------------------------------------------------------------------
  278. # Only one client may run recovery at a time. Test this mechanism.
  279. #
  280. # When client-2 tries to open a read transaction while client-1 is
  281. # running recovery, it fails to obtain a lock on an aReadMark[] slot
  282. # (because they are all locked by recovery). It then tries to obtain
  283. # a shared lock on the RECOVER lock to see if there really is a
  284. # recovery running or not.
  285. #
  286. # This block of tests checks the effect of an SQLITE_BUSY or SQLITE_IOERR
  287. # being returned when client-2 attempts a shared lock on the RECOVER byte.
  288. #
  289. # An SQLITE_BUSY should be converted to an SQLITE_BUSY_RECOVERY. An
  290. # SQLITE_IOERR should be returned to the caller.
  291. #
  292. do_test wal3-5.1 {
  293. faultsim_delete_and_reopen
  294. execsql {
  295. PRAGMA journal_mode = WAL;
  296. CREATE TABLE t1(a, b);
  297. INSERT INTO t1 VALUES(1, 2);
  298. INSERT INTO t1 VALUES(3, 4);
  299. }
  300. faultsim_save_and_close
  301. } {}
  302. testvfs T -default 1
  303. T script method_callback
  304. proc method_callback {method args} {
  305. if {$method == "xShmBarrier"} {
  306. incr ::barrier_count
  307. if {$::barrier_count == 2} {
  308. # This code is executed within the xShmBarrier() callback invoked
  309. # by the client running recovery as part of writing the recovered
  310. # wal-index header. If a second client attempts to access the
  311. # database now, it reads a corrupt (partially written) wal-index
  312. # header. But it cannot even get that far, as the first client
  313. # is still holding all the locks (recovery takes an exclusive lock
  314. # on *all* db locks, preventing access by any other client).
  315. #
  316. # If global variable ::wal3_do_lockfailure is non-zero, then set
  317. # things up so that an IO error occurs within an xShmLock() callback
  318. # made by the second client (aka [db2]).
  319. #
  320. sqlite3 db2 test.db
  321. if { $::wal3_do_lockfailure } { T filter xShmLock }
  322. set ::testrc [ catch { db2 eval "SELECT * FROM t1" } ::testmsg ]
  323. T filter {}
  324. db2 close
  325. }
  326. }
  327. if {$method == "xShmLock"} {
  328. foreach {file handle spec} $args break
  329. if { $spec == "2 1 lock shared" } {
  330. return SQLITE_IOERR
  331. }
  332. }
  333. return SQLITE_OK
  334. }
  335. # Test a normal SQLITE_BUSY return.
  336. #
  337. T filter xShmBarrier
  338. set testrc ""
  339. set testmsg ""
  340. set barrier_count 0
  341. set wal3_do_lockfailure 0
  342. do_test wal3-5.2 {
  343. faultsim_restore_and_reopen
  344. execsql { SELECT * FROM t1 }
  345. } {1 2 3 4}
  346. do_test wal3-5.3 {
  347. list $::testrc $::testmsg
  348. } {1 {database is locked}}
  349. db close
  350. # Test an SQLITE_IOERR return.
  351. #
  352. T filter xShmBarrier
  353. set barrier_count 0
  354. set wal3_do_lockfailure 1
  355. set testrc ""
  356. set testmsg ""
  357. do_test wal3-5.4 {
  358. faultsim_restore_and_reopen
  359. execsql { SELECT * FROM t1 }
  360. } {1 2 3 4}
  361. do_test wal3-5.5 {
  362. list $::testrc $::testmsg
  363. } {1 {disk I/O error}}
  364. db close
  365. T delete
  366. #-------------------------------------------------------------------------
  367. # When opening a read-transaction on a database, if the entire log has
  368. # already been copied to the database file, the reader grabs a special
  369. # kind of read lock (on aReadMark[0]). This set of test cases tests the
  370. # outcome of the following:
  371. #
  372. # + The reader discovering that between the time when it determined
  373. # that the log had been completely backfilled and the lock is obtained
  374. # that a writer has written to the log. In this case the reader should
  375. # acquire a different read-lock (not aReadMark[0]) and read the new
  376. # snapshot.
  377. #
  378. # + The attempt to obtain the lock on aReadMark[0] fails with SQLITE_BUSY.
  379. # This can happen if a checkpoint is ongoing. In this case also simply
  380. # obtain a different read-lock.
  381. #
  382. catch {db close}
  383. testvfs T -default 1
  384. do_test wal3-6.1.1 {
  385. forcedelete test.db test.db-journal test.db wal
  386. sqlite3 db test.db
  387. execsql { PRAGMA auto_vacuum = off }
  388. execsql { PRAGMA journal_mode = WAL }
  389. execsql {
  390. CREATE TABLE t1(a, b);
  391. INSERT INTO t1 VALUES('o', 't');
  392. INSERT INTO t1 VALUES('t', 'f');
  393. }
  394. } {}
  395. do_test wal3-6.1.2 {
  396. sqlite3 db2 test.db
  397. sqlite3 db3 test.db
  398. execsql { BEGIN ; SELECT * FROM t1 } db3
  399. } {o t t f}
  400. do_test wal3-6.1.3 {
  401. execsql { PRAGMA wal_checkpoint } db2
  402. } {0 4 4}
  403. # At this point the log file has been fully checkpointed. However,
  404. # connection [db3] holds a lock that prevents the log from being wrapped.
  405. # Test case 3.6.1.4 has [db] attempt a read-lock on aReadMark[0]. But
  406. # as it is obtaining the lock, [db2] appends to the log file.
  407. #
  408. T filter xShmLock
  409. T script lock_callback
  410. proc lock_callback {method file handle spec} {
  411. if {$spec == "3 1 lock shared"} {
  412. # This is the callback for [db] to obtain the read lock on aReadMark[0].
  413. # Disable future callbacks using [T filter {}] and write to the log
  414. # file using [db2]. [db3] is preventing [db2] from wrapping the log
  415. # here, so this is an append.
  416. T filter {}
  417. db2 eval { INSERT INTO t1 VALUES('f', 's') }
  418. }
  419. return SQLITE_OK
  420. }
  421. do_test wal3-6.1.4 {
  422. execsql {
  423. BEGIN;
  424. SELECT * FROM t1;
  425. }
  426. } {o t t f f s}
  427. # [db] should be left holding a read-lock on some slot other than
  428. # aReadMark[0]. Test this by demonstrating that the read-lock is preventing
  429. # the log from being wrapped.
  430. #
  431. do_test wal3-6.1.5 {
  432. db3 eval COMMIT
  433. db2 eval { PRAGMA wal_checkpoint }
  434. set sz1 [file size test.db-wal]
  435. db2 eval { INSERT INTO t1 VALUES('s', 'e') }
  436. set sz2 [file size test.db-wal]
  437. expr {$sz2>$sz1}
  438. } {1}
  439. # Test that if [db2] had not interfered when [db] was trying to grab
  440. # aReadMark[0], it would have been possible to wrap the log in 3.6.1.5.
  441. #
  442. do_test wal3-6.1.6 {
  443. execsql { COMMIT }
  444. execsql { PRAGMA wal_checkpoint } db2
  445. execsql {
  446. BEGIN;
  447. SELECT * FROM t1;
  448. }
  449. } {o t t f f s s e}
  450. do_test wal3-6.1.7 {
  451. db2 eval { PRAGMA wal_checkpoint }
  452. set sz1 [file size test.db-wal]
  453. db2 eval { INSERT INTO t1 VALUES('n', 't') }
  454. set sz2 [file size test.db-wal]
  455. expr {$sz2==$sz1}
  456. } {1}
  457. db3 close
  458. db2 close
  459. db close
  460. do_test wal3-6.2.1 {
  461. forcedelete test.db test.db-journal test.db wal
  462. sqlite3 db test.db
  463. sqlite3 db2 test.db
  464. execsql { PRAGMA auto_vacuum = off }
  465. execsql { PRAGMA journal_mode = WAL }
  466. execsql {
  467. CREATE TABLE t1(a, b);
  468. INSERT INTO t1 VALUES('h', 'h');
  469. INSERT INTO t1 VALUES('l', 'b');
  470. }
  471. } {}
  472. T filter xShmLock
  473. T script lock_callback
  474. proc lock_callback {method file handle spec} {
  475. if {$spec == "3 1 unlock exclusive"} {
  476. T filter {}
  477. set ::R [db2 eval {
  478. BEGIN;
  479. SELECT * FROM t1;
  480. }]
  481. }
  482. }
  483. do_test wal3-6.2.2 {
  484. execsql { PRAGMA wal_checkpoint }
  485. } {0 4 4}
  486. do_test wal3-6.2.3 {
  487. set ::R
  488. } {h h l b}
  489. do_test wal3-6.2.4 {
  490. set sz1 [file size test.db-wal]
  491. execsql { INSERT INTO t1 VALUES('b', 'c'); }
  492. set sz2 [file size test.db-wal]
  493. expr {$sz2 > $sz1}
  494. } {1}
  495. do_test wal3-6.2.5 {
  496. db2 eval { COMMIT }
  497. execsql { PRAGMA wal_checkpoint }
  498. set sz1 [file size test.db-wal]
  499. execsql { INSERT INTO t1 VALUES('n', 'o'); }
  500. set sz2 [file size test.db-wal]
  501. expr {$sz2 == $sz1}
  502. } {1}
  503. db2 close
  504. db close
  505. T delete
  506. #-------------------------------------------------------------------------
  507. # When opening a read-transaction on a database, if the entire log has
  508. # not yet been copied to the database file, the reader grabs a read
  509. # lock on aReadMark[x], where x>0. The following test cases experiment
  510. # with the outcome of the following:
  511. #
  512. # + The reader discovering that between the time when it read the
  513. # wal-index header and the lock was obtained that a writer has
  514. # written to the log. In this case the reader should re-read the
  515. # wal-index header and lock a snapshot corresponding to the new
  516. # header.
  517. #
  518. # + The value in the aReadMark[x] slot has been modified since it was
  519. # read.
  520. #
  521. catch {db close}
  522. testvfs T -default 1
  523. do_test wal3-7.1.1 {
  524. forcedelete test.db test.db-journal test.db wal
  525. sqlite3 db test.db
  526. execsql {
  527. PRAGMA journal_mode = WAL;
  528. CREATE TABLE blue(red PRIMARY KEY, green);
  529. }
  530. } {wal}
  531. T script method_callback
  532. T filter xOpen
  533. proc method_callback {method args} {
  534. if {$method == "xOpen"} { return "reader" }
  535. }
  536. do_test wal3-7.1.2 {
  537. sqlite3 db2 test.db
  538. execsql { SELECT * FROM blue } db2
  539. } {}
  540. T filter xShmLock
  541. set ::locks [list]
  542. proc method_callback {method file handle spec} {
  543. if {$handle != "reader" } { return }
  544. if {$method == "xShmLock"} {
  545. catch { execsql { INSERT INTO blue VALUES(1, 2) } }
  546. catch { execsql { INSERT INTO blue VALUES(3, 4) } }
  547. }
  548. lappend ::locks $spec
  549. }
  550. do_test wal3-7.1.3 {
  551. execsql { SELECT * FROM blue } db2
  552. } {1 2 3 4}
  553. do_test wal3-7.1.4 {
  554. set ::locks
  555. } {{4 1 lock shared} {4 1 unlock shared} {5 1 lock shared} {5 1 unlock shared}}
  556. set ::locks [list]
  557. proc method_callback {method file handle spec} {
  558. if {$handle != "reader" } { return }
  559. if {$method == "xShmLock"} {
  560. catch { execsql { INSERT INTO blue VALUES(5, 6) } }
  561. }
  562. lappend ::locks $spec
  563. }
  564. do_test wal3-7.2.1 {
  565. execsql { SELECT * FROM blue } db2
  566. } {1 2 3 4 5 6}
  567. do_test wal3-7.2.2 {
  568. set ::locks
  569. } {{5 1 lock shared} {5 1 unlock shared} {4 1 lock shared} {4 1 unlock shared}}
  570. db close
  571. db2 close
  572. T delete
  573. #-------------------------------------------------------------------------
  574. #
  575. do_test wal3-8.1 {
  576. forcedelete test.db test.db-journal test.db wal
  577. sqlite3 db test.db
  578. sqlite3 db2 test.db
  579. execsql {
  580. PRAGMA auto_vacuum = off;
  581. PRAGMA journal_mode = WAL;
  582. CREATE TABLE b(c);
  583. INSERT INTO b VALUES('Tehran');
  584. INSERT INTO b VALUES('Qom');
  585. INSERT INTO b VALUES('Markazi');
  586. PRAGMA wal_checkpoint;
  587. }
  588. } {wal 0 5 5}
  589. do_test wal3-8.2 {
  590. execsql { SELECT * FROM b }
  591. } {Tehran Qom Markazi}
  592. do_test wal3-8.3 {
  593. db eval { SELECT * FROM b } {
  594. db eval { INSERT INTO b VALUES('Qazvin') }
  595. set r [db2 eval { SELECT * FROM b }]
  596. break
  597. }
  598. set r
  599. } {Tehran Qom Markazi Qazvin}
  600. do_test wal3-8.4 {
  601. execsql {
  602. INSERT INTO b VALUES('Gilan');
  603. INSERT INTO b VALUES('Ardabil');
  604. }
  605. } {}
  606. db2 close
  607. faultsim_save_and_close
  608. testvfs T -default 1
  609. faultsim_restore_and_reopen
  610. T filter xShmLock
  611. T script lock_callback
  612. proc lock_callback {method file handle spec} {
  613. if {$spec == "1 7 unlock exclusive"} {
  614. T filter {}
  615. set ::r [catchsql { SELECT * FROM b } db2]
  616. }
  617. }
  618. sqlite3 db test.db
  619. sqlite3 db2 test.db
  620. do_test wal3-8.5 {
  621. execsql { SELECT * FROM b }
  622. } {Tehran Qom Markazi Qazvin Gilan Ardabil}
  623. do_test wal3-8.6 {
  624. set ::r
  625. } {1 {locking protocol}}
  626. db close
  627. db2 close
  628. faultsim_restore_and_reopen
  629. sqlite3 db2 test.db
  630. T filter xShmLock
  631. T script lock_callback
  632. proc lock_callback {method file handle spec} {
  633. if {$spec == "1 7 unlock exclusive"} {
  634. T filter {}
  635. set ::r [catchsql { SELECT * FROM b } db2]
  636. }
  637. }
  638. unset ::r
  639. do_test wal3-8.5 {
  640. execsql { SELECT * FROM b }
  641. } {Tehran Qom Markazi Qazvin Gilan Ardabil}
  642. do_test wal3-8.6 {
  643. set ::r
  644. } {1 {locking protocol}}
  645. db close
  646. db2 close
  647. T delete
  648. #-------------------------------------------------------------------------
  649. # When a connection opens a read-lock on the database, it searches for
  650. # an aReadMark[] slot that is already set to the mxFrame value for the
  651. # new transaction. If it cannot find one, it attempts to obtain an
  652. # exclusive lock on an aReadMark[] slot for the purposes of modifying
  653. # the value, then drops back to a shared-lock for the duration of the
  654. # transaction.
  655. #
  656. # This test case verifies that if an exclusive lock cannot be obtained
  657. # on any aReadMark[] slot (because there are already several readers),
  658. # the client takes a shared-lock on a slot without modifying the value
  659. # and continues.
  660. #
  661. set nConn 50
  662. if { [string match *BSD $tcl_platform(os)] } { set nConn 25 }
  663. do_test wal3-9.0 {
  664. forcedelete test.db test.db-journal test.db wal
  665. sqlite3 db test.db
  666. execsql {
  667. PRAGMA page_size = 1024;
  668. PRAGMA journal_mode = WAL;
  669. CREATE TABLE whoami(x);
  670. INSERT INTO whoami VALUES('nobody');
  671. }
  672. } {wal}
  673. for {set i 0} {$i < $nConn} {incr i} {
  674. set c db$i
  675. do_test wal3-9.1.$i {
  676. sqlite3 $c test.db
  677. execsql { UPDATE whoami SET x = $c }
  678. execsql {
  679. BEGIN;
  680. SELECT * FROM whoami
  681. } $c
  682. } $c
  683. }
  684. for {set i 0} {$i < $nConn} {incr i} {
  685. set c db$i
  686. do_test wal3-9.2.$i {
  687. execsql { SELECT * FROM whoami } $c
  688. } $c
  689. }
  690. set sz [expr 1024 * (2+$AUTOVACUUM)]
  691. do_test wal3-9.3 {
  692. for {set i 0} {$i < ($nConn-1)} {incr i} { db$i close }
  693. execsql { PRAGMA wal_checkpoint }
  694. byte_is_zero test.db [expr $sz-1024]
  695. } {1}
  696. do_test wal3-9.4 {
  697. db[expr $nConn-1] close
  698. execsql { PRAGMA wal_checkpoint }
  699. set sz2 [file size test.db]
  700. byte_is_zero test.db [expr $sz-1024]
  701. } {0}
  702. do_multiclient_test tn {
  703. do_test wal3-10.$tn.1 {
  704. sql1 {
  705. PRAGMA page_size = 1024;
  706. CREATE TABLE t1(x);
  707. PRAGMA journal_mode = WAL;
  708. PRAGMA wal_autocheckpoint = 100000;
  709. BEGIN;
  710. INSERT INTO t1 VALUES(randomblob(800));
  711. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2
  712. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4
  713. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8
  714. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 16
  715. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 32
  716. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 64
  717. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 128
  718. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 256
  719. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 512
  720. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 1024
  721. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 2048
  722. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 4096
  723. INSERT INTO t1 SELECT randomblob(800) FROM t1; -- 8192
  724. COMMIT;
  725. CREATE INDEX i1 ON t1(x);
  726. }
  727. expr {[file size test.db-wal] > [expr 1032*9000]}
  728. } 1
  729. do_test wal3-10.$tn.2 {
  730. sql2 {PRAGMA integrity_check}
  731. } {ok}
  732. }
  733. finish_test