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.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/benchmark/timer-watcher/benchmark.rb +44 -0
  4. data/bin/droonga-engine-absorb-data +246 -187
  5. data/bin/droonga-engine-catalog-generate +12 -12
  6. data/bin/droonga-engine-catalog-modify +4 -4
  7. data/bin/droonga-engine-join +352 -171
  8. data/bin/droonga-engine-set-role +54 -0
  9. data/bin/droonga-engine-unjoin +107 -112
  10. data/droonga-engine.gemspec +3 -3
  11. data/install.sh +55 -36
  12. data/install/centos/functions.sh +2 -2
  13. data/install/debian/functions.sh +2 -2
  14. data/lib/droonga/address.rb +26 -24
  15. data/lib/droonga/buffered_tcp_socket.rb +65 -10
  16. data/lib/droonga/catalog/base.rb +9 -6
  17. data/lib/droonga/catalog/dataset.rb +17 -41
  18. data/lib/droonga/catalog/fetcher.rb +64 -0
  19. data/lib/droonga/catalog/generator.rb +245 -0
  20. data/lib/droonga/catalog/loader.rb +66 -0
  21. data/lib/droonga/{catalog_modifier.rb → catalog/modifier.rb} +11 -18
  22. data/lib/droonga/catalog/replicas_volume.rb +123 -0
  23. data/lib/droonga/catalog/schema.rb +37 -37
  24. data/lib/droonga/catalog/single_volume.rb +11 -3
  25. data/lib/droonga/catalog/slice.rb +10 -6
  26. data/lib/droonga/catalog/{collection_volume.rb → slices_volume.rb} +47 -11
  27. data/lib/droonga/catalog/version1.rb +47 -19
  28. data/lib/droonga/catalog/version2.rb +11 -10
  29. data/lib/droonga/catalog/version2_validator.rb +4 -4
  30. data/lib/droonga/catalog/volume.rb +17 -5
  31. data/lib/droonga/changable.rb +25 -0
  32. data/lib/droonga/cluster.rb +237 -0
  33. data/lib/droonga/collector_runner.rb +4 -0
  34. data/lib/droonga/collectors.rb +2 -1
  35. data/lib/droonga/collectors/recursive_sum.rb +26 -0
  36. data/lib/droonga/command/droonga_engine.rb +404 -127
  37. data/lib/droonga/command/droonga_engine_service.rb +47 -11
  38. data/lib/droonga/command/droonga_engine_worker.rb +21 -1
  39. data/lib/droonga/command/remote_command_base.rb +78 -0
  40. data/lib/droonga/command/serf_event_handler.rb +29 -20
  41. data/lib/droonga/data_absorber_client.rb +222 -0
  42. data/lib/droonga/database_scanner.rb +106 -0
  43. data/lib/droonga/{live_nodes_list_loader.rb → deferrable.rb} +11 -24
  44. data/lib/droonga/differ.rb +58 -0
  45. data/lib/droonga/dispatcher.rb +155 -32
  46. data/lib/droonga/distributed_command_planner.rb +9 -11
  47. data/lib/droonga/engine.rb +83 -78
  48. data/lib/droonga/engine/version.rb +1 -1
  49. data/lib/droonga/engine_node.rb +301 -0
  50. data/lib/droonga/engine_state.rb +62 -40
  51. data/lib/droonga/farm.rb +44 -5
  52. data/lib/droonga/file_observer.rb +16 -12
  53. data/lib/droonga/fluent_message_receiver.rb +98 -29
  54. data/lib/droonga/fluent_message_sender.rb +30 -23
  55. data/lib/droonga/forward_buffer.rb +160 -0
  56. data/lib/droonga/forwarder.rb +73 -40
  57. data/lib/droonga/handler.rb +7 -6
  58. data/lib/droonga/handler_messenger.rb +15 -6
  59. data/lib/droonga/handler_runner.rb +6 -1
  60. data/lib/droonga/internal_fluent_message_receiver.rb +28 -8
  61. data/lib/droonga/job_pusher.rb +10 -7
  62. data/lib/droonga/job_receiver.rb +6 -4
  63. data/lib/droonga/logger.rb +7 -1
  64. data/lib/droonga/node_name.rb +90 -0
  65. data/lib/droonga/node_role.rb +72 -0
  66. data/lib/droonga/path.rb +34 -9
  67. data/lib/droonga/planner.rb +73 -7
  68. data/lib/droonga/plugin/async_command.rb +154 -0
  69. data/lib/droonga/plugins/catalog.rb +1 -0
  70. data/lib/droonga/plugins/crud.rb +22 -6
  71. data/lib/droonga/plugins/dump.rb +66 -135
  72. data/lib/droonga/plugins/groonga/delete.rb +13 -0
  73. data/lib/droonga/plugins/search/distributed_search_planner.rb +4 -4
  74. data/lib/droonga/plugins/system.rb +5 -26
  75. data/lib/droonga/plugins/system/absorb_data.rb +405 -0
  76. data/lib/droonga/plugins/system/statistics.rb +71 -0
  77. data/lib/droonga/plugins/system/status.rb +53 -0
  78. data/lib/droonga/process_control_protocol.rb +3 -1
  79. data/lib/droonga/process_supervisor.rb +32 -15
  80. data/lib/droonga/reducer.rb +69 -0
  81. data/lib/droonga/safe_file_writer.rb +1 -1
  82. data/lib/droonga/serf.rb +207 -276
  83. data/lib/droonga/serf/agent.rb +228 -0
  84. data/lib/droonga/serf/command.rb +94 -0
  85. data/lib/droonga/serf/downloader.rb +120 -0
  86. data/lib/droonga/serf/remote_command.rb +348 -0
  87. data/lib/droonga/serf/tag.rb +56 -0
  88. data/lib/droonga/service_installation.rb +2 -2
  89. data/lib/droonga/session.rb +49 -1
  90. data/lib/droonga/single_step.rb +6 -11
  91. data/lib/droonga/single_step_definition.rb +32 -1
  92. data/lib/droonga/slice.rb +14 -9
  93. data/lib/droonga/supervisor.rb +27 -20
  94. data/lib/droonga/test/stub_handler_messenger.rb +2 -1
  95. data/lib/droonga/timestamp.rb +69 -0
  96. data/lib/droonga/worker_process_agent.rb +33 -15
  97. data/sample/cluster-state.json +8 -0
  98. data/sample/cluster/Rakefile +30 -6
  99. data/test/command/fixture/integer-key-table.jsons +11 -0
  100. data/test/command/fixture/string-key-table.jsons +11 -0
  101. data/test/command/run-test.rb +4 -0
  102. data/test/command/suite/add/error/invalid-integer.expected +3 -3
  103. data/test/command/suite/add/error/invalid-time.expected +3 -3
  104. data/test/command/suite/add/{minimum.expected → key-integer.expected} +0 -0
  105. data/test/command/suite/add/{minimum.test → key-integer.test} +0 -0
  106. data/test/command/suite/add/key-string.expected +6 -0
  107. data/test/command/suite/add/key-string.test +9 -0
  108. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.expected +6 -0
  109. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.test +9 -0
  110. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.expected +6 -0
  111. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.test +9 -0
  112. data/test/command/suite/add/without-values.expected +6 -0
  113. data/test/command/suite/add/without-values.test +11 -0
  114. data/test/command/suite/dump/column/index.expected +33 -1
  115. data/test/command/suite/dump/column/index.test +1 -0
  116. data/test/command/suite/dump/column/scalar.expected +29 -1
  117. data/test/command/suite/dump/column/scalar.test +1 -0
  118. data/test/command/suite/dump/column/vector.expected +29 -1
  119. data/test/command/suite/dump/column/vector.test +1 -0
  120. data/test/command/suite/dump/record/scalar.catalog.json +12 -0
  121. data/test/command/suite/dump/record/scalar.expected +84 -0
  122. data/test/command/suite/dump/record/scalar.test +16 -0
  123. data/test/command/suite/dump/record/vector/reference.expected +83 -1
  124. data/test/command/suite/dump/record/vector/reference.test +1 -0
  125. data/test/command/suite/dump/table/array.expected +27 -1
  126. data/test/command/suite/dump/table/array.test +1 -0
  127. data/test/command/suite/dump/table/double_array_trie.expected +27 -1
  128. data/test/command/suite/dump/table/double_array_trie.test +1 -0
  129. data/test/command/suite/dump/table/hash.expected +27 -1
  130. data/test/command/suite/dump/table/hash.test +1 -0
  131. data/test/command/suite/dump/table/patricia_trie.expected +27 -1
  132. data/test/command/suite/dump/table/patricia_trie.test +1 -0
  133. data/test/command/suite/groonga/delete/{success.expected → key-integer.expected} +0 -0
  134. data/test/command/suite/groonga/delete/key-integer.test +17 -0
  135. data/test/command/suite/groonga/delete/key-string.expected +19 -0
  136. data/test/command/suite/groonga/delete/{success.test → key-string.test} +4 -6
  137. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.expected +19 -0
  138. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.test +17 -0
  139. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.expected +19 -0
  140. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.test +17 -0
  141. data/test/command/suite/message/error/missing-dataset.test +1 -0
  142. data/test/command/suite/system/absorb-data/records.catalog.json +58 -0
  143. data/test/command/suite/system/absorb-data/records.expected +32 -0
  144. data/test/command/suite/system/absorb-data/records.test +24 -0
  145. data/test/command/suite/system/statistics/object/count/empty.expected +11 -0
  146. data/test/command/suite/system/statistics/object/count/empty.test +12 -0
  147. data/test/command/suite/system/statistics/object/count/per-volume/empty.catalog.json +36 -0
  148. data/test/command/suite/system/statistics/object/count/per-volume/empty.expected +19 -0
  149. data/test/command/suite/system/statistics/object/count/per-volume/empty.test +12 -0
  150. data/test/command/suite/system/statistics/object/count/per-volume/record.catalog.json +40 -0
  151. data/test/command/suite/system/statistics/object/count/per-volume/record.expected +19 -0
  152. data/test/command/suite/system/statistics/object/count/per-volume/record.test +23 -0
  153. data/test/command/suite/system/statistics/object/count/per-volume/schema.catalog.json +40 -0
  154. data/test/command/suite/system/statistics/object/count/per-volume/schema.expected +19 -0
  155. data/test/command/suite/system/statistics/object/count/per-volume/schema.test +13 -0
  156. data/test/command/suite/system/statistics/object/count/record.catalog.json +12 -0
  157. data/test/command/suite/system/statistics/object/count/record.expected +11 -0
  158. data/test/command/suite/system/statistics/object/count/record.test +23 -0
  159. data/test/command/suite/system/statistics/object/count/schema.catalog.json +12 -0
  160. data/test/command/suite/system/statistics/object/count/schema.expected +11 -0
  161. data/test/command/suite/system/statistics/object/count/schema.test +13 -0
  162. data/test/command/suite/system/status.expected +3 -2
  163. data/test/unit/catalog/test_dataset.rb +4 -1
  164. data/test/unit/{test_catalog_generator.rb → catalog/test_generator.rb} +2 -2
  165. data/test/unit/catalog/test_replicas_volume.rb +79 -0
  166. data/test/unit/catalog/test_single_volume.rb +2 -2
  167. data/test/unit/catalog/test_slice.rb +33 -1
  168. data/test/unit/catalog/{test_collection_volume.rb → test_slices_volume.rb} +72 -11
  169. data/test/unit/catalog/test_version2.rb +3 -0
  170. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  171. data/test/unit/plugins/catalog/test_fetch.rb +4 -4
  172. data/test/unit/plugins/crud/test_add.rb +44 -4
  173. data/test/unit/plugins/groonga/test_column_create.rb +4 -4
  174. data/test/unit/plugins/groonga/test_column_list.rb +4 -4
  175. data/test/unit/plugins/groonga/test_column_remove.rb +4 -4
  176. data/test/unit/plugins/groonga/test_column_rename.rb +4 -4
  177. data/test/unit/plugins/groonga/test_delete.rb +73 -10
  178. data/test/unit/plugins/groonga/test_table_create.rb +4 -4
  179. data/test/unit/plugins/groonga/test_table_list.rb +4 -4
  180. data/test/unit/plugins/groonga/test_table_remove.rb +4 -4
  181. data/test/unit/plugins/search/test_handler.rb +4 -4
  182. data/test/unit/plugins/search/test_planner.rb +4 -2
  183. data/test/unit/plugins/system/test_status.rb +31 -15
  184. data/test/unit/plugins/test_watch.rb +16 -16
  185. data/test/unit/test_address.rb +4 -4
  186. metadata +134 -35
  187. data/lib/droonga/catalog/volume_collection.rb +0 -79
  188. data/lib/droonga/catalog_fetcher.rb +0 -53
  189. data/lib/droonga/catalog_generator.rb +0 -243
  190. data/lib/droonga/catalog_loader.rb +0 -56
  191. data/lib/droonga/command/remote.rb +0 -404
  192. data/lib/droonga/data_absorber.rb +0 -264
  193. data/lib/droonga/node_status.rb +0 -71
  194. data/lib/droonga/serf_downloader.rb +0 -115
  195. 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
- connect unless connected?
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
- connect unless connected?
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.buffer + "#{@host}:#{@port}"
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
- log_write_complete.call
87
+ logger.trace("write completed")
96
88
  end
97
89
  @socket.on_connect do
98
- log_connect.call
90
+ logger.trace("connected")
99
91
  end
100
92
  @socket.on_connect_failed do
101
- log_failed.call
93
+ logger.error("failed to connect")
94
+ @socket = nil
102
95
  end
103
96
  @socket.on_close do
104
- on_close.call
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
- @socket.close unless @socket.closed?
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
@@ -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
- @senders.each_value do |sender|
43
- sender.shutdown
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 resume
58
- return unless Path.buffer.exist?
59
- Pathname.glob("#{Path.buffer}/*") do |path|
60
- next unless path.directory?
61
-
62
- destination = path.basename.to_s
63
- sender = @senders[destination]
64
- if sender
65
- sender.resume
66
- next
67
- end
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 find_sender(host, port, params)
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
- options = {
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
@@ -35,12 +35,13 @@ module Droonga
35
35
  end
36
36
  end
37
37
 
38
- attr_reader :messenger, :loop
39
- def initialize(name, context, messenger, loop)
40
- @name = name
41
- @context = context
42
- @messenger = messenger
43
- @loop = loop
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)