fluent-plugin-droonga 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/Gemfile +1 -1
- data/fluent-plugin-droonga.gemspec +1 -1
- data/lib/droonga/catalog/collection_volume.rb +97 -0
- data/lib/droonga/catalog/dataset.rb +28 -1
- data/lib/droonga/catalog/errors.rb +28 -9
- data/lib/droonga/catalog/schema.rb +23 -2
- data/lib/droonga/catalog/single_volume.rb +28 -0
- data/lib/droonga/catalog/slice.rb +43 -0
- data/lib/droonga/catalog/version1.rb +3 -3
- data/lib/droonga/catalog/version2.rb +17 -81
- data/lib/droonga/catalog/version2_validator.rb +63 -0
- data/lib/droonga/catalog/volume.rb +33 -0
- data/lib/droonga/catalog/volume_collection.rb +56 -0
- data/lib/droonga/catalog_observer.rb +7 -19
- data/lib/droonga/collectors.rb +1 -1
- data/lib/droonga/collectors/{add.rb → or.rb} +1 -1
- data/lib/droonga/dispatcher.rb +24 -18
- data/lib/droonga/distributed_command_planner.rb +7 -11
- data/lib/droonga/distributor.rb +29 -17
- data/lib/droonga/event_loop.rb +2 -11
- data/lib/droonga/fluent_message_sender.rb +51 -5
- data/lib/droonga/handler_runner.rb +1 -1
- data/lib/droonga/job_protocol.rb +20 -0
- data/lib/droonga/job_pusher.rb +178 -0
- data/lib/droonga/{message_receiver.rb → job_receiver.rb} +13 -6
- data/lib/droonga/message_matcher.rb +18 -15
- data/lib/droonga/planner.rb +2 -3
- data/lib/droonga/plugins/crud.rb +1 -1
- data/lib/droonga/plugins/groonga/column_create.rb +4 -1
- data/lib/droonga/plugins/groonga/table_create.rb +1 -1
- data/lib/droonga/plugins/groonga/table_remove.rb +1 -1
- data/lib/droonga/plugins/search/distributed_search_planner.rb +9 -0
- data/lib/droonga/processor.rb +3 -3
- data/lib/droonga/reducer.rb +15 -12
- data/lib/droonga/searcher.rb +49 -4
- data/lib/droonga/server.rb +2 -0
- data/lib/droonga/single_step.rb +22 -7
- data/lib/droonga/slice.rb +7 -7
- data/lib/droonga/step_runner.rb +3 -2
- data/lib/droonga/worker.rb +10 -8
- data/test/command/suite/add/dimension/column.catalog.json +27 -0
- data/test/command/suite/add/dimension/column.expected +57 -0
- data/test/command/suite/add/dimension/column.test +51 -0
- data/test/command/suite/search/adjusters/multiple.catalog.json +38 -0
- data/test/command/suite/search/adjusters/multiple.expected +23 -0
- data/test/command/suite/search/adjusters/multiple.test +75 -0
- data/test/command/suite/search/adjusters/one.catalog.json +38 -0
- data/test/command/suite/search/adjusters/one.expected +23 -0
- data/test/command/suite/search/adjusters/one.test +66 -0
- data/test/command/suite/search/attributes/array.test +0 -2
- data/test/command/suite/search/attributes/hash.test +0 -2
- data/test/command/suite/search/complex.test +0 -2
- data/test/command/suite/search/condition/nested.test +0 -2
- data/test/command/suite/search/condition/query.test +0 -2
- data/test/command/suite/search/condition/script.test +0 -2
- data/test/command/suite/search/group/string.test +0 -4
- data/test/command/suite/search/group/subrecord/with-sort.catalog.json +33 -0
- data/test/command/suite/search/group/subrecord/with-sort.expected +34 -0
- data/test/command/suite/search/group/subrecord/with-sort.test +81 -0
- data/test/command/suite/search/multiple/chained.test +0 -4
- data/test/command/suite/search/multiple/parallel.test +0 -4
- data/test/command/suite/search/range/only-output.test +0 -2
- data/test/command/suite/search/range/only-sort.test +0 -2
- data/test/command/suite/search/range/sort-and-output.test +0 -2
- data/test/command/suite/search/range/too-large-output-offset.test +0 -2
- data/test/command/suite/search/range/too-large-sort-offset.test +0 -2
- data/test/command/suite/search/response/elapsed_time.catalog.json +13 -0
- data/test/command/suite/search/response/elapsed_time.expected +15 -0
- data/test/command/suite/search/response/elapsed_time.test +26 -0
- data/test/command/suite/search/response/records/value/time.test +0 -2
- data/test/command/suite/search/simple.test +0 -2
- data/test/command/suite/search/sort/default-offset-limit.test +0 -2
- data/test/command/suite/search/sort/invisible-column.test +0 -2
- data/test/unit/catalog/test_collection_volume.rb +103 -0
- data/test/unit/catalog/test_dataset.rb +69 -8
- data/test/unit/catalog/test_schema.rb +63 -23
- data/test/unit/catalog/test_single_volume.rb +31 -0
- data/test/unit/catalog/test_slice.rb +92 -0
- data/test/unit/catalog/test_version1.rb +1 -1
- data/test/unit/catalog/test_version2.rb +1 -32
- data/test/unit/catalog/test_version2_validator.rb +66 -0
- data/test/unit/catalog/test_volume_collection.rb +50 -0
- data/test/unit/plugins/groonga/test_column_create.rb +4 -1
- data/test/unit/plugins/groonga/test_table_create.rb +1 -1
- data/test/unit/test_message_matcher.rb +15 -15
- data/test/unit/test_watch_schema.rb +1 -1
- metadata +107 -94
- checksums.yaml +0 -7
- data/lib/droonga/message_pusher.rb +0 -64
@@ -0,0 +1,63 @@
|
|
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/catalog/errors"
|
17
|
+
|
18
|
+
module Droonga
|
19
|
+
module Catalog
|
20
|
+
class Version2Validator
|
21
|
+
def initialize(data, path)
|
22
|
+
@data = data
|
23
|
+
@path = path
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate
|
27
|
+
@details = []
|
28
|
+
|
29
|
+
validate_datasets
|
30
|
+
|
31
|
+
unless @details.empty?
|
32
|
+
raise ValidationError.new(@path, @details)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def validate_datasets
|
38
|
+
unless @data.key?("datasets")
|
39
|
+
required_parameter_is_missing("datasets")
|
40
|
+
return
|
41
|
+
end
|
42
|
+
@data["datasets"].each do |name, dataset|
|
43
|
+
validate_dataset(name, dataset)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_dataset(name, dataset)
|
48
|
+
unless dataset.key?("replicas")
|
49
|
+
required_parameter_is_missing("datasets.#{name}.replicas")
|
50
|
+
return
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def add_detail(value_path, message)
|
55
|
+
@details << ValidationError::Detail.new(value_path, message)
|
56
|
+
end
|
57
|
+
|
58
|
+
def required_parameter_is_missing(value_path)
|
59
|
+
add_detail(value_path, "required parameter is missing")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,33 @@
|
|
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/catalog/single_volume"
|
17
|
+
require "droonga/catalog/collection_volume"
|
18
|
+
|
19
|
+
module Droonga
|
20
|
+
module Catalog
|
21
|
+
module Volume
|
22
|
+
class << self
|
23
|
+
def create(dataset, raw_volume)
|
24
|
+
if raw_volume.key?("address")
|
25
|
+
SingleVolume.new(raw_volume)
|
26
|
+
else
|
27
|
+
CollectionVolume.new(dataset, raw_volume)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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 VolumeCollection
|
19
|
+
include Enumerable
|
20
|
+
|
21
|
+
def initialize(volumes)
|
22
|
+
@volumes = volumes
|
23
|
+
end
|
24
|
+
|
25
|
+
def each(&block)
|
26
|
+
@volumes.each(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def ==(other)
|
30
|
+
other.is_a?(self.class) and
|
31
|
+
to_a == other.to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
def eql?(other)
|
35
|
+
self == other
|
36
|
+
end
|
37
|
+
|
38
|
+
def hash
|
39
|
+
to_a.hash
|
40
|
+
end
|
41
|
+
|
42
|
+
def select(how=nil)
|
43
|
+
case how
|
44
|
+
when :top
|
45
|
+
[@volumes.first]
|
46
|
+
when :random
|
47
|
+
[@volumes.sample]
|
48
|
+
when :all
|
49
|
+
@volumes
|
50
|
+
else
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -34,29 +34,17 @@ module Droonga
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def start
|
37
|
-
@
|
38
|
-
|
39
|
-
@
|
40
|
-
|
41
|
-
@loop.run
|
42
|
-
rescue => error
|
43
|
-
logger.exception("error in catalog observing thread", error)
|
44
|
-
end
|
37
|
+
@watcher = Cool.io::TimerWatcher.new(CHECK_INTERVAL, true)
|
38
|
+
observer = self
|
39
|
+
@watcher.on_timer do
|
40
|
+
observer.ensure_latest_catalog_loaded
|
45
41
|
end
|
42
|
+
loop = Coolio::Loop.default
|
43
|
+
@watcher.attach(loop)
|
46
44
|
end
|
47
45
|
|
48
46
|
def stop
|
49
|
-
@
|
50
|
-
@thread.join
|
51
|
-
end
|
52
|
-
|
53
|
-
def attach(loop)
|
54
|
-
watcher = Cool.io::TimerWatcher.new(CHECK_INTERVAL, true)
|
55
|
-
observer = self
|
56
|
-
watcher.on_timer do
|
57
|
-
observer.ensure_latest_catalog_loaded
|
58
|
-
end
|
59
|
-
loop.attach(watcher)
|
47
|
+
@watcher.detach
|
60
48
|
end
|
61
49
|
|
62
50
|
def ensure_latest_catalog_loaded
|
data/lib/droonga/collectors.rb
CHANGED
@@ -13,6 +13,6 @@
|
|
13
13
|
# License along with this library; if not, write to the Free Software
|
14
14
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
15
15
|
|
16
|
-
require "droonga/collectors/add"
|
17
16
|
require "droonga/collectors/and"
|
17
|
+
require "droonga/collectors/or"
|
18
18
|
require "droonga/collectors/sum"
|
data/lib/droonga/dispatcher.rb
CHANGED
@@ -54,7 +54,7 @@ module Droonga
|
|
54
54
|
@catalog = catalog
|
55
55
|
@options = options
|
56
56
|
@name = @options[:name]
|
57
|
-
@loop = EventLoop.new
|
57
|
+
@loop = EventLoop.new(Coolio::Loop.default)
|
58
58
|
@sessions = {}
|
59
59
|
@current_id = 0
|
60
60
|
@local = Regexp.new("^#{@name}")
|
@@ -69,9 +69,6 @@ module Droonga
|
|
69
69
|
def start
|
70
70
|
@forwarder.start
|
71
71
|
@farm.start
|
72
|
-
@loop_thread = Thread.new do
|
73
|
-
@loop.run
|
74
|
-
end
|
75
72
|
|
76
73
|
ensure_schema
|
77
74
|
end
|
@@ -85,8 +82,6 @@ module Droonga
|
|
85
82
|
adapter_runner.shutdown
|
86
83
|
end
|
87
84
|
@farm.shutdown
|
88
|
-
@loop.stop
|
89
|
-
@loop_thread.join
|
90
85
|
end
|
91
86
|
|
92
87
|
def process_message(message)
|
@@ -134,8 +129,19 @@ module Droonga
|
|
134
129
|
if adapter_runner
|
135
130
|
adapted_message = adapter_runner.adapt_output(adapted_message)
|
136
131
|
end
|
137
|
-
|
138
|
-
|
132
|
+
if adapted_message["replyTo"].nil?
|
133
|
+
status_code = adapted_message["statusCode"] || 200
|
134
|
+
if status_code != 200
|
135
|
+
dataset = adapted_message["dataset"]
|
136
|
+
body = adapted_message["body"] || {}
|
137
|
+
name = body["name"] || "Unknown"
|
138
|
+
message = body["message"] || "unknown error"
|
139
|
+
logger.error("orphan error: " +
|
140
|
+
"<#{dataset}>[#{name}](#{status_code}): #{message}")
|
141
|
+
end
|
142
|
+
else
|
143
|
+
@replier.reply(adapted_message)
|
144
|
+
end
|
139
145
|
end
|
140
146
|
|
141
147
|
def process_internal_message(message)
|
@@ -233,8 +239,8 @@ module Droonga
|
|
233
239
|
adapted_message = adapter_runner.adapt_input(message)
|
234
240
|
step_runner = @step_runners[dataset]
|
235
241
|
plan = step_runner.plan(message)
|
236
|
-
distributor = Distributor.new(self)
|
237
|
-
distributor.distribute
|
242
|
+
distributor = Distributor.new(self, plan)
|
243
|
+
distributor.distribute
|
238
244
|
rescue Droonga::UnsupportedMessageError => error
|
239
245
|
target_message = error.message
|
240
246
|
raise UnknownType.new(target_message["type"], target_message["dataset"])
|
@@ -252,27 +258,27 @@ module Droonga
|
|
252
258
|
|
253
259
|
def create_runners
|
254
260
|
runners = {}
|
255
|
-
@catalog.datasets.each do |name,
|
256
|
-
runners[name] = yield(
|
261
|
+
@catalog.datasets.each do |name, dataset|
|
262
|
+
runners[name] = yield(dataset)
|
257
263
|
end
|
258
264
|
runners
|
259
265
|
end
|
260
266
|
|
261
267
|
def create_adapter_runners
|
262
|
-
create_runners do |
|
263
|
-
AdapterRunner.new(self,
|
268
|
+
create_runners do |dataset|
|
269
|
+
AdapterRunner.new(self, dataset.plugins)
|
264
270
|
end
|
265
271
|
end
|
266
272
|
|
267
273
|
def create_collector_runners
|
268
|
-
create_runners do |
|
269
|
-
CollectorRunner.new(
|
274
|
+
create_runners do |dataset|
|
275
|
+
CollectorRunner.new(dataset.plugins)
|
270
276
|
end
|
271
277
|
end
|
272
278
|
|
273
279
|
def create_step_runners
|
274
|
-
create_runners do |
|
275
|
-
StepRunner.new(
|
280
|
+
create_runners do |dataset|
|
281
|
+
StepRunner.new(dataset, dataset.plugins)
|
276
282
|
end
|
277
283
|
end
|
278
284
|
|
@@ -55,12 +55,12 @@ module Droonga
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
def scatter(options={})
|
58
|
+
def scatter(record, options={})
|
59
59
|
@processor = {
|
60
60
|
"command" => @source_message["type"],
|
61
61
|
"dataset" => @dataset || @source_message["dataset"],
|
62
62
|
"body" => options[:body] || @source_message["body"],
|
63
|
-
"
|
63
|
+
"record" => record,
|
64
64
|
"type" => "scatter",
|
65
65
|
"outputs" => [],
|
66
66
|
"replica" => "all",
|
@@ -100,10 +100,10 @@ module Droonga
|
|
100
100
|
unified = unified_reducers[type]
|
101
101
|
if unified
|
102
102
|
unified["body"] = unified["body"].merge(reducer["body"])
|
103
|
-
unified["inputs"]
|
104
|
-
unified["outputs"]
|
103
|
+
unified["inputs"] += reducer["inputs"]
|
104
|
+
unified["outputs"] += reducer["outputs"]
|
105
105
|
else
|
106
|
-
unified_reducers[type] =
|
106
|
+
unified_reducers[type] = reducer.dup
|
107
107
|
end
|
108
108
|
end
|
109
109
|
unified_reducers.values
|
@@ -116,9 +116,9 @@ module Droonga
|
|
116
116
|
unified = unified_gatherers[type]
|
117
117
|
if unified
|
118
118
|
unified["body"] = unified["body"].merge(gatherer["body"])
|
119
|
-
unified["inputs"]
|
119
|
+
unified["inputs"] += gatherer["inputs"]
|
120
120
|
else
|
121
|
-
unified_gatherers[type] =
|
121
|
+
unified_gatherers[type] = gatherer.dup
|
122
122
|
end
|
123
123
|
end
|
124
124
|
unified_gatherers.values
|
@@ -126,10 +126,6 @@ module Droonga
|
|
126
126
|
|
127
127
|
def fixed_processor
|
128
128
|
@processor["outputs"] = @outputs
|
129
|
-
if @processor["type"] == "scatter"
|
130
|
-
raise ErrorMessages::InternalServerError.new("missing key") unless @key
|
131
|
-
@processor["key"] = @key
|
132
|
-
end
|
133
129
|
@processor
|
134
130
|
end
|
135
131
|
|
data/lib/droonga/distributor.rb
CHANGED
@@ -37,38 +37,50 @@ module Droonga
|
|
37
37
|
|
38
38
|
include TSort
|
39
39
|
|
40
|
-
def initialize(dispatcher)
|
40
|
+
def initialize(dispatcher, plan)
|
41
41
|
@dispatcher = dispatcher
|
42
|
+
@plan = plan
|
43
|
+
build_dependencies
|
42
44
|
end
|
43
45
|
|
44
|
-
def distribute
|
45
|
-
@dependency = {}
|
46
|
-
plan.each do |step|
|
47
|
-
@dependency[step] = step["inputs"]
|
48
|
-
next unless step["outputs"]
|
49
|
-
step["outputs"].each do |output|
|
50
|
-
@dependency[output] = [step]
|
51
|
-
end
|
52
|
-
end
|
46
|
+
def distribute
|
53
47
|
steps = []
|
54
|
-
each_strongly_connected_component do |
|
55
|
-
raise CyclicStepsError.new(
|
56
|
-
|
48
|
+
each_strongly_connected_component do |nodes|
|
49
|
+
raise CyclicStepsError.new(nodes) if nodes.size > 1
|
50
|
+
nodes.each do |node|
|
51
|
+
steps << @step_maps[node] if node.is_a?(Integer)
|
52
|
+
end
|
57
53
|
end
|
58
54
|
@dispatcher.dispatch_steps(steps)
|
59
55
|
end
|
60
56
|
|
61
57
|
private
|
58
|
+
def build_dependencies
|
59
|
+
@dependencies = {}
|
60
|
+
@step_maps = {}
|
61
|
+
step_id = 0
|
62
|
+
@plan.each do |step|
|
63
|
+
step_id += 1
|
64
|
+
# Integer#hash (step_id.hash) is very faster than Hash#hash (step.hash).
|
65
|
+
@step_maps[step_id] = step
|
66
|
+
@dependencies[step_id] = step["inputs"]
|
67
|
+
next unless step["outputs"]
|
68
|
+
step["outputs"].each do |output|
|
69
|
+
@dependencies[output] = [step_id]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
62
74
|
def tsort_each_node(&block)
|
63
|
-
@
|
75
|
+
@dependencies.each_key(&block)
|
64
76
|
end
|
65
77
|
|
66
78
|
def tsort_each_child(node, &block)
|
67
|
-
if node.is_a? String and @
|
79
|
+
if node.is_a? String and @dependencies[node].nil?
|
68
80
|
raise UndefinedInputError.new(node)
|
69
81
|
end
|
70
|
-
if @
|
71
|
-
@
|
82
|
+
if @dependencies[node]
|
83
|
+
@dependencies[node].each(&block)
|
72
84
|
end
|
73
85
|
end
|
74
86
|
end
|
data/lib/droonga/event_loop.rb
CHANGED
@@ -19,21 +19,12 @@ require "coolio"
|
|
19
19
|
|
20
20
|
module Droonga
|
21
21
|
class EventLoop
|
22
|
-
def initialize
|
23
|
-
@loop =
|
22
|
+
def initialize(loop)
|
23
|
+
@loop = loop
|
24
24
|
@loop_breaker = Coolio::AsyncWatcher.new
|
25
25
|
@loop_breaker.attach(@loop)
|
26
26
|
end
|
27
27
|
|
28
|
-
def run
|
29
|
-
@loop.run
|
30
|
-
end
|
31
|
-
|
32
|
-
def stop
|
33
|
-
@loop.stop
|
34
|
-
break_current_loop
|
35
|
-
end
|
36
|
-
|
37
28
|
def attach(watcher)
|
38
29
|
@loop.attach(watcher)
|
39
30
|
break_current_loop
|