droonga-engine 1.0.9 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/benchmark/timer-watcher/benchmark.rb +44 -0
- data/bin/droonga-engine-absorb-data +246 -187
- data/bin/droonga-engine-catalog-generate +12 -12
- data/bin/droonga-engine-catalog-modify +4 -4
- data/bin/droonga-engine-join +352 -171
- data/bin/droonga-engine-set-role +54 -0
- data/bin/droonga-engine-unjoin +107 -112
- data/droonga-engine.gemspec +3 -3
- data/install.sh +55 -36
- data/install/centos/functions.sh +2 -2
- data/install/debian/functions.sh +2 -2
- data/lib/droonga/address.rb +26 -24
- data/lib/droonga/buffered_tcp_socket.rb +65 -10
- data/lib/droonga/catalog/base.rb +9 -6
- data/lib/droonga/catalog/dataset.rb +17 -41
- data/lib/droonga/catalog/fetcher.rb +64 -0
- data/lib/droonga/catalog/generator.rb +245 -0
- data/lib/droonga/catalog/loader.rb +66 -0
- data/lib/droonga/{catalog_modifier.rb → catalog/modifier.rb} +11 -18
- data/lib/droonga/catalog/replicas_volume.rb +123 -0
- data/lib/droonga/catalog/schema.rb +37 -37
- data/lib/droonga/catalog/single_volume.rb +11 -3
- data/lib/droonga/catalog/slice.rb +10 -6
- data/lib/droonga/catalog/{collection_volume.rb → slices_volume.rb} +47 -11
- data/lib/droonga/catalog/version1.rb +47 -19
- data/lib/droonga/catalog/version2.rb +11 -10
- data/lib/droonga/catalog/version2_validator.rb +4 -4
- data/lib/droonga/catalog/volume.rb +17 -5
- data/lib/droonga/changable.rb +25 -0
- data/lib/droonga/cluster.rb +237 -0
- data/lib/droonga/collector_runner.rb +4 -0
- data/lib/droonga/collectors.rb +2 -1
- data/lib/droonga/collectors/recursive_sum.rb +26 -0
- data/lib/droonga/command/droonga_engine.rb +404 -127
- data/lib/droonga/command/droonga_engine_service.rb +47 -11
- data/lib/droonga/command/droonga_engine_worker.rb +21 -1
- data/lib/droonga/command/remote_command_base.rb +78 -0
- data/lib/droonga/command/serf_event_handler.rb +29 -20
- data/lib/droonga/data_absorber_client.rb +222 -0
- data/lib/droonga/database_scanner.rb +106 -0
- data/lib/droonga/{live_nodes_list_loader.rb → deferrable.rb} +11 -24
- data/lib/droonga/differ.rb +58 -0
- data/lib/droonga/dispatcher.rb +155 -32
- data/lib/droonga/distributed_command_planner.rb +9 -11
- data/lib/droonga/engine.rb +83 -78
- data/lib/droonga/engine/version.rb +1 -1
- data/lib/droonga/engine_node.rb +301 -0
- data/lib/droonga/engine_state.rb +62 -40
- data/lib/droonga/farm.rb +44 -5
- data/lib/droonga/file_observer.rb +16 -12
- data/lib/droonga/fluent_message_receiver.rb +98 -29
- data/lib/droonga/fluent_message_sender.rb +30 -23
- data/lib/droonga/forward_buffer.rb +160 -0
- data/lib/droonga/forwarder.rb +73 -40
- data/lib/droonga/handler.rb +7 -6
- data/lib/droonga/handler_messenger.rb +15 -6
- data/lib/droonga/handler_runner.rb +6 -1
- data/lib/droonga/internal_fluent_message_receiver.rb +28 -8
- data/lib/droonga/job_pusher.rb +10 -7
- data/lib/droonga/job_receiver.rb +6 -4
- data/lib/droonga/logger.rb +7 -1
- data/lib/droonga/node_name.rb +90 -0
- data/lib/droonga/node_role.rb +72 -0
- data/lib/droonga/path.rb +34 -9
- data/lib/droonga/planner.rb +73 -7
- data/lib/droonga/plugin/async_command.rb +154 -0
- data/lib/droonga/plugins/catalog.rb +1 -0
- data/lib/droonga/plugins/crud.rb +22 -6
- data/lib/droonga/plugins/dump.rb +66 -135
- data/lib/droonga/plugins/groonga/delete.rb +13 -0
- data/lib/droonga/plugins/search/distributed_search_planner.rb +4 -4
- data/lib/droonga/plugins/system.rb +5 -26
- data/lib/droonga/plugins/system/absorb_data.rb +405 -0
- data/lib/droonga/plugins/system/statistics.rb +71 -0
- data/lib/droonga/plugins/system/status.rb +53 -0
- data/lib/droonga/process_control_protocol.rb +3 -1
- data/lib/droonga/process_supervisor.rb +32 -15
- data/lib/droonga/reducer.rb +69 -0
- data/lib/droonga/safe_file_writer.rb +1 -1
- data/lib/droonga/serf.rb +207 -276
- data/lib/droonga/serf/agent.rb +228 -0
- data/lib/droonga/serf/command.rb +94 -0
- data/lib/droonga/serf/downloader.rb +120 -0
- data/lib/droonga/serf/remote_command.rb +348 -0
- data/lib/droonga/serf/tag.rb +56 -0
- data/lib/droonga/service_installation.rb +2 -2
- data/lib/droonga/session.rb +49 -1
- data/lib/droonga/single_step.rb +6 -11
- data/lib/droonga/single_step_definition.rb +32 -1
- data/lib/droonga/slice.rb +14 -9
- data/lib/droonga/supervisor.rb +27 -20
- data/lib/droonga/test/stub_handler_messenger.rb +2 -1
- data/lib/droonga/timestamp.rb +69 -0
- data/lib/droonga/worker_process_agent.rb +33 -15
- data/sample/cluster-state.json +8 -0
- data/sample/cluster/Rakefile +30 -6
- data/test/command/fixture/integer-key-table.jsons +11 -0
- data/test/command/fixture/string-key-table.jsons +11 -0
- data/test/command/run-test.rb +4 -0
- data/test/command/suite/add/error/invalid-integer.expected +3 -3
- data/test/command/suite/add/error/invalid-time.expected +3 -3
- data/test/command/suite/add/{minimum.expected → key-integer.expected} +0 -0
- data/test/command/suite/add/{minimum.test → key-integer.test} +0 -0
- data/test/command/suite/add/key-string.expected +6 -0
- data/test/command/suite/add/key-string.test +9 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.expected +6 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.test +9 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.expected +6 -0
- data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.test +9 -0
- data/test/command/suite/add/without-values.expected +6 -0
- data/test/command/suite/add/without-values.test +11 -0
- data/test/command/suite/dump/column/index.expected +33 -1
- data/test/command/suite/dump/column/index.test +1 -0
- data/test/command/suite/dump/column/scalar.expected +29 -1
- data/test/command/suite/dump/column/scalar.test +1 -0
- data/test/command/suite/dump/column/vector.expected +29 -1
- data/test/command/suite/dump/column/vector.test +1 -0
- data/test/command/suite/dump/record/scalar.catalog.json +12 -0
- data/test/command/suite/dump/record/scalar.expected +84 -0
- data/test/command/suite/dump/record/scalar.test +16 -0
- data/test/command/suite/dump/record/vector/reference.expected +83 -1
- data/test/command/suite/dump/record/vector/reference.test +1 -0
- data/test/command/suite/dump/table/array.expected +27 -1
- data/test/command/suite/dump/table/array.test +1 -0
- data/test/command/suite/dump/table/double_array_trie.expected +27 -1
- data/test/command/suite/dump/table/double_array_trie.test +1 -0
- data/test/command/suite/dump/table/hash.expected +27 -1
- data/test/command/suite/dump/table/hash.test +1 -0
- data/test/command/suite/dump/table/patricia_trie.expected +27 -1
- data/test/command/suite/dump/table/patricia_trie.test +1 -0
- data/test/command/suite/groonga/delete/{success.expected → key-integer.expected} +0 -0
- data/test/command/suite/groonga/delete/key-integer.test +17 -0
- data/test/command/suite/groonga/delete/key-string.expected +19 -0
- data/test/command/suite/groonga/delete/{success.test → key-string.test} +4 -6
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.expected +19 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.test +17 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.expected +19 -0
- data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.test +17 -0
- data/test/command/suite/message/error/missing-dataset.test +1 -0
- data/test/command/suite/system/absorb-data/records.catalog.json +58 -0
- data/test/command/suite/system/absorb-data/records.expected +32 -0
- data/test/command/suite/system/absorb-data/records.test +24 -0
- data/test/command/suite/system/statistics/object/count/empty.expected +11 -0
- data/test/command/suite/system/statistics/object/count/empty.test +12 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.catalog.json +36 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/empty.test +12 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.catalog.json +40 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/record.test +23 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.catalog.json +40 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.expected +19 -0
- data/test/command/suite/system/statistics/object/count/per-volume/schema.test +13 -0
- data/test/command/suite/system/statistics/object/count/record.catalog.json +12 -0
- data/test/command/suite/system/statistics/object/count/record.expected +11 -0
- data/test/command/suite/system/statistics/object/count/record.test +23 -0
- data/test/command/suite/system/statistics/object/count/schema.catalog.json +12 -0
- data/test/command/suite/system/statistics/object/count/schema.expected +11 -0
- data/test/command/suite/system/statistics/object/count/schema.test +13 -0
- data/test/command/suite/system/status.expected +3 -2
- data/test/unit/catalog/test_dataset.rb +4 -1
- data/test/unit/{test_catalog_generator.rb → catalog/test_generator.rb} +2 -2
- data/test/unit/catalog/test_replicas_volume.rb +79 -0
- data/test/unit/catalog/test_single_volume.rb +2 -2
- data/test/unit/catalog/test_slice.rb +33 -1
- data/test/unit/catalog/{test_collection_volume.rb → test_slices_volume.rb} +72 -11
- data/test/unit/catalog/test_version2.rb +3 -0
- data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
- data/test/unit/plugins/catalog/test_fetch.rb +4 -4
- data/test/unit/plugins/crud/test_add.rb +44 -4
- data/test/unit/plugins/groonga/test_column_create.rb +4 -4
- data/test/unit/plugins/groonga/test_column_list.rb +4 -4
- data/test/unit/plugins/groonga/test_column_remove.rb +4 -4
- data/test/unit/plugins/groonga/test_column_rename.rb +4 -4
- data/test/unit/plugins/groonga/test_delete.rb +73 -10
- data/test/unit/plugins/groonga/test_table_create.rb +4 -4
- data/test/unit/plugins/groonga/test_table_list.rb +4 -4
- data/test/unit/plugins/groonga/test_table_remove.rb +4 -4
- data/test/unit/plugins/search/test_handler.rb +4 -4
- data/test/unit/plugins/search/test_planner.rb +4 -2
- data/test/unit/plugins/system/test_status.rb +31 -15
- data/test/unit/plugins/test_watch.rb +16 -16
- data/test/unit/test_address.rb +4 -4
- metadata +134 -35
- data/lib/droonga/catalog/volume_collection.rb +0 -79
- data/lib/droonga/catalog_fetcher.rb +0 -53
- data/lib/droonga/catalog_generator.rb +0 -243
- data/lib/droonga/catalog_loader.rb +0 -56
- data/lib/droonga/command/remote.rb +0 -404
- data/lib/droonga/data_absorber.rb +0 -264
- data/lib/droonga/node_status.rb +0 -71
- data/lib/droonga/serf_downloader.rb +0 -115
- data/test/unit/catalog/test_volume_collection.rb +0 -78
@@ -52,13 +52,19 @@ module Droonga
|
|
52
52
|
def send(tag, data)
|
53
53
|
logger.trace("send: start")
|
54
54
|
packed_fluent_message = create_packed_fluent_message(tag, data)
|
55
|
-
|
55
|
+
unless connected?
|
56
|
+
logger.trace("send: reconnect")
|
57
|
+
connect
|
58
|
+
end
|
56
59
|
@socket.write(packed_fluent_message)
|
57
60
|
logger.trace("send: done")
|
58
61
|
end
|
59
62
|
|
60
63
|
def resume
|
61
|
-
|
64
|
+
unless connected?
|
65
|
+
logger.trace("resume: reconnect to #{target_node}")
|
66
|
+
connect
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
private
|
@@ -69,22 +75,8 @@ module Droonga
|
|
69
75
|
def connect
|
70
76
|
logger.trace("connect: start")
|
71
77
|
|
72
|
-
log_write_complete = lambda do
|
73
|
-
logger.trace("write completed")
|
74
|
-
end
|
75
|
-
log_connect = lambda do
|
76
|
-
logger.trace("connected to #{@host}:#{@port}")
|
77
|
-
end
|
78
|
-
log_failed = lambda do
|
79
|
-
logger.error("failed to connect to #{@host}:#{@port}")
|
80
|
-
@socket = nil
|
81
|
-
end
|
82
|
-
on_close = lambda do
|
83
|
-
@socket = nil
|
84
|
-
end
|
85
|
-
|
86
78
|
if @buffering
|
87
|
-
data_directory = Path.
|
79
|
+
data_directory = Path.accidental_buffer + "#{target_node}"
|
88
80
|
FileUtils.mkdir_p(data_directory.to_s)
|
89
81
|
@socket = BufferedTCPSocket.connect(@host, @port, data_directory)
|
90
82
|
@socket.resume
|
@@ -92,25 +84,36 @@ module Droonga
|
|
92
84
|
@socket = Coolio::TCPSocket.connect(@host, @port)
|
93
85
|
end
|
94
86
|
@socket.on_write_complete do
|
95
|
-
|
87
|
+
logger.trace("write completed")
|
96
88
|
end
|
97
89
|
@socket.on_connect do
|
98
|
-
|
90
|
+
logger.trace("connected")
|
99
91
|
end
|
100
92
|
@socket.on_connect_failed do
|
101
|
-
|
93
|
+
logger.error("failed to connect")
|
94
|
+
@socket = nil
|
102
95
|
end
|
103
96
|
@socket.on_close do
|
104
|
-
|
97
|
+
logger.trace("connection is closed by someone")
|
98
|
+
@socket = nil
|
105
99
|
end
|
106
100
|
@loop.attach(@socket)
|
101
|
+
# logger.trace("connect: new socket watcher attached",
|
102
|
+
# :watcher => @socket,
|
103
|
+
# :host => @host,
|
104
|
+
# :port => @port)
|
107
105
|
|
108
106
|
logger.trace("connect: done")
|
109
107
|
end
|
110
108
|
|
111
109
|
def shutdown_socket
|
112
110
|
return unless connected?
|
113
|
-
|
111
|
+
unless @socket.closed?
|
112
|
+
# logger.trace("shutdown_socket: socket watcher detaching",
|
113
|
+
# :watcher => @socket)
|
114
|
+
@socket.close
|
115
|
+
logger.trace("shutdown_socket: socket watcher detached")
|
116
|
+
end
|
114
117
|
end
|
115
118
|
|
116
119
|
def create_packed_fluent_message(tag, data)
|
@@ -121,8 +124,12 @@ module Droonga
|
|
121
124
|
packed_fluent_message
|
122
125
|
end
|
123
126
|
|
127
|
+
def target_node
|
128
|
+
"#{@host}:#{@port}"
|
129
|
+
end
|
130
|
+
|
124
131
|
def log_tag
|
125
|
-
"[#{Process.ppid}] fluent-message-sender"
|
132
|
+
"[#{Process.ppid}] fluent-message-sender: #{target_node}"
|
126
133
|
end
|
127
134
|
end
|
128
135
|
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
#
|
3
|
+
# Copyright (C) 2014-2015 Droonga Project
|
4
|
+
#
|
5
|
+
# This library is free software; you can redistribute it and/or
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
7
|
+
# License version 2.1 as published by the Free Software Foundation.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
|
+
|
18
|
+
require "fileutils"
|
19
|
+
require "pathname"
|
20
|
+
require "msgpack"
|
21
|
+
require "time"
|
22
|
+
|
23
|
+
require "droonga/loggable"
|
24
|
+
require "droonga/path"
|
25
|
+
require "droonga/safe_file_writer"
|
26
|
+
require "droonga/serf"
|
27
|
+
require "droonga/timestamp"
|
28
|
+
|
29
|
+
module Droonga
|
30
|
+
class ForwardBuffer
|
31
|
+
include Loggable
|
32
|
+
|
33
|
+
SUFFIX = ".msgpack"
|
34
|
+
|
35
|
+
attr_writer :on_forward
|
36
|
+
|
37
|
+
def initialize(node_name)
|
38
|
+
@on_forward = nil
|
39
|
+
|
40
|
+
@packer = MessagePack::Packer.new
|
41
|
+
@unpacker = MessagePack::Unpacker.new
|
42
|
+
|
43
|
+
@target = node_name
|
44
|
+
@serf = Serf.new(ENV["DROONGA_ENGINE_NAME"])
|
45
|
+
|
46
|
+
dirname = node_name.gsub("/", ":")
|
47
|
+
@data_directory = Path.intentional_buffer + dirname
|
48
|
+
FileUtils.mkdir_p(@data_directory.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def add(message, destination)
|
52
|
+
logger.trace("add: start")
|
53
|
+
@serf.set_have_unprocessed_messages_for(@target)
|
54
|
+
buffered_message = {
|
55
|
+
"message" => message,
|
56
|
+
"destination" => destination,
|
57
|
+
}
|
58
|
+
@packer.pack(buffered_message)
|
59
|
+
file_path = create_buffered_message_path
|
60
|
+
SafeFileWriter.write(file_path) do |output, file|
|
61
|
+
output.puts(@packer.to_s)
|
62
|
+
end
|
63
|
+
@packer.clear
|
64
|
+
logger.trace("add: done", :path => file_path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def start_forward
|
68
|
+
logger.trace("start_forward: start")
|
69
|
+
n_forwarded_messages = 0
|
70
|
+
buffered_messages.each do |buffered_message_path|
|
71
|
+
forwarded = forward(buffered_message_path)
|
72
|
+
n_forwarded_messages += 1 if forwarded
|
73
|
+
end
|
74
|
+
if n_forwarded_messages > 0 and
|
75
|
+
@process_messages_newer_than_timestamp
|
76
|
+
logger.info("#{n_forwarded_messages} new messages forwarded. " +
|
77
|
+
"The boundary is now cleared.")
|
78
|
+
# Don't clear the boundary while forwarding.
|
79
|
+
# Because buffered messages are not sorted by their "date",
|
80
|
+
# so older messages can appear after newer one.
|
81
|
+
# (ex. messages generated by Dispatcher)
|
82
|
+
@process_messages_newer_than_timestamp = nil
|
83
|
+
end
|
84
|
+
@serf.reset_have_unprocessed_messages_for(@target)
|
85
|
+
logger.trace("start_forward: done")
|
86
|
+
end
|
87
|
+
|
88
|
+
def buffered_messages
|
89
|
+
Pathname.glob("#{@data_directory}/*#{SUFFIX}").sort_by do |path|
|
90
|
+
path
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def empty?
|
95
|
+
@data_directory.children.empty?
|
96
|
+
end
|
97
|
+
|
98
|
+
def process_messages_newer_than(timestamp)
|
99
|
+
@process_messages_newer_than_timestamp = timestamp
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def forward(buffered_message_path)
|
104
|
+
logger.trace("forward: start (#{buffered_message_path})")
|
105
|
+
|
106
|
+
unless buffered_message_path.exist?
|
107
|
+
logger.warn("forward: no buffer file (maybe sent by other process)",
|
108
|
+
:path => buffered_message_path)
|
109
|
+
return false
|
110
|
+
end
|
111
|
+
|
112
|
+
file_contents = buffered_message_path.read
|
113
|
+
@unpacker.feed(file_contents)
|
114
|
+
buffered_message = @unpacker.read
|
115
|
+
@unpacker.reset
|
116
|
+
|
117
|
+
message = buffered_message["message"]
|
118
|
+
destination = buffered_message["destination"]
|
119
|
+
|
120
|
+
forwarded = false
|
121
|
+
|
122
|
+
if @process_messages_newer_than_timestamp
|
123
|
+
message_timestamp = Time.parse(message["date"])
|
124
|
+
logger.trace("Checking boundary of obsolete message",
|
125
|
+
:newer_than => @process_messages_newer_than_timestamp,
|
126
|
+
:message_at => message_timestamp)
|
127
|
+
if @process_messages_newer_than_timestamp >= message_timestamp
|
128
|
+
buffered_message = nil
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
if buffered_message
|
133
|
+
logger.trace("forward: Forwarding buffered message",
|
134
|
+
:message => message,
|
135
|
+
:destination => destination)
|
136
|
+
message["xSender"] = "forward-buffer"
|
137
|
+
on_forward(message, destination)
|
138
|
+
forwarded = true
|
139
|
+
end
|
140
|
+
|
141
|
+
FileUtils.rm_f(buffered_message_path.to_s)
|
142
|
+
logger.trace("forward: done (#{buffered_message_path})")
|
143
|
+
|
144
|
+
forwarded
|
145
|
+
end
|
146
|
+
|
147
|
+
def create_buffered_message_path(time_stamp=Time.now)
|
148
|
+
basename = Timestamp.stringify(time_stamp)
|
149
|
+
Path.unique_file_path(@data_directory, basename, SUFFIX)
|
150
|
+
end
|
151
|
+
|
152
|
+
def on_forward(message, destination)
|
153
|
+
@on_forward.call(message, destination) if @on_forward
|
154
|
+
end
|
155
|
+
|
156
|
+
def log_tag
|
157
|
+
"[#{Process.ppid}] forward-buffer"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
data/lib/droonga/forwarder.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013 Droonga Project
|
3
|
+
# Copyright (C) 2013-2015 Droonga Project
|
4
4
|
#
|
5
5
|
# This library is free software; you can redistribute it and/or
|
6
6
|
# modify it under the terms of the GNU Lesser General Public
|
@@ -15,38 +15,45 @@
|
|
15
15
|
# License along with this library; if not, write to the Free Software
|
16
16
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
17
|
|
18
|
+
require "coolio"
|
19
|
+
|
18
20
|
require "droonga/loggable"
|
19
21
|
require "droonga/path"
|
20
|
-
require "droonga/event_loop"
|
21
|
-
require "droonga/buffered_tcp_socket"
|
22
22
|
require "droonga/fluent_message_sender"
|
23
23
|
|
24
24
|
module Droonga
|
25
25
|
class Forwarder
|
26
26
|
include Loggable
|
27
27
|
|
28
|
+
class AlreadyShutdown < StandardError
|
29
|
+
end
|
30
|
+
|
31
|
+
DEFAULT_AUTO_CLOSE_TIMEOUT_SECONDS = 60
|
32
|
+
|
28
33
|
def initialize(loop, options={})
|
29
34
|
@loop = loop
|
30
|
-
@buffering = options[:buffering]
|
31
35
|
@senders = {}
|
36
|
+
@auto_close_timers = {}
|
37
|
+
@shutting_down = false
|
38
|
+
@auto_close_timeout = options[:auto_close_timeout] ||
|
39
|
+
DEFAULT_AUTO_CLOSE_TIMEOUT_SECONDS
|
32
40
|
end
|
33
41
|
|
34
42
|
def start
|
35
43
|
logger.trace("start: start")
|
36
|
-
resume
|
37
44
|
logger.trace("start: done")
|
38
45
|
end
|
39
46
|
|
40
47
|
def shutdown
|
41
48
|
logger.trace("shutdown: start")
|
42
|
-
@
|
43
|
-
|
44
|
-
end
|
49
|
+
@shutting_down = true
|
50
|
+
clear_senders
|
45
51
|
logger.trace("shutdown: done")
|
46
52
|
end
|
47
53
|
|
48
54
|
def forward(message, destination)
|
49
|
-
logger.trace("forward: start")
|
55
|
+
logger.trace("forward: start", :message => message)
|
56
|
+
raise AlreadyShutdown.new if @shutting_down
|
50
57
|
command = destination["type"]
|
51
58
|
receiver = destination["to"]
|
52
59
|
arguments = destination["arguments"]
|
@@ -54,33 +61,25 @@ module Droonga
|
|
54
61
|
logger.trace("forward: done")
|
55
62
|
end
|
56
63
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
chunk_loader = BufferedTCPSocket::ChunkLoader.new(path)
|
70
|
-
unless chunk_loader.have_any_chunk?
|
71
|
-
#FileUtils.rm_rf(path.to_s) # TODO re-enable this
|
72
|
-
next
|
73
|
-
end
|
74
|
-
|
75
|
-
components = destination.split(":")
|
76
|
-
port = components.pop.to_i
|
77
|
-
next if port.zero?
|
78
|
-
host = components.join(":")
|
79
|
-
|
80
|
-
sender = create_sender(host, port)
|
81
|
-
sender.resume
|
82
|
-
@senders[destination] = sender
|
64
|
+
def refresh_connection_for(name)
|
65
|
+
logger.trace("refresh_connection_for(#{name}): start")
|
66
|
+
sender = @senders[name]
|
67
|
+
if sender
|
68
|
+
sender.shutdown
|
69
|
+
@senders.delete(name)
|
70
|
+
end
|
71
|
+
timer = @auto_close_timers[name]
|
72
|
+
if timer
|
73
|
+
timer.detach
|
74
|
+
@auto_close_timers.delete(name)
|
83
75
|
end
|
76
|
+
logger.trace("refresh_connection_for(#{name}): done")
|
77
|
+
end
|
78
|
+
|
79
|
+
def refresh_all_connections
|
80
|
+
logger.trace("refresh_all_connections: start")
|
81
|
+
clear_senders
|
82
|
+
logger.trace("refresh_all_connections: done")
|
84
83
|
end
|
85
84
|
|
86
85
|
private
|
@@ -107,6 +106,7 @@ module Droonga
|
|
107
106
|
:params => params)
|
108
107
|
return
|
109
108
|
end
|
109
|
+
set_auto_close_timer(host, port, params)
|
110
110
|
override_message = {
|
111
111
|
"type" => command,
|
112
112
|
}
|
@@ -120,11 +120,15 @@ module Droonga
|
|
120
120
|
logger.trace("output: done")
|
121
121
|
end
|
122
122
|
|
123
|
-
def
|
123
|
+
def resolve_destination(host, port, params)
|
124
124
|
connection_id = extract_connection_id(params)
|
125
125
|
destination = "#{host}:#{port}"
|
126
126
|
destination << "?#{connection_id}" if connection_id
|
127
|
+
destination
|
128
|
+
end
|
127
129
|
|
130
|
+
def find_sender(host, port, params)
|
131
|
+
destination = resolve_destination(host, port, params)
|
128
132
|
@senders[destination] ||= create_sender(host, port)
|
129
133
|
end
|
130
134
|
|
@@ -139,14 +143,43 @@ module Droonga
|
|
139
143
|
end
|
140
144
|
|
141
145
|
def create_sender(host, port)
|
142
|
-
|
143
|
-
:buffering => @buffering,
|
144
|
-
}
|
145
|
-
sender = FluentMessageSender.new(@loop, host, port, options)
|
146
|
+
sender = FluentMessageSender.new(@loop, host, port)
|
146
147
|
sender.start
|
147
148
|
sender
|
148
149
|
end
|
149
150
|
|
151
|
+
def set_auto_close_timer(host, port, params)
|
152
|
+
destination = resolve_destination(host, port, params)
|
153
|
+
|
154
|
+
previous_timer = @auto_close_timers[destination]
|
155
|
+
previous_timer.detach if previous_timer
|
156
|
+
|
157
|
+
timer = Coolio::TimerWatcher.new(@auto_close_timeout)
|
158
|
+
timer.on_timer do
|
159
|
+
timer.detach
|
160
|
+
@auto_close_timers.delete(destination)
|
161
|
+
sender = @senders[destination]
|
162
|
+
if sender
|
163
|
+
logger.info("sender for #{destination} is automatically closed by timeout.")
|
164
|
+
sender.shutdown
|
165
|
+
@senders.delete(destination)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
@loop.attach(timer)
|
169
|
+
@auto_close_timers[destination] = timer
|
170
|
+
end
|
171
|
+
|
172
|
+
def clear_senders
|
173
|
+
@senders.each_value do |sender|
|
174
|
+
sender.shutdown
|
175
|
+
end
|
176
|
+
@senders = {}
|
177
|
+
@auto_close_timers.each_value do |timer|
|
178
|
+
timer.detach
|
179
|
+
end
|
180
|
+
@auto_close_timers = {}
|
181
|
+
end
|
182
|
+
|
150
183
|
def log_tag
|
151
184
|
"[#{Process.ppid}] forwarder"
|
152
185
|
end
|
data/lib/droonga/handler.rb
CHANGED
@@ -35,12 +35,13 @@ module Droonga
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
attr_reader :messenger, :loop
|
39
|
-
def initialize(
|
40
|
-
@name
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@
|
38
|
+
attr_reader :label, :messenger, :loop
|
39
|
+
def initialize(params)
|
40
|
+
@name = params[:name]
|
41
|
+
@label = params[:label]
|
42
|
+
@context = params[:context]
|
43
|
+
@messenger = params[:messenger]
|
44
|
+
@loop = params[:loop]
|
44
45
|
end
|
45
46
|
|
46
47
|
def handle(message)
|