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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +3 -0
- data/Gemfile +7 -0
- data/Rakefile +6 -2
- data/bin/droonga-engine +2 -2
- data/bin/{droonga-catalog-generate → droonga-engine-catalog-generate} +15 -3
- data/bin/droonga-engine-serf-event-handler +20 -0
- data/bin/droonga-engine-service +2 -2
- data/doc/text/news.md +21 -1
- data/droonga-engine.gemspec +5 -2
- data/lib/droonga/catalog/collection_volume.rb +12 -0
- data/lib/droonga/catalog/dataset.rb +25 -0
- data/lib/droonga/catalog/single_volume.rb +10 -0
- data/lib/droonga/catalog/slice.rb +4 -0
- data/lib/droonga/catalog/version1.rb +59 -48
- data/lib/droonga/catalog/version2.rb +10 -20
- data/lib/droonga/catalog/volume_collection.rb +27 -4
- data/lib/droonga/catalog_generator.rb +12 -5
- data/lib/droonga/catalog_observer.rb +17 -35
- data/lib/droonga/command/droonga_engine.rb +436 -0
- data/lib/droonga/command/droonga_engine_service.rb +273 -0
- data/lib/droonga/command/serf_event_handler.rb +85 -0
- data/lib/droonga/dispatcher.rb +8 -8
- data/lib/droonga/engine.rb +90 -26
- data/lib/droonga/engine/version.rb +1 -1
- data/lib/droonga/engine_state.rb +29 -3
- data/lib/droonga/internal_fluent_message_receiver.rb +100 -0
- data/lib/droonga/live_nodes_list_loader.rb +48 -0
- data/lib/droonga/live_nodes_list_observer.rb +72 -0
- data/lib/droonga/path.rb +47 -0
- data/lib/droonga/plugins/dump.rb +279 -38
- data/lib/droonga/plugins/groonga/select.rb +26 -14
- data/lib/droonga/plugins/search.rb +30 -2
- data/lib/droonga/plugins/search/distributed_search_planner.rb +28 -11
- data/lib/droonga/processor.rb +4 -0
- data/lib/droonga/searcher.rb +26 -0
- data/lib/droonga/serf.rb +119 -0
- data/lib/droonga/serf_downloader.rb +90 -0
- data/lib/droonga/server.rb +2 -2
- data/lib/droonga/service_control_protocol.rb +26 -0
- data/sample/cluster/catalog.json +1 -1
- data/test/command/config/default/catalog.json +2 -2
- data/test/command/config/version1/catalog.json +1 -1
- data/test/command/fixture/documents.jsons +18 -18
- data/test/command/fixture/event.jsons +4 -4
- data/test/command/fixture/user-table-array.jsons +4 -4
- data/test/command/fixture/user-table.jsons +5 -5
- data/test/command/suite/add/dimension/column.catalog.json +1 -1
- data/test/command/suite/add/dimension/column.test +4 -4
- data/test/command/suite/add/dimension/integer.catalog.json +1 -1
- data/test/command/suite/add/dimension/integer.test +4 -4
- data/test/command/suite/add/error/invalid-integer.test +1 -1
- data/test/command/suite/add/error/invalid-time.test +1 -1
- data/test/command/suite/add/error/missing-key.test +1 -1
- data/test/command/suite/add/error/missing-table.test +1 -1
- data/test/command/suite/add/error/unknown-column.test +1 -1
- data/test/command/suite/add/error/unknown-table.test +1 -1
- data/test/command/suite/add/minimum.test +1 -1
- data/test/command/suite/add/vector/short_text.catalog.json +26 -0
- data/test/command/suite/add/vector/short_text.expected +42 -0
- data/test/command/suite/add/vector/short_text.test +35 -0
- data/test/command/suite/add/with-values.test +1 -1
- data/test/command/suite/add/without-key.test +1 -1
- data/test/command/suite/dump/column/index.catalog.json +40 -0
- data/test/command/suite/dump/column/index.expected +195 -0
- data/test/command/suite/dump/column/index.test +5 -0
- data/test/command/suite/dump/column/scalar.catalog.json +19 -0
- data/test/command/suite/dump/column/scalar.expected +99 -0
- data/test/command/suite/dump/column/scalar.test +5 -0
- data/test/command/suite/dump/column/vector.catalog.json +22 -0
- data/test/command/suite/dump/column/vector.expected +108 -0
- data/test/command/suite/dump/column/vector.test +5 -0
- data/test/command/suite/dump/record/vector/reference.catalog.json +27 -0
- data/test/command/suite/dump/record/vector/reference.expected +213 -0
- data/test/command/suite/dump/record/vector/reference.test +21 -0
- data/test/command/suite/dump/table/array.catalog.json +13 -0
- data/test/command/suite/dump/table/array.expected +63 -0
- data/test/command/suite/dump/table/array.test +5 -0
- data/test/command/suite/dump/table/double_array_trie.catalog.json +14 -0
- data/test/command/suite/dump/table/double_array_trie.expected +66 -0
- data/test/command/suite/dump/table/double_array_trie.test +5 -0
- data/test/command/suite/dump/table/hash.catalog.json +14 -0
- data/test/command/suite/dump/table/hash.expected +66 -0
- data/test/command/suite/dump/table/hash.test +5 -0
- data/test/command/suite/dump/table/patricia_trie.catalog.json +14 -0
- data/test/command/suite/dump/table/patricia_trie.expected +66 -0
- data/test/command/suite/dump/table/patricia_trie.test +5 -0
- data/test/command/suite/groonga/column_create/scalar.test +2 -2
- data/test/command/suite/groonga/column_create/unknown-table.test +1 -1
- data/test/command/suite/groonga/column_create/vector.test +2 -2
- data/test/command/suite/groonga/column_list/success.test +3 -3
- data/test/command/suite/groonga/column_list/unknown-table.test +1 -1
- data/test/command/suite/groonga/column_remove/success.test +3 -3
- data/test/command/suite/groonga/column_remove/unknown-column.test +2 -2
- data/test/command/suite/groonga/column_remove/unknown-table.test +1 -1
- data/test/command/suite/groonga/column_rename/success.test +3 -3
- data/test/command/suite/groonga/column_rename/unknown-column.test +2 -2
- data/test/command/suite/groonga/column_rename/unknown-table.test +1 -1
- data/test/command/suite/groonga/delete/duplicated-identifiers.test +2 -2
- data/test/command/suite/groonga/delete/filter.test +2 -2
- data/test/command/suite/groonga/delete/invalid-filter.test +1 -1
- data/test/command/suite/groonga/delete/no-identifier.test +2 -2
- data/test/command/suite/groonga/delete/success.test +2 -2
- data/test/command/suite/groonga/delete/unknown-table.test +1 -1
- data/test/command/suite/groonga/select/minimum.expected +24 -1
- data/test/command/suite/groonga/select/minimum.test +1 -1
- data/test/command/suite/groonga/select/type/time.catalog.json +19 -0
- data/test/command/suite/groonga/select/type/time.expected +37 -0
- data/test/command/suite/groonga/select/type/time.test +35 -0
- data/test/command/suite/groonga/table_create/array.test +1 -1
- data/test/command/suite/groonga/table_create/hash.test +1 -1
- data/test/command/suite/groonga/table_list/success.test +2 -2
- data/test/command/suite/groonga/table_remove/success.test +1 -1
- data/test/command/suite/groonga/table_remove/unknown-table.test +1 -1
- data/test/command/suite/message/error/unknown-type.expected +1 -1
- data/test/command/suite/message/error/unknown-type.test +1 -1
- data/test/command/suite/search/adjusters/multiple.catalog.json +1 -1
- data/test/command/suite/search/adjusters/multiple.test +3 -3
- data/test/command/suite/search/adjusters/one.catalog.json +1 -1
- data/test/command/suite/search/adjusters/one.test +3 -3
- data/test/command/suite/search/attributes/array.expected +7 -0
- data/test/command/suite/search/attributes/array.test +1 -1
- data/test/command/suite/search/attributes/hash.expected +18 -0
- data/test/command/suite/search/attributes/hash.test +1 -1
- data/test/command/suite/search/complex.expected +12 -0
- data/test/command/suite/search/complex.test +1 -1
- data/test/command/suite/search/condition/nested.catalog.json +37 -0
- data/test/command/suite/search/condition/nested.expected +7 -0
- data/test/command/suite/search/condition/nested.test +103 -2
- data/test/command/suite/search/condition/query.catalog.json +37 -0
- data/test/command/suite/search/condition/query.expected +7 -0
- data/test/command/suite/search/condition/query.test +103 -2
- data/test/command/suite/search/condition/query/nonexistent_column.catalog.json +1 -1
- data/test/command/suite/search/condition/query/nonexistent_column.test +2 -2
- data/test/command/suite/search/condition/query/syntax_error.catalog.json +1 -1
- data/test/command/suite/search/condition/query/syntax_error.test +2 -2
- data/test/command/suite/search/condition/script.catalog.json +37 -0
- data/test/command/suite/search/condition/script.expected +7 -0
- data/test/command/suite/search/condition/script.test +103 -2
- data/test/command/suite/search/error/cyclic-source.test +1 -1
- data/test/command/suite/search/error/deeply-cyclic-source.test +1 -1
- data/test/command/suite/search/error/missing-source-parameter.test +1 -1
- data/test/command/suite/search/error/no-query.test +1 -1
- data/test/command/suite/search/error/unknown-source.test +1 -1
- data/test/command/suite/search/group/count.test +1 -1
- data/test/command/suite/search/group/limit.test +1 -1
- data/test/command/suite/search/group/string.catalog.json +41 -0
- data/test/command/suite/search/group/string.expected +18 -18
- data/test/command/suite/search/group/string.test +67 -22
- data/test/command/suite/search/group/subrecord/with-sort.catalog.json +1 -1
- data/test/command/suite/search/group/subrecord/with-sort.test +5 -5
- data/test/command/suite/search/multiple/chained.catalog.json +37 -0
- data/test/command/suite/search/multiple/chained.expected +14 -0
- data/test/command/suite/search/multiple/chained.test +103 -2
- data/test/command/suite/search/multiple/parallel.expected +14 -0
- data/test/command/suite/search/multiple/parallel.test +1 -1
- data/test/command/suite/search/output/attributes/invalid.catalog.json +1 -1
- data/test/command/suite/search/output/attributes/invalid.test +2 -2
- data/test/command/suite/search/output/attributes/star.catalog.json +23 -0
- data/test/command/suite/search/output/attributes/star.expected +27 -0
- data/test/command/suite/search/output/attributes/star.test +32 -0
- data/test/command/suite/search/range/only-output.expected +7 -0
- data/test/command/suite/search/range/only-output.test +1 -1
- data/test/command/suite/search/range/only-sort.expected +7 -0
- data/test/command/suite/search/range/only-sort.test +1 -1
- data/test/command/suite/search/range/sort-and-output.expected +7 -0
- data/test/command/suite/search/range/sort-and-output.test +1 -1
- data/test/command/suite/search/range/too-large-output-offset.expected +8 -0
- data/test/command/suite/search/range/too-large-output-offset.test +1 -1
- data/test/command/suite/search/range/too-large-sort-offset.expected +8 -0
- data/test/command/suite/search/range/too-large-sort-offset.test +1 -1
- data/test/command/suite/search/response/elapsed_time.catalog.json +1 -1
- data/test/command/suite/search/response/elapsed_time.test +2 -2
- data/test/command/suite/search/response/records/value/time.expected +12 -0
- data/test/command/suite/search/response/records/value/time.test +1 -1
- data/test/command/suite/search/simple.expected +12 -0
- data/test/command/suite/search/simple.test +1 -1
- data/test/command/suite/search/sort/default-offset-limit.expected +7 -0
- data/test/command/suite/search/sort/default-offset-limit.test +1 -1
- data/test/command/suite/search/sort/invisible-column.expected +7 -0
- data/test/command/suite/search/sort/invisible-column.test +1 -1
- data/test/unit/catalog/test_collection_volume.rb +16 -0
- data/test/unit/catalog/test_dataset.rb +36 -0
- data/test/unit/catalog/test_single_volume.rb +9 -0
- data/test/unit/catalog/test_slice.rb +11 -0
- data/test/unit/catalog/test_version1.rb +7 -12
- data/test/unit/catalog/test_version2.rb +7 -0
- data/test/unit/catalog/test_volume_collection.rb +28 -0
- data/test/unit/fixtures/catalog/version1.json +10 -3
- data/test/unit/fixtures/catalog/version2.json +2 -2
- data/test/unit/plugins/groonga/select/test_adapter_output.rb +8 -14
- data/test/unit/plugins/groonga/test_column_create.rb +5 -5
- data/test/unit/plugins/groonga/test_column_remove.rb +2 -2
- data/test/unit/plugins/groonga/test_column_rename.rb +2 -2
- data/test/unit/plugins/groonga/test_delete.rb +2 -2
- data/test/unit/plugins/groonga/test_table_create.rb +9 -9
- data/test/unit/plugins/groonga/test_table_remove.rb +1 -1
- data/test/unit/test_catalog_generator.rb +1 -1
- data/test/unit/test_schema_applier.rb +2 -2
- data/test/unit/test_watch_schema.rb +4 -4
- metadata +241 -72
- 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 =
|
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
|
-
|
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
|
-
|
103
|
-
|
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
|
-
|
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
|
-
|
345
|
+
attribute
|
329
346
|
end
|
330
347
|
end
|
331
348
|
else
|
data/lib/droonga/processor.rb
CHANGED
@@ -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
|
data/lib/droonga/searcher.rb
CHANGED
@@ -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)
|
data/lib/droonga/serf.rb
ADDED
@@ -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
|