fluent-plugin-droonga 1.0.0 → 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.
- 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
|