droonga-engine 1.0.4 → 1.0.5

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