droonga-engine 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -2
  3. data/Gemfile +1 -1
  4. data/LICENSE.txt +1 -1
  5. data/Rakefile +1 -1
  6. data/benchmark/benchmark.rb +1 -1
  7. data/benchmark/utils.rb +1 -1
  8. data/benchmark/watch/benchmark-notify.rb +1 -1
  9. data/benchmark/watch/benchmark-publish.rb +1 -1
  10. data/benchmark/watch/benchmark-scan.rb +1 -1
  11. data/bin/droonga-engine +1 -1
  12. data/bin/droonga-engine-absorb-data +48 -8
  13. data/bin/droonga-engine-catalog-generate +1 -1
  14. data/bin/droonga-engine-catalog-modify +1 -1
  15. data/bin/droonga-engine-data-publisher +66 -0
  16. data/bin/droonga-engine-join +72 -17
  17. data/bin/droonga-engine-serf-event-handler +1 -1
  18. data/bin/droonga-engine-service +1 -1
  19. data/bin/droonga-engine-unjoin +11 -4
  20. data/bin/droonga-engine-worker +20 -0
  21. data/doc/text/news.md +8 -0
  22. data/droonga-engine.gemspec +3 -3
  23. data/lib/droonga/adapter.rb +1 -1
  24. data/lib/droonga/adapter_runner.rb +1 -1
  25. data/lib/droonga/address.rb +69 -0
  26. data/lib/droonga/buffered_tcp_socket.rb +44 -22
  27. data/lib/droonga/catalog/base.rb +1 -1
  28. data/lib/droonga/catalog/collection_volume.rb +1 -1
  29. data/lib/droonga/catalog/dataset.rb +8 -8
  30. data/lib/droonga/catalog/errors.rb +1 -1
  31. data/lib/droonga/catalog/schema.rb +1 -1
  32. data/lib/droonga/catalog/single_volume.rb +6 -8
  33. data/lib/droonga/catalog/slice.rb +1 -1
  34. data/lib/droonga/catalog/version1.rb +2 -2
  35. data/lib/droonga/catalog/version2.rb +6 -6
  36. data/lib/droonga/catalog/version2_validator.rb +1 -1
  37. data/lib/droonga/catalog/volume.rb +1 -1
  38. data/lib/droonga/catalog/volume_collection.rb +2 -2
  39. data/lib/droonga/catalog_generator.rb +49 -53
  40. data/lib/droonga/catalog_loader.rb +1 -1
  41. data/lib/droonga/collector.rb +1 -1
  42. data/lib/droonga/collector_message.rb +1 -1
  43. data/lib/droonga/collector_runner.rb +1 -1
  44. data/lib/droonga/collectors/and.rb +1 -1
  45. data/lib/droonga/collectors/or.rb +1 -1
  46. data/lib/droonga/collectors/sum.rb +1 -1
  47. data/lib/droonga/collectors.rb +1 -1
  48. data/lib/droonga/command/droonga_engine.rb +103 -55
  49. data/lib/droonga/command/droonga_engine_service.rb +22 -67
  50. data/lib/droonga/command/droonga_engine_worker.rb +232 -0
  51. data/lib/droonga/command/serf_event_handler.rb +126 -46
  52. data/lib/droonga/data_absorber.rb +32 -14
  53. data/lib/droonga/dispatcher.rb +15 -11
  54. data/lib/droonga/distributed_command_planner.rb +1 -1
  55. data/lib/droonga/distributor.rb +1 -1
  56. data/lib/droonga/engine/version.rb +2 -2
  57. data/lib/droonga/engine.rb +8 -3
  58. data/lib/droonga/engine_state.rb +15 -6
  59. data/lib/droonga/error.rb +1 -1
  60. data/lib/droonga/error_messages.rb +1 -1
  61. data/lib/droonga/event_loop.rb +1 -1
  62. data/lib/droonga/farm.rb +9 -1
  63. data/lib/droonga/file_observer.rb +1 -1
  64. data/lib/droonga/fluent_message_receiver.rb +11 -5
  65. data/lib/droonga/fluent_message_sender.rb +14 -17
  66. data/lib/droonga/forwarder.rb +23 -13
  67. data/lib/droonga/handler.rb +1 -1
  68. data/lib/droonga/handler_message.rb +1 -1
  69. data/lib/droonga/handler_messenger.rb +2 -2
  70. data/lib/droonga/handler_runner.rb +2 -2
  71. data/lib/droonga/input_message.rb +1 -1
  72. data/lib/droonga/internal_fluent_message_receiver.rb +3 -2
  73. data/lib/droonga/job_protocol.rb +1 -1
  74. data/lib/droonga/job_pusher.rb +1 -1
  75. data/lib/droonga/job_receiver.rb +1 -1
  76. data/lib/droonga/line_buffer.rb +1 -1
  77. data/lib/droonga/live_nodes_list_loader.rb +1 -1
  78. data/lib/droonga/loggable.rb +1 -1
  79. data/lib/droonga/logger.rb +3 -3
  80. data/lib/droonga/message_matcher.rb +1 -1
  81. data/lib/droonga/output_message.rb +1 -1
  82. data/lib/droonga/path.rb +5 -1
  83. data/lib/droonga/planner.rb +1 -1
  84. data/lib/droonga/pluggable.rb +1 -1
  85. data/lib/droonga/plugin/metadata/adapter_input_message.rb +1 -1
  86. data/lib/droonga/plugin/metadata/adapter_output_message.rb +1 -1
  87. data/lib/droonga/plugin/metadata/collector_message.rb +1 -1
  88. data/lib/droonga/plugin/metadata/handler_action.rb +1 -1
  89. data/lib/droonga/plugin/metadata/input_message.rb +1 -1
  90. data/lib/droonga/plugin.rb +2 -1
  91. data/lib/droonga/plugin_loader.rb +1 -1
  92. data/lib/droonga/plugin_registry.rb +3 -1
  93. data/lib/droonga/plugins/basic.rb +1 -1
  94. data/lib/droonga/plugins/crud.rb +1 -1
  95. data/lib/droonga/plugins/dump.rb +13 -2
  96. data/lib/droonga/plugins/error.rb +1 -1
  97. data/lib/droonga/plugins/groonga/column_create.rb +1 -1
  98. data/lib/droonga/plugins/groonga/column_list.rb +1 -1
  99. data/lib/droonga/plugins/groonga/column_remove.rb +1 -1
  100. data/lib/droonga/plugins/groonga/column_rename.rb +1 -1
  101. data/lib/droonga/plugins/groonga/delete.rb +1 -1
  102. data/lib/droonga/plugins/groonga/generic_command.rb +1 -1
  103. data/lib/droonga/plugins/groonga/generic_response.rb +1 -1
  104. data/lib/droonga/plugins/groonga/select.rb +1 -1
  105. data/lib/droonga/plugins/groonga/table_create.rb +1 -1
  106. data/lib/droonga/plugins/groonga/table_list.rb +1 -1
  107. data/lib/droonga/plugins/groonga/table_remove.rb +1 -1
  108. data/lib/droonga/plugins/groonga.rb +1 -1
  109. data/lib/droonga/plugins/search/distributed_search_planner.rb +1 -1
  110. data/lib/droonga/plugins/search.rb +1 -1
  111. data/lib/droonga/plugins/system.rb +1 -1
  112. data/lib/droonga/plugins/watch.rb +1 -1
  113. data/lib/droonga/{service_control_protocol.rb → process_control_protocol.rb} +2 -2
  114. data/lib/droonga/process_supervisor.rb +91 -0
  115. data/lib/droonga/processor.rb +1 -1
  116. data/lib/droonga/reducer.rb +1 -1
  117. data/lib/droonga/replier.rb +2 -2
  118. data/lib/droonga/safe_file_writer.rb +1 -1
  119. data/lib/droonga/schema_applier.rb +1 -1
  120. data/lib/droonga/searcher/mecab_filter.rb +1 -1
  121. data/lib/droonga/searcher.rb +31 -19
  122. data/lib/droonga/serf.rb +81 -14
  123. data/lib/droonga/serf_downloader.rb +2 -2
  124. data/lib/droonga/session.rb +1 -1
  125. data/lib/droonga/single_step.rb +1 -1
  126. data/lib/droonga/single_step_definition.rb +1 -1
  127. data/lib/droonga/slice.rb +30 -28
  128. data/lib/droonga/status_code.rb +1 -1
  129. data/lib/droonga/step_runner.rb +1 -1
  130. data/lib/droonga/supervisor.rb +170 -0
  131. data/lib/droonga/sweeper.rb +1 -1
  132. data/lib/droonga/test/stub_handler.rb +1 -1
  133. data/lib/droonga/test/stub_handler_message.rb +1 -1
  134. data/lib/droonga/test/stub_handler_messenger.rb +1 -1
  135. data/lib/droonga/test/stub_planner.rb +1 -1
  136. data/lib/droonga/test.rb +1 -1
  137. data/lib/droonga/watch_schema.rb +2 -2
  138. data/lib/droonga/watcher.rb +1 -1
  139. data/lib/droonga/worker_process_agent.rb +111 -0
  140. data/sample/cluster/Rakefile +150 -0
  141. data/test/command/config/default/catalog.json +1 -34
  142. data/test/command/config/version1/catalog.json +3 -12
  143. data/test/command/run-test.rb +1 -1
  144. data/test/command/suite/dump/column/index.expected +19 -82
  145. data/test/command/suite/dump/column/scalar.expected +5 -36
  146. data/test/command/suite/dump/column/vector.expected +5 -39
  147. data/test/command/suite/dump/record/vector/reference.expected +24 -93
  148. data/test/command/suite/dump/table/array.expected +0 -19
  149. data/test/command/suite/dump/table/double_array_trie.expected +0 -20
  150. data/test/command/suite/dump/table/hash.expected +0 -20
  151. data/test/command/suite/dump/table/patricia_trie.expected +0 -20
  152. data/test/command/suite/search/condition/query/nonexistent_column.expected +0 -11
  153. data/test/command/suite/search/condition/query/syntax_error.expected +0 -11
  154. data/test/command/suite/search/error/unknown-source.expected +0 -12
  155. data/test/command/suite/search/output/attributes/invalid.expected +0 -10
  156. data/test/command/suite/search/output/attributes/reference_vector.catalog.json +27 -0
  157. data/test/command/suite/search/output/attributes/reference_vector.expected +30 -0
  158. data/test/command/suite/search/output/attributes/reference_vector.test +32 -0
  159. data/test/command/suite/watch/subscribe.catalog.json +23 -0
  160. data/test/command/suite/watch/subscribe.test +2 -0
  161. data/test/command/suite/watch/unsubscribe.catalog.json +23 -0
  162. data/test/command/suite/watch/unsubscribe.test +2 -0
  163. data/test/performance/run-test.rb +1 -1
  164. data/test/unit/catalog/test_collection_volume.rb +1 -1
  165. data/test/unit/catalog/test_dataset.rb +1 -1
  166. data/test/unit/catalog/test_schema.rb +1 -1
  167. data/test/unit/catalog/test_single_volume.rb +27 -19
  168. data/test/unit/catalog/test_slice.rb +2 -2
  169. data/test/unit/catalog/test_version1.rb +1 -1
  170. data/test/unit/catalog/test_version2.rb +1 -1
  171. data/test/unit/catalog/test_version2_validator.rb +1 -1
  172. data/test/unit/catalog/test_volume_collection.rb +1 -1
  173. data/test/unit/helper/distributed_search_planner_helper.rb +1 -1
  174. data/test/unit/helper/fixture.rb +1 -1
  175. data/test/unit/helper/plugin_helper.rb +1 -1
  176. data/test/unit/helper/sandbox.rb +1 -1
  177. data/test/unit/helper/stub_worker.rb +1 -1
  178. data/test/unit/helper/watch_helper.rb +1 -1
  179. data/test/unit/helper.rb +1 -1
  180. data/test/unit/plugins/crud/test_add.rb +1 -1
  181. data/test/unit/plugins/groonga/select/test_adapter_input.rb +1 -1
  182. data/test/unit/plugins/groonga/select/test_adapter_output.rb +1 -1
  183. data/test/unit/plugins/groonga/test_column_create.rb +1 -1
  184. data/test/unit/plugins/groonga/test_column_list.rb +1 -1
  185. data/test/unit/plugins/groonga/test_column_remove.rb +1 -1
  186. data/test/unit/plugins/groonga/test_column_rename.rb +1 -1
  187. data/test/unit/plugins/groonga/test_delete.rb +1 -1
  188. data/test/unit/plugins/groonga/test_table_create.rb +1 -1
  189. data/test/unit/plugins/groonga/test_table_list.rb +1 -1
  190. data/test/unit/plugins/groonga/test_table_remove.rb +1 -1
  191. data/test/unit/plugins/search/planner/test_basic.rb +1 -1
  192. data/test/unit/plugins/search/planner/test_group_by.rb +1 -1
  193. data/test/unit/plugins/search/planner/test_output.rb +1 -1
  194. data/test/unit/plugins/search/planner/test_sort_by.rb +1 -1
  195. data/test/unit/plugins/search/test_collector.rb +1 -1
  196. data/test/unit/plugins/search/test_handler.rb +1 -1
  197. data/test/unit/plugins/search/test_planner.rb +1 -1
  198. data/test/unit/plugins/system/test_status.rb +1 -1
  199. data/test/unit/plugins/test_basic.rb +1 -1
  200. data/test/unit/plugins/test_groonga.rb +1 -1
  201. data/test/unit/plugins/test_watch.rb +1 -1
  202. data/test/unit/run-test.rb +1 -1
  203. data/test/unit/test_address.rb +53 -0
  204. data/test/unit/test_catalog_generator.rb +59 -1
  205. data/test/unit/test_line_buffer.rb +1 -1
  206. data/test/unit/test_message_matcher.rb +1 -1
  207. data/test/unit/test_schema_applier.rb +1 -1
  208. data/test/unit/test_sweeper.rb +1 -1
  209. data/test/unit/test_watch_schema.rb +1 -1
  210. data/test/unit/test_watcher.rb +1 -1
  211. metadata +39 -24
  212. data/lib/droonga/server.rb +0 -45
  213. data/lib/droonga/worker.rb +0 -66
  214. data/sample/cluster/catalog.json +0 -42
  215. data/test/command/config/default/fluentd.conf +0 -11
  216. data/test/command/config/version1/fluentd.conf +0 -11
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # You should have received a copy of the GNU Lesser General Public
13
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
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
15
 
16
16
  require "optparse"
17
17
  require "socket"
@@ -24,8 +24,7 @@ require "sigdump"
24
24
  require "droonga/path"
25
25
  require "droonga/serf"
26
26
  require "droonga/file_observer"
27
- require "droonga/service_control_protocol"
28
- require "droonga/line_buffer"
27
+ require "droonga/process_supervisor"
29
28
 
30
29
  module Droonga
31
30
  module Command
@@ -94,14 +93,14 @@ module Droonga
94
93
  end
95
94
 
96
95
  def write_pid_file
97
- if @configuration.pid_file
98
- File.open(@configuration.pid_file, "w") do |file|
96
+ if @configuration.pid_file_path
97
+ @configuration.pid_file_path.open("w") do |file|
99
98
  file.puts(Process.pid)
100
99
  end
101
100
  begin
102
101
  yield
103
102
  ensure
104
- FileUtils.rm_f(@configuration.pid_file)
103
+ FileUtils.rm_f(@configuration.pid_file_path.to_s)
105
104
  end
106
105
  else
107
106
  yield
@@ -112,14 +111,16 @@ module Droonga
112
111
  DEFAULT_HOST = Socket.gethostname
113
112
  DEFAULT_PORT = 10031
114
113
 
115
- attr_reader :host, :port, :tag, :log_file, :pid_file
114
+ attr_reader :host, :port, :tag, :log_file, :pid_file_path
115
+ attr_reader :ready_notify_fd
116
116
  def initialize
117
117
  @host = DEFAULT_HOST
118
118
  @port = DEFAULT_PORT
119
119
  @tag = "droonga"
120
120
  @log_file = nil
121
121
  @daemon = false
122
- @pid_file = nil
122
+ @pid_file_path = nil
123
+ @ready_notify_fd = nil
123
124
  end
124
125
 
125
126
  def engine_name
@@ -151,6 +152,7 @@ module Droonga
151
152
  add_log_options(parser)
152
153
  add_process_options(parser)
153
154
  add_path_options(parser)
155
+ add_notification_options(parser)
154
156
  end
155
157
 
156
158
  def listen_socket
@@ -206,9 +208,9 @@ module Droonga
206
208
  "Run as a daemon") do
207
209
  @daemon = true
208
210
  end
209
- parser.on("--pid-file=FILE",
210
- "Put PID to the FILE") do |file|
211
- @pid_file = File.expand_path(file)
211
+ parser.on("--pid-file=PATH",
212
+ "Put PID to PATH") do |path|
213
+ @pid_file_path = Pathname.new(path).expand_path
212
214
  end
213
215
  end
214
216
 
@@ -222,6 +224,15 @@ module Droonga
222
224
  end
223
225
  end
224
226
 
227
+ def add_notification_options(parser)
228
+ parser.separator("")
229
+ parser.separator("Notification:")
230
+ parser.on("--ready-notify-fd=FD", Integer,
231
+ "Send 'ready' message to FD on ready") do |fd|
232
+ @ready_notify_fd = fd
233
+ end
234
+ end
235
+
225
236
  def bind_heartbeat_socket
226
237
  socket = UDPSocket.new(address_family)
227
238
  socket.bind(@host, @port)
@@ -239,36 +250,45 @@ module Droonga
239
250
  @serf = run_serf
240
251
  @serf_status_observer = run_serf_status_observer
241
252
  @service_runner = run_service
253
+ setup_initial_on_ready
242
254
  @catalog_observer = run_catalog_observer
243
- @loop_breaker = Coolio::AsyncWatcher.new
244
- @loop.attach(@loop_breaker)
255
+ @command_runner = run_command_runner
245
256
 
246
257
  trap_signals
247
258
  @loop.run
248
- @serf.shutdown if @serf.running?
259
+ @serf.stop if @serf.running?
249
260
 
250
261
  @service_runner.success?
251
262
  end
252
263
 
253
264
  private
265
+ def setup_initial_on_ready
266
+ return if @configuration.ready_notify_fd.nil?
267
+ @service_runner.on_ready = lambda do
268
+ output = IO.new(@configuration.ready_notify_fd)
269
+ output.puts("ready")
270
+ output.close
271
+ end
272
+ end
273
+
254
274
  def trap_signals
255
275
  trap(:TERM) do
256
- stop_gracefully
276
+ @command_runner.push_command(:stop_gracefully)
257
277
  trap(:TERM, "DEFAULT")
258
278
  end
259
279
  trap(:INT) do
260
- stop_immediately
280
+ @command_runner.push_command(:stop_immediately)
261
281
  trap(:INT, "DEFAULT")
262
282
  end
263
283
  trap(:QUIT) do
264
- stop_immediately
284
+ @command_runner.push_cmmand(:stop_immediately)
265
285
  trap(:QUIT, "DEFAULT")
266
286
  end
267
287
  trap(:USR1) do
268
- restart_graceful
288
+ @command_runner.push_command(:restart_graceful)
269
289
  end
270
290
  trap(:HUP) do
271
- restart_immediately
291
+ @command_runner.push_command(:restart_immediately)
272
292
  end
273
293
  trap(:USR2) do
274
294
  Sigdump.dump
@@ -276,25 +296,22 @@ module Droonga
276
296
  end
277
297
 
278
298
  def stop_gracefully
279
- @loop_breaker.signal
280
- @loop_breaker.detach
281
- @serf.shutdown
299
+ @command_runner.stop
300
+ @serf.stop
282
301
  @serf_status_observer.stop
283
302
  @catalog_observer.stop
284
303
  @service_runner.stop_gracefully
285
304
  end
286
305
 
287
306
  def stop_immediately
288
- @loop_breaker.signal
289
- @loop_breaker.detach
290
- @serf.shutdown
307
+ @command_runner.stop
308
+ @serf.stop
291
309
  @serf_status_observer.stop
292
310
  @catalog_observer.stop
293
311
  @service_runner.stop_immediately
294
312
  end
295
313
 
296
314
  def restart_graceful
297
- @loop_breaker.signal
298
315
  old_service_runner = @service_runner
299
316
  @service_runner = run_service
300
317
  @service_runner.on_ready = lambda do
@@ -308,7 +325,6 @@ module Droonga
308
325
  end
309
326
 
310
327
  def restart_immediately
311
- @loop_breaker.signal
312
328
  old_service_runner = @service_runner
313
329
  @service_runner = run_service
314
330
  old_service_runner.stop_immediately
@@ -327,7 +343,7 @@ module Droonga
327
343
  end
328
344
 
329
345
  def restart_serf
330
- @serf.shutdown if @serf
346
+ @serf.stop if @serf
331
347
  @serf = run_serf
332
348
  end
333
349
 
@@ -348,11 +364,18 @@ module Droonga
348
364
  catalog_observer.start
349
365
  catalog_observer
350
366
  end
367
+
368
+ def run_command_runner
369
+ command_runner = CommandRunner.new(@loop)
370
+ command_runner.on_command = lambda do |command|
371
+ __send__(command)
372
+ end
373
+ command_runner.start
374
+ command_runner
375
+ end
351
376
  end
352
377
 
353
378
  class ServiceRunner
354
- include ServiceControlProtocol
355
-
356
379
  def initialize(raw_loop, configuration)
357
380
  @raw_loop = raw_loop
358
381
  @configuration = configuration
@@ -394,16 +417,17 @@ module Droonga
394
417
  @pid = spawn(env, *command_line, options)
395
418
  control_write_in.close
396
419
  control_read_out.close
397
- attach_control_write_out(control_write_out)
398
- attach_control_read_in(control_read_in)
420
+ @supervisor = create_process_supervisor(control_read_in,
421
+ control_write_out)
422
+ @supervisor.start
399
423
  end
400
424
 
401
425
  def stop_gracefully
402
- @control_write_out.write(Messages::STOP_GRACEFUL)
426
+ @supervisor.stop_gracefully
403
427
  end
404
428
 
405
429
  def stop_immediately
406
- @control_write_out.write(Messages::STOP_IMMEDIATELY)
430
+ @supervisor.stop_immediately
407
431
  end
408
432
 
409
433
  def success?
@@ -411,6 +435,17 @@ module Droonga
411
435
  end
412
436
 
413
437
  private
438
+ def create_process_supervisor(input, output)
439
+ supervisor = ProcessSupervisor.new(@raw_loop, input, output)
440
+ supervisor.on_ready = lambda do
441
+ on_ready
442
+ end
443
+ supervisor.on_finish = lambda do
444
+ on_finish
445
+ end
446
+ supervisor
447
+ end
448
+
414
449
  def on_ready
415
450
  @on_ready.call if @on_ready
416
451
  end
@@ -422,33 +457,46 @@ module Droonga
422
457
  def on_finish
423
458
  _, status = Process.waitpid2(@pid)
424
459
  @success = status.success?
425
- @control_write_out.close
426
- @control_read_in.close
460
+ @supervisor.stop
427
461
  on_failure unless success?
428
462
  end
463
+ end
429
464
 
430
- def attach_control_write_out(control_write_out)
431
- @control_write_out = Coolio::IO.new(control_write_out)
432
- @raw_loop.attach(@control_write_out)
433
- end
434
-
435
- def attach_control_read_in(control_read_in)
436
- @control_read_in = Coolio::IO.new(control_read_in)
437
- line_buffer = LineBuffer.new
438
- on_read = lambda do |data|
439
- line_buffer.feed(data) do |line|
440
- case line
441
- when Messages::READY
442
- on_ready
443
- when Messages::FINISH
444
- on_finish
445
- end
465
+ class CommandRunner
466
+ attr_writer :on_command
467
+ def initialize(loop)
468
+ @loop = loop
469
+ @commands = []
470
+ @on_command = nil
471
+ end
472
+
473
+ def start
474
+ @async_watcher = Coolio::AsyncWatcher.new
475
+ on_signal = lambda do
476
+ commands = @commands.uniq
477
+ @commands.clear
478
+ until commands.empty?
479
+ command = commands.shift
480
+ @on_command.call(command) if @on_command
446
481
  end
447
482
  end
448
- @control_read_in.on_read do |data|
449
- on_read.call(data)
483
+ @async_watcher.on_signal do
484
+ on_signal.call
450
485
  end
451
- @raw_loop.attach(@control_read_in)
486
+ @loop.attach(@async_watcher)
487
+ end
488
+
489
+ def stop
490
+ return if @async_watcher.nil?
491
+ @async_watcher.detach
492
+ @async_watcher = nil
493
+ end
494
+
495
+ def push_command(command)
496
+ return if @async_watcher.nil?
497
+ first_command_p = @commands.empty?
498
+ @commands << command
499
+ @async_watcher.signal if first_command_p
452
500
  end
453
501
  end
454
502
  end
@@ -11,14 +11,13 @@
11
11
  #
12
12
  # You should have received a copy of the GNU Lesser General Public
13
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
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
15
 
16
16
  require "optparse"
17
17
 
18
18
  require "coolio"
19
19
 
20
- require "droonga/service_control_protocol"
21
- require "droonga/line_buffer"
20
+ require "droonga/worker_process_agent"
22
21
  require "droonga/engine"
23
22
  require "droonga/fluent_message_receiver"
24
23
  require "droonga/internal_fluent_message_receiver"
@@ -34,7 +33,6 @@ module Droonga
34
33
  end
35
34
 
36
35
  include Loggable
37
- include ServiceControlProtocol
38
36
 
39
37
  def initialize
40
38
  @engine_name = nil
@@ -59,10 +57,7 @@ module Droonga
59
57
  logger.exception("failed to run services", $!)
60
58
  success = false
61
59
  ensure
62
- unless @control_write_closed
63
- control_write_io.write(Messages::FINISH)
64
- control_write_io.close
65
- end
60
+ shutdown_worker_process_agent
66
61
  end
67
62
 
68
63
  success
@@ -118,9 +113,9 @@ module Droonga
118
113
  @loop = Coolio::Loop.default
119
114
 
120
115
  run_internal_message_receiver
116
+ run_worker_process_agent
121
117
  run_engine
122
118
  run_receiver
123
- run_control_io
124
119
  @loop.run
125
120
  end
126
121
 
@@ -145,6 +140,9 @@ module Droonga
145
140
 
146
141
  def run_engine
147
142
  @engine = Engine.new(@loop, @engine_name, @internal_engine_name)
143
+ @engine.on_ready = lambda do
144
+ @worker_process_agent.ready
145
+ end
148
146
  @engine.start
149
147
  end
150
148
 
@@ -153,66 +151,23 @@ module Droonga
153
151
  @receiver.start
154
152
  end
155
153
 
156
- def shutdown_receiver
157
- return if @receiver.nil?
158
- @receiver, receiver = nil, @receiver
159
- receiver.shutdown
160
- end
161
-
162
- def run_control_io
163
- @control_read = Coolio::IO.new(IO.new(@control_read_fd))
154
+ def run_worker_process_agent
155
+ input = IO.new(@control_read_fd)
164
156
  @control_read_fd = nil
165
- on_read = lambda do |data|
166
- line_buffer = LineBuffer.new
167
- line_buffer.feed(data) do |line|
168
- case line
169
- when Messages::STOP_GRACEFUL
170
- stop_gracefully
171
- when Messages::STOP_IMMEDIATELY
172
- stop_immediately
173
- end
174
- end
175
- end
176
- @control_read.on_read do |data|
177
- on_read.call(data)
178
- end
179
- read_on_close = lambda do
180
- if @control_read
181
- @control_read = nil
182
- stop_immediately
183
- end
184
- end
185
- @control_read.on_close do
186
- read_on_close.call
187
- end
188
- @loop.attach(@control_read)
189
-
190
- @control_write = Coolio::IO.new(IO.new(@control_write_fd))
157
+ output = IO.new(@control_write_fd)
191
158
  @control_write_fd = nil
192
- write_on_close = lambda do
193
- if @control_write
194
- @control_write = nil
195
- stop_immediately
196
- end
197
- @control_write_closed = true
159
+ @worker_process_agent = WorkerProcessAgent.new(@loop, input, output)
160
+ @worker_process_agent.on_stop_gracefully = lambda do
161
+ stop_gracefully
198
162
  end
199
- @control_write.on_close do
200
- write_on_close.call
163
+ @worker_process_agent.on_stop_immediately = lambda do
164
+ stop_immediately
201
165
  end
202
- @loop.attach(@control_write)
203
-
204
- @control_write.write(Messages::READY)
166
+ @worker_process_agent.start
205
167
  end
206
168
 
207
- def shutdown_control_io
208
- if @control_write
209
- @control_write, control_write = nil, @control_write
210
- control_write.detach
211
- end
212
- if @control_read
213
- @control_read, control_read = nil, @control_read
214
- control_read.close
215
- end
169
+ def shutdown_worker_process_agent
170
+ @worker_process_agent.stop
216
171
  end
217
172
 
218
173
  def create_receiver
@@ -250,17 +205,17 @@ module Droonga
250
205
  def stop_gracefully
251
206
  return if @stopping
252
207
  @stopping = true
253
- shutdown_receiver
208
+ @receiver.stop_gracefully
254
209
  @engine.stop_gracefully do
255
- shutdown_control_io
210
+ shutdown_worker_process_agent
256
211
  shutdown_internal_message_receiver
257
212
  end
258
213
  end
259
214
 
260
215
  # It may be called after stop_gracefully.
261
216
  def stop_immediately
262
- shutdown_control_io
263
- shutdown_receiver if @receiver
217
+ shutdown_worker_process_agent
218
+ @receiver.stop_immediately
264
219
  shutdown_internal_message_receiver
265
220
  @engine.stop_immediately
266
221
  @loop.stop
@@ -0,0 +1,232 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
+
16
+ require "optparse"
17
+ require "fileutils"
18
+
19
+ require "coolio"
20
+
21
+ require "droonga/job_receiver"
22
+ require "droonga/plugin_loader"
23
+ require "droonga/worker_process_agent"
24
+ require "droonga/handler_runner"
25
+
26
+ module Droonga
27
+ module Command
28
+ class DroongaEngineWorker
29
+ class << self
30
+ def run(command_line_arguments)
31
+ new.run(command_line_arguments)
32
+ end
33
+ end
34
+
35
+ include Loggable
36
+
37
+ def initialize
38
+ @job_queue_socket_path = nil
39
+ @contrtol_read_fd = nil
40
+ @contrtol_write_fd = nil
41
+ @pid_file_path = nil
42
+ @dataset = nil
43
+ @database_path = nil
44
+ @plugins = []
45
+ @worker_process_agent = nil
46
+ end
47
+
48
+ def run(command_line_arguments)
49
+ create_new_process_group
50
+
51
+ parse_command_line_arguments!(command_line_arguments)
52
+ PluginLoader.load_all
53
+
54
+ write_pid_file do
55
+ run_main_loop
56
+ end
57
+ end
58
+
59
+ private
60
+ def create_new_process_group
61
+ begin
62
+ Process.setsid
63
+ rescue SystemCallError, NotImplementedError
64
+ end
65
+ end
66
+
67
+ def parse_command_line_arguments!(command_line_arguments)
68
+ parser = OptionParser.new
69
+ add_internal_options(parser)
70
+ parser.parse!(command_line_arguments)
71
+ end
72
+
73
+ def add_internal_options(parser)
74
+ parser.separator("")
75
+ parser.separator("Internal:")
76
+ parser.on("--job-queue-socket-path=PATH",
77
+ "Read jobs from PATH") do |path|
78
+ @job_queue_socket_path = Pathname.new(path)
79
+ end
80
+ parser.on("--control-read-fd=FD", Integer,
81
+ "Use FD to read control messages from the service") do |fd|
82
+ @control_read_fd = fd
83
+ end
84
+ parser.on("--control-write-fd=FD", Integer,
85
+ "Use FD to write control messages from the service") do |fd|
86
+ @control_write_fd = fd
87
+ end
88
+ parser.on("--pid-file=PATH",
89
+ "Put PID to PATH") do |path|
90
+ @pid_file_path = Pathname.new(path)
91
+ end
92
+ parser.on("--dataset=DATASET",
93
+ "Process DATASET") do |dataset|
94
+ @dataset = dataset
95
+ end
96
+ parser.on("--database-path=PATH",
97
+ "Use database at PATH") do |path|
98
+ @database_path = Pathname.new(path)
99
+ end
100
+ parser.on("--plugins=PLUGIN1,PLUGIN2,...", Array,
101
+ "Use PLUGINs") do |plugins|
102
+ @plugins = plugins
103
+ end
104
+ end
105
+
106
+ def write_pid_file
107
+ if @pid_file_path
108
+ @pid_file_path.open("w") do |file|
109
+ file.puts(Process.pid)
110
+ end
111
+ begin
112
+ yield
113
+ ensure
114
+ FileUtils.rm_f(@pid_file_path.to_s)
115
+ end
116
+ else
117
+ yield
118
+ end
119
+ end
120
+
121
+ def run_main_loop
122
+ begin
123
+ start
124
+ true
125
+ rescue
126
+ logger.exception("failed while running", $!)
127
+ false
128
+ ensure
129
+ stop_worker_process_agent
130
+ end
131
+ end
132
+
133
+ def start
134
+ @stopping = false
135
+ @loop = Coolio::Loop.default
136
+
137
+ start_forwarder
138
+ start_handler_runner
139
+ start_job_receiver
140
+ start_worker_process_agent
141
+
142
+ @loop.run
143
+ end
144
+
145
+ def stop_gracefully
146
+ return if @stopping
147
+ @stopping = true
148
+
149
+ stop_worker_process_agent
150
+ stop_job_receiver
151
+ stop_handler_runner
152
+ stop_forwarder
153
+ end
154
+
155
+ # It may be called after stop_gracefully.
156
+ def stop_immediately
157
+ stop_gracefully
158
+ @loop.stop
159
+ end
160
+
161
+ def start_forwarder
162
+ @forwarder = Forwarder.new(@loop)
163
+ @forwarder.start
164
+ end
165
+
166
+ def stop_forwarder
167
+ @forwarder.shutdown
168
+ end
169
+
170
+ def start_handler_runner
171
+ options = {
172
+ :forwarder => @forwarder,
173
+ :dataset => @dataset,
174
+ :database => @database_path.to_s,
175
+ :plugins => @plugins,
176
+ }
177
+ @handler_runner = HandlerRunner.new(@loop, options)
178
+ @handler_runner.start
179
+ end
180
+
181
+ def stop_handler_runner
182
+ @handler_runner.shutdown
183
+ end
184
+
185
+ def start_job_receiver
186
+ @job_receiver = create_job_receiver
187
+ @job_receiver.start
188
+ end
189
+
190
+ def create_job_receiver
191
+ JobReceiver.new(@loop, @job_queue_socket_path.to_s) do |message|
192
+ process(message)
193
+ end
194
+ end
195
+
196
+ def process(message)
197
+ logger.trace("process: start")
198
+ @handler_runner.process(message)
199
+ logger.trace("process: done")
200
+ end
201
+
202
+ def stop_job_receiver
203
+ @job_receiver.shutdown
204
+ end
205
+
206
+ def start_worker_process_agent
207
+ input = IO.new(@control_read_fd)
208
+ @control_read_fd = nil
209
+ output = IO.new(@control_write_fd)
210
+ @control_write_fd = nil
211
+ @worker_process_agent = WorkerProcessAgent.new(@loop, input, output)
212
+ @worker_process_agent.on_stop_gracefully = lambda do
213
+ stop_gracefully
214
+ end
215
+ @worker_process_agent.on_stop_immediately = lambda do
216
+ stop_immediately
217
+ end
218
+ @worker_process_agent.start
219
+ @worker_process_agent.ready
220
+ end
221
+
222
+ def stop_worker_process_agent
223
+ return if @worker_process_agent.nil?
224
+ @worker_process_agent.stop
225
+ end
226
+
227
+ def log_tag
228
+ "[#{Process.ppid}] worker"
229
+ end
230
+ end
231
+ end
232
+ end