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,57 @@
1
+ /* anet.c -- Basic TCP socket stuff made a bit less boring
2
+ *
3
+ * Copyright (c) 2006-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
+ #ifndef ANET_H
32
+ #define ANET_H
33
+
34
+ #define ANET_OK 0
35
+ #define ANET_ERR -1
36
+ #define ANET_ERR_LEN 256
37
+
38
+ #if defined(__sun)
39
+ #define AF_LOCAL AF_UNIX
40
+ #endif
41
+
42
+ int anetTcpConnect(char *err, char *addr, int port);
43
+ int anetTcpNonBlockConnect(char *err, char *addr, int port);
44
+ int anetUnixConnect(char *err, char *path);
45
+ int anetUnixNonBlockConnect(char *err, char *path);
46
+ int anetRead(int fd, char *buf, int count);
47
+ int anetResolve(char *err, char *host, char *ipbuf);
48
+ int anetTcpServer(char *err, int port, char *bindaddr);
49
+ int anetUnixServer(char *err, char *path);
50
+ int anetTcpAccept(char *err, int serversock, char *ip, int *port);
51
+ int anetUnixAccept(char *err, int serversock);
52
+ int anetWrite(int fd, char *buf, int count);
53
+ int anetNonBlock(char *err, int fd);
54
+ int anetTcpNoDelay(char *err, int fd);
55
+ int anetTcpKeepAlive(char *err, int fd);
56
+
57
+ #endif
@@ -0,0 +1,675 @@
1
+ #include "redis.h"
2
+
3
+ #include <signal.h>
4
+ #include <fcntl.h>
5
+ #include <sys/stat.h>
6
+ #include <sys/types.h>
7
+ #include <sys/time.h>
8
+ #include <sys/resource.h>
9
+ #include <sys/wait.h>
10
+
11
+ /* Called when the user switches from "appendonly yes" to "appendonly no"
12
+ * at runtime using the CONFIG command. */
13
+ void stopAppendOnly(void) {
14
+ flushAppendOnlyFile();
15
+ aof_fsync(server.appendfd);
16
+ close(server.appendfd);
17
+
18
+ server.appendfd = -1;
19
+ server.appendseldb = -1;
20
+ server.appendonly = 0;
21
+ /* rewrite operation in progress? kill it, wait child exit */
22
+ if (server.bgsavechildpid != -1) {
23
+ int statloc;
24
+
25
+ if (kill(server.bgsavechildpid,SIGKILL) != -1)
26
+ wait3(&statloc,0,NULL);
27
+ /* reset the buffer accumulating changes while the child saves */
28
+ sdsfree(server.bgrewritebuf);
29
+ server.bgrewritebuf = sdsempty();
30
+ server.bgsavechildpid = -1;
31
+ }
32
+ }
33
+
34
+ /* Called when the user switches from "appendonly no" to "appendonly yes"
35
+ * at runtime using the CONFIG command. */
36
+ int startAppendOnly(void) {
37
+ server.appendonly = 1;
38
+ server.lastfsync = time(NULL);
39
+ server.appendfd = open(server.appendfilename,O_WRONLY|O_APPEND|O_CREAT,0644);
40
+ if (server.appendfd == -1) {
41
+ redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, but I can't open the AOF file: %s",strerror(errno));
42
+ return REDIS_ERR;
43
+ }
44
+ if (rewriteAppendOnlyFileBackground() == REDIS_ERR) {
45
+ server.appendonly = 0;
46
+ close(server.appendfd);
47
+ redisLog(REDIS_WARNING,"Used tried to switch on AOF via CONFIG, I can't trigger a background AOF rewrite operation. Check the above logs for more info about the error.",strerror(errno));
48
+ return REDIS_ERR;
49
+ }
50
+ return REDIS_OK;
51
+ }
52
+
53
+ /* Write the append only file buffer on disk.
54
+ *
55
+ * Since we are required to write the AOF before replying to the client,
56
+ * and the only way the client socket can get a write is entering when the
57
+ * the event loop, we accumulate all the AOF writes in a memory
58
+ * buffer and write it on disk using this function just before entering
59
+ * the event loop again. */
60
+ void flushAppendOnlyFile(void) {
61
+ time_t now;
62
+ ssize_t nwritten;
63
+
64
+ if (sdslen(server.aofbuf) == 0) return;
65
+
66
+ /* We want to perform a single write. This should be guaranteed atomic
67
+ * at least if the filesystem we are writing is a real physical one.
68
+ * While this will save us against the server being killed I don't think
69
+ * there is much to do about the whole server stopping for power problems
70
+ * or alike */
71
+ nwritten = write(server.appendfd,server.aofbuf,sdslen(server.aofbuf));
72
+ if (nwritten != (signed)sdslen(server.aofbuf)) {
73
+ /* Ooops, we are in troubles. The best thing to do for now is
74
+ * aborting instead of giving the illusion that everything is
75
+ * working as expected. */
76
+ if (nwritten == -1) {
77
+ redisLog(REDIS_WARNING,"Exiting on error writing to the append-only file: %s",strerror(errno));
78
+ } else {
79
+ redisLog(REDIS_WARNING,"Exiting on short write while writing to the append-only file: %s",strerror(errno));
80
+ }
81
+ exit(1);
82
+ }
83
+ sdsfree(server.aofbuf);
84
+ server.aofbuf = sdsempty();
85
+
86
+ /* Don't Fsync if no-appendfsync-on-rewrite is set to yes and we have
87
+ * childs performing heavy I/O on disk. */
88
+ if (server.no_appendfsync_on_rewrite &&
89
+ (server.bgrewritechildpid != -1 || server.bgsavechildpid != -1))
90
+ return;
91
+ /* Fsync if needed */
92
+ now = time(NULL);
93
+ if (server.appendfsync == APPENDFSYNC_ALWAYS ||
94
+ (server.appendfsync == APPENDFSYNC_EVERYSEC &&
95
+ now-server.lastfsync > 1))
96
+ {
97
+ /* aof_fsync is defined as fdatasync() for Linux in order to avoid
98
+ * flushing metadata. */
99
+ aof_fsync(server.appendfd); /* Let's try to get this data on the disk */
100
+ server.lastfsync = now;
101
+ }
102
+ }
103
+
104
+ sds catAppendOnlyGenericCommand(sds buf, int argc, robj **argv) {
105
+ int j;
106
+ buf = sdscatprintf(buf,"*%d\r\n",argc);
107
+ for (j = 0; j < argc; j++) {
108
+ robj *o = getDecodedObject(argv[j]);
109
+ buf = sdscatprintf(buf,"$%lu\r\n",(unsigned long)sdslen(o->ptr));
110
+ buf = sdscatlen(buf,o->ptr,sdslen(o->ptr));
111
+ buf = sdscatlen(buf,"\r\n",2);
112
+ decrRefCount(o);
113
+ }
114
+ return buf;
115
+ }
116
+
117
+ sds catAppendOnlyExpireAtCommand(sds buf, robj *key, robj *seconds) {
118
+ int argc = 3;
119
+ long when;
120
+ robj *argv[3];
121
+
122
+ /* Make sure we can use strtol */
123
+ seconds = getDecodedObject(seconds);
124
+ when = time(NULL)+strtol(seconds->ptr,NULL,10);
125
+ decrRefCount(seconds);
126
+
127
+ argv[0] = createStringObject("EXPIREAT",8);
128
+ argv[1] = key;
129
+ argv[2] = createObject(REDIS_STRING,
130
+ sdscatprintf(sdsempty(),"%ld",when));
131
+ buf = catAppendOnlyGenericCommand(buf, argc, argv);
132
+ decrRefCount(argv[0]);
133
+ decrRefCount(argv[2]);
134
+ return buf;
135
+ }
136
+
137
+ void feedAppendOnlyFile(struct redisCommand *cmd, int dictid, robj **argv, int argc) {
138
+ sds buf = sdsempty();
139
+ robj *tmpargv[3];
140
+
141
+ /* The DB this command was targetting is not the same as the last command
142
+ * we appendend. To issue a SELECT command is needed. */
143
+ if (dictid != server.appendseldb) {
144
+ char seldb[64];
145
+
146
+ snprintf(seldb,sizeof(seldb),"%d",dictid);
147
+ buf = sdscatprintf(buf,"*2\r\n$6\r\nSELECT\r\n$%lu\r\n%s\r\n",
148
+ (unsigned long)strlen(seldb),seldb);
149
+ server.appendseldb = dictid;
150
+ }
151
+
152
+ if (cmd->proc == expireCommand) {
153
+ /* Translate EXPIRE into EXPIREAT */
154
+ buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
155
+ } else if (cmd->proc == setexCommand) {
156
+ /* Translate SETEX to SET and EXPIREAT */
157
+ tmpargv[0] = createStringObject("SET",3);
158
+ tmpargv[1] = argv[1];
159
+ tmpargv[2] = argv[3];
160
+ buf = catAppendOnlyGenericCommand(buf,3,tmpargv);
161
+ decrRefCount(tmpargv[0]);
162
+ buf = catAppendOnlyExpireAtCommand(buf,argv[1],argv[2]);
163
+ } else {
164
+ buf = catAppendOnlyGenericCommand(buf,argc,argv);
165
+ }
166
+
167
+ /* Append to the AOF buffer. This will be flushed on disk just before
168
+ * of re-entering the event loop, so before the client will get a
169
+ * positive reply about the operation performed. */
170
+ server.aofbuf = sdscatlen(server.aofbuf,buf,sdslen(buf));
171
+
172
+ /* If a background append only file rewriting is in progress we want to
173
+ * accumulate the differences between the child DB and the current one
174
+ * in a buffer, so that when the child process will do its work we
175
+ * can append the differences to the new append only file. */
176
+ if (server.bgrewritechildpid != -1)
177
+ server.bgrewritebuf = sdscatlen(server.bgrewritebuf,buf,sdslen(buf));
178
+
179
+ sdsfree(buf);
180
+ }
181
+
182
+ /* In Redis commands are always executed in the context of a client, so in
183
+ * order to load the append only file we need to create a fake client. */
184
+ struct redisClient *createFakeClient(void) {
185
+ struct redisClient *c = zmalloc(sizeof(*c));
186
+
187
+ selectDb(c,0);
188
+ c->fd = -1;
189
+ c->querybuf = sdsempty();
190
+ c->argc = 0;
191
+ c->argv = NULL;
192
+ c->bufpos = 0;
193
+ c->flags = 0;
194
+ /* We set the fake client as a slave waiting for the synchronization
195
+ * so that Redis will not try to send replies to this client. */
196
+ c->replstate = REDIS_REPL_WAIT_BGSAVE_START;
197
+ c->reply = listCreate();
198
+ c->watched_keys = listCreate();
199
+ listSetFreeMethod(c->reply,decrRefCount);
200
+ listSetDupMethod(c->reply,dupClientReplyValue);
201
+ initClientMultiState(c);
202
+ return c;
203
+ }
204
+
205
+ void freeFakeClient(struct redisClient *c) {
206
+ sdsfree(c->querybuf);
207
+ listRelease(c->reply);
208
+ listRelease(c->watched_keys);
209
+ freeClientMultiState(c);
210
+ zfree(c);
211
+ }
212
+
213
+ /* Replay the append log file. On error REDIS_OK is returned. On non fatal
214
+ * error (the append only file is zero-length) REDIS_ERR is returned. On
215
+ * fatal error an error message is logged and the program exists. */
216
+ int loadAppendOnlyFile(char *filename) {
217
+ struct redisClient *fakeClient;
218
+ FILE *fp = fopen(filename,"r");
219
+ struct redis_stat sb;
220
+ int appendonly = server.appendonly;
221
+ long loops = 0;
222
+
223
+ if (fp && redis_fstat(fileno(fp),&sb) != -1 && sb.st_size == 0) {
224
+ fclose(fp);
225
+ return REDIS_ERR;
226
+ }
227
+
228
+ if (fp == NULL) {
229
+ redisLog(REDIS_WARNING,"Fatal error: can't open the append log file for reading: %s",strerror(errno));
230
+ exit(1);
231
+ }
232
+
233
+ /* Temporarily disable AOF, to prevent EXEC from feeding a MULTI
234
+ * to the same file we're about to read. */
235
+ server.appendonly = 0;
236
+
237
+ fakeClient = createFakeClient();
238
+ startLoading(fp);
239
+
240
+ while(1) {
241
+ int argc, j;
242
+ unsigned long len;
243
+ robj **argv;
244
+ char buf[128];
245
+ sds argsds;
246
+ struct redisCommand *cmd;
247
+ int force_swapout;
248
+
249
+ /* Serve the clients from time to time */
250
+ if (!(loops++ % 1000)) {
251
+ loadingProgress(ftello(fp));
252
+ aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
253
+ }
254
+
255
+ if (fgets(buf,sizeof(buf),fp) == NULL) {
256
+ if (feof(fp))
257
+ break;
258
+ else
259
+ goto readerr;
260
+ }
261
+ if (buf[0] != '*') goto fmterr;
262
+ argc = atoi(buf+1);
263
+ argv = zmalloc(sizeof(robj*)*argc);
264
+ for (j = 0; j < argc; j++) {
265
+ if (fgets(buf,sizeof(buf),fp) == NULL) goto readerr;
266
+ if (buf[0] != '$') goto fmterr;
267
+ len = strtol(buf+1,NULL,10);
268
+ argsds = sdsnewlen(NULL,len);
269
+ if (len && fread(argsds,len,1,fp) == 0) goto fmterr;
270
+ argv[j] = createObject(REDIS_STRING,argsds);
271
+ if (fread(buf,2,1,fp) == 0) goto fmterr; /* discard CRLF */
272
+ }
273
+
274
+ /* Command lookup */
275
+ cmd = lookupCommand(argv[0]->ptr);
276
+ if (!cmd) {
277
+ redisLog(REDIS_WARNING,"Unknown command '%s' reading the append only file", argv[0]->ptr);
278
+ exit(1);
279
+ }
280
+ /* Run the command in the context of a fake client */
281
+ fakeClient->argc = argc;
282
+ fakeClient->argv = argv;
283
+ cmd->proc(fakeClient);
284
+
285
+ /* The fake client should not have a reply */
286
+ redisAssert(fakeClient->bufpos == 0 && listLength(fakeClient->reply) == 0);
287
+
288
+ /* Clean up. Command code may have changed argv/argc so we use the
289
+ * argv/argc of the client instead of the local variables. */
290
+ for (j = 0; j < fakeClient->argc; j++)
291
+ decrRefCount(fakeClient->argv[j]);
292
+ zfree(fakeClient->argv);
293
+
294
+ /* Handle swapping while loading big datasets when VM is on */
295
+ force_swapout = 0;
296
+ if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
297
+ force_swapout = 1;
298
+
299
+ if (server.vm_enabled && force_swapout) {
300
+ while (zmalloc_used_memory() > server.vm_max_memory) {
301
+ if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
302
+ }
303
+ }
304
+ }
305
+
306
+ /* This point can only be reached when EOF is reached without errors.
307
+ * If the client is in the middle of a MULTI/EXEC, log error and quit. */
308
+ if (fakeClient->flags & REDIS_MULTI) goto readerr;
309
+
310
+ fclose(fp);
311
+ freeFakeClient(fakeClient);
312
+ server.appendonly = appendonly;
313
+ stopLoading();
314
+ return REDIS_OK;
315
+
316
+ readerr:
317
+ if (feof(fp)) {
318
+ redisLog(REDIS_WARNING,"Unexpected end of file reading the append only file");
319
+ } else {
320
+ redisLog(REDIS_WARNING,"Unrecoverable error reading the append only file: %s", strerror(errno));
321
+ }
322
+ exit(1);
323
+ fmterr:
324
+ redisLog(REDIS_WARNING,"Bad file format reading the append only file: make a backup of your AOF file, then use ./redis-check-aof --fix <filename>");
325
+ exit(1);
326
+ }
327
+
328
+ /* Write a sequence of commands able to fully rebuild the dataset into
329
+ * "filename". Used both by REWRITEAOF and BGREWRITEAOF. */
330
+ int rewriteAppendOnlyFile(char *filename) {
331
+ dictIterator *di = NULL;
332
+ dictEntry *de;
333
+ FILE *fp;
334
+ char tmpfile[256];
335
+ int j;
336
+ time_t now = time(NULL);
337
+
338
+ /* Note that we have to use a different temp name here compared to the
339
+ * one used by rewriteAppendOnlyFileBackground() function. */
340
+ snprintf(tmpfile,256,"temp-rewriteaof-%d.aof", (int) getpid());
341
+ fp = fopen(tmpfile,"w");
342
+ if (!fp) {
343
+ redisLog(REDIS_WARNING, "Failed rewriting the append only file: %s", strerror(errno));
344
+ return REDIS_ERR;
345
+ }
346
+ for (j = 0; j < server.dbnum; j++) {
347
+ char selectcmd[] = "*2\r\n$6\r\nSELECT\r\n";
348
+ redisDb *db = server.db+j;
349
+ dict *d = db->dict;
350
+ if (dictSize(d) == 0) continue;
351
+ di = dictGetSafeIterator(d);
352
+ if (!di) {
353
+ fclose(fp);
354
+ return REDIS_ERR;
355
+ }
356
+
357
+ /* SELECT the new DB */
358
+ if (fwrite(selectcmd,sizeof(selectcmd)-1,1,fp) == 0) goto werr;
359
+ if (fwriteBulkLongLong(fp,j) == 0) goto werr;
360
+
361
+ /* Iterate this DB writing every entry */
362
+ while((de = dictNext(di)) != NULL) {
363
+ sds keystr = dictGetEntryKey(de);
364
+ robj key, *o;
365
+ time_t expiretime;
366
+ int swapped;
367
+
368
+ keystr = dictGetEntryKey(de);
369
+ o = dictGetEntryVal(de);
370
+ initStaticStringObject(key,keystr);
371
+ /* If the value for this key is swapped, load a preview in memory.
372
+ * We use a "swapped" flag to remember if we need to free the
373
+ * value object instead to just increment the ref count anyway
374
+ * in order to avoid copy-on-write of pages if we are forked() */
375
+ if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
376
+ o->storage == REDIS_VM_SWAPPING) {
377
+ swapped = 0;
378
+ } else {
379
+ o = vmPreviewObject(o);
380
+ swapped = 1;
381
+ }
382
+ expiretime = getExpire(db,&key);
383
+
384
+ /* Save the key and associated value */
385
+ if (o->type == REDIS_STRING) {
386
+ /* Emit a SET command */
387
+ char cmd[]="*3\r\n$3\r\nSET\r\n";
388
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
389
+ /* Key and value */
390
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
391
+ if (fwriteBulkObject(fp,o) == 0) goto werr;
392
+ } else if (o->type == REDIS_LIST) {
393
+ /* Emit the RPUSHes needed to rebuild the list */
394
+ char cmd[]="*3\r\n$5\r\nRPUSH\r\n";
395
+ if (o->encoding == REDIS_ENCODING_ZIPLIST) {
396
+ unsigned char *zl = o->ptr;
397
+ unsigned char *p = ziplistIndex(zl,0);
398
+ unsigned char *vstr;
399
+ unsigned int vlen;
400
+ long long vlong;
401
+
402
+ while(ziplistGet(p,&vstr,&vlen,&vlong)) {
403
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
404
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
405
+ if (vstr) {
406
+ if (fwriteBulkString(fp,(char*)vstr,vlen) == 0)
407
+ goto werr;
408
+ } else {
409
+ if (fwriteBulkLongLong(fp,vlong) == 0)
410
+ goto werr;
411
+ }
412
+ p = ziplistNext(zl,p);
413
+ }
414
+ } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
415
+ list *list = o->ptr;
416
+ listNode *ln;
417
+ listIter li;
418
+
419
+ listRewind(list,&li);
420
+ while((ln = listNext(&li))) {
421
+ robj *eleobj = listNodeValue(ln);
422
+
423
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
424
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
425
+ if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
426
+ }
427
+ } else {
428
+ redisPanic("Unknown list encoding");
429
+ }
430
+ } else if (o->type == REDIS_SET) {
431
+ char cmd[]="*3\r\n$4\r\nSADD\r\n";
432
+
433
+ /* Emit the SADDs needed to rebuild the set */
434
+ if (o->encoding == REDIS_ENCODING_INTSET) {
435
+ int ii = 0;
436
+ int64_t llval;
437
+ while(intsetGet(o->ptr,ii++,&llval)) {
438
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
439
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
440
+ if (fwriteBulkLongLong(fp,llval) == 0) goto werr;
441
+ }
442
+ } else if (o->encoding == REDIS_ENCODING_HT) {
443
+ dictIterator *di = dictGetIterator(o->ptr);
444
+ dictEntry *de;
445
+ while((de = dictNext(di)) != NULL) {
446
+ robj *eleobj = dictGetEntryKey(de);
447
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
448
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
449
+ if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
450
+ }
451
+ dictReleaseIterator(di);
452
+ } else {
453
+ redisPanic("Unknown set encoding");
454
+ }
455
+ } else if (o->type == REDIS_ZSET) {
456
+ /* Emit the ZADDs needed to rebuild the sorted set */
457
+ zset *zs = o->ptr;
458
+ dictIterator *di = dictGetIterator(zs->dict);
459
+ dictEntry *de;
460
+
461
+ while((de = dictNext(di)) != NULL) {
462
+ char cmd[]="*4\r\n$4\r\nZADD\r\n";
463
+ robj *eleobj = dictGetEntryKey(de);
464
+ double *score = dictGetEntryVal(de);
465
+
466
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
467
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
468
+ if (fwriteBulkDouble(fp,*score) == 0) goto werr;
469
+ if (fwriteBulkObject(fp,eleobj) == 0) goto werr;
470
+ }
471
+ dictReleaseIterator(di);
472
+ } else if (o->type == REDIS_HASH) {
473
+ char cmd[]="*4\r\n$4\r\nHSET\r\n";
474
+
475
+ /* Emit the HSETs needed to rebuild the hash */
476
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
477
+ unsigned char *p = zipmapRewind(o->ptr);
478
+ unsigned char *field, *val;
479
+ unsigned int flen, vlen;
480
+
481
+ while((p = zipmapNext(p,&field,&flen,&val,&vlen)) != NULL) {
482
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
483
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
484
+ if (fwriteBulkString(fp,(char*)field,flen) == 0)
485
+ goto werr;
486
+ if (fwriteBulkString(fp,(char*)val,vlen) == 0)
487
+ goto werr;
488
+ }
489
+ } else {
490
+ dictIterator *di = dictGetIterator(o->ptr);
491
+ dictEntry *de;
492
+
493
+ while((de = dictNext(di)) != NULL) {
494
+ robj *field = dictGetEntryKey(de);
495
+ robj *val = dictGetEntryVal(de);
496
+
497
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
498
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
499
+ if (fwriteBulkObject(fp,field) == 0) goto werr;
500
+ if (fwriteBulkObject(fp,val) == 0) goto werr;
501
+ }
502
+ dictReleaseIterator(di);
503
+ }
504
+ } else {
505
+ redisPanic("Unknown object type");
506
+ }
507
+ /* Save the expire time */
508
+ if (expiretime != -1) {
509
+ char cmd[]="*3\r\n$8\r\nEXPIREAT\r\n";
510
+ /* If this key is already expired skip it */
511
+ if (expiretime < now) continue;
512
+ if (fwrite(cmd,sizeof(cmd)-1,1,fp) == 0) goto werr;
513
+ if (fwriteBulkObject(fp,&key) == 0) goto werr;
514
+ if (fwriteBulkLongLong(fp,expiretime) == 0) goto werr;
515
+ }
516
+ if (swapped) decrRefCount(o);
517
+ }
518
+ dictReleaseIterator(di);
519
+ }
520
+
521
+ /* Make sure data will not remain on the OS's output buffers */
522
+ fflush(fp);
523
+ aof_fsync(fileno(fp));
524
+ fclose(fp);
525
+
526
+ /* Use RENAME to make sure the DB file is changed atomically only
527
+ * if the generate DB file is ok. */
528
+ if (rename(tmpfile,filename) == -1) {
529
+ redisLog(REDIS_WARNING,"Error moving temp append only file on the final destination: %s", strerror(errno));
530
+ unlink(tmpfile);
531
+ return REDIS_ERR;
532
+ }
533
+ redisLog(REDIS_NOTICE,"SYNC append only file rewrite performed");
534
+ return REDIS_OK;
535
+
536
+ werr:
537
+ fclose(fp);
538
+ unlink(tmpfile);
539
+ redisLog(REDIS_WARNING,"Write error writing append only file on disk: %s", strerror(errno));
540
+ if (di) dictReleaseIterator(di);
541
+ return REDIS_ERR;
542
+ }
543
+
544
+ /* This is how rewriting of the append only file in background works:
545
+ *
546
+ * 1) The user calls BGREWRITEAOF
547
+ * 2) Redis calls this function, that forks():
548
+ * 2a) the child rewrite the append only file in a temp file.
549
+ * 2b) the parent accumulates differences in server.bgrewritebuf.
550
+ * 3) When the child finished '2a' exists.
551
+ * 4) The parent will trap the exit code, if it's OK, will append the
552
+ * data accumulated into server.bgrewritebuf into the temp file, and
553
+ * finally will rename(2) the temp file in the actual file name.
554
+ * The the new file is reopened as the new append only file. Profit!
555
+ */
556
+ int rewriteAppendOnlyFileBackground(void) {
557
+ pid_t childpid;
558
+
559
+ if (server.bgrewritechildpid != -1) return REDIS_ERR;
560
+ if (server.vm_enabled) waitEmptyIOJobsQueue();
561
+ if ((childpid = fork()) == 0) {
562
+ /* Child */
563
+ char tmpfile[256];
564
+
565
+ if (server.vm_enabled) vmReopenSwapFile();
566
+ if (server.ipfd > 0) close(server.ipfd);
567
+ if (server.sofd > 0) close(server.sofd);
568
+ snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) getpid());
569
+ if (rewriteAppendOnlyFile(tmpfile) == REDIS_OK) {
570
+ _exit(0);
571
+ } else {
572
+ _exit(1);
573
+ }
574
+ } else {
575
+ /* Parent */
576
+ if (childpid == -1) {
577
+ redisLog(REDIS_WARNING,
578
+ "Can't rewrite append only file in background: fork: %s",
579
+ strerror(errno));
580
+ return REDIS_ERR;
581
+ }
582
+ redisLog(REDIS_NOTICE,
583
+ "Background append only file rewriting started by pid %d",childpid);
584
+ server.bgrewritechildpid = childpid;
585
+ updateDictResizePolicy();
586
+ /* We set appendseldb to -1 in order to force the next call to the
587
+ * feedAppendOnlyFile() to issue a SELECT command, so the differences
588
+ * accumulated by the parent into server.bgrewritebuf will start
589
+ * with a SELECT statement and it will be safe to merge. */
590
+ server.appendseldb = -1;
591
+ return REDIS_OK;
592
+ }
593
+ return REDIS_OK; /* unreached */
594
+ }
595
+
596
+ void bgrewriteaofCommand(redisClient *c) {
597
+ if (server.bgrewritechildpid != -1) {
598
+ addReplyError(c,"Background append only file rewriting already in progress");
599
+ return;
600
+ }
601
+ if (rewriteAppendOnlyFileBackground() == REDIS_OK) {
602
+ addReplyStatus(c,"Background append only file rewriting started");
603
+ } else {
604
+ addReply(c,shared.err);
605
+ }
606
+ }
607
+
608
+ void aofRemoveTempFile(pid_t childpid) {
609
+ char tmpfile[256];
610
+
611
+ snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) childpid);
612
+ unlink(tmpfile);
613
+ }
614
+
615
+ /* A background append only file rewriting (BGREWRITEAOF) terminated its work.
616
+ * Handle this. */
617
+ void backgroundRewriteDoneHandler(int statloc) {
618
+ int exitcode = WEXITSTATUS(statloc);
619
+ int bysignal = WIFSIGNALED(statloc);
620
+
621
+ if (!bysignal && exitcode == 0) {
622
+ int fd;
623
+ char tmpfile[256];
624
+
625
+ redisLog(REDIS_NOTICE,
626
+ "Background append only file rewriting terminated with success");
627
+ /* Now it's time to flush the differences accumulated by the parent */
628
+ snprintf(tmpfile,256,"temp-rewriteaof-bg-%d.aof", (int) server.bgrewritechildpid);
629
+ fd = open(tmpfile,O_WRONLY|O_APPEND);
630
+ if (fd == -1) {
631
+ redisLog(REDIS_WARNING, "Not able to open the temp append only file produced by the child: %s", strerror(errno));
632
+ goto cleanup;
633
+ }
634
+ /* Flush our data... */
635
+ if (write(fd,server.bgrewritebuf,sdslen(server.bgrewritebuf)) !=
636
+ (signed) sdslen(server.bgrewritebuf)) {
637
+ redisLog(REDIS_WARNING, "Error or short write trying to flush the parent diff of the append log file in the child temp file: %s", strerror(errno));
638
+ close(fd);
639
+ goto cleanup;
640
+ }
641
+ redisLog(REDIS_NOTICE,"Parent diff flushed into the new append log file with success (%lu bytes)",sdslen(server.bgrewritebuf));
642
+ /* Now our work is to rename the temp file into the stable file. And
643
+ * switch the file descriptor used by the server for append only. */
644
+ if (rename(tmpfile,server.appendfilename) == -1) {
645
+ redisLog(REDIS_WARNING,"Can't rename the temp append only file into the stable one: %s", strerror(errno));
646
+ close(fd);
647
+ goto cleanup;
648
+ }
649
+ /* Mission completed... almost */
650
+ redisLog(REDIS_NOTICE,"Append only file successfully rewritten.");
651
+ if (server.appendfd != -1) {
652
+ /* If append only is actually enabled... */
653
+ close(server.appendfd);
654
+ server.appendfd = fd;
655
+ if (server.appendfsync != APPENDFSYNC_NO) aof_fsync(fd);
656
+ server.appendseldb = -1; /* Make sure it will issue SELECT */
657
+ redisLog(REDIS_NOTICE,"The new append only file was selected for future appends.");
658
+ } else {
659
+ /* If append only is disabled we just generate a dump in this
660
+ * format. Why not? */
661
+ close(fd);
662
+ }
663
+ } else if (!bysignal && exitcode != 0) {
664
+ redisLog(REDIS_WARNING, "Background append only file rewriting error");
665
+ } else {
666
+ redisLog(REDIS_WARNING,
667
+ "Background append only file rewriting terminated by signal %d",
668
+ WTERMSIG(statloc));
669
+ }
670
+ cleanup:
671
+ sdsfree(server.bgrewritebuf);
672
+ server.bgrewritebuf = sdsempty();
673
+ aofRemoveTempFile(server.bgrewritechildpid);
674
+ server.bgrewritechildpid = -1;
675
+ }