hash.tcl 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. start_server {tags {"hash"}} {
  2. test {HSET/HLEN - Small hash creation} {
  3. array set smallhash {}
  4. for {set i 0} {$i < 8} {incr i} {
  5. set key __avoid_collisions__[randstring 0 8 alpha]
  6. set val __avoid_collisions__[randstring 0 8 alpha]
  7. if {[info exists smallhash($key)]} {
  8. incr i -1
  9. continue
  10. }
  11. r hset smallhash $key $val
  12. set smallhash($key) $val
  13. }
  14. list [r hlen smallhash]
  15. } {8}
  16. test {Is the small hash encoded with a ziplist?} {
  17. assert_encoding ziplist smallhash
  18. }
  19. test {HSET/HLEN - Big hash creation} {
  20. array set bighash {}
  21. for {set i 0} {$i < 1024} {incr i} {
  22. set key __avoid_collisions__[randstring 0 8 alpha]
  23. set val __avoid_collisions__[randstring 0 8 alpha]
  24. if {[info exists bighash($key)]} {
  25. incr i -1
  26. continue
  27. }
  28. r hset bighash $key $val
  29. set bighash($key) $val
  30. }
  31. list [r hlen bighash]
  32. } {1024}
  33. test {Is the big hash encoded with an hash table?} {
  34. assert_encoding hashtable bighash
  35. }
  36. test {HGET against the small hash} {
  37. set err {}
  38. foreach k [array names smallhash *] {
  39. if {$smallhash($k) ne [r hget smallhash $k]} {
  40. set err "$smallhash($k) != [r hget smallhash $k]"
  41. break
  42. }
  43. }
  44. set _ $err
  45. } {}
  46. test {HGET against the big hash} {
  47. set err {}
  48. foreach k [array names bighash *] {
  49. if {$bighash($k) ne [r hget bighash $k]} {
  50. set err "$bighash($k) != [r hget bighash $k]"
  51. break
  52. }
  53. }
  54. set _ $err
  55. } {}
  56. test {HGET against non existing key} {
  57. set rv {}
  58. lappend rv [r hget smallhash __123123123__]
  59. lappend rv [r hget bighash __123123123__]
  60. set _ $rv
  61. } {{} {}}
  62. test {HSET in update and insert mode} {
  63. set rv {}
  64. set k [lindex [array names smallhash *] 0]
  65. lappend rv [r hset smallhash $k newval1]
  66. set smallhash($k) newval1
  67. lappend rv [r hget smallhash $k]
  68. lappend rv [r hset smallhash __foobar123__ newval]
  69. set k [lindex [array names bighash *] 0]
  70. lappend rv [r hset bighash $k newval2]
  71. set bighash($k) newval2
  72. lappend rv [r hget bighash $k]
  73. lappend rv [r hset bighash __foobar123__ newval]
  74. lappend rv [r hdel smallhash __foobar123__]
  75. lappend rv [r hdel bighash __foobar123__]
  76. set _ $rv
  77. } {0 newval1 1 0 newval2 1 1 1}
  78. test {HSETNX target key missing - small hash} {
  79. r hsetnx smallhash __123123123__ foo
  80. r hget smallhash __123123123__
  81. } {foo}
  82. test {HSETNX target key exists - small hash} {
  83. r hsetnx smallhash __123123123__ bar
  84. set result [r hget smallhash __123123123__]
  85. r hdel smallhash __123123123__
  86. set _ $result
  87. } {foo}
  88. test {HSETNX target key missing - big hash} {
  89. r hsetnx bighash __123123123__ foo
  90. r hget bighash __123123123__
  91. } {foo}
  92. test {HSETNX target key exists - big hash} {
  93. r hsetnx bighash __123123123__ bar
  94. set result [r hget bighash __123123123__]
  95. r hdel bighash __123123123__
  96. set _ $result
  97. } {foo}
  98. test {HMSET wrong number of args} {
  99. catch {r hmset smallhash key1 val1 key2} err
  100. format $err
  101. } {*wrong number*}
  102. test {HMSET - small hash} {
  103. set args {}
  104. foreach {k v} [array get smallhash] {
  105. set newval [randstring 0 8 alpha]
  106. set smallhash($k) $newval
  107. lappend args $k $newval
  108. }
  109. r hmset smallhash {*}$args
  110. } {OK}
  111. test {HMSET - big hash} {
  112. set args {}
  113. foreach {k v} [array get bighash] {
  114. set newval [randstring 0 8 alpha]
  115. set bighash($k) $newval
  116. lappend args $k $newval
  117. }
  118. r hmset bighash {*}$args
  119. } {OK}
  120. test {HMGET against non existing key and fields} {
  121. set rv {}
  122. lappend rv [r hmget doesntexist __123123123__ __456456456__]
  123. lappend rv [r hmget smallhash __123123123__ __456456456__]
  124. lappend rv [r hmget bighash __123123123__ __456456456__]
  125. set _ $rv
  126. } {{{} {}} {{} {}} {{} {}}}
  127. test {HMGET against wrong type} {
  128. r set wrongtype somevalue
  129. assert_error "*wrong*" {r hmget wrongtype field1 field2}
  130. }
  131. test {HMGET - small hash} {
  132. set keys {}
  133. set vals {}
  134. foreach {k v} [array get smallhash] {
  135. lappend keys $k
  136. lappend vals $v
  137. }
  138. set err {}
  139. set result [r hmget smallhash {*}$keys]
  140. if {$vals ne $result} {
  141. set err "$vals != $result"
  142. break
  143. }
  144. set _ $err
  145. } {}
  146. test {HMGET - big hash} {
  147. set keys {}
  148. set vals {}
  149. foreach {k v} [array get bighash] {
  150. lappend keys $k
  151. lappend vals $v
  152. }
  153. set err {}
  154. set result [r hmget bighash {*}$keys]
  155. if {$vals ne $result} {
  156. set err "$vals != $result"
  157. break
  158. }
  159. set _ $err
  160. } {}
  161. test {HKEYS - small hash} {
  162. lsort [r hkeys smallhash]
  163. } [lsort [array names smallhash *]]
  164. test {HKEYS - big hash} {
  165. lsort [r hkeys bighash]
  166. } [lsort [array names bighash *]]
  167. test {HVALS - small hash} {
  168. set vals {}
  169. foreach {k v} [array get smallhash] {
  170. lappend vals $v
  171. }
  172. set _ [lsort $vals]
  173. } [lsort [r hvals smallhash]]
  174. test {HVALS - big hash} {
  175. set vals {}
  176. foreach {k v} [array get bighash] {
  177. lappend vals $v
  178. }
  179. set _ [lsort $vals]
  180. } [lsort [r hvals bighash]]
  181. test {HGETALL - small hash} {
  182. lsort [r hgetall smallhash]
  183. } [lsort [array get smallhash]]
  184. test {HGETALL - big hash} {
  185. lsort [r hgetall bighash]
  186. } [lsort [array get bighash]]
  187. test {HDEL and return value} {
  188. set rv {}
  189. lappend rv [r hdel smallhash nokey]
  190. lappend rv [r hdel bighash nokey]
  191. set k [lindex [array names smallhash *] 0]
  192. lappend rv [r hdel smallhash $k]
  193. lappend rv [r hdel smallhash $k]
  194. lappend rv [r hget smallhash $k]
  195. unset smallhash($k)
  196. set k [lindex [array names bighash *] 0]
  197. lappend rv [r hdel bighash $k]
  198. lappend rv [r hdel bighash $k]
  199. lappend rv [r hget bighash $k]
  200. unset bighash($k)
  201. set _ $rv
  202. } {0 0 1 0 {} 1 0 {}}
  203. test {HDEL - more than a single value} {
  204. set rv {}
  205. r del myhash
  206. r hmset myhash a 1 b 2 c 3
  207. assert_equal 0 [r hdel myhash x y]
  208. assert_equal 2 [r hdel myhash a c f]
  209. r hgetall myhash
  210. } {b 2}
  211. test {HDEL - hash becomes empty before deleting all specified fields} {
  212. r del myhash
  213. r hmset myhash a 1 b 2 c 3
  214. assert_equal 3 [r hdel myhash a b c d e]
  215. assert_equal 0 [r exists myhash]
  216. }
  217. test {HEXISTS} {
  218. set rv {}
  219. set k [lindex [array names smallhash *] 0]
  220. lappend rv [r hexists smallhash $k]
  221. lappend rv [r hexists smallhash nokey]
  222. set k [lindex [array names bighash *] 0]
  223. lappend rv [r hexists bighash $k]
  224. lappend rv [r hexists bighash nokey]
  225. } {1 0 1 0}
  226. test {Is a ziplist encoded Hash promoted on big payload?} {
  227. r hset smallhash foo [string repeat a 1024]
  228. r debug object smallhash
  229. } {*hashtable*}
  230. test {HINCRBY against non existing database key} {
  231. r del htest
  232. list [r hincrby htest foo 2]
  233. } {2}
  234. test {HINCRBY against non existing hash key} {
  235. set rv {}
  236. r hdel smallhash tmp
  237. r hdel bighash tmp
  238. lappend rv [r hincrby smallhash tmp 2]
  239. lappend rv [r hget smallhash tmp]
  240. lappend rv [r hincrby bighash tmp 2]
  241. lappend rv [r hget bighash tmp]
  242. } {2 2 2 2}
  243. test {HINCRBY against hash key created by hincrby itself} {
  244. set rv {}
  245. lappend rv [r hincrby smallhash tmp 3]
  246. lappend rv [r hget smallhash tmp]
  247. lappend rv [r hincrby bighash tmp 3]
  248. lappend rv [r hget bighash tmp]
  249. } {5 5 5 5}
  250. test {HINCRBY against hash key originally set with HSET} {
  251. r hset smallhash tmp 100
  252. r hset bighash tmp 100
  253. list [r hincrby smallhash tmp 2] [r hincrby bighash tmp 2]
  254. } {102 102}
  255. test {HINCRBY over 32bit value} {
  256. r hset smallhash tmp 17179869184
  257. r hset bighash tmp 17179869184
  258. list [r hincrby smallhash tmp 1] [r hincrby bighash tmp 1]
  259. } {17179869185 17179869185}
  260. test {HINCRBY over 32bit value with over 32bit increment} {
  261. r hset smallhash tmp 17179869184
  262. r hset bighash tmp 17179869184
  263. list [r hincrby smallhash tmp 17179869184] [r hincrby bighash tmp 17179869184]
  264. } {34359738368 34359738368}
  265. test {HINCRBY fails against hash value with spaces (left)} {
  266. r hset smallhash str " 11"
  267. r hset bighash str " 11"
  268. catch {r hincrby smallhash str 1} smallerr
  269. catch {r hincrby smallhash str 1} bigerr
  270. set rv {}
  271. lappend rv [string match "ERR*not an integer*" $smallerr]
  272. lappend rv [string match "ERR*not an integer*" $bigerr]
  273. } {1 1}
  274. test {HINCRBY fails against hash value with spaces (right)} {
  275. r hset smallhash str "11 "
  276. r hset bighash str "11 "
  277. catch {r hincrby smallhash str 1} smallerr
  278. catch {r hincrby smallhash str 1} bigerr
  279. set rv {}
  280. lappend rv [string match "ERR*not an integer*" $smallerr]
  281. lappend rv [string match "ERR*not an integer*" $bigerr]
  282. } {1 1}
  283. test {HINCRBY can detect overflows} {
  284. set e {}
  285. r hset hash n -9223372036854775484
  286. assert {[r hincrby hash n -1] == -9223372036854775485}
  287. catch {r hincrby hash n -10000} e
  288. set e
  289. } {*overflow*}
  290. test {HINCRBYFLOAT against non existing database key} {
  291. r del htest
  292. list [r hincrbyfloat htest foo 2.5]
  293. } {2.5}
  294. test {HINCRBYFLOAT against non existing hash key} {
  295. set rv {}
  296. r hdel smallhash tmp
  297. r hdel bighash tmp
  298. lappend rv [roundFloat [r hincrbyfloat smallhash tmp 2.5]]
  299. lappend rv [roundFloat [r hget smallhash tmp]]
  300. lappend rv [roundFloat [r hincrbyfloat bighash tmp 2.5]]
  301. lappend rv [roundFloat [r hget bighash tmp]]
  302. } {2.5 2.5 2.5 2.5}
  303. test {HINCRBYFLOAT against hash key created by hincrby itself} {
  304. set rv {}
  305. lappend rv [roundFloat [r hincrbyfloat smallhash tmp 3.5]]
  306. lappend rv [roundFloat [r hget smallhash tmp]]
  307. lappend rv [roundFloat [r hincrbyfloat bighash tmp 3.5]]
  308. lappend rv [roundFloat [r hget bighash tmp]]
  309. } {6 6 6 6}
  310. test {HINCRBYFLOAT against hash key originally set with HSET} {
  311. r hset smallhash tmp 100
  312. r hset bighash tmp 100
  313. list [roundFloat [r hincrbyfloat smallhash tmp 2.5]] \
  314. [roundFloat [r hincrbyfloat bighash tmp 2.5]]
  315. } {102.5 102.5}
  316. test {HINCRBYFLOAT over 32bit value} {
  317. r hset smallhash tmp 17179869184
  318. r hset bighash tmp 17179869184
  319. list [r hincrbyfloat smallhash tmp 1] \
  320. [r hincrbyfloat bighash tmp 1]
  321. } {17179869185 17179869185}
  322. test {HINCRBYFLOAT over 32bit value with over 32bit increment} {
  323. r hset smallhash tmp 17179869184
  324. r hset bighash tmp 17179869184
  325. list [r hincrbyfloat smallhash tmp 17179869184] \
  326. [r hincrbyfloat bighash tmp 17179869184]
  327. } {34359738368 34359738368}
  328. test {HINCRBYFLOAT fails against hash value with spaces (left)} {
  329. r hset smallhash str " 11"
  330. r hset bighash str " 11"
  331. catch {r hincrbyfloat smallhash str 1} smallerr
  332. catch {r hincrbyfloat smallhash str 1} bigerr
  333. set rv {}
  334. lappend rv [string match "ERR*not*float*" $smallerr]
  335. lappend rv [string match "ERR*not*float*" $bigerr]
  336. } {1 1}
  337. test {HINCRBYFLOAT fails against hash value with spaces (right)} {
  338. r hset smallhash str "11 "
  339. r hset bighash str "11 "
  340. catch {r hincrbyfloat smallhash str 1} smallerr
  341. catch {r hincrbyfloat smallhash str 1} bigerr
  342. set rv {}
  343. lappend rv [string match "ERR*not*float*" $smallerr]
  344. lappend rv [string match "ERR*not*float*" $bigerr]
  345. } {1 1}
  346. test {HSTRLEN against the small hash} {
  347. set err {}
  348. foreach k [array names smallhash *] {
  349. if {[string length $smallhash($k)] ne [r hstrlen smallhash $k]} {
  350. set err "[string length $smallhash($k)] != [r hstrlen smallhash $k]"
  351. break
  352. }
  353. }
  354. set _ $err
  355. } {}
  356. test {HSTRLEN against the big hash} {
  357. set err {}
  358. foreach k [array names bighash *] {
  359. if {[string length $bighash($k)] ne [r hstrlen bighash $k]} {
  360. set err "[string length $bighash($k)] != [r hstrlen bighash $k]"
  361. puts "HSTRLEN and logical length mismatch:"
  362. puts "key: $k"
  363. puts "Logical content: $bighash($k)"
  364. puts "Server content: [r hget bighash $k]"
  365. }
  366. }
  367. set _ $err
  368. } {}
  369. test {HSTRLEN against non existing field} {
  370. set rv {}
  371. lappend rv [r hstrlen smallhash __123123123__]
  372. lappend rv [r hstrlen bighash __123123123__]
  373. set _ $rv
  374. } {0 0}
  375. test {HSTRLEN corner cases} {
  376. set vals {
  377. -9223372036854775808 9223372036854775807 9223372036854775808
  378. {} 0 -1 x
  379. }
  380. foreach v $vals {
  381. r hmset smallhash field $v
  382. r hmset bighash field $v
  383. set len1 [string length $v]
  384. set len2 [r hstrlen smallhash field]
  385. set len3 [r hstrlen bighash field]
  386. assert {$len1 == $len2}
  387. assert {$len2 == $len3}
  388. }
  389. }
  390. test {Hash ziplist regression test for large keys} {
  391. r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk a
  392. r hset hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk b
  393. r hget hash kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk
  394. } {b}
  395. foreach size {10 512} {
  396. test "Hash fuzzing #1 - $size fields" {
  397. for {set times 0} {$times < 10} {incr times} {
  398. catch {unset hash}
  399. array set hash {}
  400. r del hash
  401. # Create
  402. for {set j 0} {$j < $size} {incr j} {
  403. set field [randomValue]
  404. set value [randomValue]
  405. r hset hash $field $value
  406. set hash($field) $value
  407. }
  408. # Verify
  409. foreach {k v} [array get hash] {
  410. assert_equal $v [r hget hash $k]
  411. }
  412. assert_equal [array size hash] [r hlen hash]
  413. }
  414. }
  415. test "Hash fuzzing #2 - $size fields" {
  416. for {set times 0} {$times < 10} {incr times} {
  417. catch {unset hash}
  418. array set hash {}
  419. r del hash
  420. # Create
  421. for {set j 0} {$j < $size} {incr j} {
  422. randpath {
  423. set field [randomValue]
  424. set value [randomValue]
  425. r hset hash $field $value
  426. set hash($field) $value
  427. } {
  428. set field [randomSignedInt 512]
  429. set value [randomSignedInt 512]
  430. r hset hash $field $value
  431. set hash($field) $value
  432. } {
  433. randpath {
  434. set field [randomValue]
  435. } {
  436. set field [randomSignedInt 512]
  437. }
  438. r hdel hash $field
  439. unset -nocomplain hash($field)
  440. }
  441. }
  442. # Verify
  443. foreach {k v} [array get hash] {
  444. assert_equal $v [r hget hash $k]
  445. }
  446. assert_equal [array size hash] [r hlen hash]
  447. }
  448. }
  449. }
  450. test {Stress test the hash ziplist -> hashtable encoding conversion} {
  451. r config set hash-max-ziplist-entries 32
  452. for {set j 0} {$j < 100} {incr j} {
  453. r del myhash
  454. for {set i 0} {$i < 64} {incr i} {
  455. r hset myhash [randomValue] [randomValue]
  456. }
  457. assert {[r object encoding myhash] eq {hashtable}}
  458. }
  459. }
  460. # The following test can only be executed if we don't use Valgrind, and if
  461. # we are using x86_64 architecture, because:
  462. #
  463. # 1) Valgrind has floating point limitations, no support for 80 bits math.
  464. # 2) Other archs may have the same limits.
  465. #
  466. # 1.23 cannot be represented correctly with 64 bit doubles, so we skip
  467. # the test, since we are only testing pretty printing here and is not
  468. # a bug if the program outputs things like 1.299999...
  469. if {!$::valgrind && [string match *x86_64* [exec uname -a]]} {
  470. test {Test HINCRBYFLOAT for correct float representation (issue #2846)} {
  471. r del myhash
  472. assert {[r hincrbyfloat myhash float 1.23] eq {1.23}}
  473. assert {[r hincrbyfloat myhash float 0.77] eq {2}}
  474. assert {[r hincrbyfloat myhash float -0.1] eq {1.9}}
  475. }
  476. }
  477. }