redis-server 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (290) hide show
  1. data/LICENSE +38 -0
  2. data/README.md +33 -0
  3. data/bin/redis +114 -0
  4. data/redis/Makefile +5 -0
  5. data/redis/extconf.rb +3 -0
  6. data/redis/redis-2.2.11/00-RELEASENOTES +199 -0
  7. data/redis/redis-2.2.11/BUGS +1 -0
  8. data/redis/redis-2.2.11/CONTRIBUTING +13 -0
  9. data/redis/redis-2.2.11/COPYING +10 -0
  10. data/redis/redis-2.2.11/Changelog +1032 -0
  11. data/redis/redis-2.2.11/INSTALL +30 -0
  12. data/redis/redis-2.2.11/Makefile +22 -0
  13. data/redis/redis-2.2.11/README +83 -0
  14. data/redis/redis-2.2.11/TODO +4 -0
  15. data/redis/redis-2.2.11/client-libraries/README +11 -0
  16. data/redis/redis-2.2.11/deps/hiredis/COPYING +10 -0
  17. data/redis/redis-2.2.11/deps/hiredis/Makefile +115 -0
  18. data/redis/redis-2.2.11/deps/hiredis/README.md +311 -0
  19. data/redis/redis-2.2.11/deps/hiredis/TODO +2 -0
  20. data/redis/redis-2.2.11/deps/hiredis/adapters/ae.h +95 -0
  21. data/redis/redis-2.2.11/deps/hiredis/adapters/libev.h +113 -0
  22. data/redis/redis-2.2.11/deps/hiredis/adapters/libevent.h +76 -0
  23. data/redis/redis-2.2.11/deps/hiredis/async.c +321 -0
  24. data/redis/redis-2.2.11/deps/hiredis/async.h +112 -0
  25. data/redis/redis-2.2.11/deps/hiredis/example-ae.c +53 -0
  26. data/redis/redis-2.2.11/deps/hiredis/example-libev.c +47 -0
  27. data/redis/redis-2.2.11/deps/hiredis/example-libevent.c +48 -0
  28. data/redis/redis-2.2.11/deps/hiredis/example.c +67 -0
  29. data/redis/redis-2.2.11/deps/hiredis/fmacros.h +15 -0
  30. data/redis/redis-2.2.11/deps/hiredis/hiredis.c +1058 -0
  31. data/redis/redis-2.2.11/deps/hiredis/hiredis.h +170 -0
  32. data/redis/redis-2.2.11/deps/hiredis/net.c +170 -0
  33. data/redis/redis-2.2.11/deps/hiredis/net.h +43 -0
  34. data/redis/redis-2.2.11/deps/hiredis/sds.c +479 -0
  35. data/redis/redis-2.2.11/deps/hiredis/sds.h +77 -0
  36. data/redis/redis-2.2.11/deps/hiredis/test.c +479 -0
  37. data/redis/redis-2.2.11/deps/hiredis/util.h +40 -0
  38. data/redis/redis-2.2.11/deps/linenoise/Makefile +10 -0
  39. data/redis/redis-2.2.11/deps/linenoise/README.markdown +45 -0
  40. data/redis/redis-2.2.11/deps/linenoise/example.c +27 -0
  41. data/redis/redis-2.2.11/deps/linenoise/linenoise.c +609 -0
  42. data/redis/redis-2.2.11/deps/linenoise/linenoise.h +55 -0
  43. data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER +214 -0
  44. data/redis/redis-2.2.11/design-documents/REDIS-CLUSTER-2 +343 -0
  45. data/redis/redis-2.2.11/doc/AppendCommand.html +48 -0
  46. data/redis/redis-2.2.11/doc/AppendOnlyFileHowto.html +41 -0
  47. data/redis/redis-2.2.11/doc/AuthCommand.html +39 -0
  48. data/redis/redis-2.2.11/doc/Benchmarks.html +129 -0
  49. data/redis/redis-2.2.11/doc/BgrewriteaofCommand.html +41 -0
  50. data/redis/redis-2.2.11/doc/BgsaveCommand.html +39 -0
  51. data/redis/redis-2.2.11/doc/BlpopCommand.html +51 -0
  52. data/redis/redis-2.2.11/doc/BrpoplpushCommand.html +39 -0
  53. data/redis/redis-2.2.11/doc/CommandReference.html +47 -0
  54. data/redis/redis-2.2.11/doc/Comparisons.html +42 -0
  55. data/redis/redis-2.2.11/doc/ConfigCommand.html +76 -0
  56. data/redis/redis-2.2.11/doc/Configuration.html +38 -0
  57. data/redis/redis-2.2.11/doc/ConnectionHandlingSidebar.html +36 -0
  58. data/redis/redis-2.2.11/doc/ControlCommandsSidebar.html +36 -0
  59. data/redis/redis-2.2.11/doc/Credits.html +38 -0
  60. data/redis/redis-2.2.11/doc/DbsizeCommand.html +38 -0
  61. data/redis/redis-2.2.11/doc/DelCommand.html +41 -0
  62. data/redis/redis-2.2.11/doc/DesignPatterns.html +37 -0
  63. data/redis/redis-2.2.11/doc/EventLibray.html +44 -0
  64. data/redis/redis-2.2.11/doc/ExistsCommand.html +42 -0
  65. data/redis/redis-2.2.11/doc/ExpireCommand.html +96 -0
  66. data/redis/redis-2.2.11/doc/FAQ.html +70 -0
  67. data/redis/redis-2.2.11/doc/Features.html +38 -0
  68. data/redis/redis-2.2.11/doc/FlushallCommand.html +39 -0
  69. data/redis/redis-2.2.11/doc/FlushdbCommand.html +39 -0
  70. data/redis/redis-2.2.11/doc/FromSqlToDataStructures.html +37 -0
  71. data/redis/redis-2.2.11/doc/GenericCommandsSidebar.html +36 -0
  72. data/redis/redis-2.2.11/doc/GetCommand.html +39 -0
  73. data/redis/redis-2.2.11/doc/GetbitCommand.html +39 -0
  74. data/redis/redis-2.2.11/doc/GetsetCommand.html +38 -0
  75. data/redis/redis-2.2.11/doc/HackingStrings.html +83 -0
  76. data/redis/redis-2.2.11/doc/HashCommandsSidebar.html +36 -0
  77. data/redis/redis-2.2.11/doc/Hashes.html +37 -0
  78. data/redis/redis-2.2.11/doc/HdelCommand.html +39 -0
  79. data/redis/redis-2.2.11/doc/HexistsCommand.html +39 -0
  80. data/redis/redis-2.2.11/doc/HgetCommand.html +39 -0
  81. data/redis/redis-2.2.11/doc/HgetallCommand.html +40 -0
  82. data/redis/redis-2.2.11/doc/HincrbyCommand.html +45 -0
  83. data/redis/redis-2.2.11/doc/HlenCommand.html +38 -0
  84. data/redis/redis-2.2.11/doc/HmgetCommand.html +40 -0
  85. data/redis/redis-2.2.11/doc/HmsetCommand.html +40 -0
  86. data/redis/redis-2.2.11/doc/HsetCommand.html +40 -0
  87. data/redis/redis-2.2.11/doc/HsetnxCommand.html +41 -0
  88. data/redis/redis-2.2.11/doc/IncrCommand.html +43 -0
  89. data/redis/redis-2.2.11/doc/InfoCommand.html +48 -0
  90. data/redis/redis-2.2.11/doc/IntroductionToRedisDataTypes.html +152 -0
  91. data/redis/redis-2.2.11/doc/KeysCommand.html +43 -0
  92. data/redis/redis-2.2.11/doc/LastsaveCommand.html +39 -0
  93. data/redis/redis-2.2.11/doc/LindexCommand.html +40 -0
  94. data/redis/redis-2.2.11/doc/ListCommandsSidebar.html +36 -0
  95. data/redis/redis-2.2.11/doc/Lists.html +42 -0
  96. data/redis/redis-2.2.11/doc/LlenCommand.html +41 -0
  97. data/redis/redis-2.2.11/doc/LpopCommand.html +41 -0
  98. data/redis/redis-2.2.11/doc/LrangeCommand.html +47 -0
  99. data/redis/redis-2.2.11/doc/LremCommand.html +41 -0
  100. data/redis/redis-2.2.11/doc/LsetCommand.html +38 -0
  101. data/redis/redis-2.2.11/doc/LtrimCommand.html +47 -0
  102. data/redis/redis-2.2.11/doc/MgetCommand.html +52 -0
  103. data/redis/redis-2.2.11/doc/MonitorCommand.html +63 -0
  104. data/redis/redis-2.2.11/doc/MoveCommand.html +42 -0
  105. data/redis/redis-2.2.11/doc/MsetCommand.html +44 -0
  106. data/redis/redis-2.2.11/doc/MultiExecCommand.html +166 -0
  107. data/redis/redis-2.2.11/doc/NonexistentCommands.html +51 -0
  108. data/redis/redis-2.2.11/doc/ObjectHashMappers.html +39 -0
  109. data/redis/redis-2.2.11/doc/Pipelining.html +36 -0
  110. data/redis/redis-2.2.11/doc/ProgrammingExamples.html +38 -0
  111. data/redis/redis-2.2.11/doc/ProtocolSpecification.html +137 -0
  112. data/redis/redis-2.2.11/doc/PublishSubscribe.html +115 -0
  113. data/redis/redis-2.2.11/doc/QuickStart.html +68 -0
  114. data/redis/redis-2.2.11/doc/QuitCommand.html +38 -0
  115. data/redis/redis-2.2.11/doc/README.html +119 -0
  116. data/redis/redis-2.2.11/doc/RandomkeyCommand.html +39 -0
  117. data/redis/redis-2.2.11/doc/Redis0100ChangeLog.html +67 -0
  118. data/redis/redis-2.2.11/doc/Redis0900ChangeLog.html +56 -0
  119. data/redis/redis-2.2.11/doc/RedisBigData.html +61 -0
  120. data/redis/redis-2.2.11/doc/RedisCLI.html +37 -0
  121. data/redis/redis-2.2.11/doc/RedisEventLibrary.html +70 -0
  122. data/redis/redis-2.2.11/doc/RedisGuides.html +37 -0
  123. data/redis/redis-2.2.11/doc/RedisInternals.html +38 -0
  124. data/redis/redis-2.2.11/doc/RedisPipelining.html +93 -0
  125. data/redis/redis-2.2.11/doc/RedisStatus.html +56 -0
  126. data/redis/redis-2.2.11/doc/Redis_1_2_0_Changelog.html +40 -0
  127. data/redis/redis-2.2.11/doc/Redis_2_0_0_Changelog.html +62 -0
  128. data/redis/redis-2.2.11/doc/Redis_2_0_Whats_new.html +59 -0
  129. data/redis/redis-2.2.11/doc/RenameCommand.html +39 -0
  130. data/redis/redis-2.2.11/doc/RenamenxCommand.html +42 -0
  131. data/redis/redis-2.2.11/doc/ReplicationHowto.html +43 -0
  132. data/redis/redis-2.2.11/doc/ReplyTypes.html +42 -0
  133. data/redis/redis-2.2.11/doc/RoadMap.html +38 -0
  134. data/redis/redis-2.2.11/doc/RpoplpushCommand.html +44 -0
  135. data/redis/redis-2.2.11/doc/RpushCommand.html +40 -0
  136. data/redis/redis-2.2.11/doc/SaddCommand.html +41 -0
  137. data/redis/redis-2.2.11/doc/SaveCommand.html +39 -0
  138. data/redis/redis-2.2.11/doc/ScardCommand.html +41 -0
  139. data/redis/redis-2.2.11/doc/SdiffCommand.html +45 -0
  140. data/redis/redis-2.2.11/doc/SdiffstoreCommand.html +38 -0
  141. data/redis/redis-2.2.11/doc/SelectCommand.html +39 -0
  142. data/redis/redis-2.2.11/doc/SetCommand.html +39 -0
  143. data/redis/redis-2.2.11/doc/SetCommandsSidebar.html +36 -0
  144. data/redis/redis-2.2.11/doc/SetbitCommand.html +45 -0
  145. data/redis/redis-2.2.11/doc/SetexCommand.html +42 -0
  146. data/redis/redis-2.2.11/doc/SetnxCommand.html +51 -0
  147. data/redis/redis-2.2.11/doc/SetrangeCommand.html +58 -0
  148. data/redis/redis-2.2.11/doc/Sets.html +36 -0
  149. data/redis/redis-2.2.11/doc/ShutdownCommand.html +39 -0
  150. data/redis/redis-2.2.11/doc/SideBar.html +36 -0
  151. data/redis/redis-2.2.11/doc/SinterCommand.html +40 -0
  152. data/redis/redis-2.2.11/doc/SinterstoreCommand.html +39 -0
  153. data/redis/redis-2.2.11/doc/SismemberCommand.html +42 -0
  154. data/redis/redis-2.2.11/doc/SlaveofCommand.html +41 -0
  155. data/redis/redis-2.2.11/doc/SmembersCommand.html +38 -0
  156. data/redis/redis-2.2.11/doc/SmoveCommand.html +44 -0
  157. data/redis/redis-2.2.11/doc/SortCommand.html +75 -0
  158. data/redis/redis-2.2.11/doc/SortedSetCommandsSidebar.html +36 -0
  159. data/redis/redis-2.2.11/doc/SortedSets.html +36 -0
  160. data/redis/redis-2.2.11/doc/Speed.html +38 -0
  161. data/redis/redis-2.2.11/doc/SponsorshipHistory.html +38 -0
  162. data/redis/redis-2.2.11/doc/SpopCommand.html +40 -0
  163. data/redis/redis-2.2.11/doc/SrandmemberCommand.html +40 -0
  164. data/redis/redis-2.2.11/doc/SremCommand.html +42 -0
  165. data/redis/redis-2.2.11/doc/StringCommandsSidebar.html +36 -0
  166. data/redis/redis-2.2.11/doc/Strings.html +37 -0
  167. data/redis/redis-2.2.11/doc/StrlenCommand.html +39 -0
  168. data/redis/redis-2.2.11/doc/SubstrCommand.html +52 -0
  169. data/redis/redis-2.2.11/doc/SunionCommand.html +40 -0
  170. data/redis/redis-2.2.11/doc/SunionstoreCommand.html +38 -0
  171. data/redis/redis-2.2.11/doc/SupportedLanguages.html +60 -0
  172. data/redis/redis-2.2.11/doc/SupportedPlatforms.html +37 -0
  173. data/redis/redis-2.2.11/doc/TemplateCommand.html +38 -0
  174. data/redis/redis-2.2.11/doc/TtlCommand.html +38 -0
  175. data/redis/redis-2.2.11/doc/TwitterAlikeExample.html +250 -0
  176. data/redis/redis-2.2.11/doc/TypeCommand.html +46 -0
  177. data/redis/redis-2.2.11/doc/UnstableSource.html +39 -0
  178. data/redis/redis-2.2.11/doc/VirtualMemorySpecification.html +156 -0
  179. data/redis/redis-2.2.11/doc/VirtualMemoryUserGuide.html +66 -0
  180. data/redis/redis-2.2.11/doc/ZaddCommand.html +43 -0
  181. data/redis/redis-2.2.11/doc/ZcardCommand.html +41 -0
  182. data/redis/redis-2.2.11/doc/ZincrbyCommand.html +42 -0
  183. data/redis/redis-2.2.11/doc/ZrangeCommand.html +42 -0
  184. data/redis/redis-2.2.11/doc/ZrangebyscoreCommand.html +77 -0
  185. data/redis/redis-2.2.11/doc/ZrankCommand.html +43 -0
  186. data/redis/redis-2.2.11/doc/ZremCommand.html +42 -0
  187. data/redis/redis-2.2.11/doc/ZremrangebyrankCommand.html +39 -0
  188. data/redis/redis-2.2.11/doc/ZremrangebyscoreCommand.html +39 -0
  189. data/redis/redis-2.2.11/doc/ZscoreCommand.html +41 -0
  190. data/redis/redis-2.2.11/doc/ZunionCommand.html +42 -0
  191. data/redis/redis-2.2.11/doc/ZunionstoreCommand.html +43 -0
  192. data/redis/redis-2.2.11/doc/index.html +43 -0
  193. data/redis/redis-2.2.11/doc/redis.png +0 -0
  194. data/redis/redis-2.2.11/doc/style.css +25 -0
  195. data/redis/redis-2.2.11/redis.conf +417 -0
  196. data/redis/redis-2.2.11/src/Makefile +177 -0
  197. data/redis/redis-2.2.11/src/adlist.c +325 -0
  198. data/redis/redis-2.2.11/src/adlist.h +92 -0
  199. data/redis/redis-2.2.11/src/ae.c +390 -0
  200. data/redis/redis-2.2.11/src/ae.h +117 -0
  201. data/redis/redis-2.2.11/src/ae_epoll.c +91 -0
  202. data/redis/redis-2.2.11/src/ae_kqueue.c +93 -0
  203. data/redis/redis-2.2.11/src/ae_select.c +72 -0
  204. data/redis/redis-2.2.11/src/anet.c +347 -0
  205. data/redis/redis-2.2.11/src/anet.h +57 -0
  206. data/redis/redis-2.2.11/src/aof.c +675 -0
  207. data/redis/redis-2.2.11/src/config.c +627 -0
  208. data/redis/redis-2.2.11/src/config.h +64 -0
  209. data/redis/redis-2.2.11/src/db.c +543 -0
  210. data/redis/redis-2.2.11/src/debug.c +314 -0
  211. data/redis/redis-2.2.11/src/dict.c +721 -0
  212. data/redis/redis-2.2.11/src/dict.h +156 -0
  213. data/redis/redis-2.2.11/src/fmacros.h +15 -0
  214. data/redis/redis-2.2.11/src/help.h +638 -0
  215. data/redis/redis-2.2.11/src/intset.c +422 -0
  216. data/redis/redis-2.2.11/src/intset.h +19 -0
  217. data/redis/redis-2.2.11/src/lzf.h +100 -0
  218. data/redis/redis-2.2.11/src/lzfP.h +159 -0
  219. data/redis/redis-2.2.11/src/lzf_c.c +295 -0
  220. data/redis/redis-2.2.11/src/lzf_d.c +150 -0
  221. data/redis/redis-2.2.11/src/mkreleasehdr.sh +9 -0
  222. data/redis/redis-2.2.11/src/multi.c +268 -0
  223. data/redis/redis-2.2.11/src/networking.c +899 -0
  224. data/redis/redis-2.2.11/src/object.c +484 -0
  225. data/redis/redis-2.2.11/src/pqsort.c +197 -0
  226. data/redis/redis-2.2.11/src/pqsort.h +15 -0
  227. data/redis/redis-2.2.11/src/pubsub.c +267 -0
  228. data/redis/redis-2.2.11/src/rdb.c +1020 -0
  229. data/redis/redis-2.2.11/src/redis-benchmark.c +530 -0
  230. data/redis/redis-2.2.11/src/redis-check-aof.c +185 -0
  231. data/redis/redis-2.2.11/src/redis-check-dump.c +681 -0
  232. data/redis/redis-2.2.11/src/redis-cli.c +773 -0
  233. data/redis/redis-2.2.11/src/redis.c +1677 -0
  234. data/redis/redis-2.2.11/src/redis.h +1022 -0
  235. data/redis/redis-2.2.11/src/release.c +13 -0
  236. data/redis/redis-2.2.11/src/replication.c +557 -0
  237. data/redis/redis-2.2.11/src/sds.c +639 -0
  238. data/redis/redis-2.2.11/src/sds.h +78 -0
  239. data/redis/redis-2.2.11/src/sha1.c +276 -0
  240. data/redis/redis-2.2.11/src/sha1.h +17 -0
  241. data/redis/redis-2.2.11/src/solarisfixes.h +22 -0
  242. data/redis/redis-2.2.11/src/sort.c +389 -0
  243. data/redis/redis-2.2.11/src/syncio.c +154 -0
  244. data/redis/redis-2.2.11/src/t_hash.c +476 -0
  245. data/redis/redis-2.2.11/src/t_list.c +986 -0
  246. data/redis/redis-2.2.11/src/t_set.c +610 -0
  247. data/redis/redis-2.2.11/src/t_string.c +438 -0
  248. data/redis/redis-2.2.11/src/t_zset.c +1084 -0
  249. data/redis/redis-2.2.11/src/testhelp.h +54 -0
  250. data/redis/redis-2.2.11/src/util.c +243 -0
  251. data/redis/redis-2.2.11/src/valgrind.sup +5 -0
  252. data/redis/redis-2.2.11/src/version.h +1 -0
  253. data/redis/redis-2.2.11/src/vm.c +1149 -0
  254. data/redis/redis-2.2.11/src/ziplist.c +1323 -0
  255. data/redis/redis-2.2.11/src/ziplist.h +15 -0
  256. data/redis/redis-2.2.11/src/zipmap.c +455 -0
  257. data/redis/redis-2.2.11/src/zipmap.h +48 -0
  258. data/redis/redis-2.2.11/src/zmalloc.c +278 -0
  259. data/redis/redis-2.2.11/src/zmalloc.h +47 -0
  260. data/redis/redis-2.2.11/tests/assets/default.conf +308 -0
  261. data/redis/redis-2.2.11/tests/integration/aof.tcl +104 -0
  262. data/redis/redis-2.2.11/tests/integration/redis-cli.tcl +208 -0
  263. data/redis/redis-2.2.11/tests/integration/replication.tcl +98 -0
  264. data/redis/redis-2.2.11/tests/support/redis.tcl +241 -0
  265. data/redis/redis-2.2.11/tests/support/server.tcl +294 -0
  266. data/redis/redis-2.2.11/tests/support/test.tcl +190 -0
  267. data/redis/redis-2.2.11/tests/support/tmpfile.tcl +15 -0
  268. data/redis/redis-2.2.11/tests/support/util.tcl +296 -0
  269. data/redis/redis-2.2.11/tests/test_helper.tcl +221 -0
  270. data/redis/redis-2.2.11/tests/unit/auth.tcl +15 -0
  271. data/redis/redis-2.2.11/tests/unit/basic.tcl +616 -0
  272. data/redis/redis-2.2.11/tests/unit/cas.tcl +135 -0
  273. data/redis/redis-2.2.11/tests/unit/expire.tcl +74 -0
  274. data/redis/redis-2.2.11/tests/unit/other.tcl +240 -0
  275. data/redis/redis-2.2.11/tests/unit/printver.tcl +6 -0
  276. data/redis/redis-2.2.11/tests/unit/protocol.tcl +62 -0
  277. data/redis/redis-2.2.11/tests/unit/pubsub.tcl +195 -0
  278. data/redis/redis-2.2.11/tests/unit/quit.tcl +40 -0
  279. data/redis/redis-2.2.11/tests/unit/sort.tcl +189 -0
  280. data/redis/redis-2.2.11/tests/unit/type/hash.tcl +300 -0
  281. data/redis/redis-2.2.11/tests/unit/type/list.tcl +819 -0
  282. data/redis/redis-2.2.11/tests/unit/type/set.tcl +334 -0
  283. data/redis/redis-2.2.11/tests/unit/type/zset.tcl +587 -0
  284. data/redis/redis-2.2.11/utils/build-static-symbols.tcl +22 -0
  285. data/redis/redis-2.2.11/utils/generate-command-help.rb +112 -0
  286. data/redis/redis-2.2.11/utils/mktarball.sh +13 -0
  287. data/redis/redis-2.2.11/utils/redis-copy.rb +78 -0
  288. data/redis/redis-2.2.11/utils/redis-sha1.rb +52 -0
  289. data/redis/redis-2.2.11/utils/redis_init_script +42 -0
  290. metadata +362 -0
@@ -0,0 +1,610 @@
1
+ #include "redis.h"
2
+
3
+ /*-----------------------------------------------------------------------------
4
+ * Set Commands
5
+ *----------------------------------------------------------------------------*/
6
+
7
+ /* Factory method to return a set that *can* hold "value". When the object has
8
+ * an integer-encodable value, an intset will be returned. Otherwise a regular
9
+ * hash table. */
10
+ robj *setTypeCreate(robj *value) {
11
+ if (isObjectRepresentableAsLongLong(value,NULL) == REDIS_OK)
12
+ return createIntsetObject();
13
+ return createSetObject();
14
+ }
15
+
16
+ int setTypeAdd(robj *subject, robj *value) {
17
+ long long llval;
18
+ if (subject->encoding == REDIS_ENCODING_HT) {
19
+ if (dictAdd(subject->ptr,value,NULL) == DICT_OK) {
20
+ incrRefCount(value);
21
+ return 1;
22
+ }
23
+ } else if (subject->encoding == REDIS_ENCODING_INTSET) {
24
+ if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
25
+ uint8_t success = 0;
26
+ subject->ptr = intsetAdd(subject->ptr,llval,&success);
27
+ if (success) {
28
+ /* Convert to regular set when the intset contains
29
+ * too many entries. */
30
+ if (intsetLen(subject->ptr) > server.set_max_intset_entries)
31
+ setTypeConvert(subject,REDIS_ENCODING_HT);
32
+ return 1;
33
+ }
34
+ } else {
35
+ /* Failed to get integer from object, convert to regular set. */
36
+ setTypeConvert(subject,REDIS_ENCODING_HT);
37
+
38
+ /* The set *was* an intset and this value is not integer
39
+ * encodable, so dictAdd should always work. */
40
+ redisAssert(dictAdd(subject->ptr,value,NULL) == DICT_OK);
41
+ incrRefCount(value);
42
+ return 1;
43
+ }
44
+ } else {
45
+ redisPanic("Unknown set encoding");
46
+ }
47
+ return 0;
48
+ }
49
+
50
+ int setTypeRemove(robj *setobj, robj *value) {
51
+ long long llval;
52
+ if (setobj->encoding == REDIS_ENCODING_HT) {
53
+ if (dictDelete(setobj->ptr,value) == DICT_OK) {
54
+ if (htNeedsResize(setobj->ptr)) dictResize(setobj->ptr);
55
+ return 1;
56
+ }
57
+ } else if (setobj->encoding == REDIS_ENCODING_INTSET) {
58
+ if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
59
+ int success;
60
+ setobj->ptr = intsetRemove(setobj->ptr,llval,&success);
61
+ if (success) return 1;
62
+ }
63
+ } else {
64
+ redisPanic("Unknown set encoding");
65
+ }
66
+ return 0;
67
+ }
68
+
69
+ int setTypeIsMember(robj *subject, robj *value) {
70
+ long long llval;
71
+ if (subject->encoding == REDIS_ENCODING_HT) {
72
+ return dictFind((dict*)subject->ptr,value) != NULL;
73
+ } else if (subject->encoding == REDIS_ENCODING_INTSET) {
74
+ if (isObjectRepresentableAsLongLong(value,&llval) == REDIS_OK) {
75
+ return intsetFind((intset*)subject->ptr,llval);
76
+ }
77
+ } else {
78
+ redisPanic("Unknown set encoding");
79
+ }
80
+ return 0;
81
+ }
82
+
83
+ setTypeIterator *setTypeInitIterator(robj *subject) {
84
+ setTypeIterator *si = zmalloc(sizeof(setTypeIterator));
85
+ si->subject = subject;
86
+ si->encoding = subject->encoding;
87
+ if (si->encoding == REDIS_ENCODING_HT) {
88
+ si->di = dictGetIterator(subject->ptr);
89
+ } else if (si->encoding == REDIS_ENCODING_INTSET) {
90
+ si->ii = 0;
91
+ } else {
92
+ redisPanic("Unknown set encoding");
93
+ }
94
+ return si;
95
+ }
96
+
97
+ void setTypeReleaseIterator(setTypeIterator *si) {
98
+ if (si->encoding == REDIS_ENCODING_HT)
99
+ dictReleaseIterator(si->di);
100
+ zfree(si);
101
+ }
102
+
103
+ /* Move to the next entry in the set. Returns the object at the current
104
+ * position.
105
+ *
106
+ * Since set elements can be internally be stored as redis objects or
107
+ * simple arrays of integers, setTypeNext returns the encoding of the
108
+ * set object you are iterating, and will populate the appropriate pointer
109
+ * (eobj) or (llobj) accordingly.
110
+ *
111
+ * When there are no longer elements -1 is returned.
112
+ * Returned objects ref count is not incremented, so this function is
113
+ * copy on write friendly. */
114
+ int setTypeNext(setTypeIterator *si, robj **objele, int64_t *llele) {
115
+ if (si->encoding == REDIS_ENCODING_HT) {
116
+ dictEntry *de = dictNext(si->di);
117
+ if (de == NULL) return -1;
118
+ *objele = dictGetEntryKey(de);
119
+ } else if (si->encoding == REDIS_ENCODING_INTSET) {
120
+ if (!intsetGet(si->subject->ptr,si->ii++,llele))
121
+ return -1;
122
+ }
123
+ return si->encoding;
124
+ }
125
+
126
+ /* The not copy on write friendly version but easy to use version
127
+ * of setTypeNext() is setTypeNextObject(), returning new objects
128
+ * or incrementing the ref count of returned objects. So if you don't
129
+ * retain a pointer to this object you should call decrRefCount() against it.
130
+ *
131
+ * This function is the way to go for write operations where COW is not
132
+ * an issue as the result will be anyway of incrementing the ref count. */
133
+ robj *setTypeNextObject(setTypeIterator *si) {
134
+ int64_t intele;
135
+ robj *objele;
136
+ int encoding;
137
+
138
+ encoding = setTypeNext(si,&objele,&intele);
139
+ switch(encoding) {
140
+ case -1: return NULL;
141
+ case REDIS_ENCODING_INTSET:
142
+ return createStringObjectFromLongLong(intele);
143
+ case REDIS_ENCODING_HT:
144
+ incrRefCount(objele);
145
+ return objele;
146
+ default:
147
+ redisPanic("Unsupported encoding");
148
+ }
149
+ return NULL; /* just to suppress warnings */
150
+ }
151
+
152
+ /* Return random element from a non empty set.
153
+ * The returned element can be a int64_t value if the set is encoded
154
+ * as an "intset" blob of integers, or a redis object if the set
155
+ * is a regular set.
156
+ *
157
+ * The caller provides both pointers to be populated with the right
158
+ * object. The return value of the function is the object->encoding
159
+ * field of the object and is used by the caller to check if the
160
+ * int64_t pointer or the redis object pointere was populated.
161
+ *
162
+ * When an object is returned (the set was a real set) the ref count
163
+ * of the object is not incremented so this function can be considered
164
+ * copy on write friendly. */
165
+ int setTypeRandomElement(robj *setobj, robj **objele, int64_t *llele) {
166
+ if (setobj->encoding == REDIS_ENCODING_HT) {
167
+ dictEntry *de = dictGetRandomKey(setobj->ptr);
168
+ *objele = dictGetEntryKey(de);
169
+ } else if (setobj->encoding == REDIS_ENCODING_INTSET) {
170
+ *llele = intsetRandom(setobj->ptr);
171
+ } else {
172
+ redisPanic("Unknown set encoding");
173
+ }
174
+ return setobj->encoding;
175
+ }
176
+
177
+ unsigned long setTypeSize(robj *subject) {
178
+ if (subject->encoding == REDIS_ENCODING_HT) {
179
+ return dictSize((dict*)subject->ptr);
180
+ } else if (subject->encoding == REDIS_ENCODING_INTSET) {
181
+ return intsetLen((intset*)subject->ptr);
182
+ } else {
183
+ redisPanic("Unknown set encoding");
184
+ }
185
+ }
186
+
187
+ /* Convert the set to specified encoding. The resulting dict (when converting
188
+ * to a hashtable) is presized to hold the number of elements in the original
189
+ * set. */
190
+ void setTypeConvert(robj *setobj, int enc) {
191
+ setTypeIterator *si;
192
+ redisAssert(setobj->type == REDIS_SET &&
193
+ setobj->encoding == REDIS_ENCODING_INTSET);
194
+
195
+ if (enc == REDIS_ENCODING_HT) {
196
+ int64_t intele;
197
+ dict *d = dictCreate(&setDictType,NULL);
198
+ robj *element;
199
+
200
+ /* Presize the dict to avoid rehashing */
201
+ dictExpand(d,intsetLen(setobj->ptr));
202
+
203
+ /* To add the elements we extract integers and create redis objects */
204
+ si = setTypeInitIterator(setobj);
205
+ while (setTypeNext(si,NULL,&intele) != -1) {
206
+ element = createStringObjectFromLongLong(intele);
207
+ redisAssert(dictAdd(d,element,NULL) == DICT_OK);
208
+ }
209
+ setTypeReleaseIterator(si);
210
+
211
+ setobj->encoding = REDIS_ENCODING_HT;
212
+ zfree(setobj->ptr);
213
+ setobj->ptr = d;
214
+ } else {
215
+ redisPanic("Unsupported set conversion");
216
+ }
217
+ }
218
+
219
+ void saddCommand(redisClient *c) {
220
+ robj *set;
221
+
222
+ set = lookupKeyWrite(c->db,c->argv[1]);
223
+ c->argv[2] = tryObjectEncoding(c->argv[2]);
224
+ if (set == NULL) {
225
+ set = setTypeCreate(c->argv[2]);
226
+ dbAdd(c->db,c->argv[1],set);
227
+ } else {
228
+ if (set->type != REDIS_SET) {
229
+ addReply(c,shared.wrongtypeerr);
230
+ return;
231
+ }
232
+ }
233
+ if (setTypeAdd(set,c->argv[2])) {
234
+ touchWatchedKey(c->db,c->argv[1]);
235
+ server.dirty++;
236
+ addReply(c,shared.cone);
237
+ } else {
238
+ addReply(c,shared.czero);
239
+ }
240
+ }
241
+
242
+ void sremCommand(redisClient *c) {
243
+ robj *set;
244
+
245
+ if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
246
+ checkType(c,set,REDIS_SET)) return;
247
+
248
+ c->argv[2] = tryObjectEncoding(c->argv[2]);
249
+ if (setTypeRemove(set,c->argv[2])) {
250
+ if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
251
+ touchWatchedKey(c->db,c->argv[1]);
252
+ server.dirty++;
253
+ addReply(c,shared.cone);
254
+ } else {
255
+ addReply(c,shared.czero);
256
+ }
257
+ }
258
+
259
+ void smoveCommand(redisClient *c) {
260
+ robj *srcset, *dstset, *ele;
261
+ srcset = lookupKeyWrite(c->db,c->argv[1]);
262
+ dstset = lookupKeyWrite(c->db,c->argv[2]);
263
+ ele = c->argv[3] = tryObjectEncoding(c->argv[3]);
264
+
265
+ /* If the source key does not exist return 0 */
266
+ if (srcset == NULL) {
267
+ addReply(c,shared.czero);
268
+ return;
269
+ }
270
+
271
+ /* If the source key has the wrong type, or the destination key
272
+ * is set and has the wrong type, return with an error. */
273
+ if (checkType(c,srcset,REDIS_SET) ||
274
+ (dstset && checkType(c,dstset,REDIS_SET))) return;
275
+
276
+ /* If srcset and dstset are equal, SMOVE is a no-op */
277
+ if (srcset == dstset) {
278
+ addReply(c,shared.cone);
279
+ return;
280
+ }
281
+
282
+ /* If the element cannot be removed from the src set, return 0. */
283
+ if (!setTypeRemove(srcset,ele)) {
284
+ addReply(c,shared.czero);
285
+ return;
286
+ }
287
+
288
+ /* Remove the src set from the database when empty */
289
+ if (setTypeSize(srcset) == 0) dbDelete(c->db,c->argv[1]);
290
+ touchWatchedKey(c->db,c->argv[1]);
291
+ touchWatchedKey(c->db,c->argv[2]);
292
+ server.dirty++;
293
+
294
+ /* Create the destination set when it doesn't exist */
295
+ if (!dstset) {
296
+ dstset = setTypeCreate(ele);
297
+ dbAdd(c->db,c->argv[2],dstset);
298
+ }
299
+
300
+ /* An extra key has changed when ele was successfully added to dstset */
301
+ if (setTypeAdd(dstset,ele)) server.dirty++;
302
+ addReply(c,shared.cone);
303
+ }
304
+
305
+ void sismemberCommand(redisClient *c) {
306
+ robj *set;
307
+
308
+ if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
309
+ checkType(c,set,REDIS_SET)) return;
310
+
311
+ c->argv[2] = tryObjectEncoding(c->argv[2]);
312
+ if (setTypeIsMember(set,c->argv[2]))
313
+ addReply(c,shared.cone);
314
+ else
315
+ addReply(c,shared.czero);
316
+ }
317
+
318
+ void scardCommand(redisClient *c) {
319
+ robj *o;
320
+
321
+ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
322
+ checkType(c,o,REDIS_SET)) return;
323
+
324
+ addReplyLongLong(c,setTypeSize(o));
325
+ }
326
+
327
+ void spopCommand(redisClient *c) {
328
+ robj *set, *ele, *aux;
329
+ int64_t llele;
330
+ int encoding;
331
+
332
+ if ((set = lookupKeyWriteOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
333
+ checkType(c,set,REDIS_SET)) return;
334
+
335
+ encoding = setTypeRandomElement(set,&ele,&llele);
336
+ if (encoding == REDIS_ENCODING_INTSET) {
337
+ ele = createStringObjectFromLongLong(llele);
338
+ set->ptr = intsetRemove(set->ptr,llele,NULL);
339
+ } else {
340
+ incrRefCount(ele);
341
+ setTypeRemove(set,ele);
342
+ }
343
+
344
+ /* Replicate/AOF this command as an SREM operation */
345
+ aux = createStringObject("SREM",4);
346
+ rewriteClientCommandVector(c,3,aux,c->argv[1],ele);
347
+ decrRefCount(ele);
348
+ decrRefCount(aux);
349
+
350
+ addReplyBulk(c,ele);
351
+ if (setTypeSize(set) == 0) dbDelete(c->db,c->argv[1]);
352
+ touchWatchedKey(c->db,c->argv[1]);
353
+ server.dirty++;
354
+ }
355
+
356
+ void srandmemberCommand(redisClient *c) {
357
+ robj *set, *ele;
358
+ int64_t llele;
359
+ int encoding;
360
+
361
+ if ((set = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
362
+ checkType(c,set,REDIS_SET)) return;
363
+
364
+ encoding = setTypeRandomElement(set,&ele,&llele);
365
+ if (encoding == REDIS_ENCODING_INTSET) {
366
+ addReplyBulkLongLong(c,llele);
367
+ } else {
368
+ addReplyBulk(c,ele);
369
+ }
370
+ }
371
+
372
+ int qsortCompareSetsByCardinality(const void *s1, const void *s2) {
373
+ return setTypeSize(*(robj**)s1)-setTypeSize(*(robj**)s2);
374
+ }
375
+
376
+ void sinterGenericCommand(redisClient *c, robj **setkeys, unsigned long setnum, robj *dstkey) {
377
+ robj **sets = zmalloc(sizeof(robj*)*setnum);
378
+ setTypeIterator *si;
379
+ robj *eleobj, *dstset = NULL;
380
+ int64_t intobj;
381
+ void *replylen = NULL;
382
+ unsigned long j, cardinality = 0;
383
+ int encoding;
384
+
385
+ for (j = 0; j < setnum; j++) {
386
+ robj *setobj = dstkey ?
387
+ lookupKeyWrite(c->db,setkeys[j]) :
388
+ lookupKeyRead(c->db,setkeys[j]);
389
+ if (!setobj) {
390
+ zfree(sets);
391
+ if (dstkey) {
392
+ if (dbDelete(c->db,dstkey)) {
393
+ touchWatchedKey(c->db,dstkey);
394
+ server.dirty++;
395
+ }
396
+ addReply(c,shared.czero);
397
+ } else {
398
+ addReply(c,shared.emptymultibulk);
399
+ }
400
+ return;
401
+ }
402
+ if (checkType(c,setobj,REDIS_SET)) {
403
+ zfree(sets);
404
+ return;
405
+ }
406
+ sets[j] = setobj;
407
+ }
408
+ /* Sort sets from the smallest to largest, this will improve our
409
+ * algorithm's performace */
410
+ qsort(sets,setnum,sizeof(robj*),qsortCompareSetsByCardinality);
411
+
412
+ /* The first thing we should output is the total number of elements...
413
+ * since this is a multi-bulk write, but at this stage we don't know
414
+ * the intersection set size, so we use a trick, append an empty object
415
+ * to the output list and save the pointer to later modify it with the
416
+ * right length */
417
+ if (!dstkey) {
418
+ replylen = addDeferredMultiBulkLength(c);
419
+ } else {
420
+ /* If we have a target key where to store the resulting set
421
+ * create this key with an empty set inside */
422
+ dstset = createIntsetObject();
423
+ }
424
+
425
+ /* Iterate all the elements of the first (smallest) set, and test
426
+ * the element against all the other sets, if at least one set does
427
+ * not include the element it is discarded */
428
+ si = setTypeInitIterator(sets[0]);
429
+ while((encoding = setTypeNext(si,&eleobj,&intobj)) != -1) {
430
+ for (j = 1; j < setnum; j++) {
431
+ if (sets[j] == sets[0]) continue;
432
+ if (encoding == REDIS_ENCODING_INTSET) {
433
+ /* intset with intset is simple... and fast */
434
+ if (sets[j]->encoding == REDIS_ENCODING_INTSET &&
435
+ !intsetFind((intset*)sets[j]->ptr,intobj))
436
+ {
437
+ break;
438
+ /* in order to compare an integer with an object we
439
+ * have to use the generic function, creating an object
440
+ * for this */
441
+ } else if (sets[j]->encoding == REDIS_ENCODING_HT) {
442
+ eleobj = createStringObjectFromLongLong(intobj);
443
+ if (!setTypeIsMember(sets[j],eleobj)) {
444
+ decrRefCount(eleobj);
445
+ break;
446
+ }
447
+ decrRefCount(eleobj);
448
+ }
449
+ } else if (encoding == REDIS_ENCODING_HT) {
450
+ /* Optimization... if the source object is integer
451
+ * encoded AND the target set is an intset, we can get
452
+ * a much faster path. */
453
+ if (eleobj->encoding == REDIS_ENCODING_INT &&
454
+ sets[j]->encoding == REDIS_ENCODING_INTSET &&
455
+ !intsetFind((intset*)sets[j]->ptr,(long)eleobj->ptr))
456
+ {
457
+ break;
458
+ /* else... object to object check is easy as we use the
459
+ * type agnostic API here. */
460
+ } else if (!setTypeIsMember(sets[j],eleobj)) {
461
+ break;
462
+ }
463
+ }
464
+ }
465
+
466
+ /* Only take action when all sets contain the member */
467
+ if (j == setnum) {
468
+ if (!dstkey) {
469
+ if (encoding == REDIS_ENCODING_HT)
470
+ addReplyBulk(c,eleobj);
471
+ else
472
+ addReplyBulkLongLong(c,intobj);
473
+ cardinality++;
474
+ } else {
475
+ if (encoding == REDIS_ENCODING_INTSET) {
476
+ eleobj = createStringObjectFromLongLong(intobj);
477
+ setTypeAdd(dstset,eleobj);
478
+ decrRefCount(eleobj);
479
+ } else {
480
+ setTypeAdd(dstset,eleobj);
481
+ }
482
+ }
483
+ }
484
+ }
485
+ setTypeReleaseIterator(si);
486
+
487
+ if (dstkey) {
488
+ /* Store the resulting set into the target, if the intersection
489
+ * is not an empty set. */
490
+ dbDelete(c->db,dstkey);
491
+ if (setTypeSize(dstset) > 0) {
492
+ dbAdd(c->db,dstkey,dstset);
493
+ addReplyLongLong(c,setTypeSize(dstset));
494
+ } else {
495
+ decrRefCount(dstset);
496
+ addReply(c,shared.czero);
497
+ }
498
+ touchWatchedKey(c->db,dstkey);
499
+ server.dirty++;
500
+ } else {
501
+ setDeferredMultiBulkLength(c,replylen,cardinality);
502
+ }
503
+ zfree(sets);
504
+ }
505
+
506
+ void sinterCommand(redisClient *c) {
507
+ sinterGenericCommand(c,c->argv+1,c->argc-1,NULL);
508
+ }
509
+
510
+ void sinterstoreCommand(redisClient *c) {
511
+ sinterGenericCommand(c,c->argv+2,c->argc-2,c->argv[1]);
512
+ }
513
+
514
+ #define REDIS_OP_UNION 0
515
+ #define REDIS_OP_DIFF 1
516
+ #define REDIS_OP_INTER 2
517
+
518
+ void sunionDiffGenericCommand(redisClient *c, robj **setkeys, int setnum, robj *dstkey, int op) {
519
+ robj **sets = zmalloc(sizeof(robj*)*setnum);
520
+ setTypeIterator *si;
521
+ robj *ele, *dstset = NULL;
522
+ int j, cardinality = 0;
523
+
524
+ for (j = 0; j < setnum; j++) {
525
+ robj *setobj = dstkey ?
526
+ lookupKeyWrite(c->db,setkeys[j]) :
527
+ lookupKeyRead(c->db,setkeys[j]);
528
+ if (!setobj) {
529
+ sets[j] = NULL;
530
+ continue;
531
+ }
532
+ if (checkType(c,setobj,REDIS_SET)) {
533
+ zfree(sets);
534
+ return;
535
+ }
536
+ sets[j] = setobj;
537
+ }
538
+
539
+ /* We need a temp set object to store our union. If the dstkey
540
+ * is not NULL (that is, we are inside an SUNIONSTORE operation) then
541
+ * this set object will be the resulting object to set into the target key*/
542
+ dstset = createIntsetObject();
543
+
544
+ /* Iterate all the elements of all the sets, add every element a single
545
+ * time to the result set */
546
+ for (j = 0; j < setnum; j++) {
547
+ if (op == REDIS_OP_DIFF && j == 0 && !sets[j]) break; /* result set is empty */
548
+ if (!sets[j]) continue; /* non existing keys are like empty sets */
549
+
550
+ si = setTypeInitIterator(sets[j]);
551
+ while((ele = setTypeNextObject(si)) != NULL) {
552
+ if (op == REDIS_OP_UNION || j == 0) {
553
+ if (setTypeAdd(dstset,ele)) {
554
+ cardinality++;
555
+ }
556
+ } else if (op == REDIS_OP_DIFF) {
557
+ if (setTypeRemove(dstset,ele)) {
558
+ cardinality--;
559
+ }
560
+ }
561
+ decrRefCount(ele);
562
+ }
563
+ setTypeReleaseIterator(si);
564
+
565
+ /* Exit when result set is empty. */
566
+ if (op == REDIS_OP_DIFF && cardinality == 0) break;
567
+ }
568
+
569
+ /* Output the content of the resulting set, if not in STORE mode */
570
+ if (!dstkey) {
571
+ addReplyMultiBulkLen(c,cardinality);
572
+ si = setTypeInitIterator(dstset);
573
+ while((ele = setTypeNextObject(si)) != NULL) {
574
+ addReplyBulk(c,ele);
575
+ decrRefCount(ele);
576
+ }
577
+ setTypeReleaseIterator(si);
578
+ decrRefCount(dstset);
579
+ } else {
580
+ /* If we have a target key where to store the resulting set
581
+ * create this key with the result set inside */
582
+ dbDelete(c->db,dstkey);
583
+ if (setTypeSize(dstset) > 0) {
584
+ dbAdd(c->db,dstkey,dstset);
585
+ addReplyLongLong(c,setTypeSize(dstset));
586
+ } else {
587
+ decrRefCount(dstset);
588
+ addReply(c,shared.czero);
589
+ }
590
+ touchWatchedKey(c->db,dstkey);
591
+ server.dirty++;
592
+ }
593
+ zfree(sets);
594
+ }
595
+
596
+ void sunionCommand(redisClient *c) {
597
+ sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_UNION);
598
+ }
599
+
600
+ void sunionstoreCommand(redisClient *c) {
601
+ sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_UNION);
602
+ }
603
+
604
+ void sdiffCommand(redisClient *c) {
605
+ sunionDiffGenericCommand(c,c->argv+1,c->argc-1,NULL,REDIS_OP_DIFF);
606
+ }
607
+
608
+ void sdiffstoreCommand(redisClient *c) {
609
+ sunionDiffGenericCommand(c,c->argv+2,c->argc-2,c->argv[1],REDIS_OP_DIFF);
610
+ }