droonga-engine 1.0.3 → 1.0.4

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.
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