droonga-engine 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. data/.dir-locals.el +3 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +15 -0
  4. data/.yardopts +7 -0
  5. data/Gemfile +66 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +17 -0
  8. data/Rakefile +64 -0
  9. data/benchmark/benchmark.rb +123 -0
  10. data/benchmark/utils.rb +246 -0
  11. data/benchmark/watch/benchmark-notify.rb +143 -0
  12. data/benchmark/watch/benchmark-notify.sh +20 -0
  13. data/benchmark/watch/benchmark-publish.rb +120 -0
  14. data/benchmark/watch/benchmark-scan.rb +213 -0
  15. data/bin/droonga-catalog-generate +103 -0
  16. data/bin/droonga-engine +20 -0
  17. data/bin/droonga-engine-service +20 -0
  18. data/doc/text/news.md +106 -0
  19. data/droonga-engine.gemspec +52 -0
  20. data/lib/droonga/adapter.rb +48 -0
  21. data/lib/droonga/adapter_runner.rb +104 -0
  22. data/lib/droonga/catalog/base.rb +41 -0
  23. data/lib/droonga/catalog/collection_volume.rb +106 -0
  24. data/lib/droonga/catalog/dataset.rb +69 -0
  25. data/lib/droonga/catalog/errors.rb +113 -0
  26. data/lib/droonga/catalog/schema.rb +186 -0
  27. data/lib/droonga/catalog/single_volume.rb +28 -0
  28. data/lib/droonga/catalog/slice.rb +41 -0
  29. data/lib/droonga/catalog/version1.rb +427 -0
  30. data/lib/droonga/catalog/version2.rb +96 -0
  31. data/lib/droonga/catalog/version2_validator.rb +63 -0
  32. data/lib/droonga/catalog/volume.rb +33 -0
  33. data/lib/droonga/catalog/volume_collection.rb +56 -0
  34. data/lib/droonga/catalog_generator.rb +156 -0
  35. data/lib/droonga/catalog_loader.rb +56 -0
  36. data/lib/droonga/catalog_observer.rb +83 -0
  37. data/lib/droonga/collector.rb +38 -0
  38. data/lib/droonga/collector_message.rb +71 -0
  39. data/lib/droonga/collector_runner.rb +64 -0
  40. data/lib/droonga/collectors/and.rb +26 -0
  41. data/lib/droonga/collectors/or.rb +26 -0
  42. data/lib/droonga/collectors/sum.rb +26 -0
  43. data/lib/droonga/collectors.rb +18 -0
  44. data/lib/droonga/dispatcher.rb +326 -0
  45. data/lib/droonga/distributed_command_planner.rb +179 -0
  46. data/lib/droonga/distributor.rb +87 -0
  47. data/lib/droonga/engine/command/droonga_engine.rb +441 -0
  48. data/lib/droonga/engine/version.rb +20 -0
  49. data/lib/droonga/engine.rb +80 -0
  50. data/lib/droonga/engine_state.rb +79 -0
  51. data/lib/droonga/error.rb +73 -0
  52. data/lib/droonga/error_messages.rb +33 -0
  53. data/lib/droonga/event_loop.rb +46 -0
  54. data/lib/droonga/farm.rb +58 -0
  55. data/lib/droonga/fluent_message_receiver.rb +191 -0
  56. data/lib/droonga/fluent_message_sender.rb +140 -0
  57. data/lib/droonga/forwarder.rb +119 -0
  58. data/lib/droonga/handler.rb +49 -0
  59. data/lib/droonga/handler_message.rb +61 -0
  60. data/lib/droonga/handler_messenger.rb +119 -0
  61. data/lib/droonga/handler_runner.rb +125 -0
  62. data/lib/droonga/input_message.rb +51 -0
  63. data/lib/droonga/job_protocol.rb +20 -0
  64. data/lib/droonga/job_pusher.rb +179 -0
  65. data/lib/droonga/job_receiver.rb +70 -0
  66. data/lib/droonga/loggable.rb +29 -0
  67. data/lib/droonga/logger.rb +142 -0
  68. data/lib/droonga/message_matcher.rb +109 -0
  69. data/lib/droonga/output_message.rb +55 -0
  70. data/lib/droonga/planner.rb +47 -0
  71. data/lib/droonga/pluggable.rb +31 -0
  72. data/lib/droonga/plugin/metadata/adapter_input_message.rb +39 -0
  73. data/lib/droonga/plugin/metadata/adapter_output_message.rb +39 -0
  74. data/lib/droonga/plugin/metadata/collector_message.rb +39 -0
  75. data/lib/droonga/plugin/metadata/handler_action.rb +39 -0
  76. data/lib/droonga/plugin/metadata/input_message.rb +54 -0
  77. data/lib/droonga/plugin.rb +43 -0
  78. data/lib/droonga/plugin_loader.rb +63 -0
  79. data/lib/droonga/plugin_registry.rb +66 -0
  80. data/lib/droonga/plugins/basic.rb +54 -0
  81. data/lib/droonga/plugins/crud.rb +145 -0
  82. data/lib/droonga/plugins/dump.rb +97 -0
  83. data/lib/droonga/plugins/error.rb +51 -0
  84. data/lib/droonga/plugins/groonga/column_create.rb +123 -0
  85. data/lib/droonga/plugins/groonga/column_list.rb +124 -0
  86. data/lib/droonga/plugins/groonga/column_remove.rb +65 -0
  87. data/lib/droonga/plugins/groonga/column_rename.rb +67 -0
  88. data/lib/droonga/plugins/groonga/delete.rb +117 -0
  89. data/lib/droonga/plugins/groonga/generic_command.rb +105 -0
  90. data/lib/droonga/plugins/groonga/generic_response.rb +43 -0
  91. data/lib/droonga/plugins/groonga/select.rb +236 -0
  92. data/lib/droonga/plugins/groonga/table_create.rb +111 -0
  93. data/lib/droonga/plugins/groonga/table_list.rb +120 -0
  94. data/lib/droonga/plugins/groonga/table_remove.rb +57 -0
  95. data/lib/droonga/plugins/groonga.rb +37 -0
  96. data/lib/droonga/plugins/search/distributed_search_planner.rb +407 -0
  97. data/lib/droonga/plugins/search.rb +146 -0
  98. data/lib/droonga/plugins/watch.rb +178 -0
  99. data/lib/droonga/processor.rb +63 -0
  100. data/lib/droonga/reducer.rb +169 -0
  101. data/lib/droonga/replier.rb +49 -0
  102. data/lib/droonga/schema_applier.rb +167 -0
  103. data/lib/droonga/searcher/mecab_filter.rb +67 -0
  104. data/lib/droonga/searcher.rb +733 -0
  105. data/lib/droonga/server.rb +45 -0
  106. data/lib/droonga/session.rb +99 -0
  107. data/lib/droonga/single_step.rb +68 -0
  108. data/lib/droonga/single_step_definition.rb +54 -0
  109. data/lib/droonga/slice.rb +122 -0
  110. data/lib/droonga/status_code.rb +25 -0
  111. data/lib/droonga/step_runner.rb +64 -0
  112. data/lib/droonga/sweeper.rb +42 -0
  113. data/lib/droonga/test/stub_handler.rb +37 -0
  114. data/lib/droonga/test/stub_handler_message.rb +35 -0
  115. data/lib/droonga/test/stub_handler_messenger.rb +34 -0
  116. data/lib/droonga/test/stub_planner.rb +31 -0
  117. data/lib/droonga/test.rb +21 -0
  118. data/lib/droonga/watch_schema.rb +92 -0
  119. data/lib/droonga/watcher.rb +257 -0
  120. data/lib/droonga/worker.rb +61 -0
  121. data/sample/cluster/catalog.json +42 -0
  122. data/sample/mecab_filter/data.grn +7 -0
  123. data/sample/mecab_filter/ddl.grn +7 -0
  124. data/sample/mecab_filter/search_with_mecab_filter.json +21 -0
  125. data/sample/mecab_filter/search_without_mecab_filter.json +21 -0
  126. data/test/command/config/default/catalog.json +85 -0
  127. data/test/command/config/default/fluentd.conf +11 -0
  128. data/test/command/config/version1/catalog.json +68 -0
  129. data/test/command/config/version1/fluentd.conf +11 -0
  130. data/test/command/fixture/documents.jsons +208 -0
  131. data/test/command/fixture/event.jsons +41 -0
  132. data/test/command/fixture/user-table-array.jsons +38 -0
  133. data/test/command/fixture/user-table.jsons +47 -0
  134. data/test/command/run-test.rb +34 -0
  135. data/test/command/suite/add/dimension/column.catalog.json +28 -0
  136. data/test/command/suite/add/dimension/column.expected +41 -0
  137. data/test/command/suite/add/dimension/column.test +51 -0
  138. data/test/command/suite/add/dimension/integer.catalog.json +19 -0
  139. data/test/command/suite/add/dimension/integer.expected +41 -0
  140. data/test/command/suite/add/dimension/integer.test +51 -0
  141. data/test/command/suite/add/error/invalid-integer.expected +46 -0
  142. data/test/command/suite/add/error/invalid-integer.test +12 -0
  143. data/test/command/suite/add/error/invalid-time.expected +46 -0
  144. data/test/command/suite/add/error/invalid-time.test +12 -0
  145. data/test/command/suite/add/error/missing-key.expected +25 -0
  146. data/test/command/suite/add/error/missing-key.test +16 -0
  147. data/test/command/suite/add/error/missing-table.expected +25 -0
  148. data/test/command/suite/add/error/missing-table.test +16 -0
  149. data/test/command/suite/add/error/unknown-column.expected +46 -0
  150. data/test/command/suite/add/error/unknown-column.test +12 -0
  151. data/test/command/suite/add/error/unknown-table.expected +25 -0
  152. data/test/command/suite/add/error/unknown-table.test +17 -0
  153. data/test/command/suite/add/minimum.expected +6 -0
  154. data/test/command/suite/add/minimum.test +11 -0
  155. data/test/command/suite/add/with-values.expected +6 -0
  156. data/test/command/suite/add/with-values.test +17 -0
  157. data/test/command/suite/add/without-key.expected +6 -0
  158. data/test/command/suite/add/without-key.test +16 -0
  159. data/test/command/suite/groonga/column_create/scalar.expected +26 -0
  160. data/test/command/suite/groonga/column_create/scalar.test +17 -0
  161. data/test/command/suite/groonga/column_create/unknown-table.expected +14 -0
  162. data/test/command/suite/groonga/column_create/unknown-table.test +7 -0
  163. data/test/command/suite/groonga/column_create/vector.expected +26 -0
  164. data/test/command/suite/groonga/column_create/vector.test +18 -0
  165. data/test/command/suite/groonga/column_list/success.expected +86 -0
  166. data/test/command/suite/groonga/column_list/success.test +24 -0
  167. data/test/command/suite/groonga/column_list/unknown-table.expected +13 -0
  168. data/test/command/suite/groonga/column_list/unknown-table.test +7 -0
  169. data/test/command/suite/groonga/column_remove/success.expected +39 -0
  170. data/test/command/suite/groonga/column_remove/success.test +25 -0
  171. data/test/command/suite/groonga/column_remove/unknown-column.expected +27 -0
  172. data/test/command/suite/groonga/column_remove/unknown-column.test +16 -0
  173. data/test/command/suite/groonga/column_remove/unknown-table.expected +14 -0
  174. data/test/command/suite/groonga/column_remove/unknown-table.test +7 -0
  175. data/test/command/suite/groonga/column_rename/success.expected +39 -0
  176. data/test/command/suite/groonga/column_rename/success.test +26 -0
  177. data/test/command/suite/groonga/column_rename/unknown-column.expected +27 -0
  178. data/test/command/suite/groonga/column_rename/unknown-column.test +16 -0
  179. data/test/command/suite/groonga/column_rename/unknown-table.expected +14 -0
  180. data/test/command/suite/groonga/column_rename/unknown-table.test +7 -0
  181. data/test/command/suite/groonga/delete/duplicated-identifiers.expected +27 -0
  182. data/test/command/suite/groonga/delete/duplicated-identifiers.test +17 -0
  183. data/test/command/suite/groonga/delete/filter.expected +19 -0
  184. data/test/command/suite/groonga/delete/filter.test +19 -0
  185. data/test/command/suite/groonga/delete/invalid-filter.expected +14 -0
  186. data/test/command/suite/groonga/delete/invalid-filter.test +9 -0
  187. data/test/command/suite/groonga/delete/no-identifier.expected +27 -0
  188. data/test/command/suite/groonga/delete/no-identifier.test +15 -0
  189. data/test/command/suite/groonga/delete/success.expected +19 -0
  190. data/test/command/suite/groonga/delete/success.test +19 -0
  191. data/test/command/suite/groonga/delete/unknown-table.expected +14 -0
  192. data/test/command/suite/groonga/delete/unknown-table.test +7 -0
  193. data/test/command/suite/groonga/select/minimum.expected +22 -0
  194. data/test/command/suite/groonga/select/minimum.test +8 -0
  195. data/test/command/suite/groonga/table_create/array.expected +14 -0
  196. data/test/command/suite/groonga/table_create/array.test +8 -0
  197. data/test/command/suite/groonga/table_create/hash.expected +13 -0
  198. data/test/command/suite/groonga/table_create/hash.test +8 -0
  199. data/test/command/suite/groonga/table_list/success.expected +71 -0
  200. data/test/command/suite/groonga/table_list/success.test +15 -0
  201. data/test/command/suite/groonga/table_remove/success.expected +13 -0
  202. data/test/command/suite/groonga/table_remove/success.test +8 -0
  203. data/test/command/suite/groonga/table_remove/unknown-table.expected +14 -0
  204. data/test/command/suite/groonga/table_remove/unknown-table.test +7 -0
  205. data/test/command/suite/message/error/missing-dataset.expected +9 -0
  206. data/test/command/suite/message/error/missing-dataset.test +5 -0
  207. data/test/command/suite/message/error/unknown-dataset.expected +9 -0
  208. data/test/command/suite/message/error/unknown-dataset.test +6 -0
  209. data/test/command/suite/message/error/unknown-type.expected +9 -0
  210. data/test/command/suite/message/error/unknown-type.test +6 -0
  211. data/test/command/suite/search/adjusters/multiple.catalog.json +38 -0
  212. data/test/command/suite/search/adjusters/multiple.expected +19 -0
  213. data/test/command/suite/search/adjusters/multiple.test +75 -0
  214. data/test/command/suite/search/adjusters/one.catalog.json +38 -0
  215. data/test/command/suite/search/adjusters/one.expected +19 -0
  216. data/test/command/suite/search/adjusters/one.test +66 -0
  217. data/test/command/suite/search/attributes/array.expected +21 -0
  218. data/test/command/suite/search/attributes/array.test +28 -0
  219. data/test/command/suite/search/attributes/hash.expected +30 -0
  220. data/test/command/suite/search/attributes/hash.test +36 -0
  221. data/test/command/suite/search/complex.expected +48 -0
  222. data/test/command/suite/search/complex.test +23 -0
  223. data/test/command/suite/search/condition/nested.expected +15 -0
  224. data/test/command/suite/search/condition/nested.test +27 -0
  225. data/test/command/suite/search/condition/query/nonexistent_column.catalog.json +37 -0
  226. data/test/command/suite/search/condition/query/nonexistent_column.expected +48 -0
  227. data/test/command/suite/search/condition/query/nonexistent_column.test +33 -0
  228. data/test/command/suite/search/condition/query/syntax_error.catalog.json +36 -0
  229. data/test/command/suite/search/condition/query/syntax_error.expected +48 -0
  230. data/test/command/suite/search/condition/query/syntax_error.test +33 -0
  231. data/test/command/suite/search/condition/query.expected +24 -0
  232. data/test/command/suite/search/condition/query.test +23 -0
  233. data/test/command/suite/search/condition/script.expected +24 -0
  234. data/test/command/suite/search/condition/script.test +26 -0
  235. data/test/command/suite/search/error/cyclic-source.expected +14 -0
  236. data/test/command/suite/search/error/cyclic-source.test +12 -0
  237. data/test/command/suite/search/error/deeply-cyclic-source.expected +17 -0
  238. data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
  239. data/test/command/suite/search/error/missing-source-parameter.expected +13 -0
  240. data/test/command/suite/search/error/missing-source-parameter.test +11 -0
  241. data/test/command/suite/search/error/no-query.expected +9 -0
  242. data/test/command/suite/search/error/no-query.test +7 -0
  243. data/test/command/suite/search/error/unknown-source.expected +52 -0
  244. data/test/command/suite/search/error/unknown-source.test +12 -0
  245. data/test/command/suite/search/group/count.expected +10 -0
  246. data/test/command/suite/search/group/count.test +18 -0
  247. data/test/command/suite/search/group/limit.expected +15 -0
  248. data/test/command/suite/search/group/limit.test +20 -0
  249. data/test/command/suite/search/group/string.expected +32 -0
  250. data/test/command/suite/search/group/string.test +40 -0
  251. data/test/command/suite/search/group/subrecord/with-sort.catalog.json +33 -0
  252. data/test/command/suite/search/group/subrecord/with-sort.expected +30 -0
  253. data/test/command/suite/search/group/subrecord/with-sort.test +81 -0
  254. data/test/command/suite/search/multiple/chained.expected +41 -0
  255. data/test/command/suite/search/multiple/chained.test +39 -0
  256. data/test/command/suite/search/multiple/parallel.expected +35 -0
  257. data/test/command/suite/search/multiple/parallel.test +35 -0
  258. data/test/command/suite/search/output/attributes/invalid.catalog.json +13 -0
  259. data/test/command/suite/search/output/attributes/invalid.expected +44 -0
  260. data/test/command/suite/search/output/attributes/invalid.test +28 -0
  261. data/test/command/suite/search/range/only-output.expected +24 -0
  262. data/test/command/suite/search/range/only-output.test +23 -0
  263. data/test/command/suite/search/range/only-sort.expected +24 -0
  264. data/test/command/suite/search/range/only-sort.test +26 -0
  265. data/test/command/suite/search/range/sort-and-output.expected +21 -0
  266. data/test/command/suite/search/range/sort-and-output.test +27 -0
  267. data/test/command/suite/search/range/too-large-output-offset.expected +12 -0
  268. data/test/command/suite/search/range/too-large-output-offset.test +23 -0
  269. data/test/command/suite/search/range/too-large-sort-offset.expected +12 -0
  270. data/test/command/suite/search/range/too-large-sort-offset.test +26 -0
  271. data/test/command/suite/search/response/elapsed_time.catalog.json +13 -0
  272. data/test/command/suite/search/response/elapsed_time.expected +11 -0
  273. data/test/command/suite/search/response/elapsed_time.test +26 -0
  274. data/test/command/suite/search/response/records/value/time.expected +20 -0
  275. data/test/command/suite/search/response/records/value/time.test +22 -0
  276. data/test/command/suite/search/simple.expected +48 -0
  277. data/test/command/suite/search/simple.test +22 -0
  278. data/test/command/suite/search/sort/default-offset-limit.expected +39 -0
  279. data/test/command/suite/search/sort/default-offset-limit.test +24 -0
  280. data/test/command/suite/search/sort/invisible-column.expected +24 -0
  281. data/test/command/suite/search/sort/invisible-column.test +26 -0
  282. data/test/command/suite/watch/subscribe.expected +6 -0
  283. data/test/command/suite/watch/subscribe.test +9 -0
  284. data/test/command/suite/watch/unsubscribe.expected +6 -0
  285. data/test/command/suite/watch/unsubscribe.test +9 -0
  286. data/test/performance/run-test.rb +56 -0
  287. data/test/performance/watch/catalog.json +33 -0
  288. data/test/performance/watch/feed.json +9 -0
  289. data/test/performance/watch/fluentd.conf +11 -0
  290. data/test/performance/watch/subscribe.json +3 -0
  291. data/test/unit/catalog/test_collection_volume.rb +103 -0
  292. data/test/unit/catalog/test_dataset.rb +104 -0
  293. data/test/unit/catalog/test_schema.rb +226 -0
  294. data/test/unit/catalog/test_single_volume.rb +31 -0
  295. data/test/unit/catalog/test_slice.rb +92 -0
  296. data/test/unit/catalog/test_version1.rb +361 -0
  297. data/test/unit/catalog/test_version2.rb +124 -0
  298. data/test/unit/catalog/test_version2_validator.rb +66 -0
  299. data/test/unit/catalog/test_volume_collection.rb +50 -0
  300. data/test/unit/fixtures/array.grn +18 -0
  301. data/test/unit/fixtures/catalog/version1.json +40 -0
  302. data/test/unit/fixtures/catalog/version2.json +62 -0
  303. data/test/unit/fixtures/document.grn +34 -0
  304. data/test/unit/fixtures/reference/array.grn +11 -0
  305. data/test/unit/fixtures/reference/hash.grn +7 -0
  306. data/test/unit/helper/distributed_search_planner_helper.rb +83 -0
  307. data/test/unit/helper/fixture.rb +28 -0
  308. data/test/unit/helper/plugin_helper.rb +38 -0
  309. data/test/unit/helper/sandbox.rb +86 -0
  310. data/test/unit/helper/stub_worker.rb +27 -0
  311. data/test/unit/helper/watch_helper.rb +23 -0
  312. data/test/unit/helper.rb +28 -0
  313. data/test/unit/plugins/crud/test_add.rb +190 -0
  314. data/test/unit/plugins/groonga/select/test_adapter_input.rb +510 -0
  315. data/test/unit/plugins/groonga/select/test_adapter_output.rb +201 -0
  316. data/test/unit/plugins/groonga/test_column_create.rb +171 -0
  317. data/test/unit/plugins/groonga/test_column_list.rb +170 -0
  318. data/test/unit/plugins/groonga/test_column_remove.rb +98 -0
  319. data/test/unit/plugins/groonga/test_column_rename.rb +105 -0
  320. data/test/unit/plugins/groonga/test_delete.rb +127 -0
  321. data/test/unit/plugins/groonga/test_table_create.rb +147 -0
  322. data/test/unit/plugins/groonga/test_table_list.rb +184 -0
  323. data/test/unit/plugins/groonga/test_table_remove.rb +61 -0
  324. data/test/unit/plugins/search/planner/test_basic.rb +120 -0
  325. data/test/unit/plugins/search/planner/test_group_by.rb +573 -0
  326. data/test/unit/plugins/search/planner/test_output.rb +388 -0
  327. data/test/unit/plugins/search/planner/test_sort_by.rb +938 -0
  328. data/test/unit/plugins/search/test_collector.rb +806 -0
  329. data/test/unit/plugins/search/test_handler.rb +930 -0
  330. data/test/unit/plugins/search/test_planner.rb +174 -0
  331. data/test/unit/plugins/test_basic.rb +510 -0
  332. data/test/unit/plugins/test_groonga.rb +70 -0
  333. data/test/unit/plugins/test_watch.rb +211 -0
  334. data/test/unit/run-test.rb +56 -0
  335. data/test/unit/test_catalog_generator.rb +93 -0
  336. data/test/unit/test_message_matcher.rb +160 -0
  337. data/test/unit/test_schema_applier.rb +59 -0
  338. data/test/unit/test_sweeper.rb +95 -0
  339. data/test/unit/test_watch_schema.rb +57 -0
  340. data/test/unit/test_watcher.rb +336 -0
  341. metadata +759 -0
@@ -0,0 +1,61 @@
1
+ # Copyright (C) 2013 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ module Droonga
17
+ class HandlerMessage
18
+ attr_reader :raw
19
+ def initialize(raw)
20
+ @raw = raw
21
+ end
22
+
23
+ def validate
24
+ unless task.is_a?(Hash)
25
+ raise "<task> value isn't object: <#{@raw.inspect}>"
26
+ end
27
+
28
+ unless step.is_a?(Hash)
29
+ raise "<task/step> value isn't object: <#{@raw.inspect}>"
30
+ end
31
+ end
32
+
33
+ def [](name)
34
+ @raw[name]
35
+ end
36
+
37
+ def body
38
+ @body ||= self["body"]
39
+ end
40
+
41
+ def task
42
+ @task ||= body["task"]
43
+ end
44
+
45
+ def step
46
+ @step ||= task["step"]
47
+ end
48
+
49
+ def request
50
+ @request ||= step["body"]
51
+ end
52
+
53
+ def id
54
+ @id ||= body["id"]
55
+ end
56
+
57
+ def descendants
58
+ @descendants ||= body["descendants"]
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,119 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "droonga/replier"
17
+ require "droonga/forwarder"
18
+
19
+ module Droonga
20
+ class HandlerMessenger
21
+ attr_reader :database_name
22
+
23
+ def initialize(forwarder, message, options={})
24
+ @forwarder = forwarder
25
+ @message = message
26
+ @options = options
27
+ @replier = Replier.new(@forwarder)
28
+ @dispatcher = @options[:dispatcher]
29
+ @database_name = options[:database]
30
+ end
31
+
32
+ def emit(value)
33
+ descendants = @message.descendants
34
+ raw_message = @message.raw
35
+ if descendants.empty?
36
+ return if raw_message["replyTo"].nil?
37
+ @replier.reply(raw_message.merge("body" => value))
38
+ else
39
+ descendants.each do |name, dests|
40
+ body = {
41
+ "id" => @message.id,
42
+ "input" => name,
43
+ "value" => value[name],
44
+ }
45
+ dests.each do |dest|
46
+ if @dispatcher
47
+ @dispatcher.dispatch(body, dest)
48
+ else
49
+ message = raw_message.merge("body" => body)
50
+ forward(message, "to" => dest, "type" => "dispatcher")
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ def error(status_code, body)
58
+ descendants = @message.descendants
59
+ raw_message = @message.raw
60
+ if descendants.empty?
61
+ return if raw_message["replyTo"].nil?
62
+ response = raw_message.merge("statusCode" => status_code,
63
+ "body" => body)
64
+ @replier.reply(response)
65
+ else
66
+ #XXX This is just a temporary solution. We should rewrite this,
67
+ # to put errors outside of the message body. Otherwise
68
+ # plugins cannot use the name "errors" for their message body.
69
+ body = {
70
+ "id" => @message.id,
71
+ "input" => "errors",
72
+ "value" => {
73
+ database_name => {
74
+ "statusCode" => status_code,
75
+ "body" => body,
76
+ },
77
+ },
78
+ }
79
+ all_dests = []
80
+ descendants.each do |name, dests|
81
+ all_dests += dests
82
+ end
83
+ all_dests.each do |dest|
84
+ if @dispatcher
85
+ @dispatcher.dispatch(body, dest)
86
+ else
87
+ message = raw_message.merge("statusCode" => status_code,
88
+ "body" => body,)
89
+ forward(message, "to" => dest, "type" => "dispatcher")
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ # Forwards a Droonga message to other Droonga Engine.
96
+ #
97
+ # @param [Hash] droonga_message
98
+ # The Droonga message to be forwarded.
99
+ # @param [Hash] destination
100
+ # The destination of the Droonga message. See {Forwarder#forward} to
101
+ # know about how to specify destination.
102
+ #
103
+ # @return [void]
104
+ #
105
+ # @see Forwarder#forward
106
+ def forward(droonga_message, destination)
107
+ @forwarder.forward(droonga_message, destination)
108
+ end
109
+
110
+ def inspect
111
+ "\#<#{self.class} id=#{object_id}>"
112
+ end
113
+
114
+ private
115
+ def log_tag
116
+ "[#{Process.ppid}][#{Process.pid}] handler_messenger"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,125 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "groonga"
17
+
18
+ require "droonga/loggable"
19
+ require "droonga/forwarder"
20
+ require "droonga/handler_message"
21
+ require "droonga/handler_messenger"
22
+ require "droonga/step_runner"
23
+
24
+ module Droonga
25
+ class HandlerRunner
26
+ include Loggable
27
+
28
+ def initialize(loop, options={})
29
+ @loop = loop
30
+ @options = options
31
+ @name = options[:name]
32
+ @dataset_name = options[:dataset]
33
+ @database_name = options[:database]
34
+ prepare
35
+ end
36
+
37
+ def start
38
+ logger.trace("start: start")
39
+ @forwarder.start
40
+ logger.trace("start: done")
41
+ end
42
+
43
+ def shutdown
44
+ logger.trace("shutdown: start")
45
+ @forwarder.shutdown
46
+ if @database
47
+ @database.close
48
+ @context.close
49
+ @database = @context = nil
50
+ end
51
+ logger.trace("shutdown: done")
52
+ end
53
+
54
+ def prefer_synchronous?(type)
55
+ find_handler_class(type).action.synchronous?
56
+ end
57
+
58
+ def processable?(type)
59
+ not find_handler_class(type).nil?
60
+ end
61
+
62
+ def process(message)
63
+ logger.trace("process: start")
64
+ type = message["type"]
65
+ handler_class = find_handler_class(type)
66
+ if handler_class.nil?
67
+ logger.trace("process: done: no handler: <#{type}>")
68
+ return
69
+ end
70
+ process_type(handler_class, type, message)
71
+ logger.trace("process: done: <#{type}>",
72
+ :handler => handler_class)
73
+ end
74
+
75
+ private
76
+ def prepare
77
+ if @database_name and !@database_name.empty?
78
+ @context = Groonga::Context.new
79
+ @database = @context.open_database(@database_name)
80
+ end
81
+ logger.debug("#{self.class.name}: activating plugins for the dataset \"#{@dataset_name}\": " +
82
+ "#{@options[:plugins].join(", ")}")
83
+ @step_runner = StepRunner.new(nil, @options[:plugins] || [])
84
+ @forwarder = Forwarder.new(@loop)
85
+ end
86
+
87
+ def find_handler_class(type)
88
+ step_definition = @step_runner.find(type)
89
+ return nil if step_definition.nil?
90
+ step_definition.handler_class
91
+ end
92
+
93
+ def process_type(handler_class, type, raw_message)
94
+ handler_message = HandlerMessage.new(raw_message)
95
+ handler_message.validate
96
+
97
+ messenger = HandlerMessenger.new(@forwarder, handler_message, @options)
98
+ handler = handler_class.new(@name, @context, messenger, @loop)
99
+ begin
100
+ result = handler.handle(handler_message)
101
+ unless result.nil?
102
+ # XXX: It is just a workaround.
103
+ # Remove me when super step is introduced.
104
+ if handler.is_a?(Droonga::Plugins::Search::Handler)
105
+ messenger.emit(result)
106
+ else
107
+ messenger.emit("result" => result)
108
+ end
109
+ end
110
+ rescue ErrorMessage => error
111
+ messenger.error(error.status_code, error.response_body)
112
+ rescue => error
113
+ logger.exception("failed to handle message", error)
114
+ internal_server_error =
115
+ ErrorMessages::InternalServerError.new("Unknown internal error")
116
+ messenger.error(internal_server_error.status_code,
117
+ internal_server_error.response_body)
118
+ end
119
+ end
120
+
121
+ def log_tag
122
+ "[#{Process.ppid}][#{Process.pid}] handler"
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ module Droonga
19
+ class InputMessage
20
+ def initialize(raw_message)
21
+ @raw_message = raw_message
22
+ end
23
+
24
+ def adapted_message
25
+ # TODO: We can create adapted message non-destructively.
26
+ # If it is not performance issue, it is better that we don't
27
+ # change message destructively. Consider about it later.
28
+ @raw_message
29
+ end
30
+
31
+ def body
32
+ @raw_message["body"]
33
+ end
34
+
35
+ def body=(body)
36
+ @raw_message["body"] = body
37
+ end
38
+
39
+ def type
40
+ @raw_message["type"]
41
+ end
42
+
43
+ def type=(type)
44
+ original_type = @raw_message["type"]
45
+ return if original_type == type
46
+ @raw_message["originalTypes"] ||= []
47
+ @raw_message["originalTypes"] << original_type
48
+ @raw_message["type"] = type
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,20 @@
1
+ # Copyright (C) 2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ module Droonga
17
+ module JobProtocol
18
+ READY_SIGNAL = "R"
19
+ end
20
+ end
@@ -0,0 +1,179 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "msgpack"
17
+
18
+ require "droonga/logger"
19
+ require "droonga/job_protocol"
20
+
21
+ module Droonga
22
+ class JobPusher
23
+ include Loggable
24
+
25
+ attr_reader :socket_path
26
+ def initialize(loop, base_path)
27
+ @loop = loop
28
+ @socket_path = "#{base_path}.#{Process.pid}.#{object_id}.sock"
29
+ @job_queue = JobQueue.new(@loop)
30
+ @server = nil
31
+ end
32
+
33
+ def start
34
+ FileUtils.rm_f(@socket_path)
35
+ @server = Coolio::UNIXServer.new(@socket_path) do |connection|
36
+ @job_queue.add_worker(WorkerConnection.new(connection))
37
+ end
38
+ FileUtils.chmod(0600, @socket_path)
39
+ @loop.attach(@server)
40
+ end
41
+
42
+ def close
43
+ @server.close if @server
44
+ end
45
+
46
+ def shutdown
47
+ logger.trace("shutdown: start")
48
+ @server.close if @server
49
+ @job_queue.close
50
+ FileUtils.rm_f(@socket_path)
51
+ logger.trace("shutdown: done")
52
+ end
53
+
54
+ def push(message)
55
+ logger.trace("push: start")
56
+ @job_queue.push(message)
57
+ logger.trace("push: done")
58
+ end
59
+
60
+ private
61
+ def log_tag
62
+ "job_pusher"
63
+ end
64
+
65
+ class JobQueue
66
+ include Loggable
67
+
68
+ def initialize(loop)
69
+ @loop = loop
70
+ @buffers = []
71
+ @ready_workers = []
72
+ @workers = []
73
+ @many_jobs_report_interval = 100
74
+ update_many_jobs_threshold
75
+ end
76
+
77
+ def close
78
+ @workers.each do |worker|
79
+ worker.close
80
+ end
81
+ end
82
+
83
+ def add_worker(worker)
84
+ @workers << worker
85
+ update_many_jobs_threshold
86
+ worker.on_ready = lambda do |ready_worker|
87
+ supply_job(ready_worker)
88
+ end
89
+ end
90
+
91
+ def push(message)
92
+ job = message.to_msgpack
93
+ if @ready_workers.empty?
94
+ @buffers << job
95
+ report_statistics_on_push
96
+ else
97
+ worker = @ready_workers.shift
98
+ if @buffers.empty?
99
+ worker.write(job)
100
+ else
101
+ @buffers << job
102
+ worker.write(@buffers.shift)
103
+ end
104
+ end
105
+ end
106
+
107
+ private
108
+ def supply_job(worker)
109
+ if @buffers.empty?
110
+ @ready_workers << worker
111
+ else
112
+ worker.write(@buffers.shift)
113
+ report_statistics_on_pull
114
+ end
115
+ end
116
+
117
+ def update_many_jobs_threshold
118
+ @many_jobs_threshold = @workers.size * 100
119
+ end
120
+
121
+ def report_statistics_on_push
122
+ if @buffers.size >= @many_jobs_threshold
123
+ if (@buffers.size % @many_jobs_report_interval).zero?
124
+ logger.warn("push: many jobs in queue: #{@buffers.size}")
125
+ end
126
+ end
127
+ end
128
+
129
+ def report_statistics_on_pull
130
+ if @buffers.size >= @many_jobs_threshold
131
+ if (@buffers.size % @many_jobs_report_interval).zero?
132
+ logger.info("pull: many jobs in queue: #{@buffers.size}")
133
+ end
134
+ elsif @buffers.size == (@many_jobs_threshold - 1)
135
+ logger.info("pull: reducing jobs in queue: #{@buffers.size}")
136
+ end
137
+ end
138
+
139
+ def log_tag
140
+ "job_queue"
141
+ end
142
+ end
143
+
144
+ class WorkerConnection
145
+ attr_writer :on_ready
146
+
147
+ def initialize(connection)
148
+ @connection = connection
149
+ @ready = false
150
+ @on_ready = nil
151
+ setup_connection
152
+ end
153
+
154
+ def ready?
155
+ @ready
156
+ end
157
+
158
+ def write(job)
159
+ @connection.write(job)
160
+ @ready = false
161
+ end
162
+
163
+ def close
164
+ @connection.close
165
+ end
166
+
167
+ private
168
+ def setup_connection
169
+ on_read = lambda do |data|
170
+ @ready = (data == JobProtocol::READY_SIGNAL)
171
+ @on_ready.call(self) if @on_ready
172
+ end
173
+ @connection.on_read do |data|
174
+ on_read.call(data)
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,70 @@
1
+ # Copyright (C) 2013-2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "msgpack"
17
+
18
+ require "droonga/loggable"
19
+ require "droonga/job_protocol"
20
+
21
+ module Droonga
22
+ class JobReceiver
23
+ include Loggable
24
+
25
+ def initialize(loop, socket_path, &callback)
26
+ @loop = loop
27
+ @socket_path = socket_path
28
+ @callback = callback
29
+ end
30
+
31
+ def start
32
+ logger.trace("start: start")
33
+ @receiver = Coolio::UNIXSocket.connect(@socket_path)
34
+ setup_receive_handler(@receiver)
35
+ @loop.attach(@receiver)
36
+ logger.trace("start: done")
37
+ end
38
+
39
+ def shutdown
40
+ logger.trace("shutdown: start")
41
+ @receiver.close
42
+ logger.trace("shutdown: done")
43
+ end
44
+
45
+ private
46
+ def setup_receive_handler(connection)
47
+ unpacker = MessagePack::Unpacker.new
48
+ on_read = lambda do |data|
49
+ logger.trace("on_read: start")
50
+ unpacker.feed_each(data) do |message|
51
+ @callback.call(message)
52
+ end
53
+ logger.trace("on_read: done")
54
+ send_ready(connection)
55
+ end
56
+ connection.on_read do |data|
57
+ on_read.call(data)
58
+ end
59
+ send_ready(connection)
60
+ end
61
+
62
+ def send_ready(connection)
63
+ connection.write(JobProtocol::READY_SIGNAL)
64
+ end
65
+
66
+ def log_tag
67
+ "job_receiver"
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,29 @@
1
+ # Copyright (C) 2014 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
+
16
+ require "droonga/logger"
17
+
18
+ module Droonga
19
+ module Loggable
20
+ private
21
+ def logger
22
+ @logger ||= Logger.new(:tag => log_tag)
23
+ end
24
+
25
+ def log_tag
26
+ nil
27
+ end
28
+ end
29
+ end