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,154 @@
1
+ /* Synchronous socket and file I/O operations useful across the core.
2
+ *
3
+ * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
4
+ * All rights reserved.
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions are met:
8
+ *
9
+ * * Redistributions of source code must retain the above copyright notice,
10
+ * this list of conditions and the following disclaimer.
11
+ * * Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * * Neither the name of Redis nor the names of its contributors may be used
15
+ * to endorse or promote products derived from this software without
16
+ * specific prior written permission.
17
+ *
18
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
+ * POSSIBILITY OF SUCH DAMAGE.
29
+ */
30
+
31
+ #include "redis.h"
32
+
33
+ /* ----------------- Blocking sockets I/O with timeouts --------------------- */
34
+
35
+ /* Redis performs most of the I/O in a nonblocking way, with the exception
36
+ * of the SYNC command where the slave does it in a blocking way, and
37
+ * the MIGRATE command that must be blocking in order to be atomic from the
38
+ * point of view of the two instances (one migrating the key and one receiving
39
+ * the key). This is why need the following blocking I/O functions. */
40
+
41
+ int syncWrite(int fd, char *ptr, ssize_t size, int timeout) {
42
+ ssize_t nwritten, ret = size;
43
+ time_t start = time(NULL);
44
+
45
+ timeout++;
46
+ while(size) {
47
+ if (aeWait(fd,AE_WRITABLE,1000) & AE_WRITABLE) {
48
+ nwritten = write(fd,ptr,size);
49
+ if (nwritten == -1) return -1;
50
+ ptr += nwritten;
51
+ size -= nwritten;
52
+ }
53
+ if ((time(NULL)-start) > timeout) {
54
+ errno = ETIMEDOUT;
55
+ return -1;
56
+ }
57
+ }
58
+ return ret;
59
+ }
60
+
61
+ int syncRead(int fd, char *ptr, ssize_t size, int timeout) {
62
+ ssize_t nread, totread = 0;
63
+ time_t start = time(NULL);
64
+
65
+ timeout++;
66
+ while(size) {
67
+ if (aeWait(fd,AE_READABLE,1000) & AE_READABLE) {
68
+ nread = read(fd,ptr,size);
69
+ if (nread <= 0) return -1;
70
+ ptr += nread;
71
+ size -= nread;
72
+ totread += nread;
73
+ }
74
+ if ((time(NULL)-start) > timeout) {
75
+ errno = ETIMEDOUT;
76
+ return -1;
77
+ }
78
+ }
79
+ return totread;
80
+ }
81
+
82
+ int syncReadLine(int fd, char *ptr, ssize_t size, int timeout) {
83
+ ssize_t nread = 0;
84
+
85
+ size--;
86
+ while(size) {
87
+ char c;
88
+
89
+ if (syncRead(fd,&c,1,timeout) == -1) return -1;
90
+ if (c == '\n') {
91
+ *ptr = '\0';
92
+ if (nread && *(ptr-1) == '\r') *(ptr-1) = '\0';
93
+ return nread;
94
+ } else {
95
+ *ptr++ = c;
96
+ *ptr = '\0';
97
+ nread++;
98
+ }
99
+ }
100
+ return nread;
101
+ }
102
+
103
+ /* ----------------- Blocking sockets I/O with timeouts --------------------- */
104
+
105
+ /* Write binary-safe string into a file in the bulkformat
106
+ * $<count>\r\n<payload>\r\n */
107
+ int fwriteBulkString(FILE *fp, char *s, unsigned long len) {
108
+ char cbuf[128];
109
+ int clen;
110
+ cbuf[0] = '$';
111
+ clen = 1+ll2string(cbuf+1,sizeof(cbuf)-1,len);
112
+ cbuf[clen++] = '\r';
113
+ cbuf[clen++] = '\n';
114
+ if (fwrite(cbuf,clen,1,fp) == 0) return 0;
115
+ if (len > 0 && fwrite(s,len,1,fp) == 0) return 0;
116
+ if (fwrite("\r\n",2,1,fp) == 0) return 0;
117
+ return 1;
118
+ }
119
+
120
+ /* Write a double value in bulk format $<count>\r\n<payload>\r\n */
121
+ int fwriteBulkDouble(FILE *fp, double d) {
122
+ char buf[128], dbuf[128];
123
+
124
+ snprintf(dbuf,sizeof(dbuf),"%.17g\r\n",d);
125
+ snprintf(buf,sizeof(buf),"$%lu\r\n",(unsigned long)strlen(dbuf)-2);
126
+ if (fwrite(buf,strlen(buf),1,fp) == 0) return 0;
127
+ if (fwrite(dbuf,strlen(dbuf),1,fp) == 0) return 0;
128
+ return 1;
129
+ }
130
+
131
+ /* Write a long value in bulk format $<count>\r\n<payload>\r\n */
132
+ int fwriteBulkLongLong(FILE *fp, long long l) {
133
+ char bbuf[128], lbuf[128];
134
+ unsigned int blen, llen;
135
+ llen = ll2string(lbuf,32,l);
136
+ blen = snprintf(bbuf,sizeof(bbuf),"$%u\r\n%s\r\n",llen,lbuf);
137
+ if (fwrite(bbuf,blen,1,fp) == 0) return 0;
138
+ return 1;
139
+ }
140
+
141
+ /* Delegate writing an object to writing a bulk string or bulk long long. */
142
+ int fwriteBulkObject(FILE *fp, robj *obj) {
143
+ /* Avoid using getDecodedObject to help copy-on-write (we are often
144
+ * in a child process when this function is called). */
145
+ if (obj->encoding == REDIS_ENCODING_INT) {
146
+ return fwriteBulkLongLong(fp,(long)obj->ptr);
147
+ } else if (obj->encoding == REDIS_ENCODING_RAW) {
148
+ return fwriteBulkString(fp,obj->ptr,sdslen(obj->ptr));
149
+ } else {
150
+ redisPanic("Unknown string encoding");
151
+ }
152
+ }
153
+
154
+
@@ -0,0 +1,476 @@
1
+ #include "redis.h"
2
+
3
+ #include <math.h>
4
+
5
+ /*-----------------------------------------------------------------------------
6
+ * Hash type API
7
+ *----------------------------------------------------------------------------*/
8
+
9
+ /* Check the length of a number of objects to see if we need to convert a
10
+ * zipmap to a real hash. Note that we only check string encoded objects
11
+ * as their string length can be queried in constant time. */
12
+ void hashTypeTryConversion(robj *subject, robj **argv, int start, int end) {
13
+ int i;
14
+ if (subject->encoding != REDIS_ENCODING_ZIPMAP) return;
15
+
16
+ for (i = start; i <= end; i++) {
17
+ if (argv[i]->encoding == REDIS_ENCODING_RAW &&
18
+ sdslen(argv[i]->ptr) > server.hash_max_zipmap_value)
19
+ {
20
+ convertToRealHash(subject);
21
+ return;
22
+ }
23
+ }
24
+ }
25
+
26
+ /* Encode given objects in-place when the hash uses a dict. */
27
+ void hashTypeTryObjectEncoding(robj *subject, robj **o1, robj **o2) {
28
+ if (subject->encoding == REDIS_ENCODING_HT) {
29
+ if (o1) *o1 = tryObjectEncoding(*o1);
30
+ if (o2) *o2 = tryObjectEncoding(*o2);
31
+ }
32
+ }
33
+
34
+ /* Get the value from a hash identified by key.
35
+ *
36
+ * If the string is found either REDIS_ENCODING_HT or REDIS_ENCODING_ZIPMAP
37
+ * is returned, and either **objval or **v and *vlen are set accordingly,
38
+ * so that objects in hash tables are returend as objects and pointers
39
+ * inside a zipmap are returned as such.
40
+ *
41
+ * If the object was not found -1 is returned.
42
+ *
43
+ * This function is copy on write friendly as there is no incr/decr
44
+ * of refcount needed if objects are accessed just for reading operations. */
45
+ int hashTypeGet(robj *o, robj *key, robj **objval, unsigned char **v,
46
+ unsigned int *vlen)
47
+ {
48
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
49
+ int found;
50
+
51
+ key = getDecodedObject(key);
52
+ found = zipmapGet(o->ptr,key->ptr,sdslen(key->ptr),v,vlen);
53
+ decrRefCount(key);
54
+ if (!found) return -1;
55
+ } else {
56
+ dictEntry *de = dictFind(o->ptr,key);
57
+ if (de == NULL) return -1;
58
+ *objval = dictGetEntryVal(de);
59
+ }
60
+ return o->encoding;
61
+ }
62
+
63
+ /* Higher level function of hashTypeGet() that always returns a Redis
64
+ * object (either new or with refcount incremented), so that the caller
65
+ * can retain a reference or call decrRefCount after the usage.
66
+ *
67
+ * The lower level function can prevent copy on write so it is
68
+ * the preferred way of doing read operations. */
69
+ robj *hashTypeGetObject(robj *o, robj *key) {
70
+ robj *objval;
71
+ unsigned char *v;
72
+ unsigned int vlen;
73
+
74
+ int encoding = hashTypeGet(o,key,&objval,&v,&vlen);
75
+ switch(encoding) {
76
+ case REDIS_ENCODING_HT:
77
+ incrRefCount(objval);
78
+ return objval;
79
+ case REDIS_ENCODING_ZIPMAP:
80
+ objval = createStringObject((char*)v,vlen);
81
+ return objval;
82
+ default: return NULL;
83
+ }
84
+ }
85
+
86
+ /* Test if the key exists in the given hash. Returns 1 if the key
87
+ * exists and 0 when it doesn't. */
88
+ int hashTypeExists(robj *o, robj *key) {
89
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
90
+ key = getDecodedObject(key);
91
+ if (zipmapExists(o->ptr,key->ptr,sdslen(key->ptr))) {
92
+ decrRefCount(key);
93
+ return 1;
94
+ }
95
+ decrRefCount(key);
96
+ } else {
97
+ if (dictFind(o->ptr,key) != NULL) {
98
+ return 1;
99
+ }
100
+ }
101
+ return 0;
102
+ }
103
+
104
+ /* Add an element, discard the old if the key already exists.
105
+ * Return 0 on insert and 1 on update. */
106
+ int hashTypeSet(robj *o, robj *key, robj *value) {
107
+ int update = 0;
108
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
109
+ key = getDecodedObject(key);
110
+ value = getDecodedObject(value);
111
+ o->ptr = zipmapSet(o->ptr,
112
+ key->ptr,sdslen(key->ptr),
113
+ value->ptr,sdslen(value->ptr), &update);
114
+ decrRefCount(key);
115
+ decrRefCount(value);
116
+
117
+ /* Check if the zipmap needs to be upgraded to a real hash table */
118
+ if (zipmapLen(o->ptr) > server.hash_max_zipmap_entries)
119
+ convertToRealHash(o);
120
+ } else {
121
+ if (dictReplace(o->ptr,key,value)) {
122
+ /* Insert */
123
+ incrRefCount(key);
124
+ } else {
125
+ /* Update */
126
+ update = 1;
127
+ }
128
+ incrRefCount(value);
129
+ }
130
+ return update;
131
+ }
132
+
133
+ /* Delete an element from a hash.
134
+ * Return 1 on deleted and 0 on not found. */
135
+ int hashTypeDelete(robj *o, robj *key) {
136
+ int deleted = 0;
137
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
138
+ key = getDecodedObject(key);
139
+ o->ptr = zipmapDel(o->ptr,key->ptr,sdslen(key->ptr), &deleted);
140
+ decrRefCount(key);
141
+ } else {
142
+ deleted = dictDelete((dict*)o->ptr,key) == DICT_OK;
143
+ /* Always check if the dictionary needs a resize after a delete. */
144
+ if (deleted && htNeedsResize(o->ptr)) dictResize(o->ptr);
145
+ }
146
+ return deleted;
147
+ }
148
+
149
+ /* Return the number of elements in a hash. */
150
+ unsigned long hashTypeLength(robj *o) {
151
+ return (o->encoding == REDIS_ENCODING_ZIPMAP) ?
152
+ zipmapLen((unsigned char*)o->ptr) : dictSize((dict*)o->ptr);
153
+ }
154
+
155
+ hashTypeIterator *hashTypeInitIterator(robj *subject) {
156
+ hashTypeIterator *hi = zmalloc(sizeof(hashTypeIterator));
157
+ hi->encoding = subject->encoding;
158
+ if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
159
+ hi->zi = zipmapRewind(subject->ptr);
160
+ } else if (hi->encoding == REDIS_ENCODING_HT) {
161
+ hi->di = dictGetIterator(subject->ptr);
162
+ } else {
163
+ redisAssert(NULL);
164
+ }
165
+ return hi;
166
+ }
167
+
168
+ void hashTypeReleaseIterator(hashTypeIterator *hi) {
169
+ if (hi->encoding == REDIS_ENCODING_HT) {
170
+ dictReleaseIterator(hi->di);
171
+ }
172
+ zfree(hi);
173
+ }
174
+
175
+ /* Move to the next entry in the hash. Return REDIS_OK when the next entry
176
+ * could be found and REDIS_ERR when the iterator reaches the end. */
177
+ int hashTypeNext(hashTypeIterator *hi) {
178
+ if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
179
+ if ((hi->zi = zipmapNext(hi->zi, &hi->zk, &hi->zklen,
180
+ &hi->zv, &hi->zvlen)) == NULL) return REDIS_ERR;
181
+ } else {
182
+ if ((hi->de = dictNext(hi->di)) == NULL) return REDIS_ERR;
183
+ }
184
+ return REDIS_OK;
185
+ }
186
+
187
+ /* Get key or value object at current iteration position.
188
+ * The returned item differs with the hash object encoding:
189
+ * - When encoding is REDIS_ENCODING_HT, the objval pointer is populated
190
+ * with the original object.
191
+ * - When encoding is REDIS_ENCODING_ZIPMAP, a pointer to the string and
192
+ * its length is retunred populating the v and vlen pointers.
193
+ * This function is copy on write friendly as accessing objects in read only
194
+ * does not require writing to any memory page.
195
+ *
196
+ * The function returns the encoding of the object, so that the caller
197
+ * can underestand if the key or value was returned as object or C string. */
198
+ int hashTypeCurrent(hashTypeIterator *hi, int what, robj **objval, unsigned char **v, unsigned int *vlen) {
199
+ if (hi->encoding == REDIS_ENCODING_ZIPMAP) {
200
+ if (what & REDIS_HASH_KEY) {
201
+ *v = hi->zk;
202
+ *vlen = hi->zklen;
203
+ } else {
204
+ *v = hi->zv;
205
+ *vlen = hi->zvlen;
206
+ }
207
+ } else {
208
+ if (what & REDIS_HASH_KEY)
209
+ *objval = dictGetEntryKey(hi->de);
210
+ else
211
+ *objval = dictGetEntryVal(hi->de);
212
+ }
213
+ return hi->encoding;
214
+ }
215
+
216
+ /* A non copy-on-write friendly but higher level version of hashTypeCurrent()
217
+ * that always returns an object with refcount incremented by one (or a new
218
+ * object), so it's up to the caller to decrRefCount() the object if no
219
+ * reference is retained. */
220
+ robj *hashTypeCurrentObject(hashTypeIterator *hi, int what) {
221
+ robj *obj;
222
+ unsigned char *v = NULL;
223
+ unsigned int vlen = 0;
224
+ int encoding = hashTypeCurrent(hi,what,&obj,&v,&vlen);
225
+
226
+ if (encoding == REDIS_ENCODING_HT) {
227
+ incrRefCount(obj);
228
+ return obj;
229
+ } else {
230
+ return createStringObject((char*)v,vlen);
231
+ }
232
+ }
233
+
234
+ robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {
235
+ robj *o = lookupKeyWrite(c->db,key);
236
+ if (o == NULL) {
237
+ o = createHashObject();
238
+ dbAdd(c->db,key,o);
239
+ } else {
240
+ if (o->type != REDIS_HASH) {
241
+ addReply(c,shared.wrongtypeerr);
242
+ return NULL;
243
+ }
244
+ }
245
+ return o;
246
+ }
247
+
248
+ void convertToRealHash(robj *o) {
249
+ unsigned char *key, *val, *p, *zm = o->ptr;
250
+ unsigned int klen, vlen;
251
+ dict *dict = dictCreate(&hashDictType,NULL);
252
+
253
+ redisAssert(o->type == REDIS_HASH && o->encoding != REDIS_ENCODING_HT);
254
+ p = zipmapRewind(zm);
255
+ while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
256
+ robj *keyobj, *valobj;
257
+
258
+ keyobj = createStringObject((char*)key,klen);
259
+ valobj = createStringObject((char*)val,vlen);
260
+ keyobj = tryObjectEncoding(keyobj);
261
+ valobj = tryObjectEncoding(valobj);
262
+ dictAdd(dict,keyobj,valobj);
263
+ }
264
+ o->encoding = REDIS_ENCODING_HT;
265
+ o->ptr = dict;
266
+ zfree(zm);
267
+ }
268
+
269
+ /*-----------------------------------------------------------------------------
270
+ * Hash type commands
271
+ *----------------------------------------------------------------------------*/
272
+
273
+ void hsetCommand(redisClient *c) {
274
+ int update;
275
+ robj *o;
276
+
277
+ if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
278
+ hashTypeTryConversion(o,c->argv,2,3);
279
+ hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
280
+ update = hashTypeSet(o,c->argv[2],c->argv[3]);
281
+ addReply(c, update ? shared.czero : shared.cone);
282
+ touchWatchedKey(c->db,c->argv[1]);
283
+ server.dirty++;
284
+ }
285
+
286
+ void hsetnxCommand(redisClient *c) {
287
+ robj *o;
288
+ if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
289
+ hashTypeTryConversion(o,c->argv,2,3);
290
+
291
+ if (hashTypeExists(o, c->argv[2])) {
292
+ addReply(c, shared.czero);
293
+ } else {
294
+ hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);
295
+ hashTypeSet(o,c->argv[2],c->argv[3]);
296
+ addReply(c, shared.cone);
297
+ touchWatchedKey(c->db,c->argv[1]);
298
+ server.dirty++;
299
+ }
300
+ }
301
+
302
+ void hmsetCommand(redisClient *c) {
303
+ int i;
304
+ robj *o;
305
+
306
+ if ((c->argc % 2) == 1) {
307
+ addReplyError(c,"wrong number of arguments for HMSET");
308
+ return;
309
+ }
310
+
311
+ if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
312
+ hashTypeTryConversion(o,c->argv,2,c->argc-1);
313
+ for (i = 2; i < c->argc; i += 2) {
314
+ hashTypeTryObjectEncoding(o,&c->argv[i], &c->argv[i+1]);
315
+ hashTypeSet(o,c->argv[i],c->argv[i+1]);
316
+ }
317
+ addReply(c, shared.ok);
318
+ touchWatchedKey(c->db,c->argv[1]);
319
+ server.dirty++;
320
+ }
321
+
322
+ void hincrbyCommand(redisClient *c) {
323
+ long long value, incr;
324
+ robj *o, *current, *new;
325
+
326
+ if (getLongLongFromObjectOrReply(c,c->argv[3],&incr,NULL) != REDIS_OK) return;
327
+ if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;
328
+ if ((current = hashTypeGetObject(o,c->argv[2])) != NULL) {
329
+ if (getLongLongFromObjectOrReply(c,current,&value,
330
+ "hash value is not an integer") != REDIS_OK) {
331
+ decrRefCount(current);
332
+ return;
333
+ }
334
+ decrRefCount(current);
335
+ } else {
336
+ value = 0;
337
+ }
338
+
339
+ value += incr;
340
+ new = createStringObjectFromLongLong(value);
341
+ hashTypeTryObjectEncoding(o,&c->argv[2],NULL);
342
+ hashTypeSet(o,c->argv[2],new);
343
+ decrRefCount(new);
344
+ addReplyLongLong(c,value);
345
+ touchWatchedKey(c->db,c->argv[1]);
346
+ server.dirty++;
347
+ }
348
+
349
+ void hgetCommand(redisClient *c) {
350
+ robj *o, *value;
351
+ unsigned char *v;
352
+ unsigned int vlen;
353
+ int encoding;
354
+
355
+ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.nullbulk)) == NULL ||
356
+ checkType(c,o,REDIS_HASH)) return;
357
+
358
+ if ((encoding = hashTypeGet(o,c->argv[2],&value,&v,&vlen)) != -1) {
359
+ if (encoding == REDIS_ENCODING_HT)
360
+ addReplyBulk(c,value);
361
+ else
362
+ addReplyBulkCBuffer(c,v,vlen);
363
+ } else {
364
+ addReply(c,shared.nullbulk);
365
+ }
366
+ }
367
+
368
+ void hmgetCommand(redisClient *c) {
369
+ int i, encoding;
370
+ robj *o, *value;
371
+ unsigned char *v;
372
+ unsigned int vlen;
373
+
374
+ o = lookupKeyRead(c->db,c->argv[1]);
375
+ if (o != NULL && o->type != REDIS_HASH) {
376
+ addReply(c,shared.wrongtypeerr);
377
+ return;
378
+ }
379
+
380
+ /* Note the check for o != NULL happens inside the loop. This is
381
+ * done because objects that cannot be found are considered to be
382
+ * an empty hash. The reply should then be a series of NULLs. */
383
+ addReplyMultiBulkLen(c,c->argc-2);
384
+ for (i = 2; i < c->argc; i++) {
385
+ if (o != NULL &&
386
+ (encoding = hashTypeGet(o,c->argv[i],&value,&v,&vlen)) != -1) {
387
+ if (encoding == REDIS_ENCODING_HT)
388
+ addReplyBulk(c,value);
389
+ else
390
+ addReplyBulkCBuffer(c,v,vlen);
391
+ } else {
392
+ addReply(c,shared.nullbulk);
393
+ }
394
+ }
395
+ }
396
+
397
+ void hdelCommand(redisClient *c) {
398
+ robj *o;
399
+ if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
400
+ checkType(c,o,REDIS_HASH)) return;
401
+
402
+ if (hashTypeDelete(o,c->argv[2])) {
403
+ if (hashTypeLength(o) == 0) dbDelete(c->db,c->argv[1]);
404
+ addReply(c,shared.cone);
405
+ touchWatchedKey(c->db,c->argv[1]);
406
+ server.dirty++;
407
+ } else {
408
+ addReply(c,shared.czero);
409
+ }
410
+ }
411
+
412
+ void hlenCommand(redisClient *c) {
413
+ robj *o;
414
+ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
415
+ checkType(c,o,REDIS_HASH)) return;
416
+
417
+ addReplyLongLong(c,hashTypeLength(o));
418
+ }
419
+
420
+ void genericHgetallCommand(redisClient *c, int flags) {
421
+ robj *o;
422
+ unsigned long count = 0;
423
+ hashTypeIterator *hi;
424
+ void *replylen = NULL;
425
+
426
+ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.emptymultibulk)) == NULL
427
+ || checkType(c,o,REDIS_HASH)) return;
428
+
429
+ replylen = addDeferredMultiBulkLength(c);
430
+ hi = hashTypeInitIterator(o);
431
+ while (hashTypeNext(hi) != REDIS_ERR) {
432
+ robj *obj;
433
+ unsigned char *v = NULL;
434
+ unsigned int vlen = 0;
435
+ int encoding;
436
+
437
+ if (flags & REDIS_HASH_KEY) {
438
+ encoding = hashTypeCurrent(hi,REDIS_HASH_KEY,&obj,&v,&vlen);
439
+ if (encoding == REDIS_ENCODING_HT)
440
+ addReplyBulk(c,obj);
441
+ else
442
+ addReplyBulkCBuffer(c,v,vlen);
443
+ count++;
444
+ }
445
+ if (flags & REDIS_HASH_VALUE) {
446
+ encoding = hashTypeCurrent(hi,REDIS_HASH_VALUE,&obj,&v,&vlen);
447
+ if (encoding == REDIS_ENCODING_HT)
448
+ addReplyBulk(c,obj);
449
+ else
450
+ addReplyBulkCBuffer(c,v,vlen);
451
+ count++;
452
+ }
453
+ }
454
+ hashTypeReleaseIterator(hi);
455
+ setDeferredMultiBulkLength(c,replylen,count);
456
+ }
457
+
458
+ void hkeysCommand(redisClient *c) {
459
+ genericHgetallCommand(c,REDIS_HASH_KEY);
460
+ }
461
+
462
+ void hvalsCommand(redisClient *c) {
463
+ genericHgetallCommand(c,REDIS_HASH_VALUE);
464
+ }
465
+
466
+ void hgetallCommand(redisClient *c) {
467
+ genericHgetallCommand(c,REDIS_HASH_KEY|REDIS_HASH_VALUE);
468
+ }
469
+
470
+ void hexistsCommand(redisClient *c) {
471
+ robj *o;
472
+ if ((o = lookupKeyReadOrReply(c,c->argv[1],shared.czero)) == NULL ||
473
+ checkType(c,o,REDIS_HASH)) return;
474
+
475
+ addReply(c, hashTypeExists(o,c->argv[2]) ? shared.cone : shared.czero);
476
+ }