droonga-engine 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -0
  3. data/bin/droonga-engine-absorb-data +82 -0
  4. data/bin/droonga-engine-catalog-generate +16 -13
  5. data/bin/droonga-engine-catalog-modify +108 -0
  6. data/bin/droonga-engine-join +115 -0
  7. data/bin/droonga-engine-unjoin +90 -0
  8. data/doc/text/news.md +8 -0
  9. data/droonga-engine.gemspec +2 -1
  10. data/lib/droonga/buffered_tcp_socket.rb +132 -0
  11. data/lib/droonga/catalog_generator.rb +87 -4
  12. data/lib/droonga/command/droonga_engine.rb +27 -7
  13. data/lib/droonga/command/droonga_engine_service.rb +3 -2
  14. data/lib/droonga/command/serf_event_handler.rb +211 -14
  15. data/lib/droonga/data_absorber.rb +55 -0
  16. data/lib/droonga/dispatcher.rb +25 -11
  17. data/lib/droonga/engine/version.rb +1 -1
  18. data/lib/droonga/engine.rb +24 -24
  19. data/lib/droonga/engine_state.rb +23 -0
  20. data/lib/droonga/{catalog_observer.rb → file_observer.rb} +12 -7
  21. data/lib/droonga/fluent_message_sender.rb +24 -37
  22. data/lib/droonga/forwarder.rb +30 -5
  23. data/lib/droonga/handler_messenger.rb +3 -2
  24. data/lib/droonga/handler_runner.rb +29 -16
  25. data/lib/droonga/job_pusher.rb +12 -0
  26. data/lib/droonga/line_buffer.rb +42 -0
  27. data/lib/droonga/logger.rb +10 -6
  28. data/lib/droonga/path.rb +16 -0
  29. data/lib/droonga/plugins/search/distributed_search_planner.rb +1 -1
  30. data/lib/droonga/plugins/system.rb +50 -0
  31. data/lib/droonga/processor.rb +9 -4
  32. data/lib/droonga/safe_file_writer.rb +39 -0
  33. data/lib/droonga/serf.rb +212 -14
  34. data/lib/droonga/test/stub_handler_messenger.rb +3 -0
  35. data/lib/droonga/worker.rb +6 -1
  36. data/test/command/config/default/catalog.json +1 -1
  37. data/test/command/config/version1/catalog.json +2 -2
  38. data/test/command/suite/system/status.expected +12 -0
  39. data/test/command/suite/system/status.test +5 -0
  40. data/test/unit/plugins/system/test_status.rb +79 -0
  41. data/test/unit/test_catalog_generator.rb +1 -1
  42. data/test/unit/test_line_buffer.rb +62 -0
  43. metadata +46 -12
  44. data/lib/droonga/live_nodes_list_observer.rb +0 -72
@@ -22,24 +22,21 @@ require "droonga/loggable"
22
22
  require "droonga/engine_state"
23
23
  require "droonga/catalog_loader"
24
24
  require "droonga/dispatcher"
25
- require "droonga/live_nodes_list_observer"
25
+ require "droonga/file_observer"
26
+ require "droonga/live_nodes_list_loader"
26
27
 
27
28
  module Droonga
28
29
  class Engine
29
30
  include Loggable
30
31
 
31
- LAST_PROCESSED_TIMESTAMP = "last-processed.timestamp"
32
- EFFECTIVE_MESSAGE_TIMESTAMP = "effective-message.timestamp"
33
-
34
32
  def initialize(loop, name, internal_name)
35
33
  @state = EngineState.new(loop, name, internal_name)
36
34
  @catalog = load_catalog
37
- @live_nodes = @catalog.all_nodes
35
+ @state.catalog = @catalog
38
36
  @dispatcher = create_dispatcher
39
- @live_nodes_list_observer = LiveNodesListObserver.new
40
- @live_nodes_list_observer.on_update = lambda do |live_nodes|
41
- @live_nodes = live_nodes
42
- @dispatcher.live_nodes = live_nodes if @dispatcher
37
+ @live_nodes_list_observer = FileObserver.new(loop, Path.live_nodes)
38
+ @live_nodes_list_observer.on_change = lambda do
39
+ @state.live_nodes = load_live_nodes
43
40
  end
44
41
  end
45
42
 
@@ -95,22 +92,28 @@ module Droonga
95
92
  catalog
96
93
  end
97
94
 
95
+ def load_live_nodes
96
+ path = Path.live_nodes
97
+ loader = LiveNodesListLoader.new(path)
98
+ live_nodes = loader.load
99
+ logger.info("live-nodes loaded",
100
+ :path => path,
101
+ :mtime => path.mtime)
102
+ live_nodes
103
+ end
104
+
98
105
  def create_dispatcher
99
- dispatcher = Dispatcher.new(@state, @catalog)
100
- dispatcher.live_nodes = @live_nodes
101
- dispatcher
106
+ Dispatcher.new(@state, @catalog)
102
107
  end
103
108
 
104
109
  def output_last_processed_timestamp
105
- File.open(last_processed_timestamp_file, "w") do |file|
110
+ path = Path.last_processed_timestamp
111
+ FileUtils.mkdir_p(path.dirname.to_s)
112
+ path.open("w") do |file|
106
113
  file.write(@last_processed_timestamp)
107
114
  end
108
115
  end
109
116
 
110
- def last_processed_timestamp_file
111
- @last_processed_timestamp_file ||= File.join(Droonga::Path.state, LAST_PROCESSED_TIMESTAMP)
112
- end
113
-
114
117
  def effective_message?(message)
115
118
  effective_timestamp = effective_message_timestamp
116
119
  return true if effective_timestamp.nil?
@@ -118,14 +121,15 @@ module Droonga
118
121
  message_timestamp = Time.parse(message["date"])
119
122
  return false if effective_timestamp >= message_timestamp
120
123
 
121
- FileUtils.rm(effective_message_timestamp_file)
124
+ FileUtils.rm(Path.effective_timestamp.to_s)
122
125
  true
123
126
  end
124
127
 
125
128
  def effective_message_timestamp
126
- return nil unless File.exist?(effective_message_timestamp_file)
129
+ path = Path.effective_message_timestamp
130
+ return nil unless path.exist?
127
131
 
128
- timestamp = File.read(effective_message_timestamp_file)
132
+ timestamp = path.read
129
133
  begin
130
134
  Time.parse(timestamp)
131
135
  rescue ArgumentError
@@ -133,10 +137,6 @@ module Droonga
133
137
  end
134
138
  end
135
139
 
136
- def effective_message_timestamp_file
137
- @effective_message_timestamp_file ||= File.join(Droonga::Path.state, EFFECTIVE_MESSAGE_TIMESTAMP)
138
- end
139
-
140
140
  def log_tag
141
141
  "engine"
142
142
  end
@@ -32,6 +32,8 @@ module Droonga
32
32
  attr_reader :forwarder
33
33
  attr_reader :replier
34
34
  attr_accessor :on_finish
35
+ attr_accessor :catalog
36
+ attr_writer :dead_nodes
35
37
  def initialize(loop, name, internal_name)
36
38
  @loop = loop
37
39
  @name = name
@@ -39,8 +41,11 @@ module Droonga
39
41
  @sessions = {}
40
42
  @current_id = 0
41
43
  @forwarder = Forwarder.new(@loop)
44
+ @forwarder.resume
42
45
  @replier = Replier.new(@forwarder)
43
46
  @on_finish = nil
47
+ @catalog = nil
48
+ @live_nodes = nil
44
49
  end
45
50
 
46
51
  def start
@@ -97,6 +102,24 @@ module Droonga
97
102
  not @sessions.empty?
98
103
  end
99
104
 
105
+ def all_nodes
106
+ @catalog.all_nodes
107
+ end
108
+
109
+ def live_nodes
110
+ @live_nodes || @catalog.all_nodes
111
+ end
112
+
113
+ def live_nodes=(nodes)
114
+ @live_nodes = nodes
115
+ @dead_nodes = all_nodes - @live_nodes
116
+ @live_nodes
117
+ end
118
+
119
+ def dead_nodes
120
+ @dead_nodes || []
121
+ end
122
+
100
123
  private
101
124
  def log_tag
102
125
  "engine_state"
@@ -21,22 +21,26 @@ require "droonga/path"
21
21
  require "droonga/loggable"
22
22
 
23
23
  module Droonga
24
- class CatalogObserver
24
+ class FileObserver
25
25
  include Loggable
26
26
 
27
27
  CHECK_INTERVAL = 1
28
28
 
29
29
  attr_accessor :on_change
30
30
 
31
- def initialize(loop)
31
+ def initialize(loop, path)
32
32
  @loop = loop
33
- @path = Path.catalog
34
- @mtime = @path.mtime
33
+ @path = path
34
+ if @path.exist?
35
+ @mtime = @path.mtime
36
+ else
37
+ @mtime = nil
38
+ end
35
39
  @on_change = nil
36
40
  end
37
41
 
38
42
  def start
39
- @watcher = Cool.io::TimerWatcher.new(CHECK_INTERVAL, true)
43
+ @watcher = Coolio::TimerWatcher.new(CHECK_INTERVAL, true)
40
44
  on_timer = lambda do
41
45
  if updated?
42
46
  @mtime = @path.mtime
@@ -55,11 +59,12 @@ module Droonga
55
59
 
56
60
  private
57
61
  def updated?
58
- @path.mtime > @mtime
62
+ return false unless @path.exist?
63
+ @mtime.nil? or @path.mtime > @mtime
59
64
  end
60
65
 
61
66
  def log_tag
62
- "catalog-observer"
67
+ "file-observer"
63
68
  end
64
69
  end
65
70
  end
@@ -15,6 +15,7 @@
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 "fileutils"
18
19
  require "thread"
19
20
 
20
21
  require "cool.io"
@@ -22,6 +23,7 @@ require "cool.io"
22
23
  require "droonga/message-pack-packer"
23
24
 
24
25
  require "droonga/loggable"
26
+ require "droonga/buffered_tcp_socket"
25
27
 
26
28
  module Droonga
27
29
  class FluentMessageSender
@@ -32,37 +34,40 @@ module Droonga
32
34
  @host = host
33
35
  @port = port
34
36
  @socket = nil
35
- @buffer = []
36
- @write_mutex = Mutex.new
37
37
  end
38
38
 
39
39
  def start
40
40
  logger.trace("start: start")
41
- start_writer
42
41
  logger.trace("start: done")
43
42
  end
44
43
 
45
44
  def shutdown
46
45
  logger.trace("shutdown: start")
47
- shutdown_writer
48
46
  shutdown_socket
49
47
  logger.trace("shutdown: done")
50
48
  end
51
49
 
52
50
  def send(tag, data)
53
51
  logger.trace("send: start")
54
- fluent_message = [tag, Time.now.to_i, data]
55
- packed_fluent_message = MessagePackPacker.pack(fluent_message)
56
- @write_mutex.synchronize do
57
- @buffer << packed_fluent_message
58
- unless @signaling
59
- @signaling = true
60
- @writer.signal
61
- end
62
- end
52
+ packed_fluent_message = create_packed_fluent_message(tag, data)
53
+ connect unless connected?
54
+ @socket.write(packed_fluent_message)
63
55
  logger.trace("send: done")
64
56
  end
65
57
 
58
+ def reserve_send(tag, data)
59
+ logger.trace("reserve_send: start")
60
+ packed_fluent_message = create_packed_fluent_message(tag, data)
61
+ connect unless connected?
62
+ @socket.reserve_write(packed_fluent_message)
63
+ logger.trace("reserve_send: done")
64
+ end
65
+
66
+ def resume
67
+ connect
68
+ @socket.resume
69
+ end
70
+
66
71
  private
67
72
  def connected?
68
73
  not @socket.nil?
@@ -85,7 +90,9 @@ module Droonga
85
90
  @socket = nil
86
91
  end
87
92
 
88
- @socket = Coolio::TCPSocket.connect(@host, @port)
93
+ data_directory = Path.buffer + "#{@host}:#{@port}"
94
+ FileUtils.mkdir_p(data_directory.to_s)
95
+ @socket = BufferedTCPSocket.connect(@host, @port, data_directory)
89
96
  @socket.on_write_complete do
90
97
  log_write_complete.call
91
98
  end
@@ -108,29 +115,9 @@ module Droonga
108
115
  @socket.close unless @socket.closed?
109
116
  end
110
117
 
111
- def start_writer
112
- @writer = Coolio::AsyncWatcher.new
113
- @signaling = false
114
-
115
- on_signal = lambda do
116
- @write_mutex.synchronize do
117
- @signaling = false
118
- connect unless connected?
119
- @buffer.each do |data|
120
- @socket.write(data)
121
- end
122
- @buffer.clear
123
- end
124
- end
125
- @writer.on_signal do
126
- on_signal.call
127
- end
128
-
129
- @loop.attach(@writer)
130
- end
131
-
132
- def shutdown_writer
133
- @writer.detach
118
+ def create_packed_fluent_message(tag, data)
119
+ fluent_message = [tag, Time.now.to_i, data]
120
+ MessagePackPacker.pack(fluent_message)
134
121
  end
135
122
 
136
123
  def log_tag
@@ -16,6 +16,7 @@
16
16
  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
 
18
18
  require "droonga/loggable"
19
+ require "droonga/path"
19
20
  require "droonga/event_loop"
20
21
  require "droonga/fluent_message_sender"
21
22
 
@@ -46,15 +47,35 @@ module Droonga
46
47
  command = destination["type"]
47
48
  receiver = destination["to"]
48
49
  arguments = destination["arguments"]
49
- output(receiver, message, command, arguments)
50
+ reserve = destination["reserve"]
51
+ output(receiver, message, command, arguments, :reserve => reserve)
50
52
  logger.trace("forward: done")
51
53
  end
52
54
 
55
+ def resume
56
+ return unless Path.buffer.exist?
57
+ Pathname.glob("#{Path.buffer}/*") do |path|
58
+ next unless path.directory?
59
+ next if Pathname.glob("#{path.to_s}/*").empty?
60
+
61
+ destination = path.basename.to_s
62
+ next if @senders.key?(destination)
63
+
64
+ components = destination.split(":")
65
+ port = components.pop.to_i
66
+ next if port.zero?
67
+ host = components.join(":")
68
+
69
+ sender = create_sender(host, port)
70
+ sender.resume
71
+ @senders[destination] = sender
72
+ end
73
+ end
74
+
53
75
  private
54
- def output(receiver, message, command, arguments)
76
+ def output(receiver, message, command, arguments, options={})
55
77
  logger.trace("output: start")
56
- # TODO: IMPROVE ME: Should not use "unless" and "and". It is confused.
57
- unless receiver.is_a?(String) and command.is_a?(String)
78
+ if not receiver.is_a?(String) or not command.is_a?(String)
58
79
  logger.trace("output: abort: invalid argument",
59
80
  :receiver => receiver,
60
81
  :command => command)
@@ -83,7 +104,11 @@ module Droonga
83
104
  output_tag = "#{tag}.message"
84
105
  log_info = "<#{receiver}>:<#{output_tag}>"
85
106
  logger.trace("output: post: start: #{log_info}")
86
- sender.send(output_tag, message)
107
+ if options[:reserve]
108
+ sender.reserve_send(output_tag, message)
109
+ else
110
+ sender.send(output_tag, message)
111
+ end
87
112
  logger.trace("output: post: done: #{log_info}")
88
113
  logger.trace("output: done")
89
114
  end
@@ -18,14 +18,15 @@ require "droonga/forwarder"
18
18
 
19
19
  module Droonga
20
20
  class HandlerMessenger
21
- attr_reader :database_name
21
+ attr_reader :database_name, :dispatcher, :engine_state
22
22
 
23
23
  def initialize(forwarder, message, options={})
24
24
  @forwarder = forwarder
25
25
  @message = message
26
26
  @options = options
27
27
  @replier = Replier.new(@forwarder)
28
- @dispatcher = @options[:dispatcher]
28
+ @dispatcher = options[:dispatcher]
29
+ @engine_state = options[:engine_state]
29
30
  @database_name = options[:database]
30
31
  end
31
32
 
@@ -16,7 +16,6 @@
16
16
  require "groonga"
17
17
 
18
18
  require "droonga/loggable"
19
- require "droonga/forwarder"
20
19
  require "droonga/handler_message"
21
20
  require "droonga/handler_messenger"
22
21
  require "droonga/step_runner"
@@ -36,18 +35,12 @@ module Droonga
36
35
 
37
36
  def start
38
37
  logger.trace("start: start")
39
- @forwarder.start
40
38
  logger.trace("start: done")
41
39
  end
42
40
 
43
41
  def shutdown
44
42
  logger.trace("shutdown: start")
45
- @forwarder.shutdown
46
- if @database
47
- @database.close
48
- @context.close
49
- @database = @context = nil
50
- end
43
+ close_database if @database
51
44
  logger.trace("shutdown: done")
52
45
  end
53
46
 
@@ -62,12 +55,17 @@ module Droonga
62
55
  def process(message)
63
56
  logger.trace("process: start")
64
57
  type = message["type"]
65
- handler_class = find_handler_class(type)
66
- if handler_class.nil?
67
- logger.trace("process: done: no handler: <#{type}>")
68
- return
58
+ if type == "database.reopen"
59
+ handler_class = nil
60
+ reopen
61
+ else
62
+ handler_class = find_handler_class(type)
63
+ if handler_class.nil?
64
+ logger.trace("process: done: no handler: <#{type}>")
65
+ return
66
+ end
67
+ process_type(handler_class, type, message)
69
68
  end
70
- process_type(handler_class, type, message)
71
69
  logger.trace("process: done: <#{type}>",
72
70
  :handler => handler_class)
73
71
  end
@@ -75,13 +73,28 @@ module Droonga
75
73
  private
76
74
  def prepare
77
75
  if @database_name and !@database_name.empty?
78
- @context = Groonga::Context.new
79
- @database = @context.open_database(@database_name)
76
+ open_database
80
77
  end
81
78
  logger.debug("#{self.class.name}: activating plugins for the dataset \"#{@dataset_name}\": " +
82
79
  "#{@options[:plugins].join(", ")}")
83
80
  @step_runner = StepRunner.new(nil, @options[:plugins] || [])
84
- @forwarder = Forwarder.new(@loop)
81
+ @forwarder = @options[:forwarder]
82
+ end
83
+
84
+ def close_database
85
+ @database.close
86
+ @context.close
87
+ @database = @context = nil
88
+ end
89
+
90
+ def open_database
91
+ @context = Groonga::Context.new
92
+ @database = @context.open_database(@database_name)
93
+ end
94
+
95
+ def reopen
96
+ close_database
97
+ open_database
85
98
  end
86
99
 
87
100
  def find_handler_class(type)
@@ -57,6 +57,12 @@ module Droonga
57
57
  logger.trace("push: done")
58
58
  end
59
59
 
60
+ def broadcast(message)
61
+ logger.trace("broadcast start")
62
+ @job_queue.broadcast(message)
63
+ logger.trace("broadcast done")
64
+ end
65
+
60
66
  private
61
67
  def log_tag
62
68
  "job_pusher"
@@ -104,6 +110,12 @@ module Droonga
104
110
  end
105
111
  end
106
112
 
113
+ def broadcast(message)
114
+ @workers.each do |worker|
115
+ worker.write(message.to_msgpack)
116
+ end
117
+ end
118
+
107
119
  private
108
120
  def supply_job(worker)
109
121
  if @buffers.empty?
@@ -0,0 +1,42 @@
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
+ class LineBuffer
18
+ def initialize
19
+ @buffer = ""
20
+ end
21
+
22
+ def feed(data)
23
+ position = 0
24
+ loop do
25
+ new_line_position = data.index("\n", position)
26
+ if new_line_position.nil?
27
+ @buffer << data[position..-1]
28
+ break
29
+ end
30
+
31
+ line = data[position..new_line_position]
32
+ if position.zero?
33
+ yield(@buffer + line)
34
+ @buffer.clear
35
+ else
36
+ yield(line)
37
+ end
38
+ position = new_line_position + 1
39
+ end
40
+ end
41
+ end
42
+ end
@@ -49,12 +49,12 @@ module Droonga
49
49
  LABELS[level]
50
50
  end
51
51
 
52
- def default
53
- WARN
52
+ def value(label)
53
+ LABELS.index(label.to_s)
54
54
  end
55
55
 
56
- def default_label
57
- label(default)
56
+ def default
57
+ ENV["DROONGA_LOG_LEVEL"] || label(WARN)
58
58
  end
59
59
  end
60
60
  end
@@ -73,7 +73,7 @@ module Droonga
73
73
  def initialize(options={})
74
74
  @output = options[:output] || self.class.default_output
75
75
  @tag = options[:tag]
76
- self.level = ENV["DROONGA_LOG_LEVEL"] || Level.default_label
76
+ self.level = options[:level] || Level.default
77
77
  end
78
78
 
79
79
  def level
@@ -81,7 +81,11 @@ module Droonga
81
81
  end
82
82
 
83
83
  def level=(level)
84
- @level = Level::LABELS.index(level.to_s)
84
+ if level.is_a?(Numeric)
85
+ @level = level
86
+ else
87
+ @level = Level.value(level)
88
+ end
85
89
  end
86
90
 
87
91
  def trace(message, data={})
data/lib/droonga/path.rb CHANGED
@@ -38,10 +38,26 @@ module Droonga
38
38
  base + "state"
39
39
  end
40
40
 
41
+ def live_nodes
42
+ state + "live-nodes.json"
43
+ end
44
+
45
+ def last_processed_timestamp
46
+ state + "last-processed.timestamp"
47
+ end
48
+
49
+ def effective_message_timestamp
50
+ state + "effective-message.timestamp"
51
+ end
52
+
41
53
  def catalog
42
54
  base_file_name = ENV["DROONGA_CATALOG"] || "catalog.json"
43
55
  Pathname.new(base_file_name).expand_path(base)
44
56
  end
57
+
58
+ def buffer
59
+ state + "buffer"
60
+ end
45
61
  end
46
62
  end
47
63
  end
@@ -72,7 +72,7 @@ module Droonga
72
72
  query = @queries[name]
73
73
  return true if query["groupBy"]
74
74
  name = query["source"]
75
- return false unless @queries.keys.include?(name)
75
+ return false unless @queries.key?(name)
76
76
  unifiable?(name)
77
77
  end
78
78
 
@@ -0,0 +1,50 @@
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 "droonga/plugin"
17
+
18
+ module Droonga
19
+ module Plugins
20
+ module System
21
+ extend Plugin
22
+ register("system")
23
+
24
+ class StatusHandler < Droonga::Handler
25
+ action.synchronous = true
26
+
27
+ def handle(message)
28
+ engine_state = @messenger.engine_state
29
+ live_nodes = engine_state.live_nodes
30
+ nodes = {}
31
+ engine_state.all_nodes.collect do |identifier|
32
+ nodes[identifier] = {
33
+ "live" => live_nodes.include?(identifier),
34
+ }
35
+ end
36
+
37
+ {
38
+ "nodes" => nodes,
39
+ }
40
+ end
41
+ end
42
+
43
+ define_single_step do |step|
44
+ step.name = "system.status"
45
+ step.handler = StatusHandler
46
+ step.collector = Collectors::Or
47
+ end
48
+ end
49
+ end
50
+ end
@@ -15,7 +15,6 @@
15
15
 
16
16
  require "droonga/loggable"
17
17
  require "droonga/handler_runner"
18
- require "fileutils"
19
18
 
20
19
  module Droonga
21
20
  class Processor
@@ -47,9 +46,9 @@ module Droonga
47
46
  synchronous = @handler_runner.prefer_synchronous?(type)
48
47
  if @n_workers.zero? or synchronous
49
48
  @handler_runner.process(message)
50
- #XXX Workaround to restart system by any schema change.
51
- # This should be done more smartly...
52
- FileUtils.touch(Path.catalog.to_s) if synchronous
49
+ if synchronous
50
+ @job_pusher.broadcast(database_reopen_message)
51
+ end
53
52
  else
54
53
  @job_pusher.push(message)
55
54
  end
@@ -60,6 +59,12 @@ module Droonga
60
59
  end
61
60
 
62
61
  private
62
+ def database_reopen_message
63
+ {
64
+ "type" => "database.reopen",
65
+ }
66
+ end
67
+
63
68
  def log_tag
64
69
  "processor"
65
70
  end