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,186 @@
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 "tsort"
17
+
18
+ module Droonga
19
+ module Catalog
20
+ class Schema
21
+ class ColumnVectorOptions
22
+ def initialize(data)
23
+ @data = data
24
+ end
25
+
26
+ def weight
27
+ @data["weight"]
28
+ end
29
+ end
30
+
31
+ class ColumnIndexOptions
32
+ def initialize(data)
33
+ @data = data
34
+ end
35
+
36
+ def section
37
+ @data["section"]
38
+ end
39
+
40
+ def weight
41
+ @data["weight"]
42
+ end
43
+
44
+ def position
45
+ @data["position"]
46
+ end
47
+
48
+ def sources
49
+ @data["sources"]
50
+ end
51
+ end
52
+
53
+ class Column
54
+ attr_reader :table, :name, :data, :vector_options, :index_options
55
+ def initialize(table, name, data)
56
+ @table = table
57
+ @name = name
58
+ @data = data
59
+ @vector_options = ColumnVectorOptions.new(vector_options_data)
60
+ @index_options = ColumnIndexOptions.new(index_options_data)
61
+ end
62
+
63
+ def ==(other)
64
+ self.class == other.class and
65
+ name == other.name and
66
+ data == other.data
67
+ end
68
+
69
+ def type
70
+ @data["type"] || "Scalar"
71
+ end
72
+
73
+ def type_symbol
74
+ case type
75
+ when "Scalar"
76
+ :scalar
77
+ when "Vector"
78
+ :vector
79
+ when "Index"
80
+ :index
81
+ end
82
+ end
83
+
84
+ def value_type
85
+ @data["valueType"]
86
+ end
87
+
88
+ def value_type_groonga
89
+ if value_type == "Integer"
90
+ "Int64"
91
+ else
92
+ value_type
93
+ end
94
+ end
95
+
96
+ private
97
+ def vector_options_data
98
+ @data["vectorOptions"] || {}
99
+ end
100
+
101
+ def index_options_data
102
+ @data["indexOptions"] || {}
103
+ end
104
+ end
105
+
106
+ class Table
107
+ attr_reader :name, :columns, :data
108
+ def initialize(name, data)
109
+ @name = name
110
+ @data = data
111
+ @columns = {}
112
+
113
+ columns_data.each do |column_name, column_data|
114
+ @columns[column_name] = Column.new(name, column_name, column_data)
115
+ end
116
+ end
117
+
118
+ def ==(other)
119
+ self.class == other.class and
120
+ name == other.name and
121
+ data == other.data
122
+ end
123
+
124
+ def type
125
+ @data["type"] || "Hash"
126
+ end
127
+
128
+ def type_symbol
129
+ case type
130
+ when "Array"
131
+ :array
132
+ when "Hash"
133
+ :hash
134
+ when "PatriciaTrie"
135
+ :patricia_trie
136
+ when "DoubleArrayTrie"
137
+ :double_array_trie
138
+ end
139
+ end
140
+
141
+ def key_type
142
+ @data["keyType"]
143
+ end
144
+
145
+ def key_type_groonga
146
+ case key_type
147
+ when "Integer"
148
+ "Int64"
149
+ when "Float", "Time", "ShortText", "TokyoGeoPoint", "WGS84GeoPoint"
150
+ key_type
151
+ else
152
+ key_type
153
+ end
154
+ end
155
+
156
+ def tokenizer
157
+ @data["tokenizer"]
158
+ end
159
+
160
+ def normalizer
161
+ @data["normalizer"]
162
+ end
163
+
164
+ private
165
+ def columns_data
166
+ @data["columns"] || []
167
+ end
168
+ end
169
+
170
+ attr_reader :tables
171
+ def initialize(dataset_name, data)
172
+ @dataset_name = dataset_name
173
+ @data = data || []
174
+ @tables = {}
175
+ @data.each do |table_name, table_data|
176
+ @tables[table_name] = Table.new(table_name, table_data)
177
+ end
178
+ end
179
+
180
+ def ==(other)
181
+ self.class == other.class and
182
+ tables == other.tables
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,28 @@
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 Catalog
18
+ class SingleVolume
19
+ def initialize(data)
20
+ @data = data
21
+ end
22
+
23
+ def address
24
+ @data["address"]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
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 Catalog
18
+ class Slice
19
+ def initialize(dataset, data)
20
+ @dataset = dataset
21
+ @data = data
22
+ end
23
+
24
+ def weight
25
+ @data["weight"] || 1
26
+ end
27
+
28
+ def label
29
+ @data["label"]
30
+ end
31
+
32
+ def boundary
33
+ @data["boundary"]
34
+ end
35
+
36
+ def volume
37
+ @volume ||= Volume.create(@dataset, @data["volume"])
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,427 @@
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/catalog/base"
17
+ require "droonga/catalog/dataset"
18
+
19
+ module Droonga
20
+ module Catalog
21
+ class Version1 < Base
22
+ def initialize(data, path)
23
+ super
24
+ @errors = []
25
+
26
+ validate
27
+ raise MultiplexError.new(@errors) unless @errors.empty?
28
+
29
+ prepare_data
30
+ end
31
+
32
+ def datasets
33
+ @datasets
34
+ end
35
+
36
+ def slices(name)
37
+ get_partitions(name)
38
+ end
39
+
40
+ def get_partitions(name)
41
+ device = @data["farms"][name]["device"]
42
+ pattern = Regexp.new("^#{name}\.")
43
+ results = {}
44
+ @data["datasets"].each do |dataset_name, dataset_data|
45
+ dataset = Dataset.new(dataset_name, dataset_data)
46
+ workers = dataset["workers"]
47
+ plugins = dataset["plugins"]
48
+ dataset["ring"].each do |key, part|
49
+ part["partitions"].each do |range, partitions|
50
+ partitions.each do |partition|
51
+ if partition =~ pattern
52
+ path = File.join([device, $POSTMATCH, "db"])
53
+ path = File.expand_path(path, base_path)
54
+ options = {
55
+ :dataset => dataset_name,
56
+ :database => path,
57
+ :n_workers => workers,
58
+ :plugins => plugins
59
+ }
60
+ results[partition] = options
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ return results
67
+ end
68
+
69
+ def get_routes(name, args)
70
+ routes = []
71
+ dataset = dataset(name)
72
+ case args["type"]
73
+ when "broadcast"
74
+ dataset["ring"].each do |key, partition|
75
+ select_range_and_replicas(partition, args, routes)
76
+ end
77
+ when "scatter"
78
+ name = get_partition(dataset, args["record"]["_key"])
79
+ partition = dataset["ring"][name]
80
+ select_range_and_replicas(partition, args, routes)
81
+ end
82
+ return routes
83
+ end
84
+
85
+ def get_partition(dataset, key)
86
+ continuum = dataset["continuum"]
87
+ return dataset["ring"].keys[0] unless continuum
88
+ hash = Zlib.crc32(key)
89
+ min = 0
90
+ max = continuum.size - 1
91
+ while (min < max) do
92
+ index = (min + max) / 2
93
+ value, key = continuum[index]
94
+ return key if value == hash
95
+ if value > hash
96
+ max = index
97
+ else
98
+ min = index + 1
99
+ end
100
+ end
101
+ return continuum[max][1]
102
+ end
103
+
104
+ def select_range_and_replicas(partition, args, routes)
105
+ date_range = args["date_range"] || 0..-1
106
+ partition["partitions"].sort[date_range].each do |time, replicas|
107
+ case args["replica"]
108
+ when "top"
109
+ routes << replicas[0]
110
+ when "random"
111
+ routes << replicas[rand(replicas.size)]
112
+ when "all"
113
+ routes.concat(replicas)
114
+ end
115
+ end
116
+ end
117
+
118
+ private
119
+ def prepare_data
120
+ @datasets = {}
121
+ @data["datasets"].each do |name, dataset|
122
+ @datasets[name] = Dataset.new(name, dataset)
123
+ number_of_partitions = dataset["number_of_partitions"]
124
+ next if number_of_partitions < 2
125
+ total_weight = compute_total_weight(dataset)
126
+ continuum = []
127
+ dataset["ring"].each do |key, value|
128
+ points = number_of_partitions * 160 * value["weight"] / total_weight
129
+ points.times do |point|
130
+ hash = Digest::SHA1.hexdigest("#{key}:#{point}")
131
+ continuum << [hash[0..7].to_i(16), key]
132
+ end
133
+ end
134
+ dataset["continuum"] = continuum.sort do |a, b| a[0] - b[0]; end
135
+ end
136
+ @options = @data["options"] || {}
137
+ end
138
+
139
+ def compute_total_weight(dataset)
140
+ dataset["ring"].reduce(0) do |result, zone|
141
+ result + zone[1]["weight"]
142
+ end
143
+ end
144
+
145
+ def validate
146
+ do_validation do
147
+ validate_effective_date
148
+ end
149
+ do_validation do
150
+ validate_farms
151
+ end
152
+ do_validation do
153
+ validate_zones
154
+ end
155
+ do_validation do
156
+ validate_datasets
157
+ end
158
+ do_validation do
159
+ validate_zone_relations
160
+ end
161
+ do_validation do
162
+ validate_database_relations
163
+ end
164
+ end
165
+
166
+ def do_validation(&block)
167
+ begin
168
+ yield
169
+ rescue LegacyValidationError => error
170
+ @errors << error
171
+ end
172
+ end
173
+
174
+ def validate_required_parameter(value, name)
175
+ raise MissingRequiredParameter.new(name, @path) unless value
176
+ end
177
+
178
+ def validate_parameter_type(expected_types, value, name)
179
+ expected_types = [expected_types] unless expected_types.is_a?(Array)
180
+
181
+ if expected_types.any? do |type|
182
+ value.is_a?(type)
183
+ end
184
+ return
185
+ end
186
+
187
+ raise MismatchedParameterType.new(name,
188
+ expected_types,
189
+ value.class,
190
+ @path)
191
+ end
192
+
193
+ def validate_valid_datetime(value, name)
194
+ validate_required_parameter(value, name)
195
+ validate_parameter_type(String, value, name)
196
+ begin
197
+ Time.parse(value)
198
+ rescue ArgumentError
199
+ raise InvalidDate.new(name, value, @path)
200
+ end
201
+ end
202
+
203
+ def validate_positive_numeric_parameter(value, name)
204
+ validate_required_parameter(value, name)
205
+ validate_parameter_type(Numeric, value, name)
206
+ if value < 0
207
+ raise NegativeNumber.new(name, value, @path)
208
+ end
209
+ end
210
+
211
+ def validate_positive_integer_parameter(value, name)
212
+ validate_required_parameter(value, name)
213
+ validate_parameter_type(Integer, value, name)
214
+ if value < 0
215
+ raise NegativeNumber.new(name, value, @path)
216
+ end
217
+ end
218
+
219
+ def validate_one_or_larger_integer_parameter(value, name)
220
+ validate_required_parameter(value, name)
221
+ validate_parameter_type(Integer, value, name)
222
+ if value < 1
223
+ raise SmallerThanOne.new(name, value, @path)
224
+ end
225
+ end
226
+
227
+ def validate_effective_date
228
+ date = @data["effective_date"]
229
+ validate_required_parameter(date, "effective_date")
230
+ validate_valid_datetime(date, "effective_date")
231
+ end
232
+
233
+ def validate_farms
234
+ farms = @data["farms"]
235
+
236
+ validate_required_parameter(farms, "farms")
237
+ validate_parameter_type(Hash, farms, "farms")
238
+
239
+ farms.each do |key, value|
240
+ validate_farm(value, "farms.#{key}")
241
+ end
242
+ end
243
+
244
+ def validate_farm(farm, name)
245
+ validate_parameter_type(Hash, farm, name)
246
+
247
+ validate_required_parameter(farm["device"], "#{name}.device")
248
+ validate_parameter_type(String, farm["device"], "#{name}.device")
249
+ end
250
+
251
+ def validate_zones
252
+ zones = @data["zones"]
253
+
254
+ validate_required_parameter(zones, "zones")
255
+ validate_parameter_type(Array, zones, "zones")
256
+
257
+ validate_zone(zones, "zones")
258
+ end
259
+
260
+ def validate_zone(zone, name)
261
+ case zone
262
+ when String
263
+ return
264
+ when Array
265
+ zone.each_with_index do |sub_zone, index|
266
+ validate_zone(sub_zone, "#{name}[#{index}]")
267
+ end
268
+ else
269
+ validate_parameter_type([String, Array], zone, name)
270
+ end
271
+ end
272
+
273
+ def validate_datasets
274
+ datasets = @data["datasets"]
275
+
276
+ validate_required_parameter(datasets, "datasets")
277
+ validate_parameter_type(Hash, datasets, "datasets")
278
+
279
+ datasets.each do |name, dataset|
280
+ validate_dataset(dataset, "datasets.#{name}")
281
+ end
282
+ end
283
+
284
+ def validate_dataset(dataset, name)
285
+ validate_parameter_type(Hash, dataset, name)
286
+
287
+ do_validation do
288
+ validate_one_or_larger_integer_parameter(dataset["number_of_partitions"],
289
+ "#{name}.number_of_partitions")
290
+ end
291
+ do_validation do
292
+ validate_one_or_larger_integer_parameter(dataset["number_of_replicas"],
293
+ "#{name}.number_of_replicas")
294
+ end
295
+ do_validation do
296
+ validate_positive_integer_parameter(dataset["workers"],
297
+ "#{name}.workers")
298
+ end
299
+ do_validation do
300
+ validate_date_range(dataset["date_range"], "#{name}.date_range")
301
+ end
302
+ do_validation do
303
+ validate_partition_key(dataset["partition_key"],
304
+ "#{name}.partition_key")
305
+ end
306
+
307
+ do_validation do
308
+ ring = dataset["ring"]
309
+ validate_required_parameter(ring, "#{name}.ring")
310
+ validate_parameter_type(Hash, ring, "#{name}.ring")
311
+ ring.each do |key, value|
312
+ validate_ring(value, "#{name}.ring.#{key}")
313
+ end
314
+ end
315
+
316
+ do_validation do
317
+ validate_plugins(dataset["plugins"], "#{name}.plugins")
318
+ end
319
+ end
320
+
321
+ def validate_date_range(value, name)
322
+ validate_required_parameter(value, name)
323
+ return if value == "infinity"
324
+ raise UnsupportedValue.new(name, value, @path)
325
+ end
326
+
327
+ def validate_partition_key(value, name)
328
+ validate_required_parameter(value, name)
329
+ validate_parameter_type(String, value, name)
330
+ return if value == "_key"
331
+ raise UnsupportedValue.new(name, value, @path)
332
+ end
333
+
334
+ def validate_ring(ring, name)
335
+ validate_parameter_type(Hash, ring, name)
336
+
337
+ do_validation do
338
+ validate_positive_numeric_parameter(ring["weight"], "#{name}.weight")
339
+ end
340
+
341
+ do_validation do
342
+ validate_parameter_type(Hash, ring["partitions"], "#{name}.partitions")
343
+ ring["partitions"].each do |key, value|
344
+ validate_partition(value, "#{name}.partitions.#{key}")
345
+ end
346
+ end
347
+ end
348
+
349
+ def validate_partition(partition, name)
350
+ validate_parameter_type(Array, partition, name)
351
+
352
+ partition.each_with_index do |value, index|
353
+ do_validation do
354
+ validate_parameter_type(String, value, "#{name}[#{index}]")
355
+ end
356
+ end
357
+ end
358
+
359
+ def validate_plugins(plugins, name)
360
+ return unless plugins
361
+ validate_required_parameter(plugins, name)
362
+ validate_parameter_type(Array, plugins, "#{name}.plugins")
363
+ end
364
+
365
+ def validate_zone_relations
366
+ return unless @data["zones"].is_a?(Array)
367
+ return unless @data["farms"].is_a?(Hash)
368
+
369
+ farms = @data["farms"]
370
+ zones = @data["zones"]
371
+
372
+ all_farms = farms.keys
373
+ all_zones = zones.flatten
374
+
375
+ all_farms.each do |farm|
376
+ unless all_zones.include?(farm)
377
+ raise FarmNotZoned.new(farm, zones, @path)
378
+ end
379
+ end
380
+
381
+ all_zones.each do |zone|
382
+ unless all_farms.include?(zone)
383
+ raise UnknownFarmInZones.new(farm, zones, @path)
384
+ end
385
+ end
386
+ end
387
+
388
+ def validate_database_relations
389
+ return unless @data["farms"]
390
+
391
+ farm_names = @data["farms"].keys.collect do |name|
392
+ Regexp.escape(name)
393
+ end
394
+ valid_farms_matcher = Regexp.new("^(#{farm_names.join("|")})\.")
395
+
396
+ @data["datasets"].each do |dataset_name, dataset|
397
+ ring = dataset["ring"]
398
+ next if ring.nil? or !ring.is_a?(Hash)
399
+ ring.each do |ring_key, part|
400
+ partitions_set = part["partitions"]
401
+ next if partitions_set.nil? or !partitions_set.is_a?(Hash)
402
+ partitions_set.each do |range, partitions|
403
+ next unless partitions.is_a?(Array)
404
+ partitions.each_with_index do |partition, index|
405
+ name = "datasets.#{dataset_name}.ring.#{ring_key}." +
406
+ "partitions.#{range}[#{index}]"
407
+ do_validation do
408
+ unless partition =~ valid_farms_matcher
409
+ raise UnknownFarmForPartition.new(name, partition, @path)
410
+ end
411
+ do_validation do
412
+ directory_name = $POSTMATCH
413
+ if directory_name.nil? or directory_name.empty?
414
+ message = "\"#{partition}\" has no database name. " +
415
+ "You mus specify a database name for \"#{name}\"."
416
+ raise LegacyValidationError.new(message, @path)
417
+ end
418
+ end
419
+ end
420
+ end
421
+ end
422
+ end
423
+ end
424
+ end
425
+ end
426
+ end
427
+ end