1start_server { 2 tags {"set"} 3 overrides { 4 "set-max-intset-entries" 512 5 } 6} { 7 proc create_set {key entries} { 8 r del $key 9 foreach entry $entries { r sadd $key $entry } 10 } 11 12 test {SADD, SCARD, SISMEMBER, SMEMBERS basics - regular set} { 13 create_set myset {foo} 14 assert_encoding hashtable myset 15 assert_equal 1 [r sadd myset bar] 16 assert_equal 0 [r sadd myset bar] 17 assert_equal 2 [r scard myset] 18 assert_equal 1 [r sismember myset foo] 19 assert_equal 1 [r sismember myset bar] 20 assert_equal 0 [r sismember myset bla] 21 assert_equal {bar foo} [lsort [r smembers myset]] 22 } 23 24 test {SADD, SCARD, SISMEMBER, SMEMBERS basics - intset} { 25 create_set myset {17} 26 assert_encoding intset myset 27 assert_equal 1 [r sadd myset 16] 28 assert_equal 0 [r sadd myset 16] 29 assert_equal 2 [r scard myset] 30 assert_equal 1 [r sismember myset 16] 31 assert_equal 1 [r sismember myset 17] 32 assert_equal 0 [r sismember myset 18] 33 assert_equal {16 17} [lsort [r smembers myset]] 34 } 35 36 test {SADD against non set} { 37 r lpush mylist foo 38 assert_error ERR*kind* {r sadd mylist bar} 39 } 40 41 test "SADD a non-integer against an intset" { 42 create_set myset {1 2 3} 43 assert_encoding intset myset 44 assert_equal 1 [r sadd myset a] 45 assert_encoding hashtable myset 46 } 47 48 test "SADD an integer larger than 64 bits" { 49 create_set myset {213244124402402314402033402} 50 assert_encoding hashtable myset 51 assert_equal 1 [r sismember myset 213244124402402314402033402] 52 } 53 54 test "SADD overflows the maximum allowed integers in an intset" { 55 r del myset 56 for {set i 0} {$i < 512} {incr i} { r sadd myset $i } 57 assert_encoding intset myset 58 assert_equal 1 [r sadd myset 512] 59 assert_encoding hashtable myset 60 } 61 62 test "Set encoding after DEBUG RELOAD" { 63 r del myintset myhashset mylargeintset 64 for {set i 0} {$i < 100} {incr i} { r sadd myintset $i } 65 for {set i 0} {$i < 1280} {incr i} { r sadd mylargeintset $i } 66 for {set i 0} {$i < 256} {incr i} { r sadd myhashset [format "i%03d" $i] } 67 assert_encoding intset myintset 68 assert_encoding hashtable mylargeintset 69 assert_encoding hashtable myhashset 70 71 r debug reload 72 assert_encoding intset myintset 73 assert_encoding hashtable mylargeintset 74 assert_encoding hashtable myhashset 75 } 76 77 test {SREM basics - regular set} { 78 create_set myset {foo bar ciao} 79 assert_encoding hashtable myset 80 assert_equal 0 [r srem myset qux] 81 assert_equal 1 [r srem myset foo] 82 assert_equal {bar ciao} [lsort [r smembers myset]] 83 } 84 85 test {SREM basics - intset} { 86 create_set myset {3 4 5} 87 assert_encoding intset myset 88 assert_equal 0 [r srem myset 6] 89 assert_equal 1 [r srem myset 4] 90 assert_equal {3 5} [lsort [r smembers myset]] 91 } 92 93 foreach {type} {hashtable intset} { 94 for {set i 1} {$i <= 5} {incr i} { 95 r del [format "set%d" $i] 96 } 97 for {set i 0} {$i < 200} {incr i} { 98 r sadd set1 $i 99 r sadd set2 [expr $i+195] 100 } 101 foreach i {199 195 1000 2000} { 102 r sadd set3 $i 103 } 104 for {set i 5} {$i < 200} {incr i} { 105 r sadd set4 $i 106 } 107 r sadd set5 0 108 109 # To make sure the sets are encoded as the type we are testing -- also 110 # when the VM is enabled and the values may be swapped in and out 111 # while the tests are running -- an extra element is added to every 112 # set that determines its encoding. 113 set large 200 114 if {$type eq "hashtable"} { 115 set large foo 116 } 117 118 for {set i 1} {$i <= 5} {incr i} { 119 r sadd [format "set%d" $i] $large 120 } 121 122 test "Generated sets must be encoded as $type" { 123 for {set i 1} {$i <= 5} {incr i} { 124 assert_encoding $type [format "set%d" $i] 125 } 126 } 127 128 test "SINTER with two sets - $type" { 129 assert_equal [list 195 196 197 198 199 $large] [lsort [r sinter set1 set2]] 130 } 131 132 test "SINTERSTORE with two sets - $type" { 133 r sinterstore setres set1 set2 134 assert_encoding $type setres 135 assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]] 136 } 137 138 test "SINTERSTORE with two sets, after a DEBUG RELOAD - $type" { 139 r debug reload 140 r sinterstore setres set1 set2 141 assert_encoding $type setres 142 assert_equal [list 195 196 197 198 199 $large] [lsort [r smembers setres]] 143 } 144 145 test "SUNION with two sets - $type" { 146 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"] 147 assert_equal $expected [lsort [r sunion set1 set2]] 148 } 149 150 test "SUNIONSTORE with two sets - $type" { 151 r sunionstore setres set1 set2 152 assert_encoding $type setres 153 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"] 154 assert_equal $expected [lsort [r smembers setres]] 155 } 156 157 test "SINTER against three sets - $type" { 158 assert_equal [list 195 199 $large] [lsort [r sinter set1 set2 set3]] 159 } 160 161 test "SINTERSTORE with three sets - $type" { 162 r sinterstore setres set1 set2 set3 163 assert_equal [list 195 199 $large] [lsort [r smembers setres]] 164 } 165 166 test "SUNION with non existing keys - $type" { 167 set expected [lsort -uniq "[r smembers set1] [r smembers set2]"] 168 assert_equal $expected [lsort [r sunion nokey1 set1 set2 nokey2]] 169 } 170 171 test "SDIFF with two sets - $type" { 172 assert_equal {0 1 2 3 4} [lsort [r sdiff set1 set4]] 173 } 174 175 test "SDIFF with three sets - $type" { 176 assert_equal {1 2 3 4} [lsort [r sdiff set1 set4 set5]] 177 } 178 179 test "SDIFFSTORE with three sets - $type" { 180 r sdiffstore setres set1 set4 set5 181 # The type is determined by type of the first key to diff against. 182 # See the implementation for more information. 183 assert_encoding $type setres 184 assert_equal {1 2 3 4} [lsort [r smembers setres]] 185 } 186 } 187 188 test "SINTER against non-set should throw error" { 189 r set key1 x 190 assert_error "ERR*wrong kind*" {r sinter key1 noset} 191 } 192 193 test "SUNION against non-set should throw error" { 194 r set key1 x 195 assert_error "ERR*wrong kind*" {r sunion key1 noset} 196 } 197 198 test "SINTERSTORE against non existing keys should delete dstkey" { 199 r set setres xxx 200 assert_equal 0 [r sinterstore setres foo111 bar222] 201 assert_equal 0 [r exists setres] 202 } 203 204 test "SUNIONSTORE against non existing keys should delete dstkey" { 205 r set setres xxx 206 assert_equal 0 [r sunionstore setres foo111 bar222] 207 assert_equal 0 [r exists setres] 208 } 209 210 foreach {type contents} {hashtable {a b c} intset {1 2 3}} { 211 test "SPOP basics - $type" { 212 create_set myset $contents 213 assert_encoding $type myset 214 assert_equal $contents [lsort [list [r spop myset] [r spop myset] [r spop myset]]] 215 assert_equal 0 [r scard myset] 216 } 217 218 test "SRANDMEMBER - $type" { 219 create_set myset $contents 220 unset -nocomplain myset 221 array set myset {} 222 for {set i 0} {$i < 100} {incr i} { 223 set myset([r srandmember myset]) 1 224 } 225 assert_equal $contents [lsort [array names myset]] 226 } 227 } 228 229 proc setup_move {} { 230 r del myset3 myset4 231 create_set myset1 {1 a b} 232 create_set myset2 {2 3 4} 233 assert_encoding hashtable myset1 234 assert_encoding intset myset2 235 } 236 237 test "SMOVE basics - from regular set to intset" { 238 # move a non-integer element to an intset should convert encoding 239 setup_move 240 assert_equal 1 [r smove myset1 myset2 a] 241 assert_equal {1 b} [lsort [r smembers myset1]] 242 assert_equal {2 3 4 a} [lsort [r smembers myset2]] 243 assert_encoding hashtable myset2 244 245 # move an integer element should not convert the encoding 246 setup_move 247 assert_equal 1 [r smove myset1 myset2 1] 248 assert_equal {a b} [lsort [r smembers myset1]] 249 assert_equal {1 2 3 4} [lsort [r smembers myset2]] 250 assert_encoding intset myset2 251 } 252 253 test "SMOVE basics - from intset to regular set" { 254 setup_move 255 assert_equal 1 [r smove myset2 myset1 2] 256 assert_equal {1 2 a b} [lsort [r smembers myset1]] 257 assert_equal {3 4} [lsort [r smembers myset2]] 258 } 259 260 test "SMOVE non existing key" { 261 setup_move 262 assert_equal 0 [r smove myset1 myset2 foo] 263 assert_equal {1 a b} [lsort [r smembers myset1]] 264 assert_equal {2 3 4} [lsort [r smembers myset2]] 265 } 266 267 test "SMOVE non existing src set" { 268 setup_move 269 assert_equal 0 [r smove noset myset2 foo] 270 assert_equal {2 3 4} [lsort [r smembers myset2]] 271 } 272 273 test "SMOVE from regular set to non existing destination set" { 274 setup_move 275 assert_equal 1 [r smove myset1 myset3 a] 276 assert_equal {1 b} [lsort [r smembers myset1]] 277 assert_equal {a} [lsort [r smembers myset3]] 278 assert_encoding hashtable myset3 279 } 280 281 test "SMOVE from intset to non existing destination set" { 282 setup_move 283 assert_equal 1 [r smove myset2 myset3 2] 284 assert_equal {3 4} [lsort [r smembers myset2]] 285 assert_equal {2} [lsort [r smembers myset3]] 286 assert_encoding intset myset3 287 } 288 289 test "SMOVE wrong src key type" { 290 r set x 10 291 assert_error "ERR*wrong kind*" {r smove x myset2 foo} 292 } 293 294 test "SMOVE wrong dst key type" { 295 r set x 10 296 assert_error "ERR*wrong kind*" {r smove myset2 x foo} 297 } 298 299 tags {slow} { 300 test {intsets implementation stress testing} { 301 for {set j 0} {$j < 20} {incr j} { 302 unset -nocomplain s 303 array set s {} 304 r del s 305 set len [randomInt 1024] 306 for {set i 0} {$i < $len} {incr i} { 307 randpath { 308 set data [randomInt 65536] 309 } { 310 set data [randomInt 4294967296] 311 } { 312 set data [randomInt 18446744073709551616] 313 } 314 set s($data) {} 315 r sadd s $data 316 } 317 assert_equal [lsort [r smembers s]] [lsort [array names s]] 318 set len [array size s] 319 for {set i 0} {$i < $len} {incr i} { 320 set e [r spop s] 321 if {![info exists s($e)]} { 322 puts "Can't find '$e' on local array" 323 puts "Local array: [lsort [r smembers s]]" 324 puts "Remote array: [lsort [array names s]]" 325 error "exception" 326 } 327 array unset s $e 328 } 329 assert_equal [r scard s] 0 330 assert_equal [array size s] 0 331 } 332 } 333 } 334} 335