multi.tcl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. start_server {tags {"multi"}} {
  2. test {MUTLI / EXEC basics} {
  3. r del mylist
  4. r rpush mylist a
  5. r rpush mylist b
  6. r rpush mylist c
  7. r multi
  8. set v1 [r lrange mylist 0 -1]
  9. set v2 [r ping]
  10. set v3 [r exec]
  11. list $v1 $v2 $v3
  12. } {QUEUED QUEUED {{a b c} PONG}}
  13. test {DISCARD} {
  14. r del mylist
  15. r rpush mylist a
  16. r rpush mylist b
  17. r rpush mylist c
  18. r multi
  19. set v1 [r del mylist]
  20. set v2 [r discard]
  21. set v3 [r lrange mylist 0 -1]
  22. list $v1 $v2 $v3
  23. } {QUEUED OK {a b c}}
  24. test {Nested MULTI are not allowed} {
  25. set err {}
  26. r multi
  27. catch {[r multi]} err
  28. r exec
  29. set _ $err
  30. } {*ERR MULTI*}
  31. test {MULTI where commands alter argc/argv} {
  32. r sadd myset a
  33. r multi
  34. r spop myset
  35. list [r exec] [r exists myset]
  36. } {a 0}
  37. test {WATCH inside MULTI is not allowed} {
  38. set err {}
  39. r multi
  40. catch {[r watch x]} err
  41. r exec
  42. set _ $err
  43. } {*ERR WATCH*}
  44. test {EXEC fails if there are errors while queueing commands #1} {
  45. r del foo1 foo2
  46. r multi
  47. r set foo1 bar1
  48. catch {r non-existing-command}
  49. r set foo2 bar2
  50. catch {r exec} e
  51. assert_match {EXECABORT*} $e
  52. list [r exists foo1] [r exists foo2]
  53. } {0 0}
  54. test {EXEC fails if there are errors while queueing commands #2} {
  55. set rd [redis_deferring_client]
  56. r del foo1 foo2
  57. r multi
  58. r set foo1 bar1
  59. $rd config set maxmemory 1
  60. assert {[$rd read] eq {OK}}
  61. catch {r lpush mylist myvalue}
  62. $rd config set maxmemory 0
  63. assert {[$rd read] eq {OK}}
  64. r set foo2 bar2
  65. catch {r exec} e
  66. assert_match {EXECABORT*} $e
  67. $rd close
  68. list [r exists foo1] [r exists foo2]
  69. } {0 0}
  70. test {If EXEC aborts, the client MULTI state is cleared} {
  71. r del foo1 foo2
  72. r multi
  73. r set foo1 bar1
  74. catch {r non-existing-command}
  75. r set foo2 bar2
  76. catch {r exec} e
  77. assert_match {EXECABORT*} $e
  78. r ping
  79. } {PONG}
  80. test {EXEC works on WATCHed key not modified} {
  81. r watch x y z
  82. r watch k
  83. r multi
  84. r ping
  85. r exec
  86. } {PONG}
  87. test {EXEC fail on WATCHed key modified (1 key of 1 watched)} {
  88. r set x 30
  89. r watch x
  90. r set x 40
  91. r multi
  92. r ping
  93. r exec
  94. } {}
  95. test {EXEC fail on WATCHed key modified (1 key of 5 watched)} {
  96. r set x 30
  97. r watch a b x k z
  98. r set x 40
  99. r multi
  100. r ping
  101. r exec
  102. } {}
  103. test {EXEC fail on WATCHed key modified by SORT with STORE even if the result is empty} {
  104. r flushdb
  105. r lpush foo bar
  106. r watch foo
  107. r sort emptylist store foo
  108. r multi
  109. r ping
  110. r exec
  111. } {}
  112. test {After successful EXEC key is no longer watched} {
  113. r set x 30
  114. r watch x
  115. r multi
  116. r ping
  117. r exec
  118. r set x 40
  119. r multi
  120. r ping
  121. r exec
  122. } {PONG}
  123. test {After failed EXEC key is no longer watched} {
  124. r set x 30
  125. r watch x
  126. r set x 40
  127. r multi
  128. r ping
  129. r exec
  130. r set x 40
  131. r multi
  132. r ping
  133. r exec
  134. } {PONG}
  135. test {It is possible to UNWATCH} {
  136. r set x 30
  137. r watch x
  138. r set x 40
  139. r unwatch
  140. r multi
  141. r ping
  142. r exec
  143. } {PONG}
  144. test {UNWATCH when there is nothing watched works as expected} {
  145. r unwatch
  146. } {OK}
  147. test {FLUSHALL is able to touch the watched keys} {
  148. r set x 30
  149. r watch x
  150. r flushall
  151. r multi
  152. r ping
  153. r exec
  154. } {}
  155. test {FLUSHALL does not touch non affected keys} {
  156. r del x
  157. r watch x
  158. r flushall
  159. r multi
  160. r ping
  161. r exec
  162. } {PONG}
  163. test {FLUSHDB is able to touch the watched keys} {
  164. r set x 30
  165. r watch x
  166. r flushdb
  167. r multi
  168. r ping
  169. r exec
  170. } {}
  171. test {FLUSHDB does not touch non affected keys} {
  172. r del x
  173. r watch x
  174. r flushdb
  175. r multi
  176. r ping
  177. r exec
  178. } {PONG}
  179. test {WATCH is able to remember the DB a key belongs to} {
  180. r select 5
  181. r set x 30
  182. r watch x
  183. r select 1
  184. r set x 10
  185. r select 5
  186. r multi
  187. r ping
  188. set res [r exec]
  189. # Restore original DB
  190. r select 9
  191. set res
  192. } {PONG}
  193. test {WATCH will consider touched keys target of EXPIRE} {
  194. r del x
  195. r set x foo
  196. r watch x
  197. r expire x 10
  198. r multi
  199. r ping
  200. r exec
  201. } {}
  202. test {WATCH will not consider touched expired keys} {
  203. r del x
  204. r set x foo
  205. r expire x 1
  206. r watch x
  207. after 1100
  208. r multi
  209. r ping
  210. r exec
  211. } {PONG}
  212. test {DISCARD should clear the WATCH dirty flag on the client} {
  213. r watch x
  214. r set x 10
  215. r multi
  216. r discard
  217. r multi
  218. r incr x
  219. r exec
  220. } {11}
  221. test {DISCARD should UNWATCH all the keys} {
  222. r watch x
  223. r set x 10
  224. r multi
  225. r discard
  226. r set x 10
  227. r multi
  228. r incr x
  229. r exec
  230. } {11}
  231. test {MULTI / EXEC is propagated correctly (single write command)} {
  232. set repl [attach_to_replication_stream]
  233. r multi
  234. r set foo bar
  235. r exec
  236. assert_replication_stream $repl {
  237. {select *}
  238. {multi}
  239. {set foo bar}
  240. {exec}
  241. }
  242. close_replication_stream $repl
  243. }
  244. test {MULTI / EXEC is propagated correctly (empty transaction)} {
  245. set repl [attach_to_replication_stream]
  246. r multi
  247. r exec
  248. r set foo bar
  249. assert_replication_stream $repl {
  250. {select *}
  251. {set foo bar}
  252. }
  253. close_replication_stream $repl
  254. }
  255. test {MULTI / EXEC is propagated correctly (read-only commands)} {
  256. r set foo value1
  257. set repl [attach_to_replication_stream]
  258. r multi
  259. r get foo
  260. r exec
  261. r set foo value2
  262. assert_replication_stream $repl {
  263. {select *}
  264. {set foo value2}
  265. }
  266. close_replication_stream $repl
  267. }
  268. test {MULTI / EXEC is propagated correctly (write command, no effect)} {
  269. r del bar foo bar
  270. set repl [attach_to_replication_stream]
  271. r multi
  272. r del foo
  273. r exec
  274. assert_replication_stream $repl {
  275. {select *}
  276. {multi}
  277. {exec}
  278. }
  279. close_replication_stream $repl
  280. }
  281. test {DISCARD should not fail during OOM} {
  282. set rd [redis_deferring_client]
  283. $rd config set maxmemory 1
  284. assert {[$rd read] eq {OK}}
  285. r multi
  286. catch {r set x 1} e
  287. assert_match {OOM*} $e
  288. r discard
  289. $rd config set maxmemory 0
  290. assert {[$rd read] eq {OK}}
  291. $rd close
  292. r ping
  293. } {PONG}
  294. test {MULTI and script timeout} {
  295. # check that if MULTI arrives during timeout, it is either refused, or
  296. # allowed to pass, and we don't end up executing half of the transaction
  297. set rd1 [redis_deferring_client]
  298. set rd2 [redis_deferring_client]
  299. r config set lua-time-limit 10
  300. r set xx 1
  301. $rd1 eval {while true do end} 0
  302. after 200
  303. catch { $rd2 multi; $rd2 read } e
  304. catch { $rd2 incr xx; $rd2 read } e
  305. r script kill
  306. after 200 ; # Give some time to Lua to call the hook again...
  307. catch { $rd2 incr xx; $rd2 read } e
  308. catch { $rd2 exec; $rd2 read } e
  309. set xx [r get xx]
  310. # make sure that either the whole transcation passed or none of it (we actually expect none)
  311. assert { $xx == 1 || $xx == 3}
  312. # check that the connection is no longer in multi state
  313. $rd2 ping asdf
  314. set pong [$rd2 read]
  315. assert_equal $pong "asdf"
  316. }
  317. test {EXEC and script timeout} {
  318. # check that if EXEC arrives during timeout, we don't end up executing
  319. # half of the transaction, and also that we exit the multi state
  320. set rd1 [redis_deferring_client]
  321. set rd2 [redis_deferring_client]
  322. r config set lua-time-limit 10
  323. r set xx 1
  324. catch { $rd2 multi; $rd2 read } e
  325. catch { $rd2 incr xx; $rd2 read } e
  326. $rd1 eval {while true do end} 0
  327. after 200
  328. catch { $rd2 incr xx; $rd2 read } e
  329. catch { $rd2 exec; $rd2 read } e
  330. r script kill
  331. after 200 ; # Give some time to Lua to call the hook again...
  332. set xx [r get xx]
  333. # make sure that either the whole transcation passed or none of it (we actually expect none)
  334. assert { $xx == 1 || $xx == 3}
  335. # check that the connection is no longer in multi state
  336. $rd2 ping asdf
  337. set pong [$rd2 read]
  338. assert_equal $pong "asdf"
  339. }
  340. test {MULTI-EXEC body and script timeout} {
  341. # check that we don't run an imcomplete transaction due to some commands
  342. # arriving during busy script
  343. set rd1 [redis_deferring_client]
  344. set rd2 [redis_deferring_client]
  345. r config set lua-time-limit 10
  346. r set xx 1
  347. catch { $rd2 multi; $rd2 read } e
  348. catch { $rd2 incr xx; $rd2 read } e
  349. $rd1 eval {while true do end} 0
  350. after 200
  351. catch { $rd2 incr xx; $rd2 read } e
  352. r script kill
  353. after 200 ; # Give some time to Lua to call the hook again...
  354. catch { $rd2 exec; $rd2 read } e
  355. set xx [r get xx]
  356. # make sure that either the whole transcation passed or none of it (we actually expect none)
  357. assert { $xx == 1 || $xx == 3}
  358. # check that the connection is no longer in multi state
  359. $rd2 ping asdf
  360. set pong [$rd2 read]
  361. assert_equal $pong "asdf"
  362. }
  363. }