multi.tcl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. proc wait_for_dbsize {size} {
  2. set r2 [redis_client]
  3. wait_for_condition 50 100 {
  4. [$r2 dbsize] == $size
  5. } else {
  6. fail "Target dbsize not reached"
  7. }
  8. $r2 close
  9. }
  10. start_server {tags {"multi"}} {
  11. test {MUTLI / EXEC basics} {
  12. r del mylist
  13. r rpush mylist a
  14. r rpush mylist b
  15. r rpush mylist c
  16. r multi
  17. set v1 [r lrange mylist 0 -1]
  18. set v2 [r ping]
  19. set v3 [r exec]
  20. list $v1 $v2 $v3
  21. } {QUEUED QUEUED {{a b c} PONG}}
  22. test {DISCARD} {
  23. r del mylist
  24. r rpush mylist a
  25. r rpush mylist b
  26. r rpush mylist c
  27. r multi
  28. set v1 [r del mylist]
  29. set v2 [r discard]
  30. set v3 [r lrange mylist 0 -1]
  31. list $v1 $v2 $v3
  32. } {QUEUED OK {a b c}}
  33. test {Nested MULTI are not allowed} {
  34. set err {}
  35. r multi
  36. catch {[r multi]} err
  37. r exec
  38. set _ $err
  39. } {*ERR MULTI*}
  40. test {MULTI where commands alter argc/argv} {
  41. r sadd myset a
  42. r multi
  43. r spop myset
  44. list [r exec] [r exists myset]
  45. } {a 0}
  46. test {WATCH inside MULTI is not allowed} {
  47. set err {}
  48. r multi
  49. catch {[r watch x]} err
  50. r exec
  51. set _ $err
  52. } {*ERR WATCH*}
  53. test {EXEC fails if there are errors while queueing commands #1} {
  54. r del foo1{t} foo2{t}
  55. r multi
  56. r set foo1{t} bar1
  57. catch {r non-existing-command}
  58. r set foo2{t} bar2
  59. catch {r exec} e
  60. assert_match {EXECABORT*} $e
  61. list [r exists foo1{t}] [r exists foo2{t}]
  62. } {0 0}
  63. test {If EXEC aborts, the client MULTI state is cleared} {
  64. r del foo1{t} foo2{t}
  65. r multi
  66. r set foo1{t} bar1
  67. catch {r non-existing-command}
  68. r set foo2{t} bar2
  69. catch {r exec} e
  70. assert_match {EXECABORT*} $e
  71. r ping
  72. } {PONG}
  73. test {EXEC works on WATCHed key not modified} {
  74. r watch x{t} y{t} z{t}
  75. r watch k{t}
  76. r multi
  77. r ping
  78. r exec
  79. } {PONG}
  80. test {EXEC fail on WATCHed key modified (1 key of 1 watched)} {
  81. r set x 30
  82. r watch x
  83. r set x 40
  84. r multi
  85. r ping
  86. r exec
  87. } {}
  88. test {EXEC fail on WATCHed key modified (1 key of 5 watched)} {
  89. r set x{t} 30
  90. r watch a{t} b{t} x{t} k{t} z{t}
  91. r set x{t} 40
  92. r multi
  93. r ping
  94. r exec
  95. } {}
  96. test {EXEC fail on lazy expired WATCHed key} {
  97. r flushall
  98. r debug set-active-expire 0
  99. r del key
  100. r set key 1 px 2
  101. r watch key
  102. after 100
  103. r multi
  104. r incr key
  105. assert_equal [r exec] {}
  106. r debug set-active-expire 1
  107. } {OK} {needs:debug}
  108. test {After successful EXEC key is no longer watched} {
  109. r set x 30
  110. r watch x
  111. r multi
  112. r ping
  113. r exec
  114. r set x 40
  115. r multi
  116. r ping
  117. r exec
  118. } {PONG}
  119. test {After failed EXEC key is no longer watched} {
  120. r set x 30
  121. r watch x
  122. r set x 40
  123. r multi
  124. r ping
  125. r exec
  126. r set x 40
  127. r multi
  128. r ping
  129. r exec
  130. } {PONG}
  131. test {It is possible to UNWATCH} {
  132. r set x 30
  133. r watch x
  134. r set x 40
  135. r unwatch
  136. r multi
  137. r ping
  138. r exec
  139. } {PONG}
  140. test {UNWATCH when there is nothing watched works as expected} {
  141. r unwatch
  142. } {OK}
  143. test {FLUSHALL is able to touch the watched keys} {
  144. r set x 30
  145. r watch x
  146. r flushall
  147. r multi
  148. r ping
  149. r exec
  150. } {}
  151. test {FLUSHALL does not touch non affected keys} {
  152. r del x
  153. r watch x
  154. r flushall
  155. r multi
  156. r ping
  157. r exec
  158. } {PONG}
  159. test {FLUSHDB is able to touch the watched keys} {
  160. r set x 30
  161. r watch x
  162. r flushdb
  163. r multi
  164. r ping
  165. r exec
  166. } {}
  167. test {FLUSHDB does not touch non affected keys} {
  168. r del x
  169. r watch x
  170. r flushdb
  171. r multi
  172. r ping
  173. r exec
  174. } {PONG}
  175. test {WATCH is able to remember the DB a key belongs to} {
  176. r select 5
  177. r set x 30
  178. r watch x
  179. r select 1
  180. r set x 10
  181. r select 5
  182. r multi
  183. r ping
  184. set res [r exec]
  185. # Restore original DB
  186. r select 9
  187. set res
  188. } {PONG} {singledb:skip}
  189. test {WATCH will consider touched keys target of EXPIRE} {
  190. r del x
  191. r set x foo
  192. r watch x
  193. r expire x 10
  194. r multi
  195. r ping
  196. r exec
  197. } {}
  198. test {WATCH will consider touched expired keys} {
  199. r flushall
  200. r del x
  201. r set x foo
  202. r expire x 1
  203. r watch x
  204. # Wait for the keys to expire.
  205. wait_for_dbsize 0
  206. r multi
  207. r ping
  208. r exec
  209. } {}
  210. test {DISCARD should clear the WATCH dirty flag on the client} {
  211. r watch x
  212. r set x 10
  213. r multi
  214. r discard
  215. r multi
  216. r incr x
  217. r exec
  218. } {11}
  219. test {DISCARD should UNWATCH all the keys} {
  220. r watch x
  221. r set x 10
  222. r multi
  223. r discard
  224. r set x 10
  225. r multi
  226. r incr x
  227. r exec
  228. } {11}
  229. test {MULTI / EXEC is propagated correctly (single write command)} {
  230. set repl [attach_to_replication_stream]
  231. r multi
  232. r set foo bar
  233. r exec
  234. assert_replication_stream $repl {
  235. {select *}
  236. {multi}
  237. {set foo bar}
  238. {exec}
  239. }
  240. close_replication_stream $repl
  241. } {} {needs:repl}
  242. test {MULTI / EXEC is propagated correctly (empty transaction)} {
  243. set repl [attach_to_replication_stream]
  244. r multi
  245. r exec
  246. r set foo bar
  247. assert_replication_stream $repl {
  248. {select *}
  249. {set foo bar}
  250. }
  251. close_replication_stream $repl
  252. } {} {needs:repl}
  253. test {MULTI / EXEC is propagated correctly (read-only commands)} {
  254. r set foo value1
  255. set repl [attach_to_replication_stream]
  256. r multi
  257. r get foo
  258. r exec
  259. r set foo value2
  260. assert_replication_stream $repl {
  261. {select *}
  262. {set foo value2}
  263. }
  264. close_replication_stream $repl
  265. } {} {needs:repl}
  266. test {MULTI / EXEC is propagated correctly (write command, no effect)} {
  267. r del bar
  268. r del foo
  269. set repl [attach_to_replication_stream]
  270. r multi
  271. r del foo
  272. r exec
  273. # add another command so that when we see it we know multi-exec wasn't
  274. # propagated
  275. r incr foo
  276. assert_replication_stream $repl {
  277. {select *}
  278. {incr foo}
  279. }
  280. close_replication_stream $repl
  281. } {} {needs:repl}
  282. test {DISCARD should not fail during OOM} {
  283. set rd [redis_deferring_client]
  284. $rd config set maxmemory 1
  285. assert {[$rd read] eq {OK}}
  286. r multi
  287. catch {r set x 1} e
  288. assert_match {OOM*} $e
  289. r discard
  290. $rd config set maxmemory 0
  291. assert {[$rd read] eq {OK}}
  292. $rd close
  293. r ping
  294. } {PONG} {needs:config-maxmemory}
  295. test {exec with write commands and state change} {
  296. # check that exec that contains write commands fails if server state changed since they were queued
  297. set r1 [redis_client]
  298. r set xx 1
  299. r multi
  300. r incr xx
  301. $r1 config set min-replicas-to-write 2
  302. catch {r exec} e
  303. assert_match {*EXECABORT*NOREPLICAS*} $e
  304. set xx [r get xx]
  305. # make sure that the INCR wasn't executed
  306. assert { $xx == 1}
  307. $r1 config set min-replicas-to-write 0
  308. $r1 close
  309. } {0} {needs:repl}
  310. test {exec with read commands and stale replica state change} {
  311. # check that exec that contains read commands fails if server state changed since they were queued
  312. r config set replica-serve-stale-data no
  313. set r1 [redis_client]
  314. r set xx 1
  315. # check that GET is disallowed on stale replica, even if the replica becomes stale only after queuing.
  316. r multi
  317. r get xx
  318. $r1 replicaof localhsot 0
  319. catch {r exec} e
  320. assert_match {*EXECABORT*MASTERDOWN*} $e
  321. # check that PING is allowed
  322. r multi
  323. r ping
  324. $r1 replicaof localhsot 0
  325. set pong [r exec]
  326. assert {$pong == "PONG"}
  327. # check that when replica is not stale, GET is allowed
  328. # while we're at it, let's check that multi is allowed on stale replica too
  329. r multi
  330. $r1 replicaof no one
  331. r get xx
  332. set xx [r exec]
  333. # make sure that the INCR was executed
  334. assert { $xx == 1 }
  335. $r1 close
  336. } {0} {needs:repl cluster:skip}
  337. test {EXEC with only read commands should not be rejected when OOM} {
  338. set r2 [redis_client]
  339. r set x value
  340. r multi
  341. r get x
  342. r ping
  343. # enforcing OOM
  344. $r2 config set maxmemory 1
  345. # finish the multi transaction with exec
  346. assert { [r exec] == {value PONG} }
  347. # releasing OOM
  348. $r2 config set maxmemory 0
  349. $r2 close
  350. } {0} {needs:config-maxmemory}
  351. test {EXEC with at least one use-memory command should fail} {
  352. set r2 [redis_client]
  353. r multi
  354. r set x 1
  355. r get x
  356. # enforcing OOM
  357. $r2 config set maxmemory 1
  358. # finish the multi transaction with exec
  359. catch {r exec} e
  360. assert_match {EXECABORT*OOM*} $e
  361. # releasing OOM
  362. $r2 config set maxmemory 0
  363. $r2 close
  364. } {0} {needs:config-maxmemory}
  365. test {MULTI propagation of PUBLISH} {
  366. set repl [attach_to_replication_stream]
  367. # make sure that PUBLISH inside MULTI is propagated in a transaction
  368. r multi
  369. r publish bla bla
  370. r exec
  371. assert_replication_stream $repl {
  372. {select *}
  373. {multi}
  374. {publish bla bla}
  375. {exec}
  376. }
  377. close_replication_stream $repl
  378. } {} {needs:repl cluster:skip}
  379. test {MULTI propagation of SCRIPT LOAD} {
  380. set repl [attach_to_replication_stream]
  381. # make sure that SCRIPT LOAD inside MULTI is propagated in a transaction
  382. r multi
  383. r script load {redis.call('set', KEYS[1], 'foo')}
  384. set res [r exec]
  385. set sha [lindex $res 0]
  386. assert_replication_stream $repl {
  387. {select *}
  388. {multi}
  389. {script load *}
  390. {exec}
  391. }
  392. close_replication_stream $repl
  393. } {} {needs:repl}
  394. test {MULTI propagation of SCRIPT LOAD} {
  395. set repl [attach_to_replication_stream]
  396. # make sure that EVAL inside MULTI is propagated in a transaction
  397. r config set lua-replicate-commands no
  398. r multi
  399. r eval {redis.call('set', KEYS[1], 'bar')} 1 bar
  400. r exec
  401. assert_replication_stream $repl {
  402. {select *}
  403. {multi}
  404. {eval *}
  405. {exec}
  406. }
  407. close_replication_stream $repl
  408. } {} {needs:repl}
  409. tags {"stream"} {
  410. test {MULTI propagation of XREADGROUP} {
  411. # stream is a special case because it calls propagate() directly for XREADGROUP
  412. set repl [attach_to_replication_stream]
  413. r XADD mystream * foo bar
  414. r XGROUP CREATE mystream mygroup 0
  415. # make sure the XCALIM (propagated by XREADGROUP) is indeed inside MULTI/EXEC
  416. r multi
  417. r XREADGROUP GROUP mygroup consumer1 STREAMS mystream ">"
  418. r exec
  419. assert_replication_stream $repl {
  420. {select *}
  421. {xadd *}
  422. {xgroup CREATE *}
  423. {multi}
  424. {xclaim *}
  425. {exec}
  426. }
  427. close_replication_stream $repl
  428. } {} {needs:repl}
  429. }
  430. }