droonga-engine 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (203) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -0
  4. data/Gemfile +7 -0
  5. data/Rakefile +6 -2
  6. data/bin/droonga-engine +2 -2
  7. data/bin/{droonga-catalog-generate → droonga-engine-catalog-generate} +15 -3
  8. data/bin/droonga-engine-serf-event-handler +20 -0
  9. data/bin/droonga-engine-service +2 -2
  10. data/doc/text/news.md +21 -1
  11. data/droonga-engine.gemspec +5 -2
  12. data/lib/droonga/catalog/collection_volume.rb +12 -0
  13. data/lib/droonga/catalog/dataset.rb +25 -0
  14. data/lib/droonga/catalog/single_volume.rb +10 -0
  15. data/lib/droonga/catalog/slice.rb +4 -0
  16. data/lib/droonga/catalog/version1.rb +59 -48
  17. data/lib/droonga/catalog/version2.rb +10 -20
  18. data/lib/droonga/catalog/volume_collection.rb +27 -4
  19. data/lib/droonga/catalog_generator.rb +12 -5
  20. data/lib/droonga/catalog_observer.rb +17 -35
  21. data/lib/droonga/command/droonga_engine.rb +436 -0
  22. data/lib/droonga/command/droonga_engine_service.rb +273 -0
  23. data/lib/droonga/command/serf_event_handler.rb +85 -0
  24. data/lib/droonga/dispatcher.rb +8 -8
  25. data/lib/droonga/engine.rb +90 -26
  26. data/lib/droonga/engine/version.rb +1 -1
  27. data/lib/droonga/engine_state.rb +29 -3
  28. data/lib/droonga/internal_fluent_message_receiver.rb +100 -0
  29. data/lib/droonga/live_nodes_list_loader.rb +48 -0
  30. data/lib/droonga/live_nodes_list_observer.rb +72 -0
  31. data/lib/droonga/path.rb +47 -0
  32. data/lib/droonga/plugins/dump.rb +279 -38
  33. data/lib/droonga/plugins/groonga/select.rb +26 -14
  34. data/lib/droonga/plugins/search.rb +30 -2
  35. data/lib/droonga/plugins/search/distributed_search_planner.rb +28 -11
  36. data/lib/droonga/processor.rb +4 -0
  37. data/lib/droonga/searcher.rb +26 -0
  38. data/lib/droonga/serf.rb +119 -0
  39. data/lib/droonga/serf_downloader.rb +90 -0
  40. data/lib/droonga/server.rb +2 -2
  41. data/lib/droonga/service_control_protocol.rb +26 -0
  42. data/sample/cluster/catalog.json +1 -1
  43. data/test/command/config/default/catalog.json +2 -2
  44. data/test/command/config/version1/catalog.json +1 -1
  45. data/test/command/fixture/documents.jsons +18 -18
  46. data/test/command/fixture/event.jsons +4 -4
  47. data/test/command/fixture/user-table-array.jsons +4 -4
  48. data/test/command/fixture/user-table.jsons +5 -5
  49. data/test/command/suite/add/dimension/column.catalog.json +1 -1
  50. data/test/command/suite/add/dimension/column.test +4 -4
  51. data/test/command/suite/add/dimension/integer.catalog.json +1 -1
  52. data/test/command/suite/add/dimension/integer.test +4 -4
  53. data/test/command/suite/add/error/invalid-integer.test +1 -1
  54. data/test/command/suite/add/error/invalid-time.test +1 -1
  55. data/test/command/suite/add/error/missing-key.test +1 -1
  56. data/test/command/suite/add/error/missing-table.test +1 -1
  57. data/test/command/suite/add/error/unknown-column.test +1 -1
  58. data/test/command/suite/add/error/unknown-table.test +1 -1
  59. data/test/command/suite/add/minimum.test +1 -1
  60. data/test/command/suite/add/vector/short_text.catalog.json +26 -0
  61. data/test/command/suite/add/vector/short_text.expected +42 -0
  62. data/test/command/suite/add/vector/short_text.test +35 -0
  63. data/test/command/suite/add/with-values.test +1 -1
  64. data/test/command/suite/add/without-key.test +1 -1
  65. data/test/command/suite/dump/column/index.catalog.json +40 -0
  66. data/test/command/suite/dump/column/index.expected +195 -0
  67. data/test/command/suite/dump/column/index.test +5 -0
  68. data/test/command/suite/dump/column/scalar.catalog.json +19 -0
  69. data/test/command/suite/dump/column/scalar.expected +99 -0
  70. data/test/command/suite/dump/column/scalar.test +5 -0
  71. data/test/command/suite/dump/column/vector.catalog.json +22 -0
  72. data/test/command/suite/dump/column/vector.expected +108 -0
  73. data/test/command/suite/dump/column/vector.test +5 -0
  74. data/test/command/suite/dump/record/vector/reference.catalog.json +27 -0
  75. data/test/command/suite/dump/record/vector/reference.expected +213 -0
  76. data/test/command/suite/dump/record/vector/reference.test +21 -0
  77. data/test/command/suite/dump/table/array.catalog.json +13 -0
  78. data/test/command/suite/dump/table/array.expected +63 -0
  79. data/test/command/suite/dump/table/array.test +5 -0
  80. data/test/command/suite/dump/table/double_array_trie.catalog.json +14 -0
  81. data/test/command/suite/dump/table/double_array_trie.expected +66 -0
  82. data/test/command/suite/dump/table/double_array_trie.test +5 -0
  83. data/test/command/suite/dump/table/hash.catalog.json +14 -0
  84. data/test/command/suite/dump/table/hash.expected +66 -0
  85. data/test/command/suite/dump/table/hash.test +5 -0
  86. data/test/command/suite/dump/table/patricia_trie.catalog.json +14 -0
  87. data/test/command/suite/dump/table/patricia_trie.expected +66 -0
  88. data/test/command/suite/dump/table/patricia_trie.test +5 -0
  89. data/test/command/suite/groonga/column_create/scalar.test +2 -2
  90. data/test/command/suite/groonga/column_create/unknown-table.test +1 -1
  91. data/test/command/suite/groonga/column_create/vector.test +2 -2
  92. data/test/command/suite/groonga/column_list/success.test +3 -3
  93. data/test/command/suite/groonga/column_list/unknown-table.test +1 -1
  94. data/test/command/suite/groonga/column_remove/success.test +3 -3
  95. data/test/command/suite/groonga/column_remove/unknown-column.test +2 -2
  96. data/test/command/suite/groonga/column_remove/unknown-table.test +1 -1
  97. data/test/command/suite/groonga/column_rename/success.test +3 -3
  98. data/test/command/suite/groonga/column_rename/unknown-column.test +2 -2
  99. data/test/command/suite/groonga/column_rename/unknown-table.test +1 -1
  100. data/test/command/suite/groonga/delete/duplicated-identifiers.test +2 -2
  101. data/test/command/suite/groonga/delete/filter.test +2 -2
  102. data/test/command/suite/groonga/delete/invalid-filter.test +1 -1
  103. data/test/command/suite/groonga/delete/no-identifier.test +2 -2
  104. data/test/command/suite/groonga/delete/success.test +2 -2
  105. data/test/command/suite/groonga/delete/unknown-table.test +1 -1
  106. data/test/command/suite/groonga/select/minimum.expected +24 -1
  107. data/test/command/suite/groonga/select/minimum.test +1 -1
  108. data/test/command/suite/groonga/select/type/time.catalog.json +19 -0
  109. data/test/command/suite/groonga/select/type/time.expected +37 -0
  110. data/test/command/suite/groonga/select/type/time.test +35 -0
  111. data/test/command/suite/groonga/table_create/array.test +1 -1
  112. data/test/command/suite/groonga/table_create/hash.test +1 -1
  113. data/test/command/suite/groonga/table_list/success.test +2 -2
  114. data/test/command/suite/groonga/table_remove/success.test +1 -1
  115. data/test/command/suite/groonga/table_remove/unknown-table.test +1 -1
  116. data/test/command/suite/message/error/unknown-type.expected +1 -1
  117. data/test/command/suite/message/error/unknown-type.test +1 -1
  118. data/test/command/suite/search/adjusters/multiple.catalog.json +1 -1
  119. data/test/command/suite/search/adjusters/multiple.test +3 -3
  120. data/test/command/suite/search/adjusters/one.catalog.json +1 -1
  121. data/test/command/suite/search/adjusters/one.test +3 -3
  122. data/test/command/suite/search/attributes/array.expected +7 -0
  123. data/test/command/suite/search/attributes/array.test +1 -1
  124. data/test/command/suite/search/attributes/hash.expected +18 -0
  125. data/test/command/suite/search/attributes/hash.test +1 -1
  126. data/test/command/suite/search/complex.expected +12 -0
  127. data/test/command/suite/search/complex.test +1 -1
  128. data/test/command/suite/search/condition/nested.catalog.json +37 -0
  129. data/test/command/suite/search/condition/nested.expected +7 -0
  130. data/test/command/suite/search/condition/nested.test +103 -2
  131. data/test/command/suite/search/condition/query.catalog.json +37 -0
  132. data/test/command/suite/search/condition/query.expected +7 -0
  133. data/test/command/suite/search/condition/query.test +103 -2
  134. data/test/command/suite/search/condition/query/nonexistent_column.catalog.json +1 -1
  135. data/test/command/suite/search/condition/query/nonexistent_column.test +2 -2
  136. data/test/command/suite/search/condition/query/syntax_error.catalog.json +1 -1
  137. data/test/command/suite/search/condition/query/syntax_error.test +2 -2
  138. data/test/command/suite/search/condition/script.catalog.json +37 -0
  139. data/test/command/suite/search/condition/script.expected +7 -0
  140. data/test/command/suite/search/condition/script.test +103 -2
  141. data/test/command/suite/search/error/cyclic-source.test +1 -1
  142. data/test/command/suite/search/error/deeply-cyclic-source.test +1 -1
  143. data/test/command/suite/search/error/missing-source-parameter.test +1 -1
  144. data/test/command/suite/search/error/no-query.test +1 -1
  145. data/test/command/suite/search/error/unknown-source.test +1 -1
  146. data/test/command/suite/search/group/count.test +1 -1
  147. data/test/command/suite/search/group/limit.test +1 -1
  148. data/test/command/suite/search/group/string.catalog.json +41 -0
  149. data/test/command/suite/search/group/string.expected +18 -18
  150. data/test/command/suite/search/group/string.test +67 -22
  151. data/test/command/suite/search/group/subrecord/with-sort.catalog.json +1 -1
  152. data/test/command/suite/search/group/subrecord/with-sort.test +5 -5
  153. data/test/command/suite/search/multiple/chained.catalog.json +37 -0
  154. data/test/command/suite/search/multiple/chained.expected +14 -0
  155. data/test/command/suite/search/multiple/chained.test +103 -2
  156. data/test/command/suite/search/multiple/parallel.expected +14 -0
  157. data/test/command/suite/search/multiple/parallel.test +1 -1
  158. data/test/command/suite/search/output/attributes/invalid.catalog.json +1 -1
  159. data/test/command/suite/search/output/attributes/invalid.test +2 -2
  160. data/test/command/suite/search/output/attributes/star.catalog.json +23 -0
  161. data/test/command/suite/search/output/attributes/star.expected +27 -0
  162. data/test/command/suite/search/output/attributes/star.test +32 -0
  163. data/test/command/suite/search/range/only-output.expected +7 -0
  164. data/test/command/suite/search/range/only-output.test +1 -1
  165. data/test/command/suite/search/range/only-sort.expected +7 -0
  166. data/test/command/suite/search/range/only-sort.test +1 -1
  167. data/test/command/suite/search/range/sort-and-output.expected +7 -0
  168. data/test/command/suite/search/range/sort-and-output.test +1 -1
  169. data/test/command/suite/search/range/too-large-output-offset.expected +8 -0
  170. data/test/command/suite/search/range/too-large-output-offset.test +1 -1
  171. data/test/command/suite/search/range/too-large-sort-offset.expected +8 -0
  172. data/test/command/suite/search/range/too-large-sort-offset.test +1 -1
  173. data/test/command/suite/search/response/elapsed_time.catalog.json +1 -1
  174. data/test/command/suite/search/response/elapsed_time.test +2 -2
  175. data/test/command/suite/search/response/records/value/time.expected +12 -0
  176. data/test/command/suite/search/response/records/value/time.test +1 -1
  177. data/test/command/suite/search/simple.expected +12 -0
  178. data/test/command/suite/search/simple.test +1 -1
  179. data/test/command/suite/search/sort/default-offset-limit.expected +7 -0
  180. data/test/command/suite/search/sort/default-offset-limit.test +1 -1
  181. data/test/command/suite/search/sort/invisible-column.expected +7 -0
  182. data/test/command/suite/search/sort/invisible-column.test +1 -1
  183. data/test/unit/catalog/test_collection_volume.rb +16 -0
  184. data/test/unit/catalog/test_dataset.rb +36 -0
  185. data/test/unit/catalog/test_single_volume.rb +9 -0
  186. data/test/unit/catalog/test_slice.rb +11 -0
  187. data/test/unit/catalog/test_version1.rb +7 -12
  188. data/test/unit/catalog/test_version2.rb +7 -0
  189. data/test/unit/catalog/test_volume_collection.rb +28 -0
  190. data/test/unit/fixtures/catalog/version1.json +10 -3
  191. data/test/unit/fixtures/catalog/version2.json +2 -2
  192. data/test/unit/plugins/groonga/select/test_adapter_output.rb +8 -14
  193. data/test/unit/plugins/groonga/test_column_create.rb +5 -5
  194. data/test/unit/plugins/groonga/test_column_remove.rb +2 -2
  195. data/test/unit/plugins/groonga/test_column_rename.rb +2 -2
  196. data/test/unit/plugins/groonga/test_delete.rb +2 -2
  197. data/test/unit/plugins/groonga/test_table_create.rb +9 -9
  198. data/test/unit/plugins/groonga/test_table_remove.rb +1 -1
  199. data/test/unit/test_catalog_generator.rb +1 -1
  200. data/test/unit/test_schema_applier.rb +2 -2
  201. data/test/unit/test_watch_schema.rb +4 -4
  202. metadata +241 -72
  203. data/lib/droonga/engine/command/droonga_engine.rb +0 -441
@@ -26,8 +26,8 @@ module Droonga
26
26
  @table = select_request["table"]
27
27
  @result_name = @table + "_result"
28
28
 
29
- output_columns = select_request["output_columns"] || ""
30
- attributes = output_columns.split(/, */)
29
+ output_columns = select_request["output_columns"] || "_id, _key, *"
30
+ attributes = output_columns.split(/\s*,\s*/)
31
31
  offset = (select_request["offset"] || "0").to_i
32
32
  limit = (select_request["limit"] || "10").to_i
33
33
 
@@ -121,7 +121,7 @@ module Droonga
121
121
  drilldown_keys = drilldown_keys.split(",")
122
122
 
123
123
  sort_keys = (select_request["drilldown_sortby"] || "").split(",")
124
- columns = (select_request["drilldown_output_columns"] || "").split(",")
124
+ columns = (select_request["drilldown_output_columns"] || "_key,_nsubrecs").split(",")
125
125
  offset = (select_request["drilldown_offset"] || "0").to_i
126
126
  limit = (select_request["drilldown_limit"] || "10").to_i
127
127
 
@@ -177,16 +177,18 @@ module Droonga
177
177
  def convert_main_result(result)
178
178
  status_code = 0
179
179
  start_time = result["startTime"]
180
- start_time_in_unix_time = if start_time
181
- Time.parse(start_time).to_f
182
- else
183
- Time.now.to_f
184
- end
180
+ start_time_in_unix_time = normalize_time(start_time).to_f
185
181
  elapsed_time = result["elapsedTime"] || 0
186
182
  @header = [status_code, start_time_in_unix_time, elapsed_time]
187
183
  @body = convert_search_result(result)
188
184
  end
189
185
 
186
+ def normalize_time(time)
187
+ time ||= Time.now
188
+ time = Time.parse(time) if time.is_a?(String)
189
+ time
190
+ end
191
+
190
192
  def convert_drilldown_result(key, result)
191
193
  @drilldown_results << convert_search_result(result)
192
194
  end
@@ -194,12 +196,8 @@ module Droonga
194
196
  def convert_search_result(result)
195
197
  count = result["count"]
196
198
  attributes = convert_attributes(result["attributes"])
197
- records = result["records"]
198
- if records.nil? or records.empty?
199
- [[count], attributes]
200
- else
201
- [[count], attributes, records]
202
- end
199
+ records = convert_records(attributes, result["records"] || [])
200
+ [[count], attributes, *records]
203
201
  end
204
202
 
205
203
  def convert_attributes(attributes)
@@ -210,6 +208,20 @@ module Droonga
210
208
  [name, type]
211
209
  end
212
210
  end
211
+
212
+ def convert_records(attributes, records)
213
+ records.collect do |record|
214
+ record.collect.each_with_index do |value, i|
215
+ name, type = attributes[i]
216
+ case type
217
+ when "Time"
218
+ normalize_time(value).to_f
219
+ else
220
+ value
221
+ end
222
+ end
223
+ end
224
+ end
213
225
  end
214
226
 
215
227
  class Adapter < Droonga::Adapter
@@ -76,6 +76,28 @@ module Droonga
76
76
  end
77
77
  end
78
78
 
79
+ attributes_mapper = elements["attributes"]
80
+ if attributes_mapper and value["attributes"]
81
+ attributes = value["attributes"]
82
+ output_attributes = []
83
+ attributes_mapper["names"].each do |name|
84
+ if name == "*"
85
+ attributes.each do |attribute|
86
+ next if attribute["name"].start_with?("_")
87
+ output_attributes << attribute
88
+ end
89
+ else
90
+ attributes.each do |attribute|
91
+ if attribute["name"] == name
92
+ output_attributes << attribute
93
+ break
94
+ end
95
+ end
96
+ end
97
+ end
98
+ value["attributes"] = output_attributes
99
+ end
100
+
79
101
  records_mapper = elements["records"]
80
102
  if records_mapper and value["records"]
81
103
  if records_mapper["no_output"]
@@ -99,8 +121,14 @@ module Droonga
99
121
  complex_item
100
122
  end
101
123
  else
102
- items.collect do |item|
103
- item[0...attributes.size]
124
+ # FIXME: Compare with "attributes" value from "search" not
125
+ # gather parameter like the following.
126
+ if attributes.include?("*")
127
+ items
128
+ else
129
+ items.collect do |item|
130
+ item[0...attributes.size]
131
+ end
104
132
  end
105
133
  end
106
134
  end
@@ -77,18 +77,9 @@ module Droonga
77
77
  end
78
78
 
79
79
  def transform_query(input_name, query)
80
- output = query["output"]
81
-
82
- # Skip reducing phase for a result with no output.
83
- if output.nil? or
84
- output["elements"].nil? or
85
- (!output["elements"].include?("count") and
86
- !output["elements"].include?("records"))
87
- return
88
- end
80
+ return unless need_reduce?(query)
89
81
 
90
82
  transformer = QueryTransformer.new(query)
91
-
92
83
  elements = transformer.mappers
93
84
  mapper = {}
94
85
  mapper["elements"] = elements unless elements.empty?
@@ -96,6 +87,19 @@ module Droonga
96
87
  :gather => mapper })
97
88
  end
98
89
 
90
+ def need_reduce?(query)
91
+ output = query["output"]
92
+ return false if output.nil?
93
+
94
+ output_elements = output["elements"]
95
+ return false if output_elements.nil?
96
+
97
+ need_reduce_elements = ["count", "attributes", "records"]
98
+ output_elements.any? do |element|
99
+ need_reduce_elements.include?(element)
100
+ end
101
+ end
102
+
99
103
  class QueryTransformer
100
104
  attr_reader :reducers, :mappers
101
105
 
@@ -123,6 +127,7 @@ module Droonga
123
127
  calculate_offset_and_limit!
124
128
  build_count_mapper_and_reducer!
125
129
  build_elapsed_time_mapper_and_reducer!
130
+ build_attributes_mapper_and_reducer!
126
131
  build_records_mapper_and_reducer!
127
132
  end
128
133
 
@@ -265,6 +270,18 @@ module Droonga
265
270
  }
266
271
  end
267
272
 
273
+ def build_attributes_mapper_and_reducer!
274
+ return unless @output["elements"].include?("attributes")
275
+
276
+ @reducers["attributes"] = {
277
+ "type" => "or",
278
+ }
279
+
280
+ @mappers["attributes"] = {
281
+ "names" => output_attribute_names,
282
+ }
283
+ end
284
+
268
285
  def build_records_mapper_and_reducer!
269
286
  # Skip reducing phase for a result with no record output.
270
287
  return if !@output["elements"].include?("records") || @records_limit.zero?
@@ -325,7 +342,7 @@ module Droonga
325
342
  }
326
343
  when Hash
327
344
  attribute["label"] = key
328
- attribute
345
+ attribute
329
346
  end
330
347
  end
331
348
  else
@@ -15,6 +15,7 @@
15
15
 
16
16
  require "droonga/loggable"
17
17
  require "droonga/handler_runner"
18
+ require "fileutils"
18
19
 
19
20
  module Droonga
20
21
  class Processor
@@ -46,6 +47,9 @@ module Droonga
46
47
  synchronous = @handler_runner.prefer_synchronous?(type)
47
48
  if @n_workers.zero? or synchronous
48
49
  @handler_runner.process(message)
50
+ #XXX Workaround to restart system by any schema change.
51
+ # This should be done more smartly...
52
+ FileUtils.touch(Path.catalog.to_s) if synchronous
49
53
  else
50
54
  @job_pusher.push(message)
51
55
  end
@@ -663,6 +663,7 @@ module Droonga
663
663
 
664
664
  def output_target_attributes
665
665
  attributes = @request.output["attributes"]
666
+ attributes = expand_attributes(attributes)
666
667
  normalize_target_attributes(attributes)
667
668
  end
668
669
 
@@ -675,6 +676,31 @@ module Droonga
675
676
  formatter.format(output_target_attributes, @result.records, output_limit, output_offset)
676
677
  end
677
678
 
679
+ def expand_attributes(attributes, domain = @result.records)
680
+ expanded_attributes = []
681
+ attributes.each do |attribute|
682
+ if attribute.is_a?(String)
683
+ source = attribute
684
+ else
685
+ source = attribute["source"]
686
+ end
687
+ if source == "*"
688
+ real_table = domain
689
+ loop do
690
+ next_domain = real_table.domain
691
+ break unless next_domain.is_a?(Groonga::Table)
692
+ real_table = next_domain
693
+ end
694
+ real_table.columns.each do |column|
695
+ expanded_attributes << column.local_name
696
+ end
697
+ else
698
+ expanded_attributes << attribute
699
+ end
700
+ end
701
+ expanded_attributes
702
+ end
703
+
678
704
  def normalize_target_attributes(attributes, domain = @result.records)
679
705
  attributes.collect do |attribute|
680
706
  if attribute.is_a?(String)
@@ -0,0 +1,119 @@
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/path"
17
+ require "droonga/loggable"
18
+ require "droonga/catalog_loader"
19
+ require "droonga/serf_downloader"
20
+
21
+ module Droonga
22
+ class Serf
23
+ class << self
24
+ def path
25
+ Droonga::Path.base + "serf"
26
+ end
27
+ end
28
+
29
+ include Loggable
30
+
31
+ def initialize(loop, name)
32
+ @loop = loop
33
+ @name = name
34
+ @pid = nil
35
+ end
36
+
37
+ def start
38
+ logger.trace("start: start")
39
+ ensure_serf
40
+ ENV["SERF"] = @serf
41
+ ENV["SERF_RPC_ADDRESS"] = rpc_address
42
+ retry_joins = []
43
+ detect_other_hosts.each do |other_host|
44
+ retry_joins.push("-retry-join", other_host)
45
+ end
46
+ @pid = run("agent",
47
+ "-node", @name,
48
+ "-bind", extract_host(@name),
49
+ "-event-handler", "droonga-engine-serf-event-handler",
50
+ *retry_joins)
51
+ logger.trace("start: done")
52
+ end
53
+
54
+ def running?
55
+ not @pid.nil?
56
+ end
57
+
58
+ def shutdown
59
+ logger.trace("shutdown: start")
60
+ Process.waitpid(run("leave"))
61
+ Process.waitpid(@pid)
62
+ @pid = nil
63
+ logger.trace("shutdown: done")
64
+ end
65
+
66
+ def restart
67
+ shutdown
68
+ start
69
+ end
70
+
71
+ private
72
+ def ensure_serf
73
+ @serf = find_system_serf
74
+ return if @serf
75
+
76
+ serf_path = self.class.path
77
+ @serf = serf_path.to_s
78
+ return if serf_path.executable?
79
+ downloader = SerfDownloader.new(serf_path)
80
+ downloader.download
81
+ end
82
+
83
+ def find_system_serf
84
+ paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
85
+ paths.each do |path|
86
+ serf = File.join(path, "serf")
87
+ return serf if File.executable?(serf)
88
+ end
89
+ nil
90
+ end
91
+
92
+ def run(command, *options)
93
+ spawn(@serf, command, "-rpc-addr", rpc_address, *options)
94
+ end
95
+
96
+ def extract_host(node_name)
97
+ node_name.split(":").first
98
+ end
99
+
100
+ def rpc_address
101
+ "#{extract_host(@name)}:7373"
102
+ end
103
+
104
+ def detect_other_hosts
105
+ loader = CatalogLoader.new(Path.catalog.to_s)
106
+ catalog = loader.load
107
+ other_nodes = catalog.all_nodes.reject do |node|
108
+ node == @name
109
+ end
110
+ other_nodes.collect do |node|
111
+ extract_host(node)
112
+ end
113
+ end
114
+
115
+ def log_tag
116
+ "serf"
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,90 @@
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 "stringio"
17
+ require "tmpdir"
18
+ require "fileutils"
19
+
20
+ require "faraday"
21
+ require "faraday_middleware"
22
+ require "archive/zip"
23
+
24
+ require "droonga/loggable"
25
+
26
+ module Droonga
27
+ class SerfDownloader
28
+ include Loggable
29
+
30
+ def initialize(output_path)
31
+ @output_path = output_path
32
+ end
33
+
34
+ def download
35
+ detect_platform
36
+ version = "0.6.0"
37
+ url_base = "https://dl.bintray.com/mitchellh/serf"
38
+ base_name = "#{version}_#{@os}_#{@architecture}.zip"
39
+ connection = Faraday.new(url_base) do |builder|
40
+ builder.response(:follow_redirects)
41
+ builder.adapter(Faraday.default_adapter)
42
+ end
43
+ response = connection.get(base_name)
44
+ absolete_output_path = @output_path.expand_path
45
+ Dir.mktmpdir do |dir|
46
+ Archive::Zip.extract(StringIO.new(response.body),
47
+ dir,
48
+ :directories => false)
49
+ FileUtils.mv("#{dir}/serf", absolete_output_path.to_s)
50
+ FileUtils.chmod(0755, absolete_output_path.to_s)
51
+ end
52
+ end
53
+
54
+ private
55
+ def detect_platform
56
+ detect_os
57
+ detect_architecture
58
+ end
59
+
60
+ def detect_os
61
+ case RUBY_PLATFORM
62
+ when /linux/
63
+ @os = "linux"
64
+ when /freebsd/
65
+ @os = "freebsd"
66
+ when /darwin/
67
+ @os = "darwin"
68
+ when /mswin|mingw/
69
+ @os = "windows"
70
+ else
71
+ raise "Unsupported OS: #{RUBY_PLATFORM}"
72
+ end
73
+ end
74
+
75
+ def detect_architecture
76
+ case RUBY_PLATFORM
77
+ when /x86_64|x64/
78
+ @architecture = "amd64"
79
+ when /i\d86/
80
+ @architecture = "i386"
81
+ else
82
+ raise "Unsupported architecture: #{RUBY_PLATFORM}"
83
+ end
84
+ end
85
+
86
+ def log_tag
87
+ "serf-downloader"
88
+ end
89
+ end
90
+ end