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
@@ -15,6 +15,8 @@
|
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
17
17
|
|
18
|
+
require "thread"
|
19
|
+
|
18
20
|
require "cool.io"
|
19
21
|
|
20
22
|
require "droonga/loggable"
|
@@ -28,31 +30,40 @@ module Droonga
|
|
28
30
|
@loop = loop
|
29
31
|
@host = host
|
30
32
|
@port = port
|
33
|
+
@socket = nil
|
34
|
+
@buffer = []
|
35
|
+
@write_mutex = Mutex.new
|
31
36
|
end
|
32
37
|
|
33
38
|
def start
|
34
39
|
logger.trace("start: start")
|
35
|
-
|
40
|
+
start_writer
|
36
41
|
logger.trace("start: done")
|
37
42
|
end
|
38
43
|
|
39
44
|
def shutdown
|
40
45
|
logger.trace("shutdown: start")
|
41
|
-
|
46
|
+
shutdown_writer
|
47
|
+
shutdown_socket
|
42
48
|
logger.trace("shutdown: done")
|
43
49
|
end
|
44
50
|
|
45
51
|
def send(tag, data)
|
46
52
|
logger.trace("send: start")
|
47
|
-
connect if @socket.closed?
|
48
53
|
fluent_message = [tag, Time.now.to_i, data]
|
49
54
|
packed_fluent_message = MessagePackPacker.pack(fluent_message)
|
50
|
-
@
|
51
|
-
|
55
|
+
@write_mutex.synchronize do
|
56
|
+
@buffer << packed_fluent_message
|
57
|
+
@writer.signal
|
58
|
+
end
|
52
59
|
logger.trace("send: done")
|
53
60
|
end
|
54
61
|
|
55
62
|
private
|
63
|
+
def connected?
|
64
|
+
not @socket.nil?
|
65
|
+
end
|
66
|
+
|
56
67
|
def connect
|
57
68
|
logger.trace("connect: start")
|
58
69
|
|
@@ -64,6 +75,10 @@ module Droonga
|
|
64
75
|
end
|
65
76
|
log_failed = lambda do
|
66
77
|
logger.error("failed to connect to #{@host}:#{@port}")
|
78
|
+
@socket = nil
|
79
|
+
end
|
80
|
+
on_close = lambda do
|
81
|
+
@socket = nil
|
67
82
|
end
|
68
83
|
|
69
84
|
@socket = Coolio::TCPSocket.connect(@host, @port)
|
@@ -76,11 +91,42 @@ module Droonga
|
|
76
91
|
@socket.on_connect_failed do
|
77
92
|
log_failed.call
|
78
93
|
end
|
94
|
+
@socket.on_close do
|
95
|
+
on_close.call
|
96
|
+
end
|
79
97
|
@loop.attach(@socket)
|
80
98
|
|
81
99
|
logger.trace("connect: done")
|
82
100
|
end
|
83
101
|
|
102
|
+
def shutdown_socket
|
103
|
+
return unless connected?
|
104
|
+
@socket.close unless @socket.closed?
|
105
|
+
end
|
106
|
+
|
107
|
+
def start_writer
|
108
|
+
@writer = Coolio::AsyncWatcher.new
|
109
|
+
|
110
|
+
on_signal = lambda do
|
111
|
+
@write_mutex.synchronize do
|
112
|
+
connect unless connected?
|
113
|
+
@buffer.each do |data|
|
114
|
+
@socket.write(data)
|
115
|
+
end
|
116
|
+
@buffer.clear
|
117
|
+
end
|
118
|
+
end
|
119
|
+
@writer.on_signal do
|
120
|
+
on_signal.call
|
121
|
+
end
|
122
|
+
|
123
|
+
@loop.attach(@writer)
|
124
|
+
end
|
125
|
+
|
126
|
+
def shutdown_writer
|
127
|
+
@writer.detach
|
128
|
+
end
|
129
|
+
|
84
130
|
def log_tag
|
85
131
|
"[#{Process.ppid}][#{Process.pid}] fluent-message-sender"
|
86
132
|
end
|
@@ -80,7 +80,7 @@ module Droonga
|
|
80
80
|
end
|
81
81
|
logger.debug("#{self.class.name}: activating plugins for the dataset \"#{@dataset_name}\": " +
|
82
82
|
"#{@options[:plugins].join(", ")}")
|
83
|
-
@step_runner = StepRunner.new(@options[:plugins] || [])
|
83
|
+
@step_runner = StepRunner.new(nil, @options[:plugins] || [])
|
84
84
|
@forwarder = Forwarder.new(@loop)
|
85
85
|
end
|
86
86
|
|
@@ -0,0 +1,20 @@
|
|
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 JobProtocol
|
18
|
+
READY_SIGNAL = "R"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,178 @@
|
|
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 "msgpack"
|
17
|
+
|
18
|
+
require "droonga/logger"
|
19
|
+
require "droonga/job_protocol"
|
20
|
+
|
21
|
+
module Droonga
|
22
|
+
class JobPusher
|
23
|
+
include Loggable
|
24
|
+
|
25
|
+
attr_reader :socket_path
|
26
|
+
def initialize(loop, base_path)
|
27
|
+
@loop = loop
|
28
|
+
@socket_path = "#{base_path}.sock"
|
29
|
+
@job_queue = JobQueue.new(@loop)
|
30
|
+
end
|
31
|
+
|
32
|
+
def start
|
33
|
+
FileUtils.rm_f(@socket_path)
|
34
|
+
@server = Coolio::UNIXServer.new(@socket_path) do |connection|
|
35
|
+
@job_queue.add_worker(WorkerConnection.new(connection))
|
36
|
+
end
|
37
|
+
FileUtils.chmod(0600, @socket_path)
|
38
|
+
@loop.attach(@server)
|
39
|
+
end
|
40
|
+
|
41
|
+
def close
|
42
|
+
@server.close
|
43
|
+
end
|
44
|
+
|
45
|
+
def shutdown
|
46
|
+
logger.trace("shutdown: start")
|
47
|
+
@server.close
|
48
|
+
@job_queue.close
|
49
|
+
FileUtils.rm_f(@socket_path)
|
50
|
+
logger.trace("shutdown: done")
|
51
|
+
end
|
52
|
+
|
53
|
+
def push(message)
|
54
|
+
logger.trace("push: start")
|
55
|
+
@job_queue.push(message)
|
56
|
+
logger.trace("push: done")
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def log_tag
|
61
|
+
"job_pusher"
|
62
|
+
end
|
63
|
+
|
64
|
+
class JobQueue
|
65
|
+
include Loggable
|
66
|
+
|
67
|
+
def initialize(loop)
|
68
|
+
@loop = loop
|
69
|
+
@buffers = []
|
70
|
+
@ready_workers = []
|
71
|
+
@workers = []
|
72
|
+
@many_jobs_report_interval = 100
|
73
|
+
update_many_jobs_threshold
|
74
|
+
end
|
75
|
+
|
76
|
+
def close
|
77
|
+
@workers.each do |worker|
|
78
|
+
worker.close
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_worker(worker)
|
83
|
+
@workers << worker
|
84
|
+
update_many_jobs_threshold
|
85
|
+
worker.on_ready = lambda do |ready_worker|
|
86
|
+
supply_job(ready_worker)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def push(message)
|
91
|
+
job = message.to_msgpack
|
92
|
+
if @ready_workers.empty?
|
93
|
+
@buffers << job
|
94
|
+
report_statistics_on_push
|
95
|
+
else
|
96
|
+
worker = @ready_workers.shift
|
97
|
+
if @buffers.empty?
|
98
|
+
worker.write(job)
|
99
|
+
else
|
100
|
+
@buffers << job
|
101
|
+
worker.write(@buffers.shift)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
def supply_job(worker)
|
108
|
+
if @buffers.empty?
|
109
|
+
@ready_workers << worker
|
110
|
+
else
|
111
|
+
worker.write(@buffers.shift)
|
112
|
+
report_statistics_on_pull
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def update_many_jobs_threshold
|
117
|
+
@many_jobs_threshold = @workers.size * 100
|
118
|
+
end
|
119
|
+
|
120
|
+
def report_statistics_on_push
|
121
|
+
if @buffers.size >= @many_jobs_threshold
|
122
|
+
if (@buffers.size % @many_jobs_report_interval).zero?
|
123
|
+
logger.warn("push: many jobs in queue: #{@buffers.size}")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def report_statistics_on_pull
|
129
|
+
if @buffers.size >= @many_jobs_threshold
|
130
|
+
if (@buffers.size % @many_jobs_report_interval).zero?
|
131
|
+
logger.info("pull: many jobs in queue: #{@buffers.size}")
|
132
|
+
end
|
133
|
+
elsif @buffers.size == (@many_jobs_threshold - 1)
|
134
|
+
logger.info("pull: reducing jobs in queue: #{@buffers.size}")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def log_tag
|
139
|
+
"job_queue"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class WorkerConnection
|
144
|
+
attr_writer :on_ready
|
145
|
+
|
146
|
+
def initialize(connection)
|
147
|
+
@connection = connection
|
148
|
+
@ready = false
|
149
|
+
@on_ready = nil
|
150
|
+
setup_connection
|
151
|
+
end
|
152
|
+
|
153
|
+
def ready?
|
154
|
+
@ready
|
155
|
+
end
|
156
|
+
|
157
|
+
def write(job)
|
158
|
+
@connection.write(job)
|
159
|
+
@ready = false
|
160
|
+
end
|
161
|
+
|
162
|
+
def close
|
163
|
+
@connection.close
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
def setup_connection
|
168
|
+
on_read = lambda do |data|
|
169
|
+
@ready = (data == JobProtocol::READY_SIGNAL)
|
170
|
+
@on_ready.call(self) if @on_ready
|
171
|
+
end
|
172
|
+
@connection.on_read do |data|
|
173
|
+
on_read.call(data)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
@@ -16,21 +16,22 @@
|
|
16
16
|
require "msgpack"
|
17
17
|
|
18
18
|
require "droonga/loggable"
|
19
|
+
require "droonga/job_protocol"
|
19
20
|
|
20
21
|
module Droonga
|
21
|
-
class
|
22
|
+
class JobReceiver
|
22
23
|
include Loggable
|
23
24
|
|
24
|
-
def initialize(loop,
|
25
|
+
def initialize(loop, socket_path, &callback)
|
25
26
|
@loop = loop
|
26
|
-
@
|
27
|
-
setup_receive_handler(connection)
|
28
|
-
end
|
27
|
+
@socket_path = socket_path
|
29
28
|
@callback = callback
|
30
29
|
end
|
31
30
|
|
32
31
|
def start
|
33
32
|
logger.trace("start: start")
|
33
|
+
@receiver = Coolio::UNIXSocket.connect(@socket_path)
|
34
|
+
setup_receive_handler(@receiver)
|
34
35
|
@loop.attach(@receiver)
|
35
36
|
logger.trace("start: done")
|
36
37
|
end
|
@@ -50,14 +51,20 @@ module Droonga
|
|
50
51
|
@callback.call(message)
|
51
52
|
end
|
52
53
|
logger.trace("on_read: done")
|
54
|
+
send_ready(connection)
|
53
55
|
end
|
54
56
|
connection.on_read do |data|
|
55
57
|
on_read.call(data)
|
56
58
|
end
|
59
|
+
send_ready(connection)
|
60
|
+
end
|
61
|
+
|
62
|
+
def send_ready(connection)
|
63
|
+
connection.write(JobProtocol::READY_SIGNAL)
|
57
64
|
end
|
58
65
|
|
59
66
|
def log_tag
|
60
|
-
"
|
67
|
+
"job_receiver"
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
@@ -59,47 +59,50 @@ module Droonga
|
|
59
59
|
class MessageMatcher
|
60
60
|
# @param [Array] pattern The pattern to be matched against a message.
|
61
61
|
def initialize(pattern)
|
62
|
-
|
62
|
+
path, operator, *arguments = pattern
|
63
|
+
@path_components = path.split(".")
|
64
|
+
@operator = operator
|
65
|
+
@arguments = arguments
|
63
66
|
end
|
64
67
|
|
65
68
|
def match?(message)
|
66
|
-
|
67
|
-
|
68
|
-
target = resolve_path(path, message)
|
69
|
-
apply_operator(operator, target, arguments)
|
69
|
+
target = extract_target(message)
|
70
|
+
apply_operator(target)
|
70
71
|
end
|
71
72
|
|
72
73
|
private
|
73
74
|
NONEXISTENT_PATH = Object.new
|
74
|
-
def
|
75
|
-
|
75
|
+
def extract_target(message)
|
76
|
+
result = message
|
77
|
+
@path_components.each do |component|
|
76
78
|
return NONEXISTENT_PATH unless result.is_a?(Hash)
|
77
|
-
result[component]
|
79
|
+
result = result[component]
|
78
80
|
end
|
81
|
+
result
|
79
82
|
end
|
80
83
|
|
81
|
-
def apply_operator(
|
82
|
-
case operator
|
84
|
+
def apply_operator(target)
|
85
|
+
case @operator
|
83
86
|
when :equal
|
84
|
-
[target] == arguments
|
87
|
+
[target] == @arguments
|
85
88
|
when :in
|
86
|
-
arguments.any? do |argument|
|
89
|
+
@arguments.any? do |argument|
|
87
90
|
argument.include?(target)
|
88
91
|
end
|
89
92
|
when :include
|
90
93
|
return false unless target.respond_to?(:include?)
|
91
|
-
arguments.any? do |argument|
|
94
|
+
@arguments.any? do |argument|
|
92
95
|
target.include?(argument)
|
93
96
|
end
|
94
97
|
when :exist
|
95
98
|
target != NONEXISTENT_PATH
|
96
99
|
when :start_with
|
97
100
|
return false unless target.respond_to?(:start_with?)
|
98
|
-
arguments.any? do |argument|
|
101
|
+
@arguments.any? do |argument|
|
99
102
|
target.start_with?(argument)
|
100
103
|
end
|
101
104
|
else
|
102
|
-
raise ArgumentError, "Unknown operator: <#{operator}>"
|
105
|
+
raise ArgumentError, "Unknown operator: <#{@operator}>"
|
103
106
|
end
|
104
107
|
end
|
105
108
|
end
|
data/lib/droonga/planner.rb
CHANGED
@@ -30,10 +30,9 @@ module Droonga
|
|
30
30
|
end
|
31
31
|
|
32
32
|
private
|
33
|
-
def scatter(message, options={})
|
33
|
+
def scatter(message, record, options={})
|
34
34
|
planner = DistributedCommandPlanner.new(message)
|
35
|
-
planner.scatter
|
36
|
-
planner.key = options[:key]
|
35
|
+
planner.scatter(record)
|
37
36
|
planner.reduce(options[:reduce])
|
38
37
|
planner.plan
|
39
38
|
end
|
data/lib/droonga/plugins/crud.rb
CHANGED
@@ -32,7 +32,7 @@ module Droonga
|
|
32
32
|
request = input_message.body
|
33
33
|
key = request["key"] || rand.to_s
|
34
34
|
values = request["values"] || {}
|
35
|
-
request["filter"] = values.merge("
|
35
|
+
request["filter"] = values.merge("_key" => key)
|
36
36
|
end
|
37
37
|
|
38
38
|
def adapt_output(output_message)
|