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,73 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2014 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 Error < StandardError
20
+ end
21
+
22
+ class MultiplexError < Error
23
+ attr_reader :errors
24
+
25
+ def initialize(errors=[])
26
+ @errors = errors
27
+ error_messages = @errors.collect do |error|
28
+ error.message
29
+ end
30
+ message = error_messages.sort.join("\n-----------------------\n")
31
+ super(message)
32
+ end
33
+ end
34
+
35
+ # the base class for any error which can be described as a Droonga message
36
+ class ErrorMessage < Error
37
+ STATUS_CODE = nil
38
+
39
+ attr_reader :detail
40
+
41
+ def initialize(message, detail=nil)
42
+ @detail = detail
43
+ super(message)
44
+ end
45
+
46
+ def name
47
+ self.class.name.split("::").last
48
+ end
49
+
50
+ def status_code
51
+ self.class::STATUS_CODE
52
+ end
53
+
54
+ def response_body
55
+ body = {
56
+ "name" => name,
57
+ "message" => message,
58
+ }
59
+ body["detail"] = @detail unless @detail.nil?
60
+ body
61
+ end
62
+ end
63
+
64
+ # TODO: Move to common file for runners
65
+ class UnsupportedMessageError < Error
66
+ attr_reader :phase, :message
67
+ def initialize(phase, message)
68
+ @phase = phase
69
+ @message = message
70
+ super("[#{@phase}] Unsupported message: #{@message.inspect}")
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,33 @@
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/error"
17
+ require "droonga/status_code"
18
+
19
+ module Droonga
20
+ module ErrorMessages
21
+ class InternalServerError < ErrorMessage
22
+ STATUS_CODE = StatusCode::INTERNAL_SERVER_ERROR
23
+ end
24
+
25
+ class BadRequest < ErrorMessage
26
+ STATUS_CODE = StatusCode::BAD_REQUEST
27
+ end
28
+
29
+ class NotFound < ErrorMessage
30
+ STATUS_CODE = StatusCode::NOT_FOUND
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,46 @@
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
+ require "coolio"
19
+
20
+ module Droonga
21
+ class EventLoop
22
+ def initialize(loop)
23
+ @loop = loop
24
+ @loop_breaker = Coolio::AsyncWatcher.new
25
+ @loop_breaker.attach(@loop)
26
+ end
27
+
28
+ def attach(watcher)
29
+ @loop.attach(watcher)
30
+ break_current_loop
31
+ end
32
+
33
+ def break_current_loop
34
+ @loop_breaker.signal
35
+ end
36
+
37
+ def run
38
+ @loop.run
39
+ end
40
+
41
+ def stop
42
+ @loop.stop
43
+ break_current_loop
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
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
+ require "droonga/slice"
19
+
20
+ module Droonga
21
+ class Farm
22
+ def initialize(name, catalog, loop, options={})
23
+ @name = name
24
+ @catalog = catalog
25
+ @loop = loop
26
+ @options = options
27
+ @slices = {}
28
+ slices = @catalog.slices(name)
29
+ slices.each do |slice_name, slice_options|
30
+ dataset = @catalog.datasets[slice_options[:dataset]]
31
+ slice = Droonga::Slice.new(dataset,
32
+ @loop,
33
+ @options.merge(slice_options))
34
+ @slices[slice_name] = slice
35
+ end
36
+ end
37
+
38
+ def start
39
+ @slices.each_value do |slice|
40
+ slice.start
41
+ end
42
+ end
43
+
44
+ def shutdown
45
+ threads = []
46
+ @slices.each_value do |slice|
47
+ threads << Thread.new do
48
+ slice.shutdown
49
+ end
50
+ end
51
+ threads.each(&:join)
52
+ end
53
+
54
+ def process(slice_name, message)
55
+ @slices[slice_name].process(message)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,191 @@
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 "socket"
17
+
18
+ require "msgpack"
19
+
20
+ require "droonga/loggable"
21
+ require "droonga/event_loop"
22
+
23
+ module Droonga
24
+ class FluentMessageReceiver
25
+ include Loggable
26
+
27
+ def initialize(loop, options={}, &on_message)
28
+ @loop = loop
29
+ @listen_fd = options[:listen_fd]
30
+ @heartbeat_fd = options[:heartbeat_fd]
31
+ @server = nil
32
+ @clients = []
33
+ @on_message = on_message
34
+ end
35
+
36
+ def start
37
+ logger.trace("start: start")
38
+ start_heartbeat_receiver
39
+ start_server
40
+ logger.trace("start: done")
41
+ end
42
+
43
+ def shutdown
44
+ logger.trace("shutdown: start")
45
+ shutdown_server
46
+ shutdown_clients
47
+ shutdown_heartbeat_receiver
48
+ logger.trace("shutdown: done")
49
+ end
50
+
51
+ private
52
+ def start_heartbeat_receiver
53
+ logger.trace("start_heartbeat_receiver: start")
54
+ @heartbeat_receiver = HeartbeatReceiver.new(@loop, @heartbeat_fd)
55
+ @heartbeat_receiver.start
56
+ logger.trace("start_heartbeat_receiver: done")
57
+ end
58
+
59
+ def shutdown_heartbeat_receiver
60
+ logger.trace("shutdown_heartbeat_receiver: start")
61
+ @heartbeat_receiver.shutdown
62
+ logger.trace("shutdown_heartbeat_receiver: done")
63
+ end
64
+
65
+ def start_server
66
+ logger.trace("start_server: start")
67
+
68
+ @clients = []
69
+ @server = create_server do |connection|
70
+ client = Client.new(connection) do |tag, time, record|
71
+ @on_message.call(tag, time, record)
72
+ end
73
+ @clients << client
74
+ end
75
+ @loop.attach(@server)
76
+
77
+ logger.trace("start_server: done")
78
+ end
79
+
80
+ def create_server(&block)
81
+ Coolio::Server.new(TCPServer.for_fd(@listen_fd), Coolio::TCPSocket, &block)
82
+ end
83
+
84
+ def shutdown_server
85
+ @server.close
86
+ end
87
+
88
+ def shutdown_clients
89
+ @clients.each do |client|
90
+ client.close
91
+ end
92
+ end
93
+
94
+ def log_tag
95
+ "fluent-message-receiver"
96
+ end
97
+
98
+ class HeartbeatReceiver
99
+ def initialize(loop, fd)
100
+ @loop = loop
101
+ @fd = fd
102
+ end
103
+
104
+ def start
105
+ @socket = UDPSocket.for_fd(@fd)
106
+
107
+ @watcher = Coolio::IOWatcher.new(@socket, "r")
108
+ on_readable = lambda do
109
+ receive_heartbeat
110
+ end
111
+ @watcher.on_readable do
112
+ on_readable.call
113
+ end
114
+ @loop.attach(@watcher)
115
+ end
116
+
117
+ def shutdown
118
+ @socket.close
119
+ @watcher.detach
120
+ end
121
+
122
+ private
123
+ def receive_heartbeat
124
+ address = nil
125
+ begin
126
+ _, address = @socket.recvfrom(1024)
127
+ rescue SystamCallError
128
+ return
129
+ end
130
+
131
+ host = address[3]
132
+ port = address[1]
133
+ send_back_heartbeat(host, port)
134
+ end
135
+
136
+ def send_back_heartbeat(host, port)
137
+ data = "\0"
138
+ flags = 0
139
+ begin
140
+ @socket.send(data, flags, host, port)
141
+ rescue SystemCallError
142
+ end
143
+ end
144
+ end
145
+
146
+ class Client
147
+ include Loggable
148
+
149
+ def initialize(io, &on_message)
150
+ @io = io
151
+ @on_message = on_message
152
+ @unpacker = MessagePack::Unpacker.new
153
+ on_read = lambda do |data|
154
+ feed(data)
155
+ end
156
+ @io.on_read do |data|
157
+ on_read.call(data)
158
+ end
159
+ end
160
+
161
+ def close
162
+ @io.close
163
+ end
164
+
165
+ private
166
+ def feed(data)
167
+ @unpacker.feed_each(data) do |object|
168
+ tag = object[0]
169
+ case object[1]
170
+ when String # PackedForward message
171
+ entries = MessagePack.unpack(object[1])
172
+ when Array # Forward message
173
+ entries = object[1]
174
+ when Integer, Float # Message message
175
+ entries = [[object[1], object[2]]]
176
+ else
177
+ logger.error("unknown message", :message => object)
178
+ next
179
+ end
180
+ entries.each do |time, record|
181
+ @on_message.call(tag, time || Time.now.to_i, record)
182
+ end
183
+ end
184
+ end
185
+
186
+ def log_tag
187
+ "fluent-message-receiver::client"
188
+ end
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,140 @@
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
+ require "thread"
19
+
20
+ require "cool.io"
21
+
22
+ require "droonga/message-pack-packer"
23
+
24
+ require "droonga/loggable"
25
+
26
+ module Droonga
27
+ class FluentMessageSender
28
+ include Loggable
29
+
30
+ def initialize(loop, host, port)
31
+ @loop = loop
32
+ @host = host
33
+ @port = port
34
+ @socket = nil
35
+ @buffer = []
36
+ @write_mutex = Mutex.new
37
+ end
38
+
39
+ def start
40
+ logger.trace("start: start")
41
+ start_writer
42
+ logger.trace("start: done")
43
+ end
44
+
45
+ def shutdown
46
+ logger.trace("shutdown: start")
47
+ shutdown_writer
48
+ shutdown_socket
49
+ logger.trace("shutdown: done")
50
+ end
51
+
52
+ def send(tag, data)
53
+ logger.trace("send: start")
54
+ fluent_message = [tag, Time.now.to_i, data]
55
+ packed_fluent_message = MessagePackPacker.pack(fluent_message)
56
+ @write_mutex.synchronize do
57
+ @buffer << packed_fluent_message
58
+ unless @signaling
59
+ @signaling = true
60
+ @writer.signal
61
+ end
62
+ end
63
+ logger.trace("send: done")
64
+ end
65
+
66
+ private
67
+ def connected?
68
+ not @socket.nil?
69
+ end
70
+
71
+ def connect
72
+ logger.trace("connect: start")
73
+
74
+ log_write_complete = lambda do
75
+ logger.trace("write completed")
76
+ end
77
+ log_connect = lambda do
78
+ logger.trace("connected to #{@host}:#{@port}")
79
+ end
80
+ log_failed = lambda do
81
+ logger.error("failed to connect to #{@host}:#{@port}")
82
+ @socket = nil
83
+ end
84
+ on_close = lambda do
85
+ @socket = nil
86
+ end
87
+
88
+ @socket = Coolio::TCPSocket.connect(@host, @port)
89
+ @socket.on_write_complete do
90
+ log_write_complete.call
91
+ end
92
+ @socket.on_connect do
93
+ log_connect.call
94
+ end
95
+ @socket.on_connect_failed do
96
+ log_failed.call
97
+ end
98
+ @socket.on_close do
99
+ on_close.call
100
+ end
101
+ @loop.attach(@socket)
102
+
103
+ logger.trace("connect: done")
104
+ end
105
+
106
+ def shutdown_socket
107
+ return unless connected?
108
+ @socket.close unless @socket.closed?
109
+ end
110
+
111
+ def start_writer
112
+ @writer = Coolio::AsyncWatcher.new
113
+ @signaling = false
114
+
115
+ on_signal = lambda do
116
+ @write_mutex.synchronize do
117
+ @signaling = false
118
+ connect unless connected?
119
+ @buffer.each do |data|
120
+ @socket.write(data)
121
+ end
122
+ @buffer.clear
123
+ end
124
+ end
125
+ @writer.on_signal do
126
+ on_signal.call
127
+ end
128
+
129
+ @loop.attach(@writer)
130
+ end
131
+
132
+ def shutdown_writer
133
+ @writer.detach
134
+ end
135
+
136
+ def log_tag
137
+ "[#{Process.ppid}][#{Process.pid}] fluent-message-sender"
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,119 @@
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
+ require "droonga/loggable"
19
+ require "droonga/event_loop"
20
+ require "droonga/fluent_message_sender"
21
+
22
+ module Droonga
23
+ class Forwarder
24
+ include Loggable
25
+
26
+ def initialize(loop)
27
+ @loop = loop
28
+ @senders = {}
29
+ end
30
+
31
+ def start
32
+ logger.trace("start: start")
33
+ logger.trace("start: done")
34
+ end
35
+
36
+ def shutdown
37
+ logger.trace("shutdown: start")
38
+ @senders.each_value do |sender|
39
+ sender.shutdown
40
+ end
41
+ logger.trace("shutdown: done")
42
+ end
43
+
44
+ def forward(message, destination)
45
+ logger.trace("forward: start")
46
+ command = destination["type"]
47
+ receiver = destination["to"]
48
+ arguments = destination["arguments"]
49
+ output(receiver, message, command, arguments)
50
+ logger.trace("forward: done")
51
+ end
52
+
53
+ private
54
+ def output(receiver, message, command, arguments)
55
+ logger.trace("output: start")
56
+ # TODO: IMPROVE ME: Should not use "unless" and "and". It is confused.
57
+ unless receiver.is_a?(String) and command.is_a?(String)
58
+ logger.trace("output: abort: invalid argument",
59
+ :receiver => receiver,
60
+ :command => command)
61
+ return
62
+ end
63
+ unless receiver =~ /\A(.*):(\d+)\/(.*?)(\?.+)?\z/
64
+ raise "format: hostname:port/tag(?params)"
65
+ end
66
+ host = $1
67
+ port = $2
68
+ tag = $3
69
+ params = $4
70
+ sender = find_sender(host, port, params)
71
+ unless sender
72
+ logger.trace("output: abort: no sender",
73
+ :host => host,
74
+ :port => port,
75
+ :params => params)
76
+ return
77
+ end
78
+ override_message = {
79
+ "type" => command,
80
+ }
81
+ override_message["arguments"] = arguments if arguments
82
+ message = message.merge(override_message)
83
+ output_tag = "#{tag}.message"
84
+ log_info = "<#{receiver}>:<#{output_tag}>"
85
+ logger.trace("output: post: start: #{log_info}")
86
+ sender.send(output_tag, message)
87
+ logger.trace("output: post: done: #{log_info}")
88
+ logger.trace("output: done")
89
+ end
90
+
91
+ def find_sender(host, port, params)
92
+ connection_id = extract_connection_id(params)
93
+ destination = "#{host}:#{port}"
94
+ destination << "?#{connection_id}" if connection_id
95
+
96
+ @senders[destination] ||= create_sender(host, port)
97
+ end
98
+
99
+ def extract_connection_id(params)
100
+ return nil unless params
101
+
102
+ if /[\?&;]connection_id=([^&;]+)/ =~ params
103
+ $1
104
+ else
105
+ nil
106
+ end
107
+ end
108
+
109
+ def create_sender(host, port)
110
+ sender = FluentMessageSender.new(@loop, host, port)
111
+ sender.start
112
+ sender
113
+ end
114
+
115
+ def log_tag
116
+ "[#{Process.ppid}][#{Process.pid}] forwarder"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,49 @@
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/pluggable"
17
+ require "droonga/loggable"
18
+ require "droonga/plugin/metadata/input_message"
19
+ require "droonga/plugin/metadata/handler_action"
20
+ require "droonga/error_messages"
21
+
22
+ module Droonga
23
+ class Handler
24
+ extend Pluggable
25
+ include Loggable
26
+ include ErrorMessages
27
+
28
+ class << self
29
+ def message
30
+ Plugin::Metadata::InputMessage.new(self)
31
+ end
32
+
33
+ def action
34
+ Plugin::Metadata::HandlerAction.new(self)
35
+ end
36
+ end
37
+
38
+ attr_reader :messenger, :loop
39
+ def initialize(name, context, messenger, loop)
40
+ @name = name
41
+ @context = context
42
+ @messenger = messenger
43
+ @loop = loop
44
+ end
45
+
46
+ def handle(message)
47
+ end
48
+ end
49
+ end