heroku-tokyotyrant 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (340) hide show
  1. data/COPYING +504 -0
  2. data/README.rdoc +231 -0
  3. data/Rakefile +72 -0
  4. data/benchmarks/balancer.rb +101 -0
  5. data/benchmarks/bulk_db.rb +74 -0
  6. data/benchmarks/bulk_table.rb +87 -0
  7. data/benchmarks/db.rb +114 -0
  8. data/benchmarks/table.rb +161 -0
  9. data/ext/extconf.rb +43 -0
  10. data/ext/tokyo/bin/tcamgr +0 -0
  11. data/ext/tokyo/bin/tcamttest +0 -0
  12. data/ext/tokyo/bin/tcatest +0 -0
  13. data/ext/tokyo/bin/tcbmgr +0 -0
  14. data/ext/tokyo/bin/tcbmttest +0 -0
  15. data/ext/tokyo/bin/tcbtest +0 -0
  16. data/ext/tokyo/bin/tcfmgr +0 -0
  17. data/ext/tokyo/bin/tcfmttest +0 -0
  18. data/ext/tokyo/bin/tcftest +0 -0
  19. data/ext/tokyo/bin/tchmgr +0 -0
  20. data/ext/tokyo/bin/tchmttest +0 -0
  21. data/ext/tokyo/bin/tchtest +0 -0
  22. data/ext/tokyo/bin/tcrmgr +0 -0
  23. data/ext/tokyo/bin/tcrmttest +0 -0
  24. data/ext/tokyo/bin/tcrtest +0 -0
  25. data/ext/tokyo/bin/tctmgr +0 -0
  26. data/ext/tokyo/bin/tctmttest +0 -0
  27. data/ext/tokyo/bin/tcttest +0 -0
  28. data/ext/tokyo/bin/tcucodec +0 -0
  29. data/ext/tokyo/bin/tcumttest +0 -0
  30. data/ext/tokyo/bin/tcutest +0 -0
  31. data/ext/tokyo/bin/ttserver +0 -0
  32. data/ext/tokyo/bin/ttulmgr +0 -0
  33. data/ext/tokyo/bin/ttultest +0 -0
  34. data/ext/tokyo/include/tcadb.h +548 -0
  35. data/ext/tokyo/include/tcbdb.h +1101 -0
  36. data/ext/tokyo/include/tcfdb.h +858 -0
  37. data/ext/tokyo/include/tchdb.h +871 -0
  38. data/ext/tokyo/include/tcrdb.h +801 -0
  39. data/ext/tokyo/include/tctdb.h +1086 -0
  40. data/ext/tokyo/include/tculog.h +392 -0
  41. data/ext/tokyo/include/tcutil.h +4184 -0
  42. data/ext/tokyo/include/ttutil.h +494 -0
  43. data/ext/tokyo/lib/libtokyocabinet.9.4.0.dylib +0 -0
  44. data/ext/tokyo/lib/libtokyocabinet.9.dylib +0 -0
  45. data/ext/tokyo/lib/libtokyocabinet.a +0 -0
  46. data/ext/tokyo/lib/libtokyocabinet.dylib +0 -0
  47. data/ext/tokyo/lib/libtokyotyrant.3.22.0.dylib +0 -0
  48. data/ext/tokyo/lib/libtokyotyrant.3.dylib +0 -0
  49. data/ext/tokyo/lib/libtokyotyrant.a +0 -0
  50. data/ext/tokyo/lib/libtokyotyrant.dylib +0 -0
  51. data/ext/tokyo/lib/pkgconfig/tokyocabinet.pc +14 -0
  52. data/ext/tokyo/lib/pkgconfig/tokyotyrant.pc +14 -0
  53. data/ext/tokyo/lib/ttskeldir.bundle +0 -0
  54. data/ext/tokyo/lib/ttskelmock.bundle +0 -0
  55. data/ext/tokyo/lib/ttskelnull.bundle +0 -0
  56. data/ext/tokyo/lib/ttskelproxy.bundle +0 -0
  57. data/ext/tokyo/libexec/tcawmgr.cgi +0 -0
  58. data/ext/tokyo/sbin/ttservctl +163 -0
  59. data/ext/tokyo/share/man/man1/tcamgr.1 +97 -0
  60. data/ext/tokyo/share/man/man1/tcamttest.1 +35 -0
  61. data/ext/tokyo/share/man/man1/tcatest.1 +55 -0
  62. data/ext/tokyo/share/man/man1/tcbmgr.1 +125 -0
  63. data/ext/tokyo/share/man/man1/tcbmttest.1 +81 -0
  64. data/ext/tokyo/share/man/man1/tcbtest.1 +107 -0
  65. data/ext/tokyo/share/man/man1/tcfmgr.1 +98 -0
  66. data/ext/tokyo/share/man/man1/tcfmttest.1 +62 -0
  67. data/ext/tokyo/share/man/man1/tcftest.1 +73 -0
  68. data/ext/tokyo/share/man/man1/tchmgr.1 +110 -0
  69. data/ext/tokyo/share/man/man1/tchmttest.1 +85 -0
  70. data/ext/tokyo/share/man/man1/tchtest.1 +95 -0
  71. data/ext/tokyo/share/man/man1/tcrmgr.1 +164 -0
  72. data/ext/tokyo/share/man/man1/tcrmttest.1 +55 -0
  73. data/ext/tokyo/share/man/man1/tcrtest.1 +89 -0
  74. data/ext/tokyo/share/man/man1/tctmgr.1 +140 -0
  75. data/ext/tokyo/share/man/man1/tctmttest.1 +92 -0
  76. data/ext/tokyo/share/man/man1/tcttest.1 +105 -0
  77. data/ext/tokyo/share/man/man1/tcucodec.1 +162 -0
  78. data/ext/tokyo/share/man/man1/tcumttest.1 +41 -0
  79. data/ext/tokyo/share/man/man1/tcutest.1 +81 -0
  80. data/ext/tokyo/share/man/man1/ttserver.1 +84 -0
  81. data/ext/tokyo/share/man/man1/ttulmgr.1 +40 -0
  82. data/ext/tokyo/share/man/man1/ttultest.1 +16 -0
  83. data/ext/tokyo/share/man/man3/tcadb.3 +676 -0
  84. data/ext/tokyo/share/man/man3/tcbdb.3 +1355 -0
  85. data/ext/tokyo/share/man/man3/tcfdb.3 +975 -0
  86. data/ext/tokyo/share/man/man3/tchdb.3 +898 -0
  87. data/ext/tokyo/share/man/man3/tclist.3 +1 -0
  88. data/ext/tokyo/share/man/man3/tcmap.3 +1 -0
  89. data/ext/tokyo/share/man/man3/tcmdb.3 +1 -0
  90. data/ext/tokyo/share/man/man3/tcmpool.3 +1 -0
  91. data/ext/tokyo/share/man/man3/tcrdb.3 +1309 -0
  92. data/ext/tokyo/share/man/man3/tctdb.3 +1110 -0
  93. data/ext/tokyo/share/man/man3/tctree.3 +1 -0
  94. data/ext/tokyo/share/man/man3/tculog.3 +15 -0
  95. data/ext/tokyo/share/man/man3/tcutil.3 +4518 -0
  96. data/ext/tokyo/share/man/man3/tcxstr.3 +1 -0
  97. data/ext/tokyo/share/man/man3/tokyocabinet.3 +132 -0
  98. data/ext/tokyo/share/man/man3/ttutil.3 +14 -0
  99. data/ext/tokyo/share/man/man8/ttservctl.8 +37 -0
  100. data/ext/tokyo/share/tokyocabinet/COPYING +504 -0
  101. data/ext/tokyo/share/tokyocabinet/ChangeLog +1252 -0
  102. data/ext/tokyo/share/tokyocabinet/THANKS +12 -0
  103. data/ext/tokyo/share/tokyocabinet/doc/benchmark.pdf +0 -0
  104. data/ext/tokyo/share/tokyocabinet/doc/common.css +211 -0
  105. data/ext/tokyo/share/tokyocabinet/doc/icon16.png +0 -0
  106. data/ext/tokyo/share/tokyocabinet/doc/index.html +156 -0
  107. data/ext/tokyo/share/tokyocabinet/doc/index.ja.html +197 -0
  108. data/ext/tokyo/share/tokyocabinet/doc/logo-ja.png +0 -0
  109. data/ext/tokyo/share/tokyocabinet/doc/logo.png +0 -0
  110. data/ext/tokyo/share/tokyocabinet/doc/spex-en.html +7145 -0
  111. data/ext/tokyo/share/tokyocabinet/doc/spex-ja.html +7476 -0
  112. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.pdf +0 -0
  113. data/ext/tokyo/share/tokyocabinet/doc/tokyoproducts.ppt +0 -0
  114. data/ext/tokyo/share/tokyotyrant/COPYING +504 -0
  115. data/ext/tokyo/share/tokyotyrant/ChangeLog +578 -0
  116. data/ext/tokyo/share/tokyotyrant/THANKS +15 -0
  117. data/ext/tokyo/share/tokyotyrant/doc/common.css +211 -0
  118. data/ext/tokyo/share/tokyotyrant/doc/index.html +79 -0
  119. data/ext/tokyo/share/tokyotyrant/doc/spex.html +2264 -0
  120. data/ext/tokyo/share/tokyotyrant/ext/mapreduce.lua +57 -0
  121. data/ext/tokyo/share/tokyotyrant/ext/queue.lua +55 -0
  122. data/ext/tokyo/share/tokyotyrant/ext/senatus.lua +532 -0
  123. data/ext/tokyo/share/tokyotyrant/ext/usherette.lua +438 -0
  124. data/ext/tokyo_tyrant.c +147 -0
  125. data/ext/tokyo_tyrant.h +48 -0
  126. data/ext/tokyo_tyrant_db.c +227 -0
  127. data/ext/tokyo_tyrant_db.h +8 -0
  128. data/ext/tokyo_tyrant_module.c +453 -0
  129. data/ext/tokyo_tyrant_module.h +10 -0
  130. data/ext/tokyo_tyrant_query.c +226 -0
  131. data/ext/tokyo_tyrant_query.h +9 -0
  132. data/ext/tokyo_tyrant_table.c +319 -0
  133. data/ext/tokyo_tyrant_table.h +8 -0
  134. data/ext/tokyocabinet-1.4.41/COPYING +504 -0
  135. data/ext/tokyocabinet-1.4.41/ChangeLog +1252 -0
  136. data/ext/tokyocabinet-1.4.41/Makefile.in +825 -0
  137. data/ext/tokyocabinet-1.4.41/README +38 -0
  138. data/ext/tokyocabinet-1.4.41/THANKS +12 -0
  139. data/ext/tokyocabinet-1.4.41/bros/Makefile +133 -0
  140. data/ext/tokyocabinet-1.4.41/bros/bdbtest.c +438 -0
  141. data/ext/tokyocabinet-1.4.41/bros/cdbtest.c +219 -0
  142. data/ext/tokyocabinet-1.4.41/bros/cmpsqltctest.c +186 -0
  143. data/ext/tokyocabinet-1.4.41/bros/gdbmtest.c +216 -0
  144. data/ext/tokyocabinet-1.4.41/bros/mapreporter +72 -0
  145. data/ext/tokyocabinet-1.4.41/bros/maptest.cc +677 -0
  146. data/ext/tokyocabinet-1.4.41/bros/ndbmtest.c +204 -0
  147. data/ext/tokyocabinet-1.4.41/bros/qdbmtest.c +375 -0
  148. data/ext/tokyocabinet-1.4.41/bros/reporter +141 -0
  149. data/ext/tokyocabinet-1.4.41/bros/result.xls +0 -0
  150. data/ext/tokyocabinet-1.4.41/bros/sdbmtest.c +204 -0
  151. data/ext/tokyocabinet-1.4.41/bros/sqltest.c +404 -0
  152. data/ext/tokyocabinet-1.4.41/bros/tctest.c +748 -0
  153. data/ext/tokyocabinet-1.4.41/bros/tdbtest.c +205 -0
  154. data/ext/tokyocabinet-1.4.41/configure +7402 -0
  155. data/ext/tokyocabinet-1.4.41/configure.in +362 -0
  156. data/ext/tokyocabinet-1.4.41/doc/benchmark.pdf +0 -0
  157. data/ext/tokyocabinet-1.4.41/doc/common.css +211 -0
  158. data/ext/tokyocabinet-1.4.41/doc/icon16.png +0 -0
  159. data/ext/tokyocabinet-1.4.41/doc/index.html +156 -0
  160. data/ext/tokyocabinet-1.4.41/doc/index.ja.html +197 -0
  161. data/ext/tokyocabinet-1.4.41/doc/logo-ja.png +0 -0
  162. data/ext/tokyocabinet-1.4.41/doc/logo.png +0 -0
  163. data/ext/tokyocabinet-1.4.41/doc/spex-en.html +7145 -0
  164. data/ext/tokyocabinet-1.4.41/doc/spex-ja.html +7476 -0
  165. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.pdf +0 -0
  166. data/ext/tokyocabinet-1.4.41/doc/tokyoproducts.ppt +0 -0
  167. data/ext/tokyocabinet-1.4.41/example/Makefile +113 -0
  168. data/ext/tokyocabinet-1.4.41/example/tcadbex.c +55 -0
  169. data/ext/tokyocabinet-1.4.41/example/tcbdbex.c +64 -0
  170. data/ext/tokyocabinet-1.4.41/example/tcfdbex.c +60 -0
  171. data/ext/tokyocabinet-1.4.41/example/tchdbex.c +60 -0
  172. data/ext/tokyocabinet-1.4.41/example/tctchat.c +97 -0
  173. data/ext/tokyocabinet-1.4.41/example/tctchat.tmpl +141 -0
  174. data/ext/tokyocabinet-1.4.41/example/tctdbex.c +85 -0
  175. data/ext/tokyocabinet-1.4.41/example/tctsearch.c +95 -0
  176. data/ext/tokyocabinet-1.4.41/example/tctsearch.tmpl +122 -0
  177. data/ext/tokyocabinet-1.4.41/example/tcutilex.c +77 -0
  178. data/ext/tokyocabinet-1.4.41/f.tsv +2 -0
  179. data/ext/tokyocabinet-1.4.41/lab/calccomp +118 -0
  180. data/ext/tokyocabinet-1.4.41/lab/datechange +56 -0
  181. data/ext/tokyocabinet-1.4.41/lab/diffcheck +45 -0
  182. data/ext/tokyocabinet-1.4.41/lab/htmltotsv +102 -0
  183. data/ext/tokyocabinet-1.4.41/lab/magic +19 -0
  184. data/ext/tokyocabinet-1.4.41/lab/printenv.cgi +27 -0
  185. data/ext/tokyocabinet-1.4.41/lab/stepcount +26 -0
  186. data/ext/tokyocabinet-1.4.41/lab/stopwatch +61 -0
  187. data/ext/tokyocabinet-1.4.41/lab/tabcheck +43 -0
  188. data/ext/tokyocabinet-1.4.41/lab/wgettsv +239 -0
  189. data/ext/tokyocabinet-1.4.41/lab/widthcheck +57 -0
  190. data/ext/tokyocabinet-1.4.41/man/htmltoman +104 -0
  191. data/ext/tokyocabinet-1.4.41/man/tcadb.3 +676 -0
  192. data/ext/tokyocabinet-1.4.41/man/tcamgr.1 +97 -0
  193. data/ext/tokyocabinet-1.4.41/man/tcamttest.1 +35 -0
  194. data/ext/tokyocabinet-1.4.41/man/tcatest.1 +55 -0
  195. data/ext/tokyocabinet-1.4.41/man/tcbdb.3 +1355 -0
  196. data/ext/tokyocabinet-1.4.41/man/tcbmgr.1 +125 -0
  197. data/ext/tokyocabinet-1.4.41/man/tcbmttest.1 +81 -0
  198. data/ext/tokyocabinet-1.4.41/man/tcbtest.1 +107 -0
  199. data/ext/tokyocabinet-1.4.41/man/tcfdb.3 +975 -0
  200. data/ext/tokyocabinet-1.4.41/man/tcfmgr.1 +98 -0
  201. data/ext/tokyocabinet-1.4.41/man/tcfmttest.1 +62 -0
  202. data/ext/tokyocabinet-1.4.41/man/tcftest.1 +73 -0
  203. data/ext/tokyocabinet-1.4.41/man/tchdb.3 +898 -0
  204. data/ext/tokyocabinet-1.4.41/man/tchmgr.1 +110 -0
  205. data/ext/tokyocabinet-1.4.41/man/tchmttest.1 +85 -0
  206. data/ext/tokyocabinet-1.4.41/man/tchtest.1 +95 -0
  207. data/ext/tokyocabinet-1.4.41/man/tclist.3 +1 -0
  208. data/ext/tokyocabinet-1.4.41/man/tcmap.3 +1 -0
  209. data/ext/tokyocabinet-1.4.41/man/tcmdb.3 +1 -0
  210. data/ext/tokyocabinet-1.4.41/man/tcmpool.3 +1 -0
  211. data/ext/tokyocabinet-1.4.41/man/tctdb.3 +1110 -0
  212. data/ext/tokyocabinet-1.4.41/man/tctmgr.1 +140 -0
  213. data/ext/tokyocabinet-1.4.41/man/tctmttest.1 +92 -0
  214. data/ext/tokyocabinet-1.4.41/man/tctree.3 +1 -0
  215. data/ext/tokyocabinet-1.4.41/man/tcttest.1 +105 -0
  216. data/ext/tokyocabinet-1.4.41/man/tcucodec.1 +162 -0
  217. data/ext/tokyocabinet-1.4.41/man/tcumttest.1 +41 -0
  218. data/ext/tokyocabinet-1.4.41/man/tcutest.1 +81 -0
  219. data/ext/tokyocabinet-1.4.41/man/tcutil.3 +4518 -0
  220. data/ext/tokyocabinet-1.4.41/man/tcxstr.3 +1 -0
  221. data/ext/tokyocabinet-1.4.41/man/tokyocabinet.3 +132 -0
  222. data/ext/tokyocabinet-1.4.41/md5.c +381 -0
  223. data/ext/tokyocabinet-1.4.41/md5.h +101 -0
  224. data/ext/tokyocabinet-1.4.41/myconf.c +493 -0
  225. data/ext/tokyocabinet-1.4.41/myconf.h +549 -0
  226. data/ext/tokyocabinet-1.4.41/tcadb.c +4339 -0
  227. data/ext/tokyocabinet-1.4.41/tcadb.h +548 -0
  228. data/ext/tokyocabinet-1.4.41/tcamgr.c +1019 -0
  229. data/ext/tokyocabinet-1.4.41/tcamttest.c +542 -0
  230. data/ext/tokyocabinet-1.4.41/tcatest.c +1845 -0
  231. data/ext/tokyocabinet-1.4.41/tcawmgr.c +482 -0
  232. data/ext/tokyocabinet-1.4.41/tcbdb.c +4180 -0
  233. data/ext/tokyocabinet-1.4.41/tcbdb.h +1101 -0
  234. data/ext/tokyocabinet-1.4.41/tcbmgr.c +1012 -0
  235. data/ext/tokyocabinet-1.4.41/tcbmttest.c +1810 -0
  236. data/ext/tokyocabinet-1.4.41/tcbtest.c +2586 -0
  237. data/ext/tokyocabinet-1.4.41/tcfdb.c +2746 -0
  238. data/ext/tokyocabinet-1.4.41/tcfdb.h +858 -0
  239. data/ext/tokyocabinet-1.4.41/tcfmgr.c +786 -0
  240. data/ext/tokyocabinet-1.4.41/tcfmttest.c +1220 -0
  241. data/ext/tokyocabinet-1.4.41/tcftest.c +1695 -0
  242. data/ext/tokyocabinet-1.4.41/tchdb.c +5153 -0
  243. data/ext/tokyocabinet-1.4.41/tchdb.h +871 -0
  244. data/ext/tokyocabinet-1.4.41/tchmgr.c +842 -0
  245. data/ext/tokyocabinet-1.4.41/tchmttest.c +1757 -0
  246. data/ext/tokyocabinet-1.4.41/tchtest.c +2129 -0
  247. data/ext/tokyocabinet-1.4.41/tctdb.c +6199 -0
  248. data/ext/tokyocabinet-1.4.41/tctdb.h +1086 -0
  249. data/ext/tokyocabinet-1.4.41/tctmgr.c +1241 -0
  250. data/ext/tokyocabinet-1.4.41/tctmttest.c +1563 -0
  251. data/ext/tokyocabinet-1.4.41/tcttest.c +2062 -0
  252. data/ext/tokyocabinet-1.4.41/tcucodec.c +1357 -0
  253. data/ext/tokyocabinet-1.4.41/tcumttest.c +578 -0
  254. data/ext/tokyocabinet-1.4.41/tcutest.c +1875 -0
  255. data/ext/tokyocabinet-1.4.41/tcutil.c +10528 -0
  256. data/ext/tokyocabinet-1.4.41/tcutil.h +4184 -0
  257. data/ext/tokyocabinet-1.4.41/tokyocabinet.idl +336 -0
  258. data/ext/tokyocabinet-1.4.41/tokyocabinet.pc.in +14 -0
  259. data/ext/tokyotyrant-1.1.39/COPYING +504 -0
  260. data/ext/tokyotyrant-1.1.39/ChangeLog +578 -0
  261. data/ext/tokyotyrant-1.1.39/Makefile.in +365 -0
  262. data/ext/tokyotyrant-1.1.39/README +38 -0
  263. data/ext/tokyotyrant-1.1.39/THANKS +15 -0
  264. data/ext/tokyotyrant-1.1.39/configure +6979 -0
  265. data/ext/tokyotyrant-1.1.39/configure.in +300 -0
  266. data/ext/tokyotyrant-1.1.39/doc/common.css +211 -0
  267. data/ext/tokyotyrant-1.1.39/doc/index.html +79 -0
  268. data/ext/tokyotyrant-1.1.39/doc/spex.html +2264 -0
  269. data/ext/tokyotyrant-1.1.39/example/Makefile +68 -0
  270. data/ext/tokyotyrant-1.1.39/example/httptest.pl +88 -0
  271. data/ext/tokyotyrant-1.1.39/example/mcftest.pl +39 -0
  272. data/ext/tokyotyrant-1.1.39/example/mctest.pl +43 -0
  273. data/ext/tokyotyrant-1.1.39/example/tcrdbex +0 -0
  274. data/ext/tokyotyrant-1.1.39/example/tcrdbex.c +49 -0
  275. data/ext/tokyotyrant-1.1.39/example/tcrdbex.o +0 -0
  276. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex +0 -0
  277. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.c +79 -0
  278. data/ext/tokyotyrant-1.1.39/example/tcrdbtblex.o +0 -0
  279. data/ext/tokyotyrant-1.1.39/ext/mapreduce.lua +57 -0
  280. data/ext/tokyotyrant-1.1.39/ext/queue.lua +55 -0
  281. data/ext/tokyotyrant-1.1.39/ext/senatus.lua +532 -0
  282. data/ext/tokyotyrant-1.1.39/ext/usherette.lua +438 -0
  283. data/ext/tokyotyrant-1.1.39/lab/datechange +56 -0
  284. data/ext/tokyotyrant-1.1.39/lab/diffcheck +45 -0
  285. data/ext/tokyotyrant-1.1.39/lab/fibonacci.lua +20 -0
  286. data/ext/tokyotyrant-1.1.39/lab/footprint.lua +67 -0
  287. data/ext/tokyotyrant-1.1.39/lab/highlow.lua +88 -0
  288. data/ext/tokyotyrant-1.1.39/lab/killdualmaster +12 -0
  289. data/ext/tokyotyrant-1.1.39/lab/rundualmaster +38 -0
  290. data/ext/tokyotyrant-1.1.39/lab/stepcount +26 -0
  291. data/ext/tokyotyrant-1.1.39/lab/tabcheck +43 -0
  292. data/ext/tokyotyrant-1.1.39/lab/ushrtregister.pl +55 -0
  293. data/ext/tokyotyrant-1.1.39/lab/widthcheck +57 -0
  294. data/ext/tokyotyrant-1.1.39/man/htmltoman +100 -0
  295. data/ext/tokyotyrant-1.1.39/man/tcrdb.3 +1309 -0
  296. data/ext/tokyotyrant-1.1.39/man/tcrmgr.1 +164 -0
  297. data/ext/tokyotyrant-1.1.39/man/tcrmttest.1 +55 -0
  298. data/ext/tokyotyrant-1.1.39/man/tcrtest.1 +89 -0
  299. data/ext/tokyotyrant-1.1.39/man/tculog.3 +15 -0
  300. data/ext/tokyotyrant-1.1.39/man/ttservctl.8 +37 -0
  301. data/ext/tokyotyrant-1.1.39/man/ttserver.1 +84 -0
  302. data/ext/tokyotyrant-1.1.39/man/ttulmgr.1 +40 -0
  303. data/ext/tokyotyrant-1.1.39/man/ttultest.1 +16 -0
  304. data/ext/tokyotyrant-1.1.39/man/ttutil.3 +14 -0
  305. data/ext/tokyotyrant-1.1.39/myconf.c +169 -0
  306. data/ext/tokyotyrant-1.1.39/myconf.h +408 -0
  307. data/ext/tokyotyrant-1.1.39/scrext.c +2394 -0
  308. data/ext/tokyotyrant-1.1.39/scrext.h +96 -0
  309. data/ext/tokyotyrant-1.1.39/tcrdb.c +2637 -0
  310. data/ext/tokyotyrant-1.1.39/tcrdb.h +801 -0
  311. data/ext/tokyotyrant-1.1.39/tcrmgr.c +1559 -0
  312. data/ext/tokyotyrant-1.1.39/tcrmttest.c +915 -0
  313. data/ext/tokyotyrant-1.1.39/tcrtest.c +1542 -0
  314. data/ext/tokyotyrant-1.1.39/tculog.c +1211 -0
  315. data/ext/tokyotyrant-1.1.39/tculog.h +392 -0
  316. data/ext/tokyotyrant-1.1.39/tokyotyrant.idl +143 -0
  317. data/ext/tokyotyrant-1.1.39/tokyotyrant.pc.in +14 -0
  318. data/ext/tokyotyrant-1.1.39/ttservctl +163 -0
  319. data/ext/tokyotyrant-1.1.39/ttserver.c +3583 -0
  320. data/ext/tokyotyrant-1.1.39/ttskeldir.c +141 -0
  321. data/ext/tokyotyrant-1.1.39/ttskelmock.c +64 -0
  322. data/ext/tokyotyrant-1.1.39/ttskelnull.c +79 -0
  323. data/ext/tokyotyrant-1.1.39/ttskelproxy.c +74 -0
  324. data/ext/tokyotyrant-1.1.39/ttulmgr.c +266 -0
  325. data/ext/tokyotyrant-1.1.39/ttultest.c +371 -0
  326. data/ext/tokyotyrant-1.1.39/ttutil.c +1510 -0
  327. data/ext/tokyotyrant-1.1.39/ttutil.h +494 -0
  328. data/lib/tokyo_tyrant/balancer.rb +189 -0
  329. data/spec/ext.lua +4 -0
  330. data/spec/plu_db.rb +538 -0
  331. data/spec/spec.rb +1 -0
  332. data/spec/spec_base.rb +17 -0
  333. data/spec/start_tyrants.sh +36 -0
  334. data/spec/stop_tyrants.sh +9 -0
  335. data/spec/tokyo_tyrant_balancer_db_spec.rb +160 -0
  336. data/spec/tokyo_tyrant_balancer_table_spec.rb +177 -0
  337. data/spec/tokyo_tyrant_query_spec.rb +159 -0
  338. data/spec/tokyo_tyrant_spec.rb +254 -0
  339. data/spec/tokyo_tyrant_table_spec.rb +301 -0
  340. metadata +402 -0
@@ -0,0 +1,14 @@
1
+ prefix=@prefix@
2
+ exec_prefix=@exec_prefix@
3
+ datarootdir = @datarootdir@
4
+ bindir=@bindir@
5
+ libdir=@libdir@
6
+ libexecdir=@libexecdir@
7
+ includedir=@includedir@
8
+ datadir=@datadir@
9
+
10
+ Name: Tokyo Tyrant
11
+ Description: network interface of Tokyo Cabinet
12
+ Version: @PACKAGE_VERSION@
13
+ Libs: -L${libdir} -ltokyotyrant @LIBS@
14
+ Cflags: -I${includedir}
@@ -0,0 +1,163 @@
1
+ #! /bin/sh
2
+
3
+ #----------------------------------------------------------------
4
+ # Startup script for the server of Tokyo Tyrant
5
+ #----------------------------------------------------------------
6
+
7
+
8
+ # configuration variables
9
+ prog="ttservctl"
10
+ cmd="ttserver"
11
+ basedir="/var/ttserver"
12
+ port="1978"
13
+ pidfile="$basedir/pid"
14
+ #logfile="$basedir/log"
15
+ #ulogdir="$basedir/ulog"
16
+ #ulimsiz="256m"
17
+ #sid=1
18
+ #mhost="remotehost1"
19
+ #mport="1978"
20
+ #rtsfile="$basedir/rts"
21
+ dbname="$basedir/casket.tch#bnum=1000000"
22
+ retval=0
23
+
24
+
25
+ # setting environment variables
26
+ LANG=C
27
+ LC_ALL=C
28
+ PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
29
+ export LANG LC_ALL PATH
30
+
31
+
32
+ # start the server
33
+ start(){
34
+ printf 'Starting the server of Tokyo Tyrant\n'
35
+ mkdir -p "$basedir"
36
+ if [ -z "$basedir" ] || [ -z "$port" ] || [ -z "$pidfile" ] || [ -z "$dbname" ] ; then
37
+ printf 'Invalid configuration\n'
38
+ retval=1
39
+ elif ! [ -d "$basedir" ] ; then
40
+ printf 'No such directory: %s\n' "$basedir"
41
+ retval=1
42
+ elif [ -f "$pidfile" ] ; then
43
+ pid=`cat "$pidfile"`
44
+ printf 'Existing process: %d\n' "$pid"
45
+ retval=1
46
+ else
47
+ cmd="$cmd -port $port -dmn -pid $pidfile"
48
+ if [ -n "$logfile" ] ; then
49
+ cmd="$cmd -log $logfile"
50
+ fi
51
+ if [ -n "$ulogdir" ] ; then
52
+ mkdir -p "$ulogdir"
53
+ cmd="$cmd -ulog $ulogdir"
54
+ fi
55
+ if [ -n "$ulimsiz" ] ; then
56
+ cmd="$cmd -ulim $ulimsiz"
57
+ fi
58
+ if [ -n "$sid" ] ; then
59
+ cmd="$cmd -sid $sid"
60
+ fi
61
+ if [ -n "$mhost" ] ; then
62
+ cmd="$cmd -mhost $mhost"
63
+ fi
64
+ if [ -n "$mport" ] ; then
65
+ cmd="$cmd -mport $mport"
66
+ fi
67
+ if [ -n "$rtsfile" ] ; then
68
+ cmd="$cmd -rts $rtsfile"
69
+ fi
70
+ printf "Executing: %s\n" "$cmd"
71
+ cmd="$cmd $dbname"
72
+ $cmd
73
+ if [ "$?" -eq 0 ] ; then
74
+ printf 'Done\n'
75
+ else
76
+ printf 'The server could not started\n'
77
+ retval=1
78
+ fi
79
+ fi
80
+ }
81
+
82
+
83
+ # stop the server
84
+ stop(){
85
+ printf 'Stopping the server of Tokyo Tyrant\n'
86
+ if [ -f "$pidfile" ] ; then
87
+ pid=`cat "$pidfile"`
88
+ printf "Sending the terminal signal to the process: %s\n" "$pid"
89
+ kill -TERM "$pid"
90
+ c=0
91
+ while true ; do
92
+ sleep 0.1
93
+ if [ -f "$pidfile" ] ; then
94
+ c=`expr $c + 1`
95
+ if [ "$c" -ge 100 ] ; then
96
+ printf 'Hanging process: %d\n' "$pid"
97
+ retval=1
98
+ break
99
+ fi
100
+ else
101
+ printf 'Done\n'
102
+ break
103
+ fi
104
+ done
105
+ else
106
+ printf 'No process found\n'
107
+ retval=1
108
+ fi
109
+ }
110
+
111
+
112
+ # send HUP to the server for log rotation
113
+ hup(){
114
+ printf 'Sending HUP signal to the server of Tokyo Tyrant\n'
115
+ if [ -f "$pidfile" ] ; then
116
+ pid=`cat "$pidfile"`
117
+ printf "Sending the hangup signal to the process: %s\n" "$pid"
118
+ kill -HUP "$pid"
119
+ printf 'Done\n'
120
+ else
121
+ printf 'No process found\n'
122
+ retval=1
123
+ fi
124
+ }
125
+
126
+
127
+ # check permission
128
+ if [ -d "$basedir" ] && ! touch "$basedir/$$" >/dev/null 2>&1
129
+ then
130
+ printf 'Permission denied\n'
131
+ exit 1
132
+ fi
133
+ rm -f "$basedir/$$"
134
+
135
+
136
+ # dispatch the command
137
+ case "$1" in
138
+ start)
139
+ start
140
+ ;;
141
+ stop)
142
+ stop
143
+ ;;
144
+ restart)
145
+ stop
146
+ start
147
+ ;;
148
+ hup)
149
+ hup
150
+ ;;
151
+ *)
152
+ printf 'Usage: %s {start|stop|restart|hup}\n' "$prog"
153
+ exit 1
154
+ ;;
155
+ esac
156
+
157
+
158
+ # exit
159
+ exit "$retval"
160
+
161
+
162
+
163
+ # END OF FILE
@@ -0,0 +1,3583 @@
1
+ /*************************************************************************************************
2
+ * The server of Tokyo Tyrant
3
+ * Copyright (C) 2006-2009 Mikio Hirabayashi
4
+ * This file is part of Tokyo Tyrant.
5
+ * Tokyo Tyrant is free software; you can redistribute it and/or modify it under the terms of
6
+ * the GNU Lesser General Public License as published by the Free Software Foundation; either
7
+ * version 2.1 of the License or any later version. Tokyo Tyrant is distributed in the hope
8
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10
+ * License for more details.
11
+ * You should have received a copy of the GNU Lesser General Public License along with Tokyo
12
+ * Tyrant; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
13
+ * Boston, MA 02111-1307 USA.
14
+ *************************************************************************************************/
15
+
16
+
17
+ #include <ttutil.h>
18
+ #include <tculog.h>
19
+ #include <tcrdb.h>
20
+ #include "myconf.h"
21
+ #include "scrext.h"
22
+
23
+ #define DEFTHNUM 8 // default thread number
24
+ #define DEFPIDPATH "ttserver.pid" // default name of the PID file
25
+ #define DEFRTSPATH "ttserver.rts" // default name of the RTS file
26
+ #define DEFULIMSIZ (1LL<<30) // default limit size of an update log file
27
+ #define MAXARGSIZ (32<<20) // maximum size of each argument
28
+ #define MAXARGNUM (1<<20) // maximum number of arguments
29
+ #define NUMBUFSIZ 32 // size of a numeric buffer
30
+ #define LINEBUFSIZ 8192 // size of a line buffer
31
+ #define TOKENUNIT 256 // unit number of tokens
32
+ #define RECMTXNUM 31 // number of mutexes of records
33
+ #define STASHBNUM 1021 // bucket number of the script stash object
34
+ #define REPLPERIOD 1.0 // period of calling replication request
35
+
36
+ enum { // enumeration for command sequential numbers
37
+ TTSEQPUT, // sequential number of put command
38
+ TTSEQPUTKEEP, // sequential number of putkeep command
39
+ TTSEQPUTCAT, // sequential number of putcat command
40
+ TTSEQPUTSHL, // sequential number of putshl command
41
+ TTSEQPUTNR, // sequential number of putnr command
42
+ TTSEQOUT, // sequential number of out command
43
+ TTSEQGET, // sequential number of get command
44
+ TTSEQMGET, // sequential number of mget command
45
+ TTSEQVSIZ, // sequential number of vsiz command
46
+ TTSEQITERINIT, // sequential number of iterinit command
47
+ TTSEQITERNEXT, // sequential number of iternext command
48
+ TTSEQFWMKEYS, // sequential number of fwmkeys command
49
+ TTSEQADDINT, // sequential number of addint command
50
+ TTSEQADDDOUBLE, // sequential number of adddouble command
51
+ TTSEQEXT, // sequential number of ext command
52
+ TTSEQSYNC, // sequential number of sync command
53
+ TTSEQOPTIMIZE, // sequential number of sync command
54
+ TTSEQVANISH, // sequential number of vanish command
55
+ TTSEQCOPY, // sequential number of copy command
56
+ TTSEQRESTORE, // sequential number of restore command
57
+ TTSEQSETMST, // sequential number of setmst command
58
+ TTSEQRNUM, // sequential number of rnum command
59
+ TTSEQSIZE, // sequential number of size command
60
+ TTSEQSTAT, // sequential number of stat command
61
+ TTSEQMISC, // sequential number of stat command
62
+ TTSEQREPL, // sequential number of repl command
63
+ TTSEQSLAVE, // sequential number of slave command
64
+ TTSEQALLORG, // sequential number of all commands the original
65
+ TTSEQALLMC, // sequential number of all commands the memcached
66
+ TTSEQALLHTTP, // sequential number of all commands the HTTP
67
+ TTSEQALLREAD, // sequential number of all commands of reading
68
+ TTSEQALLWRITE, // sequential number of all commands of writing
69
+ TTSEQALLMANAGE // sequential number of all commands of managing
70
+ };
71
+
72
+ enum { // enumeration for command sequential numbers
73
+ TTSEQPUTMISS = TTSEQSLAVE, // sequential number of misses of get commands
74
+ TTSEQOUTMISS, // sequential number of misses of out commands
75
+ TTSEQGETMISS, // sequential number of misses of get commands
76
+ TTSEQNUM // number of sequential numbers
77
+ };
78
+
79
+ typedef struct { // type of structure of logging opaque object
80
+ int fd;
81
+ } LOGARG;
82
+
83
+ typedef struct { // type of structure of master synchronous object
84
+ char host[TTADDRBUFSIZ]; // host name
85
+ int port; // port number
86
+ const char *rtspath; // path of the replication time stamp file
87
+ uint64_t rts; // replication time stamp
88
+ int opts; // options
89
+ TCADB *adb; // database object
90
+ TCULOG *ulog; // update log object
91
+ uint32_t sid; // server ID number
92
+ bool fail; // failure flag
93
+ bool recon; // re-connect flag
94
+ bool fatal; // fatal error flag
95
+ uint64_t mts; // modified time stamp
96
+ } REPLARG;
97
+
98
+ typedef struct { // type of structure of periodic opaque object
99
+ const char *name; // function name
100
+ TCADB *adb; // database object
101
+ TCULOG *ulog; // update log object
102
+ uint32_t sid; // server ID number
103
+ REPLARG *sarg; // replication object
104
+ void *scrext; // script extension object
105
+ } EXTPCARG;
106
+
107
+ typedef struct { // type of structure of task opaque object
108
+ int thnum; // number of threads
109
+ uint64_t *counts; // conunters of execution
110
+ uint64_t mask; // bit mask of commands
111
+ TCADB *adb; // database object
112
+ TCULOG *ulog; // update log object
113
+ uint32_t sid; // server ID number
114
+ REPLARG *sarg; // replication object
115
+ pthread_mutex_t rmtxs[RECMTXNUM]; // mutex for records
116
+ void **screxts; // script extension objects
117
+ } TASKARG;
118
+
119
+ typedef struct { // type of structure of termination opaque object
120
+ int thnum; // number of threads
121
+ TCADB *adb; // database object
122
+ REPLARG *sarg; // replication object
123
+ void **screxts; // script extension objects
124
+ EXTPCARG *pcargs; // periodic opaque objects
125
+ int pcnum; // number of periodic opaque objects
126
+ bool err; // error flag
127
+ } TERMARG;
128
+
129
+
130
+ /* global variables */
131
+ const char *g_progname = NULL; // program name
132
+ double g_starttime = 0.0; // start time
133
+ TTSERV *g_serv = NULL; // server object
134
+ int g_loglevel = TTLOGINFO; // whether to log debug information
135
+ bool g_restart = false; // restart flag
136
+
137
+
138
+ /* function prototypes */
139
+ int main(int argc, char **argv);
140
+ static void usage(void);
141
+ static uint64_t getcmdmask(const char *expr);
142
+ static void sigtermhandler(int signum);
143
+ static void sigchldhandler(int signum);
144
+ static int proc(const char *dbname, const char *host, int port, int thnum, int tout,
145
+ bool dmn, const char *pidpath, bool kl, const char *logpath,
146
+ const char *ulogpath, uint64_t ulim, bool uas, uint32_t sid,
147
+ const char *mhost, int mport, const char *rtspath, int ropts,
148
+ const char *skelpath, int mulnum, const char *extpath, const TCLIST *extpcs,
149
+ uint64_t mask);
150
+ static void do_log(int level, const char *msg, void *opq);
151
+ static void do_slave(void *opq);
152
+ static void do_extpc(void *opq);
153
+ static void do_task(TTSOCK *sock, void *opq, TTREQ *req);
154
+ static char **tokenize(char *str, int *np);
155
+ static uint32_t recmtxidx(const char *kbuf, int ksiz);
156
+ static uint64_t sumstat(TASKARG *arg, int seq);
157
+ static void do_put(TTSOCK *sock, TASKARG *arg, TTREQ *req);
158
+ static void do_putkeep(TTSOCK *sock, TASKARG *arg, TTREQ *req);
159
+ static void do_putcat(TTSOCK *sock, TASKARG *arg, TTREQ *req);
160
+ static void do_putshl(TTSOCK *sock, TASKARG *arg, TTREQ *req);
161
+ static void do_putnr(TTSOCK *sock, TASKARG *arg, TTREQ *req);
162
+ static void do_out(TTSOCK *sock, TASKARG *arg, TTREQ *req);
163
+ static void do_get(TTSOCK *sock, TASKARG *arg, TTREQ *req);
164
+ static void do_mget(TTSOCK *sock, TASKARG *arg, TTREQ *req);
165
+ static void do_vsiz(TTSOCK *sock, TASKARG *arg, TTREQ *req);
166
+ static void do_iterinit(TTSOCK *sock, TASKARG *arg, TTREQ *req);
167
+ static void do_iternext(TTSOCK *sock, TASKARG *arg, TTREQ *req);
168
+ static void do_fwmkeys(TTSOCK *sock, TASKARG *arg, TTREQ *req);
169
+ static void do_addint(TTSOCK *sock, TASKARG *arg, TTREQ *req);
170
+ static void do_adddouble(TTSOCK *sock, TASKARG *arg, TTREQ *req);
171
+ static void do_ext(TTSOCK *sock, TASKARG *arg, TTREQ *req);
172
+ static void do_sync(TTSOCK *sock, TASKARG *arg, TTREQ *req);
173
+ static void do_optimize(TTSOCK *sock, TASKARG *arg, TTREQ *req);
174
+ static void do_vanish(TTSOCK *sock, TASKARG *arg, TTREQ *req);
175
+ static void do_copy(TTSOCK *sock, TASKARG *arg, TTREQ *req);
176
+ static void do_restore(TTSOCK *sock, TASKARG *arg, TTREQ *req);
177
+ static void do_setmst(TTSOCK *sock, TASKARG *arg, TTREQ *req);
178
+ static void do_rnum(TTSOCK *sock, TASKARG *arg, TTREQ *req);
179
+ static void do_size(TTSOCK *sock, TASKARG *arg, TTREQ *req);
180
+ static void do_stat(TTSOCK *sock, TASKARG *arg, TTREQ *req);
181
+ static void do_misc(TTSOCK *sock, TASKARG *arg, TTREQ *req);
182
+ static void do_repl(TTSOCK *sock, TASKARG *arg, TTREQ *req);
183
+ static void do_mc_set(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
184
+ static void do_mc_add(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
185
+ static void do_mc_replace(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
186
+ static void do_mc_append(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
187
+ static void do_mc_prepend(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
188
+ static void do_mc_get(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
189
+ static void do_mc_delete(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
190
+ static void do_mc_incr(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
191
+ static void do_mc_decr(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
192
+ static void do_mc_stats(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
193
+ static void do_mc_flushall(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
194
+ static void do_mc_version(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
195
+ static void do_mc_quit(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum);
196
+ static void do_http_get(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
197
+ static void do_http_head(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
198
+ static void do_http_put(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
199
+ static void do_http_post(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
200
+ static void do_http_delete(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
201
+ static void do_http_options(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri);
202
+ static void do_term(void *opq);
203
+
204
+
205
+ /* main routine */
206
+ int main(int argc, char **argv){
207
+ g_progname = argv[0];
208
+ g_starttime = tctime();
209
+ char *dbname = NULL;
210
+ char *host = NULL;
211
+ char *pidpath = NULL;
212
+ char *logpath = NULL;
213
+ char *ulogpath = NULL;
214
+ char *mhost = NULL;
215
+ char *rtspath = NULL;
216
+ char *skelpath = NULL;
217
+ char *extpath = NULL;
218
+ TCLIST *extpcs = NULL;
219
+ int port = TTDEFPORT;
220
+ int thnum = DEFTHNUM;
221
+ int tout = 0;
222
+ bool dmn = false;
223
+ bool kl = false;
224
+ uint64_t ulim = DEFULIMSIZ;
225
+ bool uas = false;
226
+ uint32_t sid = 0;
227
+ int mport = TTDEFPORT;
228
+ int ropts = 0;
229
+ int mulnum = 0;
230
+ uint64_t mask = 0;
231
+ for(int i = 1; i < argc; i++){
232
+ if(!dbname && argv[i][0] == '-'){
233
+ if(!strcmp(argv[i], "-host")){
234
+ if(++i >= argc) usage();
235
+ host = argv[i];
236
+ } else if(!strcmp(argv[i], "-port")){
237
+ if(++i >= argc) usage();
238
+ port = tcatoi(argv[i]);
239
+ } else if(!strcmp(argv[i], "-thnum")){
240
+ if(++i >= argc) usage();
241
+ thnum = tcatoi(argv[i]);
242
+ } else if(!strcmp(argv[i], "-tout")){
243
+ if(++i >= argc) usage();
244
+ tout = tcatoi(argv[i]);
245
+ } else if(!strcmp(argv[i], "-dmn")){
246
+ dmn = true;
247
+ } else if(!strcmp(argv[i], "-pid")){
248
+ if(++i >= argc) usage();
249
+ pidpath = argv[i];
250
+ } else if(!strcmp(argv[i], "-kl")){
251
+ kl = true;
252
+ } else if(!strcmp(argv[i], "-log")){
253
+ if(++i >= argc) usage();
254
+ logpath = argv[i];
255
+ } else if(!strcmp(argv[i], "-ld")){
256
+ g_loglevel = TTLOGDEBUG;
257
+ } else if(!strcmp(argv[i], "-le")){
258
+ g_loglevel = TTLOGERROR;
259
+ } else if(!strcmp(argv[i], "-ulog")){
260
+ if(++i >= argc) usage();
261
+ ulogpath = argv[i];
262
+ } else if(!strcmp(argv[i], "-ulim")){
263
+ if(++i >= argc) usage();
264
+ ulim = tcatoix(argv[i]);
265
+ } else if(!strcmp(argv[i], "-uas")){
266
+ uas = true;
267
+ } else if(!strcmp(argv[i], "-sid")){
268
+ if(++i >= argc) usage();
269
+ sid = tcatoi(argv[i]);
270
+ } else if(!strcmp(argv[i], "-mhost")){
271
+ if(++i >= argc) usage();
272
+ mhost = argv[i];
273
+ } else if(!strcmp(argv[i], "-mport")){
274
+ if(++i >= argc) usage();
275
+ mport = tcatoi(argv[i]);
276
+ } else if(!strcmp(argv[i], "-rts")){
277
+ if(++i >= argc) usage();
278
+ rtspath = argv[i];
279
+ } else if(!strcmp(argv[i], "-rcc")){
280
+ ropts |= RDBROCHKCON;
281
+ } else if(!strcmp(argv[i], "-skel")){
282
+ if(++i >= argc) usage();
283
+ skelpath = argv[i];
284
+ } else if(!strcmp(argv[i], "-mul")){
285
+ if(++i >= argc) usage();
286
+ mulnum = tcatoi(argv[i]);
287
+ } else if(!strcmp(argv[i], "-ext")){
288
+ if(++i >= argc) usage();
289
+ extpath = argv[i];
290
+ } else if(!strcmp(argv[i], "-extpc")){
291
+ if(!extpcs) extpcs = tclistnew2(1);
292
+ if(++i >= argc) usage();
293
+ tclistpush2(extpcs, argv[i]);
294
+ if(++i >= argc) usage();
295
+ tclistpush2(extpcs, argv[i]);
296
+ } else if(!strcmp(argv[i], "-mask")){
297
+ if(++i >= argc) usage();
298
+ mask |= getcmdmask(argv[i]);
299
+ } else if(!strcmp(argv[i], "-unmask")){
300
+ if(++i >= argc) usage();
301
+ mask &= ~getcmdmask(argv[i]);
302
+ } else if(!strcmp(argv[i], "--version")){
303
+ printf("Tokyo Tyrant version %s (%d:%s) for %s\n",
304
+ ttversion, _TT_LIBVER, _TT_PROTVER, TTSYSNAME);
305
+ printf("Copyright (C) 2006-2009 Mikio Hirabayashi\n");
306
+ exit(0);
307
+ } else {
308
+ usage();
309
+ }
310
+ } else if(!dbname){
311
+ dbname = argv[i];
312
+ } else {
313
+ usage();
314
+ }
315
+ }
316
+ if(!dbname) dbname = "*";
317
+ if(thnum < 1 || mport < 1) usage();
318
+ if(dmn && !pidpath) pidpath = DEFPIDPATH;
319
+ if(!rtspath) rtspath = DEFRTSPATH;
320
+ g_serv = ttservnew();
321
+ int rv = proc(dbname, host, port, thnum, tout, dmn, pidpath, kl, logpath,
322
+ ulogpath, ulim, uas, sid, mhost, mport, rtspath, ropts,
323
+ skelpath, mulnum, extpath, extpcs, mask);
324
+ ttservdel(g_serv);
325
+ if(extpcs) tclistdel(extpcs);
326
+ return rv;
327
+ }
328
+
329
+
330
+ /* print the usage and exit */
331
+ static void usage(void){
332
+ fprintf(stderr, "%s: the server of Tokyo Tyrant\n", g_progname);
333
+ fprintf(stderr, "\n");
334
+ fprintf(stderr, "usage:\n");
335
+ fprintf(stderr, " %s [-host name] [-port num] [-thnum num] [-tout num]"
336
+ " [-dmn] [-pid path] [-kl] [-log path] [-ld|-le] [-ulog path] [-ulim num] [-uas]"
337
+ " [-sid num] [-mhost name] [-mport num] [-rts path] [-rcc] [-skel name] [-mul num]"
338
+ " [-ext path] [-extpc name period] [-mask expr] [-unmask expr] [dbname]\n",
339
+ g_progname);
340
+ fprintf(stderr, "\n");
341
+ exit(1);
342
+ }
343
+
344
+
345
+ /* get the bit mask of a command name */
346
+ static uint64_t getcmdmask(const char *expr){
347
+ uint64_t mask = 0;
348
+ TCLIST *fields = tcstrsplit(expr, " ,");
349
+ for(int i = 0; i < tclistnum(fields); i++){
350
+ const char *name = tclistval2(fields, i);
351
+ if(tcstrifwm(name, "0x")){
352
+ mask |= tcatoih(name);
353
+ } else if(!tcstricmp(name, "put")){
354
+ mask |= 1ULL << TTSEQPUT;
355
+ } else if(!tcstricmp(name, "putkeep")){
356
+ mask |= 1ULL << TTSEQPUTKEEP;
357
+ } else if(!tcstricmp(name, "putcat")){
358
+ mask |= 1ULL << TTSEQPUTCAT;
359
+ } else if(!tcstricmp(name, "putshl")){
360
+ mask |= 1ULL << TTSEQPUTSHL;
361
+ } else if(!tcstricmp(name, "putnr")){
362
+ mask |= 1ULL << TTSEQPUTNR;
363
+ } else if(!tcstricmp(name, "out")){
364
+ mask |= 1ULL << TTSEQOUT;
365
+ } else if(!tcstricmp(name, "get")){
366
+ mask |= 1ULL << TTSEQGET;
367
+ } else if(!tcstricmp(name, "mget")){
368
+ mask |= 1ULL << TTSEQMGET;
369
+ } else if(!tcstricmp(name, "vsiz")){
370
+ mask |= 1ULL << TTSEQVSIZ;
371
+ } else if(!tcstricmp(name, "iterinit")){
372
+ mask |= 1ULL << TTSEQITERINIT;
373
+ } else if(!tcstricmp(name, "iternext")){
374
+ mask |= 1ULL << TTSEQITERNEXT;
375
+ } else if(!tcstricmp(name, "fwmkeys")){
376
+ mask |= 1ULL << TTSEQFWMKEYS;
377
+ } else if(!tcstricmp(name, "addint")){
378
+ mask |= 1ULL << TTSEQADDINT;
379
+ } else if(!tcstricmp(name, "adddouble")){
380
+ mask |= 1ULL << TTSEQADDDOUBLE;
381
+ } else if(!tcstricmp(name, "ext")){
382
+ mask |= 1ULL << TTSEQEXT;
383
+ } else if(!tcstricmp(name, "sync")){
384
+ mask |= 1ULL << TTSEQSYNC;
385
+ } else if(!tcstricmp(name, "optimize")){
386
+ mask |= 1ULL << TTSEQOPTIMIZE;
387
+ } else if(!tcstricmp(name, "vanish")){
388
+ mask |= 1ULL << TTSEQVANISH;
389
+ } else if(!tcstricmp(name, "copy")){
390
+ mask |= 1ULL << TTSEQCOPY;
391
+ } else if(!tcstricmp(name, "restore")){
392
+ mask |= 1ULL << TTSEQRESTORE;
393
+ } else if(!tcstricmp(name, "setmst")){
394
+ mask |= 1ULL << TTSEQSETMST;
395
+ } else if(!tcstricmp(name, "rnum")){
396
+ mask |= 1ULL << TTSEQRNUM;
397
+ } else if(!tcstricmp(name, "size")){
398
+ mask |= 1ULL << TTSEQSIZE;
399
+ } else if(!tcstricmp(name, "stat")){
400
+ mask |= 1ULL << TTSEQSTAT;
401
+ } else if(!tcstricmp(name, "misc")){
402
+ mask |= 1ULL << TTSEQMISC;
403
+ } else if(!tcstricmp(name, "repl")){
404
+ mask |= 1ULL << TTSEQREPL;
405
+ } else if(!tcstricmp(name, "slave")){
406
+ mask |= 1ULL << TTSEQSLAVE;
407
+ } else if(!tcstricmp(name, "all")){
408
+ mask |= UINT64_MAX;
409
+ } else if(!tcstricmp(name, "allorg")){
410
+ mask |= 1ULL << TTSEQALLORG;
411
+ } else if(!tcstricmp(name, "allmc")){
412
+ mask |= 1ULL << TTSEQALLMC;
413
+ } else if(!tcstricmp(name, "allhttp")){
414
+ mask |= 1ULL << TTSEQALLHTTP;
415
+ } else if(!tcstricmp(name, "allread")){
416
+ mask |= 1ULL << TTSEQALLREAD;
417
+ } else if(!tcstricmp(name, "allwrite")){
418
+ mask |= 1ULL << TTSEQALLWRITE;
419
+ } else if(!tcstricmp(name, "allmanage")){
420
+ mask |= 1ULL << TTSEQALLMANAGE;
421
+ }
422
+ }
423
+ tclistdel(fields);
424
+ return mask;
425
+ }
426
+
427
+
428
+ /* handle termination signals */
429
+ static void sigtermhandler(int signum){
430
+ if(signum == SIGHUP) g_restart = true;
431
+ ttservkill(g_serv);
432
+ }
433
+
434
+
435
+ /* handle child event signals */
436
+ static void sigchldhandler(int signum){
437
+ return;
438
+ }
439
+
440
+
441
+ /* perform the command */
442
+ static int proc(const char *dbname, const char *host, int port, int thnum, int tout,
443
+ bool dmn, const char *pidpath, bool kl, const char *logpath,
444
+ const char *ulogpath, uint64_t ulim, bool uas, uint32_t sid,
445
+ const char *mhost, int mport, const char *rtspath, int ropts,
446
+ const char *skelpath, int mulnum, const char *extpath, const TCLIST *extpcs,
447
+ uint64_t mask){
448
+ LOGARG larg;
449
+ larg.fd = 1;
450
+ ttservsetloghandler(g_serv, do_log, &larg);
451
+ if(dmn){
452
+ if(dbname && *dbname != '*' && *dbname != '+' && *dbname != MYPATHCHR)
453
+ ttservlog(g_serv, TTLOGINFO, "warning: dbname(%s) is not the absolute path", dbname);
454
+ if(port == 0 && host && *host != MYPATHCHR)
455
+ ttservlog(g_serv, TTLOGINFO, "warning: host(%s) is not the absolute path", host);
456
+ if(pidpath && *pidpath != MYPATHCHR)
457
+ ttservlog(g_serv, TTLOGINFO, "warning: pid(%s) is not the absolute path", pidpath);
458
+ if(logpath && *logpath != MYPATHCHR)
459
+ ttservlog(g_serv, TTLOGINFO, "warning: log(%s) is not the absolute path", logpath);
460
+ if(ulogpath && *ulogpath != MYPATHCHR)
461
+ ttservlog(g_serv, TTLOGINFO, "warning: ulog(%s) is not the absolute path", ulogpath);
462
+ if(mport == 0 && mhost && *mhost != MYPATHCHR)
463
+ ttservlog(g_serv, TTLOGINFO, "warning: mhost(%s) is not the absolute path", mhost);
464
+ if(mhost && rtspath && *rtspath != MYPATHCHR)
465
+ ttservlog(g_serv, TTLOGINFO, "warning: rts(%s) is not the absolute path", rtspath);
466
+ if(skelpath && strchr(skelpath, MYPATHCHR) && *skelpath != MYPATHCHR)
467
+ ttservlog(g_serv, TTLOGINFO, "warning: skel(%s) is not the absolute path", skelpath);
468
+ if(extpath && *extpath != MYPATHCHR)
469
+ ttservlog(g_serv, TTLOGINFO, "warning: ext(%s) is not the absolute path", extpath);
470
+ if(chdir("/") == -1){
471
+ ttservlog(g_serv, TTLOGERROR, "chdir failed");
472
+ return 1;
473
+ }
474
+ }
475
+ if(!skelpath && dbname && *dbname != '*' && *dbname != '+' && !strstr(dbname, ".tc"))
476
+ ttservlog(g_serv, TTLOGINFO, "warning: dbname(%s) has no suffix for database type", dbname);
477
+ struct stat sbuf;
478
+ if(ulogpath && (stat(ulogpath, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)))
479
+ ttservlog(g_serv, TTLOGINFO, "warning: ulog(%s) is not a directory", ulogpath);
480
+ if(pidpath){
481
+ char *numstr = tcreadfile(pidpath, -1, NULL);
482
+ if(numstr && kl){
483
+ int64_t pid = tcatoi(numstr);
484
+ tcfree(numstr);
485
+ ttservlog(g_serv, TTLOGINFO,
486
+ "warning: killing the process %lld with SIGTERM", (long long)pid);
487
+ if(kill(pid, SIGTERM) != 0) ttservlog(g_serv, TTLOGERROR, "kill failed");
488
+ int cnt = 0;
489
+ while(true){
490
+ tcsleep(0.1);
491
+ if((numstr = tcreadfile(pidpath, -1, NULL)) != NULL){
492
+ tcfree(numstr);
493
+ } else {
494
+ break;
495
+ }
496
+ if(++cnt >= 100){
497
+ ttservlog(g_serv, TTLOGINFO,
498
+ "warning: killing the process %lld with SIGKILL", (long long)pid);
499
+ if(kill(pid, SIGKILL) != 0) ttservlog(g_serv, TTLOGERROR, "kill failed");
500
+ unlink(pidpath);
501
+ break;
502
+ }
503
+ }
504
+ numstr = tcreadfile(pidpath, -1, NULL);
505
+ }
506
+ if(numstr){
507
+ int64_t pid = tcatoi(numstr);
508
+ tcfree(numstr);
509
+ ttservlog(g_serv, TTLOGERROR, "the process %lld may be already running", (long long)pid);
510
+ return 1;
511
+ }
512
+ }
513
+ if(sid > UINT16_MAX){
514
+ ttservlog(g_serv, TTLOGINFO,
515
+ "warning: the SID is ignored because it exceeds %d", UINT16_MAX);
516
+ sid = 0;
517
+ }
518
+ if(sid < 1){
519
+ if(ulogpath){
520
+ ttservlog(g_serv, TTLOGINFO,
521
+ "warning: update logging is omitted because the SID is not specified");
522
+ ulogpath = NULL;
523
+ }
524
+ if(mhost){
525
+ ttservlog(g_serv, TTLOGINFO,
526
+ "warning: replication is omitted because the SID is not specified");
527
+ mhost = NULL;
528
+ }
529
+ }
530
+ if(dmn && !ttdaemonize()){
531
+ ttservlog(g_serv, TTLOGERROR, "ttdaemonize failed");
532
+ return 1;
533
+ }
534
+ if(logpath){
535
+ int fd = open(logpath, O_WRONLY | O_APPEND | O_CREAT, 00644);
536
+ if(fd != -1){
537
+ larg.fd = fd;
538
+ } else {
539
+ ttservlog(g_serv, TTLOGERROR, "the log file %s could not be opened", logpath);
540
+ return 1;
541
+ }
542
+ }
543
+ int64_t pid = getpid();
544
+ ttservlog(g_serv, TTLOGSYSTEM, "--------- logging started [%lld] --------", (long long)pid);
545
+ if(pidpath){
546
+ char buf[32];
547
+ sprintf(buf, "%lld\n", (long long)pid);
548
+ if(!tcwritefile(pidpath, buf, strlen(buf))){
549
+ ttservlog(g_serv, TTLOGERROR, "tcwritefile failed");
550
+ return 1;
551
+ }
552
+ ttservlog(g_serv, TTLOGSYSTEM, "process ID configuration: path=%s pid=%lld",
553
+ pidpath, (long long)pid);
554
+ }
555
+ ttservlog(g_serv, TTLOGSYSTEM, "server configuration: host=%s port=%d",
556
+ host ? host : "(any)", port);
557
+ if(!ttservconf(g_serv, host, port)) return 1;
558
+ struct rlimit rlbuf;
559
+ memset(&rlbuf, 0, sizeof(rlbuf));
560
+ if(getrlimit(RLIMIT_NOFILE, &rlbuf) == 0 && rlbuf.rlim_cur != RLIM_INFINITY){
561
+ rlim_t min = rlbuf.rlim_cur;
562
+ for(rlim_t max = INT32_MAX; max > min; max /= 2){
563
+ rlbuf.rlim_cur = max;
564
+ rlbuf.rlim_max = max;
565
+ if(setrlimit(RLIMIT_NOFILE, &rlbuf) == 0) break;
566
+ }
567
+ } else {
568
+ ttservlog(g_serv, TTLOGERROR, "getrlimit failed");
569
+ }
570
+ memset(&rlbuf, 0, sizeof(rlbuf));
571
+ if(getrlimit(RLIMIT_NOFILE, &rlbuf) == 0){
572
+ ttservlog(g_serv, TTLOGSYSTEM, "maximum connection: %d", (int)rlbuf.rlim_cur);
573
+ } else {
574
+ ttservlog(g_serv, TTLOGERROR, "getrlimit failed");
575
+ }
576
+ bool err = false;
577
+ TCADB *adb = tcadbnew();
578
+ ADBSKEL skel;
579
+ memset(&skel, 0, sizeof(skel));
580
+ void *skellib = NULL;
581
+ if(skelpath){
582
+ ttservlog(g_serv, TTLOGSYSTEM, "skeleton database library: %s", skelpath);
583
+ skellib = dlopen(skelpath, RTLD_LAZY);
584
+ if(skellib){
585
+ void *initsym = dlsym(skellib, "initialize");
586
+ if(initsym){
587
+ bool (*initfunc)(ADBSKEL *);
588
+ memcpy(&initfunc, &initsym, sizeof(initsym));
589
+ if(initfunc(&skel)){
590
+ if(!tcadbsetskel(adb, &skel)){
591
+ if(skel.opq && skel.del) skel.del(skel.opq);
592
+ err = true;
593
+ ttservlog(g_serv, TTLOGERROR, "tcadbsetskel failed");
594
+ }
595
+ } else {
596
+ if(skel.opq && skel.del) skel.del(skel.opq);
597
+ err = true;
598
+ ttservlog(g_serv, TTLOGERROR, "initialize failed");
599
+ }
600
+ } else {
601
+ err = true;
602
+ ttservlog(g_serv, TTLOGERROR, "dlsym failed: %s", dlerror());
603
+ }
604
+ } else {
605
+ err = true;
606
+ ttservlog(g_serv, TTLOGERROR, "dlopen failed: %s", dlerror());
607
+ }
608
+ }
609
+ ttservlog(g_serv, TTLOGSYSTEM, "opening the database: %s", dbname);
610
+ if(mulnum > 0 && !tcadbsetskelmulti(adb, mulnum)){
611
+ err = true;
612
+ ttservlog(g_serv, TTLOGERROR, "tcadbsetskelmulti failed");
613
+ }
614
+ if(!tcadbopen(adb, dbname)){
615
+ err = true;
616
+ ttservlog(g_serv, TTLOGERROR, "tcadbopen failed");
617
+ }
618
+ TCULOG *ulog = tculognew();
619
+ if(ulogpath){
620
+ ttservlog(g_serv, TTLOGSYSTEM,
621
+ "update log configuration: path=%s limit=%llu async=%d sid=%d",
622
+ ulogpath, (unsigned long long)ulim, uas, sid);
623
+ if(uas && !tculogsetaio(ulog)){
624
+ err = true;
625
+ ttservlog(g_serv, TTLOGERROR, "tculogsetaio failed");
626
+ }
627
+ if(!tculogopen(ulog, ulogpath, ulim)){
628
+ err = true;
629
+ ttservlog(g_serv, TTLOGERROR, "tculogopen failed");
630
+ }
631
+ }
632
+ ttservtune(g_serv, thnum, tout);
633
+ if(mhost)
634
+ ttservlog(g_serv, TTLOGSYSTEM, "replication configuration: host=%s port=%d ropts=%d",
635
+ mhost, mport, ropts);
636
+ uint64_t *counts = tccalloc(sizeof(*counts), (TTSEQNUM) * thnum);
637
+ void *screxts[thnum];
638
+ TCMDB *scrstash = NULL;
639
+ TCMDB *scrlock = NULL;
640
+ pthread_mutex_t *scrlcks = NULL;
641
+ if(extpath){
642
+ ttservlog(g_serv, TTLOGSYSTEM, "scripting extension: %s", extpath);
643
+ scrstash = tcmdbnew2(STASHBNUM);
644
+ scrlock = tcmdbnew2(thnum * 2 + 1);
645
+ bool screrr = false;
646
+ for(int i = 0; i < thnum; i++){
647
+ screxts[i] = NULL;
648
+ }
649
+ for(int i = 0; i < thnum; i++){
650
+ screxts[i] = scrextnew(screxts, thnum, i, extpath, adb, ulog, sid, scrstash, scrlock,
651
+ do_log, &larg);
652
+ if(!screxts[i]) screrr = true;
653
+ }
654
+ if(screrr){
655
+ err = true;
656
+ ttservlog(g_serv, TTLOGERROR, "scrextnew failed");
657
+ }
658
+ } else {
659
+ for(int i = 0; i < thnum; i++){
660
+ screxts[i] = NULL;
661
+ }
662
+ }
663
+ if(mask != 0)
664
+ ttservlog(g_serv, TTLOGSYSTEM, "command bit mask: 0x%llx", (unsigned long long)mask);
665
+ REPLARG sarg;
666
+ snprintf(sarg.host, TTADDRBUFSIZ, "%s", mhost ? mhost : "");
667
+ sarg.port = mport;
668
+ sarg.rtspath = rtspath;
669
+ sarg.rts = 0;
670
+ sarg.opts = ropts;
671
+ sarg.adb = adb;
672
+ sarg.ulog = ulog;
673
+ sarg.sid = sid;
674
+ sarg.fail = false;
675
+ sarg.recon = false;
676
+ sarg.fatal = false;
677
+ sarg.mts = 0;
678
+ if(!(mask & (1ULL << TTSEQSLAVE))) ttservaddtimedhandler(g_serv, REPLPERIOD, do_slave, &sarg);
679
+ EXTPCARG *pcargs = NULL;
680
+ int pcnum = 0;
681
+ if(extpath && extpcs){
682
+ pcnum = tclistnum(extpcs) / 2;
683
+ pcargs = tcmalloc(sizeof(*pcargs) * pcnum);
684
+ for(int i = 0; i < pcnum; i++){
685
+ const char *name = tclistval2(extpcs, i * 2);
686
+ double period = tcatof(tclistval2(extpcs, i * 2 + 1));
687
+ EXTPCARG *pcarg = pcargs + i;
688
+ pcarg->name = name;
689
+ pcarg->adb = adb;
690
+ pcarg->ulog = ulog;
691
+ pcarg->sid = sid;
692
+ pcarg->sarg = &sarg;
693
+ pcarg->scrext = scrextnew(screxts, thnum, thnum + i, extpath, adb, ulog, sid,
694
+ scrstash, scrlock, do_log, &larg);
695
+ if(pcarg->scrext){
696
+ if(*name && period > 0) ttservaddtimedhandler(g_serv, period, do_extpc, pcarg);
697
+ } else {
698
+ err = true;
699
+ ttservlog(g_serv, TTLOGERROR, "scrextnew failed");
700
+ }
701
+ }
702
+ }
703
+ TASKARG targ;
704
+ targ.thnum = thnum;
705
+ targ.counts = counts;
706
+ targ.mask = mask;
707
+ targ.adb = adb;
708
+ targ.ulog = ulog;
709
+ targ.sid = sid;
710
+ targ.sarg = &sarg;
711
+ for(int i = 0; i < RECMTXNUM; i++){
712
+ if(pthread_mutex_init(targ.rmtxs + i, NULL) != 0)
713
+ ttservlog(g_serv, TTLOGERROR, "pthread_mutex_init failed");
714
+ }
715
+ targ.screxts = screxts;
716
+ ttservsettaskhandler(g_serv, do_task, &targ);
717
+ TERMARG karg;
718
+ karg.thnum = thnum;
719
+ karg.adb = adb;
720
+ karg.sarg = &sarg;
721
+ karg.screxts = screxts;
722
+ karg.pcargs = pcargs;
723
+ karg.pcnum = pcnum;
724
+ karg.err = false;
725
+ ttservsettermhandler(g_serv, do_term, &karg);
726
+ if(larg.fd != 1){
727
+ close(larg.fd);
728
+ larg.fd = 1;
729
+ }
730
+ do {
731
+ g_restart = false;
732
+ if(logpath){
733
+ int fd = open(logpath, O_WRONLY | O_APPEND | O_CREAT, 00644);
734
+ if(fd != -1){
735
+ larg.fd = fd;
736
+ } else {
737
+ err = true;
738
+ ttservlog(g_serv, TTLOGERROR, "open failed");
739
+ }
740
+ }
741
+ if(signal(SIGTERM, sigtermhandler) == SIG_ERR || signal(SIGINT, sigtermhandler) == SIG_ERR ||
742
+ signal(SIGHUP, sigtermhandler) == SIG_ERR || signal(SIGPIPE, SIG_IGN) == SIG_ERR ||
743
+ signal(SIGCHLD, sigchldhandler) == SIG_ERR){
744
+ err = true;
745
+ ttservlog(g_serv, TTLOGERROR, "signal failed");
746
+ }
747
+ if(!ttservstart(g_serv)) err = true;
748
+ } while(g_restart);
749
+ if(karg.err) err = true;
750
+ if(pcargs){
751
+ for(int i = 0; i < pcnum; i++){
752
+ EXTPCARG *pcarg = pcargs + i;
753
+ if(!pcarg->scrext) continue;
754
+ if(!scrextdel(pcarg->scrext)){
755
+ err = true;
756
+ ttservlog(g_serv, TTLOGERROR, "scrextdel failed");
757
+ }
758
+ }
759
+ tcfree(pcargs);
760
+ }
761
+ for(int i = 0; i < RECMTXNUM; i++){
762
+ if(pthread_mutex_destroy(targ.rmtxs + i) != 0)
763
+ ttservlog(g_serv, TTLOGERROR, "pthread_mutex_destroy failed");
764
+ }
765
+ for(int i = 0; i < thnum; i++){
766
+ if(!screxts[i]) continue;
767
+ if(!scrextdel(screxts[i])){
768
+ err = true;
769
+ ttservlog(g_serv, TTLOGERROR, "scrextdel failed");
770
+ }
771
+ }
772
+ if(scrlcks){
773
+ for(int i = 0; i < RECMTXNUM; i++){
774
+ if(pthread_mutex_destroy(scrlcks + i) != 0)
775
+ ttservlog(g_serv, TTLOGERROR, "pthread_mutex_destroy failed");
776
+ }
777
+ tcfree(scrlcks);
778
+ }
779
+ if(scrlock) tcmdbdel(scrlock);
780
+ if(scrstash) tcmdbdel(scrstash);
781
+ tcfree(counts);
782
+ if(ulogpath && !tculogclose(ulog)){
783
+ err = true;
784
+ ttservlog(g_serv, TTLOGERROR, "tculogclose failed");
785
+ }
786
+ tculogdel(ulog);
787
+ if(skellib && dlclose(skellib) != 0){
788
+ err = true;
789
+ ttservlog(g_serv, TTLOGERROR, "dlclose failed");
790
+ }
791
+ tcadbdel(adb);
792
+ if(pidpath && unlink(pidpath) != 0){
793
+ err = true;
794
+ ttservlog(g_serv, TTLOGERROR, "unlink failed");
795
+ }
796
+ ttservlog(g_serv, TTLOGSYSTEM, "--------- logging finished [%d] --------", pid);
797
+ if(logpath && close(larg.fd) == -1) err = true;
798
+ return err ? 1 : 0;
799
+ }
800
+
801
+
802
+ /* handle a log message */
803
+ static void do_log(int level, const char *msg, void *opq){
804
+ if(level < g_loglevel) return;
805
+ LOGARG *arg = (LOGARG *)opq;
806
+ char date[48];
807
+ tcdatestrwww(INT64_MAX, INT_MAX, date);
808
+ const char *lvstr = "unknown";
809
+ switch(level){
810
+ case TTLOGDEBUG: lvstr = "DEBUG"; break;
811
+ case TTLOGINFO: lvstr = "INFO"; break;
812
+ case TTLOGERROR: lvstr = "ERROR"; break;
813
+ case TTLOGSYSTEM: lvstr = "SYSTEM"; break;
814
+ }
815
+ char buf[LINEBUFSIZ];
816
+ int len = snprintf(buf, LINEBUFSIZ, "%s\t%s\t%s\n", date, lvstr, msg);
817
+ if(len >= LINEBUFSIZ){
818
+ buf[LINEBUFSIZ-1] = '\n';
819
+ len = LINEBUFSIZ;
820
+ }
821
+ tcwrite(arg ? arg->fd : 1, buf, len);
822
+ }
823
+
824
+
825
+ /* replicate master data */
826
+ static void do_slave(void *opq){
827
+ REPLARG *arg = opq;
828
+ TCADB *adb = arg->adb;
829
+ TCULOG *ulog = arg->ulog;
830
+ uint32_t sid = arg->sid;
831
+ if(arg->fatal) return;
832
+ if(arg->host[0] == '\0' || arg->port < 1) return;
833
+ if(arg->mts > 0){
834
+ char rtsbuf[NUMBUFSIZ];
835
+ int len = sprintf(rtsbuf, "%llu\n", (unsigned long long)arg->mts);
836
+ if(!tcwritefile(arg->rtspath, rtsbuf, len))
837
+ ttservlog(g_serv, TTLOGERROR, "do_slave: tcwritefile failed");
838
+ arg->mts = 0;
839
+ }
840
+ int rtsfd = open(arg->rtspath, O_RDWR | O_CREAT, 00644);
841
+ if(rtsfd == -1){
842
+ ttservlog(g_serv, TTLOGERROR, "do_slave: open failed");
843
+ return;
844
+ }
845
+ struct stat sbuf;
846
+ if(fstat(rtsfd, &sbuf) == -1){
847
+ ttservlog(g_serv, TTLOGERROR, "do_slave: stat failed");
848
+ close(rtsfd);
849
+ return;
850
+ }
851
+ char rtsbuf[NUMBUFSIZ];
852
+ memset(rtsbuf, 0, NUMBUFSIZ);
853
+ arg->rts = 0;
854
+ if(sbuf.st_size > 0 && tcread(rtsfd, rtsbuf, tclmin(NUMBUFSIZ - 1, sbuf.st_size)))
855
+ arg->rts = tcatoi(rtsbuf);
856
+ TCREPL *repl = tcreplnew();
857
+ pthread_cleanup_push((void (*)(void *))tcrepldel, repl);
858
+ if(tcreplopen(repl, arg->host, arg->port, arg->rts + 1, sid)){
859
+ ttservlog(g_serv, TTLOGINFO, "replicating from sid=%u (%s:%d) after %llu",
860
+ repl->mid, arg->host, arg->port, (unsigned long long)arg->rts);
861
+ arg->fail = false;
862
+ arg->recon = false;
863
+ bool err = false;
864
+ uint32_t rsid;
865
+ const char *rbuf;
866
+ int rsiz;
867
+ uint64_t rts;
868
+ while(!err && !ttserviskilled(g_serv) && !arg->recon &&
869
+ (rbuf = tcreplread(repl, &rsiz, &rts, &rsid)) != NULL){
870
+ if(rsiz < 1) continue;
871
+ bool cc;
872
+ if(!tculogadbredo(adb, rbuf, rsiz, ulog, rsid, repl->mid, &cc)){
873
+ err = true;
874
+ ttservlog(g_serv, TTLOGERROR, "do_slave: tculogadbredo failed");
875
+ } else if(!cc){
876
+ if(arg->opts & RDBROCHKCON){
877
+ err = true;
878
+ arg->fatal = true;
879
+ ttservlog(g_serv, TTLOGERROR, "do_slave: detected inconsistency");
880
+ } else {
881
+ ttservlog(g_serv, TTLOGINFO, "do_slave: detected inconsistency");
882
+ }
883
+ }
884
+ if(lseek(rtsfd, 0, SEEK_SET) != -1){
885
+ int len = sprintf(rtsbuf, "%llu\n", (unsigned long long)rts);
886
+ if(tcwrite(rtsfd, rtsbuf, len)){
887
+ arg->rts = rts;
888
+ } else {
889
+ err = true;
890
+ ttservlog(g_serv, TTLOGERROR, "do_slave: tcwrite failed");
891
+ }
892
+ } else {
893
+ err = true;
894
+ ttservlog(g_serv, TTLOGERROR, "do_slave: lseek failed");
895
+ }
896
+ }
897
+ tcreplclose(repl);
898
+ ttservlog(g_serv, TTLOGINFO, "replication finished");
899
+ } else {
900
+ if(!arg->fail) ttservlog(g_serv, TTLOGERROR, "do_slave: tcreplopen failed");
901
+ arg->fail = true;
902
+ }
903
+ pthread_cleanup_pop(1);
904
+ if(close(rtsfd) == -1) ttservlog(g_serv, TTLOGERROR, "do_slave: close failed");
905
+ }
906
+
907
+
908
+ /* perform an extension command */
909
+ static void do_extpc(void *opq){
910
+ EXTPCARG *arg = (EXTPCARG *)opq;
911
+ const char *name = arg->name;
912
+ void *scr = arg->scrext;
913
+ int xsiz;
914
+ char *xbuf = scrextcallmethod(scr, name, "", 0, "", 0, &xsiz);
915
+ tcfree(xbuf);
916
+ }
917
+
918
+
919
+ /* handle a task and dispatch it */
920
+ static void do_task(TTSOCK *sock, void *opq, TTREQ *req){
921
+ TASKARG *arg = (TASKARG *)opq;
922
+ int c = ttsockgetc(sock);
923
+ if(c == TTMAGICNUM){
924
+ switch(ttsockgetc(sock)){
925
+ case TTCMDPUT:
926
+ do_put(sock, arg, req);
927
+ break;
928
+ case TTCMDPUTKEEP:
929
+ do_putkeep(sock, arg, req);
930
+ break;
931
+ case TTCMDPUTCAT:
932
+ do_putcat(sock, arg, req);
933
+ break;
934
+ case TTCMDPUTSHL:
935
+ do_putshl(sock, arg, req);
936
+ break;
937
+ case TTCMDPUTNR:
938
+ do_putnr(sock, arg, req);
939
+ break;
940
+ case TTCMDOUT:
941
+ do_out(sock, arg, req);
942
+ break;
943
+ case TTCMDGET:
944
+ do_get(sock, arg, req);
945
+ break;
946
+ case TTCMDMGET:
947
+ do_mget(sock, arg, req);
948
+ break;
949
+ case TTCMDVSIZ:
950
+ do_vsiz(sock, arg, req);
951
+ break;
952
+ case TTCMDITERINIT:
953
+ do_iterinit(sock, arg, req);
954
+ break;
955
+ case TTCMDITERNEXT:
956
+ do_iternext(sock, arg, req);
957
+ break;
958
+ case TTCMDFWMKEYS:
959
+ do_fwmkeys(sock, arg, req);
960
+ break;
961
+ case TTCMDADDINT:
962
+ do_addint(sock, arg, req);
963
+ break;
964
+ case TTCMDADDDOUBLE:
965
+ do_adddouble(sock, arg, req);
966
+ break;
967
+ case TTCMDEXT:
968
+ do_ext(sock, arg, req);
969
+ break;
970
+ case TTCMDSYNC:
971
+ do_sync(sock, arg, req);
972
+ break;
973
+ case TTCMDOPTIMIZE:
974
+ do_optimize(sock, arg, req);
975
+ break;
976
+ case TTCMDVANISH:
977
+ do_vanish(sock, arg, req);
978
+ break;
979
+ case TTCMDCOPY:
980
+ do_copy(sock, arg, req);
981
+ break;
982
+ case TTCMDRESTORE:
983
+ do_restore(sock, arg, req);
984
+ break;
985
+ case TTCMDSETMST:
986
+ do_setmst(sock, arg, req);
987
+ break;
988
+ case TTCMDRNUM:
989
+ do_rnum(sock, arg, req);
990
+ break;
991
+ case TTCMDSIZE:
992
+ do_size(sock, arg, req);
993
+ break;
994
+ case TTCMDSTAT:
995
+ do_stat(sock, arg, req);
996
+ break;
997
+ case TTCMDMISC:
998
+ do_misc(sock, arg, req);
999
+ break;
1000
+ case TTCMDREPL:
1001
+ do_repl(sock, arg, req);
1002
+ break;
1003
+ default:
1004
+ ttservlog(g_serv, TTLOGINFO, "unknown command");
1005
+ break;
1006
+ }
1007
+ } else {
1008
+ ttsockungetc(sock, c);
1009
+ char *line = ttsockgets2(sock);
1010
+ if(line){
1011
+ pthread_cleanup_push(tcfree, line);
1012
+ int tnum;
1013
+ char **tokens = tokenize(line, &tnum);
1014
+ pthread_cleanup_push(tcfree, tokens);
1015
+ if(tnum > 0){
1016
+ const char *cmd = tokens[0];
1017
+ if(!strcmp(cmd, "set")){
1018
+ do_mc_set(sock, arg, req, tokens, tnum);
1019
+ } else if(!strcmp(cmd, "add")){
1020
+ do_mc_add(sock, arg, req, tokens, tnum);
1021
+ } else if(!strcmp(cmd, "replace")){
1022
+ do_mc_replace(sock, arg, req, tokens, tnum);
1023
+ } else if(!strcmp(cmd, "append")){
1024
+ do_mc_append(sock, arg, req, tokens, tnum);
1025
+ } else if(!strcmp(cmd, "prepend")){
1026
+ do_mc_prepend(sock, arg, req, tokens, tnum);
1027
+ } else if(!strcmp(cmd, "get") || !strcmp(cmd, "gets")){
1028
+ do_mc_get(sock, arg, req, tokens, tnum);
1029
+ } else if(!strcmp(cmd, "delete")){
1030
+ do_mc_delete(sock, arg, req, tokens, tnum);
1031
+ } else if(!strcmp(cmd, "incr")){
1032
+ do_mc_incr(sock, arg, req, tokens, tnum);
1033
+ } else if(!strcmp(cmd, "decr")){
1034
+ do_mc_decr(sock, arg, req, tokens, tnum);
1035
+ } else if(!strcmp(cmd, "stats")){
1036
+ do_mc_stats(sock, arg, req, tokens, tnum);
1037
+ } else if(!strcmp(cmd, "flush_all")){
1038
+ do_mc_flushall(sock, arg, req, tokens, tnum);
1039
+ } else if(!strcmp(cmd, "version")){
1040
+ do_mc_version(sock, arg, req, tokens, tnum);
1041
+ } else if(!strcmp(cmd, "quit")){
1042
+ do_mc_quit(sock, arg, req, tokens, tnum);
1043
+ } else if(tnum > 2 && tcstrfwm(tokens[2], "HTTP/1.")){
1044
+ int ver = tcatoi(tokens[2] + 7);
1045
+ const char *uri = tokens[1];
1046
+ if(tcstrifwm(uri, "http://")){
1047
+ const char *pv = strchr(uri + 7, '/');
1048
+ if(pv) uri = pv;
1049
+ }
1050
+ if(!strcmp(cmd, "GET")){
1051
+ do_http_get(sock, arg, req, ver, uri);
1052
+ } else if(!strcmp(cmd, "HEAD")){
1053
+ do_http_head(sock, arg, req, ver, uri);
1054
+ } else if(!strcmp(cmd, "PUT")){
1055
+ do_http_put(sock, arg, req, ver, uri);
1056
+ } else if(!strcmp(cmd, "POST")){
1057
+ do_http_post(sock, arg, req, ver, uri);
1058
+ } else if(!strcmp(cmd, "DELETE")){
1059
+ do_http_delete(sock, arg, req, ver, uri);
1060
+ } else if(!strcmp(cmd, "OPTIONS")){
1061
+ do_http_options(sock, arg, req, ver, uri);
1062
+ }
1063
+ }
1064
+ }
1065
+ pthread_cleanup_pop(1);
1066
+ pthread_cleanup_pop(1);
1067
+ }
1068
+ }
1069
+ }
1070
+
1071
+
1072
+ /* tokenize a string */
1073
+ static char **tokenize(char *str, int *np){
1074
+ int anum = TOKENUNIT;
1075
+ char **tokens = tcmalloc(sizeof(*tokens) * anum);
1076
+ int tnum = 0;
1077
+ while(*str == ' ' || *str == '\t'){
1078
+ str++;
1079
+ }
1080
+ while(*str != '\0'){
1081
+ if(tnum >= anum){
1082
+ anum *= 2;
1083
+ tokens = tcrealloc(tokens, sizeof(*tokens) * anum);
1084
+ }
1085
+ tokens[tnum++] = str;
1086
+ while(*str != '\0' && *str != ' ' && *str != '\t'){
1087
+ str++;
1088
+ }
1089
+ while(*str == ' ' || *str == '\t'){
1090
+ *(str++) = '\0';
1091
+ }
1092
+ }
1093
+ *np = tnum;
1094
+ return tokens;
1095
+ }
1096
+
1097
+
1098
+ /* get the mutex index of a record */
1099
+ static uint32_t recmtxidx(const char *kbuf, int ksiz){
1100
+ uint32_t hash = 725;
1101
+ while(ksiz--){
1102
+ hash = hash * 29 + *(uint8_t *)kbuf++;
1103
+ }
1104
+ return hash % RECMTXNUM;
1105
+ }
1106
+
1107
+
1108
+ /* get the summation of status information of a command */
1109
+ static uint64_t sumstat(TASKARG *arg, int seq){
1110
+ int thnum = arg->thnum;
1111
+ uint64_t *counts = arg->counts;
1112
+ uint64_t sum = 0;
1113
+ for(int i = 0; i < thnum; i++){
1114
+ sum += counts[TTSEQNUM*i+seq];
1115
+ }
1116
+ return sum;
1117
+ }
1118
+
1119
+
1120
+ /* handle the put command */
1121
+ static void do_put(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1122
+ ttservlog(g_serv, TTLOGDEBUG, "doing put command");
1123
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
1124
+ uint64_t mask = arg->mask;
1125
+ TCADB *adb = arg->adb;
1126
+ TCULOG *ulog = arg->ulog;
1127
+ uint32_t sid = arg->sid;
1128
+ int ksiz = ttsockgetint32(sock);
1129
+ int vsiz = ttsockgetint32(sock);
1130
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ){
1131
+ ttservlog(g_serv, TTLOGINFO, "do_put: invalid parameters");
1132
+ return;
1133
+ }
1134
+ int rsiz = ksiz + vsiz;
1135
+ char stack[TTIOBUFSIZ];
1136
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1137
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1138
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1139
+ uint8_t code = 0;
1140
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1141
+ code = 1;
1142
+ ttservlog(g_serv, TTLOGINFO, "do_put: forbidden");
1143
+ } else if(!tculogadbput(ulog, sid, 0, adb, buf, ksiz, buf + ksiz, vsiz)){
1144
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
1145
+ code = 1;
1146
+ ttservlog(g_serv, TTLOGERROR, "do_put: operation failed");
1147
+ }
1148
+ if(ttsocksend(sock, &code, sizeof(code))){
1149
+ req->keep = true;
1150
+ } else {
1151
+ ttservlog(g_serv, TTLOGINFO, "do_put: response failed");
1152
+ }
1153
+ } else {
1154
+ ttservlog(g_serv, TTLOGINFO, "do_put: invalid entity");
1155
+ }
1156
+ pthread_cleanup_pop(1);
1157
+ }
1158
+
1159
+
1160
+ /* handle the putkeep command */
1161
+ static void do_putkeep(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1162
+ ttservlog(g_serv, TTLOGDEBUG, "doing putkeep command");
1163
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTKEEP]++;
1164
+ uint64_t mask = arg->mask;
1165
+ TCADB *adb = arg->adb;
1166
+ TCULOG *ulog = arg->ulog;
1167
+ uint32_t sid = arg->sid;
1168
+ int ksiz = ttsockgetint32(sock);
1169
+ int vsiz = ttsockgetint32(sock);
1170
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ){
1171
+ ttservlog(g_serv, TTLOGINFO, "do_putkeep: invalid parameters");
1172
+ return;
1173
+ }
1174
+ int rsiz = ksiz + vsiz;
1175
+ char stack[TTIOBUFSIZ];
1176
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1177
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1178
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1179
+ uint8_t code = 0;
1180
+ if(mask & ((1ULL << TTSEQPUTKEEP) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1181
+ code = 1;
1182
+ ttservlog(g_serv, TTLOGINFO, "do_putkeep: forbidden");
1183
+ } else if(!tculogadbputkeep(ulog, sid, 0, adb, buf, ksiz, buf + ksiz, vsiz)){
1184
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
1185
+ code = 1;
1186
+ }
1187
+ if(ttsocksend(sock, &code, sizeof(code))){
1188
+ req->keep = true;
1189
+ } else {
1190
+ ttservlog(g_serv, TTLOGINFO, "do_putkeep: response failed");
1191
+ }
1192
+ } else {
1193
+ ttservlog(g_serv, TTLOGINFO, "do_putkeep: invalid entity");
1194
+ }
1195
+ pthread_cleanup_pop(1);
1196
+ }
1197
+
1198
+
1199
+ /* handle the putcat command */
1200
+ static void do_putcat(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1201
+ ttservlog(g_serv, TTLOGDEBUG, "doing putcat command");
1202
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTCAT]++;
1203
+ uint64_t mask = arg->mask;
1204
+ TCADB *adb = arg->adb;
1205
+ TCULOG *ulog = arg->ulog;
1206
+ uint32_t sid = arg->sid;
1207
+ int ksiz = ttsockgetint32(sock);
1208
+ int vsiz = ttsockgetint32(sock);
1209
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ){
1210
+ ttservlog(g_serv, TTLOGINFO, "do_putcat: invalid parameters");
1211
+ return;
1212
+ }
1213
+ int rsiz = ksiz + vsiz;
1214
+ char stack[TTIOBUFSIZ];
1215
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1216
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1217
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1218
+ uint8_t code = 0;
1219
+ if(mask & ((1ULL << TTSEQPUTCAT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1220
+ code = 1;
1221
+ ttservlog(g_serv, TTLOGINFO, "do_putcat: forbidden");
1222
+ } else if(!tculogadbputcat(ulog, sid, 0, adb, buf, ksiz, buf + ksiz, vsiz)){
1223
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
1224
+ code = 1;
1225
+ ttservlog(g_serv, TTLOGERROR, "do_putcat: operation failed");
1226
+ }
1227
+ if(ttsocksend(sock, &code, sizeof(code))){
1228
+ req->keep = true;
1229
+ } else {
1230
+ ttservlog(g_serv, TTLOGINFO, "do_putcat: response failed");
1231
+ }
1232
+ } else {
1233
+ ttservlog(g_serv, TTLOGINFO, "do_putcat: invalid entity");
1234
+ }
1235
+ pthread_cleanup_pop(1);
1236
+ }
1237
+
1238
+
1239
+ /* handle the putshl command */
1240
+ static void do_putshl(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1241
+ ttservlog(g_serv, TTLOGDEBUG, "doing putshl command");
1242
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTSHL]++;
1243
+ uint64_t mask = arg->mask;
1244
+ TCADB *adb = arg->adb;
1245
+ TCULOG *ulog = arg->ulog;
1246
+ uint32_t sid = arg->sid;
1247
+ int ksiz = ttsockgetint32(sock);
1248
+ int vsiz = ttsockgetint32(sock);
1249
+ int width = ttsockgetint32(sock);
1250
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ ||
1251
+ width < 0){
1252
+ ttservlog(g_serv, TTLOGINFO, "do_putshl: invalid parameters");
1253
+ return;
1254
+ }
1255
+ int rsiz = ksiz + vsiz;
1256
+ char stack[TTIOBUFSIZ];
1257
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1258
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1259
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1260
+ uint8_t code = 0;
1261
+ if(mask & ((1ULL << TTSEQPUTSHL) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1262
+ code = 1;
1263
+ ttservlog(g_serv, TTLOGINFO, "do_putshl: forbidden");
1264
+ } else if(!tculogadbputshl(ulog, sid, 0, adb, buf, ksiz, buf + ksiz, vsiz, width)){
1265
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
1266
+ code = 1;
1267
+ ttservlog(g_serv, TTLOGERROR, "do_putshl: operation failed");
1268
+ }
1269
+ if(ttsocksend(sock, &code, sizeof(code))){
1270
+ req->keep = true;
1271
+ } else {
1272
+ ttservlog(g_serv, TTLOGINFO, "do_putshl: response failed");
1273
+ }
1274
+ } else {
1275
+ ttservlog(g_serv, TTLOGINFO, "do_putshl: invalid entity");
1276
+ }
1277
+ pthread_cleanup_pop(1);
1278
+ }
1279
+
1280
+
1281
+ /* handle the putnr command */
1282
+ static void do_putnr(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1283
+ ttservlog(g_serv, TTLOGDEBUG, "doing putnr command");
1284
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTNR]++;
1285
+ uint64_t mask = arg->mask;
1286
+ TCADB *adb = arg->adb;
1287
+ TCULOG *ulog = arg->ulog;
1288
+ uint32_t sid = arg->sid;
1289
+ int ksiz = ttsockgetint32(sock);
1290
+ int vsiz = ttsockgetint32(sock);
1291
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ){
1292
+ ttservlog(g_serv, TTLOGINFO, "do_putnr: invalid parameters");
1293
+ return;
1294
+ }
1295
+ int rsiz = ksiz + vsiz;
1296
+ char stack[TTIOBUFSIZ];
1297
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1298
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1299
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1300
+ uint8_t code = 0;
1301
+ if(mask & ((1ULL << TTSEQPUTNR) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1302
+ code = 1;
1303
+ ttservlog(g_serv, TTLOGINFO, "do_putnr: forbidden");
1304
+ } else if(!tculogadbput(ulog, sid, 0, adb, buf, ksiz, buf + ksiz, vsiz)){
1305
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
1306
+ code = 1;
1307
+ ttservlog(g_serv, TTLOGERROR, "do_putnr: operation failed");
1308
+ }
1309
+ req->keep = true;
1310
+ } else {
1311
+ ttservlog(g_serv, TTLOGINFO, "do_putnr: invalid entity");
1312
+ }
1313
+ pthread_cleanup_pop(1);
1314
+ }
1315
+
1316
+
1317
+ /* handle the out command */
1318
+ static void do_out(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1319
+ ttservlog(g_serv, TTLOGDEBUG, "doing out command");
1320
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUT]++;
1321
+ uint64_t mask = arg->mask;
1322
+ TCADB *adb = arg->adb;
1323
+ TCULOG *ulog = arg->ulog;
1324
+ uint32_t sid = arg->sid;
1325
+ int ksiz = ttsockgetint32(sock);
1326
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ){
1327
+ ttservlog(g_serv, TTLOGINFO, "do_out: invalid parameters");
1328
+ return;
1329
+ }
1330
+ char stack[TTIOBUFSIZ];
1331
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1332
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1333
+ if(ttsockrecv(sock, buf, ksiz) && !ttsockcheckend(sock)){
1334
+ uint8_t code = 0;
1335
+ if(mask & ((1ULL << TTSEQOUT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1336
+ code = 1;
1337
+ ttservlog(g_serv, TTLOGINFO, "do_out: forbidden");
1338
+ } else if(!tculogadbout(ulog, sid, 0, adb, buf, ksiz)){
1339
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUTMISS]++;
1340
+ code = 1;
1341
+ }
1342
+ if(ttsocksend(sock, &code, sizeof(code))){
1343
+ req->keep = true;
1344
+ } else {
1345
+ ttservlog(g_serv, TTLOGINFO, "do_out: response failed");
1346
+ }
1347
+ } else {
1348
+ ttservlog(g_serv, TTLOGINFO, "do_out: invalid entity");
1349
+ }
1350
+ pthread_cleanup_pop(1);
1351
+ }
1352
+
1353
+
1354
+ /* handle the get command */
1355
+ static void do_get(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1356
+ ttservlog(g_serv, TTLOGDEBUG, "doing get command");
1357
+ arg->counts[TTSEQNUM*req->idx+TTSEQGET]++;
1358
+ uint64_t mask = arg->mask;
1359
+ TCADB *adb = arg->adb;
1360
+ int ksiz = ttsockgetint32(sock);
1361
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ){
1362
+ ttservlog(g_serv, TTLOGINFO, "do_get: invalid parameters");
1363
+ return;
1364
+ }
1365
+ char stack[TTIOBUFSIZ];
1366
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1367
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1368
+ if(ttsockrecv(sock, buf, ksiz) && !ttsockcheckend(sock)){
1369
+ char *vbuf;
1370
+ int vsiz;
1371
+ if(mask & ((1ULL << TTSEQGET) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1372
+ vbuf = NULL;
1373
+ vsiz = 0;
1374
+ ttservlog(g_serv, TTLOGINFO, "do_get: forbidden");
1375
+ } else {
1376
+ vbuf = tcadbget(adb, buf, ksiz, &vsiz);
1377
+ }
1378
+ if(vbuf){
1379
+ int rsiz = vsiz + sizeof(uint8_t) + sizeof(uint32_t);
1380
+ char *rbuf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz);
1381
+ pthread_cleanup_push(free, (rbuf == stack) ? NULL : rbuf);
1382
+ *rbuf = 0;
1383
+ uint32_t num;
1384
+ num = TTHTONL((uint32_t)vsiz);
1385
+ memcpy(rbuf + sizeof(uint8_t), &num, sizeof(uint32_t));
1386
+ memcpy(rbuf + sizeof(uint8_t) + sizeof(uint32_t), vbuf, vsiz);
1387
+ tcfree(vbuf);
1388
+ if(ttsocksend(sock, rbuf, rsiz)){
1389
+ req->keep = true;
1390
+ } else {
1391
+ ttservlog(g_serv, TTLOGINFO, "do_get: response failed");
1392
+ }
1393
+ pthread_cleanup_pop(1);
1394
+ } else {
1395
+ arg->counts[TTSEQNUM*req->idx+TTSEQGETMISS]++;
1396
+ uint8_t code = 1;
1397
+ if(ttsocksend(sock, &code, sizeof(code))){
1398
+ req->keep = true;
1399
+ } else {
1400
+ ttservlog(g_serv, TTLOGINFO, "do_get: response failed");
1401
+ }
1402
+ }
1403
+ } else {
1404
+ ttservlog(g_serv, TTLOGINFO, "do_get: invalid entity");
1405
+ }
1406
+ pthread_cleanup_pop(1);
1407
+ }
1408
+
1409
+
1410
+ /* handle the mget command */
1411
+ static void do_mget(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1412
+ ttservlog(g_serv, TTLOGDEBUG, "doing mget command");
1413
+ arg->counts[TTSEQNUM*req->idx+TTSEQMGET]++;
1414
+ uint64_t mask = arg->mask;
1415
+ TCADB *adb = arg->adb;
1416
+ int rnum = ttsockgetint32(sock);
1417
+ if(ttsockcheckend(sock) || rnum < 0 || rnum > MAXARGNUM){
1418
+ ttservlog(g_serv, TTLOGINFO, "do_mget: invalid parameters");
1419
+ return;
1420
+ }
1421
+ TCLIST *keys = tclistnew2(rnum);
1422
+ pthread_cleanup_push((void (*)(void *))tclistdel, keys);
1423
+ char stack[TTIOBUFSIZ];
1424
+ for(int i = 0; i < rnum; i++){
1425
+ int ksiz = ttsockgetint32(sock);
1426
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ) break;
1427
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1428
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1429
+ if(ttsockrecv(sock, buf, ksiz)) tclistpush(keys, buf, ksiz);
1430
+ pthread_cleanup_pop(1);
1431
+ }
1432
+ if(!ttsockcheckend(sock)){
1433
+ TCXSTR *xstr = tcxstrnew();
1434
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
1435
+ uint8_t code = 0;
1436
+ tcxstrcat(xstr, &code, sizeof(code));
1437
+ uint32_t num = 0;
1438
+ tcxstrcat(xstr, &num, sizeof(num));
1439
+ rnum = 0;
1440
+ if(mask & ((1ULL << TTSEQMGET) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1441
+ ttservlog(g_serv, TTLOGINFO, "do_mget: forbidden");
1442
+ } else {
1443
+ for(int i = 0; i < tclistnum(keys); i++){
1444
+ int ksiz;
1445
+ const char *kbuf = tclistval(keys, i, &ksiz);
1446
+ int vsiz;
1447
+ char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
1448
+ if(vbuf){
1449
+ num = TTHTONL((uint32_t)ksiz);
1450
+ tcxstrcat(xstr, &num, sizeof(num));
1451
+ num = TTHTONL((uint32_t)vsiz);
1452
+ tcxstrcat(xstr, &num, sizeof(num));
1453
+ tcxstrcat(xstr, kbuf, ksiz);
1454
+ tcxstrcat(xstr, vbuf, vsiz);
1455
+ tcfree(vbuf);
1456
+ rnum++;
1457
+ }
1458
+ }
1459
+ }
1460
+ num = TTHTONL((uint32_t)rnum);
1461
+ memcpy((char *)tcxstrptr(xstr) + sizeof(code), &num, sizeof(num));
1462
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
1463
+ req->keep = true;
1464
+ } else {
1465
+ ttservlog(g_serv, TTLOGINFO, "do_mget: response failed");
1466
+ }
1467
+ pthread_cleanup_pop(1);
1468
+ } else {
1469
+ ttservlog(g_serv, TTLOGINFO, "do_mget: invalid entity");
1470
+ }
1471
+ pthread_cleanup_pop(1);
1472
+ }
1473
+
1474
+
1475
+ /* handle the vsiz command */
1476
+ static void do_vsiz(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1477
+ ttservlog(g_serv, TTLOGDEBUG, "doing vsiz command");
1478
+ arg->counts[TTSEQNUM*req->idx+TTSEQVSIZ]++;
1479
+ uint64_t mask = arg->mask;
1480
+ TCADB *adb = arg->adb;
1481
+ int ksiz = ttsockgetint32(sock);
1482
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ){
1483
+ ttservlog(g_serv, TTLOGINFO, "do_vsiz: invalid parameters");
1484
+ return;
1485
+ }
1486
+ char stack[TTIOBUFSIZ];
1487
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1488
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1489
+ if(ttsockrecv(sock, buf, ksiz) && !ttsockcheckend(sock)){
1490
+ int vsiz;
1491
+ if(mask & ((1ULL << TTSEQVSIZ) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1492
+ vsiz = -1;
1493
+ ttservlog(g_serv, TTLOGINFO, "do_vsiz: forbidden");
1494
+ } else {
1495
+ vsiz = tcadbvsiz(adb, buf, ksiz);
1496
+ }
1497
+ if(vsiz >= 0){
1498
+ *stack = 0;
1499
+ uint32_t num;
1500
+ num = TTHTONL((uint32_t)vsiz);
1501
+ memcpy(stack + sizeof(uint8_t), &num, sizeof(uint32_t));
1502
+ if(ttsocksend(sock, stack, sizeof(uint8_t) + sizeof(uint32_t))){
1503
+ req->keep = true;
1504
+ } else {
1505
+ ttservlog(g_serv, TTLOGINFO, "do_vsiz: response failed");
1506
+ }
1507
+ } else {
1508
+ uint8_t code = 1;
1509
+ if(ttsocksend(sock, &code, sizeof(code))){
1510
+ req->keep = true;
1511
+ } else {
1512
+ ttservlog(g_serv, TTLOGINFO, "do_vsiz: response failed");
1513
+ }
1514
+ }
1515
+ } else {
1516
+ ttservlog(g_serv, TTLOGINFO, "do_vsiz: invalid entity");
1517
+ }
1518
+ pthread_cleanup_pop(1);
1519
+ }
1520
+
1521
+
1522
+ /* handle the iterinit command */
1523
+ static void do_iterinit(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1524
+ ttservlog(g_serv, TTLOGDEBUG, "doing iterinit command");
1525
+ arg->counts[TTSEQNUM*req->idx+TTSEQITERINIT]++;
1526
+ uint64_t mask = arg->mask;
1527
+ TCADB *adb = arg->adb;
1528
+ uint8_t code = 0;
1529
+ if(mask & ((1ULL << TTSEQITERINIT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1530
+ code = 1;
1531
+ ttservlog(g_serv, TTLOGINFO, "do_iterinit: forbidden");
1532
+ } else if(!tcadbiterinit(adb)){
1533
+ code = 1;
1534
+ ttservlog(g_serv, TTLOGERROR, "do_iterinit: operation failed");
1535
+ }
1536
+ if(ttsocksend(sock, &code, sizeof(code))){
1537
+ req->keep = true;
1538
+ } else {
1539
+ ttservlog(g_serv, TTLOGINFO, "do_iterinit: response failed");
1540
+ }
1541
+ }
1542
+
1543
+
1544
+ /* handle the iternext command */
1545
+ static void do_iternext(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1546
+ ttservlog(g_serv, TTLOGDEBUG, "doing iternext command");
1547
+ arg->counts[TTSEQNUM*req->idx+TTSEQITERNEXT]++;
1548
+ uint64_t mask = arg->mask;
1549
+ TCADB *adb = arg->adb;
1550
+ int vsiz;
1551
+ char *vbuf;
1552
+ if(mask & ((1ULL << TTSEQITERNEXT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1553
+ vbuf = NULL;
1554
+ vsiz = 0;
1555
+ ttservlog(g_serv, TTLOGINFO, "do_iternext: forbidden");
1556
+ } else {
1557
+ vbuf = tcadbiternext(adb, &vsiz);
1558
+ }
1559
+ if(vbuf){
1560
+ int rsiz = vsiz + sizeof(uint8_t) + sizeof(uint32_t);
1561
+ char stack[TTIOBUFSIZ];
1562
+ char *rbuf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz);
1563
+ pthread_cleanup_push(free, (rbuf == stack) ? NULL : rbuf);
1564
+ *rbuf = 0;
1565
+ uint32_t num;
1566
+ num = TTHTONL((uint32_t)vsiz);
1567
+ memcpy(rbuf + sizeof(uint8_t), &num, sizeof(uint32_t));
1568
+ memcpy(rbuf + sizeof(uint8_t) + sizeof(uint32_t), vbuf, vsiz);
1569
+ tcfree(vbuf);
1570
+ if(ttsocksend(sock, rbuf, rsiz)){
1571
+ req->keep = true;
1572
+ } else {
1573
+ ttservlog(g_serv, TTLOGINFO, "do_iternext: response failed");
1574
+ }
1575
+ pthread_cleanup_pop(1);
1576
+ } else {
1577
+ uint8_t code = 1;
1578
+ if(ttsocksend(sock, &code, sizeof(code))){
1579
+ req->keep = true;
1580
+ } else {
1581
+ ttservlog(g_serv, TTLOGINFO, "do_iternext: response failed");
1582
+ }
1583
+ }
1584
+ }
1585
+
1586
+
1587
+ /* handle the fwmkeys command */
1588
+ static void do_fwmkeys(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1589
+ ttservlog(g_serv, TTLOGDEBUG, "doing fwmkeys command");
1590
+ arg->counts[TTSEQNUM*req->idx+TTSEQFWMKEYS]++;
1591
+ uint64_t mask = arg->mask;
1592
+ TCADB *adb = arg->adb;
1593
+ int psiz = ttsockgetint32(sock);
1594
+ int max = ttsockgetint32(sock);
1595
+ if(ttsockcheckend(sock) || psiz < 0 || psiz > MAXARGSIZ){
1596
+ ttservlog(g_serv, TTLOGINFO, "do_fwmkeys: invalid parameters");
1597
+ return;
1598
+ }
1599
+ char stack[TTIOBUFSIZ];
1600
+ char *buf = (psiz < TTIOBUFSIZ) ? stack : tcmalloc(psiz + 1);
1601
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1602
+ if(ttsockrecv(sock, buf, psiz) && !ttsockcheckend(sock)){
1603
+ TCLIST *keys = tcadbfwmkeys(adb, buf, psiz, max);
1604
+ pthread_cleanup_push((void (*)(void *))tclistdel, keys);
1605
+ TCXSTR *xstr = tcxstrnew();
1606
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
1607
+ uint8_t code = 0;
1608
+ tcxstrcat(xstr, &code, sizeof(code));
1609
+ uint32_t num = 0;
1610
+ tcxstrcat(xstr, &num, sizeof(num));
1611
+ int knum = 0;
1612
+ if(mask & ((1ULL << TTSEQFWMKEYS) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
1613
+ ttservlog(g_serv, TTLOGINFO, "do_fwmkeys: forbidden");
1614
+ } else {
1615
+ for(int i = 0; i < tclistnum(keys); i++){
1616
+ int ksiz;
1617
+ const char *kbuf = tclistval(keys, i, &ksiz);
1618
+ num = TTHTONL((uint32_t)ksiz);
1619
+ tcxstrcat(xstr, &num, sizeof(num));
1620
+ tcxstrcat(xstr, kbuf, ksiz);
1621
+ knum++;
1622
+ }
1623
+ }
1624
+ num = TTHTONL((uint32_t)knum);
1625
+ memcpy((char *)tcxstrptr(xstr) + sizeof(code), &num, sizeof(num));
1626
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
1627
+ req->keep = true;
1628
+ } else {
1629
+ ttservlog(g_serv, TTLOGINFO, "do_fwmkeys: response failed");
1630
+ }
1631
+ pthread_cleanup_pop(1);
1632
+ pthread_cleanup_pop(1);
1633
+ } else {
1634
+ ttservlog(g_serv, TTLOGINFO, "do_fwmkeys: invalid entity");
1635
+ }
1636
+ pthread_cleanup_pop(1);
1637
+ }
1638
+
1639
+
1640
+ /* handle the addint command */
1641
+ static void do_addint(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1642
+ ttservlog(g_serv, TTLOGDEBUG, "doing addint command");
1643
+ arg->counts[TTSEQNUM*req->idx+TTSEQADDINT]++;
1644
+ uint64_t mask = arg->mask;
1645
+ TCADB *adb = arg->adb;
1646
+ TCULOG *ulog = arg->ulog;
1647
+ uint32_t sid = arg->sid;
1648
+ int ksiz = ttsockgetint32(sock);
1649
+ int anum = ttsockgetint32(sock);
1650
+ if(ttsockcheckend(sock) || ksiz < 0 || ksiz > MAXARGSIZ){
1651
+ ttservlog(g_serv, TTLOGINFO, "do_addint: invalid parameters");
1652
+ return;
1653
+ }
1654
+ char stack[TTIOBUFSIZ];
1655
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1656
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1657
+ if(ttsockrecv(sock, buf, ksiz) && !ttsockcheckend(sock)){
1658
+ int snum;
1659
+ if(mask & ((1ULL << TTSEQADDINT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1660
+ snum = INT_MIN;
1661
+ ttservlog(g_serv, TTLOGINFO, "do_addint: forbidden");
1662
+ } else {
1663
+ snum = tculogadbaddint(ulog, sid, 0, adb, buf, ksiz, anum);
1664
+ }
1665
+ if(snum != INT_MIN){
1666
+ *stack = 0;
1667
+ uint32_t num;
1668
+ num = TTHTONL((uint32_t)snum);
1669
+ memcpy(stack + sizeof(uint8_t), &num, sizeof(uint32_t));
1670
+ if(ttsocksend(sock, stack, sizeof(uint8_t) + sizeof(uint32_t))){
1671
+ req->keep = true;
1672
+ } else {
1673
+ ttservlog(g_serv, TTLOGINFO, "do_addint: response failed");
1674
+ }
1675
+ } else {
1676
+ uint8_t code = 1;
1677
+ if(ttsocksend(sock, &code, sizeof(code))){
1678
+ req->keep = true;
1679
+ } else {
1680
+ ttservlog(g_serv, TTLOGINFO, "do_addint: response failed");
1681
+ }
1682
+ }
1683
+ } else {
1684
+ ttservlog(g_serv, TTLOGINFO, "do_addint: invalid entity");
1685
+ }
1686
+ pthread_cleanup_pop(1);
1687
+ }
1688
+
1689
+
1690
+ /* handle the adddouble command */
1691
+ static void do_adddouble(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1692
+ ttservlog(g_serv, TTLOGDEBUG, "doing adddouble command");
1693
+ arg->counts[TTSEQNUM*req->idx+TTSEQADDDOUBLE]++;
1694
+ uint64_t mask = arg->mask;
1695
+ TCADB *adb = arg->adb;
1696
+ TCULOG *ulog = arg->ulog;
1697
+ uint32_t sid = arg->sid;
1698
+ int ksiz = ttsockgetint32(sock);
1699
+ char abuf[sizeof(uint64_t)*2];
1700
+ if(!ttsockrecv(sock, abuf, sizeof(abuf)) || ttsockcheckend(sock) ||
1701
+ ksiz < 0 || ksiz > MAXARGSIZ){
1702
+ ttservlog(g_serv, TTLOGINFO, "do_adddouble: invalid parameters");
1703
+ return;
1704
+ }
1705
+ double anum = ttunpackdouble(abuf);
1706
+ char stack[TTIOBUFSIZ];
1707
+ char *buf = (ksiz < TTIOBUFSIZ) ? stack : tcmalloc(ksiz + 1);
1708
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1709
+ if(ttsockrecv(sock, buf, ksiz) && !ttsockcheckend(sock)){
1710
+ double snum;
1711
+ if(mask & ((1ULL << TTSEQADDDOUBLE) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1712
+ snum = nan("");
1713
+ ttservlog(g_serv, TTLOGINFO, "do_adddouble: forbidden");
1714
+ } else {
1715
+ snum = tculogadbadddouble(ulog, sid, 0, adb, buf, ksiz, anum);
1716
+ }
1717
+ if(!isnan(snum)){
1718
+ *stack = 0;
1719
+ ttpackdouble(snum, abuf);
1720
+ memcpy(stack + sizeof(uint8_t), abuf, sizeof(abuf));
1721
+ if(ttsocksend(sock, stack, sizeof(uint8_t) + sizeof(abuf))){
1722
+ req->keep = true;
1723
+ } else {
1724
+ ttservlog(g_serv, TTLOGINFO, "do_adddouble: response failed");
1725
+ }
1726
+ } else {
1727
+ uint8_t code = 1;
1728
+ if(ttsocksend(sock, &code, sizeof(code))){
1729
+ req->keep = true;
1730
+ } else {
1731
+ ttservlog(g_serv, TTLOGINFO, "do_adddouble: response failed");
1732
+ }
1733
+ }
1734
+ } else {
1735
+ ttservlog(g_serv, TTLOGINFO, "do_adddouble: invalid entity");
1736
+ }
1737
+ pthread_cleanup_pop(1);
1738
+ }
1739
+
1740
+
1741
+ /* handle the ext command */
1742
+ static void do_ext(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1743
+ ttservlog(g_serv, TTLOGDEBUG, "doing ext command");
1744
+ arg->counts[TTSEQNUM*req->idx+TTSEQEXT]++;
1745
+ uint64_t mask = arg->mask;
1746
+ pthread_mutex_t *rmtxs = arg->rmtxs;
1747
+ void *scr = arg->screxts[req->idx];
1748
+ int nsiz = ttsockgetint32(sock);
1749
+ int opts = ttsockgetint32(sock);
1750
+ int ksiz = ttsockgetint32(sock);
1751
+ int vsiz = ttsockgetint32(sock);
1752
+ if(ttsockcheckend(sock) || nsiz < 0 || nsiz >= TTADDRBUFSIZ ||
1753
+ ksiz < 0 || ksiz > MAXARGSIZ || vsiz < 0 || vsiz > MAXARGSIZ){
1754
+ ttservlog(g_serv, TTLOGINFO, "do_ext: invalid parameters");
1755
+ return;
1756
+ }
1757
+ int rsiz = nsiz + ksiz + vsiz;
1758
+ char stack[TTIOBUFSIZ];
1759
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
1760
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1761
+ if(ttsockrecv(sock, buf, rsiz) && !ttsockcheckend(sock)){
1762
+ char name[TTADDRBUFSIZ];
1763
+ memcpy(name, buf, nsiz);
1764
+ name[nsiz] = '\0';
1765
+ const char *kbuf = buf + nsiz;
1766
+ const char *vbuf = kbuf + ksiz;
1767
+ int xsiz = 0;
1768
+ char *xbuf = NULL;
1769
+ if(mask & ((1ULL << TTSEQEXT) | (1ULL << TTSEQALLORG))){
1770
+ ttservlog(g_serv, TTLOGINFO, "do_ext: forbidden");
1771
+ } else if(scr){
1772
+ if(opts & RDBXOLCKGLB){
1773
+ bool err = false;
1774
+ for(int i = 0; i < RECMTXNUM; i++){
1775
+ if(pthread_mutex_lock(rmtxs + i) != 0){
1776
+ ttservlog(g_serv, TTLOGERROR, "do_ext: pthread_mutex_lock failed");
1777
+ while(--i >= 0){
1778
+ pthread_mutex_unlock(rmtxs + i);
1779
+ }
1780
+ err = true;
1781
+ break;
1782
+ }
1783
+ }
1784
+ if(!err){
1785
+ xbuf = scrextcallmethod(scr, name, kbuf, ksiz, vbuf, vsiz, &xsiz);
1786
+ for(int i = RECMTXNUM - 1; i >= 0; i--){
1787
+ if(pthread_mutex_unlock(rmtxs + i) != 0)
1788
+ ttservlog(g_serv, TTLOGERROR, "do_ext: pthread_mutex_unlock failed");
1789
+ }
1790
+ }
1791
+ } else if(opts & RDBXOLCKREC){
1792
+ int mtxidx = recmtxidx(kbuf, ksiz);
1793
+ if(pthread_mutex_lock(rmtxs + mtxidx) == 0){
1794
+ xbuf = scrextcallmethod(scr, name, kbuf, ksiz, vbuf, vsiz, &xsiz);
1795
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
1796
+ ttservlog(g_serv, TTLOGERROR, "do_ext: pthread_mutex_unlock failed");
1797
+ } else {
1798
+ ttservlog(g_serv, TTLOGERROR, "do_ext: pthread_mutex_lock failed");
1799
+ }
1800
+ } else {
1801
+ xbuf = scrextcallmethod(scr, name, kbuf, ksiz, vbuf, vsiz, &xsiz);
1802
+ }
1803
+ }
1804
+ if(xbuf){
1805
+ int rsiz = xsiz + sizeof(uint8_t) + sizeof(uint32_t);
1806
+ char *rbuf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz);
1807
+ pthread_cleanup_push(free, (rbuf == stack) ? NULL : rbuf);
1808
+ *rbuf = 0;
1809
+ uint32_t num;
1810
+ num = TTHTONL((uint32_t)xsiz);
1811
+ memcpy(rbuf + sizeof(uint8_t), &num, sizeof(uint32_t));
1812
+ memcpy(rbuf + sizeof(uint8_t) + sizeof(uint32_t), xbuf, xsiz);
1813
+ tcfree(xbuf);
1814
+ if(ttsocksend(sock, rbuf, rsiz)){
1815
+ req->keep = true;
1816
+ } else {
1817
+ ttservlog(g_serv, TTLOGINFO, "do_ext: response failed");
1818
+ }
1819
+ pthread_cleanup_pop(1);
1820
+ } else {
1821
+ uint8_t code = 1;
1822
+ if(ttsocksend(sock, &code, sizeof(code))){
1823
+ req->keep = true;
1824
+ } else {
1825
+ ttservlog(g_serv, TTLOGINFO, "do_ext: response failed");
1826
+ }
1827
+ }
1828
+ } else {
1829
+ ttservlog(g_serv, TTLOGINFO, "do_ext: invalid entity");
1830
+ }
1831
+ pthread_cleanup_pop(1);
1832
+ }
1833
+
1834
+
1835
+ /* handle the sync command */
1836
+ static void do_sync(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1837
+ ttservlog(g_serv, TTLOGINFO, "doing sync command");
1838
+ arg->counts[TTSEQNUM*req->idx+TTSEQSYNC]++;
1839
+ uint64_t mask = arg->mask;
1840
+ TCADB *adb = arg->adb;
1841
+ TCULOG *ulog = arg->ulog;
1842
+ uint32_t sid = arg->sid;
1843
+ uint8_t code = 0;
1844
+ if(mask & ((1ULL << TTSEQSYNC) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLMANAGE))){
1845
+ code = 1;
1846
+ ttservlog(g_serv, TTLOGINFO, "do_sync: forbidden");
1847
+ } else if(!tculogadbsync(ulog, sid, 0, adb)){
1848
+ code = 1;
1849
+ ttservlog(g_serv, TTLOGERROR, "do_sync: operation failed");
1850
+ }
1851
+ if(ttsocksend(sock, &code, sizeof(code))){
1852
+ req->keep = true;
1853
+ } else {
1854
+ ttservlog(g_serv, TTLOGINFO, "do_sync: response failed");
1855
+ }
1856
+ }
1857
+
1858
+
1859
+ /* handle the optimize command */
1860
+ static void do_optimize(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1861
+ ttservlog(g_serv, TTLOGINFO, "doing optimize command");
1862
+ arg->counts[TTSEQNUM*req->idx+TTSEQOPTIMIZE]++;
1863
+ uint64_t mask = arg->mask;
1864
+ TCADB *adb = arg->adb;
1865
+ TCULOG *ulog = arg->ulog;
1866
+ uint32_t sid = arg->sid;
1867
+ int psiz = ttsockgetint32(sock);
1868
+ if(ttsockcheckend(sock) || psiz < 0 || psiz > MAXARGSIZ){
1869
+ ttservlog(g_serv, TTLOGINFO, "do_optimize: invalid parameters");
1870
+ return;
1871
+ }
1872
+ char stack[TTIOBUFSIZ];
1873
+ char *buf = (psiz < TTIOBUFSIZ) ? stack : tcmalloc(psiz + 1);
1874
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1875
+ if(ttsockrecv(sock, buf, psiz) && !ttsockcheckend(sock)){
1876
+ buf[psiz] = '\0';
1877
+ uint8_t code = 0;
1878
+ if(mask & ((1ULL << TTSEQOPTIMIZE) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLMANAGE))){
1879
+ code = 1;
1880
+ ttservlog(g_serv, TTLOGINFO, "do_optimize: forbidden");
1881
+ } else if(!tculogadboptimize(ulog, sid, 0, adb, buf)){
1882
+ code = 1;
1883
+ }
1884
+ if(ttsocksend(sock, &code, sizeof(code))){
1885
+ req->keep = true;
1886
+ } else {
1887
+ ttservlog(g_serv, TTLOGINFO, "do_optimize: response failed");
1888
+ }
1889
+ } else {
1890
+ ttservlog(g_serv, TTLOGINFO, "do_optimize: invalid entity");
1891
+ }
1892
+ pthread_cleanup_pop(1);
1893
+ }
1894
+
1895
+
1896
+ /* handle the vanish command */
1897
+ static void do_vanish(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1898
+ ttservlog(g_serv, TTLOGINFO, "doing vanish command");
1899
+ arg->counts[TTSEQNUM*req->idx+TTSEQVANISH]++;
1900
+ uint64_t mask = arg->mask;
1901
+ TCADB *adb = arg->adb;
1902
+ TCULOG *ulog = arg->ulog;
1903
+ uint32_t sid = arg->sid;
1904
+ uint8_t code = 0;
1905
+ if(mask & ((1ULL << TTSEQVANISH) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
1906
+ code = 1;
1907
+ ttservlog(g_serv, TTLOGINFO, "do_vanish: forbidden");
1908
+ } else if(!tculogadbvanish(ulog, sid, 0, adb)){
1909
+ code = 1;
1910
+ ttservlog(g_serv, TTLOGERROR, "do_vanish: operation failed");
1911
+ }
1912
+ if(ttsocksend(sock, &code, sizeof(code))){
1913
+ req->keep = true;
1914
+ } else {
1915
+ ttservlog(g_serv, TTLOGINFO, "do_vanish: response failed");
1916
+ }
1917
+ }
1918
+
1919
+
1920
+ /* handle the copy command */
1921
+ static void do_copy(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1922
+ ttservlog(g_serv, TTLOGINFO, "doing copy command");
1923
+ arg->counts[TTSEQNUM*req->idx+TTSEQCOPY]++;
1924
+ uint64_t mask = arg->mask;
1925
+ TCADB *adb = arg->adb;
1926
+ int psiz = ttsockgetint32(sock);
1927
+ if(ttsockcheckend(sock) || psiz < 0 || psiz > MAXARGSIZ){
1928
+ ttservlog(g_serv, TTLOGINFO, "do_copy: invalid parameters");
1929
+ return;
1930
+ }
1931
+ char stack[TTIOBUFSIZ];
1932
+ char *buf = (psiz < TTIOBUFSIZ) ? stack : tcmalloc(psiz + 1);
1933
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1934
+ if(ttsockrecv(sock, buf, psiz) && !ttsockcheckend(sock)){
1935
+ buf[psiz] = '\0';
1936
+ uint8_t code = 0;
1937
+ if(mask & ((1ULL << TTSEQCOPY) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLMANAGE))){
1938
+ code = 1;
1939
+ ttservlog(g_serv, TTLOGINFO, "do_copy: forbidden");
1940
+ } else if(!tcadbcopy(adb, buf)){
1941
+ code = 1;
1942
+ ttservlog(g_serv, TTLOGERROR, "do_copy: operation failed");
1943
+ }
1944
+ if(ttsocksend(sock, &code, sizeof(code))){
1945
+ req->keep = true;
1946
+ } else {
1947
+ ttservlog(g_serv, TTLOGINFO, "do_copy: response failed");
1948
+ }
1949
+ } else {
1950
+ ttservlog(g_serv, TTLOGINFO, "do_copy: invalid entity");
1951
+ }
1952
+ pthread_cleanup_pop(1);
1953
+ }
1954
+
1955
+
1956
+ /* handle the restore command */
1957
+ static void do_restore(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1958
+ ttservlog(g_serv, TTLOGINFO, "doing restore command");
1959
+ arg->counts[TTSEQNUM*req->idx+TTSEQRESTORE]++;
1960
+ uint64_t mask = arg->mask;
1961
+ TCADB *adb = arg->adb;
1962
+ TCULOG *ulog = arg->ulog;
1963
+ int psiz = ttsockgetint32(sock);
1964
+ uint64_t ts = ttsockgetint64(sock);
1965
+ int opts = ttsockgetint32(sock);
1966
+ if(ttsockcheckend(sock) || psiz < 0 || psiz > MAXARGSIZ){
1967
+ ttservlog(g_serv, TTLOGINFO, "do_restore: invalid parameters");
1968
+ return;
1969
+ }
1970
+ char stack[TTIOBUFSIZ];
1971
+ char *buf = (psiz < TTIOBUFSIZ) ? stack : tcmalloc(psiz + 1);
1972
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
1973
+ if(ttsockrecv(sock, buf, psiz) && !ttsockcheckend(sock)){
1974
+ buf[psiz] = '\0';
1975
+ bool con = (opts & RDBROCHKCON) != 0;
1976
+ uint8_t code = 0;
1977
+ if(mask & ((1ULL << TTSEQRESTORE) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLMANAGE))){
1978
+ code = 1;
1979
+ ttservlog(g_serv, TTLOGINFO, "do_restore: forbidden");
1980
+ } else if(!tculogadbrestore(adb, buf, ts, con, ulog)){
1981
+ code = 1;
1982
+ ttservlog(g_serv, TTLOGERROR, "do_restore: operation failed");
1983
+ }
1984
+ if(ttsocksend(sock, &code, sizeof(code))){
1985
+ req->keep = true;
1986
+ } else {
1987
+ ttservlog(g_serv, TTLOGINFO, "do_restore: response failed");
1988
+ }
1989
+ } else {
1990
+ ttservlog(g_serv, TTLOGINFO, "do_restore: invalid entity");
1991
+ }
1992
+ pthread_cleanup_pop(1);
1993
+ }
1994
+
1995
+
1996
+ /* handle the setmst command */
1997
+ static void do_setmst(TTSOCK *sock, TASKARG *arg, TTREQ *req){
1998
+ ttservlog(g_serv, TTLOGINFO, "doing setmst command");
1999
+ arg->counts[TTSEQNUM*req->idx+TTSEQSETMST]++;
2000
+ uint64_t mask = arg->mask;
2001
+ REPLARG *sarg = arg->sarg;
2002
+ int hsiz = ttsockgetint32(sock);
2003
+ int port = ttsockgetint32(sock);
2004
+ uint64_t ts = ttsockgetint64(sock);
2005
+ int opts = ttsockgetint32(sock);
2006
+ if(ttsockcheckend(sock) || hsiz < 0 || hsiz > MAXARGSIZ || port < 0){
2007
+ ttservlog(g_serv, TTLOGINFO, "do_setmst: invalid parameters");
2008
+ return;
2009
+ }
2010
+ char stack[TTIOBUFSIZ];
2011
+ char *buf = (hsiz < TTIOBUFSIZ) ? stack : tcmalloc(hsiz + 1);
2012
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
2013
+ if(ttsockrecv(sock, buf, hsiz) && !ttsockcheckend(sock)){
2014
+ buf[hsiz] = '\0';
2015
+ uint8_t code = 0;
2016
+ if(mask & ((1ULL << TTSEQSETMST) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLMANAGE))){
2017
+ code = 1;
2018
+ ttservlog(g_serv, TTLOGINFO, "do_setmst: forbidden");
2019
+ } else {
2020
+ snprintf(sarg->host, TTADDRBUFSIZ, "%s", buf);
2021
+ sarg->port = port;
2022
+ sarg->opts = opts;
2023
+ sarg->recon = true;
2024
+ sarg->fatal = false;
2025
+ sarg->mts = ts;
2026
+ }
2027
+ if(ttsocksend(sock, &code, sizeof(code))){
2028
+ req->keep = true;
2029
+ } else {
2030
+ ttservlog(g_serv, TTLOGINFO, "do_setmst: response failed");
2031
+ }
2032
+ } else {
2033
+ ttservlog(g_serv, TTLOGINFO, "do_setmst: invalid entity");
2034
+ }
2035
+ pthread_cleanup_pop(1);
2036
+ }
2037
+
2038
+
2039
+ /* handle the rnum command */
2040
+ static void do_rnum(TTSOCK *sock, TASKARG *arg, TTREQ *req){
2041
+ ttservlog(g_serv, TTLOGDEBUG, "doing rnum command");
2042
+ arg->counts[TTSEQNUM*req->idx+TTSEQRNUM]++;
2043
+ uint64_t mask = arg->mask;
2044
+ TCADB *adb = arg->adb;
2045
+ char buf[LINEBUFSIZ];
2046
+ *buf = 0;
2047
+ uint64_t rnum;
2048
+ if(mask & ((1ULL << TTSEQRNUM) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
2049
+ rnum = 0;
2050
+ ttservlog(g_serv, TTLOGINFO, "do_rnum: forbidden");
2051
+ } else {
2052
+ rnum = tcadbrnum(adb);
2053
+ }
2054
+ rnum = TTHTONLL(rnum);
2055
+ memcpy(buf + sizeof(uint8_t), &rnum, sizeof(uint64_t));
2056
+ if(ttsocksend(sock, buf, sizeof(uint8_t) + sizeof(uint64_t))){
2057
+ req->keep = true;
2058
+ } else {
2059
+ ttservlog(g_serv, TTLOGINFO, "do_rnum: response failed");
2060
+ }
2061
+ }
2062
+
2063
+
2064
+ /* handle the size command */
2065
+ static void do_size(TTSOCK *sock, TASKARG *arg, TTREQ *req){
2066
+ ttservlog(g_serv, TTLOGDEBUG, "doing size command");
2067
+ arg->counts[TTSEQNUM*req->idx+TTSEQSIZE]++;
2068
+ uint64_t mask = arg->mask;
2069
+ TCADB *adb = arg->adb;
2070
+ char buf[LINEBUFSIZ];
2071
+ *buf = 0;
2072
+ uint64_t size;
2073
+ if(mask & ((1ULL << TTSEQSIZE) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
2074
+ size = 0;
2075
+ ttservlog(g_serv, TTLOGINFO, "do_size: forbidden");
2076
+ } else {
2077
+ size = tcadbsize(adb);
2078
+ }
2079
+ size = TTHTONLL(size);
2080
+ memcpy(buf + sizeof(uint8_t), &size, sizeof(uint64_t));
2081
+ if(ttsocksend(sock, buf, sizeof(uint8_t) + sizeof(uint64_t))){
2082
+ req->keep = true;
2083
+ } else {
2084
+ ttservlog(g_serv, TTLOGINFO, "do_size: response failed");
2085
+ }
2086
+ }
2087
+
2088
+
2089
+ /* handle the stat command */
2090
+ static void do_stat(TTSOCK *sock, TASKARG *arg, TTREQ *req){
2091
+ ttservlog(g_serv, TTLOGDEBUG, "doing stat command");
2092
+ arg->counts[TTSEQNUM*req->idx+TTSEQSTAT]++;
2093
+ uint64_t mask = arg->mask;
2094
+ TCADB *adb = arg->adb;
2095
+ REPLARG *sarg = arg->sarg;
2096
+ char buf[TTIOBUFSIZ];
2097
+ char *wp = buf + sizeof(uint8_t) + sizeof(uint32_t);
2098
+ if(mask & ((1ULL << TTSEQSTAT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
2099
+ ttservlog(g_serv, TTLOGINFO, "do_stat: forbidden");
2100
+ } else {
2101
+ double now = tctime();
2102
+ wp += sprintf(wp, "version\t%s\n", ttversion);
2103
+ wp += sprintf(wp, "libver\t%d\n", _TT_LIBVER);
2104
+ wp += sprintf(wp, "protver\t%s\n", _TT_PROTVER);
2105
+ wp += sprintf(wp, "os\t%s\n", TTSYSNAME);
2106
+ wp += sprintf(wp, "time\t%.6f\n", now);
2107
+ wp += sprintf(wp, "pid\t%lld\n", (long long)getpid());
2108
+ wp += sprintf(wp, "sid\t%d\n", arg->sid);
2109
+ switch(tcadbomode(adb)){
2110
+ case ADBOVOID: wp += sprintf(wp, "type\tvoid\n"); break;
2111
+ case ADBOMDB: wp += sprintf(wp, "type\ton-memory hash\n"); break;
2112
+ case ADBONDB: wp += sprintf(wp, "type\ton-memory tree\n"); break;
2113
+ case ADBOHDB: wp += sprintf(wp, "type\thash\n"); break;
2114
+ case ADBOBDB: wp += sprintf(wp, "type\tB+ tree\n"); break;
2115
+ case ADBOFDB: wp += sprintf(wp, "type\tfixed-length\n"); break;
2116
+ case ADBOTDB: wp += sprintf(wp, "type\ttable\n"); break;
2117
+ case ADBOSKEL: wp += sprintf(wp, "type\tskeleton\n"); break;
2118
+ }
2119
+ const char *path = tcadbpath(adb);
2120
+ if(path) wp += sprintf(wp, "path\t%s\n", path);
2121
+ wp += sprintf(wp, "rnum\t%llu\n", (unsigned long long)tcadbrnum(adb));
2122
+ wp += sprintf(wp, "size\t%llu\n", (unsigned long long)tcadbsize(adb));
2123
+ TCLIST *args = tclistnew2(1);
2124
+ pthread_cleanup_push((void (*)(void *))tclistdel, args);
2125
+ TCLIST *res = tcadbmisc(adb, "error", args);
2126
+ if(res){
2127
+ int rnum = tclistnum(res);
2128
+ const char *emsg = NULL;
2129
+ bool fatal = false;
2130
+ for(int i = 0; i < rnum; i++){
2131
+ const char *vbuf = tclistval2(res, i);
2132
+ if(!tcstricmp(vbuf, "fatal")){
2133
+ fatal = true;
2134
+ } else {
2135
+ emsg = vbuf;
2136
+ }
2137
+ }
2138
+ if(fatal) wp += sprintf(wp, "fatal\t%s\n", emsg);
2139
+ tclistdel(res);
2140
+ }
2141
+ pthread_cleanup_pop(1);
2142
+ wp += sprintf(wp, "bigend\t%d\n", TTBIGEND);
2143
+ if(sarg->host[0] != '\0'){
2144
+ wp += sprintf(wp, "mhost\t%s\n", sarg->host);
2145
+ wp += sprintf(wp, "mport\t%d\n", sarg->port);
2146
+ wp += sprintf(wp, "rts\t%llu\n", (unsigned long long)sarg->rts);
2147
+ double delay = now - sarg->rts / 1000000.0;
2148
+ wp += sprintf(wp, "delay\t%.6f\n", delay >= 0 ? delay : 0.0);
2149
+ }
2150
+ wp += sprintf(wp, "fd\t%d\n", sock->fd);
2151
+ wp += sprintf(wp, "loadavg\t%.6f\n", ttgetloadavg());
2152
+ TCMAP *info = tcsysinfo();
2153
+ if(info){
2154
+ const char *vbuf = tcmapget2(info, "size");
2155
+ if(vbuf) wp += sprintf(wp, "memsize\t%s\n", vbuf);
2156
+ vbuf = tcmapget2(info, "rss");
2157
+ if(vbuf) wp += sprintf(wp, "memrss\t%s\n", vbuf);
2158
+ vbuf = tcmapget2(info, "utime");
2159
+ if(vbuf) wp += sprintf(wp, "ru_user\t%s\n", vbuf);
2160
+ vbuf = tcmapget2(info, "stime");
2161
+ if(vbuf) wp += sprintf(wp, "ru_sys\t%s\n", vbuf);
2162
+ tcmapdel(info);
2163
+ }
2164
+ wp += sprintf(wp, "ru_real\t%.6f\n", now - g_starttime);
2165
+ }
2166
+ wp += sprintf(wp, "cnt_put\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUT));
2167
+ wp += sprintf(wp, "cnt_putkeep\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUTKEEP));
2168
+ wp += sprintf(wp, "cnt_putcat\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUTCAT));
2169
+ wp += sprintf(wp, "cnt_putshl\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUTSHL));
2170
+ wp += sprintf(wp, "cnt_putnr\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUTNR));
2171
+ wp += sprintf(wp, "cnt_out\t%llu\n", (unsigned long long)sumstat(arg, TTSEQOUT));
2172
+ wp += sprintf(wp, "cnt_get\t%llu\n", (unsigned long long)sumstat(arg, TTSEQGET));
2173
+ wp += sprintf(wp, "cnt_mget\t%llu\n", (unsigned long long)sumstat(arg, TTSEQMGET));
2174
+ wp += sprintf(wp, "cnt_vsiz\t%llu\n", (unsigned long long)sumstat(arg, TTSEQVSIZ));
2175
+ wp += sprintf(wp, "cnt_iterinit\t%llu\n", (unsigned long long)sumstat(arg, TTSEQITERINIT));
2176
+ wp += sprintf(wp, "cnt_iternext\t%llu\n", (unsigned long long)sumstat(arg, TTSEQITERNEXT));
2177
+ wp += sprintf(wp, "cnt_fwmkeys\t%llu\n", (unsigned long long)sumstat(arg, TTSEQFWMKEYS));
2178
+ wp += sprintf(wp, "cnt_addint\t%llu\n", (unsigned long long)sumstat(arg, TTSEQADDINT));
2179
+ wp += sprintf(wp, "cnt_adddouble\t%llu\n", (unsigned long long)sumstat(arg, TTSEQADDDOUBLE));
2180
+ wp += sprintf(wp, "cnt_ext\t%llu\n", (unsigned long long)sumstat(arg, TTSEQEXT));
2181
+ wp += sprintf(wp, "cnt_sync\t%llu\n", (unsigned long long)sumstat(arg, TTSEQSYNC));
2182
+ wp += sprintf(wp, "cnt_optimize\t%llu\n", (unsigned long long)sumstat(arg, TTSEQOPTIMIZE));
2183
+ wp += sprintf(wp, "cnt_vanish\t%llu\n", (unsigned long long)sumstat(arg, TTSEQVANISH));
2184
+ wp += sprintf(wp, "cnt_copy\t%llu\n", (unsigned long long)sumstat(arg, TTSEQCOPY));
2185
+ wp += sprintf(wp, "cnt_restore\t%llu\n", (unsigned long long)sumstat(arg, TTSEQRESTORE));
2186
+ wp += sprintf(wp, "cnt_setmst\t%llu\n", (unsigned long long)sumstat(arg, TTSEQSETMST));
2187
+ wp += sprintf(wp, "cnt_rnum\t%llu\n", (unsigned long long)sumstat(arg, TTSEQRNUM));
2188
+ wp += sprintf(wp, "cnt_size\t%llu\n", (unsigned long long)sumstat(arg, TTSEQSIZE));
2189
+ wp += sprintf(wp, "cnt_stat\t%llu\n", (unsigned long long)sumstat(arg, TTSEQSTAT));
2190
+ wp += sprintf(wp, "cnt_misc\t%llu\n", (unsigned long long)sumstat(arg, TTSEQMISC));
2191
+ wp += sprintf(wp, "cnt_repl\t%llu\n", (unsigned long long)sumstat(arg, TTSEQREPL));
2192
+ wp += sprintf(wp, "cnt_put_miss\t%llu\n", (unsigned long long)sumstat(arg, TTSEQPUTMISS));
2193
+ wp += sprintf(wp, "cnt_out_miss\t%llu\n", (unsigned long long)sumstat(arg, TTSEQOUTMISS));
2194
+ wp += sprintf(wp, "cnt_get_miss\t%llu\n", (unsigned long long)sumstat(arg, TTSEQGETMISS));
2195
+ *buf = 0;
2196
+ uint32_t size = wp - buf - (sizeof(uint8_t) + sizeof(uint32_t));
2197
+ size = TTHTONL(size);
2198
+ memcpy(buf + sizeof(uint8_t), &size, sizeof(uint32_t));
2199
+ if(ttsocksend(sock, buf, wp - buf)){
2200
+ req->keep = true;
2201
+ } else {
2202
+ ttservlog(g_serv, TTLOGINFO, "do_stat: response failed");
2203
+ }
2204
+ }
2205
+
2206
+
2207
+ /* handle the misc command */
2208
+ static void do_misc(TTSOCK *sock, TASKARG *arg, TTREQ *req){
2209
+ ttservlog(g_serv, TTLOGDEBUG, "doing misc command");
2210
+ arg->counts[TTSEQNUM*req->idx+TTSEQMISC]++;
2211
+ uint64_t mask = arg->mask;
2212
+ TCADB *adb = arg->adb;
2213
+ TCULOG *ulog = arg->ulog;
2214
+ uint32_t sid = arg->sid;
2215
+ int nsiz = ttsockgetint32(sock);
2216
+ int opts = ttsockgetint32(sock);
2217
+ int rnum = ttsockgetint32(sock);
2218
+ if(ttsockcheckend(sock) || nsiz < 0 || nsiz >= TTADDRBUFSIZ || rnum < 0 || rnum > MAXARGNUM){
2219
+ ttservlog(g_serv, TTLOGINFO, "do_misc: invalid parameters");
2220
+ return;
2221
+ }
2222
+ char name[TTADDRBUFSIZ];
2223
+ if(!ttsockrecv(sock, name, nsiz) && !ttsockcheckend(sock)){
2224
+ ttservlog(g_serv, TTLOGINFO, "do_misc: invalid parameters");
2225
+ return;
2226
+ }
2227
+ name[nsiz] = '\0';
2228
+ TCLIST *args = tclistnew2(rnum);
2229
+ pthread_cleanup_push((void (*)(void *))tclistdel, args);
2230
+ char stack[TTIOBUFSIZ];
2231
+ for(int i = 0; i < rnum; i++){
2232
+ int rsiz = ttsockgetint32(sock);
2233
+ if(ttsockcheckend(sock) || rsiz < 0 || rsiz > MAXARGSIZ) break;
2234
+ char *buf = (rsiz < TTIOBUFSIZ) ? stack : tcmalloc(rsiz + 1);
2235
+ pthread_cleanup_push(free, (buf == stack) ? NULL : buf);
2236
+ if(ttsockrecv(sock, buf, rsiz)) tclistpush(args, buf, rsiz);
2237
+ pthread_cleanup_pop(1);
2238
+ }
2239
+ if(!ttsockcheckend(sock)){
2240
+ TCXSTR *xstr = tcxstrnew();
2241
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
2242
+ uint8_t code = 0;
2243
+ tcxstrcat(xstr, &code, sizeof(code));
2244
+ uint32_t num = 0;
2245
+ tcxstrcat(xstr, &num, sizeof(num));
2246
+ rnum = 0;
2247
+ if(mask & ((1ULL << TTSEQMISC) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLWRITE))){
2248
+ ttservlog(g_serv, TTLOGINFO, "do_misc: forbidden");
2249
+ } else {
2250
+ TCLIST *res = (opts & RDBMONOULOG) ?
2251
+ tcadbmisc(adb, name, args) : tculogadbmisc(ulog, sid, 0, adb, name, args);
2252
+ if(res){
2253
+ for(int i = 0; i < tclistnum(res); i++){
2254
+ int esiz;
2255
+ const char *ebuf = tclistval(res, i, &esiz);
2256
+ num = TTHTONL((uint32_t)esiz);
2257
+ tcxstrcat(xstr, &num, sizeof(num));
2258
+ tcxstrcat(xstr, ebuf, esiz);
2259
+ rnum++;
2260
+ }
2261
+ tclistdel(res);
2262
+ } else {
2263
+ *(uint8_t *)tcxstrptr(xstr) = 1;
2264
+ }
2265
+ }
2266
+ num = TTHTONL((uint32_t)rnum);
2267
+ memcpy((char *)tcxstrptr(xstr) + sizeof(code), &num, sizeof(num));
2268
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
2269
+ req->keep = true;
2270
+ } else {
2271
+ ttservlog(g_serv, TTLOGINFO, "do_misc: response failed");
2272
+ }
2273
+ pthread_cleanup_pop(1);
2274
+ } else {
2275
+ ttservlog(g_serv, TTLOGINFO, "do_misc: invalid entity");
2276
+ }
2277
+ pthread_cleanup_pop(1);
2278
+ }
2279
+
2280
+
2281
+ /* handle the repl command */
2282
+ static void do_repl(TTSOCK *sock, TASKARG *arg, TTREQ *req){
2283
+ ttservlog(g_serv, TTLOGINFO, "doing repl command");
2284
+ arg->counts[TTSEQNUM*req->idx+TTSEQREPL]++;
2285
+ uint64_t mask = arg->mask;
2286
+ TCULOG *ulog = arg->ulog;
2287
+ uint64_t ts = ttsockgetint64(sock);
2288
+ uint32_t sid = ttsockgetint32(sock);
2289
+ if(ttsockcheckend(sock) || ts < 1 || sid < 1){
2290
+ ttservlog(g_serv, TTLOGINFO, "do_repl: invalid parameters");
2291
+ return;
2292
+ }
2293
+ if(mask & (1ULL << TTSEQREPL)){
2294
+ ttservlog(g_serv, TTLOGINFO, "do_repl: forbidden");
2295
+ return;
2296
+ }
2297
+ if(sid == arg->sid){
2298
+ ttservlog(g_serv, TTLOGINFO, "do_repl: rejected circular replication");
2299
+ return;
2300
+ }
2301
+ uint32_t lnum = TTHTONL(arg->sid);
2302
+ if(!ttsocksend(sock, &lnum, sizeof(lnum))){
2303
+ ttservlog(g_serv, TTLOGINFO, "do_repl: response failed");
2304
+ return;
2305
+ }
2306
+ TCULRD *ulrd = tculrdnew(ulog, ts);
2307
+ if(ulrd){
2308
+ ttservlog(g_serv, TTLOGINFO, "replicating to sid=%u after %llu",
2309
+ (unsigned int)sid, (unsigned long long)ts - 1);
2310
+ pthread_cleanup_push((void (*)(void *))tculrddel, ulrd);
2311
+ bool err = false;
2312
+ double noptime = 0;
2313
+ char stack[TTIOBUFSIZ];
2314
+ while(!err && !ttserviskilled(g_serv)){
2315
+ ttsocksetlife(sock, UINT_MAX);
2316
+ double now = tctime();
2317
+ req->mtime = now + UINT_MAX;
2318
+ if(now - noptime >= 1.0){
2319
+ *(unsigned char *)stack = TCULMAGICNOP;
2320
+ if(!ttsocksend(sock, stack, sizeof(uint8_t))){
2321
+ err = true;
2322
+ ttservlog(g_serv, TTLOGINFO, "do_repl: connection closed");
2323
+ }
2324
+ noptime = now;
2325
+ }
2326
+ tculrdwait(ulrd);
2327
+ uint32_t nopcnt = 0;
2328
+ const char *rbuf;
2329
+ int rsiz;
2330
+ uint64_t rts;
2331
+ uint32_t rsid, rmid;
2332
+ while(!err && (rbuf = tculrdread(ulrd, &rsiz, &rts, &rsid, &rmid)) != NULL){
2333
+ if(rsid == sid || rmid == sid){
2334
+ if((nopcnt++ & 0xff) == 0){
2335
+ now = tctime();
2336
+ if(now - noptime >= 1.0){
2337
+ *(unsigned char *)stack = TCULMAGICNOP;
2338
+ if(!ttsocksend(sock, stack, sizeof(uint8_t))){
2339
+ err = true;
2340
+ ttservlog(g_serv, TTLOGINFO, "do_repl: connection closed");
2341
+ }
2342
+ noptime = now;
2343
+ }
2344
+ }
2345
+ continue;
2346
+ }
2347
+ int msiz = sizeof(uint8_t) + sizeof(uint64_t) + sizeof(uint32_t) * 2 + rsiz;
2348
+ char *mbuf = (msiz < TTIOBUFSIZ) ? stack : tcmalloc(msiz);
2349
+ pthread_cleanup_push(free, (mbuf == stack) ? NULL : mbuf);
2350
+ unsigned char *wp = (unsigned char *)mbuf;
2351
+ *(wp++) = TCULMAGICNUM;
2352
+ uint64_t llnum = TTHTONLL(rts);
2353
+ memcpy(wp, &llnum, sizeof(llnum));
2354
+ wp += sizeof(llnum);
2355
+ lnum = TTHTONL(rsid);
2356
+ memcpy(wp, &lnum, sizeof(lnum));
2357
+ wp += sizeof(lnum);
2358
+ lnum = TTHTONL(rsiz);
2359
+ memcpy(wp, &lnum, sizeof(lnum));
2360
+ wp += sizeof(lnum);
2361
+ memcpy(wp, rbuf, rsiz);
2362
+ if(!ttsocksend(sock, mbuf, msiz)){
2363
+ err = true;
2364
+ ttservlog(g_serv, TTLOGINFO, "do_repl: response failed");
2365
+ }
2366
+ pthread_cleanup_pop(1);
2367
+ }
2368
+ }
2369
+ pthread_cleanup_pop(1);
2370
+ } else {
2371
+ ttservlog(g_serv, TTLOGERROR, "do_repl: tculrdnew failed");
2372
+ }
2373
+ }
2374
+
2375
+
2376
+ /* handle the memcached set command */
2377
+ static void do_mc_set(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2378
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_set command");
2379
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
2380
+ uint64_t mask = arg->mask;
2381
+ TCADB *adb = arg->adb;
2382
+ TCULOG *ulog = arg->ulog;
2383
+ uint32_t sid = arg->sid;
2384
+ if(tnum < 5){
2385
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2386
+ return;
2387
+ }
2388
+ bool nr = tnum > 5 && !strcmp(tokens[5], "noreply");
2389
+ const char *kbuf = tokens[1];
2390
+ int ksiz = strlen(kbuf);
2391
+ int vsiz = tclmax(tcatoi(tokens[4]), 0);
2392
+ char stack[TTIOBUFSIZ];
2393
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
2394
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
2395
+ if(ttsockrecv(sock, vbuf, vsiz) && ttsockgetc(sock) == '\r' && ttsockgetc(sock) == '\n' &&
2396
+ !ttsockcheckend(sock)){
2397
+ int len;
2398
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2399
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2400
+ ttservlog(g_serv, TTLOGINFO, "do_mc_set: forbidden");
2401
+ } else if(tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
2402
+ len = sprintf(stack, "STORED\r\n");
2403
+ } else {
2404
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
2405
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2406
+ ttservlog(g_serv, TTLOGERROR, "do_mc_set: operation failed");
2407
+ }
2408
+ if(nr || ttsocksend(sock, stack, len)){
2409
+ req->keep = true;
2410
+ } else {
2411
+ ttservlog(g_serv, TTLOGINFO, "do_mc_set: response failed");
2412
+ }
2413
+ } else {
2414
+ ttservlog(g_serv, TTLOGINFO, "do_mc_set: invalid entity");
2415
+ }
2416
+ pthread_cleanup_pop(1);
2417
+ }
2418
+
2419
+
2420
+ /* handle the memcached add command */
2421
+ static void do_mc_add(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2422
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_add command");
2423
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTKEEP]++;
2424
+ uint64_t mask = arg->mask;
2425
+ TCADB *adb = arg->adb;
2426
+ TCULOG *ulog = arg->ulog;
2427
+ uint32_t sid = arg->sid;
2428
+ if(tnum < 5){
2429
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2430
+ return;
2431
+ }
2432
+ bool nr = tnum > 5 && !strcmp(tokens[5], "noreply");
2433
+ const char *kbuf = tokens[1];
2434
+ int ksiz = strlen(kbuf);
2435
+ int vsiz = tclmax(tcatoi(tokens[4]), 0);
2436
+ char stack[TTIOBUFSIZ];
2437
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
2438
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
2439
+ if(ttsockrecv(sock, vbuf, vsiz) && ttsockgetc(sock) == '\r' && ttsockgetc(sock) == '\n' &&
2440
+ !ttsockcheckend(sock)){
2441
+ int len;
2442
+ if(mask & ((1ULL << TTSEQPUTKEEP) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2443
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2444
+ ttservlog(g_serv, TTLOGINFO, "do_mc_add: forbidden");
2445
+ } else if(tculogadbputkeep(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
2446
+ len = sprintf(stack, "STORED\r\n");
2447
+ } else {
2448
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
2449
+ len = sprintf(stack, "NOT_STORED\r\n");
2450
+ }
2451
+ if(nr || ttsocksend(sock, stack, len)){
2452
+ req->keep = true;
2453
+ } else {
2454
+ ttservlog(g_serv, TTLOGINFO, "do_mc_add: response failed");
2455
+ }
2456
+ } else {
2457
+ ttservlog(g_serv, TTLOGINFO, "do_mc_add: invalid entity");
2458
+ }
2459
+ pthread_cleanup_pop(1);
2460
+ }
2461
+
2462
+
2463
+ /* handle the memcached replace command */
2464
+ static void do_mc_replace(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2465
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_replace command");
2466
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
2467
+ uint64_t mask = arg->mask;
2468
+ TCADB *adb = arg->adb;
2469
+ TCULOG *ulog = arg->ulog;
2470
+ uint32_t sid = arg->sid;
2471
+ pthread_mutex_t *rmtxs = arg->rmtxs;
2472
+ if(tnum < 5){
2473
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2474
+ return;
2475
+ }
2476
+ bool nr = tnum > 5 && !strcmp(tokens[5], "noreply");
2477
+ const char *kbuf = tokens[1];
2478
+ int ksiz = strlen(kbuf);
2479
+ int vsiz = tclmax(tcatoi(tokens[4]), 0);
2480
+ int mtxidx = recmtxidx(kbuf, ksiz);
2481
+ char stack[TTIOBUFSIZ];
2482
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
2483
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
2484
+ if(ttsockrecv(sock, vbuf, vsiz) && ttsockgetc(sock) == '\r' && ttsockgetc(sock) == '\n' &&
2485
+ !ttsockcheckend(sock)){
2486
+ int len;
2487
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2488
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2489
+ ttservlog(g_serv, TTLOGINFO, "do_mc_replace: forbidden");
2490
+ } else {
2491
+ if(pthread_mutex_lock(rmtxs + mtxidx) != 0){
2492
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2493
+ ttservlog(g_serv, TTLOGERROR, "do_mc_replace: pthread_mutex_lock failed");
2494
+ } else if(tcadbvsiz(adb, kbuf, ksiz) >= 0){
2495
+ if(tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
2496
+ len = sprintf(stack, "STORED\r\n");
2497
+ } else {
2498
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2499
+ ttservlog(g_serv, TTLOGERROR, "do_mc_replace: operation failed");
2500
+ }
2501
+ } else {
2502
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
2503
+ len = sprintf(stack, "NOT_STORED\r\n");
2504
+ }
2505
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
2506
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: pthread_mutex_unlock failed");
2507
+ }
2508
+ if(nr || ttsocksend(sock, stack, len)){
2509
+ req->keep = true;
2510
+ } else {
2511
+ ttservlog(g_serv, TTLOGINFO, "do_mc_replace: response failed");
2512
+ }
2513
+ } else {
2514
+ ttservlog(g_serv, TTLOGINFO, "do_mc_replace: invalid entity");
2515
+ }
2516
+ pthread_cleanup_pop(1);
2517
+ }
2518
+
2519
+
2520
+ /* handle the memcached append command */
2521
+ static void do_mc_append(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2522
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_append command");
2523
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
2524
+ uint64_t mask = arg->mask;
2525
+ TCADB *adb = arg->adb;
2526
+ TCULOG *ulog = arg->ulog;
2527
+ uint32_t sid = arg->sid;
2528
+ pthread_mutex_t *rmtxs = arg->rmtxs;
2529
+ if(tnum < 5){
2530
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2531
+ return;
2532
+ }
2533
+ bool nr = tnum > 5 && !strcmp(tokens[5], "noreply");
2534
+ const char *kbuf = tokens[1];
2535
+ int ksiz = strlen(kbuf);
2536
+ int vsiz = tclmax(tcatoi(tokens[4]), 0);
2537
+ int mtxidx = recmtxidx(kbuf, ksiz);
2538
+ char stack[TTIOBUFSIZ];
2539
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
2540
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
2541
+ if(ttsockrecv(sock, vbuf, vsiz) && ttsockgetc(sock) == '\r' && ttsockgetc(sock) == '\n' &&
2542
+ !ttsockcheckend(sock)){
2543
+ int len;
2544
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2545
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2546
+ ttservlog(g_serv, TTLOGINFO, "do_mc_append: forbidden");
2547
+ } else {
2548
+ if(pthread_mutex_lock(rmtxs + mtxidx) != 0){
2549
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2550
+ ttservlog(g_serv, TTLOGERROR, "do_mc_append: pthread_mutex_lock failed");
2551
+ } else if(tcadbvsiz(adb, kbuf, ksiz) >= 0){
2552
+ if(tculogadbputcat(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
2553
+ len = sprintf(stack, "STORED\r\n");
2554
+ } else {
2555
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2556
+ ttservlog(g_serv, TTLOGERROR, "do_mc_append: operation failed");
2557
+ }
2558
+ } else {
2559
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
2560
+ len = sprintf(stack, "NOT_STORED\r\n");
2561
+ }
2562
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
2563
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: pthread_mutex_unlock failed");
2564
+ }
2565
+ if(nr || ttsocksend(sock, stack, len)){
2566
+ req->keep = true;
2567
+ } else {
2568
+ ttservlog(g_serv, TTLOGINFO, "do_mc_append: response failed");
2569
+ }
2570
+ } else {
2571
+ ttservlog(g_serv, TTLOGINFO, "do_mc_append: invalid entity");
2572
+ }
2573
+ pthread_cleanup_pop(1);
2574
+ }
2575
+
2576
+
2577
+ /* handle the memcached prepend command */
2578
+ static void do_mc_prepend(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2579
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_prepend command");
2580
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
2581
+ uint64_t mask = arg->mask;
2582
+ TCADB *adb = arg->adb;
2583
+ TCULOG *ulog = arg->ulog;
2584
+ uint32_t sid = arg->sid;
2585
+ pthread_mutex_t *rmtxs = arg->rmtxs;
2586
+ if(tnum < 5){
2587
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2588
+ return;
2589
+ }
2590
+ bool nr = tnum > 5 && !strcmp(tokens[5], "noreply");
2591
+ const char *kbuf = tokens[1];
2592
+ int ksiz = strlen(kbuf);
2593
+ int vsiz = tclmax(tcatoi(tokens[4]), 0);
2594
+ int mtxidx = recmtxidx(kbuf, ksiz);
2595
+ char stack[TTIOBUFSIZ];
2596
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
2597
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
2598
+ if(ttsockrecv(sock, vbuf, vsiz) && ttsockgetc(sock) == '\r' && ttsockgetc(sock) == '\n' &&
2599
+ !ttsockcheckend(sock)){
2600
+ int len;
2601
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2602
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2603
+ ttservlog(g_serv, TTLOGINFO, "do_mc_prepend: forbidden");
2604
+ } else {
2605
+ char *obuf;
2606
+ int osiz;
2607
+ if(pthread_mutex_lock(rmtxs + mtxidx) != 0){
2608
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2609
+ ttservlog(g_serv, TTLOGERROR, "do_mc_prepend: pthread_mutex_lock failed");
2610
+ } else if((obuf = tcadbget(adb, kbuf, ksiz, &osiz)) != NULL){
2611
+ char *nbuf = tcmalloc(vsiz + osiz + 1);
2612
+ memcpy(nbuf, vbuf, vsiz);
2613
+ memcpy(nbuf + vsiz, obuf, osiz);
2614
+ tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, nbuf, vsiz + osiz);
2615
+ len = sprintf(stack, "STORED\r\n");
2616
+ tcfree(nbuf);
2617
+ tcfree(obuf);
2618
+ } else {
2619
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
2620
+ len = sprintf(stack, "NOT_STORED\r\n");
2621
+ }
2622
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
2623
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: pthread_mutex_unlock failed");
2624
+ }
2625
+ if(nr || ttsocksend(sock, stack, len)){
2626
+ req->keep = true;
2627
+ } else {
2628
+ ttservlog(g_serv, TTLOGINFO, "do_mc_prepend: response failed");
2629
+ }
2630
+ } else {
2631
+ ttservlog(g_serv, TTLOGINFO, "do_mc_prepend: invalid entity");
2632
+ }
2633
+ pthread_cleanup_pop(1);
2634
+ }
2635
+
2636
+
2637
+ /* handle the memcached get command */
2638
+ static void do_mc_get(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2639
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_get command");
2640
+ uint64_t mask = arg->mask;
2641
+ TCADB *adb = arg->adb;
2642
+ if(tnum < 2){
2643
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2644
+ return;
2645
+ }
2646
+ TCXSTR *xstr = tcxstrnew();
2647
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
2648
+ for(int i = 1; i < tnum; i++){
2649
+ arg->counts[TTSEQNUM*req->idx+TTSEQGET]++;
2650
+ const char *kbuf = tokens[i];
2651
+ int ksiz = strlen(kbuf);
2652
+ int vsiz;
2653
+ char *vbuf;
2654
+ if(mask & ((1ULL << TTSEQGET) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLREAD))){
2655
+ vbuf = NULL;
2656
+ vsiz = 0;
2657
+ ttservlog(g_serv, TTLOGINFO, "do_mc_get: forbidden");
2658
+ } else {
2659
+ vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
2660
+ }
2661
+ if(vbuf){
2662
+ tcxstrprintf(xstr, "VALUE %s 0 %d\r\n", kbuf, vsiz);
2663
+ tcxstrcat(xstr, vbuf, vsiz);
2664
+ tcxstrcat(xstr, "\r\n", 2);
2665
+ tcfree(vbuf);
2666
+ } else {
2667
+ arg->counts[TTSEQNUM*req->idx+TTSEQGETMISS]++;
2668
+ }
2669
+ }
2670
+ tcxstrprintf(xstr, "END\r\n");
2671
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
2672
+ req->keep = true;
2673
+ } else {
2674
+ ttservlog(g_serv, TTLOGINFO, "do_mc_get: response failed");
2675
+ }
2676
+ pthread_cleanup_pop(1);
2677
+ }
2678
+
2679
+
2680
+ /* handle the memcached delete command */
2681
+ static void do_mc_delete(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2682
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_delete command");
2683
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUT]++;
2684
+ uint64_t mask = arg->mask;
2685
+ TCADB *adb = arg->adb;
2686
+ TCULOG *ulog = arg->ulog;
2687
+ uint32_t sid = arg->sid;
2688
+ if(tnum < 2){
2689
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2690
+ return;
2691
+ }
2692
+ bool nr = (tnum > 2 && !strcmp(tokens[2], "noreply")) ||
2693
+ (tnum > 3 && !strcmp(tokens[3], "noreply"));
2694
+ const char *kbuf = tokens[1];
2695
+ int ksiz = strlen(kbuf);
2696
+ char stack[TTIOBUFSIZ];
2697
+ int len;
2698
+ if(mask & ((1ULL << TTSEQOUT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2699
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2700
+ ttservlog(g_serv, TTLOGINFO, "do_mc_delete: forbidden");
2701
+ } else if(tculogadbout(ulog, sid, 0, adb, kbuf, ksiz)){
2702
+ len = sprintf(stack, "DELETED\r\n");
2703
+ } else {
2704
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUTMISS]++;
2705
+ len = sprintf(stack, "NOT_FOUND\r\n");
2706
+ }
2707
+ if(nr || ttsocksend(sock, stack, len)){
2708
+ req->keep = true;
2709
+ } else {
2710
+ ttservlog(g_serv, TTLOGINFO, "do_mc_delete: response failed");
2711
+ }
2712
+ }
2713
+
2714
+
2715
+ /* handle the memcached incr command */
2716
+ static void do_mc_incr(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2717
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_incr command");
2718
+ arg->counts[TTSEQNUM*req->idx+TTSEQADDINT]++;
2719
+ uint64_t mask = arg->mask;
2720
+ TCADB *adb = arg->adb;
2721
+ TCULOG *ulog = arg->ulog;
2722
+ uint32_t sid = arg->sid;
2723
+ pthread_mutex_t *rmtxs = arg->rmtxs;
2724
+ if(tnum < 3){
2725
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2726
+ return;
2727
+ }
2728
+ bool nr = tnum > 3 && !strcmp(tokens[3], "noreply");
2729
+ const char *kbuf = tokens[1];
2730
+ int ksiz = strlen(kbuf);
2731
+ int64_t num = tcatoi(tokens[2]);
2732
+ int mtxidx = recmtxidx(kbuf, ksiz);
2733
+ char stack[TTIOBUFSIZ];
2734
+ int len;
2735
+ if(mask & ((1ULL << TTSEQADDINT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2736
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2737
+ ttservlog(g_serv, TTLOGINFO, "do_mc_incr: forbidden");
2738
+ } else {
2739
+ if(pthread_mutex_lock(rmtxs + mtxidx) != 0){
2740
+ ttsockprintf(sock, "SERVER_ERROR unexpected\r\n");
2741
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: pthread_mutex_lock failed");
2742
+ return;
2743
+ }
2744
+ int vsiz;
2745
+ char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
2746
+ if(vbuf){
2747
+ num += tcatoi(vbuf);
2748
+ if(num < 0) num = 0;
2749
+ len = sprintf(stack, "%lld", (long long)num);
2750
+ if(tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, stack, len)){
2751
+ len = sprintf(stack, "%lld\r\n", (long long)num);
2752
+ } else {
2753
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2754
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: operation failed");
2755
+ }
2756
+ tcfree(vbuf);
2757
+ } else {
2758
+ len = sprintf(stack, "NOT_FOUND\r\n");
2759
+ }
2760
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
2761
+ ttservlog(g_serv, TTLOGERROR, "do_mc_incr: pthread_mutex_unlock failed");
2762
+ }
2763
+ if(nr || ttsocksend(sock, stack, len)){
2764
+ req->keep = true;
2765
+ } else {
2766
+ ttservlog(g_serv, TTLOGINFO, "do_mc_incr: response failed");
2767
+ }
2768
+ }
2769
+
2770
+
2771
+ /* handle the memcached decr command */
2772
+ static void do_mc_decr(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2773
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_decr command");
2774
+ arg->counts[TTSEQNUM*req->idx+TTSEQADDINT]++;
2775
+ uint64_t mask = arg->mask;
2776
+ TCADB *adb = arg->adb;
2777
+ TCULOG *ulog = arg->ulog;
2778
+ uint32_t sid = arg->sid;
2779
+ pthread_mutex_t *rmtxs = arg->rmtxs;
2780
+ if(tnum < 3){
2781
+ ttsockprintf(sock, "CLIENT_ERROR error\r\n");
2782
+ return;
2783
+ }
2784
+ bool nr = tnum > 3 && !strcmp(tokens[3], "noreply");
2785
+ const char *kbuf = tokens[1];
2786
+ int ksiz = strlen(kbuf);
2787
+ int64_t num = tcatoi(tokens[2]) * -1;
2788
+ int mtxidx = recmtxidx(kbuf, ksiz);
2789
+ char stack[TTIOBUFSIZ];
2790
+ int len;
2791
+ if(mask & ((1ULL << TTSEQADDINT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2792
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2793
+ ttservlog(g_serv, TTLOGINFO, "do_mc_decr: forbidden");
2794
+ } else {
2795
+ if(pthread_mutex_lock(rmtxs + mtxidx) != 0){
2796
+ ttsockprintf(sock, "SERVER_ERROR unexpected\r\n");
2797
+ ttservlog(g_serv, TTLOGERROR, "do_mc_decr: pthread_mutex_lock failed");
2798
+ return;
2799
+ }
2800
+ int vsiz;
2801
+ char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
2802
+ if(vbuf){
2803
+ num += tcatoi(vbuf);
2804
+ if(num < 0) num = 0;
2805
+ len = sprintf(stack, "%lld", (long long)num);
2806
+ if(tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, stack, len)){
2807
+ len = sprintf(stack, "%lld\r\n", (long long)num);
2808
+ } else {
2809
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2810
+ ttservlog(g_serv, TTLOGERROR, "do_mc_decr: operation failed");
2811
+ }
2812
+ tcfree(vbuf);
2813
+ } else {
2814
+ len = sprintf(stack, "NOT_FOUND\r\n");
2815
+ }
2816
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
2817
+ ttservlog(g_serv, TTLOGERROR, "do_mc_decr: pthread_mutex_unlock failed");
2818
+ }
2819
+ if(nr || ttsocksend(sock, stack, len)){
2820
+ req->keep = true;
2821
+ } else {
2822
+ ttservlog(g_serv, TTLOGINFO, "do_mc_decr: response failed");
2823
+ }
2824
+ }
2825
+
2826
+
2827
+ /* handle the memcached stat command */
2828
+ static void do_mc_stats(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2829
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_stats command");
2830
+ arg->counts[TTSEQNUM*req->idx+TTSEQSTAT]++;
2831
+ uint64_t mask = arg->mask;
2832
+ TCADB *adb = arg->adb;
2833
+ char stack[TTIOBUFSIZ];
2834
+ char *wp = stack;
2835
+ if(mask & ((1ULL << TTSEQSTAT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLREAD))){
2836
+ ttservlog(g_serv, TTLOGINFO, "do_mc_stats: forbidden");
2837
+ } else {
2838
+ wp += sprintf(wp, "STAT pid %lld\r\n", (long long)getpid());
2839
+ time_t now = time(NULL);
2840
+ wp += sprintf(wp, "STAT uptime %lld\r\n", (long long)(now - (int)g_starttime));
2841
+ wp += sprintf(wp, "STAT time %lld\r\n", (long long)now);
2842
+ wp += sprintf(wp, "STAT version %s\r\n", ttversion);
2843
+ wp += sprintf(wp, "STAT pointer_size %d\r\n", (int)sizeof(void *) * 8);
2844
+ struct rusage ubuf;
2845
+ memset(&ubuf, 0, sizeof(ubuf));
2846
+ if(getrusage(RUSAGE_SELF, &ubuf) == 0){
2847
+ wp += sprintf(wp, "STAT rusage_user %d.%06d\r\n",
2848
+ (int)ubuf.ru_utime.tv_sec, (int)ubuf.ru_utime.tv_usec);
2849
+ wp += sprintf(wp, "STAT rusage_system %d.%06d\r\n",
2850
+ (int)ubuf.ru_stime.tv_sec, (int)ubuf.ru_stime.tv_usec);
2851
+ }
2852
+ uint64_t putsum = sumstat(arg, TTSEQPUT) + sumstat(arg, TTSEQPUTKEEP) +
2853
+ sumstat(arg, TTSEQPUTCAT) + sumstat(arg, TTSEQPUTSHL) + sumstat(arg, TTSEQPUTNR);
2854
+ uint64_t putmiss = sumstat(arg, TTSEQPUTMISS);
2855
+ wp += sprintf(wp, "STAT cmd_set %llu\r\n", (unsigned long long)putsum);
2856
+ wp += sprintf(wp, "STAT cmd_set_hits %llu\r\n", (unsigned long long)(putsum - putmiss));
2857
+ wp += sprintf(wp, "STAT cmd_set_misses %llu\r\n", (unsigned long long)putmiss);
2858
+ uint64_t outsum = sumstat(arg, TTSEQOUT);
2859
+ uint64_t outmiss = sumstat(arg, TTSEQOUTMISS);
2860
+ wp += sprintf(wp, "STAT cmd_delete %llu\r\n", (unsigned long long)outsum);
2861
+ wp += sprintf(wp, "STAT cmd_delete_hits %llu\r\n", (unsigned long long)(outsum - outmiss));
2862
+ wp += sprintf(wp, "STAT cmd_delete_misses %llu\r\n", (unsigned long long)outmiss);
2863
+ uint64_t getsum = sumstat(arg, TTSEQGET);
2864
+ uint64_t getmiss = sumstat(arg, TTSEQGETMISS);
2865
+ wp += sprintf(wp, "STAT cmd_get %llu\r\n", (unsigned long long)getsum);
2866
+ wp += sprintf(wp, "STAT cmd_get_hits %llu\r\n", (unsigned long long)(getsum - getmiss));
2867
+ wp += sprintf(wp, "STAT cmd_get_misses %llu\r\n", (unsigned long long)getmiss);
2868
+ wp += sprintf(wp, "STAT cmd_flush %llu\r\n", (unsigned long long)sumstat(arg, TTSEQVANISH));
2869
+ int64_t rnum = tcadbrnum(adb);
2870
+ wp += sprintf(wp, "STAT curr_items %lld\r\n", (long long)rnum);
2871
+ wp += sprintf(wp, "STAT total_items %lld\r\n", (long long)rnum);
2872
+ wp += sprintf(wp, "STAT bytes %lld\r\n", (long long)tcadbsize(adb));
2873
+ wp += sprintf(wp, "STAT threads %d\r\n", arg->thnum);
2874
+ wp += sprintf(wp, "END\r\n");
2875
+ }
2876
+ if(ttsocksend(sock, stack, wp - stack)){
2877
+ req->keep = true;
2878
+ } else {
2879
+ ttservlog(g_serv, TTLOGINFO, "do_mc_stats: response failed");
2880
+ }
2881
+ }
2882
+
2883
+
2884
+ /* handle the memcached flush_all command */
2885
+ static void do_mc_flushall(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2886
+ ttservlog(g_serv, TTLOGINFO, "doing mc_flushall command");
2887
+ arg->counts[TTSEQNUM*req->idx+TTSEQVANISH]++;
2888
+ uint64_t mask = arg->mask;
2889
+ TCADB *adb = arg->adb;
2890
+ TCULOG *ulog = arg->ulog;
2891
+ uint32_t sid = arg->sid;
2892
+ bool nr = (tnum > 1 && !strcmp(tokens[1], "noreply")) ||
2893
+ (tnum > 2 && !strcmp(tokens[2], "noreply"));
2894
+ char stack[TTIOBUFSIZ];
2895
+ int len;
2896
+ if(mask & ((1ULL << TTSEQVANISH) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLWRITE))){
2897
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2898
+ ttservlog(g_serv, TTLOGINFO, "do_mc_flushall: forbidden");
2899
+ } else if(tculogadbvanish(ulog, sid, 0, adb)){
2900
+ len = sprintf(stack, "OK\r\n");
2901
+ } else {
2902
+ len = sprintf(stack, "SERVER_ERROR unexpected\r\n");
2903
+ ttservlog(g_serv, TTLOGERROR, "do_mc_flushall: operation failed");
2904
+ }
2905
+ if(nr || ttsocksend(sock, stack, len)){
2906
+ req->keep = true;
2907
+ } else {
2908
+ ttservlog(g_serv, TTLOGINFO, "do_mc_flushall: response failed");
2909
+ }
2910
+ }
2911
+
2912
+
2913
+ /* handle the memcached version command */
2914
+ static void do_mc_version(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2915
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_version command");
2916
+ arg->counts[TTSEQNUM*req->idx+TTSEQSTAT]++;
2917
+ uint64_t mask = arg->mask;
2918
+ char stack[TTIOBUFSIZ];
2919
+ int len;
2920
+ if(mask & ((1ULL << TTSEQSTAT) | (1ULL << TTSEQALLMC) | (1ULL << TTSEQALLREAD))){
2921
+ len = sprintf(stack, "CLIENT_ERROR forbidden\r\n");
2922
+ ttservlog(g_serv, TTLOGINFO, "do_mc_version: forbidden");
2923
+ } else {
2924
+ len = sprintf(stack, "VERSION %s\r\n", ttversion);
2925
+ }
2926
+ if(ttsocksend(sock, stack, len)){
2927
+ req->keep = true;
2928
+ } else {
2929
+ ttservlog(g_serv, TTLOGINFO, "do_mc_version: response failed");
2930
+ }
2931
+ }
2932
+
2933
+
2934
+ /* handle the memcached quit command */
2935
+ static void do_mc_quit(TTSOCK *sock, TASKARG *arg, TTREQ *req, char **tokens, int tnum){
2936
+ ttservlog(g_serv, TTLOGDEBUG, "doing mc_quit command");
2937
+ }
2938
+
2939
+
2940
+ /* handle the HTTP GET command */
2941
+ static void do_http_get(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
2942
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_get command");
2943
+ arg->counts[TTSEQNUM*req->idx+TTSEQGET]++;
2944
+ uint64_t mask = arg->mask;
2945
+ TCADB *adb = arg->adb;
2946
+ bool keep = ver >= 1;
2947
+ char line[LINEBUFSIZ];
2948
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
2949
+ char *pv = strchr(line, ':');
2950
+ if(!pv) continue;
2951
+ *(pv++) = '\0';
2952
+ while(*pv == ' ' || *pv == '\t'){
2953
+ pv++;
2954
+ }
2955
+ if(!tcstricmp(line, "connection")){
2956
+ if(!tcstricmp(pv, "close")){
2957
+ keep = false;
2958
+ } else if(!tcstricmp(pv, "keep-alive")){
2959
+ keep = true;
2960
+ }
2961
+ }
2962
+ }
2963
+ if(*uri == '/') uri++;
2964
+ int ksiz;
2965
+ char *kbuf = tcurldecode(uri, &ksiz);
2966
+ pthread_cleanup_push(free, kbuf);
2967
+ TCXSTR *xstr = tcxstrnew();
2968
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
2969
+ if(mask & ((1ULL << TTSEQGET) | (1ULL << TTSEQALLHTTP) | (1ULL << TTSEQALLREAD))){
2970
+ int len = sprintf(line, "Forbidden\n");
2971
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
2972
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
2973
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
2974
+ tcxstrprintf(xstr, "\r\n");
2975
+ tcxstrcat(xstr, line, len);
2976
+ ttservlog(g_serv, TTLOGINFO, "do_http_get: forbidden");
2977
+ } else {
2978
+ int vsiz;
2979
+ char *vbuf = tcadbget(adb, kbuf, ksiz, &vsiz);
2980
+ if(vbuf){
2981
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
2982
+ tcxstrprintf(xstr, "Content-Type: application/octet-stream\r\n");
2983
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", vsiz);
2984
+ tcxstrprintf(xstr, "\r\n");
2985
+ tcxstrcat(xstr, vbuf, vsiz);
2986
+ tcfree(vbuf);
2987
+ } else {
2988
+ arg->counts[TTSEQNUM*req->idx+TTSEQGETMISS]++;
2989
+ int len = sprintf(line, "Not Found\n");
2990
+ tcxstrprintf(xstr, "HTTP/1.1 404 Not Found\r\n");
2991
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
2992
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
2993
+ tcxstrprintf(xstr, "\r\n");
2994
+ tcxstrcat(xstr, line, len);
2995
+ }
2996
+ }
2997
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
2998
+ req->keep = keep;
2999
+ } else {
3000
+ ttservlog(g_serv, TTLOGINFO, "do_http_get: response failed");
3001
+ }
3002
+ pthread_cleanup_pop(1);
3003
+ pthread_cleanup_pop(1);
3004
+ }
3005
+
3006
+
3007
+ /* handle the HTTP HEAD command */
3008
+ static void do_http_head(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
3009
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_head command");
3010
+ arg->counts[TTSEQNUM*req->idx+TTSEQVSIZ]++;
3011
+ uint64_t mask = arg->mask;
3012
+ TCADB *adb = arg->adb;
3013
+ bool keep = ver >= 1;
3014
+ char line[LINEBUFSIZ];
3015
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
3016
+ char *pv = strchr(line, ':');
3017
+ if(!pv) continue;
3018
+ *(pv++) = '\0';
3019
+ while(*pv == ' ' || *pv == '\t'){
3020
+ pv++;
3021
+ }
3022
+ if(!tcstricmp(line, "connection")){
3023
+ if(!tcstricmp(pv, "close")){
3024
+ keep = false;
3025
+ } else if(!tcstricmp(pv, "keep-alive")){
3026
+ keep = true;
3027
+ }
3028
+ }
3029
+ }
3030
+ if(*uri == '/') uri++;
3031
+ int ksiz;
3032
+ char *kbuf = tcurldecode(uri, &ksiz);
3033
+ pthread_cleanup_push(free, kbuf);
3034
+ TCXSTR *xstr = tcxstrnew();
3035
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
3036
+ if(mask & ((1ULL << TTSEQVSIZ) | (1ULL << TTSEQALLHTTP) | (1ULL << TTSEQALLREAD))){
3037
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3038
+ tcxstrprintf(xstr, "\r\n");
3039
+ ttservlog(g_serv, TTLOGINFO, "do_http_head: forbidden");
3040
+ } else {
3041
+ int vsiz = tcadbvsiz(adb, kbuf, ksiz);
3042
+ if(vsiz >= 0){
3043
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
3044
+ tcxstrprintf(xstr, "Content-Type: application/octet-stream\r\n");
3045
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", vsiz);
3046
+ tcxstrprintf(xstr, "\r\n");
3047
+ } else {
3048
+ tcxstrprintf(xstr, "HTTP/1.1 404 Not Found\r\n");
3049
+ tcxstrprintf(xstr, "\r\n");
3050
+ }
3051
+ }
3052
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
3053
+ req->keep = keep;
3054
+ } else {
3055
+ ttservlog(g_serv, TTLOGINFO, "do_http_head: response failed");
3056
+ }
3057
+ pthread_cleanup_pop(1);
3058
+ pthread_cleanup_pop(1);
3059
+ }
3060
+
3061
+
3062
+ /* handle the HTTP PUT command */
3063
+ static void do_http_put(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
3064
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_put command");
3065
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUT]++;
3066
+ uint64_t mask = arg->mask;
3067
+ TCADB *adb = arg->adb;
3068
+ TCULOG *ulog = arg->ulog;
3069
+ uint32_t sid = arg->sid;
3070
+ bool keep = ver >= 1;
3071
+ int vsiz = 0;
3072
+ int pdmode = 0;
3073
+ char line[LINEBUFSIZ];
3074
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
3075
+ char *pv = strchr(line, ':');
3076
+ if(!pv) continue;
3077
+ *(pv++) = '\0';
3078
+ while(*pv == ' ' || *pv == '\t'){
3079
+ pv++;
3080
+ }
3081
+ if(!tcstricmp(line, "connection")){
3082
+ if(!tcstricmp(pv, "close")){
3083
+ keep = false;
3084
+ } else if(!tcstricmp(pv, "keep-alive")){
3085
+ keep = true;
3086
+ }
3087
+ } else if(!tcstricmp(line, "content-length")){
3088
+ vsiz = tcatoi(pv);
3089
+ } else if(!tcstricmp(line, "x-tt-pdmode")){
3090
+ pdmode = tcatoi(pv);
3091
+ }
3092
+ }
3093
+ if(*uri == '/') uri++;
3094
+ int ksiz;
3095
+ char *kbuf = tcurldecode(uri, &ksiz);
3096
+ pthread_cleanup_push(free, kbuf);
3097
+ char stack[TTIOBUFSIZ];
3098
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
3099
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
3100
+ if(vsiz >= 0 && ttsockrecv(sock, vbuf, vsiz) && !ttsockcheckend(sock)){
3101
+ TCXSTR *xstr = tcxstrnew();
3102
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
3103
+ if(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLHTTP) | (1ULL << TTSEQALLWRITE))){
3104
+ int len = sprintf(line, "Forbidden\n");
3105
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3106
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3107
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3108
+ tcxstrprintf(xstr, "\r\n");
3109
+ tcxstrcat(xstr, line, len);
3110
+ ttservlog(g_serv, TTLOGINFO, "do_http_put: forbidden");
3111
+ } else {
3112
+ switch(pdmode){
3113
+ case 1:
3114
+ if(tculogadbputkeep(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
3115
+ int len = sprintf(line, "Created\n");
3116
+ tcxstrprintf(xstr, "HTTP/1.1 201 Created\r\n");
3117
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3118
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3119
+ tcxstrprintf(xstr, "\r\n");
3120
+ tcxstrcat(xstr, line, len);
3121
+ } else {
3122
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
3123
+ int len = sprintf(line, "Conflict\n");
3124
+ tcxstrprintf(xstr, "HTTP/1.1 409 Conflict\r\n");
3125
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3126
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3127
+ tcxstrprintf(xstr, "\r\n");
3128
+ tcxstrcat(xstr, line, len);
3129
+ }
3130
+ break;
3131
+ case 2:
3132
+ if(tculogadbputcat(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
3133
+ int len = sprintf(line, "Created\n");
3134
+ tcxstrprintf(xstr, "HTTP/1.1 201 Created\r\n");
3135
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3136
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3137
+ tcxstrprintf(xstr, "\r\n");
3138
+ tcxstrcat(xstr, line, len);
3139
+ } else {
3140
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
3141
+ int len = sprintf(line, "Internal Server Error\n");
3142
+ tcxstrprintf(xstr, "HTTP/1.1 500 Internal Server Error\r\n");
3143
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3144
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3145
+ tcxstrprintf(xstr, "\r\n");
3146
+ tcxstrcat(xstr, line, len);
3147
+ ttservlog(g_serv, TTLOGERROR, "do_http_put: operation failed");
3148
+ }
3149
+ break;
3150
+ default:
3151
+ if(tculogadbput(ulog, sid, 0, adb, kbuf, ksiz, vbuf, vsiz)){
3152
+ int len = sprintf(line, "Created\n");
3153
+ tcxstrprintf(xstr, "HTTP/1.1 201 Created\r\n");
3154
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3155
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3156
+ tcxstrprintf(xstr, "\r\n");
3157
+ tcxstrcat(xstr, line, len);
3158
+ } else {
3159
+ arg->counts[TTSEQNUM*req->idx+TTSEQPUTMISS]++;
3160
+ int len = sprintf(line, "Internal Server Error\n");
3161
+ tcxstrprintf(xstr, "HTTP/1.1 500 Internal Server Error\r\n");
3162
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3163
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3164
+ tcxstrprintf(xstr, "\r\n");
3165
+ tcxstrcat(xstr, line, len);
3166
+ ttservlog(g_serv, TTLOGERROR, "do_http_put: operation failed");
3167
+ }
3168
+ }
3169
+ }
3170
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
3171
+ req->keep = keep;
3172
+ } else {
3173
+ ttservlog(g_serv, TTLOGINFO, "do_http_put: response failed");
3174
+ }
3175
+ pthread_cleanup_pop(1);
3176
+ } else {
3177
+ ttservlog(g_serv, TTLOGINFO, "do_http_put: invalid entity");
3178
+ }
3179
+ pthread_cleanup_pop(1);
3180
+ pthread_cleanup_pop(1);
3181
+ }
3182
+
3183
+
3184
+ /* handle the HTTP POST command */
3185
+ static void do_http_post(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
3186
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_post command");
3187
+ arg->counts[TTSEQNUM*req->idx+TTSEQEXT]++;
3188
+ uint64_t mask = arg->mask;
3189
+ pthread_mutex_t *rmtxs = arg->rmtxs;
3190
+ void *scr = arg->screxts[req->idx];
3191
+ TCADB *adb = arg->adb;
3192
+ TCULOG *ulog = arg->ulog;
3193
+ uint32_t sid = arg->sid;
3194
+ bool keep = ver >= 1;
3195
+ int vsiz = 0;
3196
+ char ctype[LINEBUFSIZ/4+1];
3197
+ *ctype = '\0';
3198
+ char xname[LINEBUFSIZ/4+1];
3199
+ *xname = '\0';
3200
+ char mname[LINEBUFSIZ/4+1];
3201
+ *mname = '\0';
3202
+ int xopts = 0;
3203
+ int mopts = 0;
3204
+ char line[LINEBUFSIZ];
3205
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
3206
+ char *pv = strchr(line, ':');
3207
+ if(!pv) continue;
3208
+ *(pv++) = '\0';
3209
+ while(*pv == ' ' || *pv == '\t'){
3210
+ pv++;
3211
+ }
3212
+ if(!tcstricmp(line, "connection")){
3213
+ if(!tcstricmp(pv, "close")){
3214
+ keep = false;
3215
+ } else if(!tcstricmp(pv, "keep-alive")){
3216
+ keep = true;
3217
+ }
3218
+ } else if(!tcstricmp(line, "content-length")){
3219
+ vsiz = tcatoi(pv);
3220
+ } else if(!tcstricmp(line, "content-type")){
3221
+ snprintf(ctype, sizeof(ctype), "%s", pv);
3222
+ ctype[sizeof(ctype)-1] = '\0';
3223
+ } else if(!tcstricmp(line, "x-tt-xname")){
3224
+ snprintf(xname, sizeof(xname), "%s", pv);
3225
+ xname[sizeof(xname)-1] = '\0';
3226
+ } else if(!tcstricmp(line, "x-tt-mname")){
3227
+ snprintf(mname, sizeof(mname), "%s", pv);
3228
+ mname[sizeof(mname)-1] = '\0';
3229
+ } else if(!tcstricmp(line, "x-tt-xopts")){
3230
+ xopts = tcatoi(pv);
3231
+ } else if(!tcstricmp(line, "x-tt-mopts")){
3232
+ mopts = tcatoi(pv);
3233
+ }
3234
+ }
3235
+ if(*uri == '/') uri++;
3236
+ int ksiz;
3237
+ char *kbuf = tcurldecode(uri, &ksiz);
3238
+ pthread_cleanup_push(free, kbuf);
3239
+ char stack[TTIOBUFSIZ];
3240
+ char *vbuf = (vsiz < TTIOBUFSIZ) ? stack : tcmalloc(vsiz + 1);
3241
+ pthread_cleanup_push(free, (vbuf == stack) ? NULL : vbuf);
3242
+ if(vsiz >= 0 && ttsockrecv(sock, vbuf, vsiz) && !ttsockcheckend(sock)){
3243
+ TCXSTR *xstr = tcxstrnew();
3244
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
3245
+ if(*xname != '\0'){
3246
+ if(mask & ((1ULL << TTSEQEXT) | (1ULL << TTSEQALLHTTP))){
3247
+ int len = sprintf(line, "Forbidden\n");
3248
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3249
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3250
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3251
+ tcxstrprintf(xstr, "\r\n");
3252
+ tcxstrcat(xstr, line, len);
3253
+ ttservlog(g_serv, TTLOGINFO, "do_http_post: forbidden");
3254
+ } else {
3255
+ int xsiz = 0;
3256
+ char *xbuf = NULL;
3257
+ if(scr){
3258
+ if(xopts & RDBXOLCKGLB){
3259
+ bool err = false;
3260
+ for(int i = 0; i < RECMTXNUM; i++){
3261
+ if(pthread_mutex_lock(rmtxs + i) != 0){
3262
+ ttservlog(g_serv, TTLOGERROR, "do_http_post: pthread_mutex_lock failed");
3263
+ while(--i >= 0){
3264
+ pthread_mutex_unlock(rmtxs + i);
3265
+ }
3266
+ err = true;
3267
+ break;
3268
+ }
3269
+ }
3270
+ if(!err){
3271
+ xbuf = scrextcallmethod(scr, xname, kbuf, ksiz, vbuf, vsiz, &xsiz);
3272
+ for(int i = RECMTXNUM - 1; i >= 0; i--){
3273
+ if(pthread_mutex_unlock(rmtxs + i) != 0)
3274
+ ttservlog(g_serv, TTLOGERROR, "do_http_post: pthread_mutex_unlock failed");
3275
+ }
3276
+ }
3277
+ } else if(xopts & RDBXOLCKREC){
3278
+ int mtxidx = recmtxidx(kbuf, ksiz);
3279
+ if(pthread_mutex_lock(rmtxs + mtxidx) == 0){
3280
+ xbuf = scrextcallmethod(scr, xname, kbuf, ksiz, vbuf, vsiz, &xsiz);
3281
+ if(pthread_mutex_unlock(rmtxs + mtxidx) != 0)
3282
+ ttservlog(g_serv, TTLOGERROR, "do_http_post: pthread_mutex_unlock failed");
3283
+ } else {
3284
+ ttservlog(g_serv, TTLOGERROR, "do_http_post: pthread_mutex_lock failed");
3285
+ }
3286
+ } else {
3287
+ xbuf = scrextcallmethod(scr, xname, kbuf, ksiz, vbuf, vsiz, &xsiz);
3288
+ }
3289
+ }
3290
+ if(xbuf){
3291
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
3292
+ tcxstrprintf(xstr, "Content-Type: application/octet-stream\r\n");
3293
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", xsiz);
3294
+ tcxstrprintf(xstr, "\r\n");
3295
+ tcxstrcat(xstr, xbuf, xsiz);
3296
+ tcfree(xbuf);
3297
+ } else {
3298
+ int len = sprintf(line, "Internal Server Error\n");
3299
+ tcxstrprintf(xstr, "HTTP/1.1 500 Internal Server Error\r\n");
3300
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3301
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3302
+ tcxstrprintf(xstr, "\r\n");
3303
+ tcxstrcat(xstr, line, len);
3304
+ }
3305
+ }
3306
+ } else if(*mname != '\0'){
3307
+ if(mask & ((1ULL << TTSEQMISC) | (1ULL << TTSEQALLHTTP))){
3308
+ int len = sprintf(line, "Forbidden\n");
3309
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3310
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3311
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3312
+ tcxstrprintf(xstr, "\r\n");
3313
+ tcxstrcat(xstr, line, len);
3314
+ ttservlog(g_serv, TTLOGINFO, "do_http_post: forbidden");
3315
+ } else {
3316
+ TCMAP *params = tcmapnew2(1);
3317
+ pthread_cleanup_push((void (*)(void *))tcmapdel, params);
3318
+ if(vsiz > 0) tcwwwformdecode2(vbuf, vsiz, ctype, params);
3319
+ TCLIST *args = tcmapvals(params);
3320
+ pthread_cleanup_push((void (*)(void *))tclistdel, args);
3321
+ TCLIST *res = (mopts & RDBMONOULOG) ?
3322
+ tcadbmisc(adb, mname, args) : tculogadbmisc(ulog, sid, 0, adb, mname, args);
3323
+ if(res){
3324
+ TCXSTR *rbuf = tcxstrnew();
3325
+ for(int i = 0; i < tclistnum(res); i++){
3326
+ int esiz;
3327
+ const char *ebuf = tclistval(res, i, &esiz);
3328
+ if(i > 0) tcxstrcat(rbuf, "&", 1);
3329
+ tcxstrprintf(rbuf, "res%d=", i + 1);
3330
+ char *enc = tcurlencode(ebuf, esiz);
3331
+ tcxstrcat2(rbuf, enc);
3332
+ tcfree(enc);
3333
+ }
3334
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
3335
+ tcxstrprintf(xstr, "Content-Type: application/x-www-form-urlencoded\r\n");
3336
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", tcxstrsize(rbuf));
3337
+ tcxstrprintf(xstr, "\r\n");
3338
+ tcxstrcat(xstr, tcxstrptr(rbuf), tcxstrsize(rbuf));
3339
+ tcxstrdel(rbuf);
3340
+ tclistdel(res);
3341
+ } else {
3342
+ int len = sprintf(line, "Internal Server Error\n");
3343
+ tcxstrprintf(xstr, "HTTP/1.1 500 Internal Server Error\r\n");
3344
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3345
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3346
+ tcxstrprintf(xstr, "\r\n");
3347
+ tcxstrcat(xstr, line, len);
3348
+ }
3349
+ pthread_cleanup_pop(1);
3350
+ pthread_cleanup_pop(1);
3351
+ }
3352
+ } else {
3353
+ int len = sprintf(line, "Bad Request\n");
3354
+ tcxstrprintf(xstr, "HTTP/1.1 400 Bad Request\r\n");
3355
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3356
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3357
+ tcxstrprintf(xstr, "\r\n");
3358
+ tcxstrcat(xstr, line, len);
3359
+ ttservlog(g_serv, TTLOGINFO, "do_http_post: bad request");
3360
+ }
3361
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
3362
+ req->keep = keep;
3363
+ } else {
3364
+ ttservlog(g_serv, TTLOGINFO, "do_http_post: response failed");
3365
+ }
3366
+ pthread_cleanup_pop(1);
3367
+ } else {
3368
+ ttservlog(g_serv, TTLOGINFO, "do_http_post: invalid entity");
3369
+ }
3370
+ pthread_cleanup_pop(1);
3371
+ pthread_cleanup_pop(1);
3372
+ }
3373
+
3374
+
3375
+ /* handle the HTTP DELETE command */
3376
+ static void do_http_delete(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
3377
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_delete command");
3378
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUT]++;
3379
+ uint64_t mask = arg->mask;
3380
+ TCADB *adb = arg->adb;
3381
+ TCULOG *ulog = arg->ulog;
3382
+ uint32_t sid = arg->sid;
3383
+ bool keep = ver >= 1;
3384
+ char line[LINEBUFSIZ];
3385
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
3386
+ char *pv = strchr(line, ':');
3387
+ if(!pv) continue;
3388
+ *(pv++) = '\0';
3389
+ while(*pv == ' ' || *pv == '\t'){
3390
+ pv++;
3391
+ }
3392
+ if(!tcstricmp(line, "connection")){
3393
+ if(!tcstricmp(pv, "close")){
3394
+ keep = false;
3395
+ } else if(!tcstricmp(pv, "keep-alive")){
3396
+ keep = true;
3397
+ }
3398
+ }
3399
+ }
3400
+ if(*uri == '/') uri++;
3401
+ int ksiz;
3402
+ char *kbuf = tcurldecode(uri, &ksiz);
3403
+ pthread_cleanup_push(free, kbuf);
3404
+ TCXSTR *xstr = tcxstrnew();
3405
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
3406
+ if(mask & ((1ULL << TTSEQOUT) | (1ULL << TTSEQALLHTTP) | (1ULL << TTSEQALLWRITE))){
3407
+ int len = sprintf(line, "Forbidden\n");
3408
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3409
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3410
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3411
+ tcxstrprintf(xstr, "\r\n");
3412
+ tcxstrcat(xstr, line, len);
3413
+ ttservlog(g_serv, TTLOGINFO, "do_http_delete: forbidden");
3414
+ } else {
3415
+ if(tculogadbout(ulog, sid, 0, adb, kbuf, ksiz)){
3416
+ int len = sprintf(line, "OK\n");
3417
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
3418
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3419
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3420
+ tcxstrprintf(xstr, "\r\n");
3421
+ tcxstrcat(xstr, line, len);
3422
+ } else {
3423
+ arg->counts[TTSEQNUM*req->idx+TTSEQOUTMISS]++;
3424
+ int len = sprintf(line, "Not Found\n");
3425
+ tcxstrprintf(xstr, "HTTP/1.1 404 Not Found\r\n");
3426
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3427
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3428
+ tcxstrprintf(xstr, "\r\n");
3429
+ tcxstrcat(xstr, line, len);
3430
+ }
3431
+ }
3432
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
3433
+ req->keep = keep;
3434
+ } else {
3435
+ ttservlog(g_serv, TTLOGINFO, "do_http_delete: response failed");
3436
+ }
3437
+ pthread_cleanup_pop(1);
3438
+ pthread_cleanup_pop(1);
3439
+ }
3440
+
3441
+
3442
+ /* handle the HTTP OPTIONS command */
3443
+ static void do_http_options(TTSOCK *sock, TASKARG *arg, TTREQ *req, int ver, const char *uri){
3444
+ ttservlog(g_serv, TTLOGDEBUG, "doing http_options command");
3445
+ arg->counts[TTSEQNUM*req->idx+TTSEQSTAT]++;
3446
+ uint64_t mask = arg->mask;
3447
+ TCADB *adb = arg->adb;
3448
+ REPLARG *sarg = arg->sarg;
3449
+ bool keep = ver >= 1;
3450
+ char line[LINEBUFSIZ];
3451
+ while(ttsockgets(sock, line, LINEBUFSIZ) && *line != '\0'){
3452
+ char *pv = strchr(line, ':');
3453
+ if(!pv) continue;
3454
+ *(pv++) = '\0';
3455
+ while(*pv == ' ' || *pv == '\t'){
3456
+ pv++;
3457
+ }
3458
+ if(!tcstricmp(line, "connection")){
3459
+ if(!tcstricmp(pv, "close")){
3460
+ keep = false;
3461
+ } else if(!tcstricmp(pv, "keep-alive")){
3462
+ keep = true;
3463
+ }
3464
+ }
3465
+ }
3466
+ TCXSTR *xstr = tcxstrnew();
3467
+ pthread_cleanup_push((void (*)(void *))tcxstrdel, xstr);
3468
+ if(mask & ((1ULL << TTSEQSTAT) | (1ULL << TTSEQALLORG) | (1ULL << TTSEQALLREAD))){
3469
+ int len = sprintf(line, "Forbidden\n");
3470
+ tcxstrprintf(xstr, "HTTP/1.1 403 Forbidden\r\n");
3471
+ tcxstrprintf(xstr, "Content-Type: text/plain\r\n");
3472
+ tcxstrprintf(xstr, "Content-Length: %d\r\n", len);
3473
+ tcxstrprintf(xstr, "\r\n");
3474
+ tcxstrcat(xstr, line, len);
3475
+ ttservlog(g_serv, TTLOGINFO, "do_http_options: forbidden");
3476
+ } else {
3477
+ double now = tctime();
3478
+ tcxstrprintf(xstr, "HTTP/1.1 200 OK\r\n");
3479
+ tcxstrprintf(xstr, "Content-Length: 0\r\n");
3480
+ tcxstrprintf(xstr, "Allow: OPTIONS");
3481
+ if(!(mask & ((1ULL << TTSEQGET) | (1ULL << TTSEQALLREAD)))) tcxstrprintf(xstr, ", GET");
3482
+ if(!(mask & ((1ULL << TTSEQVSIZ) | (1ULL << TTSEQALLREAD)))) tcxstrprintf(xstr, ", HEAD");
3483
+ if(!(mask & ((1ULL << TTSEQPUT) | (1ULL << TTSEQALLWRITE)))) tcxstrprintf(xstr, ", PUT");
3484
+ if(!(mask & ((1ULL << TTSEQEXT) | (1ULL << TTSEQALLWRITE)))) tcxstrprintf(xstr, ", POST");
3485
+ if(!(mask & ((1ULL << TTSEQOUT) | (1ULL << TTSEQALLWRITE)))) tcxstrprintf(xstr, ", DELETE");
3486
+ tcxstrprintf(xstr, "\r\n");
3487
+ tcxstrprintf(xstr, "X-TT-VERSION: %s\r\n", ttversion);
3488
+ tcxstrprintf(xstr, "X-TT-LIBVER: %d\r\n", _TT_LIBVER);
3489
+ tcxstrprintf(xstr, "X-TT-PROTVER: %s\r\n", _TT_PROTVER);
3490
+ tcxstrprintf(xstr, "X-TT-OS: %s\r\n", TTSYSNAME);
3491
+ tcxstrprintf(xstr, "X-TT-TIME: %.6f\r\n", now);
3492
+ tcxstrprintf(xstr, "X-TT-PID: %lld\r\n", (long long)getpid());
3493
+ tcxstrprintf(xstr, "X-TT-SID: %d\r\n", arg->sid);
3494
+ switch(tcadbomode(adb)){
3495
+ case ADBOVOID: tcxstrprintf(xstr, "X-TT-TYPE: void\r\n"); break;
3496
+ case ADBOMDB: tcxstrprintf(xstr, "X-TT-TYPE: on-memory hash\r\n"); break;
3497
+ case ADBONDB: tcxstrprintf(xstr, "X-TT-TYPE: on-memory tree\r\n"); break;
3498
+ case ADBOHDB: tcxstrprintf(xstr, "X-TT-TYPE: hash\r\n"); break;
3499
+ case ADBOBDB: tcxstrprintf(xstr, "X-TT-TYPE: B+ tree\r\n"); break;
3500
+ case ADBOFDB: tcxstrprintf(xstr, "X-TT-TYPE: fixed-length\r\n"); break;
3501
+ case ADBOTDB: tcxstrprintf(xstr, "X-TT-TYPE: table\r\n"); break;
3502
+ case ADBOSKEL: tcxstrprintf(xstr, "X-TT-TYPE: skeleton\r\n"); break;
3503
+ }
3504
+ const char *path = tcadbpath(adb);
3505
+ if(path) tcxstrprintf(xstr, "X-TT-PATH: %s\r\n", path);
3506
+ tcxstrprintf(xstr, "X-TT-RNUM: %llu\r\n", (unsigned long long)tcadbrnum(adb));
3507
+ tcxstrprintf(xstr, "X-TT-SIZE: %llu\r\n", (unsigned long long)tcadbsize(adb));
3508
+ tcxstrprintf(xstr, "X-TT-BIGEND: %d\r\n", TTBIGEND);
3509
+ if(sarg->host[0] != '\0'){
3510
+ tcxstrprintf(xstr, "X-TT-MHOST: %s\r\n", sarg->host);
3511
+ tcxstrprintf(xstr, "X-TT-MPORT: %d\r\n", sarg->port);
3512
+ tcxstrprintf(xstr, "X-TT-RTS: %llu\r\n", (unsigned long long)sarg->rts);
3513
+ double delay = now - sarg->rts / 1000000.0;
3514
+ tcxstrprintf(xstr, "X-TT-DELAY: %.6f\r\n", delay >= 0 ? delay : 0.0);
3515
+ }
3516
+ tcxstrprintf(xstr, "X-TT-FD: %d\r\n", sock->fd);
3517
+ tcxstrprintf(xstr, "X-TT-LOADAVG: %.6f\r\n", ttgetloadavg());
3518
+ TCMAP *info = tcsysinfo();
3519
+ if(info){
3520
+ const char *vbuf = tcmapget2(info, "size");
3521
+ if(vbuf) tcxstrprintf(xstr, "X-TT-MEMSIZE: %s\r\n", vbuf);
3522
+ vbuf = tcmapget2(info, "rss");
3523
+ if(vbuf) tcxstrprintf(xstr, "X-TT-MEMRSS: %s\r\n", vbuf);
3524
+ tcmapdel(info);
3525
+ }
3526
+ tcxstrprintf(xstr, "X-TT-RU_REAL: %.6f\r\n", now - g_starttime);
3527
+ struct rusage ubuf;
3528
+ memset(&ubuf, 0, sizeof(ubuf));
3529
+ if(getrusage(RUSAGE_SELF, &ubuf) == 0){
3530
+ tcxstrprintf(xstr, "X-TT-RU_USER: %d.%06d\r\n",
3531
+ (int)ubuf.ru_utime.tv_sec, (int)ubuf.ru_utime.tv_usec);
3532
+ tcxstrprintf(xstr, "X-TT-RU_SYS: %d.%06d\r\n",
3533
+ (int)ubuf.ru_stime.tv_sec, (int)ubuf.ru_stime.tv_usec);
3534
+ }
3535
+ tcxstrprintf(xstr, "\r\n");
3536
+ }
3537
+ if(ttsocksend(sock, tcxstrptr(xstr), tcxstrsize(xstr))){
3538
+ req->keep = keep;
3539
+ } else {
3540
+ ttservlog(g_serv, TTLOGINFO, "do_http_options: response failed");
3541
+ }
3542
+ pthread_cleanup_pop(1);
3543
+ }
3544
+
3545
+
3546
+ /* handle the termination event */
3547
+ static void do_term(void *opq){
3548
+ TERMARG *arg = (TERMARG *)opq;
3549
+ int thnum = arg->thnum;
3550
+ TCADB *adb = arg->adb;
3551
+ REPLARG *sarg = arg->sarg;
3552
+ void **screxts = arg->screxts;
3553
+ EXTPCARG *pcargs = arg->pcargs;
3554
+ int pcnum = arg->pcnum;
3555
+ if(sarg->host[0] != '\0') tcsleep(REPLPERIOD * 1.2);
3556
+ if(g_restart) return;
3557
+ if(pcargs){
3558
+ for(int i = 0; i < pcnum; i++){
3559
+ EXTPCARG *pcarg = pcargs + i;
3560
+ if(!pcarg->scrext) continue;
3561
+ if(!scrextkill(pcarg->scrext)){
3562
+ arg->err = true;
3563
+ ttservlog(g_serv, TTLOGERROR, "scrextkill failed");
3564
+ }
3565
+ }
3566
+ }
3567
+ for(int i = 0; i < thnum; i++){
3568
+ if(!screxts[i]) continue;
3569
+ if(!scrextkill(screxts[i])){
3570
+ arg->err = true;
3571
+ ttservlog(g_serv, TTLOGERROR, "scrextkill failed");
3572
+ }
3573
+ }
3574
+ ttservlog(g_serv, TTLOGSYSTEM, "closing the database");
3575
+ if(!tcadbclose(adb)){
3576
+ arg->err = true;
3577
+ ttservlog(g_serv, TTLOGERROR, "tcadbclose failed");
3578
+ }
3579
+ }
3580
+
3581
+
3582
+
3583
+ // END OF FILE