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,1020 @@
1
+ #include "redis.h"
2
+ #include "lzf.h" /* LZF compression library */
3
+
4
+ #include <math.h>
5
+ #include <sys/types.h>
6
+ #include <sys/time.h>
7
+ #include <sys/resource.h>
8
+ #include <sys/wait.h>
9
+ #include <arpa/inet.h>
10
+ #include <sys/stat.h>
11
+
12
+ /* Convenience wrapper around fwrite, that returns the number of bytes written
13
+ * to the file instead of the number of objects (see fwrite(3)) and -1 in the
14
+ * case of an error. It also supports a NULL *fp to skip writing altogether
15
+ * instead of writing to /dev/null. */
16
+ static int rdbWriteRaw(FILE *fp, void *p, size_t len) {
17
+ if (fp != NULL && fwrite(p,len,1,fp) == 0) return -1;
18
+ return len;
19
+ }
20
+
21
+ int rdbSaveType(FILE *fp, unsigned char type) {
22
+ return rdbWriteRaw(fp,&type,1);
23
+ }
24
+
25
+ int rdbSaveTime(FILE *fp, time_t t) {
26
+ int32_t t32 = (int32_t) t;
27
+ return rdbWriteRaw(fp,&t32,4);
28
+ }
29
+
30
+ /* check rdbLoadLen() comments for more info */
31
+ int rdbSaveLen(FILE *fp, uint32_t len) {
32
+ unsigned char buf[2];
33
+ int nwritten;
34
+
35
+ if (len < (1<<6)) {
36
+ /* Save a 6 bit len */
37
+ buf[0] = (len&0xFF)|(REDIS_RDB_6BITLEN<<6);
38
+ if (rdbWriteRaw(fp,buf,1) == -1) return -1;
39
+ nwritten = 1;
40
+ } else if (len < (1<<14)) {
41
+ /* Save a 14 bit len */
42
+ buf[0] = ((len>>8)&0xFF)|(REDIS_RDB_14BITLEN<<6);
43
+ buf[1] = len&0xFF;
44
+ if (rdbWriteRaw(fp,buf,2) == -1) return -1;
45
+ nwritten = 2;
46
+ } else {
47
+ /* Save a 32 bit len */
48
+ buf[0] = (REDIS_RDB_32BITLEN<<6);
49
+ if (rdbWriteRaw(fp,buf,1) == -1) return -1;
50
+ len = htonl(len);
51
+ if (rdbWriteRaw(fp,&len,4) == -1) return -1;
52
+ nwritten = 1+4;
53
+ }
54
+ return nwritten;
55
+ }
56
+
57
+ /* Encode 'value' as an integer if possible (if integer will fit the
58
+ * supported range). If the function sucessful encoded the integer
59
+ * then the (up to 5 bytes) encoded representation is written in the
60
+ * string pointed by 'enc' and the length is returned. Otherwise
61
+ * 0 is returned. */
62
+ int rdbEncodeInteger(long long value, unsigned char *enc) {
63
+ /* Finally check if it fits in our ranges */
64
+ if (value >= -(1<<7) && value <= (1<<7)-1) {
65
+ enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT8;
66
+ enc[1] = value&0xFF;
67
+ return 2;
68
+ } else if (value >= -(1<<15) && value <= (1<<15)-1) {
69
+ enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT16;
70
+ enc[1] = value&0xFF;
71
+ enc[2] = (value>>8)&0xFF;
72
+ return 3;
73
+ } else if (value >= -((long long)1<<31) && value <= ((long long)1<<31)-1) {
74
+ enc[0] = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_INT32;
75
+ enc[1] = value&0xFF;
76
+ enc[2] = (value>>8)&0xFF;
77
+ enc[3] = (value>>16)&0xFF;
78
+ enc[4] = (value>>24)&0xFF;
79
+ return 5;
80
+ } else {
81
+ return 0;
82
+ }
83
+ }
84
+
85
+ /* String objects in the form "2391" "-100" without any space and with a
86
+ * range of values that can fit in an 8, 16 or 32 bit signed value can be
87
+ * encoded as integers to save space */
88
+ int rdbTryIntegerEncoding(char *s, size_t len, unsigned char *enc) {
89
+ long long value;
90
+ char *endptr, buf[32];
91
+
92
+ /* Check if it's possible to encode this value as a number */
93
+ value = strtoll(s, &endptr, 10);
94
+ if (endptr[0] != '\0') return 0;
95
+ ll2string(buf,32,value);
96
+
97
+ /* If the number converted back into a string is not identical
98
+ * then it's not possible to encode the string as integer */
99
+ if (strlen(buf) != len || memcmp(buf,s,len)) return 0;
100
+
101
+ return rdbEncodeInteger(value,enc);
102
+ }
103
+
104
+ int rdbSaveLzfStringObject(FILE *fp, unsigned char *s, size_t len) {
105
+ size_t comprlen, outlen;
106
+ unsigned char byte;
107
+ int n, nwritten = 0;
108
+ void *out;
109
+
110
+ /* We require at least four bytes compression for this to be worth it */
111
+ if (len <= 4) return 0;
112
+ outlen = len-4;
113
+ if ((out = zmalloc(outlen+1)) == NULL) return 0;
114
+ comprlen = lzf_compress(s, len, out, outlen);
115
+ if (comprlen == 0) {
116
+ zfree(out);
117
+ return 0;
118
+ }
119
+ /* Data compressed! Let's save it on disk */
120
+ byte = (REDIS_RDB_ENCVAL<<6)|REDIS_RDB_ENC_LZF;
121
+ if ((n = rdbWriteRaw(fp,&byte,1)) == -1) goto writeerr;
122
+ nwritten += n;
123
+
124
+ if ((n = rdbSaveLen(fp,comprlen)) == -1) goto writeerr;
125
+ nwritten += n;
126
+
127
+ if ((n = rdbSaveLen(fp,len)) == -1) goto writeerr;
128
+ nwritten += n;
129
+
130
+ if ((n = rdbWriteRaw(fp,out,comprlen)) == -1) goto writeerr;
131
+ nwritten += n;
132
+
133
+ zfree(out);
134
+ return nwritten;
135
+
136
+ writeerr:
137
+ zfree(out);
138
+ return -1;
139
+ }
140
+
141
+ /* Save a string objet as [len][data] on disk. If the object is a string
142
+ * representation of an integer value we try to safe it in a special form */
143
+ int rdbSaveRawString(FILE *fp, unsigned char *s, size_t len) {
144
+ int enclen;
145
+ int n, nwritten = 0;
146
+
147
+ /* Try integer encoding */
148
+ if (len <= 11) {
149
+ unsigned char buf[5];
150
+ if ((enclen = rdbTryIntegerEncoding((char*)s,len,buf)) > 0) {
151
+ if (rdbWriteRaw(fp,buf,enclen) == -1) return -1;
152
+ return enclen;
153
+ }
154
+ }
155
+
156
+ /* Try LZF compression - under 20 bytes it's unable to compress even
157
+ * aaaaaaaaaaaaaaaaaa so skip it */
158
+ if (server.rdbcompression && len > 20) {
159
+ n = rdbSaveLzfStringObject(fp,s,len);
160
+ if (n == -1) return -1;
161
+ if (n > 0) return n;
162
+ /* Return value of 0 means data can't be compressed, save the old way */
163
+ }
164
+
165
+ /* Store verbatim */
166
+ if ((n = rdbSaveLen(fp,len)) == -1) return -1;
167
+ nwritten += n;
168
+ if (len > 0) {
169
+ if (rdbWriteRaw(fp,s,len) == -1) return -1;
170
+ nwritten += len;
171
+ }
172
+ return nwritten;
173
+ }
174
+
175
+ /* Save a long long value as either an encoded string or a string. */
176
+ int rdbSaveLongLongAsStringObject(FILE *fp, long long value) {
177
+ unsigned char buf[32];
178
+ int n, nwritten = 0;
179
+ int enclen = rdbEncodeInteger(value,buf);
180
+ if (enclen > 0) {
181
+ return rdbWriteRaw(fp,buf,enclen);
182
+ } else {
183
+ /* Encode as string */
184
+ enclen = ll2string((char*)buf,32,value);
185
+ redisAssert(enclen < 32);
186
+ if ((n = rdbSaveLen(fp,enclen)) == -1) return -1;
187
+ nwritten += n;
188
+ if ((n = rdbWriteRaw(fp,buf,enclen)) == -1) return -1;
189
+ nwritten += n;
190
+ }
191
+ return nwritten;
192
+ }
193
+
194
+ /* Like rdbSaveStringObjectRaw() but handle encoded objects */
195
+ int rdbSaveStringObject(FILE *fp, robj *obj) {
196
+ /* Avoid to decode the object, then encode it again, if the
197
+ * object is alrady integer encoded. */
198
+ if (obj->encoding == REDIS_ENCODING_INT) {
199
+ return rdbSaveLongLongAsStringObject(fp,(long)obj->ptr);
200
+ } else {
201
+ redisAssert(obj->encoding == REDIS_ENCODING_RAW);
202
+ return rdbSaveRawString(fp,obj->ptr,sdslen(obj->ptr));
203
+ }
204
+ }
205
+
206
+ /* Save a double value. Doubles are saved as strings prefixed by an unsigned
207
+ * 8 bit integer specifing the length of the representation.
208
+ * This 8 bit integer has special values in order to specify the following
209
+ * conditions:
210
+ * 253: not a number
211
+ * 254: + inf
212
+ * 255: - inf
213
+ */
214
+ int rdbSaveDoubleValue(FILE *fp, double val) {
215
+ unsigned char buf[128];
216
+ int len;
217
+
218
+ if (isnan(val)) {
219
+ buf[0] = 253;
220
+ len = 1;
221
+ } else if (!isfinite(val)) {
222
+ len = 1;
223
+ buf[0] = (val < 0) ? 255 : 254;
224
+ } else {
225
+ #if (DBL_MANT_DIG >= 52) && (LLONG_MAX == 0x7fffffffffffffffLL)
226
+ /* Check if the float is in a safe range to be casted into a
227
+ * long long. We are assuming that long long is 64 bit here.
228
+ * Also we are assuming that there are no implementations around where
229
+ * double has precision < 52 bit.
230
+ *
231
+ * Under this assumptions we test if a double is inside an interval
232
+ * where casting to long long is safe. Then using two castings we
233
+ * make sure the decimal part is zero. If all this is true we use
234
+ * integer printing function that is much faster. */
235
+ double min = -4503599627370495; /* (2^52)-1 */
236
+ double max = 4503599627370496; /* -(2^52) */
237
+ if (val > min && val < max && val == ((double)((long long)val)))
238
+ ll2string((char*)buf+1,sizeof(buf),(long long)val);
239
+ else
240
+ #endif
241
+ snprintf((char*)buf+1,sizeof(buf)-1,"%.17g",val);
242
+ buf[0] = strlen((char*)buf+1);
243
+ len = buf[0]+1;
244
+ }
245
+ return rdbWriteRaw(fp,buf,len);
246
+ }
247
+
248
+ /* Save a Redis object. */
249
+ int rdbSaveObject(FILE *fp, robj *o) {
250
+ int n, nwritten = 0;
251
+
252
+ if (o->type == REDIS_STRING) {
253
+ /* Save a string value */
254
+ if ((n = rdbSaveStringObject(fp,o)) == -1) return -1;
255
+ nwritten += n;
256
+ } else if (o->type == REDIS_LIST) {
257
+ /* Save a list value */
258
+ if (o->encoding == REDIS_ENCODING_ZIPLIST) {
259
+ unsigned char *p;
260
+ unsigned char *vstr;
261
+ unsigned int vlen;
262
+ long long vlong;
263
+
264
+ if ((n = rdbSaveLen(fp,ziplistLen(o->ptr))) == -1) return -1;
265
+ nwritten += n;
266
+
267
+ p = ziplistIndex(o->ptr,0);
268
+ while(ziplistGet(p,&vstr,&vlen,&vlong)) {
269
+ if (vstr) {
270
+ if ((n = rdbSaveRawString(fp,vstr,vlen)) == -1)
271
+ return -1;
272
+ nwritten += n;
273
+ } else {
274
+ if ((n = rdbSaveLongLongAsStringObject(fp,vlong)) == -1)
275
+ return -1;
276
+ nwritten += n;
277
+ }
278
+ p = ziplistNext(o->ptr,p);
279
+ }
280
+ } else if (o->encoding == REDIS_ENCODING_LINKEDLIST) {
281
+ list *list = o->ptr;
282
+ listIter li;
283
+ listNode *ln;
284
+
285
+ if ((n = rdbSaveLen(fp,listLength(list))) == -1) return -1;
286
+ nwritten += n;
287
+
288
+ listRewind(list,&li);
289
+ while((ln = listNext(&li))) {
290
+ robj *eleobj = listNodeValue(ln);
291
+ if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
292
+ nwritten += n;
293
+ }
294
+ } else {
295
+ redisPanic("Unknown list encoding");
296
+ }
297
+ } else if (o->type == REDIS_SET) {
298
+ /* Save a set value */
299
+ if (o->encoding == REDIS_ENCODING_HT) {
300
+ dict *set = o->ptr;
301
+ dictIterator *di = dictGetIterator(set);
302
+ dictEntry *de;
303
+
304
+ if ((n = rdbSaveLen(fp,dictSize(set))) == -1) return -1;
305
+ nwritten += n;
306
+
307
+ while((de = dictNext(di)) != NULL) {
308
+ robj *eleobj = dictGetEntryKey(de);
309
+ if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
310
+ nwritten += n;
311
+ }
312
+ dictReleaseIterator(di);
313
+ } else if (o->encoding == REDIS_ENCODING_INTSET) {
314
+ intset *is = o->ptr;
315
+ int64_t llval;
316
+ int i = 0;
317
+
318
+ if ((n = rdbSaveLen(fp,intsetLen(is))) == -1) return -1;
319
+ nwritten += n;
320
+
321
+ while(intsetGet(is,i++,&llval)) {
322
+ if ((n = rdbSaveLongLongAsStringObject(fp,llval)) == -1) return -1;
323
+ nwritten += n;
324
+ }
325
+ } else {
326
+ redisPanic("Unknown set encoding");
327
+ }
328
+ } else if (o->type == REDIS_ZSET) {
329
+ /* Save a set value */
330
+ zset *zs = o->ptr;
331
+ dictIterator *di = dictGetIterator(zs->dict);
332
+ dictEntry *de;
333
+
334
+ if ((n = rdbSaveLen(fp,dictSize(zs->dict))) == -1) return -1;
335
+ nwritten += n;
336
+
337
+ while((de = dictNext(di)) != NULL) {
338
+ robj *eleobj = dictGetEntryKey(de);
339
+ double *score = dictGetEntryVal(de);
340
+
341
+ if ((n = rdbSaveStringObject(fp,eleobj)) == -1) return -1;
342
+ nwritten += n;
343
+ if ((n = rdbSaveDoubleValue(fp,*score)) == -1) return -1;
344
+ nwritten += n;
345
+ }
346
+ dictReleaseIterator(di);
347
+ } else if (o->type == REDIS_HASH) {
348
+ /* Save a hash value */
349
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
350
+ unsigned char *p = zipmapRewind(o->ptr);
351
+ unsigned int count = zipmapLen(o->ptr);
352
+ unsigned char *key, *val;
353
+ unsigned int klen, vlen;
354
+
355
+ if ((n = rdbSaveLen(fp,count)) == -1) return -1;
356
+ nwritten += n;
357
+
358
+ while((p = zipmapNext(p,&key,&klen,&val,&vlen)) != NULL) {
359
+ if ((n = rdbSaveRawString(fp,key,klen)) == -1) return -1;
360
+ nwritten += n;
361
+ if ((n = rdbSaveRawString(fp,val,vlen)) == -1) return -1;
362
+ nwritten += n;
363
+ }
364
+ } else {
365
+ dictIterator *di = dictGetIterator(o->ptr);
366
+ dictEntry *de;
367
+
368
+ if ((n = rdbSaveLen(fp,dictSize((dict*)o->ptr))) == -1) return -1;
369
+ nwritten += n;
370
+
371
+ while((de = dictNext(di)) != NULL) {
372
+ robj *key = dictGetEntryKey(de);
373
+ robj *val = dictGetEntryVal(de);
374
+
375
+ if ((n = rdbSaveStringObject(fp,key)) == -1) return -1;
376
+ nwritten += n;
377
+ if ((n = rdbSaveStringObject(fp,val)) == -1) return -1;
378
+ nwritten += n;
379
+ }
380
+ dictReleaseIterator(di);
381
+ }
382
+ } else {
383
+ redisPanic("Unknown object type");
384
+ }
385
+ return nwritten;
386
+ }
387
+
388
+ /* Return the length the object will have on disk if saved with
389
+ * the rdbSaveObject() function. Currently we use a trick to get
390
+ * this length with very little changes to the code. In the future
391
+ * we could switch to a faster solution. */
392
+ off_t rdbSavedObjectLen(robj *o) {
393
+ int len = rdbSaveObject(NULL,o);
394
+ redisAssert(len != -1);
395
+ return len;
396
+ }
397
+
398
+ /* Return the number of pages required to save this object in the swap file */
399
+ off_t rdbSavedObjectPages(robj *o) {
400
+ off_t bytes = rdbSavedObjectLen(o);
401
+ return (bytes+(server.vm_page_size-1))/server.vm_page_size;
402
+ }
403
+
404
+ /* Save the DB on disk. Return REDIS_ERR on error, REDIS_OK on success */
405
+ int rdbSave(char *filename) {
406
+ dictIterator *di = NULL;
407
+ dictEntry *de;
408
+ FILE *fp;
409
+ char tmpfile[256];
410
+ int j;
411
+ time_t now = time(NULL);
412
+
413
+ /* Wait for I/O therads to terminate, just in case this is a
414
+ * foreground-saving, to avoid seeking the swap file descriptor at the
415
+ * same time. */
416
+ if (server.vm_enabled)
417
+ waitEmptyIOJobsQueue();
418
+
419
+ snprintf(tmpfile,256,"temp-%d.rdb", (int) getpid());
420
+ fp = fopen(tmpfile,"w");
421
+ if (!fp) {
422
+ redisLog(REDIS_WARNING, "Failed saving the DB: %s", strerror(errno));
423
+ return REDIS_ERR;
424
+ }
425
+ if (fwrite("REDIS0001",9,1,fp) == 0) goto werr;
426
+ for (j = 0; j < server.dbnum; j++) {
427
+ redisDb *db = server.db+j;
428
+ dict *d = db->dict;
429
+ if (dictSize(d) == 0) continue;
430
+ di = dictGetSafeIterator(d);
431
+ if (!di) {
432
+ fclose(fp);
433
+ return REDIS_ERR;
434
+ }
435
+
436
+ /* Write the SELECT DB opcode */
437
+ if (rdbSaveType(fp,REDIS_SELECTDB) == -1) goto werr;
438
+ if (rdbSaveLen(fp,j) == -1) goto werr;
439
+
440
+ /* Iterate this DB writing every entry */
441
+ while((de = dictNext(di)) != NULL) {
442
+ sds keystr = dictGetEntryKey(de);
443
+ robj key, *o = dictGetEntryVal(de);
444
+ time_t expiretime;
445
+
446
+ initStaticStringObject(key,keystr);
447
+ expiretime = getExpire(db,&key);
448
+
449
+ /* Save the expire time */
450
+ if (expiretime != -1) {
451
+ /* If this key is already expired skip it */
452
+ if (expiretime < now) continue;
453
+ if (rdbSaveType(fp,REDIS_EXPIRETIME) == -1) goto werr;
454
+ if (rdbSaveTime(fp,expiretime) == -1) goto werr;
455
+ }
456
+ /* Save the key and associated value. This requires special
457
+ * handling if the value is swapped out. */
458
+ if (!server.vm_enabled || o->storage == REDIS_VM_MEMORY ||
459
+ o->storage == REDIS_VM_SWAPPING) {
460
+ /* Save type, key, value */
461
+ if (rdbSaveType(fp,o->type) == -1) goto werr;
462
+ if (rdbSaveStringObject(fp,&key) == -1) goto werr;
463
+ if (rdbSaveObject(fp,o) == -1) goto werr;
464
+ } else {
465
+ /* REDIS_VM_SWAPPED or REDIS_VM_LOADING */
466
+ robj *po;
467
+ /* Get a preview of the object in memory */
468
+ po = vmPreviewObject(o);
469
+ /* Save type, key, value */
470
+ if (rdbSaveType(fp,po->type) == -1) goto werr;
471
+ if (rdbSaveStringObject(fp,&key) == -1) goto werr;
472
+ if (rdbSaveObject(fp,po) == -1) goto werr;
473
+ /* Remove the loaded object from memory */
474
+ decrRefCount(po);
475
+ }
476
+ }
477
+ dictReleaseIterator(di);
478
+ }
479
+ /* EOF opcode */
480
+ if (rdbSaveType(fp,REDIS_EOF) == -1) goto werr;
481
+
482
+ /* Make sure data will not remain on the OS's output buffers */
483
+ fflush(fp);
484
+ fsync(fileno(fp));
485
+ fclose(fp);
486
+
487
+ /* Use RENAME to make sure the DB file is changed atomically only
488
+ * if the generate DB file is ok. */
489
+ if (rename(tmpfile,filename) == -1) {
490
+ redisLog(REDIS_WARNING,"Error moving temp DB file on the final destination: %s", strerror(errno));
491
+ unlink(tmpfile);
492
+ return REDIS_ERR;
493
+ }
494
+ redisLog(REDIS_NOTICE,"DB saved on disk");
495
+ server.dirty = 0;
496
+ server.lastsave = time(NULL);
497
+ return REDIS_OK;
498
+
499
+ werr:
500
+ fclose(fp);
501
+ unlink(tmpfile);
502
+ redisLog(REDIS_WARNING,"Write error saving DB on disk: %s", strerror(errno));
503
+ if (di) dictReleaseIterator(di);
504
+ return REDIS_ERR;
505
+ }
506
+
507
+ int rdbSaveBackground(char *filename) {
508
+ pid_t childpid;
509
+
510
+ if (server.bgsavechildpid != -1) return REDIS_ERR;
511
+ if (server.vm_enabled) waitEmptyIOJobsQueue();
512
+ server.dirty_before_bgsave = server.dirty;
513
+ if ((childpid = fork()) == 0) {
514
+ /* Child */
515
+ if (server.vm_enabled) vmReopenSwapFile();
516
+ if (server.ipfd > 0) close(server.ipfd);
517
+ if (server.sofd > 0) close(server.sofd);
518
+ if (rdbSave(filename) == REDIS_OK) {
519
+ _exit(0);
520
+ } else {
521
+ _exit(1);
522
+ }
523
+ } else {
524
+ /* Parent */
525
+ if (childpid == -1) {
526
+ redisLog(REDIS_WARNING,"Can't save in background: fork: %s",
527
+ strerror(errno));
528
+ return REDIS_ERR;
529
+ }
530
+ redisLog(REDIS_NOTICE,"Background saving started by pid %d",childpid);
531
+ server.bgsavechildpid = childpid;
532
+ updateDictResizePolicy();
533
+ return REDIS_OK;
534
+ }
535
+ return REDIS_OK; /* unreached */
536
+ }
537
+
538
+ void rdbRemoveTempFile(pid_t childpid) {
539
+ char tmpfile[256];
540
+
541
+ snprintf(tmpfile,256,"temp-%d.rdb", (int) childpid);
542
+ unlink(tmpfile);
543
+ }
544
+
545
+ int rdbLoadType(FILE *fp) {
546
+ unsigned char type;
547
+ if (fread(&type,1,1,fp) == 0) return -1;
548
+ return type;
549
+ }
550
+
551
+ time_t rdbLoadTime(FILE *fp) {
552
+ int32_t t32;
553
+ if (fread(&t32,4,1,fp) == 0) return -1;
554
+ return (time_t) t32;
555
+ }
556
+
557
+ /* Load an encoded length from the DB, see the REDIS_RDB_* defines on the top
558
+ * of this file for a description of how this are stored on disk.
559
+ *
560
+ * isencoded is set to 1 if the readed length is not actually a length but
561
+ * an "encoding type", check the above comments for more info */
562
+ uint32_t rdbLoadLen(FILE *fp, int *isencoded) {
563
+ unsigned char buf[2];
564
+ uint32_t len;
565
+ int type;
566
+
567
+ if (isencoded) *isencoded = 0;
568
+ if (fread(buf,1,1,fp) == 0) return REDIS_RDB_LENERR;
569
+ type = (buf[0]&0xC0)>>6;
570
+ if (type == REDIS_RDB_6BITLEN) {
571
+ /* Read a 6 bit len */
572
+ return buf[0]&0x3F;
573
+ } else if (type == REDIS_RDB_ENCVAL) {
574
+ /* Read a 6 bit len encoding type */
575
+ if (isencoded) *isencoded = 1;
576
+ return buf[0]&0x3F;
577
+ } else if (type == REDIS_RDB_14BITLEN) {
578
+ /* Read a 14 bit len */
579
+ if (fread(buf+1,1,1,fp) == 0) return REDIS_RDB_LENERR;
580
+ return ((buf[0]&0x3F)<<8)|buf[1];
581
+ } else {
582
+ /* Read a 32 bit len */
583
+ if (fread(&len,4,1,fp) == 0) return REDIS_RDB_LENERR;
584
+ return ntohl(len);
585
+ }
586
+ }
587
+
588
+ /* Load an integer-encoded object from file 'fp', with the specified
589
+ * encoding type 'enctype'. If encode is true the function may return
590
+ * an integer-encoded object as reply, otherwise the returned object
591
+ * will always be encoded as a raw string. */
592
+ robj *rdbLoadIntegerObject(FILE *fp, int enctype, int encode) {
593
+ unsigned char enc[4];
594
+ long long val;
595
+
596
+ if (enctype == REDIS_RDB_ENC_INT8) {
597
+ if (fread(enc,1,1,fp) == 0) return NULL;
598
+ val = (signed char)enc[0];
599
+ } else if (enctype == REDIS_RDB_ENC_INT16) {
600
+ uint16_t v;
601
+ if (fread(enc,2,1,fp) == 0) return NULL;
602
+ v = enc[0]|(enc[1]<<8);
603
+ val = (int16_t)v;
604
+ } else if (enctype == REDIS_RDB_ENC_INT32) {
605
+ uint32_t v;
606
+ if (fread(enc,4,1,fp) == 0) return NULL;
607
+ v = enc[0]|(enc[1]<<8)|(enc[2]<<16)|(enc[3]<<24);
608
+ val = (int32_t)v;
609
+ } else {
610
+ val = 0; /* anti-warning */
611
+ redisPanic("Unknown RDB integer encoding type");
612
+ }
613
+ if (encode)
614
+ return createStringObjectFromLongLong(val);
615
+ else
616
+ return createObject(REDIS_STRING,sdsfromlonglong(val));
617
+ }
618
+
619
+ robj *rdbLoadLzfStringObject(FILE*fp) {
620
+ unsigned int len, clen;
621
+ unsigned char *c = NULL;
622
+ sds val = NULL;
623
+
624
+ if ((clen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
625
+ if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
626
+ if ((c = zmalloc(clen)) == NULL) goto err;
627
+ if ((val = sdsnewlen(NULL,len)) == NULL) goto err;
628
+ if (fread(c,clen,1,fp) == 0) goto err;
629
+ if (lzf_decompress(c,clen,val,len) == 0) goto err;
630
+ zfree(c);
631
+ return createObject(REDIS_STRING,val);
632
+ err:
633
+ zfree(c);
634
+ sdsfree(val);
635
+ return NULL;
636
+ }
637
+
638
+ robj *rdbGenericLoadStringObject(FILE*fp, int encode) {
639
+ int isencoded;
640
+ uint32_t len;
641
+ sds val;
642
+
643
+ len = rdbLoadLen(fp,&isencoded);
644
+ if (isencoded) {
645
+ switch(len) {
646
+ case REDIS_RDB_ENC_INT8:
647
+ case REDIS_RDB_ENC_INT16:
648
+ case REDIS_RDB_ENC_INT32:
649
+ return rdbLoadIntegerObject(fp,len,encode);
650
+ case REDIS_RDB_ENC_LZF:
651
+ return rdbLoadLzfStringObject(fp);
652
+ default:
653
+ redisPanic("Unknown RDB encoding type");
654
+ }
655
+ }
656
+
657
+ if (len == REDIS_RDB_LENERR) return NULL;
658
+ val = sdsnewlen(NULL,len);
659
+ if (len && fread(val,len,1,fp) == 0) {
660
+ sdsfree(val);
661
+ return NULL;
662
+ }
663
+ return createObject(REDIS_STRING,val);
664
+ }
665
+
666
+ robj *rdbLoadStringObject(FILE *fp) {
667
+ return rdbGenericLoadStringObject(fp,0);
668
+ }
669
+
670
+ robj *rdbLoadEncodedStringObject(FILE *fp) {
671
+ return rdbGenericLoadStringObject(fp,1);
672
+ }
673
+
674
+ /* For information about double serialization check rdbSaveDoubleValue() */
675
+ int rdbLoadDoubleValue(FILE *fp, double *val) {
676
+ char buf[128];
677
+ unsigned char len;
678
+
679
+ if (fread(&len,1,1,fp) == 0) return -1;
680
+ switch(len) {
681
+ case 255: *val = R_NegInf; return 0;
682
+ case 254: *val = R_PosInf; return 0;
683
+ case 253: *val = R_Nan; return 0;
684
+ default:
685
+ if (fread(buf,len,1,fp) == 0) return -1;
686
+ buf[len] = '\0';
687
+ sscanf(buf, "%lg", val);
688
+ return 0;
689
+ }
690
+ }
691
+
692
+ /* Load a Redis object of the specified type from the specified file.
693
+ * On success a newly allocated object is returned, otherwise NULL. */
694
+ robj *rdbLoadObject(int type, FILE *fp) {
695
+ robj *o, *ele, *dec;
696
+ size_t len;
697
+ unsigned int i;
698
+
699
+ redisLog(REDIS_DEBUG,"LOADING OBJECT %d (at %d)\n",type,ftell(fp));
700
+ if (type == REDIS_STRING) {
701
+ /* Read string value */
702
+ if ((o = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
703
+ o = tryObjectEncoding(o);
704
+ } else if (type == REDIS_LIST) {
705
+ /* Read list value */
706
+ if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
707
+
708
+ /* Use a real list when there are too many entries */
709
+ if (len > server.list_max_ziplist_entries) {
710
+ o = createListObject();
711
+ } else {
712
+ o = createZiplistObject();
713
+ }
714
+
715
+ /* Load every single element of the list */
716
+ while(len--) {
717
+ if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
718
+
719
+ /* If we are using a ziplist and the value is too big, convert
720
+ * the object to a real list. */
721
+ if (o->encoding == REDIS_ENCODING_ZIPLIST &&
722
+ ele->encoding == REDIS_ENCODING_RAW &&
723
+ sdslen(ele->ptr) > server.list_max_ziplist_value)
724
+ listTypeConvert(o,REDIS_ENCODING_LINKEDLIST);
725
+
726
+ if (o->encoding == REDIS_ENCODING_ZIPLIST) {
727
+ dec = getDecodedObject(ele);
728
+ o->ptr = ziplistPush(o->ptr,dec->ptr,sdslen(dec->ptr),REDIS_TAIL);
729
+ decrRefCount(dec);
730
+ decrRefCount(ele);
731
+ } else {
732
+ ele = tryObjectEncoding(ele);
733
+ listAddNodeTail(o->ptr,ele);
734
+ }
735
+ }
736
+ } else if (type == REDIS_SET) {
737
+ /* Read list/set value */
738
+ if ((len = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
739
+
740
+ /* Use a regular set when there are too many entries. */
741
+ if (len > server.set_max_intset_entries) {
742
+ o = createSetObject();
743
+ /* It's faster to expand the dict to the right size asap in order
744
+ * to avoid rehashing */
745
+ if (len > DICT_HT_INITIAL_SIZE)
746
+ dictExpand(o->ptr,len);
747
+ } else {
748
+ o = createIntsetObject();
749
+ }
750
+
751
+ /* Load every single element of the list/set */
752
+ for (i = 0; i < len; i++) {
753
+ long long llval;
754
+ if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
755
+ ele = tryObjectEncoding(ele);
756
+
757
+ if (o->encoding == REDIS_ENCODING_INTSET) {
758
+ /* Fetch integer value from element */
759
+ if (isObjectRepresentableAsLongLong(ele,&llval) == REDIS_OK) {
760
+ o->ptr = intsetAdd(o->ptr,llval,NULL);
761
+ } else {
762
+ setTypeConvert(o,REDIS_ENCODING_HT);
763
+ dictExpand(o->ptr,len);
764
+ }
765
+ }
766
+
767
+ /* This will also be called when the set was just converted
768
+ * to regular hashtable encoded set */
769
+ if (o->encoding == REDIS_ENCODING_HT) {
770
+ dictAdd((dict*)o->ptr,ele,NULL);
771
+ } else {
772
+ decrRefCount(ele);
773
+ }
774
+ }
775
+ } else if (type == REDIS_ZSET) {
776
+ /* Read list/set value */
777
+ size_t zsetlen;
778
+ zset *zs;
779
+
780
+ if ((zsetlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
781
+ o = createZsetObject();
782
+ zs = o->ptr;
783
+ /* Load every single element of the list/set */
784
+ while(zsetlen--) {
785
+ robj *ele;
786
+ double score;
787
+ zskiplistNode *znode;
788
+
789
+ if ((ele = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
790
+ ele = tryObjectEncoding(ele);
791
+ if (rdbLoadDoubleValue(fp,&score) == -1) return NULL;
792
+ znode = zslInsert(zs->zsl,score,ele);
793
+ dictAdd(zs->dict,ele,&znode->score);
794
+ incrRefCount(ele); /* added to skiplist */
795
+ }
796
+ } else if (type == REDIS_HASH) {
797
+ size_t hashlen;
798
+
799
+ if ((hashlen = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR) return NULL;
800
+ o = createHashObject();
801
+ /* Too many entries? Use an hash table. */
802
+ if (hashlen > server.hash_max_zipmap_entries)
803
+ convertToRealHash(o);
804
+ /* Load every key/value, then set it into the zipmap or hash
805
+ * table, as needed. */
806
+ while(hashlen--) {
807
+ robj *key, *val;
808
+
809
+ if ((key = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
810
+ if ((val = rdbLoadEncodedStringObject(fp)) == NULL) return NULL;
811
+ /* If we are using a zipmap and there are too big values
812
+ * the object is converted to real hash table encoding. */
813
+ if (o->encoding != REDIS_ENCODING_HT &&
814
+ ((key->encoding == REDIS_ENCODING_RAW &&
815
+ sdslen(key->ptr) > server.hash_max_zipmap_value) ||
816
+ (val->encoding == REDIS_ENCODING_RAW &&
817
+ sdslen(val->ptr) > server.hash_max_zipmap_value)))
818
+ {
819
+ convertToRealHash(o);
820
+ }
821
+
822
+ if (o->encoding == REDIS_ENCODING_ZIPMAP) {
823
+ unsigned char *zm = o->ptr;
824
+ robj *deckey, *decval;
825
+
826
+ /* We need raw string objects to add them to the zipmap */
827
+ deckey = getDecodedObject(key);
828
+ decval = getDecodedObject(val);
829
+ zm = zipmapSet(zm,deckey->ptr,sdslen(deckey->ptr),
830
+ decval->ptr,sdslen(decval->ptr),NULL);
831
+ o->ptr = zm;
832
+ decrRefCount(deckey);
833
+ decrRefCount(decval);
834
+ decrRefCount(key);
835
+ decrRefCount(val);
836
+ } else {
837
+ key = tryObjectEncoding(key);
838
+ val = tryObjectEncoding(val);
839
+ dictAdd((dict*)o->ptr,key,val);
840
+ }
841
+ }
842
+ } else {
843
+ redisPanic("Unknown object type");
844
+ }
845
+ return o;
846
+ }
847
+
848
+ /* Mark that we are loading in the global state and setup the fields
849
+ * needed to provide loading stats. */
850
+ void startLoading(FILE *fp) {
851
+ struct stat sb;
852
+
853
+ /* Load the DB */
854
+ server.loading = 1;
855
+ server.loading_start_time = time(NULL);
856
+ if (fstat(fileno(fp), &sb) == -1) {
857
+ server.loading_total_bytes = 1; /* just to avoid division by zero */
858
+ } else {
859
+ server.loading_total_bytes = sb.st_size;
860
+ }
861
+ }
862
+
863
+ /* Refresh the loading progress info */
864
+ void loadingProgress(off_t pos) {
865
+ server.loading_loaded_bytes = pos;
866
+ }
867
+
868
+ /* Loading finished */
869
+ void stopLoading(void) {
870
+ server.loading = 0;
871
+ }
872
+
873
+ int rdbLoad(char *filename) {
874
+ FILE *fp;
875
+ uint32_t dbid;
876
+ int type, retval, rdbver;
877
+ int swap_all_values = 0;
878
+ redisDb *db = server.db+0;
879
+ char buf[1024];
880
+ time_t expiretime, now = time(NULL);
881
+ long loops = 0;
882
+
883
+ fp = fopen(filename,"r");
884
+ if (!fp) return REDIS_ERR;
885
+ if (fread(buf,9,1,fp) == 0) goto eoferr;
886
+ buf[9] = '\0';
887
+ if (memcmp(buf,"REDIS",5) != 0) {
888
+ fclose(fp);
889
+ redisLog(REDIS_WARNING,"Wrong signature trying to load DB from file");
890
+ return REDIS_ERR;
891
+ }
892
+ rdbver = atoi(buf+5);
893
+ if (rdbver != 1) {
894
+ fclose(fp);
895
+ redisLog(REDIS_WARNING,"Can't handle RDB format version %d",rdbver);
896
+ return REDIS_ERR;
897
+ }
898
+
899
+ startLoading(fp);
900
+ while(1) {
901
+ robj *key, *val;
902
+ int force_swapout;
903
+
904
+ expiretime = -1;
905
+
906
+ /* Serve the clients from time to time */
907
+ if (!(loops++ % 1000)) {
908
+ loadingProgress(ftello(fp));
909
+ aeProcessEvents(server.el, AE_FILE_EVENTS|AE_DONT_WAIT);
910
+ }
911
+
912
+ /* Read type. */
913
+ if ((type = rdbLoadType(fp)) == -1) goto eoferr;
914
+ if (type == REDIS_EXPIRETIME) {
915
+ if ((expiretime = rdbLoadTime(fp)) == -1) goto eoferr;
916
+ /* We read the time so we need to read the object type again */
917
+ if ((type = rdbLoadType(fp)) == -1) goto eoferr;
918
+ }
919
+ if (type == REDIS_EOF) break;
920
+ /* Handle SELECT DB opcode as a special case */
921
+ if (type == REDIS_SELECTDB) {
922
+ if ((dbid = rdbLoadLen(fp,NULL)) == REDIS_RDB_LENERR)
923
+ goto eoferr;
924
+ if (dbid >= (unsigned)server.dbnum) {
925
+ redisLog(REDIS_WARNING,"FATAL: Data file was created with a Redis server configured to handle more than %d databases. Exiting\n", server.dbnum);
926
+ exit(1);
927
+ }
928
+ db = server.db+dbid;
929
+ continue;
930
+ }
931
+ /* Read key */
932
+ if ((key = rdbLoadStringObject(fp)) == NULL) goto eoferr;
933
+ /* Read value */
934
+ if ((val = rdbLoadObject(type,fp)) == NULL) goto eoferr;
935
+ /* Check if the key already expired */
936
+ if (expiretime != -1 && expiretime < now) {
937
+ decrRefCount(key);
938
+ decrRefCount(val);
939
+ continue;
940
+ }
941
+ /* Add the new object in the hash table */
942
+ retval = dbAdd(db,key,val);
943
+ if (retval == REDIS_ERR) {
944
+ redisLog(REDIS_WARNING,"Loading DB, duplicated key (%s) found! Unrecoverable error, exiting now.", key->ptr);
945
+ exit(1);
946
+ }
947
+ /* Set the expire time if needed */
948
+ if (expiretime != -1) setExpire(db,key,expiretime);
949
+
950
+ /* Handle swapping while loading big datasets when VM is on */
951
+
952
+ /* If we detecter we are hopeless about fitting something in memory
953
+ * we just swap every new key on disk. Directly...
954
+ * Note that's important to check for this condition before resorting
955
+ * to random sampling, otherwise we may try to swap already
956
+ * swapped keys. */
957
+ if (swap_all_values) {
958
+ dictEntry *de = dictFind(db->dict,key->ptr);
959
+
960
+ /* de may be NULL since the key already expired */
961
+ if (de) {
962
+ vmpointer *vp;
963
+ val = dictGetEntryVal(de);
964
+
965
+ if (val->refcount == 1 &&
966
+ (vp = vmSwapObjectBlocking(val)) != NULL)
967
+ dictGetEntryVal(de) = vp;
968
+ }
969
+ decrRefCount(key);
970
+ continue;
971
+ }
972
+ decrRefCount(key);
973
+
974
+ /* Flush data on disk once 32 MB of additional RAM are used... */
975
+ force_swapout = 0;
976
+ if ((zmalloc_used_memory() - server.vm_max_memory) > 1024*1024*32)
977
+ force_swapout = 1;
978
+
979
+ /* If we have still some hope of having some value fitting memory
980
+ * then we try random sampling. */
981
+ if (!swap_all_values && server.vm_enabled && force_swapout) {
982
+ while (zmalloc_used_memory() > server.vm_max_memory) {
983
+ if (vmSwapOneObjectBlocking() == REDIS_ERR) break;
984
+ }
985
+ if (zmalloc_used_memory() > server.vm_max_memory)
986
+ swap_all_values = 1; /* We are already using too much mem */
987
+ }
988
+ }
989
+ fclose(fp);
990
+ stopLoading();
991
+ return REDIS_OK;
992
+
993
+ eoferr: /* unexpected end of file is handled here with a fatal exit */
994
+ redisLog(REDIS_WARNING,"Short read or OOM loading DB. Unrecoverable error, aborting now.");
995
+ exit(1);
996
+ return REDIS_ERR; /* Just to avoid warning */
997
+ }
998
+
999
+ /* A background saving child (BGSAVE) terminated its work. Handle this. */
1000
+ void backgroundSaveDoneHandler(int statloc) {
1001
+ int exitcode = WEXITSTATUS(statloc);
1002
+ int bysignal = WIFSIGNALED(statloc);
1003
+
1004
+ if (!bysignal && exitcode == 0) {
1005
+ redisLog(REDIS_NOTICE,
1006
+ "Background saving terminated with success");
1007
+ server.dirty = server.dirty - server.dirty_before_bgsave;
1008
+ server.lastsave = time(NULL);
1009
+ } else if (!bysignal && exitcode != 0) {
1010
+ redisLog(REDIS_WARNING, "Background saving error");
1011
+ } else {
1012
+ redisLog(REDIS_WARNING,
1013
+ "Background saving terminated by signal %d", WTERMSIG(statloc));
1014
+ rdbRemoveTempFile(server.bgsavechildpid);
1015
+ }
1016
+ server.bgsavechildpid = -1;
1017
+ /* Possibly there are slaves waiting for a BGSAVE in order to be served
1018
+ * (the first stage of SYNC is a bulk transfer of dump.rdb) */
1019
+ updateSlavesWaitingBgsave(exitcode == 0 ? REDIS_OK : REDIS_ERR);
1020
+ }