couchbase-memcached 1.2.8

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 (539) hide show
  1. data.tar.gz.sig +2 -0
  2. data/BENCHMARKS +134 -0
  3. data/CHANGELOG +127 -0
  4. data/LICENSE +184 -0
  5. data/Manifest +535 -0
  6. data/README +118 -0
  7. data/Rakefile +83 -0
  8. data/TODO +4 -0
  9. data/couchbase-memcached.gemspec +33 -0
  10. data/ext/extconf-make.rb +25 -0
  11. data/ext/extconf.rb +91 -0
  12. data/ext/libmemcached-0.50/AUTHORS +11 -0
  13. data/ext/libmemcached-0.50/COPYING +33 -0
  14. data/ext/libmemcached-0.50/ChangeLog +392 -0
  15. data/ext/libmemcached-0.50/Makefile.am +114 -0
  16. data/ext/libmemcached-0.50/Makefile.in +4232 -0
  17. data/ext/libmemcached-0.50/NEWS +1 -0
  18. data/ext/libmemcached-0.50/README +43 -0
  19. data/ext/libmemcached-0.50/README.FIRST +31 -0
  20. data/ext/libmemcached-0.50/README.win32 +25 -0
  21. data/ext/libmemcached-0.50/THANKS +14 -0
  22. data/ext/libmemcached-0.50/TODO +11 -0
  23. data/ext/libmemcached-0.50/aclocal.m4 +1077 -0
  24. data/ext/libmemcached-0.50/clients/client_options.h +45 -0
  25. data/ext/libmemcached-0.50/clients/execute.cc +131 -0
  26. data/ext/libmemcached-0.50/clients/execute.h +30 -0
  27. data/ext/libmemcached-0.50/clients/generator.cc +96 -0
  28. data/ext/libmemcached-0.50/clients/generator.h +36 -0
  29. data/ext/libmemcached-0.50/clients/include.am +116 -0
  30. data/ext/libmemcached-0.50/clients/memaslap.c +908 -0
  31. data/ext/libmemcached-0.50/clients/memcapable.cc +2094 -0
  32. data/ext/libmemcached-0.50/clients/memcat.cc +242 -0
  33. data/ext/libmemcached-0.50/clients/memcp.cc +317 -0
  34. data/ext/libmemcached-0.50/clients/memdump.cc +183 -0
  35. data/ext/libmemcached-0.50/clients/memerror.cc +102 -0
  36. data/ext/libmemcached-0.50/clients/memflush.cc +154 -0
  37. data/ext/libmemcached-0.50/clients/memparse.cc +68 -0
  38. data/ext/libmemcached-0.50/clients/memrm.cc +177 -0
  39. data/ext/libmemcached-0.50/clients/memslap.cc +495 -0
  40. data/ext/libmemcached-0.50/clients/memstat.cc +349 -0
  41. data/ext/libmemcached-0.50/clients/ms_atomic.h +69 -0
  42. data/ext/libmemcached-0.50/clients/ms_conn.c +3413 -0
  43. data/ext/libmemcached-0.50/clients/ms_conn.h +241 -0
  44. data/ext/libmemcached-0.50/clients/ms_memslap.h +132 -0
  45. data/ext/libmemcached-0.50/clients/ms_setting.c +1068 -0
  46. data/ext/libmemcached-0.50/clients/ms_setting.h +181 -0
  47. data/ext/libmemcached-0.50/clients/ms_sigsegv.c +126 -0
  48. data/ext/libmemcached-0.50/clients/ms_sigsegv.h +34 -0
  49. data/ext/libmemcached-0.50/clients/ms_stats.c +307 -0
  50. data/ext/libmemcached-0.50/clients/ms_stats.h +69 -0
  51. data/ext/libmemcached-0.50/clients/ms_task.c +1114 -0
  52. data/ext/libmemcached-0.50/clients/ms_task.h +94 -0
  53. data/ext/libmemcached-0.50/clients/ms_thread.c +351 -0
  54. data/ext/libmemcached-0.50/clients/ms_thread.h +78 -0
  55. data/ext/libmemcached-0.50/clients/utilities.cc +231 -0
  56. data/ext/libmemcached-0.50/clients/utilities.h +64 -0
  57. data/ext/libmemcached-0.50/config.h.in +647 -0
  58. data/ext/libmemcached-0.50/config/autorun.sh +126 -0
  59. data/ext/libmemcached-0.50/config/compile +143 -0
  60. data/ext/libmemcached-0.50/config/config.guess +1517 -0
  61. data/ext/libmemcached-0.50/config/config.rpath +666 -0
  62. data/ext/libmemcached-0.50/config/config.sub +1760 -0
  63. data/ext/libmemcached-0.50/config/depcomp +630 -0
  64. data/ext/libmemcached-0.50/config/install-sh +520 -0
  65. data/ext/libmemcached-0.50/config/ltmain.sh +9642 -0
  66. data/ext/libmemcached-0.50/config/missing +376 -0
  67. data/ext/libmemcached-0.50/config/pandora-plugin +752 -0
  68. data/ext/libmemcached-0.50/config/uncrustify.cfg +1112 -0
  69. data/ext/libmemcached-0.50/configure +27103 -0
  70. data/ext/libmemcached-0.50/configure.ac +186 -0
  71. data/ext/libmemcached-0.50/docs/conf.py.in +354 -0
  72. data/ext/libmemcached-0.50/docs/include.am +240 -0
  73. data/ext/libmemcached-0.50/docs/man/hashkit_clone.3 +88 -0
  74. data/ext/libmemcached-0.50/docs/man/hashkit_crc32.3 +105 -0
  75. data/ext/libmemcached-0.50/docs/man/hashkit_create.3 +88 -0
  76. data/ext/libmemcached-0.50/docs/man/hashkit_fnv1_32.3 +105 -0
  77. data/ext/libmemcached-0.50/docs/man/hashkit_fnv1_64.3 +105 -0
  78. data/ext/libmemcached-0.50/docs/man/hashkit_fnv1a_32.3 +105 -0
  79. data/ext/libmemcached-0.50/docs/man/hashkit_fnv1a_64.3 +105 -0
  80. data/ext/libmemcached-0.50/docs/man/hashkit_free.3 +88 -0
  81. data/ext/libmemcached-0.50/docs/man/hashkit_functions.3 +105 -0
  82. data/ext/libmemcached-0.50/docs/man/hashkit_hsieh.3 +105 -0
  83. data/ext/libmemcached-0.50/docs/man/hashkit_is_allocated.3 +88 -0
  84. data/ext/libmemcached-0.50/docs/man/hashkit_jenkins.3 +105 -0
  85. data/ext/libmemcached-0.50/docs/man/hashkit_md5.3 +105 -0
  86. data/ext/libmemcached-0.50/docs/man/hashkit_murmur.3 +105 -0
  87. data/ext/libmemcached-0.50/docs/man/hashkit_value.3 +66 -0
  88. data/ext/libmemcached-0.50/docs/man/libhashkit.3 +57 -0
  89. data/ext/libmemcached-0.50/docs/man/libmemcached.3 +208 -0
  90. data/ext/libmemcached-0.50/docs/man/libmemcached_check_configuration.3 +293 -0
  91. data/ext/libmemcached-0.50/docs/man/libmemcached_configuration.3 +293 -0
  92. data/ext/libmemcached-0.50/docs/man/libmemcached_examples.3 +144 -0
  93. data/ext/libmemcached-0.50/docs/man/libmemcachedutil.3 +68 -0
  94. data/ext/libmemcached-0.50/docs/man/memaslap.1 +1222 -0
  95. data/ext/libmemcached-0.50/docs/man/memcached.3 +293 -0
  96. data/ext/libmemcached-0.50/docs/man/memcached_add.3 +132 -0
  97. data/ext/libmemcached-0.50/docs/man/memcached_add_by_key.3 +132 -0
  98. data/ext/libmemcached-0.50/docs/man/memcached_analyze.3 +77 -0
  99. data/ext/libmemcached-0.50/docs/man/memcached_append.3 +111 -0
  100. data/ext/libmemcached-0.50/docs/man/memcached_append_by_key.3 +111 -0
  101. data/ext/libmemcached-0.50/docs/man/memcached_behavior_get.3 +333 -0
  102. data/ext/libmemcached-0.50/docs/man/memcached_behavior_set.3 +333 -0
  103. data/ext/libmemcached-0.50/docs/man/memcached_callback_get.3 +159 -0
  104. data/ext/libmemcached-0.50/docs/man/memcached_callback_set.3 +159 -0
  105. data/ext/libmemcached-0.50/docs/man/memcached_cas.3 +91 -0
  106. data/ext/libmemcached-0.50/docs/man/memcached_cas_by_key.3 +91 -0
  107. data/ext/libmemcached-0.50/docs/man/memcached_clone.3 +99 -0
  108. data/ext/libmemcached-0.50/docs/man/memcached_create.3 +99 -0
  109. data/ext/libmemcached-0.50/docs/man/memcached_decrement.3 +124 -0
  110. data/ext/libmemcached-0.50/docs/man/memcached_decrement_with_initial.3 +124 -0
  111. data/ext/libmemcached-0.50/docs/man/memcached_delete.3 +83 -0
  112. data/ext/libmemcached-0.50/docs/man/memcached_delete_by_key.3 +83 -0
  113. data/ext/libmemcached-0.50/docs/man/memcached_destroy_sasl_auth_data.3 +95 -0
  114. data/ext/libmemcached-0.50/docs/man/memcached_dump.3 +77 -0
  115. data/ext/libmemcached-0.50/docs/man/memcached_fetch.3 +174 -0
  116. data/ext/libmemcached-0.50/docs/man/memcached_fetch_execute.3 +174 -0
  117. data/ext/libmemcached-0.50/docs/man/memcached_fetch_result.3 +174 -0
  118. data/ext/libmemcached-0.50/docs/man/memcached_flush_buffers.3 +72 -0
  119. data/ext/libmemcached-0.50/docs/man/memcached_free.3 +99 -0
  120. data/ext/libmemcached-0.50/docs/man/memcached_generate_hash.3 +85 -0
  121. data/ext/libmemcached-0.50/docs/man/memcached_generate_hash_value.3 +85 -0
  122. data/ext/libmemcached-0.50/docs/man/memcached_get.3 +174 -0
  123. data/ext/libmemcached-0.50/docs/man/memcached_get_by_key.3 +174 -0
  124. data/ext/libmemcached-0.50/docs/man/memcached_get_memory_allocators.3 +111 -0
  125. data/ext/libmemcached-0.50/docs/man/memcached_get_sasl_callbacks.3 +95 -0
  126. data/ext/libmemcached-0.50/docs/man/memcached_get_user_data.3 +79 -0
  127. data/ext/libmemcached-0.50/docs/man/memcached_increment.3 +124 -0
  128. data/ext/libmemcached-0.50/docs/man/memcached_increment_with_initial.3 +124 -0
  129. data/ext/libmemcached-0.50/docs/man/memcached_lib_version.3 +76 -0
  130. data/ext/libmemcached-0.50/docs/man/memcached_mget.3 +174 -0
  131. data/ext/libmemcached-0.50/docs/man/memcached_mget_by_key.3 +174 -0
  132. data/ext/libmemcached-0.50/docs/man/memcached_mget_execute.3 +174 -0
  133. data/ext/libmemcached-0.50/docs/man/memcached_mget_execute_by_key.3 +174 -0
  134. data/ext/libmemcached-0.50/docs/man/memcached_pool_behavior_get.3 +139 -0
  135. data/ext/libmemcached-0.50/docs/man/memcached_pool_behavior_set.3 +139 -0
  136. data/ext/libmemcached-0.50/docs/man/memcached_pool_create.3 +139 -0
  137. data/ext/libmemcached-0.50/docs/man/memcached_pool_destroy.3 +139 -0
  138. data/ext/libmemcached-0.50/docs/man/memcached_pool_pop.3 +139 -0
  139. data/ext/libmemcached-0.50/docs/man/memcached_pool_push.3 +139 -0
  140. data/ext/libmemcached-0.50/docs/man/memcached_pool_st.3 +139 -0
  141. data/ext/libmemcached-0.50/docs/man/memcached_prepend.3 +111 -0
  142. data/ext/libmemcached-0.50/docs/man/memcached_prepend_by_key.3 +111 -0
  143. data/ext/libmemcached-0.50/docs/man/memcached_quit.3 +74 -0
  144. data/ext/libmemcached-0.50/docs/man/memcached_replace.3 +132 -0
  145. data/ext/libmemcached-0.50/docs/man/memcached_replace_by_key.3 +132 -0
  146. data/ext/libmemcached-0.50/docs/man/memcached_sasl_set_auth_data.3 +95 -0
  147. data/ext/libmemcached-0.50/docs/man/memcached_server_add.3 +141 -0
  148. data/ext/libmemcached-0.50/docs/man/memcached_server_count.3 +141 -0
  149. data/ext/libmemcached-0.50/docs/man/memcached_server_cursor.3 +141 -0
  150. data/ext/libmemcached-0.50/docs/man/memcached_server_list.3 +141 -0
  151. data/ext/libmemcached-0.50/docs/man/memcached_server_list_append.3 +111 -0
  152. data/ext/libmemcached-0.50/docs/man/memcached_server_list_count.3 +111 -0
  153. data/ext/libmemcached-0.50/docs/man/memcached_server_list_free.3 +111 -0
  154. data/ext/libmemcached-0.50/docs/man/memcached_server_push.3 +141 -0
  155. data/ext/libmemcached-0.50/docs/man/memcached_servers_parse.3 +111 -0
  156. data/ext/libmemcached-0.50/docs/man/memcached_set.3 +132 -0
  157. data/ext/libmemcached-0.50/docs/man/memcached_set_by_key.3 +132 -0
  158. data/ext/libmemcached-0.50/docs/man/memcached_set_memory_allocators.3 +111 -0
  159. data/ext/libmemcached-0.50/docs/man/memcached_set_sasl_callbacks.3 +95 -0
  160. data/ext/libmemcached-0.50/docs/man/memcached_set_user_data.3 +79 -0
  161. data/ext/libmemcached-0.50/docs/man/memcached_stat.3 +116 -0
  162. data/ext/libmemcached-0.50/docs/man/memcached_stat_execute.3 +116 -0
  163. data/ext/libmemcached-0.50/docs/man/memcached_stat_get_keys.3 +116 -0
  164. data/ext/libmemcached-0.50/docs/man/memcached_stat_get_value.3 +116 -0
  165. data/ext/libmemcached-0.50/docs/man/memcached_stat_servername.3 +116 -0
  166. data/ext/libmemcached-0.50/docs/man/memcached_strerror.3 +69 -0
  167. data/ext/libmemcached-0.50/docs/man/memcached_verbosity.3 +66 -0
  168. data/ext/libmemcached-0.50/docs/man/memcached_version.3 +76 -0
  169. data/ext/libmemcached-0.50/docs/man/memcapable.1 +92 -0
  170. data/ext/libmemcached-0.50/docs/man/memcat.1 +71 -0
  171. data/ext/libmemcached-0.50/docs/man/memcp.1 +77 -0
  172. data/ext/libmemcached-0.50/docs/man/memdump.1 +66 -0
  173. data/ext/libmemcached-0.50/docs/man/memerror.1 +65 -0
  174. data/ext/libmemcached-0.50/docs/man/memflush.1 +73 -0
  175. data/ext/libmemcached-0.50/docs/man/memrm.1 +72 -0
  176. data/ext/libmemcached-0.50/docs/man/memslap.1 +59 -0
  177. data/ext/libmemcached-0.50/docs/man/memstat.1 +70 -0
  178. data/ext/libmemcached-0.50/example/include.am +24 -0
  179. data/ext/libmemcached-0.50/example/interface_v0.c +594 -0
  180. data/ext/libmemcached-0.50/example/interface_v1.c +411 -0
  181. data/ext/libmemcached-0.50/example/memcached_light.c +474 -0
  182. data/ext/libmemcached-0.50/example/memcached_light.h +7 -0
  183. data/ext/libmemcached-0.50/example/storage.c +172 -0
  184. data/ext/libmemcached-0.50/example/storage.h +27 -0
  185. data/ext/libmemcached-0.50/example/storage_innodb.c +535 -0
  186. data/ext/libmemcached-0.50/libhashkit/algorithm.cc +69 -0
  187. data/ext/libmemcached-0.50/libhashkit/algorithm.h +96 -0
  188. data/ext/libmemcached-0.50/libhashkit/behavior.cc +9 -0
  189. data/ext/libmemcached-0.50/libhashkit/behavior.h +26 -0
  190. data/ext/libmemcached-0.50/libhashkit/common.h +33 -0
  191. data/ext/libmemcached-0.50/libhashkit/configure.h.in +19 -0
  192. data/ext/libmemcached-0.50/libhashkit/crc32.cc +86 -0
  193. data/ext/libmemcached-0.50/libhashkit/digest.cc +62 -0
  194. data/ext/libmemcached-0.50/libhashkit/digest.h +30 -0
  195. data/ext/libmemcached-0.50/libhashkit/fnv.cc +75 -0
  196. data/ext/libmemcached-0.50/libhashkit/function.cc +156 -0
  197. data/ext/libmemcached-0.50/libhashkit/function.h +44 -0
  198. data/ext/libmemcached-0.50/libhashkit/hashkit.cc +100 -0
  199. data/ext/libmemcached-0.50/libhashkit/hashkit.h +95 -0
  200. data/ext/libmemcached-0.50/libhashkit/hashkit.hpp +97 -0
  201. data/ext/libmemcached-0.50/libhashkit/hsieh.cc +70 -0
  202. data/ext/libmemcached-0.50/libhashkit/include.am +69 -0
  203. data/ext/libmemcached-0.50/libhashkit/jenkins.cc +214 -0
  204. data/ext/libmemcached-0.50/libhashkit/ketama.cc +164 -0
  205. data/ext/libmemcached-0.50/libhashkit/md5.cc +367 -0
  206. data/ext/libmemcached-0.50/libhashkit/murmur.cc +77 -0
  207. data/ext/libmemcached-0.50/libhashkit/one_at_a_time.cc +34 -0
  208. data/ext/libmemcached-0.50/libhashkit/str_algorithm.cc +58 -0
  209. data/ext/libmemcached-0.50/libhashkit/str_algorithm.h +48 -0
  210. data/ext/libmemcached-0.50/libhashkit/strerror.cc +25 -0
  211. data/ext/libmemcached-0.50/libhashkit/strerror.h +23 -0
  212. data/ext/libmemcached-0.50/libhashkit/types.h +90 -0
  213. data/ext/libmemcached-0.50/libhashkit/visibility.h +48 -0
  214. data/ext/libmemcached-0.50/libmemcached/allocators.cc +119 -0
  215. data/ext/libmemcached-0.50/libmemcached/allocators.h +87 -0
  216. data/ext/libmemcached-0.50/libmemcached/analyze.cc +110 -0
  217. data/ext/libmemcached-0.50/libmemcached/analyze.h +66 -0
  218. data/ext/libmemcached-0.50/libmemcached/array.c +128 -0
  219. data/ext/libmemcached-0.50/libmemcached/array.h +75 -0
  220. data/ext/libmemcached-0.50/libmemcached/auto.cc +383 -0
  221. data/ext/libmemcached-0.50/libmemcached/auto.h +111 -0
  222. data/ext/libmemcached-0.50/libmemcached/basic_string.h +55 -0
  223. data/ext/libmemcached-0.50/libmemcached/behavior.cc +590 -0
  224. data/ext/libmemcached-0.50/libmemcached/behavior.h +86 -0
  225. data/ext/libmemcached-0.50/libmemcached/byteorder.cc +90 -0
  226. data/ext/libmemcached-0.50/libmemcached/byteorder.h +52 -0
  227. data/ext/libmemcached-0.50/libmemcached/callback.cc +160 -0
  228. data/ext/libmemcached-0.50/libmemcached/callback.h +61 -0
  229. data/ext/libmemcached-0.50/libmemcached/common.h +182 -0
  230. data/ext/libmemcached-0.50/libmemcached/configure.h.in +52 -0
  231. data/ext/libmemcached-0.50/libmemcached/connect.cc +626 -0
  232. data/ext/libmemcached-0.50/libmemcached/constants.h +167 -0
  233. data/ext/libmemcached-0.50/libmemcached/delete.cc +266 -0
  234. data/ext/libmemcached-0.50/libmemcached/delete.h +57 -0
  235. data/ext/libmemcached-0.50/libmemcached/do.cc +100 -0
  236. data/ext/libmemcached-0.50/libmemcached/do.hpp +49 -0
  237. data/ext/libmemcached-0.50/libmemcached/dump.cc +107 -0
  238. data/ext/libmemcached-0.50/libmemcached/dump.h +51 -0
  239. data/ext/libmemcached-0.50/libmemcached/error.cc +419 -0
  240. data/ext/libmemcached-0.50/libmemcached/error.h +61 -0
  241. data/ext/libmemcached-0.50/libmemcached/error.hpp +87 -0
  242. data/ext/libmemcached-0.50/libmemcached/exception.hpp +63 -0
  243. data/ext/libmemcached-0.50/libmemcached/fetch.cc +267 -0
  244. data/ext/libmemcached-0.50/libmemcached/fetch.h +53 -0
  245. data/ext/libmemcached-0.50/libmemcached/flush.cc +149 -0
  246. data/ext/libmemcached-0.50/libmemcached/flush.h +49 -0
  247. data/ext/libmemcached-0.50/libmemcached/flush_buffers.cc +66 -0
  248. data/ext/libmemcached-0.50/libmemcached/flush_buffers.h +49 -0
  249. data/ext/libmemcached-0.50/libmemcached/get.cc +842 -0
  250. data/ext/libmemcached-0.50/libmemcached/get.h +135 -0
  251. data/ext/libmemcached-0.50/libmemcached/hash.cc +178 -0
  252. data/ext/libmemcached-0.50/libmemcached/hash.h +68 -0
  253. data/ext/libmemcached-0.50/libmemcached/hosts.cc +516 -0
  254. data/ext/libmemcached-0.50/libmemcached/include.am +183 -0
  255. data/ext/libmemcached-0.50/libmemcached/initialize_query.cc +70 -0
  256. data/ext/libmemcached-0.50/libmemcached/initialize_query.h +51 -0
  257. data/ext/libmemcached-0.50/libmemcached/internal.h +46 -0
  258. data/ext/libmemcached-0.50/libmemcached/io.cc +920 -0
  259. data/ext/libmemcached-0.50/libmemcached/io.h +119 -0
  260. data/ext/libmemcached-0.50/libmemcached/is.h +48 -0
  261. data/ext/libmemcached-0.50/libmemcached/key.cc +23 -0
  262. data/ext/libmemcached-0.50/libmemcached/libmemcached_probes.d +30 -0
  263. data/ext/libmemcached-0.50/libmemcached/libmemcached_probes.h +118 -0
  264. data/ext/libmemcached-0.50/libmemcached/memcached.cc +437 -0
  265. data/ext/libmemcached-0.50/libmemcached/memcached.h +214 -0
  266. data/ext/libmemcached-0.50/libmemcached/memcached.hpp +799 -0
  267. data/ext/libmemcached-0.50/libmemcached/memcached/README.txt +7 -0
  268. data/ext/libmemcached-0.50/libmemcached/memcached/protocol_binary.h +726 -0
  269. data/ext/libmemcached-0.50/libmemcached/memcached/vbucket.h +26 -0
  270. data/ext/libmemcached-0.50/libmemcached/memcached_util.h +44 -0
  271. data/ext/libmemcached-0.50/libmemcached/memory.h +79 -0
  272. data/ext/libmemcached-0.50/libmemcached/options.cc +178 -0
  273. data/ext/libmemcached-0.50/libmemcached/options.h +49 -0
  274. data/ext/libmemcached-0.50/libmemcached/options.hpp +56 -0
  275. data/ext/libmemcached-0.50/libmemcached/options/context.h +151 -0
  276. data/ext/libmemcached-0.50/libmemcached/options/include.am +19 -0
  277. data/ext/libmemcached-0.50/libmemcached/options/parser.am +0 -0
  278. data/ext/libmemcached-0.50/libmemcached/options/parser.cc +2324 -0
  279. data/ext/libmemcached-0.50/libmemcached/options/parser.h +122 -0
  280. data/ext/libmemcached-0.50/libmemcached/options/scanner.cc +3203 -0
  281. data/ext/libmemcached-0.50/libmemcached/options/scanner.h +479 -0
  282. data/ext/libmemcached-0.50/libmemcached/options/server.h +60 -0
  283. data/ext/libmemcached-0.50/libmemcached/options/symbol.h +57 -0
  284. data/ext/libmemcached-0.50/libmemcached/parse.cc +110 -0
  285. data/ext/libmemcached-0.50/libmemcached/parse.h +23 -0
  286. data/ext/libmemcached-0.50/libmemcached/platform.h +56 -0
  287. data/ext/libmemcached-0.50/libmemcached/prefix_key.cc +65 -0
  288. data/ext/libmemcached-0.50/libmemcached/prefix_key.h +49 -0
  289. data/ext/libmemcached-0.50/libmemcached/protocol/ascii_handler.c +963 -0
  290. data/ext/libmemcached-0.50/libmemcached/protocol/ascii_handler.h +40 -0
  291. data/ext/libmemcached-0.50/libmemcached/protocol/binary_handler.c +1121 -0
  292. data/ext/libmemcached-0.50/libmemcached/protocol/binary_handler.h +47 -0
  293. data/ext/libmemcached-0.50/libmemcached/protocol/cache.c +149 -0
  294. data/ext/libmemcached-0.50/libmemcached/protocol/cache.h +116 -0
  295. data/ext/libmemcached-0.50/libmemcached/protocol/callback.h +418 -0
  296. data/ext/libmemcached-0.50/libmemcached/protocol/common.h +163 -0
  297. data/ext/libmemcached-0.50/libmemcached/protocol/include.am +26 -0
  298. data/ext/libmemcached-0.50/libmemcached/protocol/pedantic.c +202 -0
  299. data/ext/libmemcached-0.50/libmemcached/protocol/protocol_handler.c +365 -0
  300. data/ext/libmemcached-0.50/libmemcached/protocol_handler.h +215 -0
  301. data/ext/libmemcached-0.50/libmemcached/purge.cc +90 -0
  302. data/ext/libmemcached-0.50/libmemcached/quit.cc +139 -0
  303. data/ext/libmemcached-0.50/libmemcached/quit.h +55 -0
  304. data/ext/libmemcached-0.50/libmemcached/response.cc +619 -0
  305. data/ext/libmemcached-0.50/libmemcached/response.h +57 -0
  306. data/ext/libmemcached-0.50/libmemcached/result.cc +173 -0
  307. data/ext/libmemcached-0.50/libmemcached/result.h +100 -0
  308. data/ext/libmemcached-0.50/libmemcached/return.h +98 -0
  309. data/ext/libmemcached-0.50/libmemcached/sasl.c +408 -0
  310. data/ext/libmemcached-0.50/libmemcached/sasl.h +86 -0
  311. data/ext/libmemcached-0.50/libmemcached/server.cc +351 -0
  312. data/ext/libmemcached-0.50/libmemcached/server.h +169 -0
  313. data/ext/libmemcached-0.50/libmemcached/server_list.cc +88 -0
  314. data/ext/libmemcached-0.50/libmemcached/server_list.h +77 -0
  315. data/ext/libmemcached-0.50/libmemcached/stats.cc +623 -0
  316. data/ext/libmemcached-0.50/libmemcached/stats.h +96 -0
  317. data/ext/libmemcached-0.50/libmemcached/storage.cc +567 -0
  318. data/ext/libmemcached-0.50/libmemcached/storage.h +133 -0
  319. data/ext/libmemcached-0.50/libmemcached/strerror.cc +189 -0
  320. data/ext/libmemcached-0.50/libmemcached/strerror.h +50 -0
  321. data/ext/libmemcached-0.50/libmemcached/string.cc +253 -0
  322. data/ext/libmemcached-0.50/libmemcached/string.h +121 -0
  323. data/ext/libmemcached-0.50/libmemcached/touch.cc +106 -0
  324. data/ext/libmemcached-0.50/libmemcached/touch.h +59 -0
  325. data/ext/libmemcached-0.50/libmemcached/types.h +117 -0
  326. data/ext/libmemcached-0.50/libmemcached/util.h +40 -0
  327. data/ext/libmemcached-0.50/libmemcached/util/flush.cc +61 -0
  328. data/ext/libmemcached-0.50/libmemcached/util/flush.h +50 -0
  329. data/ext/libmemcached-0.50/libmemcached/util/include.am +34 -0
  330. data/ext/libmemcached-0.50/libmemcached/util/ping.cc +62 -0
  331. data/ext/libmemcached-0.50/libmemcached/util/ping.h +49 -0
  332. data/ext/libmemcached-0.50/libmemcached/util/pool.cc +392 -0
  333. data/ext/libmemcached-0.50/libmemcached/util/pool.h +78 -0
  334. data/ext/libmemcached-0.50/libmemcached/util/version.cc +87 -0
  335. data/ext/libmemcached-0.50/libmemcached/util/version.h +53 -0
  336. data/ext/libmemcached-0.50/libmemcached/verbosity.cc +97 -0
  337. data/ext/libmemcached-0.50/libmemcached/verbosity.h +50 -0
  338. data/ext/libmemcached-0.50/libmemcached/version.cc +214 -0
  339. data/ext/libmemcached-0.50/libmemcached/version.h +52 -0
  340. data/ext/libmemcached-0.50/libmemcached/virtual_bucket.c +118 -0
  341. data/ext/libmemcached-0.50/libmemcached/virtual_bucket.h +59 -0
  342. data/ext/libmemcached-0.50/libmemcached/visibility.h +51 -0
  343. data/ext/libmemcached-0.50/libmemcached/watchpoint.h +110 -0
  344. data/ext/libmemcached-0.50/libtest/callbacks.h +21 -0
  345. data/ext/libmemcached-0.50/libtest/collection.h +19 -0
  346. data/ext/libmemcached-0.50/libtest/common.h +50 -0
  347. data/ext/libmemcached-0.50/libtest/core.h +11 -0
  348. data/ext/libmemcached-0.50/libtest/error.h +18 -0
  349. data/ext/libmemcached-0.50/libtest/failed.h +52 -0
  350. data/ext/libmemcached-0.50/libtest/framework.cc +57 -0
  351. data/ext/libmemcached-0.50/libtest/framework.h +137 -0
  352. data/ext/libmemcached-0.50/libtest/get.h +22 -0
  353. data/ext/libmemcached-0.50/libtest/include.am +52 -0
  354. data/ext/libmemcached-0.50/libtest/runner.h +19 -0
  355. data/ext/libmemcached-0.50/libtest/server.c +355 -0
  356. data/ext/libmemcached-0.50/libtest/server.h +43 -0
  357. data/ext/libmemcached-0.50/libtest/stats.h +30 -0
  358. data/ext/libmemcached-0.50/libtest/strerror.h +14 -0
  359. data/ext/libmemcached-0.50/libtest/test.cc +319 -0
  360. data/ext/libmemcached-0.50/libtest/test.h +162 -0
  361. data/ext/libmemcached-0.50/libtest/test.hpp +46 -0
  362. data/ext/libmemcached-0.50/libtest/visibility.h +69 -0
  363. data/ext/libmemcached-0.50/m4/ac_cxx_header_stdcxx_98.m4 +83 -0
  364. data/ext/libmemcached-0.50/m4/acx_pthread.m4 +271 -0
  365. data/ext/libmemcached-0.50/m4/byteorder.m4 +19 -0
  366. data/ext/libmemcached-0.50/m4/deprecated.m4 +17 -0
  367. data/ext/libmemcached-0.50/m4/eagain.m4 +28 -0
  368. data/ext/libmemcached-0.50/m4/enable_utillib.m4 +16 -0
  369. data/ext/libmemcached-0.50/m4/gettext.m4 +379 -0
  370. data/ext/libmemcached-0.50/m4/hsieh.m4 +18 -0
  371. data/ext/libmemcached-0.50/m4/iconv.m4 +214 -0
  372. data/ext/libmemcached-0.50/m4/lib-ld.m4 +110 -0
  373. data/ext/libmemcached-0.50/m4/lib-link.m4 +767 -0
  374. data/ext/libmemcached-0.50/m4/lib-prefix.m4 +221 -0
  375. data/ext/libmemcached-0.50/m4/libtool.m4 +7851 -0
  376. data/ext/libmemcached-0.50/m4/ltoptions.m4 +369 -0
  377. data/ext/libmemcached-0.50/m4/ltsugar.m4 +123 -0
  378. data/ext/libmemcached-0.50/m4/ltversion.m4 +23 -0
  379. data/ext/libmemcached-0.50/m4/lt~obsolete.m4 +98 -0
  380. data/ext/libmemcached-0.50/m4/memaslap.m4 +9 -0
  381. data/ext/libmemcached-0.50/m4/memcached.m4 +31 -0
  382. data/ext/libmemcached-0.50/m4/murmur.m4 +18 -0
  383. data/ext/libmemcached-0.50/m4/pandora_64bit.m4 +60 -0
  384. data/ext/libmemcached-0.50/m4/pandora_bison.m4 +33 -0
  385. data/ext/libmemcached-0.50/m4/pandora_canonical.m4 +418 -0
  386. data/ext/libmemcached-0.50/m4/pandora_check_compiler_version.m4 +37 -0
  387. data/ext/libmemcached-0.50/m4/pandora_check_cxx_standard.m4 +23 -0
  388. data/ext/libmemcached-0.50/m4/pandora_cinttypes.m4 +39 -0
  389. data/ext/libmemcached-0.50/m4/pandora_clock_gettime.m4 +15 -0
  390. data/ext/libmemcached-0.50/m4/pandora_compile_stdcxx_0x.m4 +103 -0
  391. data/ext/libmemcached-0.50/m4/pandora_cstdint.m4 +38 -0
  392. data/ext/libmemcached-0.50/m4/pandora_cxx_demangle.m4 +27 -0
  393. data/ext/libmemcached-0.50/m4/pandora_enable_dtrace.m4 +60 -0
  394. data/ext/libmemcached-0.50/m4/pandora_ensure_gcc_version.m4 +62 -0
  395. data/ext/libmemcached-0.50/m4/pandora_extensions.m4 +16 -0
  396. data/ext/libmemcached-0.50/m4/pandora_fdatasync.m4 +25 -0
  397. data/ext/libmemcached-0.50/m4/pandora_flex.m4 +33 -0
  398. data/ext/libmemcached-0.50/m4/pandora_have_better_malloc.m4 +66 -0
  399. data/ext/libmemcached-0.50/m4/pandora_have_boost.m4 +93 -0
  400. data/ext/libmemcached-0.50/m4/pandora_have_gcc_atomics.m4 +37 -0
  401. data/ext/libmemcached-0.50/m4/pandora_have_innodb.m4 +41 -0
  402. data/ext/libmemcached-0.50/m4/pandora_have_libaio.m4 +56 -0
  403. data/ext/libmemcached-0.50/m4/pandora_have_libavahi.m4 +41 -0
  404. data/ext/libmemcached-0.50/m4/pandora_have_libbdb.m4 +40 -0
  405. data/ext/libmemcached-0.50/m4/pandora_have_libboost_date_time.m4 +46 -0
  406. data/ext/libmemcached-0.50/m4/pandora_have_libboost_filesystem.m4 +47 -0
  407. data/ext/libmemcached-0.50/m4/pandora_have_libboost_iostreams.m4 +49 -0
  408. data/ext/libmemcached-0.50/m4/pandora_have_libboost_options.m4 +47 -0
  409. data/ext/libmemcached-0.50/m4/pandora_have_libboost_regex.m4 +54 -0
  410. data/ext/libmemcached-0.50/m4/pandora_have_libboost_test.m4 +45 -0
  411. data/ext/libmemcached-0.50/m4/pandora_have_libboost_thread.m4 +54 -0
  412. data/ext/libmemcached-0.50/m4/pandora_have_libcassandra.m4 +44 -0
  413. data/ext/libmemcached-0.50/m4/pandora_have_libcurl.m4 +62 -0
  414. data/ext/libmemcached-0.50/m4/pandora_have_libdl.m4 +51 -0
  415. data/ext/libmemcached-0.50/m4/pandora_have_libdrizzle.m4 +61 -0
  416. data/ext/libmemcached-0.50/m4/pandora_have_libevent.m4 +66 -0
  417. data/ext/libmemcached-0.50/m4/pandora_have_libgearman.m4 +41 -0
  418. data/ext/libmemcached-0.50/m4/pandora_have_libgtest.m4 +47 -0
  419. data/ext/libmemcached-0.50/m4/pandora_have_libhaildb.m4 +43 -0
  420. data/ext/libmemcached-0.50/m4/pandora_have_libhashkit.m4 +42 -0
  421. data/ext/libmemcached-0.50/m4/pandora_have_libinnodb.m4 +64 -0
  422. data/ext/libmemcached-0.50/m4/pandora_have_libldap.m4 +73 -0
  423. data/ext/libmemcached-0.50/m4/pandora_have_libmemcached.m4 +106 -0
  424. data/ext/libmemcached-0.50/m4/pandora_have_libmysqlclient.m4 +146 -0
  425. data/ext/libmemcached-0.50/m4/pandora_have_libndbclient.m4 +80 -0
  426. data/ext/libmemcached-0.50/m4/pandora_have_libpcre.m4 +73 -0
  427. data/ext/libmemcached-0.50/m4/pandora_have_libpq.m4 +46 -0
  428. data/ext/libmemcached-0.50/m4/pandora_have_libpqxx.m4 +44 -0
  429. data/ext/libmemcached-0.50/m4/pandora_have_libsqlite3.m4 +42 -0
  430. data/ext/libmemcached-0.50/m4/pandora_have_libtokyocabinet.m4 +54 -0
  431. data/ext/libmemcached-0.50/m4/pandora_have_libuuid.m4 +55 -0
  432. data/ext/libmemcached-0.50/m4/pandora_have_libvbucket.m4 +40 -0
  433. data/ext/libmemcached-0.50/m4/pandora_have_libxml2.m4 +52 -0
  434. data/ext/libmemcached-0.50/m4/pandora_have_libz.m4 +51 -0
  435. data/ext/libmemcached-0.50/m4/pandora_have_protobuf.m4 +82 -0
  436. data/ext/libmemcached-0.50/m4/pandora_have_sasl.m4 +133 -0
  437. data/ext/libmemcached-0.50/m4/pandora_have_thrift.m4 +45 -0
  438. data/ext/libmemcached-0.50/m4/pandora_header_assert.m4 +23 -0
  439. data/ext/libmemcached-0.50/m4/pandora_header_stdcxx_98.m4 +83 -0
  440. data/ext/libmemcached-0.50/m4/pandora_intltool.m4 +225 -0
  441. data/ext/libmemcached-0.50/m4/pandora_libtool.m4 +25 -0
  442. data/ext/libmemcached-0.50/m4/pandora_optimize.m4 +75 -0
  443. data/ext/libmemcached-0.50/m4/pandora_platform.m4 +117 -0
  444. data/ext/libmemcached-0.50/m4/pandora_plugins.m4 +62 -0
  445. data/ext/libmemcached-0.50/m4/pandora_print_callstack.m4 +61 -0
  446. data/ext/libmemcached-0.50/m4/pandora_pthread.m4 +258 -0
  447. data/ext/libmemcached-0.50/m4/pandora_python3_devel.m4 +236 -0
  448. data/ext/libmemcached-0.50/m4/pandora_run_cpplint.m4 +8 -0
  449. data/ext/libmemcached-0.50/m4/pandora_sasl.m4 +133 -0
  450. data/ext/libmemcached-0.50/m4/pandora_shared_ptr.m4 +59 -0
  451. data/ext/libmemcached-0.50/m4/pandora_stack_direction.m4 +39 -0
  452. data/ext/libmemcached-0.50/m4/pandora_stl_hash.m4 +94 -0
  453. data/ext/libmemcached-0.50/m4/pandora_swig.m4 +39 -0
  454. data/ext/libmemcached-0.50/m4/pandora_use_pipe.m4 +36 -0
  455. data/ext/libmemcached-0.50/m4/pandora_vc_build.m4 +168 -0
  456. data/ext/libmemcached-0.50/m4/pandora_version.m4 +11 -0
  457. data/ext/libmemcached-0.50/m4/pandora_visibility.m4 +75 -0
  458. data/ext/libmemcached-0.50/m4/pandora_warnings.m4 +447 -0
  459. data/ext/libmemcached-0.50/m4/pandora_with_gettext.m4 +44 -0
  460. data/ext/libmemcached-0.50/m4/pandora_with_lua.m4 +55 -0
  461. data/ext/libmemcached-0.50/m4/pandora_with_memcached.m4 +41 -0
  462. data/ext/libmemcached-0.50/m4/pandora_with_perl.m4 +81 -0
  463. data/ext/libmemcached-0.50/m4/pandora_with_php.m4 +56 -0
  464. data/ext/libmemcached-0.50/m4/pandora_with_python.m4 +37 -0
  465. data/ext/libmemcached-0.50/m4/pandora_with_python3.m4 +44 -0
  466. data/ext/libmemcached-0.50/m4/pandora_with_r.m4 +33 -0
  467. data/ext/libmemcached-0.50/m4/pandora_with_ruby.m4 +79 -0
  468. data/ext/libmemcached-0.50/m4/pandora_with_valgrind.m4 +17 -0
  469. data/ext/libmemcached-0.50/m4/pkg.m4 +157 -0
  470. data/ext/libmemcached-0.50/m4/po.m4 +449 -0
  471. data/ext/libmemcached-0.50/m4/progtest.m4 +92 -0
  472. data/ext/libmemcached-0.50/m4/protocol_binary.m4 +36 -0
  473. data/ext/libmemcached-0.50/m4/setsockopt.m4 +73 -0
  474. data/ext/libmemcached-0.50/m4/socket_send_flags.m4 +66 -0
  475. data/ext/libmemcached-0.50/poll/include.am +8 -0
  476. data/ext/libmemcached-0.50/poll/poll.c +77 -0
  477. data/ext/libmemcached-0.50/poll/poll.h +45 -0
  478. data/ext/libmemcached-0.50/support/include.am +11 -0
  479. data/ext/libmemcached-0.50/support/libmemcached-fc.spec.in +105 -0
  480. data/ext/libmemcached-0.50/support/libmemcached.pc.in +10 -0
  481. data/ext/libmemcached-0.50/support/libmemcached.spec.in +281 -0
  482. data/ext/libmemcached-0.50/support/set_benchmark.sh +5 -0
  483. data/ext/libmemcached-0.50/tests/atomsmasher.cc +295 -0
  484. data/ext/libmemcached-0.50/tests/basic.cc +134 -0
  485. data/ext/libmemcached-0.50/tests/basic.h +66 -0
  486. data/ext/libmemcached-0.50/tests/cpp_example.cc +195 -0
  487. data/ext/libmemcached-0.50/tests/deprecated.cc +72 -0
  488. data/ext/libmemcached-0.50/tests/deprecated.h +49 -0
  489. data/ext/libmemcached-0.50/tests/error_conditions.cc +63 -0
  490. data/ext/libmemcached-0.50/tests/error_conditions.h +48 -0
  491. data/ext/libmemcached-0.50/tests/hash_plus.cc +225 -0
  492. data/ext/libmemcached-0.50/tests/hash_results.h +127 -0
  493. data/ext/libmemcached-0.50/tests/hashkit_functions.cc +619 -0
  494. data/ext/libmemcached-0.50/tests/include.am +342 -0
  495. data/ext/libmemcached-0.50/tests/ketama_test_cases.h +121 -0
  496. data/ext/libmemcached-0.50/tests/ketama_test_cases_spy.h +118 -0
  497. data/ext/libmemcached-0.50/tests/libmemcached_world.h +205 -0
  498. data/ext/libmemcached-0.50/tests/mem_functions.cc +6648 -0
  499. data/ext/libmemcached-0.50/tests/mem_udp.cc +510 -0
  500. data/ext/libmemcached-0.50/tests/output_plus.res +5 -0
  501. data/ext/libmemcached-0.50/tests/parser.cc +599 -0
  502. data/ext/libmemcached-0.50/tests/parser.h +109 -0
  503. data/ext/libmemcached-0.50/tests/plus.cpp +240 -0
  504. data/ext/libmemcached-0.50/tests/pool.cc +78 -0
  505. data/ext/libmemcached-0.50/tests/pool.h +49 -0
  506. data/ext/libmemcached-0.50/tests/print.cc +58 -0
  507. data/ext/libmemcached-0.50/tests/print.h +51 -0
  508. data/ext/libmemcached-0.50/tests/replication.cc +333 -0
  509. data/ext/libmemcached-0.50/tests/replication.h +64 -0
  510. data/ext/libmemcached-0.50/tests/start.cc +29 -0
  511. data/ext/libmemcached-0.50/tests/string.cc +174 -0
  512. data/ext/libmemcached-0.50/tests/string.h +67 -0
  513. data/ext/libmemcached-0.50/tests/virtual_buckets.cc +143 -0
  514. data/ext/libmemcached-0.50/tests/virtual_buckets.h +51 -0
  515. data/ext/libmemcached-0.50/win32/include.am +11 -0
  516. data/ext/libmemcached-0.50/win32/wrappers.h +55 -0
  517. data/ext/rlibmemcached.i +263 -0
  518. data/ext/rlibmemcached_wrap.c +16732 -0
  519. data/lib/memcached.rb +32 -0
  520. data/lib/memcached/auth.rb +16 -0
  521. data/lib/memcached/behaviors.rb +77 -0
  522. data/lib/memcached/exceptions.rb +84 -0
  523. data/lib/memcached/experimental.rb +48 -0
  524. data/lib/memcached/memcached.rb +660 -0
  525. data/lib/memcached/rails.rb +133 -0
  526. data/test/profile/benchmark.rb +245 -0
  527. data/test/profile/c_profiler.rb +14 -0
  528. data/test/profile/exercise.rb +185 -0
  529. data/test/profile/rb_profiler.rb +21 -0
  530. data/test/profile/valgrind.rb +10 -0
  531. data/test/setup.rb +30 -0
  532. data/test/teardown.rb +0 -0
  533. data/test/test_helper.rb +19 -0
  534. data/test/unit/binding_test.rb +8 -0
  535. data/test/unit/memcached_experimental_test.rb +274 -0
  536. data/test/unit/memcached_test.rb +1293 -0
  537. data/test/unit/rails_test.rb +122 -0
  538. metadata +650 -0
  539. metadata.gz.sig +0 -0
@@ -0,0 +1,349 @@
1
+ /* LibMemcached
2
+ * Copyright (C) 2006-2009 Brian Aker
3
+ * All rights reserved.
4
+ *
5
+ * Use and distribution licensed under the BSD license. See
6
+ * the COPYING file in the parent directory for full text.
7
+ *
8
+ * Summary:
9
+ *
10
+ * Authors:
11
+ * Brian Aker
12
+ * Toru Maesaka
13
+ */
14
+ #include "config.h"
15
+
16
+ #include <cstdio>
17
+ #include <cstring>
18
+ #include <ctime>
19
+ #include <fcntl.h>
20
+ #include <getopt.h>
21
+ #include <sys/stat.h>
22
+ #include <sys/time.h>
23
+ #include <sys/types.h>
24
+ #include <sys/types.h>
25
+
26
+ #include <libmemcached/memcached.h>
27
+
28
+ #include "client_options.h"
29
+ #include "utilities.h"
30
+
31
+ #define PROGRAM_NAME "memstat"
32
+ #define PROGRAM_DESCRIPTION "Output the state of a memcached cluster."
33
+
34
+ /* Prototypes */
35
+ static void options_parse(int argc, char *argv[]);
36
+ static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat);
37
+ static void print_analysis_report(memcached_st *memc,
38
+ memcached_analysis_st *report);
39
+
40
+ static int opt_verbose= 0;
41
+ static int opt_displayflag= 0;
42
+ static int opt_analyze= 0;
43
+ static char *opt_servers= NULL;
44
+ static char *stat_args= NULL;
45
+ static char *analyze_mode= NULL;
46
+
47
+ static struct option long_options[]=
48
+ {
49
+ {(OPTIONSTRING)"args", required_argument, NULL, OPT_STAT_ARGS},
50
+ {(OPTIONSTRING)"version", no_argument, NULL, OPT_VERSION},
51
+ {(OPTIONSTRING)"help", no_argument, NULL, OPT_HELP},
52
+ {(OPTIONSTRING)"verbose", no_argument, &opt_verbose, OPT_VERBOSE},
53
+ {(OPTIONSTRING)"debug", no_argument, &opt_verbose, OPT_DEBUG},
54
+ {(OPTIONSTRING)"servers", required_argument, NULL, OPT_SERVERS},
55
+ {(OPTIONSTRING)"flag", no_argument, &opt_displayflag, OPT_FLAG},
56
+ {(OPTIONSTRING)"analyze", optional_argument, NULL, OPT_ANALYZE},
57
+ {0, 0, 0, 0},
58
+ };
59
+
60
+
61
+ static memcached_return_t stat_printer(memcached_server_instance_st instance,
62
+ const char *key, size_t key_length,
63
+ const char *value, size_t value_length,
64
+ void *context)
65
+ {
66
+ static memcached_server_instance_st last= NULL;
67
+ (void)context;
68
+
69
+ if (last != instance)
70
+ {
71
+ printf("Server: %s (%u)\n", memcached_server_name(instance),
72
+ (uint32_t)memcached_server_port(instance));
73
+ last= instance;
74
+ }
75
+
76
+ printf("\t %.*s: %.*s\n", (int)key_length, key, (int)value_length, value);
77
+
78
+ return MEMCACHED_SUCCESS;
79
+ }
80
+
81
+ int main(int argc, char *argv[])
82
+ {
83
+ options_parse(argc, argv);
84
+ initialize_sockets();
85
+
86
+ if (! opt_servers)
87
+ {
88
+ char *temp;
89
+
90
+ if ((temp= getenv("MEMCACHED_SERVERS")))
91
+ opt_servers= strdup(temp);
92
+ else
93
+ {
94
+ fprintf(stderr, "No Servers provided\n\n");
95
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, 0);
96
+ exit(1);
97
+ }
98
+ }
99
+
100
+ memcached_st *memc= memcached_create(NULL);
101
+
102
+ memcached_server_st *servers= memcached_servers_parse(opt_servers);
103
+ free(opt_servers);
104
+
105
+ memcached_return_t rc= memcached_server_push(memc, servers);
106
+ memcached_server_list_free(servers);
107
+
108
+ if (rc != MEMCACHED_SUCCESS && rc != MEMCACHED_SOME_ERRORS)
109
+ {
110
+ printf("Failure to communicate with servers (%s)\n",
111
+ memcached_strerror(memc, rc));
112
+ exit(1);
113
+ }
114
+
115
+ if (opt_analyze)
116
+ {
117
+ memcached_stat_st *memc_stat;
118
+
119
+ memc_stat= memcached_stat(memc, NULL, &rc);
120
+
121
+ if (! memc_stat)
122
+ exit(-1);
123
+
124
+ run_analyzer(memc, memc_stat);
125
+
126
+ memcached_stat_free(memc, memc_stat);
127
+ }
128
+ else
129
+ {
130
+ rc= memcached_stat_execute(memc, stat_args, stat_printer, NULL);
131
+ }
132
+
133
+ memcached_free(memc);
134
+
135
+ return rc == MEMCACHED_SUCCESS ? EXIT_SUCCESS: EXIT_FAILURE;
136
+ }
137
+
138
+ static void run_analyzer(memcached_st *memc, memcached_stat_st *memc_stat)
139
+ {
140
+ memcached_return_t rc;
141
+
142
+ if (analyze_mode == NULL)
143
+ {
144
+ memcached_analysis_st *report;
145
+ report= memcached_analyze(memc, memc_stat, &rc);
146
+ if (rc != MEMCACHED_SUCCESS || report == NULL)
147
+ {
148
+ printf("Failure to analyze servers (%s)\n",
149
+ memcached_strerror(memc, rc));
150
+ exit(1);
151
+ }
152
+ print_analysis_report(memc, report);
153
+ free(report);
154
+ }
155
+ else if (strcmp(analyze_mode, "latency") == 0)
156
+ {
157
+ uint32_t flags, server_count= memcached_server_count(memc);
158
+ uint32_t num_of_tests= 32;
159
+ const char *test_key= "libmemcached_test_key";
160
+
161
+ memcached_st **servers;
162
+ servers= static_cast<memcached_st**>(malloc(sizeof(memcached_st*) * server_count));
163
+ if (not servers)
164
+ {
165
+ fprintf(stderr, "Failed to allocate memory\n");
166
+ return;
167
+ }
168
+
169
+ for (uint32_t x= 0; x < server_count; x++)
170
+ {
171
+ memcached_server_instance_st instance=
172
+ memcached_server_instance_by_position(memc, x);
173
+
174
+ if ((servers[x]= memcached_create(NULL)) == NULL)
175
+ {
176
+ fprintf(stderr, "Failed to memcached_create()\n");
177
+ if (x > 0)
178
+ memcached_free(servers[0]);
179
+ x--;
180
+
181
+ for (; x > 0; x--)
182
+ memcached_free(servers[x]);
183
+
184
+ free(servers);
185
+ return;
186
+ }
187
+ memcached_server_add(servers[x],
188
+ memcached_server_name(instance),
189
+ memcached_server_port(instance));
190
+ }
191
+
192
+ printf("Network Latency Test:\n\n");
193
+ struct timeval start_time, end_time;
194
+ uint32_t slowest_server= 0;
195
+ long elapsed_time, slowest_time= 0;
196
+
197
+ for (uint32_t x= 0; x < server_count; x++)
198
+ {
199
+ memcached_server_instance_st instance=
200
+ memcached_server_instance_by_position(memc, x);
201
+ gettimeofday(&start_time, NULL);
202
+
203
+ for (uint32_t y= 0; y < num_of_tests; y++)
204
+ {
205
+ size_t vlen;
206
+ char *val= memcached_get(servers[x], test_key, strlen(test_key),
207
+ &vlen, &flags, &rc);
208
+ if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
209
+ break;
210
+ free(val);
211
+ }
212
+ gettimeofday(&end_time, NULL);
213
+
214
+ elapsed_time= (long) timedif(end_time, start_time);
215
+ elapsed_time /= (long) num_of_tests;
216
+
217
+ if (elapsed_time > slowest_time)
218
+ {
219
+ slowest_server= x;
220
+ slowest_time= elapsed_time;
221
+ }
222
+
223
+ if (rc != MEMCACHED_NOTFOUND && rc != MEMCACHED_SUCCESS)
224
+ {
225
+ printf("\t %s (%d) => failed to reach the server\n",
226
+ memcached_server_name(instance),
227
+ memcached_server_port(instance));
228
+ }
229
+ else
230
+ {
231
+ printf("\t %s (%d) => %ld.%ld seconds\n",
232
+ memcached_server_name(instance),
233
+ memcached_server_port(instance),
234
+ elapsed_time / 1000, elapsed_time % 1000);
235
+ }
236
+ }
237
+
238
+ if (server_count > 1 && slowest_time > 0)
239
+ {
240
+ memcached_server_instance_st slowest=
241
+ memcached_server_instance_by_position(memc, slowest_server);
242
+
243
+ printf("---\n");
244
+ printf("Slowest Server: %s (%d) => %ld.%ld seconds\n",
245
+ memcached_server_name(slowest),
246
+ memcached_server_port(slowest),
247
+ slowest_time / 1000, slowest_time % 1000);
248
+ }
249
+ printf("\n");
250
+
251
+ for (uint32_t x= 0; x < server_count; x++)
252
+ memcached_free(servers[x]);
253
+
254
+ free(servers);
255
+ free(analyze_mode);
256
+ }
257
+ else
258
+ {
259
+ fprintf(stderr, "Invalid Analyzer Option provided\n");
260
+ free(analyze_mode);
261
+ }
262
+ }
263
+
264
+ static void print_analysis_report(memcached_st *memc,
265
+ memcached_analysis_st *report)
266
+
267
+ {
268
+ uint32_t server_count= memcached_server_count(memc);
269
+ memcached_server_instance_st most_consumed_server= memcached_server_instance_by_position(memc, report->most_consumed_server);
270
+ memcached_server_instance_st least_free_server= memcached_server_instance_by_position(memc, report->least_free_server);
271
+ memcached_server_instance_st oldest_server= memcached_server_instance_by_position(memc, report->oldest_server);
272
+
273
+ printf("Memcached Cluster Analysis Report\n\n");
274
+
275
+ printf("\tNumber of Servers Analyzed : %u\n", server_count);
276
+ printf("\tAverage Item Size (incl/overhead) : %u bytes\n",
277
+ report->average_item_size);
278
+
279
+ if (server_count == 1)
280
+ {
281
+ printf("\nFor a detailed report, you must supply multiple servers.\n");
282
+ return;
283
+ }
284
+
285
+ printf("\n");
286
+ printf("\tNode with most memory consumption : %s:%u (%llu bytes)\n",
287
+ memcached_server_name(most_consumed_server),
288
+ (uint32_t)memcached_server_port(most_consumed_server),
289
+ (unsigned long long)report->most_used_bytes);
290
+ printf("\tNode with least free space : %s:%u (%llu bytes remaining)\n",
291
+ memcached_server_name(least_free_server),
292
+ (uint32_t)memcached_server_port(least_free_server),
293
+ (unsigned long long)report->least_remaining_bytes);
294
+ printf("\tNode with longest uptime : %s:%u (%us)\n",
295
+ memcached_server_name(oldest_server),
296
+ (uint32_t)memcached_server_port(oldest_server),
297
+ report->longest_uptime);
298
+ printf("\tPool-wide Hit Ratio : %1.f%%\n", report->pool_hit_ratio);
299
+ printf("\n");
300
+ }
301
+
302
+ static void options_parse(int argc, char *argv[])
303
+ {
304
+ memcached_programs_help_st help_options[]=
305
+ {
306
+ {0},
307
+ };
308
+
309
+ int option_index= 0;
310
+ int option_rv;
311
+
312
+ while (1)
313
+ {
314
+ option_rv= getopt_long(argc, argv, "Vhvds:a", long_options, &option_index);
315
+ if (option_rv == -1) break;
316
+ switch (option_rv)
317
+ {
318
+ case 0:
319
+ break;
320
+ case OPT_VERBOSE: /* --verbose or -v */
321
+ opt_verbose = OPT_VERBOSE;
322
+ break;
323
+ case OPT_DEBUG: /* --debug or -d */
324
+ opt_verbose = OPT_DEBUG;
325
+ break;
326
+ case OPT_VERSION: /* --version or -V */
327
+ version_command(PROGRAM_NAME);
328
+ break;
329
+ case OPT_HELP: /* --help or -h */
330
+ help_command(PROGRAM_NAME, PROGRAM_DESCRIPTION, long_options, help_options);
331
+ break;
332
+ case OPT_SERVERS: /* --servers or -s */
333
+ opt_servers= strdup(optarg);
334
+ break;
335
+ case OPT_STAT_ARGS:
336
+ stat_args= strdup(optarg);
337
+ break;
338
+ case OPT_ANALYZE: /* --analyze or -a */
339
+ opt_analyze= OPT_ANALYZE;
340
+ analyze_mode= (optarg) ? strdup(optarg) : NULL;
341
+ break;
342
+ case '?':
343
+ /* getopt_long already printed an error message. */
344
+ exit(1);
345
+ default:
346
+ abort();
347
+ }
348
+ }
349
+ }
@@ -0,0 +1,69 @@
1
+ /* LibMemcached
2
+ * Copyright (C) 2006-2009 Brian Aker
3
+ * All rights reserved.
4
+ *
5
+ * Use and distribution licensed under the BSD license. See
6
+ * the COPYING file in the parent directory for full text.
7
+ *
8
+ * Summary:
9
+ *
10
+ */
11
+
12
+ #ifndef CLIENTS_MS_ATOMIC_H
13
+ #define CLIENTS_MS_ATOMIC_H
14
+
15
+ #if defined(__SUNPRO_C)
16
+ # define _KERNEL
17
+ # include <atomic.h>
18
+ # if SIZEOF_SIZE_T == 8
19
+ # define atomic_add_size(X, Y) atomic_add_64((X), (Y))
20
+ # define atomic_add_size_nv(X, Y) atomic_add_64((X), (Y))
21
+ # define atomic_dec_size(X, Y) atomic_add_64((X), (Y))
22
+ # define atomic_dec_size_nv(X, Y) atomic_add_64((X), (Y))
23
+ # else
24
+ # define atomic_add_size(X, Y) atomic_add_32((X), (Y))
25
+ # define atomic_add_size_nv(X, Y) atomic_add_32((X), (Y))
26
+ # define atomic_dec_size(X, Y) atomic_add_32((X), (Y))
27
+ # define atomic_dec_size_nv(X, Y) atomic_add_32((X), (Y))
28
+ # endif
29
+ # undef _KERNEL
30
+ #elif HAVE_GCC_ATOMIC_BUILTINS
31
+ # define atomic_add_8(X, Y) __sync_fetch_and_add((X), (Y))
32
+ # define atomic_add_16(X, Y) __sync_fetch_and_add((X), (Y))
33
+ # define atomic_add_32(X, Y) __sync_fetch_and_add((X), (Y))
34
+ # define atomic_add_size(X, Y) __sync_fetch_and_add((X), (Y))
35
+ # define atomic_dec_8(X) __sync_fetch_and_sub((X), 1)
36
+ # define atomic_dec_16(X) __sync_fetch_and_sub((X), 1)
37
+ # define atomic_dec_32(X) __sync_fetch_and_sub((X), 1)
38
+ # define atomic_dec_size(X) __sync_fetch_and_sub((X), 1)
39
+ /* The same as above, but these return the new value instead of void */
40
+ # define atomic_add_8_nv(X, Y) __sync_fetch_and_add((X), (Y))
41
+ # define atomic_add_16_nv(X, Y) __sync_fetch_and_add((X), (Y))
42
+ # define atomic_add_32_nv(X, Y) __sync_fetch_and_add((X), (Y))
43
+ # define atomic_add_size_nv(X, Y) __sync_fetch_and_add((X), (Y))
44
+ # define atomic_dec_8_nv(X) __sync_fetch_and_sub((X), 1)
45
+ # define atomic_dec_16_nv(X) __sync_fetch_and_sub((X), 1)
46
+ # define atomic_dec_32_nv(X) __sync_fetch_and_sub((X), 1)
47
+ # define atomic_dec_size_nv(X) __sync_fetch_and_sub((X), 1)
48
+ #else
49
+ #warning "Atomic operators not found so memslap will not work correctly"
50
+ # define atomic_add_8(X, Y)
51
+ # define atomic_add_16(X, Y)
52
+ # define atomic_add_32(X, Y)
53
+ # define atomic_add_size(X, Y)
54
+ # define atomic_dec_8(X)
55
+ # define atomic_dec_16(X)
56
+ # define atomic_dec_32(X)
57
+ # define atomic_dec_size(X)
58
+ /* The same as above, but these return the new value instead of void */
59
+ # define atomic_add_8_nv(X, Y)
60
+ # define atomic_add_16_nv(X, Y)
61
+ # define atomic_add_32_nv(X, Y)
62
+ # define atomic_add_size_nv(X, Y)
63
+ # define atomic_dec_8_nv(X)
64
+ # define atomic_dec_16_nv(X)
65
+ # define atomic_dec_32_nv(X)
66
+ # define atomic_dec_size_nv(X)
67
+ #endif /* defined(__SUNPRO_C) */
68
+
69
+ #endif /* CLIENTS_MS_ATOMIC_H */
@@ -0,0 +1,3413 @@
1
+ /*
2
+ * File: ms_conn.c
3
+ * Author: Mingqiang Zhuang
4
+ *
5
+ * Created on February 10, 2009
6
+ *
7
+ * (c) Copyright 2009, Schooner Information Technology, Inc.
8
+ * http://www.schoonerinfotech.com/
9
+ *
10
+ */
11
+
12
+ #include "config.h"
13
+
14
+ #include <stdio.h>
15
+ #include <inttypes.h>
16
+ #include <limits.h>
17
+ #include <sys/uio.h>
18
+ #include <event.h>
19
+ #include <fcntl.h>
20
+ #include <netinet/tcp.h>
21
+ #include <netinet/in.h>
22
+ #include <arpa/inet.h>
23
+ #if TIME_WITH_SYS_TIME
24
+ # include <sys/time.h>
25
+ # include <time.h>
26
+ #else
27
+ # if HAVE_SYS_TIME_H
28
+ # include <sys/time.h>
29
+ # else
30
+ # include <time.h>
31
+ # endif
32
+ #endif
33
+ #include "ms_setting.h"
34
+ #include "ms_thread.h"
35
+ #include "ms_atomic.h"
36
+
37
+ #ifdef linux
38
+ /* /usr/include/netinet/in.h defines macros from ntohs() to _bswap_nn to
39
+ * optimize the conversion functions, but the prototypes generate warnings
40
+ * from gcc. The conversion methods isn't the bottleneck for my app, so
41
+ * just remove the warnings by undef'ing the optimization ..
42
+ */
43
+ #undef ntohs
44
+ #undef ntohl
45
+ #undef htons
46
+ #undef htonl
47
+ #endif
48
+
49
+ /* for network write */
50
+ #define TRANSMIT_COMPLETE 0
51
+ #define TRANSMIT_INCOMPLETE 1
52
+ #define TRANSMIT_SOFT_ERROR 2
53
+ #define TRANSMIT_HARD_ERROR 3
54
+
55
+ /* for generating key */
56
+ #define KEY_PREFIX_BASE 0x1010101010101010 /* not include ' ' '\r' '\n' '\0' */
57
+ #define KEY_PREFIX_MASK 0x1010101010101010
58
+
59
+ /* For parse the value length return by server */
60
+ #define KEY_TOKEN 1
61
+ #define VALUELEN_TOKEN 3
62
+
63
+ /* global increasing counter, to ensure the key prefix unique */
64
+ static uint64_t key_prefix_seq= KEY_PREFIX_BASE;
65
+
66
+ /* global increasing counter, generating request id for UDP */
67
+ static volatile uint32_t udp_request_id= 0;
68
+
69
+ extern pthread_key_t ms_thread_key;
70
+
71
+ /* generate upd request id */
72
+ static uint32_t ms_get_udp_request_id(void);
73
+
74
+
75
+ /* connect initialize */
76
+ static void ms_task_init(ms_conn_t *c);
77
+ static int ms_conn_udp_init(ms_conn_t *c, const bool is_udp);
78
+ static int ms_conn_sock_init(ms_conn_t *c);
79
+ static int ms_conn_event_init(ms_conn_t *c);
80
+ static int ms_conn_init(ms_conn_t *c,
81
+ const int init_state,
82
+ const int read_buffer_size,
83
+ const bool is_udp);
84
+ static void ms_warmup_num_init(ms_conn_t *c);
85
+ static int ms_item_win_init(ms_conn_t *c);
86
+
87
+
88
+ /* connection close */
89
+ void ms_conn_free(ms_conn_t *c);
90
+ static void ms_conn_close(ms_conn_t *c);
91
+
92
+
93
+ /* create network connection */
94
+ static int ms_new_socket(struct addrinfo *ai);
95
+ static void ms_maximize_sndbuf(const int sfd);
96
+ static int ms_network_connect(ms_conn_t *c,
97
+ char *srv_host_name,
98
+ const int srv_port,
99
+ const bool is_udp,
100
+ int *ret_sfd);
101
+ static int ms_reconn(ms_conn_t *c);
102
+
103
+
104
+ /* read and parse */
105
+ static int ms_tokenize_command(char *command,
106
+ token_t *tokens,
107
+ const int max_tokens);
108
+ static int ms_ascii_process_line(ms_conn_t *c, char *command);
109
+ static int ms_try_read_line(ms_conn_t *c);
110
+ static int ms_sort_udp_packet(ms_conn_t *c, char *buf, int rbytes);
111
+ static int ms_udp_read(ms_conn_t *c, char *buf, int len);
112
+ static int ms_try_read_network(ms_conn_t *c);
113
+ static void ms_verify_value(ms_conn_t *c,
114
+ ms_mlget_task_item_t *mlget_item,
115
+ char *value,
116
+ int vlen);
117
+ static void ms_ascii_complete_nread(ms_conn_t *c);
118
+ static void ms_bin_complete_nread(ms_conn_t *c);
119
+ static void ms_complete_nread(ms_conn_t *c);
120
+
121
+
122
+ /* send functions */
123
+ static int ms_add_msghdr(ms_conn_t *c);
124
+ static int ms_ensure_iov_space(ms_conn_t *c);
125
+ static int ms_add_iov(ms_conn_t *c, const void *buf, int len);
126
+ static int ms_build_udp_headers(ms_conn_t *c);
127
+ static int ms_transmit(ms_conn_t *c);
128
+
129
+
130
+ /* status adjustment */
131
+ static void ms_conn_shrink(ms_conn_t *c);
132
+ static void ms_conn_set_state(ms_conn_t *c, int state);
133
+ static bool ms_update_event(ms_conn_t *c, const int new_flags);
134
+ static uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd);
135
+ static uint32_t ms_get_next_sock_index(ms_conn_t *c);
136
+ static int ms_update_conn_sock_event(ms_conn_t *c);
137
+ static bool ms_need_yield(ms_conn_t *c);
138
+ static void ms_update_start_time(ms_conn_t *c);
139
+
140
+
141
+ /* main loop */
142
+ static void ms_drive_machine(ms_conn_t *c);
143
+ void ms_event_handler(const int fd, const short which, void *arg);
144
+
145
+
146
+ /* ascii protocol */
147
+ static int ms_build_ascii_write_buf_set(ms_conn_t *c, ms_task_item_t *item);
148
+ static int ms_build_ascii_write_buf_get(ms_conn_t *c, ms_task_item_t *item);
149
+ static int ms_build_ascii_write_buf_mlget(ms_conn_t *c);
150
+
151
+
152
+ /* binary protocol */
153
+ static int ms_bin_process_response(ms_conn_t *c);
154
+ static void ms_add_bin_header(ms_conn_t *c,
155
+ uint8_t opcode,
156
+ uint8_t hdr_len,
157
+ uint16_t key_len,
158
+ uint32_t body_len);
159
+ static void ms_add_key_to_iov(ms_conn_t *c, ms_task_item_t *item);
160
+ static int ms_build_bin_write_buf_set(ms_conn_t *c, ms_task_item_t *item);
161
+ static int ms_build_bin_write_buf_get(ms_conn_t *c, ms_task_item_t *item);
162
+ static int ms_build_bin_write_buf_mlget(ms_conn_t *c);
163
+
164
+
165
+ /**
166
+ * each key has two parts, prefix and suffix. The suffix is a
167
+ * string random get form the character table. The prefix is a
168
+ * uint64_t variable. And the prefix must be unique. we use the
169
+ * prefix to identify a key. And the prefix can't include
170
+ * character ' ' '\r' '\n' '\0'.
171
+ *
172
+ * @return uint64_t
173
+ */
174
+ uint64_t ms_get_key_prefix(void)
175
+ {
176
+ uint64_t key_prefix;
177
+
178
+ pthread_mutex_lock(&ms_global.seq_mutex);
179
+ key_prefix_seq|= KEY_PREFIX_MASK;
180
+ key_prefix= key_prefix_seq;
181
+ key_prefix_seq++;
182
+ pthread_mutex_unlock(&ms_global.seq_mutex);
183
+
184
+ return key_prefix;
185
+ } /* ms_get_key_prefix */
186
+
187
+
188
+ /**
189
+ * get an unique udp request id
190
+ *
191
+ * @return an unique UDP request id
192
+ */
193
+ static uint32_t ms_get_udp_request_id(void)
194
+ {
195
+ return atomic_add_32_nv(&udp_request_id, 1);
196
+ }
197
+
198
+
199
+ /**
200
+ * initialize current task structure
201
+ *
202
+ * @param c, pointer of the concurrency
203
+ */
204
+ static void ms_task_init(ms_conn_t *c)
205
+ {
206
+ c->curr_task.cmd= CMD_NULL;
207
+ c->curr_task.item= 0;
208
+ c->curr_task.verify= false;
209
+ c->curr_task.finish_verify= true;
210
+ c->curr_task.get_miss= true;
211
+
212
+ c->curr_task.get_opt= 0;
213
+ c->curr_task.set_opt= 0;
214
+ c->curr_task.cycle_undo_get= 0;
215
+ c->curr_task.cycle_undo_set= 0;
216
+ c->curr_task.verified_get= 0;
217
+ c->curr_task.overwrite_set= 0;
218
+ } /* ms_task_init */
219
+
220
+
221
+ /**
222
+ * initialize udp for the connection structure
223
+ *
224
+ * @param c, pointer of the concurrency
225
+ * @param is_udp, whether it's udp
226
+ *
227
+ * @return int, if success, return EXIT_SUCCESS, else return -1
228
+ */
229
+ static int ms_conn_udp_init(ms_conn_t *c, const bool is_udp)
230
+ {
231
+ c->hdrbuf= 0;
232
+ c->rudpbuf= 0;
233
+ c->udppkt= 0;
234
+
235
+ c->rudpsize= UDP_DATA_BUFFER_SIZE;
236
+ c->hdrsize= 0;
237
+
238
+ c->rudpbytes= 0;
239
+ c->packets= 0;
240
+ c->recvpkt= 0;
241
+ c->pktcurr= 0;
242
+ c->ordcurr= 0;
243
+
244
+ c->udp= is_udp;
245
+
246
+ if (c->udp || (! c->udp && ms_setting.facebook_test))
247
+ {
248
+ c->rudpbuf= (char *)malloc((size_t)c->rudpsize);
249
+ c->udppkt= (ms_udppkt_t *)malloc(MAX_UDP_PACKET * sizeof(ms_udppkt_t));
250
+
251
+ if ((c->rudpbuf == NULL) || (c->udppkt == NULL))
252
+ {
253
+ if (c->rudpbuf != NULL)
254
+ free(c->rudpbuf);
255
+ if (c->udppkt != NULL)
256
+ free(c->udppkt);
257
+ fprintf(stderr, "malloc()\n");
258
+ return -1;
259
+ }
260
+ memset(c->udppkt, 0, MAX_UDP_PACKET * sizeof(ms_udppkt_t));
261
+ }
262
+
263
+ return EXIT_SUCCESS;
264
+ } /* ms_conn_udp_init */
265
+
266
+
267
+ /**
268
+ * initialize the connection structure
269
+ *
270
+ * @param c, pointer of the concurrency
271
+ * @param init_state, (conn_read, conn_write, conn_closing)
272
+ * @param read_buffer_size
273
+ * @param is_udp, whether it's udp
274
+ *
275
+ * @return int, if success, return EXIT_SUCCESS, else return -1
276
+ */
277
+ static int ms_conn_init(ms_conn_t *c,
278
+ const int init_state,
279
+ const int read_buffer_size,
280
+ const bool is_udp)
281
+ {
282
+ assert(c != NULL);
283
+
284
+ c->rbuf= c->wbuf= 0;
285
+ c->iov= 0;
286
+ c->msglist= 0;
287
+
288
+ c->rsize= read_buffer_size;
289
+ c->wsize= WRITE_BUFFER_SIZE;
290
+ c->iovsize= IOV_LIST_INITIAL;
291
+ c->msgsize= MSG_LIST_INITIAL;
292
+
293
+ /* for replication, each connection need connect all the server */
294
+ if (ms_setting.rep_write_srv > 0)
295
+ {
296
+ c->total_sfds= ms_setting.srv_cnt * ms_setting.sock_per_conn;
297
+ }
298
+ else
299
+ {
300
+ c->total_sfds= ms_setting.sock_per_conn;
301
+ }
302
+ c->alive_sfds= 0;
303
+
304
+ c->rbuf= (char *)malloc((size_t)c->rsize);
305
+ c->wbuf= (char *)malloc((size_t)c->wsize);
306
+ c->iov= (struct iovec *)malloc(sizeof(struct iovec) * (size_t)c->iovsize);
307
+ c->msglist= (struct msghdr *)malloc(
308
+ sizeof(struct msghdr) * (size_t)c->msgsize);
309
+ if (ms_setting.mult_key_num > 1)
310
+ {
311
+ c->mlget_task.mlget_item= (ms_mlget_task_item_t *)
312
+ malloc(
313
+ sizeof(ms_mlget_task_item_t) * (size_t)ms_setting.mult_key_num);
314
+ }
315
+ c->tcpsfd= (int *)malloc((size_t)c->total_sfds * sizeof(int));
316
+
317
+ if ((c->rbuf == NULL) || (c->wbuf == NULL) || (c->iov == NULL)
318
+ || (c->msglist == NULL) || (c->tcpsfd == NULL)
319
+ || ((ms_setting.mult_key_num > 1)
320
+ && (c->mlget_task.mlget_item == NULL)))
321
+ {
322
+ if (c->rbuf != NULL)
323
+ free(c->rbuf);
324
+ if (c->wbuf != NULL)
325
+ free(c->wbuf);
326
+ if (c->iov != NULL)
327
+ free(c->iov);
328
+ if (c->msglist != NULL)
329
+ free(c->msglist);
330
+ if (c->mlget_task.mlget_item != NULL)
331
+ free(c->mlget_task.mlget_item);
332
+ if (c->tcpsfd != NULL)
333
+ free(c->tcpsfd);
334
+ fprintf(stderr, "malloc()\n");
335
+ return -1;
336
+ }
337
+
338
+ c->state= init_state;
339
+ c->rvbytes= 0;
340
+ c->rbytes= 0;
341
+ c->rcurr= c->rbuf;
342
+ c->wcurr= c->wbuf;
343
+ c->iovused= 0;
344
+ c->msgcurr= 0;
345
+ c->msgused= 0;
346
+ c->cur_idx= c->total_sfds; /* default index is a invalid value */
347
+
348
+ c->ctnwrite= false;
349
+ c->readval= false;
350
+ c->change_sfd= false;
351
+
352
+ c->precmd.cmd= c->currcmd.cmd= CMD_NULL;
353
+ c->precmd.isfinish= true; /* default the previous command finished */
354
+ c->currcmd.isfinish= false;
355
+ c->precmd.retstat= c->currcmd.retstat= MCD_FAILURE;
356
+ c->precmd.key_prefix= c->currcmd.key_prefix= 0;
357
+
358
+ c->mlget_task.mlget_num= 0;
359
+ c->mlget_task.value_index= -1; /* default invalid value */
360
+
361
+ if (ms_setting.binary_prot)
362
+ {
363
+ c->protocol= binary_prot;
364
+ }
365
+ else
366
+ {
367
+ c->protocol= ascii_prot;
368
+ }
369
+
370
+ /* initialize udp */
371
+ if (ms_conn_udp_init(c, is_udp) != 0)
372
+ {
373
+ return -1;
374
+ }
375
+
376
+ /* initialize task */
377
+ ms_task_init(c);
378
+
379
+ if (! (ms_setting.facebook_test && is_udp))
380
+ {
381
+ atomic_add_32(&ms_stats.active_conns, 1);
382
+ }
383
+
384
+ return EXIT_SUCCESS;
385
+ } /* ms_conn_init */
386
+
387
+
388
+ /**
389
+ * when doing 100% get operation, it could preset some objects
390
+ * to warmup the server. this function is used to initialize the
391
+ * number of the objects to preset.
392
+ *
393
+ * @param c, pointer of the concurrency
394
+ */
395
+ static void ms_warmup_num_init(ms_conn_t *c)
396
+ {
397
+ /* no set operation, preset all the items in the window */
398
+ if (ms_setting.cmd_distr[CMD_SET].cmd_prop < PROP_ERROR)
399
+ {
400
+ c->warmup_num= c->win_size;
401
+ c->remain_warmup_num= c->warmup_num;
402
+ }
403
+ else
404
+ {
405
+ c->warmup_num= 0;
406
+ c->remain_warmup_num= c->warmup_num;
407
+ }
408
+ } /* ms_warmup_num_init */
409
+
410
+
411
+ /**
412
+ * each connection has an item window, this function initialize
413
+ * the window. The window is used to generate task.
414
+ *
415
+ * @param c, pointer of the concurrency
416
+ *
417
+ * @return int, if success, return EXIT_SUCCESS, else return -1
418
+ */
419
+ static int ms_item_win_init(ms_conn_t *c)
420
+ {
421
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
422
+ int exp_cnt= 0;
423
+
424
+ c->win_size= (int)ms_setting.win_size;
425
+ c->set_cursor= 0;
426
+ c->exec_num= ms_thread->thread_ctx->exec_num_perconn;
427
+ c->remain_exec_num= c->exec_num;
428
+
429
+ c->item_win= (ms_task_item_t *)malloc(
430
+ sizeof(ms_task_item_t) * (size_t)c->win_size);
431
+ if (c->item_win == NULL)
432
+ {
433
+ fprintf(stderr, "Can't allocate task item array for conn.\n");
434
+ return -1;
435
+ }
436
+ memset(c->item_win, 0, sizeof(ms_task_item_t) * (size_t)c->win_size);
437
+
438
+ for (int i= 0; i < c->win_size; i++)
439
+ {
440
+ c->item_win[i].key_size= (int)ms_setting.distr[i].key_size;
441
+ c->item_win[i].key_prefix= ms_get_key_prefix();
442
+ c->item_win[i].key_suffix_offset= ms_setting.distr[i].key_offset;
443
+ c->item_win[i].value_size= (int)ms_setting.distr[i].value_size;
444
+ c->item_win[i].value_offset= INVALID_OFFSET; /* default in invalid offset */
445
+ c->item_win[i].client_time= 0;
446
+
447
+ /* set expire time base on the proportion */
448
+ if (exp_cnt < ms_setting.exp_ver_per * i)
449
+ {
450
+ c->item_win[i].exp_time= FIXED_EXPIRE_TIME;
451
+ exp_cnt++;
452
+ }
453
+ else
454
+ {
455
+ c->item_win[i].exp_time= 0;
456
+ }
457
+ }
458
+
459
+ ms_warmup_num_init(c);
460
+
461
+ return EXIT_SUCCESS;
462
+ } /* ms_item_win_init */
463
+
464
+
465
+ /**
466
+ * each connection structure can include one or more sock
467
+ * handlers. this function create these socks and connect the
468
+ * server(s).
469
+ *
470
+ * @param c, pointer of the concurrency
471
+ *
472
+ * @return int, if success, return EXIT_SUCCESS, else return -1
473
+ */
474
+ static int ms_conn_sock_init(ms_conn_t *c)
475
+ {
476
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
477
+ uint32_t i;
478
+ int ret_sfd;
479
+ uint32_t srv_idx= 0;
480
+
481
+ assert(c != NULL);
482
+ assert(c->tcpsfd != NULL);
483
+
484
+ for (i= 0; i < c->total_sfds; i++)
485
+ {
486
+ ret_sfd= 0;
487
+ if (ms_setting.rep_write_srv > 0)
488
+ {
489
+ /* for replication, each connection need connect all the server */
490
+ srv_idx= i % ms_setting.srv_cnt;
491
+ }
492
+ else
493
+ {
494
+ /* all the connections in a thread connects the same server */
495
+ srv_idx= ms_thread->thread_ctx->srv_idx;
496
+ }
497
+
498
+ if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
499
+ ms_setting.servers[srv_idx].srv_port,
500
+ ms_setting.udp, &ret_sfd) != 0)
501
+ {
502
+ break;
503
+ }
504
+
505
+ if (i == 0)
506
+ {
507
+ c->sfd= ret_sfd;
508
+ }
509
+
510
+ if (! ms_setting.udp)
511
+ {
512
+ c->tcpsfd[i]= ret_sfd;
513
+ }
514
+
515
+ c->alive_sfds++;
516
+ }
517
+
518
+ /* initialize udp sock handler if necessary */
519
+ if (ms_setting.facebook_test)
520
+ {
521
+ ret_sfd= 0;
522
+ if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
523
+ ms_setting.servers[srv_idx].srv_port,
524
+ true, &ret_sfd) != 0)
525
+ {
526
+ c->udpsfd= 0;
527
+ }
528
+ else
529
+ {
530
+ c->udpsfd= ret_sfd;
531
+ }
532
+ }
533
+
534
+ if ((i != c->total_sfds) || (ms_setting.facebook_test && (c->udpsfd == 0)))
535
+ {
536
+ if (ms_setting.udp)
537
+ {
538
+ close(c->sfd);
539
+ }
540
+ else
541
+ {
542
+ for (uint32_t j= 0; j < i; j++)
543
+ {
544
+ close(c->tcpsfd[j]);
545
+ }
546
+ }
547
+
548
+ if (c->udpsfd != 0)
549
+ {
550
+ close(c->udpsfd);
551
+ }
552
+
553
+ return -1;
554
+ }
555
+
556
+ return EXIT_SUCCESS;
557
+ } /* ms_conn_sock_init */
558
+
559
+
560
+ /**
561
+ * each connection is managed by libevent, this function
562
+ * initialize the event of the connection structure.
563
+ *
564
+ * @param c, pointer of the concurrency
565
+ *
566
+ * @return int, if success, return EXIT_SUCCESS, else return -1
567
+ */
568
+ static int ms_conn_event_init(ms_conn_t *c)
569
+ {
570
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
571
+ short event_flags= EV_WRITE | EV_PERSIST;
572
+
573
+ event_set(&c->event, c->sfd, event_flags, ms_event_handler, (void *)c);
574
+ event_base_set(ms_thread->base, &c->event);
575
+ c->ev_flags= event_flags;
576
+
577
+ if (event_add(&c->event, NULL) == -1)
578
+ {
579
+ return -1;
580
+ }
581
+
582
+ return EXIT_SUCCESS;
583
+ } /* ms_conn_event_init */
584
+
585
+
586
+ /**
587
+ * setup a connection, each connection structure of each
588
+ * thread must call this function to initialize.
589
+ *
590
+ * @param c, pointer of the concurrency
591
+ *
592
+ * @return int, if success, return EXIT_SUCCESS, else return -1
593
+ */
594
+ int ms_setup_conn(ms_conn_t *c)
595
+ {
596
+ if (ms_item_win_init(c) != 0)
597
+ {
598
+ return -1;
599
+ }
600
+
601
+ if (ms_conn_init(c, conn_write, DATA_BUFFER_SIZE, ms_setting.udp) != 0)
602
+ {
603
+ return -1;
604
+ }
605
+
606
+ if (ms_conn_sock_init(c) != 0)
607
+ {
608
+ return -1;
609
+ }
610
+
611
+ if (ms_conn_event_init(c) != 0)
612
+ {
613
+ return -1;
614
+ }
615
+
616
+ return EXIT_SUCCESS;
617
+ } /* ms_setup_conn */
618
+
619
+
620
+ /**
621
+ * Frees a connection.
622
+ *
623
+ * @param c, pointer of the concurrency
624
+ */
625
+ void ms_conn_free(ms_conn_t *c)
626
+ {
627
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
628
+ if (c != NULL)
629
+ {
630
+ if (c->hdrbuf != NULL)
631
+ free(c->hdrbuf);
632
+ if (c->msglist != NULL)
633
+ free(c->msglist);
634
+ if (c->rbuf != NULL)
635
+ free(c->rbuf);
636
+ if (c->wbuf != NULL)
637
+ free(c->wbuf);
638
+ if (c->iov != NULL)
639
+ free(c->iov);
640
+ if (c->mlget_task.mlget_item != NULL)
641
+ free(c->mlget_task.mlget_item);
642
+ if (c->rudpbuf != NULL)
643
+ free(c->rudpbuf);
644
+ if (c->udppkt != NULL)
645
+ free(c->udppkt);
646
+ if (c->item_win != NULL)
647
+ free(c->item_win);
648
+ if (c->tcpsfd != NULL)
649
+ free(c->tcpsfd);
650
+
651
+ if (--ms_thread->nactive_conn == 0)
652
+ {
653
+ free(ms_thread->conn);
654
+ }
655
+ }
656
+ } /* ms_conn_free */
657
+
658
+
659
+ /**
660
+ * close a connection
661
+ *
662
+ * @param c, pointer of the concurrency
663
+ */
664
+ static void ms_conn_close(ms_conn_t *c)
665
+ {
666
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
667
+ assert(c != NULL);
668
+
669
+ /* delete the event, the socket and the connection */
670
+ event_del(&c->event);
671
+
672
+ for (uint32_t i= 0; i < c->total_sfds; i++)
673
+ {
674
+ if (c->tcpsfd[i] > 0)
675
+ {
676
+ close(c->tcpsfd[i]);
677
+ }
678
+ }
679
+ c->sfd= 0;
680
+
681
+ if (ms_setting.facebook_test)
682
+ {
683
+ close(c->udpsfd);
684
+ }
685
+
686
+ atomic_dec_32(&ms_stats.active_conns);
687
+
688
+ ms_conn_free(c);
689
+
690
+ if (ms_setting.run_time == 0)
691
+ {
692
+ pthread_mutex_lock(&ms_global.run_lock.lock);
693
+ ms_global.run_lock.count++;
694
+ pthread_cond_signal(&ms_global.run_lock.cond);
695
+ pthread_mutex_unlock(&ms_global.run_lock.lock);
696
+ }
697
+
698
+ if (ms_thread->nactive_conn == 0)
699
+ {
700
+ pthread_exit(NULL);
701
+ }
702
+ } /* ms_conn_close */
703
+
704
+
705
+ /**
706
+ * create a new sock
707
+ *
708
+ * @param ai, server address information
709
+ *
710
+ * @return int, if success, return EXIT_SUCCESS, else return -1
711
+ */
712
+ static int ms_new_socket(struct addrinfo *ai)
713
+ {
714
+ int sfd;
715
+
716
+ if ((sfd= socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == -1)
717
+ {
718
+ fprintf(stderr, "socket() error: %s.\n", strerror(errno));
719
+ return -1;
720
+ }
721
+
722
+ return sfd;
723
+ } /* ms_new_socket */
724
+
725
+
726
+ /**
727
+ * Sets a socket's send buffer size to the maximum allowed by the system.
728
+ *
729
+ * @param sfd, file descriptor of socket
730
+ */
731
+ static void ms_maximize_sndbuf(const int sfd)
732
+ {
733
+ socklen_t intsize= sizeof(int);
734
+ unsigned int last_good= 0;
735
+ unsigned int min, max, avg;
736
+ unsigned int old_size;
737
+
738
+ /* Start with the default size. */
739
+ if (getsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &old_size, &intsize) != 0)
740
+ {
741
+ fprintf(stderr, "getsockopt(SO_SNDBUF)\n");
742
+ return;
743
+ }
744
+
745
+ /* Binary-search for the real maximum. */
746
+ min= old_size;
747
+ max= MAX_SENDBUF_SIZE;
748
+
749
+ while (min <= max)
750
+ {
751
+ avg= ((unsigned int)(min + max)) / 2;
752
+ if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void *)&avg, intsize) == 0)
753
+ {
754
+ last_good= avg;
755
+ min= avg + 1;
756
+ }
757
+ else
758
+ {
759
+ max= avg - 1;
760
+ }
761
+ }
762
+ } /* ms_maximize_sndbuf */
763
+
764
+
765
+ /**
766
+ * socket connects the server
767
+ *
768
+ * @param c, pointer of the concurrency
769
+ * @param srv_host_name, the host name of the server
770
+ * @param srv_port, port of server
771
+ * @param is_udp, whether it's udp
772
+ * @param ret_sfd, the connected socket file descriptor
773
+ *
774
+ * @return int, if success, return EXIT_SUCCESS, else return -1
775
+ */
776
+ static int ms_network_connect(ms_conn_t *c,
777
+ char *srv_host_name,
778
+ const int srv_port,
779
+ const bool is_udp,
780
+ int *ret_sfd)
781
+ {
782
+ int sfd;
783
+ struct linger ling=
784
+ {
785
+ 0, 0
786
+ };
787
+ struct addrinfo *ai;
788
+ struct addrinfo *next;
789
+ struct addrinfo hints;
790
+ char port_buf[NI_MAXSERV];
791
+ int error;
792
+ int success= 0;
793
+
794
+ int flags= 1;
795
+
796
+ /*
797
+ * the memset call clears nonstandard fields in some impementations
798
+ * that otherwise mess things up.
799
+ */
800
+ memset(&hints, 0, sizeof(hints));
801
+ #ifdef AI_ADDRCONFIG
802
+ hints.ai_flags= AI_PASSIVE | AI_ADDRCONFIG;
803
+ #else
804
+ hints.ai_flags= AI_PASSIVE;
805
+ #endif /* AI_ADDRCONFIG */
806
+ if (is_udp)
807
+ {
808
+ hints.ai_protocol= IPPROTO_UDP;
809
+ hints.ai_socktype= SOCK_DGRAM;
810
+ hints.ai_family= AF_INET; /* This left here because of issues with OSX 10.5 */
811
+ }
812
+ else
813
+ {
814
+ hints.ai_family= AF_UNSPEC;
815
+ hints.ai_protocol= IPPROTO_TCP;
816
+ hints.ai_socktype= SOCK_STREAM;
817
+ }
818
+
819
+ snprintf(port_buf, NI_MAXSERV, "%d", srv_port);
820
+ error= getaddrinfo(srv_host_name, port_buf, &hints, &ai);
821
+ if (error != 0)
822
+ {
823
+ if (error != EAI_SYSTEM)
824
+ fprintf(stderr, "getaddrinfo(): %s.\n", gai_strerror(error));
825
+ else
826
+ perror("getaddrinfo()\n");
827
+
828
+ return -1;
829
+ }
830
+
831
+ for (next= ai; next; next= next->ai_next)
832
+ {
833
+ if ((sfd= ms_new_socket(next)) == -1)
834
+ {
835
+ freeaddrinfo(ai);
836
+ return -1;
837
+ }
838
+
839
+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags));
840
+ if (is_udp)
841
+ {
842
+ ms_maximize_sndbuf(sfd);
843
+ }
844
+ else
845
+ {
846
+ setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&flags,
847
+ sizeof(flags));
848
+ setsockopt(sfd, SOL_SOCKET, SO_LINGER, (void *)&ling, sizeof(ling));
849
+ setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags,
850
+ sizeof(flags));
851
+ }
852
+
853
+ if (is_udp)
854
+ {
855
+ c->srv_recv_addr_size= sizeof(struct sockaddr);
856
+ memcpy(&c->srv_recv_addr, next->ai_addr, c->srv_recv_addr_size);
857
+ }
858
+ else
859
+ {
860
+ if (connect(sfd, next->ai_addr, next->ai_addrlen) == -1)
861
+ {
862
+ close(sfd);
863
+ freeaddrinfo(ai);
864
+ return -1;
865
+ }
866
+ }
867
+
868
+ if (((flags= fcntl(sfd, F_GETFL, 0)) < 0)
869
+ || (fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0))
870
+ {
871
+ fprintf(stderr, "setting O_NONBLOCK\n");
872
+ close(sfd);
873
+ freeaddrinfo(ai);
874
+ return -1;
875
+ }
876
+
877
+ if (ret_sfd != NULL)
878
+ {
879
+ *ret_sfd= sfd;
880
+ }
881
+
882
+ success++;
883
+ }
884
+
885
+ freeaddrinfo(ai);
886
+
887
+ /* Return zero if we detected no errors in starting up connections */
888
+ return success == 0;
889
+ } /* ms_network_connect */
890
+
891
+
892
+ /**
893
+ * reconnect a disconnected sock
894
+ *
895
+ * @param c, pointer of the concurrency
896
+ *
897
+ * @return int, if success, return EXIT_SUCCESS, else return -1
898
+ */
899
+ static int ms_reconn(ms_conn_t *c)
900
+ {
901
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
902
+ uint32_t srv_idx= 0;
903
+ uint32_t srv_conn_cnt= 0;
904
+
905
+ if (ms_setting.rep_write_srv > 0)
906
+ {
907
+ srv_idx= c->cur_idx % ms_setting.srv_cnt;
908
+ srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
909
+ }
910
+ else
911
+ {
912
+ srv_idx= ms_thread->thread_ctx->srv_idx;
913
+ srv_conn_cnt= ms_setting.nconns / ms_setting.srv_cnt;
914
+ }
915
+
916
+ /* close the old socket handler */
917
+ close(c->sfd);
918
+ c->tcpsfd[c->cur_idx]= 0;
919
+
920
+ if (atomic_add_32_nv(&ms_setting.servers[srv_idx].disconn_cnt, 1)
921
+ % srv_conn_cnt == 0)
922
+ {
923
+ gettimeofday(&ms_setting.servers[srv_idx].disconn_time, NULL);
924
+ fprintf(stderr, "Server %s:%d disconnect\n",
925
+ ms_setting.servers[srv_idx].srv_host_name,
926
+ ms_setting.servers[srv_idx].srv_port);
927
+ }
928
+
929
+ if (ms_setting.rep_write_srv > 0)
930
+ {
931
+ uint32_t i= 0;
932
+
933
+ for (i= 0; i < c->total_sfds; i++)
934
+ {
935
+ if (c->tcpsfd[i] != 0)
936
+ {
937
+ break;
938
+ }
939
+ }
940
+
941
+ /* all socks disconnect */
942
+ if (i == c->total_sfds)
943
+ {
944
+ return -1;
945
+ }
946
+ }
947
+ else
948
+ {
949
+ do
950
+ {
951
+ /* reconnect success, break the loop */
952
+ if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
953
+ ms_setting.servers[srv_idx].srv_port,
954
+ ms_setting.udp, &c->sfd) == 0)
955
+ {
956
+ c->tcpsfd[c->cur_idx]= c->sfd;
957
+ if (atomic_add_32_nv(&ms_setting.servers[srv_idx].reconn_cnt, 1)
958
+ % (uint32_t)srv_conn_cnt == 0)
959
+ {
960
+ gettimeofday(&ms_setting.servers[srv_idx].reconn_time, NULL);
961
+ int reconn_time=
962
+ (int)(ms_setting.servers[srv_idx].reconn_time.tv_sec
963
+ - ms_setting.servers[srv_idx].disconn_time
964
+ .tv_sec);
965
+ fprintf(stderr, "Server %s:%d reconnect after %ds\n",
966
+ ms_setting.servers[srv_idx].srv_host_name,
967
+ ms_setting.servers[srv_idx].srv_port, reconn_time);
968
+ }
969
+ break;
970
+ }
971
+
972
+ if (ms_setting.rep_write_srv == 0 && c->total_sfds > 0)
973
+ {
974
+ /* wait a second and reconnect */
975
+ sleep(1);
976
+ }
977
+ }
978
+ while (ms_setting.rep_write_srv == 0 && c->total_sfds > 0);
979
+ }
980
+
981
+ if ((c->total_sfds > 1) && (c->tcpsfd[c->cur_idx] == 0))
982
+ {
983
+ c->sfd= 0;
984
+ c->alive_sfds--;
985
+ }
986
+
987
+ return EXIT_SUCCESS;
988
+ } /* ms_reconn */
989
+
990
+
991
+ /**
992
+ * reconnect several disconnected socks in the connection
993
+ * structure, the ever-1-second timer of the thread will check
994
+ * whether some socks in the connections disconnect. if
995
+ * disconnect, reconnect the sock.
996
+ *
997
+ * @param c, pointer of the concurrency
998
+ *
999
+ * @return int, if success, return EXIT_SUCCESS, else return -1
1000
+ */
1001
+ int ms_reconn_socks(ms_conn_t *c)
1002
+ {
1003
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
1004
+ uint32_t srv_idx= 0;
1005
+ int ret_sfd= 0;
1006
+ uint32_t srv_conn_cnt= 0;
1007
+ struct timeval cur_time;
1008
+
1009
+ assert(c != NULL);
1010
+
1011
+ if ((c->total_sfds == 1) || (c->total_sfds == c->alive_sfds))
1012
+ {
1013
+ return EXIT_SUCCESS;
1014
+ }
1015
+
1016
+ for (uint32_t i= 0; i < c->total_sfds; i++)
1017
+ {
1018
+ if (c->tcpsfd[i] == 0)
1019
+ {
1020
+ gettimeofday(&cur_time, NULL);
1021
+
1022
+ /**
1023
+ * For failover test of replication, reconnect the socks after
1024
+ * it disconnects more than 5 seconds, Otherwise memslap will
1025
+ * block at connect() function and the work threads can't work
1026
+ * in this interval.
1027
+ */
1028
+ if (cur_time.tv_sec
1029
+ - ms_setting.servers[srv_idx].disconn_time.tv_sec < 5)
1030
+ {
1031
+ break;
1032
+ }
1033
+
1034
+ if (ms_setting.rep_write_srv > 0)
1035
+ {
1036
+ srv_idx= i % ms_setting.srv_cnt;
1037
+ srv_conn_cnt= ms_setting.sock_per_conn * ms_setting.nconns;
1038
+ }
1039
+ else
1040
+ {
1041
+ srv_idx= ms_thread->thread_ctx->srv_idx;
1042
+ srv_conn_cnt= ms_setting.nconns / ms_setting.srv_cnt;
1043
+ }
1044
+
1045
+ if (ms_network_connect(c, ms_setting.servers[srv_idx].srv_host_name,
1046
+ ms_setting.servers[srv_idx].srv_port,
1047
+ ms_setting.udp, &ret_sfd) == 0)
1048
+ {
1049
+ c->tcpsfd[i]= ret_sfd;
1050
+ c->alive_sfds++;
1051
+
1052
+ if (atomic_add_32_nv(&ms_setting.servers[srv_idx].reconn_cnt, 1)
1053
+ % (uint32_t)srv_conn_cnt == 0)
1054
+ {
1055
+ gettimeofday(&ms_setting.servers[srv_idx].reconn_time, NULL);
1056
+ int reconn_time=
1057
+ (int)(ms_setting.servers[srv_idx].reconn_time.tv_sec
1058
+ - ms_setting.servers[srv_idx].disconn_time
1059
+ .tv_sec);
1060
+ fprintf(stderr, "Server %s:%d reconnect after %ds\n",
1061
+ ms_setting.servers[srv_idx].srv_host_name,
1062
+ ms_setting.servers[srv_idx].srv_port, reconn_time);
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+
1068
+ return EXIT_SUCCESS;
1069
+ } /* ms_reconn_socks */
1070
+
1071
+
1072
+ /**
1073
+ * Tokenize the command string by replacing whitespace with '\0' and update
1074
+ * the token array tokens with pointer to start of each token and length.
1075
+ * Returns total number of tokens. The last valid token is the terminal
1076
+ * token (value points to the first unprocessed character of the string and
1077
+ * length zero).
1078
+ *
1079
+ * Usage example:
1080
+ *
1081
+ * while(ms_tokenize_command(command, ncommand, tokens, max_tokens) > 0) {
1082
+ * for(int ix = 0; tokens[ix].length != 0; ix++) {
1083
+ * ...
1084
+ * }
1085
+ * ncommand = tokens[ix].value - command;
1086
+ * command = tokens[ix].value;
1087
+ * }
1088
+ *
1089
+ * @param command, the command string to token
1090
+ * @param tokens, array to store tokens
1091
+ * @param max_tokens, maximum tokens number
1092
+ *
1093
+ * @return int, the number of tokens
1094
+ */
1095
+ static int ms_tokenize_command(char *command,
1096
+ token_t *tokens,
1097
+ const int max_tokens)
1098
+ {
1099
+ char *s, *e;
1100
+ int ntokens= 0;
1101
+
1102
+ assert(command != NULL && tokens != NULL && max_tokens > 1);
1103
+
1104
+ for (s= e= command; ntokens < max_tokens - 1; ++e)
1105
+ {
1106
+ if (*e == ' ')
1107
+ {
1108
+ if (s != e)
1109
+ {
1110
+ tokens[ntokens].value= s;
1111
+ tokens[ntokens].length= (size_t)(e - s);
1112
+ ntokens++;
1113
+ *e= '\0';
1114
+ }
1115
+ s= e + 1;
1116
+ }
1117
+ else if (*e == '\0')
1118
+ {
1119
+ if (s != e)
1120
+ {
1121
+ tokens[ntokens].value= s;
1122
+ tokens[ntokens].length= (size_t)(e - s);
1123
+ ntokens++;
1124
+ }
1125
+
1126
+ break; /* string end */
1127
+ }
1128
+ }
1129
+
1130
+ return ntokens;
1131
+ } /* ms_tokenize_command */
1132
+
1133
+
1134
+ /**
1135
+ * parse the response of server.
1136
+ *
1137
+ * @param c, pointer of the concurrency
1138
+ * @param command, the string responded by server
1139
+ *
1140
+ * @return int, if the command completed return EXIT_SUCCESS, else return
1141
+ * -1
1142
+ */
1143
+ static int ms_ascii_process_line(ms_conn_t *c, char *command)
1144
+ {
1145
+ int ret= 0;
1146
+ int64_t value_len;
1147
+ char *buffer= command;
1148
+
1149
+ assert(c != NULL);
1150
+
1151
+ /**
1152
+ * for command get, we store the returned value into local buffer
1153
+ * then continue in ms_complete_nread().
1154
+ */
1155
+
1156
+ switch (buffer[0])
1157
+ {
1158
+ case 'V': /* VALUE || VERSION */
1159
+ if (buffer[1] == 'A') /* VALUE */
1160
+ {
1161
+ token_t tokens[MAX_TOKENS];
1162
+ ms_tokenize_command(command, tokens, MAX_TOKENS);
1163
+ value_len= strtol(tokens[VALUELEN_TOKEN].value, NULL, 10);
1164
+ c->currcmd.key_prefix= *(uint64_t *)tokens[KEY_TOKEN].value;
1165
+
1166
+ /*
1167
+ * We read the \r\n into the string since not doing so is more
1168
+ * cycles then the waster of memory to do so.
1169
+ *
1170
+ * We are null terminating through, which will most likely make
1171
+ * some people lazy about using the return length.
1172
+ */
1173
+ c->rvbytes= (int)(value_len + 2);
1174
+ c->readval= true;
1175
+ ret= -1;
1176
+ }
1177
+
1178
+ break;
1179
+
1180
+ case 'O': /* OK */
1181
+ c->currcmd.retstat= MCD_SUCCESS;
1182
+
1183
+ case 'S': /* STORED STATS SERVER_ERROR */
1184
+ if (buffer[2] == 'A') /* STORED STATS */
1185
+ { /* STATS*/
1186
+ c->currcmd.retstat= MCD_STAT;
1187
+ }
1188
+ else if (buffer[1] == 'E')
1189
+ {
1190
+ /* SERVER_ERROR */
1191
+ printf("<%d %s\n", c->sfd, buffer);
1192
+
1193
+ c->currcmd.retstat= MCD_SERVER_ERROR;
1194
+ }
1195
+ else if (buffer[1] == 'T')
1196
+ {
1197
+ /* STORED */
1198
+ c->currcmd.retstat= MCD_STORED;
1199
+ }
1200
+ else
1201
+ {
1202
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
1203
+ }
1204
+ break;
1205
+
1206
+ case 'D': /* DELETED DATA */
1207
+ if (buffer[1] == 'E')
1208
+ {
1209
+ c->currcmd.retstat= MCD_DELETED;
1210
+ }
1211
+ else
1212
+ {
1213
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
1214
+ }
1215
+
1216
+ break;
1217
+
1218
+ case 'N': /* NOT_FOUND NOT_STORED*/
1219
+ if (buffer[4] == 'F')
1220
+ {
1221
+ c->currcmd.retstat= MCD_NOTFOUND;
1222
+ }
1223
+ else if (buffer[4] == 'S')
1224
+ {
1225
+ printf("<%d %s\n", c->sfd, buffer);
1226
+ c->currcmd.retstat= MCD_NOTSTORED;
1227
+ }
1228
+ else
1229
+ {
1230
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
1231
+ }
1232
+ break;
1233
+
1234
+ case 'E': /* PROTOCOL ERROR or END */
1235
+ if (buffer[1] == 'N')
1236
+ {
1237
+ /* END */
1238
+ c->currcmd.retstat= MCD_END;
1239
+ }
1240
+ else if (buffer[1] == 'R')
1241
+ {
1242
+ printf("<%d ERROR\n", c->sfd);
1243
+ c->currcmd.retstat= MCD_PROTOCOL_ERROR;
1244
+ }
1245
+ else if (buffer[1] == 'X')
1246
+ {
1247
+ c->currcmd.retstat= MCD_DATA_EXISTS;
1248
+ printf("<%d %s\n", c->sfd, buffer);
1249
+ }
1250
+ else
1251
+ {
1252
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
1253
+ }
1254
+ break;
1255
+
1256
+ case 'C': /* CLIENT ERROR */
1257
+ printf("<%d %s\n", c->sfd, buffer);
1258
+ c->currcmd.retstat= MCD_CLIENT_ERROR;
1259
+ break;
1260
+
1261
+ default:
1262
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
1263
+ break;
1264
+ } /* switch */
1265
+
1266
+ return ret;
1267
+ } /* ms_ascii_process_line */
1268
+
1269
+
1270
+ /**
1271
+ * after one operation completes, reset the concurrency
1272
+ *
1273
+ * @param c, pointer of the concurrency
1274
+ * @param timeout, whether it's timeout
1275
+ */
1276
+ void ms_reset_conn(ms_conn_t *c, bool timeout)
1277
+ {
1278
+ assert(c != NULL);
1279
+
1280
+ if (c->udp)
1281
+ {
1282
+ if ((c->packets > 0) && (c->packets < MAX_UDP_PACKET))
1283
+ {
1284
+ memset(c->udppkt, 0, sizeof(ms_udppkt_t) * (size_t)c->packets);
1285
+ }
1286
+
1287
+ c->packets= 0;
1288
+ c->recvpkt= 0;
1289
+ c->pktcurr= 0;
1290
+ c->ordcurr= 0;
1291
+ c->rudpbytes= 0;
1292
+ }
1293
+ c->currcmd.isfinish= true;
1294
+ c->ctnwrite= false;
1295
+ c->rbytes= 0;
1296
+ c->rcurr= c->rbuf;
1297
+ c->msgcurr = 0;
1298
+ c->msgused = 0;
1299
+ c->iovused = 0;
1300
+ ms_conn_set_state(c, conn_write);
1301
+ memcpy(&c->precmd, &c->currcmd, sizeof(ms_cmdstat_t)); /* replicate command state */
1302
+
1303
+ if (timeout)
1304
+ {
1305
+ ms_drive_machine(c);
1306
+ }
1307
+ } /* ms_reset_conn */
1308
+
1309
+
1310
+ /**
1311
+ * if we have a complete line in the buffer, process it.
1312
+ *
1313
+ * @param c, pointer of the concurrency
1314
+ *
1315
+ * @return int, if success, return EXIT_SUCCESS, else return -1
1316
+ */
1317
+ static int ms_try_read_line(ms_conn_t *c)
1318
+ {
1319
+ if (c->protocol == binary_prot)
1320
+ {
1321
+ /* Do we have the complete packet header? */
1322
+ if ((uint64_t)c->rbytes < sizeof(c->binary_header))
1323
+ {
1324
+ /* need more data! */
1325
+ return EXIT_SUCCESS;
1326
+ }
1327
+ else
1328
+ {
1329
+ #ifdef NEED_ALIGN
1330
+ if (((long)(c->rcurr)) % 8 != 0)
1331
+ {
1332
+ /* must realign input buffer */
1333
+ memmove(c->rbuf, c->rcurr, c->rbytes);
1334
+ c->rcurr= c->rbuf;
1335
+ if (settings.verbose)
1336
+ {
1337
+ fprintf(stderr, "%d: Realign input buffer.\n", c->sfd);
1338
+ }
1339
+ }
1340
+ #endif
1341
+ protocol_binary_response_header *rsp;
1342
+ rsp= (protocol_binary_response_header *)c->rcurr;
1343
+
1344
+ c->binary_header= *rsp;
1345
+ c->binary_header.response.extlen= rsp->response.extlen;
1346
+ c->binary_header.response.keylen= ntohs(rsp->response.keylen);
1347
+ c->binary_header.response.bodylen= ntohl(rsp->response.bodylen);
1348
+ c->binary_header.response.status= ntohs(rsp->response.status);
1349
+
1350
+ if (c->binary_header.response.magic != PROTOCOL_BINARY_RES)
1351
+ {
1352
+ fprintf(stderr, "Invalid magic: %x\n",
1353
+ c->binary_header.response.magic);
1354
+ ms_conn_set_state(c, conn_closing);
1355
+ return EXIT_SUCCESS;
1356
+ }
1357
+
1358
+ /* process this complete response */
1359
+ if (ms_bin_process_response(c) == 0)
1360
+ {
1361
+ /* current operation completed */
1362
+ ms_reset_conn(c, false);
1363
+ return -1;
1364
+ }
1365
+ else
1366
+ {
1367
+ c->rbytes-= (int32_t)sizeof(c->binary_header);
1368
+ c->rcurr+= sizeof(c->binary_header);
1369
+ }
1370
+ }
1371
+ }
1372
+ else
1373
+ {
1374
+ char *el, *cont;
1375
+
1376
+ assert(c != NULL);
1377
+ assert(c->rcurr <= (c->rbuf + c->rsize));
1378
+
1379
+ if (c->rbytes == 0)
1380
+ return EXIT_SUCCESS;
1381
+
1382
+ el= memchr(c->rcurr, '\n', (size_t)c->rbytes);
1383
+ if (! el)
1384
+ return EXIT_SUCCESS;
1385
+
1386
+ cont= el + 1;
1387
+ if (((el - c->rcurr) > 1) && (*(el - 1) == '\r'))
1388
+ {
1389
+ el--;
1390
+ }
1391
+ *el= '\0';
1392
+
1393
+ assert(cont <= (c->rcurr + c->rbytes));
1394
+
1395
+ /* process this complete line */
1396
+ if (ms_ascii_process_line(c, c->rcurr) == 0)
1397
+ {
1398
+ /* current operation completed */
1399
+ ms_reset_conn(c, false);
1400
+ return -1;
1401
+ }
1402
+ else
1403
+ {
1404
+ /* current operation didn't complete */
1405
+ c->rbytes-= (int32_t)(cont - c->rcurr);
1406
+ c->rcurr= cont;
1407
+ }
1408
+
1409
+ assert(c->rcurr <= (c->rbuf + c->rsize));
1410
+ }
1411
+
1412
+ return -1;
1413
+ } /* ms_try_read_line */
1414
+
1415
+
1416
+ /**
1417
+ * because the packet of UDP can't ensure the order, the
1418
+ * function is used to sort the received udp packet.
1419
+ *
1420
+ * @param c, pointer of the concurrency
1421
+ * @param buf, the buffer to store the ordered packages data
1422
+ * @param rbytes, the maximum capacity of the buffer
1423
+ *
1424
+ * @return int, if success, return the copy bytes, else return
1425
+ * -1
1426
+ */
1427
+ static int ms_sort_udp_packet(ms_conn_t *c, char *buf, int rbytes)
1428
+ {
1429
+ int len= 0;
1430
+ int wbytes= 0;
1431
+ uint16_t req_id= 0;
1432
+ uint16_t seq_num= 0;
1433
+ uint16_t packets= 0;
1434
+ unsigned char *header= NULL;
1435
+
1436
+ /* no enough data */
1437
+ assert(c != NULL);
1438
+ assert(buf != NULL);
1439
+ assert(c->rudpbytes >= UDP_HEADER_SIZE);
1440
+
1441
+ /* calculate received packets count */
1442
+ if (c->rudpbytes % UDP_MAX_PAYLOAD_SIZE >= UDP_HEADER_SIZE)
1443
+ {
1444
+ /* the last packet has some data */
1445
+ c->recvpkt= c->rudpbytes / UDP_MAX_PAYLOAD_SIZE + 1;
1446
+ }
1447
+ else
1448
+ {
1449
+ c->recvpkt= c->rudpbytes / UDP_MAX_PAYLOAD_SIZE;
1450
+ }
1451
+
1452
+ /* get the total packets count if necessary */
1453
+ if (c->packets == 0)
1454
+ {
1455
+ c->packets= HEADER_TO_PACKETS((unsigned char *)c->rudpbuf);
1456
+ }
1457
+
1458
+ /* build the ordered packet array */
1459
+ for (int i= c->pktcurr; i < c->recvpkt; i++)
1460
+ {
1461
+ header= (unsigned char *)c->rudpbuf + i * UDP_MAX_PAYLOAD_SIZE;
1462
+ req_id= (uint16_t)HEADER_TO_REQID(header);
1463
+ assert(req_id == c->request_id % (1 << 16));
1464
+
1465
+ packets= (uint16_t)HEADER_TO_PACKETS(header);
1466
+ assert(c->packets == HEADER_TO_PACKETS(header));
1467
+
1468
+ seq_num= (uint16_t)HEADER_TO_SEQNUM(header);
1469
+ c->udppkt[seq_num].header= header;
1470
+ c->udppkt[seq_num].data= (char *)header + UDP_HEADER_SIZE;
1471
+
1472
+ if (i == c->recvpkt - 1)
1473
+ {
1474
+ /* last received packet */
1475
+ if (c->rudpbytes % UDP_MAX_PAYLOAD_SIZE == 0)
1476
+ {
1477
+ c->udppkt[seq_num].rbytes= UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE;
1478
+ c->pktcurr++;
1479
+ }
1480
+ else
1481
+ {
1482
+ c->udppkt[seq_num].rbytes= c->rudpbytes % UDP_MAX_PAYLOAD_SIZE
1483
+ - UDP_HEADER_SIZE;
1484
+ }
1485
+ }
1486
+ else
1487
+ {
1488
+ c->udppkt[seq_num].rbytes= UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE;
1489
+ c->pktcurr++;
1490
+ }
1491
+ }
1492
+
1493
+ for (int i= c->ordcurr; i < c->recvpkt; i++)
1494
+ {
1495
+ /* there is some data to copy */
1496
+ if ((c->udppkt[i].data != NULL)
1497
+ && (c->udppkt[i].copybytes < c->udppkt[i].rbytes))
1498
+ {
1499
+ header= c->udppkt[i].header;
1500
+ len= c->udppkt[i].rbytes - c->udppkt[i].copybytes;
1501
+ if (len > rbytes - wbytes)
1502
+ {
1503
+ len= rbytes - wbytes;
1504
+ }
1505
+
1506
+ assert(len <= rbytes - wbytes);
1507
+ assert(i == HEADER_TO_SEQNUM(header));
1508
+
1509
+ memcpy(buf + wbytes, c->udppkt[i].data + c->udppkt[i].copybytes,
1510
+ (size_t)len);
1511
+ wbytes+= len;
1512
+ c->udppkt[i].copybytes+= len;
1513
+
1514
+ if ((c->udppkt[i].copybytes == c->udppkt[i].rbytes)
1515
+ && (c->udppkt[i].rbytes == UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE))
1516
+ {
1517
+ /* finish copying all the data of this packet, next */
1518
+ c->ordcurr++;
1519
+ }
1520
+
1521
+ /* last received packet, and finish copying all the data */
1522
+ if ((c->recvpkt == c->packets) && (i == c->recvpkt - 1)
1523
+ && (c->udppkt[i].copybytes == c->udppkt[i].rbytes))
1524
+ {
1525
+ break;
1526
+ }
1527
+
1528
+ /* no space to copy data */
1529
+ if (wbytes >= rbytes)
1530
+ {
1531
+ break;
1532
+ }
1533
+
1534
+ /* it doesn't finish reading all the data of the packet from network */
1535
+ if ((i != c->recvpkt - 1)
1536
+ && (c->udppkt[i].rbytes < UDP_MAX_PAYLOAD_SIZE - UDP_HEADER_SIZE))
1537
+ {
1538
+ break;
1539
+ }
1540
+ }
1541
+ else
1542
+ {
1543
+ /* no data to copy */
1544
+ break;
1545
+ }
1546
+ }
1547
+
1548
+ return wbytes == 0 ? -1 : wbytes;
1549
+ } /* ms_sort_udp_packet */
1550
+
1551
+
1552
+ /**
1553
+ * encapsulate upd read like tcp read
1554
+ *
1555
+ * @param c, pointer of the concurrency
1556
+ * @param buf, read buffer
1557
+ * @param len, length to read
1558
+ *
1559
+ * @return int, if success, return the read bytes, else return
1560
+ * -1
1561
+ */
1562
+ static int ms_udp_read(ms_conn_t *c, char *buf, int len)
1563
+ {
1564
+ int res= 0;
1565
+ int avail= 0;
1566
+ int rbytes= 0;
1567
+ int copybytes= 0;
1568
+
1569
+ assert(c->udp);
1570
+
1571
+ while (1)
1572
+ {
1573
+ if (c->rudpbytes + UDP_MAX_PAYLOAD_SIZE > c->rudpsize)
1574
+ {
1575
+ char *new_rbuf= realloc(c->rudpbuf, (size_t)c->rudpsize * 2);
1576
+ if (! new_rbuf)
1577
+ {
1578
+ fprintf(stderr, "Couldn't realloc input buffer.\n");
1579
+ c->rudpbytes= 0; /* ignore what we read */
1580
+ return -1;
1581
+ }
1582
+ c->rudpbuf= new_rbuf;
1583
+ c->rudpsize*= 2;
1584
+ }
1585
+
1586
+ avail= c->rudpsize - c->rudpbytes;
1587
+ /* UDP each time read a packet, 1400 bytes */
1588
+ res= (int)read(c->sfd, c->rudpbuf + c->rudpbytes, (size_t)avail);
1589
+
1590
+ if (res > 0)
1591
+ {
1592
+ atomic_add_size(&ms_stats.bytes_read, res);
1593
+ c->rudpbytes+= res;
1594
+ rbytes+= res;
1595
+ if (res == avail)
1596
+ {
1597
+ continue;
1598
+ }
1599
+ else
1600
+ {
1601
+ break;
1602
+ }
1603
+ }
1604
+
1605
+ if (res == 0)
1606
+ {
1607
+ /* "connection" closed */
1608
+ return res;
1609
+ }
1610
+
1611
+ if (res == -1)
1612
+ {
1613
+ /* no data to read */
1614
+ return res;
1615
+ }
1616
+ }
1617
+
1618
+ /* copy data to read buffer */
1619
+ if (rbytes > 0)
1620
+ {
1621
+ copybytes= ms_sort_udp_packet(c, buf, len);
1622
+ }
1623
+
1624
+ if (copybytes == -1)
1625
+ {
1626
+ atomic_add_size(&ms_stats.pkt_disorder, 1);
1627
+ }
1628
+
1629
+ return copybytes;
1630
+ } /* ms_udp_read */
1631
+
1632
+
1633
+ /*
1634
+ * read from network as much as we can, handle buffer overflow and connection
1635
+ * close.
1636
+ * before reading, move the remaining incomplete fragment of a command
1637
+ * (if any) to the beginning of the buffer.
1638
+ * return EXIT_SUCCESS if there's nothing to read on the first read.
1639
+ */
1640
+
1641
+ /**
1642
+ * read from network as much as we can, handle buffer overflow and connection
1643
+ * close. before reading, move the remaining incomplete fragment of a command
1644
+ * (if any) to the beginning of the buffer.
1645
+ *
1646
+ * @param c, pointer of the concurrency
1647
+ *
1648
+ * @return int,
1649
+ * return EXIT_SUCCESS if there's nothing to read on the first read.
1650
+ * return EXIT_FAILURE if get data
1651
+ * return -1 if error happens
1652
+ */
1653
+ static int ms_try_read_network(ms_conn_t *c)
1654
+ {
1655
+ int gotdata= 0;
1656
+ int res;
1657
+ int64_t avail;
1658
+
1659
+ assert(c != NULL);
1660
+
1661
+ if ((c->rcurr != c->rbuf)
1662
+ && (! c->readval || (c->rvbytes > c->rsize - (c->rcurr - c->rbuf))
1663
+ || (c->readval && (c->rcurr - c->rbuf > c->rbytes))))
1664
+ {
1665
+ if (c->rbytes != 0) /* otherwise there's nothing to copy */
1666
+ memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
1667
+ c->rcurr= c->rbuf;
1668
+ }
1669
+
1670
+ while (1)
1671
+ {
1672
+ if (c->rbytes >= c->rsize)
1673
+ {
1674
+ char *new_rbuf= realloc(c->rbuf, (size_t)c->rsize * 2);
1675
+ if (! new_rbuf)
1676
+ {
1677
+ fprintf(stderr, "Couldn't realloc input buffer.\n");
1678
+ c->rbytes= 0; /* ignore what we read */
1679
+ return -1;
1680
+ }
1681
+ c->rcurr= c->rbuf= new_rbuf;
1682
+ c->rsize*= 2;
1683
+ }
1684
+
1685
+ avail= c->rsize - c->rbytes - (c->rcurr - c->rbuf);
1686
+ if (avail == 0)
1687
+ {
1688
+ break;
1689
+ }
1690
+
1691
+ if (c->udp)
1692
+ {
1693
+ res= (int32_t)ms_udp_read(c, c->rcurr + c->rbytes, (int32_t)avail);
1694
+ }
1695
+ else
1696
+ {
1697
+ res= (int)read(c->sfd, c->rcurr + c->rbytes, (size_t)avail);
1698
+ }
1699
+
1700
+ if (res > 0)
1701
+ {
1702
+ if (! c->udp)
1703
+ {
1704
+ atomic_add_size(&ms_stats.bytes_read, res);
1705
+ }
1706
+ gotdata= 1;
1707
+ c->rbytes+= res;
1708
+ if (res == avail)
1709
+ {
1710
+ continue;
1711
+ }
1712
+ else
1713
+ {
1714
+ break;
1715
+ }
1716
+ }
1717
+ if (res == 0)
1718
+ {
1719
+ /* connection closed */
1720
+ ms_conn_set_state(c, conn_closing);
1721
+ return -1;
1722
+ }
1723
+ if (res == -1)
1724
+ {
1725
+ if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
1726
+ break;
1727
+ /* Should close on unhandled errors. */
1728
+ ms_conn_set_state(c, conn_closing);
1729
+ return -1;
1730
+ }
1731
+ }
1732
+
1733
+ return gotdata;
1734
+ } /* ms_try_read_network */
1735
+
1736
+
1737
+ /**
1738
+ * after get the object from server, verify the value if
1739
+ * necessary.
1740
+ *
1741
+ * @param c, pointer of the concurrency
1742
+ * @param mlget_item, pointer of mulit-get task item structure
1743
+ * @param value, received value string
1744
+ * @param vlen, received value string length
1745
+ */
1746
+ static void ms_verify_value(ms_conn_t *c,
1747
+ ms_mlget_task_item_t *mlget_item,
1748
+ char *value,
1749
+ int vlen)
1750
+ {
1751
+ if (c->curr_task.verify)
1752
+ {
1753
+ assert(c->curr_task.item->value_offset != INVALID_OFFSET);
1754
+ char *orignval= &ms_setting.char_block[c->curr_task.item->value_offset];
1755
+ char *orignkey=
1756
+ &ms_setting.char_block[c->curr_task.item->key_suffix_offset];
1757
+
1758
+ /* verify expire time if necessary */
1759
+ if (c->curr_task.item->exp_time > 0)
1760
+ {
1761
+ struct timeval curr_time;
1762
+ gettimeofday(&curr_time, NULL);
1763
+
1764
+ /* object expired but get it now */
1765
+ if (curr_time.tv_sec - c->curr_task.item->client_time
1766
+ > c->curr_task.item->exp_time + EXPIRE_TIME_ERROR)
1767
+ {
1768
+ atomic_add_size(&ms_stats.exp_get, 1);
1769
+
1770
+ if (ms_setting.verbose)
1771
+ {
1772
+ char set_time[64];
1773
+ char cur_time[64];
1774
+ strftime(set_time, 64, "%Y-%m-%d %H:%M:%S",
1775
+ localtime(&c->curr_task.item->client_time));
1776
+ strftime(cur_time, 64, "%Y-%m-%d %H:%M:%S",
1777
+ localtime(&curr_time.tv_sec));
1778
+ fprintf(stderr,
1779
+ "\n<%d expire time verification failed, "
1780
+ "object expired but get it now\n"
1781
+ "\tkey len: %d\n"
1782
+ "\tkey: %" PRIx64 " %.*s\n"
1783
+ "\tset time: %s current time: %s "
1784
+ "diff time: %d expire time: %d\n"
1785
+ "\texpected data: \n"
1786
+ "\treceived data len: %d\n"
1787
+ "\treceived data: %.*s\n",
1788
+ c->sfd,
1789
+ c->curr_task.item->key_size,
1790
+ c->curr_task.item->key_prefix,
1791
+ c->curr_task.item->key_size - (int)KEY_PREFIX_SIZE,
1792
+ orignkey,
1793
+ set_time,
1794
+ cur_time,
1795
+ (int)(curr_time.tv_sec - c->curr_task.item->client_time),
1796
+ c->curr_task.item->exp_time,
1797
+ vlen,
1798
+ vlen,
1799
+ value);
1800
+ fflush(stderr);
1801
+ }
1802
+ }
1803
+ }
1804
+ else
1805
+ {
1806
+ if ((c->curr_task.item->value_size != vlen)
1807
+ || (memcmp(orignval, value, (size_t)vlen) != 0))
1808
+ {
1809
+ atomic_add_size(&ms_stats.vef_failed, 1);
1810
+
1811
+ if (ms_setting.verbose)
1812
+ {
1813
+ fprintf(stderr,
1814
+ "\n<%d data verification failed\n"
1815
+ "\tkey len: %d\n"
1816
+ "\tkey: %" PRIx64" %.*s\n"
1817
+ "\texpected data len: %d\n"
1818
+ "\texpected data: %.*s\n"
1819
+ "\treceived data len: %d\n"
1820
+ "\treceived data: %.*s\n",
1821
+ c->sfd,
1822
+ c->curr_task.item->key_size,
1823
+ c->curr_task.item->key_prefix,
1824
+ c->curr_task.item->key_size - (int)KEY_PREFIX_SIZE,
1825
+ orignkey,
1826
+ c->curr_task.item->value_size,
1827
+ c->curr_task.item->value_size,
1828
+ orignval,
1829
+ vlen,
1830
+ vlen,
1831
+ value);
1832
+ fflush(stderr);
1833
+ }
1834
+ }
1835
+ }
1836
+
1837
+ c->curr_task.finish_verify= true;
1838
+
1839
+ if (mlget_item != NULL)
1840
+ {
1841
+ mlget_item->finish_verify= true;
1842
+ }
1843
+ }
1844
+ } /* ms_verify_value */
1845
+
1846
+
1847
+ /**
1848
+ * For ASCII protocol, after store the data into the local
1849
+ * buffer, run this function to handle the data.
1850
+ *
1851
+ * @param c, pointer of the concurrency
1852
+ */
1853
+ static void ms_ascii_complete_nread(ms_conn_t *c)
1854
+ {
1855
+ assert(c != NULL);
1856
+ assert(c->rbytes >= c->rvbytes);
1857
+ assert(c->protocol == ascii_prot);
1858
+ if (c->rvbytes > 2)
1859
+ {
1860
+ assert(
1861
+ c->rcurr[c->rvbytes - 1] == '\n' && c->rcurr[c->rvbytes - 2] == '\r');
1862
+ }
1863
+
1864
+ /* multi-get */
1865
+ ms_mlget_task_item_t *mlget_item= NULL;
1866
+ if (((ms_setting.mult_key_num > 1)
1867
+ && (c->mlget_task.mlget_num >= ms_setting.mult_key_num))
1868
+ || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
1869
+ {
1870
+ c->mlget_task.value_index++;
1871
+ mlget_item= &c->mlget_task.mlget_item[c->mlget_task.value_index];
1872
+
1873
+ if (mlget_item->item->key_prefix == c->currcmd.key_prefix)
1874
+ {
1875
+ c->curr_task.item= mlget_item->item;
1876
+ c->curr_task.verify= mlget_item->verify;
1877
+ c->curr_task.finish_verify= mlget_item->finish_verify;
1878
+ mlget_item->get_miss= false;
1879
+ }
1880
+ else
1881
+ {
1882
+ /* Try to find the task item in multi-get task array */
1883
+ for (int i= 0; i < c->mlget_task.mlget_num; i++)
1884
+ {
1885
+ mlget_item= &c->mlget_task.mlget_item[i];
1886
+ if (mlget_item->item->key_prefix == c->currcmd.key_prefix)
1887
+ {
1888
+ c->curr_task.item= mlget_item->item;
1889
+ c->curr_task.verify= mlget_item->verify;
1890
+ c->curr_task.finish_verify= mlget_item->finish_verify;
1891
+ mlget_item->get_miss= false;
1892
+
1893
+ break;
1894
+ }
1895
+ }
1896
+ }
1897
+ }
1898
+
1899
+ ms_verify_value(c, mlget_item, c->rcurr, c->rvbytes - 2);
1900
+
1901
+ c->curr_task.get_miss= false;
1902
+ c->rbytes-= c->rvbytes;
1903
+ c->rcurr= c->rcurr + c->rvbytes;
1904
+ assert(c->rcurr <= (c->rbuf + c->rsize));
1905
+ c->readval= false;
1906
+ c->rvbytes= 0;
1907
+ } /* ms_ascii_complete_nread */
1908
+
1909
+
1910
+ /**
1911
+ * For binary protocol, after store the data into the local
1912
+ * buffer, run this function to handle the data.
1913
+ *
1914
+ * @param c, pointer of the concurrency
1915
+ */
1916
+ static void ms_bin_complete_nread(ms_conn_t *c)
1917
+ {
1918
+ assert(c != NULL);
1919
+ assert(c->rbytes >= c->rvbytes);
1920
+ assert(c->protocol == binary_prot);
1921
+
1922
+ int extlen= c->binary_header.response.extlen;
1923
+ int keylen= c->binary_header.response.keylen;
1924
+ uint8_t opcode= c->binary_header.response.opcode;
1925
+
1926
+ /* not get command or not include value, just return */
1927
+ if (((opcode != PROTOCOL_BINARY_CMD_GET)
1928
+ && (opcode != PROTOCOL_BINARY_CMD_GETQ))
1929
+ || (c->rvbytes <= extlen + keylen))
1930
+ {
1931
+ /* get miss */
1932
+ if (c->binary_header.response.opcode == PROTOCOL_BINARY_CMD_GET)
1933
+ {
1934
+ c->currcmd.retstat= MCD_END;
1935
+ c->curr_task.get_miss= true;
1936
+ }
1937
+
1938
+ c->readval= false;
1939
+ c->rvbytes= 0;
1940
+ ms_reset_conn(c, false);
1941
+ return;
1942
+ }
1943
+
1944
+ /* multi-get */
1945
+ ms_mlget_task_item_t *mlget_item= NULL;
1946
+ if (((ms_setting.mult_key_num > 1)
1947
+ && (c->mlget_task.mlget_num >= ms_setting.mult_key_num))
1948
+ || ((c->remain_exec_num == 0) && (c->mlget_task.mlget_num > 0)))
1949
+ {
1950
+ c->mlget_task.value_index++;
1951
+ mlget_item= &c->mlget_task.mlget_item[c->mlget_task.value_index];
1952
+
1953
+ c->curr_task.item= mlget_item->item;
1954
+ c->curr_task.verify= mlget_item->verify;
1955
+ c->curr_task.finish_verify= mlget_item->finish_verify;
1956
+ mlget_item->get_miss= false;
1957
+ }
1958
+
1959
+ ms_verify_value(c,
1960
+ mlget_item,
1961
+ c->rcurr + extlen + keylen,
1962
+ c->rvbytes - extlen - keylen);
1963
+
1964
+ c->currcmd.retstat= MCD_END;
1965
+ c->curr_task.get_miss= false;
1966
+ c->rbytes-= c->rvbytes;
1967
+ c->rcurr= c->rcurr + c->rvbytes;
1968
+ assert(c->rcurr <= (c->rbuf + c->rsize));
1969
+ c->readval= false;
1970
+ c->rvbytes= 0;
1971
+
1972
+ if (ms_setting.mult_key_num > 1)
1973
+ {
1974
+ /* multi-get have check all the item */
1975
+ if (c->mlget_task.value_index == c->mlget_task.mlget_num - 1)
1976
+ {
1977
+ ms_reset_conn(c, false);
1978
+ }
1979
+ }
1980
+ else
1981
+ {
1982
+ /* single get */
1983
+ ms_reset_conn(c, false);
1984
+ }
1985
+ } /* ms_bin_complete_nread */
1986
+
1987
+
1988
+ /**
1989
+ * we get here after reading the value of get commands.
1990
+ *
1991
+ * @param c, pointer of the concurrency
1992
+ */
1993
+ static void ms_complete_nread(ms_conn_t *c)
1994
+ {
1995
+ assert(c != NULL);
1996
+ assert(c->rbytes >= c->rvbytes);
1997
+ assert(c->protocol == ascii_prot
1998
+ || c->protocol == binary_prot);
1999
+
2000
+ if (c->protocol == binary_prot)
2001
+ {
2002
+ ms_bin_complete_nread(c);
2003
+ }
2004
+ else
2005
+ {
2006
+ ms_ascii_complete_nread(c);
2007
+ }
2008
+ } /* ms_complete_nread */
2009
+
2010
+
2011
+ /**
2012
+ * Adds a message header to a connection.
2013
+ *
2014
+ * @param c, pointer of the concurrency
2015
+ *
2016
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2017
+ */
2018
+ static int ms_add_msghdr(ms_conn_t *c)
2019
+ {
2020
+ struct msghdr *msg;
2021
+
2022
+ assert(c != NULL);
2023
+
2024
+ if (c->msgsize == c->msgused)
2025
+ {
2026
+ msg=
2027
+ realloc(c->msglist, (size_t)c->msgsize * 2 * sizeof(struct msghdr));
2028
+ if (! msg)
2029
+ return -1;
2030
+
2031
+ c->msglist= msg;
2032
+ c->msgsize*= 2;
2033
+ }
2034
+
2035
+ msg= c->msglist + c->msgused;
2036
+
2037
+ /**
2038
+ * this wipes msg_iovlen, msg_control, msg_controllen, and
2039
+ * msg_flags, the last 3 of which aren't defined on solaris:
2040
+ */
2041
+ memset(msg, 0, sizeof(struct msghdr));
2042
+
2043
+ msg->msg_iov= &c->iov[c->iovused];
2044
+
2045
+ if (c->udp && (c->srv_recv_addr_size > 0))
2046
+ {
2047
+ msg->msg_name= &c->srv_recv_addr;
2048
+ msg->msg_namelen= c->srv_recv_addr_size;
2049
+ }
2050
+
2051
+ c->msgbytes= 0;
2052
+ c->msgused++;
2053
+
2054
+ if (c->udp)
2055
+ {
2056
+ /* Leave room for the UDP header, which we'll fill in later. */
2057
+ return ms_add_iov(c, NULL, UDP_HEADER_SIZE);
2058
+ }
2059
+
2060
+ return EXIT_SUCCESS;
2061
+ } /* ms_add_msghdr */
2062
+
2063
+
2064
+ /**
2065
+ * Ensures that there is room for another structure iovec in a connection's
2066
+ * iov list.
2067
+ *
2068
+ * @param c, pointer of the concurrency
2069
+ *
2070
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2071
+ */
2072
+ static int ms_ensure_iov_space(ms_conn_t *c)
2073
+ {
2074
+ assert(c != NULL);
2075
+
2076
+ if (c->iovused >= c->iovsize)
2077
+ {
2078
+ int i, iovnum;
2079
+ struct iovec *new_iov= (struct iovec *)realloc(c->iov,
2080
+ ((size_t)c->iovsize
2081
+ * 2)
2082
+ * sizeof(struct iovec));
2083
+ if (! new_iov)
2084
+ return -1;
2085
+
2086
+ c->iov= new_iov;
2087
+ c->iovsize*= 2;
2088
+
2089
+ /* Point all the msghdr structures at the new list. */
2090
+ for (i= 0, iovnum= 0; i < c->msgused; i++)
2091
+ {
2092
+ c->msglist[i].msg_iov= &c->iov[iovnum];
2093
+ iovnum+= (int)c->msglist[i].msg_iovlen;
2094
+ }
2095
+ }
2096
+
2097
+ return EXIT_SUCCESS;
2098
+ } /* ms_ensure_iov_space */
2099
+
2100
+
2101
+ /**
2102
+ * Adds data to the list of pending data that will be written out to a
2103
+ * connection.
2104
+ *
2105
+ * @param c, pointer of the concurrency
2106
+ * @param buf, the buffer includes data to send
2107
+ * @param len, the data length in the buffer
2108
+ *
2109
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2110
+ */
2111
+ static int ms_add_iov(ms_conn_t *c, const void *buf, int len)
2112
+ {
2113
+ struct msghdr *m;
2114
+ int leftover;
2115
+ bool limit_to_mtu;
2116
+
2117
+ assert(c != NULL);
2118
+
2119
+ do
2120
+ {
2121
+ m= &c->msglist[c->msgused - 1];
2122
+
2123
+ /*
2124
+ * Limit UDP packets, to UDP_MAX_PAYLOAD_SIZE bytes.
2125
+ */
2126
+ limit_to_mtu= c->udp;
2127
+
2128
+ /* We may need to start a new msghdr if this one is full. */
2129
+ if ((m->msg_iovlen == IOV_MAX)
2130
+ || (limit_to_mtu && (c->msgbytes >= UDP_MAX_SEND_PAYLOAD_SIZE)))
2131
+ {
2132
+ ms_add_msghdr(c);
2133
+ m= &c->msglist[c->msgused - 1];
2134
+ }
2135
+
2136
+ if (ms_ensure_iov_space(c) != 0)
2137
+ return -1;
2138
+
2139
+ /* If the fragment is too big to fit in the datagram, split it up */
2140
+ if (limit_to_mtu && (len + c->msgbytes > UDP_MAX_SEND_PAYLOAD_SIZE))
2141
+ {
2142
+ leftover= len + c->msgbytes - UDP_MAX_SEND_PAYLOAD_SIZE;
2143
+ len-= leftover;
2144
+ }
2145
+ else
2146
+ {
2147
+ leftover= 0;
2148
+ }
2149
+
2150
+ m= &c->msglist[c->msgused - 1];
2151
+ m->msg_iov[m->msg_iovlen].iov_base= (void *)buf;
2152
+ m->msg_iov[m->msg_iovlen].iov_len= (size_t)len;
2153
+
2154
+ c->msgbytes+= len;
2155
+ c->iovused++;
2156
+ m->msg_iovlen++;
2157
+
2158
+ buf= ((char *)buf) + len;
2159
+ len= leftover;
2160
+ }
2161
+ while (leftover > 0);
2162
+
2163
+ return EXIT_SUCCESS;
2164
+ } /* ms_add_iov */
2165
+
2166
+
2167
+ /**
2168
+ * Constructs a set of UDP headers and attaches them to the outgoing messages.
2169
+ *
2170
+ * @param c, pointer of the concurrency
2171
+ *
2172
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2173
+ */
2174
+ static int ms_build_udp_headers(ms_conn_t *c)
2175
+ {
2176
+ int i;
2177
+ unsigned char *hdr;
2178
+
2179
+ assert(c != NULL);
2180
+
2181
+ c->request_id= ms_get_udp_request_id();
2182
+
2183
+ if (c->msgused > c->hdrsize)
2184
+ {
2185
+ void *new_hdrbuf;
2186
+ if (c->hdrbuf)
2187
+ new_hdrbuf= realloc(c->hdrbuf,
2188
+ (size_t)c->msgused * 2 * UDP_HEADER_SIZE);
2189
+ else
2190
+ new_hdrbuf= malloc((size_t)c->msgused * 2 * UDP_HEADER_SIZE);
2191
+ if (! new_hdrbuf)
2192
+ return -1;
2193
+
2194
+ c->hdrbuf= (unsigned char *)new_hdrbuf;
2195
+ c->hdrsize= c->msgused * 2;
2196
+ }
2197
+
2198
+ /* If this is a multi-packet request, drop it. */
2199
+ if (c->udp && (c->msgused > 1))
2200
+ {
2201
+ fprintf(stderr, "multi-packet request for UDP not supported.\n");
2202
+ return -1;
2203
+ }
2204
+
2205
+ hdr= c->hdrbuf;
2206
+ for (i= 0; i < c->msgused; i++)
2207
+ {
2208
+ c->msglist[i].msg_iov[0].iov_base= (void *)hdr;
2209
+ c->msglist[i].msg_iov[0].iov_len= UDP_HEADER_SIZE;
2210
+ *hdr++= (unsigned char)(c->request_id / 256);
2211
+ *hdr++= (unsigned char)(c->request_id % 256);
2212
+ *hdr++= (unsigned char)(i / 256);
2213
+ *hdr++= (unsigned char)(i % 256);
2214
+ *hdr++= (unsigned char)(c->msgused / 256);
2215
+ *hdr++= (unsigned char)(c->msgused % 256);
2216
+ *hdr++= (unsigned char)1; /* support facebook memcached */
2217
+ *hdr++= (unsigned char)0;
2218
+ assert(hdr ==
2219
+ ((unsigned char *)c->msglist[i].msg_iov[0].iov_base
2220
+ + UDP_HEADER_SIZE));
2221
+ }
2222
+
2223
+ return EXIT_SUCCESS;
2224
+ } /* ms_build_udp_headers */
2225
+
2226
+
2227
+ /**
2228
+ * Transmit the next chunk of data from our list of msgbuf structures.
2229
+ *
2230
+ * @param c, pointer of the concurrency
2231
+ *
2232
+ * @return TRANSMIT_COMPLETE All done writing.
2233
+ * TRANSMIT_INCOMPLETE More data remaining to write.
2234
+ * TRANSMIT_SOFT_ERROR Can't write any more right now.
2235
+ * TRANSMIT_HARD_ERROR Can't write (c->state is set to conn_closing)
2236
+ */
2237
+ static int ms_transmit(ms_conn_t *c)
2238
+ {
2239
+ assert(c != NULL);
2240
+
2241
+ if ((c->msgcurr < c->msgused)
2242
+ && (c->msglist[c->msgcurr].msg_iovlen == 0))
2243
+ {
2244
+ /* Finished writing the current msg; advance to the next. */
2245
+ c->msgcurr++;
2246
+ }
2247
+
2248
+ if (c->msgcurr < c->msgused)
2249
+ {
2250
+ ssize_t res;
2251
+ struct msghdr *m= &c->msglist[c->msgcurr];
2252
+
2253
+ res= sendmsg(c->sfd, m, 0);
2254
+ if (res > 0)
2255
+ {
2256
+ atomic_add_size(&ms_stats.bytes_written, res);
2257
+
2258
+ /* We've written some of the data. Remove the completed
2259
+ * iovec entries from the list of pending writes. */
2260
+ while (m->msg_iovlen > 0 && res >= (ssize_t)m->msg_iov->iov_len)
2261
+ {
2262
+ res-= (ssize_t)m->msg_iov->iov_len;
2263
+ m->msg_iovlen--;
2264
+ m->msg_iov++;
2265
+ }
2266
+
2267
+ /* Might have written just part of the last iovec entry;
2268
+ * adjust it so the next write will do the rest. */
2269
+ if (res > 0)
2270
+ {
2271
+ m->msg_iov->iov_base= (void *)((unsigned char *)m->msg_iov->iov_base + res);
2272
+ m->msg_iov->iov_len-= (size_t)res;
2273
+ }
2274
+ return TRANSMIT_INCOMPLETE;
2275
+ }
2276
+ if ((res == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
2277
+ {
2278
+ if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
2279
+ {
2280
+ fprintf(stderr, "Couldn't update event.\n");
2281
+ ms_conn_set_state(c, conn_closing);
2282
+ return TRANSMIT_HARD_ERROR;
2283
+ }
2284
+ return TRANSMIT_SOFT_ERROR;
2285
+ }
2286
+
2287
+ /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
2288
+ * we have a real error, on which we close the connection */
2289
+ fprintf(stderr, "Failed to write, and not due to blocking.\n");
2290
+
2291
+ ms_conn_set_state(c, conn_closing);
2292
+ return TRANSMIT_HARD_ERROR;
2293
+ }
2294
+ else
2295
+ {
2296
+ return TRANSMIT_COMPLETE;
2297
+ }
2298
+ } /* ms_transmit */
2299
+
2300
+
2301
+ /**
2302
+ * Shrinks a connection's buffers if they're too big. This prevents
2303
+ * periodic large "mget" response from server chewing lots of client
2304
+ * memory.
2305
+ *
2306
+ * This should only be called in between requests since it can wipe output
2307
+ * buffers!
2308
+ *
2309
+ * @param c, pointer of the concurrency
2310
+ */
2311
+ static void ms_conn_shrink(ms_conn_t *c)
2312
+ {
2313
+ assert(c != NULL);
2314
+
2315
+ if (c->udp)
2316
+ return;
2317
+
2318
+ if ((c->rsize > READ_BUFFER_HIGHWAT) && (c->rbytes < DATA_BUFFER_SIZE))
2319
+ {
2320
+ char *newbuf;
2321
+
2322
+ if (c->rcurr != c->rbuf)
2323
+ memmove(c->rbuf, c->rcurr, (size_t)c->rbytes);
2324
+
2325
+ newbuf= (char *)realloc((void *)c->rbuf, DATA_BUFFER_SIZE);
2326
+
2327
+ if (newbuf)
2328
+ {
2329
+ c->rbuf= newbuf;
2330
+ c->rsize= DATA_BUFFER_SIZE;
2331
+ }
2332
+ c->rcurr= c->rbuf;
2333
+ }
2334
+
2335
+ if (c->udp && (c->rudpsize > UDP_DATA_BUFFER_HIGHWAT)
2336
+ && (c->rudpbytes + UDP_MAX_PAYLOAD_SIZE < UDP_DATA_BUFFER_SIZE))
2337
+ {
2338
+ char *new_rbuf= (char *)realloc(c->rudpbuf, (size_t)c->rudpsize * 2);
2339
+ if (! new_rbuf)
2340
+ {
2341
+ c->rudpbuf= new_rbuf;
2342
+ c->rudpsize= UDP_DATA_BUFFER_SIZE;
2343
+ }
2344
+ /* TODO check error condition? */
2345
+ }
2346
+
2347
+ if (c->msgsize > MSG_LIST_HIGHWAT)
2348
+ {
2349
+ struct msghdr *newbuf= (struct msghdr *)realloc(
2350
+ (void *)c->msglist,
2351
+ MSG_LIST_INITIAL
2352
+ * sizeof(c->msglist[0]));
2353
+ if (newbuf)
2354
+ {
2355
+ c->msglist= newbuf;
2356
+ c->msgsize= MSG_LIST_INITIAL;
2357
+ }
2358
+ /* TODO check error condition? */
2359
+ }
2360
+
2361
+ if (c->iovsize > IOV_LIST_HIGHWAT)
2362
+ {
2363
+ struct iovec *newbuf= (struct iovec *)realloc((void *)c->iov,
2364
+ IOV_LIST_INITIAL
2365
+ * sizeof(c->iov[0]));
2366
+ if (newbuf)
2367
+ {
2368
+ c->iov= newbuf;
2369
+ c->iovsize= IOV_LIST_INITIAL;
2370
+ }
2371
+ /* TODO check return value */
2372
+ }
2373
+ } /* ms_conn_shrink */
2374
+
2375
+
2376
+ /**
2377
+ * Sets a connection's current state in the state machine. Any special
2378
+ * processing that needs to happen on certain state transitions can
2379
+ * happen here.
2380
+ *
2381
+ * @param c, pointer of the concurrency
2382
+ * @param state, connection state
2383
+ */
2384
+ static void ms_conn_set_state(ms_conn_t *c, int state)
2385
+ {
2386
+ assert(c != NULL);
2387
+
2388
+ if (state != c->state)
2389
+ {
2390
+ if (state == conn_read)
2391
+ {
2392
+ ms_conn_shrink(c);
2393
+ }
2394
+ c->state= state;
2395
+ }
2396
+ } /* ms_conn_set_state */
2397
+
2398
+
2399
+ /**
2400
+ * update the event if socks change state. for example: when
2401
+ * change the listen scoket read event to sock write event, or
2402
+ * change socket handler, we could call this function.
2403
+ *
2404
+ * @param c, pointer of the concurrency
2405
+ * @param new_flags, new event flags
2406
+ *
2407
+ * @return bool, if success, return true, else return false
2408
+ */
2409
+ static bool ms_update_event(ms_conn_t *c, const int new_flags)
2410
+ {
2411
+ assert(c != NULL);
2412
+
2413
+ struct event_base *base= c->event.ev_base;
2414
+ if ((c->ev_flags == new_flags) && (ms_setting.rep_write_srv == 0)
2415
+ && (! ms_setting.facebook_test || (c->total_sfds == 1)))
2416
+ {
2417
+ return true;
2418
+ }
2419
+
2420
+ if (event_del(&c->event) == -1)
2421
+ {
2422
+ /* try to delete the event again */
2423
+ if (event_del(&c->event) == -1)
2424
+ {
2425
+ return false;
2426
+ }
2427
+ }
2428
+
2429
+ event_set(&c->event,
2430
+ c->sfd,
2431
+ (short)new_flags,
2432
+ ms_event_handler,
2433
+ (void *)c);
2434
+ event_base_set(base, &c->event);
2435
+ c->ev_flags= (short)new_flags;
2436
+
2437
+ if (event_add(&c->event, NULL) == -1)
2438
+ {
2439
+ return false;
2440
+ }
2441
+
2442
+ return true;
2443
+ } /* ms_update_event */
2444
+
2445
+
2446
+ /**
2447
+ * If user want to get the expected throughput, we could limit
2448
+ * the performance of memslap. we could give up some work and
2449
+ * just wait a short time. The function is used to check this
2450
+ * case.
2451
+ *
2452
+ * @param c, pointer of the concurrency
2453
+ *
2454
+ * @return bool, if success, return true, else return false
2455
+ */
2456
+ static bool ms_need_yield(ms_conn_t *c)
2457
+ {
2458
+ ms_thread_t *ms_thread= pthread_getspecific(ms_thread_key);
2459
+ int64_t tps= 0;
2460
+ int64_t time_diff= 0;
2461
+ struct timeval curr_time;
2462
+ ms_task_t *task= &c->curr_task;
2463
+
2464
+ if (ms_setting.expected_tps > 0)
2465
+ {
2466
+ gettimeofday(&curr_time, NULL);
2467
+ time_diff= ms_time_diff(&ms_thread->startup_time, &curr_time);
2468
+ tps= (int64_t)(((task->get_opt + task->set_opt) / (uint64_t)time_diff) * 1000000);
2469
+
2470
+ /* current throughput is greater than expected throughput */
2471
+ if (tps > ms_thread->thread_ctx->tps_perconn)
2472
+ {
2473
+ return true;
2474
+ }
2475
+ }
2476
+
2477
+ return false;
2478
+ } /* ms_need_yield */
2479
+
2480
+
2481
+ /**
2482
+ * used to update the start time of each operation
2483
+ *
2484
+ * @param c, pointer of the concurrency
2485
+ */
2486
+ static void ms_update_start_time(ms_conn_t *c)
2487
+ {
2488
+ ms_task_item_t *item= c->curr_task.item;
2489
+
2490
+ if ((ms_setting.stat_freq > 0) || c->udp
2491
+ || ((c->currcmd.cmd == CMD_SET) && (item->exp_time > 0)))
2492
+ {
2493
+ gettimeofday(&c->start_time, NULL);
2494
+ if ((c->currcmd.cmd == CMD_SET) && (item->exp_time > 0))
2495
+ {
2496
+ /* record the current time */
2497
+ item->client_time= c->start_time.tv_sec;
2498
+ }
2499
+ }
2500
+ } /* ms_update_start_time */
2501
+
2502
+
2503
+ /**
2504
+ * run the state machine
2505
+ *
2506
+ * @param c, pointer of the concurrency
2507
+ */
2508
+ static void ms_drive_machine(ms_conn_t *c)
2509
+ {
2510
+ bool stop= false;
2511
+
2512
+ assert(c != NULL);
2513
+
2514
+ while (! stop)
2515
+ {
2516
+ switch (c->state)
2517
+ {
2518
+ case conn_read:
2519
+ if (c->readval)
2520
+ {
2521
+ if (c->rbytes >= c->rvbytes)
2522
+ {
2523
+ ms_complete_nread(c);
2524
+ break;
2525
+ }
2526
+ }
2527
+ else
2528
+ {
2529
+ if (ms_try_read_line(c) != 0)
2530
+ {
2531
+ break;
2532
+ }
2533
+ }
2534
+
2535
+ if (ms_try_read_network(c) != 0)
2536
+ {
2537
+ break;
2538
+ }
2539
+
2540
+ /* doesn't read all the response data, wait event wake up */
2541
+ if (! c->currcmd.isfinish)
2542
+ {
2543
+ if (! ms_update_event(c, EV_READ | EV_PERSIST))
2544
+ {
2545
+ fprintf(stderr, "Couldn't update event.\n");
2546
+ ms_conn_set_state(c, conn_closing);
2547
+ break;
2548
+ }
2549
+ stop= true;
2550
+ break;
2551
+ }
2552
+
2553
+ /* we have no command line and no data to read from network, next write */
2554
+ ms_conn_set_state(c, conn_write);
2555
+ memcpy(&c->precmd, &c->currcmd, sizeof(ms_cmdstat_t)); /* replicate command state */
2556
+
2557
+ break;
2558
+
2559
+ case conn_write:
2560
+ if (! c->ctnwrite && ms_need_yield(c))
2561
+ {
2562
+ usleep(10);
2563
+
2564
+ if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
2565
+ {
2566
+ fprintf(stderr, "Couldn't update event.\n");
2567
+ ms_conn_set_state(c, conn_closing);
2568
+ break;
2569
+ }
2570
+ stop= true;
2571
+ break;
2572
+ }
2573
+
2574
+ if (! c->ctnwrite && (ms_exec_task(c) != 0))
2575
+ {
2576
+ ms_conn_set_state(c, conn_closing);
2577
+ break;
2578
+ }
2579
+
2580
+ /* record the start time before starting to send data if necessary */
2581
+ if (! c->ctnwrite || (c->change_sfd && c->ctnwrite))
2582
+ {
2583
+ if (c->change_sfd)
2584
+ {
2585
+ c->change_sfd= false;
2586
+ }
2587
+ ms_update_start_time(c);
2588
+ }
2589
+
2590
+ /* change sfd if necessary */
2591
+ if (c->change_sfd)
2592
+ {
2593
+ c->ctnwrite= true;
2594
+ stop= true;
2595
+ break;
2596
+ }
2597
+
2598
+ /* execute task until nothing need be written to network */
2599
+ if (! c->ctnwrite && (c->msgcurr == c->msgused))
2600
+ {
2601
+ if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
2602
+ {
2603
+ fprintf(stderr, "Couldn't update event.\n");
2604
+ ms_conn_set_state(c, conn_closing);
2605
+ break;
2606
+ }
2607
+ stop= true;
2608
+ break;
2609
+ }
2610
+
2611
+ switch (ms_transmit(c))
2612
+ {
2613
+ case TRANSMIT_COMPLETE:
2614
+ /* we have no data to write to network, next wait repose */
2615
+ if (! ms_update_event(c, EV_READ | EV_PERSIST))
2616
+ {
2617
+ fprintf(stderr, "Couldn't update event.\n");
2618
+ ms_conn_set_state(c, conn_closing);
2619
+ c->ctnwrite= false;
2620
+ break;
2621
+ }
2622
+ ms_conn_set_state(c, conn_read);
2623
+ c->ctnwrite= false;
2624
+ stop= true;
2625
+ break;
2626
+
2627
+ case TRANSMIT_INCOMPLETE:
2628
+ c->ctnwrite= true;
2629
+ break; /* Continue in state machine. */
2630
+
2631
+ case TRANSMIT_HARD_ERROR:
2632
+ c->ctnwrite= false;
2633
+ break;
2634
+
2635
+ case TRANSMIT_SOFT_ERROR:
2636
+ c->ctnwrite= true;
2637
+ stop= true;
2638
+ break;
2639
+
2640
+ default:
2641
+ break;
2642
+ } /* switch */
2643
+
2644
+ break;
2645
+
2646
+ case conn_closing:
2647
+ /* recovery mode, need reconnect if connection close */
2648
+ if (ms_setting.reconnect && (! ms_global.time_out
2649
+ || ((ms_setting.run_time == 0)
2650
+ && (c->remain_exec_num > 0))))
2651
+ {
2652
+ if (ms_reconn(c) != 0)
2653
+ {
2654
+ ms_conn_close(c);
2655
+ stop= true;
2656
+ break;
2657
+ }
2658
+
2659
+ ms_reset_conn(c, false);
2660
+
2661
+ if (c->total_sfds == 1)
2662
+ {
2663
+ if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
2664
+ {
2665
+ fprintf(stderr, "Couldn't update event.\n");
2666
+ ms_conn_set_state(c, conn_closing);
2667
+ break;
2668
+ }
2669
+ }
2670
+
2671
+ break;
2672
+ }
2673
+ else
2674
+ {
2675
+ ms_conn_close(c);
2676
+ stop= true;
2677
+ break;
2678
+ }
2679
+
2680
+ default:
2681
+ assert(0);
2682
+ } /* switch */
2683
+ }
2684
+ } /* ms_drive_machine */
2685
+
2686
+
2687
+ /**
2688
+ * the event handler of each thread
2689
+ *
2690
+ * @param fd, the file descriptor of socket
2691
+ * @param which, event flag
2692
+ * @param arg, argument
2693
+ */
2694
+ void ms_event_handler(const int fd, const short which, void *arg)
2695
+ {
2696
+ ms_conn_t *c= (ms_conn_t *)arg;
2697
+
2698
+ assert(c != NULL);
2699
+
2700
+ c->which= which;
2701
+
2702
+ /* sanity */
2703
+ if (fd != c->sfd)
2704
+ {
2705
+ fprintf(stderr,
2706
+ "Catastrophic: event fd: %d doesn't match conn fd: %d\n",
2707
+ fd,
2708
+ c->sfd);
2709
+ ms_conn_close(c);
2710
+ exit(1);
2711
+ }
2712
+ assert(fd == c->sfd);
2713
+
2714
+ ms_drive_machine(c);
2715
+
2716
+ /* wait for next event */
2717
+ } /* ms_event_handler */
2718
+
2719
+
2720
+ /**
2721
+ * get the next socket descriptor index to run for replication
2722
+ *
2723
+ * @param c, pointer of the concurrency
2724
+ * @param cmd, command(get or set )
2725
+ *
2726
+ * @return int, if success, return the index, else return EXIT_SUCCESS
2727
+ */
2728
+ static uint32_t ms_get_rep_sock_index(ms_conn_t *c, int cmd)
2729
+ {
2730
+ uint32_t sock_index= 0;
2731
+ uint32_t i= 0;
2732
+
2733
+ if (c->total_sfds == 1)
2734
+ {
2735
+ return EXIT_SUCCESS;
2736
+ }
2737
+
2738
+ if (ms_setting.rep_write_srv == 0)
2739
+ {
2740
+ return sock_index;
2741
+ }
2742
+
2743
+ do
2744
+ {
2745
+ if (cmd == CMD_SET)
2746
+ {
2747
+ for (i= 0; i < ms_setting.rep_write_srv; i++)
2748
+ {
2749
+ if (c->tcpsfd[i] > 0)
2750
+ {
2751
+ break;
2752
+ }
2753
+ }
2754
+
2755
+ if (i == ms_setting.rep_write_srv)
2756
+ {
2757
+ /* random get one replication server to read */
2758
+ sock_index= (uint32_t)random() % c->total_sfds;
2759
+ }
2760
+ else
2761
+ {
2762
+ /* random get one replication writing server to write */
2763
+ sock_index= (uint32_t)random() % ms_setting.rep_write_srv;
2764
+ }
2765
+ }
2766
+ else if (cmd == CMD_GET)
2767
+ {
2768
+ /* random get one replication server to read */
2769
+ sock_index= (uint32_t)random() % c->total_sfds;
2770
+ }
2771
+ }
2772
+ while (c->tcpsfd[sock_index] == 0);
2773
+
2774
+ return sock_index;
2775
+ } /* ms_get_rep_sock_index */
2776
+
2777
+
2778
+ /**
2779
+ * get the next socket descriptor index to run
2780
+ *
2781
+ * @param c, pointer of the concurrency
2782
+ *
2783
+ * @return int, return the index
2784
+ */
2785
+ static uint32_t ms_get_next_sock_index(ms_conn_t *c)
2786
+ {
2787
+ uint32_t sock_index= 0;
2788
+
2789
+ do
2790
+ {
2791
+ sock_index= (++c->cur_idx == c->total_sfds) ? 0 : c->cur_idx;
2792
+ }
2793
+ while (c->tcpsfd[sock_index] == 0);
2794
+
2795
+ return sock_index;
2796
+ } /* ms_get_next_sock_index */
2797
+
2798
+
2799
+ /**
2800
+ * update socket event of the connections
2801
+ *
2802
+ * @param c, pointer of the concurrency
2803
+ *
2804
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2805
+ */
2806
+ static int ms_update_conn_sock_event(ms_conn_t *c)
2807
+ {
2808
+ assert(c != NULL);
2809
+
2810
+ switch (c->currcmd.cmd)
2811
+ {
2812
+ case CMD_SET:
2813
+ if (ms_setting.facebook_test && c->udp)
2814
+ {
2815
+ c->sfd= c->tcpsfd[0];
2816
+ c->udp= false;
2817
+ c->change_sfd= true;
2818
+ }
2819
+ break;
2820
+
2821
+ case CMD_GET:
2822
+ if (ms_setting.facebook_test && ! c->udp)
2823
+ {
2824
+ c->sfd= c->udpsfd;
2825
+ c->udp= true;
2826
+ c->change_sfd= true;
2827
+ }
2828
+ break;
2829
+
2830
+ default:
2831
+ break;
2832
+ } /* switch */
2833
+
2834
+ if (! c->udp && (c->total_sfds > 1))
2835
+ {
2836
+ if (c->cur_idx != c->total_sfds)
2837
+ {
2838
+ if (ms_setting.rep_write_srv == 0)
2839
+ {
2840
+ c->cur_idx= ms_get_next_sock_index(c);
2841
+ }
2842
+ else
2843
+ {
2844
+ c->cur_idx= ms_get_rep_sock_index(c, c->currcmd.cmd);
2845
+ }
2846
+ }
2847
+ else
2848
+ {
2849
+ /* must select the first sock of the connection at the beginning */
2850
+ c->cur_idx= 0;
2851
+ }
2852
+
2853
+ c->sfd= c->tcpsfd[c->cur_idx];
2854
+ assert(c->sfd != 0);
2855
+ c->change_sfd= true;
2856
+ }
2857
+
2858
+ if (c->change_sfd)
2859
+ {
2860
+ if (! ms_update_event(c, EV_WRITE | EV_PERSIST))
2861
+ {
2862
+ fprintf(stderr, "Couldn't update event.\n");
2863
+ ms_conn_set_state(c, conn_closing);
2864
+ return -1;
2865
+ }
2866
+ }
2867
+
2868
+ return EXIT_SUCCESS;
2869
+ } /* ms_update_conn_sock_event */
2870
+
2871
+
2872
+ /**
2873
+ * for ASCII protocol, this function build the set command
2874
+ * string and send the command.
2875
+ *
2876
+ * @param c, pointer of the concurrency
2877
+ * @param item, pointer of task item which includes the object
2878
+ * information
2879
+ *
2880
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2881
+ */
2882
+ static int ms_build_ascii_write_buf_set(ms_conn_t *c, ms_task_item_t *item)
2883
+ {
2884
+ int value_offset;
2885
+ int write_len;
2886
+ char *buffer= c->wbuf;
2887
+
2888
+ write_len= snprintf(buffer,
2889
+ c->wsize,
2890
+ " %u %d %d\r\n",
2891
+ 0,
2892
+ item->exp_time,
2893
+ item->value_size);
2894
+
2895
+ if (write_len > c->wsize || write_len < 0)
2896
+ {
2897
+ /* ought to be always enough. just fail for simplicity */
2898
+ fprintf(stderr, "output command line too long.\n");
2899
+ return -1;
2900
+ }
2901
+
2902
+ if (item->value_offset == INVALID_OFFSET)
2903
+ {
2904
+ value_offset= item->key_suffix_offset;
2905
+ }
2906
+ else
2907
+ {
2908
+ value_offset= item->value_offset;
2909
+ }
2910
+
2911
+ if ((ms_add_iov(c, "set ", 4) != 0)
2912
+ || (ms_add_iov(c, (char *)&item->key_prefix,
2913
+ (int)KEY_PREFIX_SIZE) != 0)
2914
+ || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
2915
+ item->key_size - (int)KEY_PREFIX_SIZE) != 0)
2916
+ || (ms_add_iov(c, buffer, write_len) != 0)
2917
+ || (ms_add_iov(c, &ms_setting.char_block[value_offset],
2918
+ item->value_size) != 0)
2919
+ || (ms_add_iov(c, "\r\n", 2) != 0)
2920
+ || (c->udp && (ms_build_udp_headers(c) != 0)))
2921
+ {
2922
+ return -1;
2923
+ }
2924
+
2925
+ return EXIT_SUCCESS;
2926
+ } /* ms_build_ascii_write_buf_set */
2927
+
2928
+
2929
+ /**
2930
+ * used to send set command to server
2931
+ *
2932
+ * @param c, pointer of the concurrency
2933
+ * @param item, pointer of task item which includes the object
2934
+ * information
2935
+ *
2936
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2937
+ */
2938
+ int ms_mcd_set(ms_conn_t *c, ms_task_item_t *item)
2939
+ {
2940
+ assert(c != NULL);
2941
+
2942
+ c->currcmd.cmd= CMD_SET;
2943
+ c->currcmd.isfinish= false;
2944
+ c->currcmd.retstat= MCD_FAILURE;
2945
+
2946
+ if (ms_update_conn_sock_event(c) != 0)
2947
+ {
2948
+ return -1;
2949
+ }
2950
+
2951
+ c->msgcurr= 0;
2952
+ c->msgused= 0;
2953
+ c->iovused= 0;
2954
+ if (ms_add_msghdr(c) != 0)
2955
+ {
2956
+ fprintf(stderr, "Out of memory preparing request.");
2957
+ return -1;
2958
+ }
2959
+
2960
+ /* binary protocol */
2961
+ if (c->protocol == binary_prot)
2962
+ {
2963
+ if (ms_build_bin_write_buf_set(c, item) != 0)
2964
+ {
2965
+ return -1;
2966
+ }
2967
+ }
2968
+ else
2969
+ {
2970
+ if (ms_build_ascii_write_buf_set(c, item) != 0)
2971
+ {
2972
+ return -1;
2973
+ }
2974
+ }
2975
+
2976
+ atomic_add_size(&ms_stats.obj_bytes,
2977
+ item->key_size + item->value_size);
2978
+ atomic_add_size(&ms_stats.cmd_set, 1);
2979
+
2980
+ return EXIT_SUCCESS;
2981
+ } /* ms_mcd_set */
2982
+
2983
+
2984
+ /**
2985
+ * for ASCII protocol, this function build the get command
2986
+ * string and send the command.
2987
+ *
2988
+ * @param c, pointer of the concurrency
2989
+ * @param item, pointer of task item which includes the object
2990
+ * information
2991
+ *
2992
+ * @return int, if success, return EXIT_SUCCESS, else return -1
2993
+ */
2994
+ static int ms_build_ascii_write_buf_get(ms_conn_t *c, ms_task_item_t *item)
2995
+ {
2996
+ if ((ms_add_iov(c, "get ", 4) != 0)
2997
+ || (ms_add_iov(c, (char *)&item->key_prefix,
2998
+ (int)KEY_PREFIX_SIZE) != 0)
2999
+ || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
3000
+ item->key_size - (int)KEY_PREFIX_SIZE) != 0)
3001
+ || (ms_add_iov(c, "\r\n", 2) != 0)
3002
+ || (c->udp && (ms_build_udp_headers(c) != 0)))
3003
+ {
3004
+ return -1;
3005
+ }
3006
+
3007
+ return EXIT_SUCCESS;
3008
+ } /* ms_build_ascii_write_buf_get */
3009
+
3010
+
3011
+ /**
3012
+ * used to send the get command to server
3013
+ *
3014
+ * @param c, pointer of the concurrency
3015
+ * @param item, pointer of task item which includes the object
3016
+ * information
3017
+ *
3018
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3019
+ */
3020
+ int ms_mcd_get(ms_conn_t *c, ms_task_item_t *item)
3021
+ {
3022
+ assert(c != NULL);
3023
+
3024
+ c->currcmd.cmd= CMD_GET;
3025
+ c->currcmd.isfinish= false;
3026
+ c->currcmd.retstat= MCD_FAILURE;
3027
+
3028
+ if (ms_update_conn_sock_event(c) != 0)
3029
+ {
3030
+ return -1;
3031
+ }
3032
+
3033
+ c->msgcurr= 0;
3034
+ c->msgused= 0;
3035
+ c->iovused= 0;
3036
+ if (ms_add_msghdr(c) != 0)
3037
+ {
3038
+ fprintf(stderr, "Out of memory preparing request.");
3039
+ return -1;
3040
+ }
3041
+
3042
+ /* binary protocol */
3043
+ if (c->protocol == binary_prot)
3044
+ {
3045
+ if (ms_build_bin_write_buf_get(c, item) != 0)
3046
+ {
3047
+ return -1;
3048
+ }
3049
+ }
3050
+ else
3051
+ {
3052
+ if (ms_build_ascii_write_buf_get(c, item) != 0)
3053
+ {
3054
+ return -1;
3055
+ }
3056
+ }
3057
+
3058
+ atomic_add_size(&ms_stats.cmd_get, 1);
3059
+
3060
+ return EXIT_SUCCESS;
3061
+ } /* ms_mcd_get */
3062
+
3063
+
3064
+ /**
3065
+ * for ASCII protocol, this function build the multi-get command
3066
+ * string and send the command.
3067
+ *
3068
+ * @param c, pointer of the concurrency
3069
+ *
3070
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3071
+ */
3072
+ static int ms_build_ascii_write_buf_mlget(ms_conn_t *c)
3073
+ {
3074
+ ms_task_item_t *item;
3075
+
3076
+ if (ms_add_iov(c, "get", 3) != 0)
3077
+ {
3078
+ return -1;
3079
+ }
3080
+
3081
+ for (int i= 0; i < c->mlget_task.mlget_num; i++)
3082
+ {
3083
+ item= c->mlget_task.mlget_item[i].item;
3084
+ assert(item != NULL);
3085
+ if ((ms_add_iov(c, " ", 1) != 0)
3086
+ || (ms_add_iov(c, (char *)&item->key_prefix,
3087
+ (int)KEY_PREFIX_SIZE) != 0)
3088
+ || (ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
3089
+ item->key_size - (int)KEY_PREFIX_SIZE) != 0))
3090
+ {
3091
+ return -1;
3092
+ }
3093
+ }
3094
+
3095
+ if ((ms_add_iov(c, "\r\n", 2) != 0)
3096
+ || (c->udp && (ms_build_udp_headers(c) != 0)))
3097
+ {
3098
+ return -1;
3099
+ }
3100
+
3101
+ return EXIT_SUCCESS;
3102
+ } /* ms_build_ascii_write_buf_mlget */
3103
+
3104
+
3105
+ /**
3106
+ * used to send the multi-get command to server
3107
+ *
3108
+ * @param c, pointer of the concurrency
3109
+ *
3110
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3111
+ */
3112
+ int ms_mcd_mlget(ms_conn_t *c)
3113
+ {
3114
+ ms_task_item_t *item;
3115
+
3116
+ assert(c != NULL);
3117
+ assert(c->mlget_task.mlget_num >= 1);
3118
+
3119
+ c->currcmd.cmd= CMD_GET;
3120
+ c->currcmd.isfinish= false;
3121
+ c->currcmd.retstat= MCD_FAILURE;
3122
+
3123
+ if (ms_update_conn_sock_event(c) != 0)
3124
+ {
3125
+ return -1;
3126
+ }
3127
+
3128
+ c->msgcurr= 0;
3129
+ c->msgused= 0;
3130
+ c->iovused= 0;
3131
+ if (ms_add_msghdr(c) != 0)
3132
+ {
3133
+ fprintf(stderr, "Out of memory preparing request.");
3134
+ return -1;
3135
+ }
3136
+
3137
+ /* binary protocol */
3138
+ if (c->protocol == binary_prot)
3139
+ {
3140
+ if (ms_build_bin_write_buf_mlget(c) != 0)
3141
+ {
3142
+ return -1;
3143
+ }
3144
+ }
3145
+ else
3146
+ {
3147
+ if (ms_build_ascii_write_buf_mlget(c) != 0)
3148
+ {
3149
+ return -1;
3150
+ }
3151
+ }
3152
+
3153
+ /* decrease operation time of each item */
3154
+ for (int i= 0; i < c->mlget_task.mlget_num; i++)
3155
+ {
3156
+ item= c->mlget_task.mlget_item[i].item;
3157
+ atomic_add_size(&ms_stats.cmd_get, 1);
3158
+ }
3159
+
3160
+ return EXIT_SUCCESS;
3161
+ } /* ms_mcd_mlget */
3162
+
3163
+
3164
+ /**
3165
+ * binary protocol support
3166
+ */
3167
+
3168
+ /**
3169
+ * for binary protocol, parse the response of server
3170
+ *
3171
+ * @param c, pointer of the concurrency
3172
+ *
3173
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3174
+ */
3175
+ static int ms_bin_process_response(ms_conn_t *c)
3176
+ {
3177
+ const char *errstr= NULL;
3178
+
3179
+ assert(c != NULL);
3180
+
3181
+ uint32_t bodylen= c->binary_header.response.bodylen;
3182
+ uint8_t opcode= c->binary_header.response.opcode;
3183
+ uint16_t status= c->binary_header.response.status;
3184
+
3185
+ if (bodylen > 0)
3186
+ {
3187
+ c->rvbytes= (int32_t)bodylen;
3188
+ c->readval= true;
3189
+ return EXIT_FAILURE;
3190
+ }
3191
+ else
3192
+ {
3193
+ switch (status)
3194
+ {
3195
+ case PROTOCOL_BINARY_RESPONSE_SUCCESS:
3196
+ if (opcode == PROTOCOL_BINARY_CMD_SET)
3197
+ {
3198
+ c->currcmd.retstat= MCD_STORED;
3199
+ }
3200
+ else if (opcode == PROTOCOL_BINARY_CMD_DELETE)
3201
+ {
3202
+ c->currcmd.retstat= MCD_DELETED;
3203
+ }
3204
+ else if (opcode == PROTOCOL_BINARY_CMD_GET)
3205
+ {
3206
+ c->currcmd.retstat= MCD_END;
3207
+ }
3208
+ break;
3209
+
3210
+ case PROTOCOL_BINARY_RESPONSE_ENOMEM:
3211
+ errstr= "Out of memory";
3212
+ c->currcmd.retstat= MCD_SERVER_ERROR;
3213
+ break;
3214
+
3215
+ case PROTOCOL_BINARY_RESPONSE_UNKNOWN_COMMAND:
3216
+ errstr= "Unknown command";
3217
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
3218
+ break;
3219
+
3220
+ case PROTOCOL_BINARY_RESPONSE_KEY_ENOENT:
3221
+ errstr= "Not found";
3222
+ c->currcmd.retstat= MCD_NOTFOUND;
3223
+ break;
3224
+
3225
+ case PROTOCOL_BINARY_RESPONSE_EINVAL:
3226
+ errstr= "Invalid arguments";
3227
+ c->currcmd.retstat= MCD_PROTOCOL_ERROR;
3228
+ break;
3229
+
3230
+ case PROTOCOL_BINARY_RESPONSE_KEY_EEXISTS:
3231
+ errstr= "Data exists for key.";
3232
+ break;
3233
+
3234
+ case PROTOCOL_BINARY_RESPONSE_E2BIG:
3235
+ errstr= "Too large.";
3236
+ c->currcmd.retstat= MCD_SERVER_ERROR;
3237
+ break;
3238
+
3239
+ case PROTOCOL_BINARY_RESPONSE_NOT_STORED:
3240
+ errstr= "Not stored.";
3241
+ c->currcmd.retstat= MCD_NOTSTORED;
3242
+ break;
3243
+
3244
+ default:
3245
+ errstr= "Unknown error";
3246
+ c->currcmd.retstat= MCD_UNKNOWN_READ_FAILURE;
3247
+ break;
3248
+ } /* switch */
3249
+
3250
+ if (errstr != NULL)
3251
+ {
3252
+ fprintf(stderr, "%s\n", errstr);
3253
+ }
3254
+ }
3255
+
3256
+ return EXIT_SUCCESS;
3257
+ } /* ms_bin_process_response */
3258
+
3259
+
3260
+ /* build binary header and add the header to the buffer to send */
3261
+
3262
+ /**
3263
+ * build binary header and add the header to the buffer to send
3264
+ *
3265
+ * @param c, pointer of the concurrency
3266
+ * @param opcode, operation code
3267
+ * @param hdr_len, length of header
3268
+ * @param key_len, length of key
3269
+ * @param body_len. length of body
3270
+ */
3271
+ static void ms_add_bin_header(ms_conn_t *c,
3272
+ uint8_t opcode,
3273
+ uint8_t hdr_len,
3274
+ uint16_t key_len,
3275
+ uint32_t body_len)
3276
+ {
3277
+ protocol_binary_request_header *header;
3278
+
3279
+ assert(c != NULL);
3280
+
3281
+ header= (protocol_binary_request_header *)c->wcurr;
3282
+
3283
+ header->request.magic= (uint8_t)PROTOCOL_BINARY_REQ;
3284
+ header->request.opcode= (uint8_t)opcode;
3285
+ header->request.keylen= htons(key_len);
3286
+
3287
+ header->request.extlen= (uint8_t)hdr_len;
3288
+ header->request.datatype= (uint8_t)PROTOCOL_BINARY_RAW_BYTES;
3289
+ header->request.vbucket= 0;
3290
+
3291
+ header->request.bodylen= htonl(body_len);
3292
+ header->request.opaque= 0;
3293
+ header->request.cas= 0;
3294
+
3295
+ ms_add_iov(c, c->wcurr, sizeof(header->request));
3296
+ } /* ms_add_bin_header */
3297
+
3298
+
3299
+ /**
3300
+ * add the key to the socket write buffer array
3301
+ *
3302
+ * @param c, pointer of the concurrency
3303
+ * @param item, pointer of task item which includes the object
3304
+ * information
3305
+ */
3306
+ static void ms_add_key_to_iov(ms_conn_t *c, ms_task_item_t *item)
3307
+ {
3308
+ ms_add_iov(c, (char *)&item->key_prefix, (int)KEY_PREFIX_SIZE);
3309
+ ms_add_iov(c, &ms_setting.char_block[item->key_suffix_offset],
3310
+ item->key_size - (int)KEY_PREFIX_SIZE);
3311
+ }
3312
+
3313
+
3314
+ /**
3315
+ * for binary protocol, this function build the set command
3316
+ * and add the command to send buffer array.
3317
+ *
3318
+ * @param c, pointer of the concurrency
3319
+ * @param item, pointer of task item which includes the object
3320
+ * information
3321
+ *
3322
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3323
+ */
3324
+ static int ms_build_bin_write_buf_set(ms_conn_t *c, ms_task_item_t *item)
3325
+ {
3326
+ assert(c->wbuf == c->wcurr);
3327
+
3328
+ int value_offset;
3329
+ protocol_binary_request_set *rep= (protocol_binary_request_set *)c->wcurr;
3330
+ uint16_t keylen= (uint16_t)item->key_size;
3331
+ uint32_t bodylen= (uint32_t)sizeof(rep->message.body)
3332
+ + (uint32_t)keylen + (uint32_t)item->value_size;
3333
+
3334
+ ms_add_bin_header(c,
3335
+ PROTOCOL_BINARY_CMD_SET,
3336
+ sizeof(rep->message.body),
3337
+ keylen,
3338
+ bodylen);
3339
+ rep->message.body.flags= 0;
3340
+ rep->message.body.expiration= htonl((uint32_t)item->exp_time);
3341
+ ms_add_iov(c, &rep->message.body, sizeof(rep->message.body));
3342
+ ms_add_key_to_iov(c, item);
3343
+
3344
+ if (item->value_offset == INVALID_OFFSET)
3345
+ {
3346
+ value_offset= item->key_suffix_offset;
3347
+ }
3348
+ else
3349
+ {
3350
+ value_offset= item->value_offset;
3351
+ }
3352
+ ms_add_iov(c, &ms_setting.char_block[value_offset], item->value_size);
3353
+
3354
+ return EXIT_SUCCESS;
3355
+ } /* ms_build_bin_write_buf_set */
3356
+
3357
+
3358
+ /**
3359
+ * for binary protocol, this function build the get command and
3360
+ * add the command to send buffer array.
3361
+ *
3362
+ * @param c, pointer of the concurrency
3363
+ * @param item, pointer of task item which includes the object
3364
+ * information
3365
+ *
3366
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3367
+ */
3368
+ static int ms_build_bin_write_buf_get(ms_conn_t *c, ms_task_item_t *item)
3369
+ {
3370
+ assert(c->wbuf == c->wcurr);
3371
+
3372
+ ms_add_bin_header(c, PROTOCOL_BINARY_CMD_GET, 0, (uint16_t)item->key_size,
3373
+ (uint32_t)item->key_size);
3374
+ ms_add_key_to_iov(c, item);
3375
+
3376
+ return EXIT_SUCCESS;
3377
+ } /* ms_build_bin_write_buf_get */
3378
+
3379
+
3380
+ /**
3381
+ * for binary protocol, this function build the multi-get
3382
+ * command and add the command to send buffer array.
3383
+ *
3384
+ * @param c, pointer of the concurrency
3385
+ * @param item, pointer of task item which includes the object
3386
+ * information
3387
+ *
3388
+ * @return int, if success, return EXIT_SUCCESS, else return -1
3389
+ */
3390
+ static int ms_build_bin_write_buf_mlget(ms_conn_t *c)
3391
+ {
3392
+ ms_task_item_t *item;
3393
+
3394
+ assert(c->wbuf == c->wcurr);
3395
+
3396
+ for (int i= 0; i < c->mlget_task.mlget_num; i++)
3397
+ {
3398
+ item= c->mlget_task.mlget_item[i].item;
3399
+ assert(item != NULL);
3400
+
3401
+ ms_add_bin_header(c,
3402
+ PROTOCOL_BINARY_CMD_GET,
3403
+ 0,
3404
+ (uint16_t)item->key_size,
3405
+ (uint32_t)item->key_size);
3406
+ ms_add_key_to_iov(c, item);
3407
+ c->wcurr+= sizeof(protocol_binary_request_get);
3408
+ }
3409
+
3410
+ c->wcurr= c->wbuf;
3411
+
3412
+ return EXIT_SUCCESS;
3413
+ } /* ms_build_bin_write_buf_mlget */