fluent-plugin-droonga 0.0.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +6 -0
  3. data/.yardopts +7 -0
  4. data/Gemfile +14 -2
  5. data/LICENSE.txt +1 -1
  6. data/README.md +1 -1
  7. data/Rakefile +27 -5
  8. data/benchmark/benchmark.rb +1 -1
  9. data/benchmark/utils.rb +9 -6
  10. data/benchmark/watch/benchmark-notify.rb +2 -2
  11. data/benchmark/watch/benchmark-publish.rb +1 -1
  12. data/benchmark/watch/benchmark-scan.rb +1 -1
  13. data/benchmark/watch/catalog.json +1 -1
  14. data/bin/grn2jsons +1 -1
  15. data/fluent-plugin-droonga.gemspec +5 -3
  16. data/lib/droonga/adapter.rb +13 -130
  17. data/lib/droonga/adapter_plugin.rb +51 -0
  18. data/lib/droonga/catalog.rb +2 -2
  19. data/lib/droonga/collector.rb +107 -0
  20. data/lib/droonga/collector_plugin.rb +82 -0
  21. data/lib/droonga/command_mapper.rb +1 -1
  22. data/lib/droonga/{proxy.rb → dispatcher.rb} +116 -151
  23. data/lib/droonga/distributor.rb +51 -0
  24. data/lib/droonga/distributor_plugin.rb +59 -0
  25. data/lib/droonga/engine.rb +9 -50
  26. data/lib/droonga/farm.rb +47 -0
  27. data/lib/droonga/forwarder.rb +125 -0
  28. data/lib/droonga/handler.rb +69 -60
  29. data/lib/droonga/handler_plugin.rb +22 -11
  30. data/lib/droonga/input_message.rb +51 -0
  31. data/lib/droonga/job_queue.rb +5 -1
  32. data/lib/droonga/job_queue_schema.rb +1 -1
  33. data/lib/droonga/logger.rb +1 -1
  34. data/lib/droonga/partition.rb +76 -0
  35. data/lib/droonga/pluggable.rb +62 -0
  36. data/lib/droonga/plugin.rb +18 -16
  37. data/lib/droonga/plugin/{adapter_groonga.rb → adapter/groonga.rb} +10 -10
  38. data/lib/droonga/plugin/adapter/groonga/select.rb +13 -4
  39. data/lib/droonga/plugin/collector/basic.rb +142 -0
  40. data/lib/droonga/plugin/distributor/crud.rb +43 -0
  41. data/lib/droonga/plugin/distributor/groonga.rb +37 -0
  42. data/lib/droonga/plugin/distributor/search.rb +273 -0
  43. data/lib/droonga/plugin/distributor/watch.rb +39 -0
  44. data/lib/droonga/plugin/{handler_add.rb → handler/add.rb} +6 -6
  45. data/lib/droonga/plugin/{handler_forward.rb → handler/forward.rb} +9 -4
  46. data/lib/droonga/plugin/{handler_groonga.rb → handler/groonga.rb} +36 -4
  47. data/lib/droonga/plugin/handler/groonga/column_create.rb +5 -9
  48. data/lib/droonga/plugin/handler/groonga/table_create.rb +9 -18
  49. data/lib/droonga/plugin/{handler_search.rb → handler/search.rb} +4 -4
  50. data/lib/droonga/plugin/{handler_watch.rb → handler/watch.rb} +4 -4
  51. data/lib/droonga/plugin_loader.rb +45 -0
  52. data/lib/droonga/plugin_registerable.rb +51 -0
  53. data/lib/droonga/plugin_repository.rb +56 -0
  54. data/lib/droonga/processor.rb +64 -0
  55. data/lib/droonga/searcher.rb +16 -7
  56. data/lib/droonga/server.rb +5 -9
  57. data/lib/droonga/sweeper.rb +1 -1
  58. data/lib/droonga/watch_schema.rb +1 -1
  59. data/lib/droonga/watcher.rb +1 -1
  60. data/lib/droonga/worker.rb +21 -9
  61. data/lib/fluent/plugin/out_droonga.rb +33 -15
  62. data/lib/groonga_command_converter.rb +1 -1
  63. data/sample/cluster/fluentd.conf +0 -1
  64. data/test/command/config/default/catalog.json +43 -0
  65. data/test/command/config/default/fluentd.conf +11 -0
  66. data/test/command/fixture/documents.jsons +208 -0
  67. data/test/command/fixture/user-table-array.jsons +38 -0
  68. data/test/command/fixture/user-table.jsons +38 -0
  69. data/test/command/run-test.rb +35 -0
  70. data/test/command/suite/add/minimum.expected +12 -0
  71. data/test/command/suite/add/minimum.test +11 -0
  72. data/test/command/suite/add/with-values.expected +12 -0
  73. data/test/command/suite/add/with-values.test +17 -0
  74. data/test/command/suite/add/without-key.expected +12 -0
  75. data/test/command/suite/add/without-key.test +16 -0
  76. data/test/command/suite/groonga/column_create/scalar.expected +34 -0
  77. data/test/command/suite/groonga/column_create/scalar.test +17 -0
  78. data/test/command/suite/groonga/column_create/vector.expected +34 -0
  79. data/test/command/suite/groonga/column_create/vector.test +18 -0
  80. data/test/command/suite/groonga/select/minimum.expected +26 -0
  81. data/test/command/suite/groonga/select/minimum.test +8 -0
  82. data/test/command/suite/groonga/table_create/array.expected +17 -0
  83. data/test/command/suite/groonga/table_create/array.test +8 -0
  84. data/test/command/suite/groonga/table_create/hash.expected +17 -0
  85. data/test/command/suite/groonga/table_create/hash.test +8 -0
  86. data/test/command/suite/search/array-attribute-label.expected +25 -0
  87. data/test/command/suite/search/array-attribute-label.test +30 -0
  88. data/test/command/suite/search/chained-queries.expected +45 -0
  89. data/test/command/suite/search/chained-queries.test +43 -0
  90. data/test/command/suite/search/complex.expected +52 -0
  91. data/test/command/suite/search/complex.test +25 -0
  92. data/test/command/suite/search/condition-nested.expected +19 -0
  93. data/test/command/suite/search/condition-nested.test +29 -0
  94. data/test/command/suite/search/condition-query.expected +28 -0
  95. data/test/command/suite/search/condition-query.test +25 -0
  96. data/test/command/suite/search/condition-script.expected +28 -0
  97. data/test/command/suite/search/condition-script.test +28 -0
  98. data/test/command/suite/search/hash-attribute-label.expected +34 -0
  99. data/test/command/suite/search/hash-attribute-label.test +38 -0
  100. data/test/command/suite/search/minimum.expected +13 -0
  101. data/test/command/suite/search/minimum.test +16 -0
  102. data/test/command/suite/search/multiple-queries.expected +39 -0
  103. data/test/command/suite/search/multiple-queries.test +39 -0
  104. data/test/command/suite/search/output-range.expected +28 -0
  105. data/test/command/suite/search/output-range.test +25 -0
  106. data/test/command/suite/search/simple.expected +52 -0
  107. data/test/command/suite/search/simple.test +24 -0
  108. data/test/command/suite/search/sort-and-output-range.expected +25 -0
  109. data/test/command/suite/search/sort-and-output-range.test +29 -0
  110. data/test/command/suite/search/sort-range.expected +28 -0
  111. data/test/command/suite/search/sort-range.test +28 -0
  112. data/test/command/suite/search/sort-with-invisible-column.expected +28 -0
  113. data/test/command/suite/search/sort-with-invisible-column.test +28 -0
  114. data/test/unit/fixtures/array.grn +18 -0
  115. data/test/{fixtures → unit/fixtures}/catalog.json +0 -0
  116. data/test/{fixtures → unit/fixtures}/document.grn +20 -9
  117. data/test/unit/fixtures/reference/array.grn +11 -0
  118. data/test/unit/fixtures/reference/hash.grn +7 -0
  119. data/test/{helper.rb → unit/helper.rb} +2 -1
  120. data/test/{helper → unit/helper}/fixture.rb +1 -1
  121. data/test/unit/helper/plugin_helper.rb +38 -0
  122. data/test/{helper → unit/helper}/sandbox.rb +19 -6
  123. data/test/{helper → unit/helper}/stub_worker.rb +1 -1
  124. data/test/{helper → unit/helper}/watch_helper.rb +1 -13
  125. data/test/{plugin → unit/plugin}/adapter/groonga/test_select.rb +108 -4
  126. data/test/unit/plugin/collector/test_basic.rb +558 -0
  127. data/test/unit/plugin/distributor/test_search.rb +914 -0
  128. data/test/{plugin → unit/plugin}/handler/groonga/test_column_create.rb +18 -14
  129. data/test/{plugin → unit/plugin}/handler/groonga/test_table_create.rb +13 -11
  130. data/test/{plugin/handler/test_handler_add.rb → unit/plugin/handler/test_add.rb} +2 -14
  131. data/test/{plugin/handler/test_handler_groonga.rb → unit/plugin/handler/test_groonga.rb} +6 -26
  132. data/test/unit/plugin/handler/test_search.rb +601 -0
  133. data/test/{plugin/handler/test_handler_watch.rb → unit/plugin/handler/test_watch.rb} +2 -2
  134. data/test/{run-test.rb → unit/run-test.rb} +3 -3
  135. data/test/{test_adapter.rb → unit/test_adapter.rb} +17 -14
  136. data/test/{test_catalog.rb → unit/test_catalog.rb} +4 -4
  137. data/test/{test_command_mapper.rb → unit/test_command_mapper.rb} +1 -1
  138. data/test/{test_groonga_command_converter.rb → unit/test_groonga_command_converter.rb} +3 -3
  139. data/test/{test_job_queue_schema.rb → unit/test_job_queue_schema.rb} +1 -1
  140. data/test/{test_output.rb → unit/test_output.rb} +9 -9
  141. data/test/{test_handler.rb → unit/test_plugin.rb} +19 -22
  142. data/test/unit/test_plugin_repository.rb +89 -0
  143. data/test/{test_sweeper.rb → unit/test_sweeper.rb} +1 -1
  144. data/test/{test_watch_schema.rb → unit/test_watch_schema.rb} +1 -1
  145. data/test/{test_watcher.rb → unit/test_watcher.rb} +1 -1
  146. metadata +226 -66
  147. data/lib/droonga/executor.rb +0 -289
  148. data/lib/droonga/plugin/handler_proxy.rb +0 -82
  149. data/test/plugin/handler/test_handler_search.rb +0 -512
  150. data/test/test_worker.rb +0 -144
@@ -0,0 +1,51 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "droonga/pluggable"
19
+ require "droonga/distributor_plugin"
20
+
21
+ module Droonga
22
+ class Distributor
23
+ include Pluggable
24
+
25
+ def initialize(dispatcher, options={})
26
+ @dispatcher = dispatcher
27
+ @plugins = []
28
+ @options = options
29
+ # TODO: don't put the default distributions
30
+ load_plugins(options[:distributors] || ["search", "crud", "groonga", "watch"])
31
+ end
32
+
33
+ def distribute(envelope)
34
+ command = envelope["type"]
35
+ process(command, envelope)
36
+ end
37
+
38
+ def post(message)
39
+ @dispatcher.handle(message, [])
40
+ end
41
+
42
+ private
43
+ def instantiate_plugin(name)
44
+ DistributorPlugin.repository.instantiate(name, self)
45
+ end
46
+
47
+ def log_tag
48
+ "[#{Process.pid}] distributor"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,59 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "droonga/plugin"
19
+
20
+ module Droonga
21
+ class DistributorPlugin < Plugin
22
+ extend PluginRegisterable
23
+
24
+ def initialize(distributor)
25
+ super()
26
+ @distributor = distributor
27
+ end
28
+
29
+ # TODO: consider better name
30
+ def post(message)
31
+ @distributor.post(message)
32
+ end
33
+
34
+ def scatter_all(envelope, key)
35
+ message = [{
36
+ "command"=> envelope["type"],
37
+ "dataset"=> envelope["dataset"],
38
+ "body"=> envelope["body"],
39
+ "key"=> key,
40
+ "type"=> "scatter",
41
+ "replica"=> "all",
42
+ "post"=> true
43
+ }]
44
+ post(message)
45
+ end
46
+
47
+ def broadcast_all(envelope)
48
+ distirubte_message = [{
49
+ "command"=> envelope["type"],
50
+ "dataset"=> envelope["dataset"],
51
+ "body"=> envelope["body"],
52
+ "type"=> "broadcast",
53
+ "replica"=> "all",
54
+ "post"=> true
55
+ }]
56
+ post(distirubte_message)
57
+ end
58
+ end
59
+ end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2013 droonga project
3
+ # Copyright (C) 2013 Droonga Project
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -15,69 +15,28 @@
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 "serverengine"
19
- require "msgpack"
20
- require "cool.io"
21
-
22
- require "droonga/server"
23
- require "droonga/worker"
24
- require "droonga/executor"
18
+ require "droonga/logger"
19
+ require "droonga/dispatcher"
25
20
 
26
21
  module Droonga
27
22
  class Engine
28
- DEFAULT_OPTIONS = {
29
- :queue_name => "DroongaQueue",
30
- :n_workers => 0,
31
- }
32
-
33
23
  def initialize(options={})
34
- @options = DEFAULT_OPTIONS.merge(options)
24
+ @options = options
25
+ @dispatcher = Dispatcher.new(@options)
35
26
  end
36
27
 
37
28
  def start
38
- if @options[:database] && !@options[:database].empty?
39
- Droonga::JobQueue.ensure_schema(@options[:database],
40
- @options[:queue_name])
41
- end
42
- start_supervisor if @options[:n_workers] > 0
43
- @executor = Executor.new(@options)
29
+ @dispatcher.start
44
30
  end
45
31
 
46
32
  def shutdown
47
33
  $log.trace("engine: shutdown: start")
48
- @executor.shutdown if @executor
49
- shutdown_supervisor if @supervisor
34
+ @dispatcher.shutdown
50
35
  $log.trace("engine: shutdown: done")
51
36
  end
52
37
 
53
- def emit(tag, time, record, synchronous=nil)
54
- $log.trace("[#{Process.pid}] tag: <#{tag}> caller: <#{caller.first}>")
55
- @executor.dispatch(tag, time, record, synchronous)
56
- end
57
-
58
- private
59
- def start_supervisor
60
- @supervisor = ServerEngine::Supervisor.new(Server, Worker) do
61
- force_options = {
62
- :worker_type => "process",
63
- :workers => @options[:n_workers],
64
- :log_level => $log.level,
65
- :server_process_name => "Server[#{@options[:database]}] #$0",
66
- :worker_process_name => "Worker[#{@options[:database]}] #$0"
67
- }
68
- @options.merge(force_options)
69
- end
70
- @supervisor_thread = Thread.new do
71
- @supervisor.main
72
- end
73
- end
74
-
75
- def shutdown_supervisor
76
- $log.trace("supervisor: shutdown: start")
77
- @supervisor.stop(true)
78
- $log.trace("supervisor: shutdown: stopped")
79
- @supervisor_thread.join
80
- $log.trace("supervisor: shutdown: done")
38
+ def process(envelope)
39
+ @dispatcher.handle_envelope(envelope)
81
40
  end
82
41
  end
83
42
  end
@@ -0,0 +1,47 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "droonga/partition"
19
+
20
+ module Droonga
21
+ class Farm
22
+ def initialize(name)
23
+ @name = name
24
+ @partitions = {}
25
+ Droonga.catalog.get_partitions(name).each do |partition_name, options|
26
+ partition = Droonga::Partition.new(options)
27
+ @partitions[partition_name] = partition
28
+ end
29
+ end
30
+
31
+ def start
32
+ @partitions.each_value do |partition|
33
+ partition.start
34
+ end
35
+ end
36
+
37
+ def shutdown
38
+ @partitions.each_value do |partition|
39
+ partition.shutdown
40
+ end
41
+ end
42
+
43
+ def process(partition_name, envelope, synchronous)
44
+ @partitions[partition_name].process(envelope, synchronous)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,125 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Copyright (C) 2013 Droonga Project
4
+ #
5
+ # This library is free software; you can redistribute it and/or
6
+ # modify it under the terms of the GNU Lesser General Public
7
+ # License version 2.1 as published by the Free Software Foundation.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
+
18
+ require "fluent-logger"
19
+ require "fluent/logger/fluent_logger"
20
+
21
+ module Droonga
22
+ class Forwarder
23
+ def initialize
24
+ @outputs = {}
25
+ end
26
+
27
+ def shutdown
28
+ $log.trace("#{log_tag}: shutdown: start")
29
+ @outputs.each do |dest, output|
30
+ output[:logger].close if output[:logger]
31
+ end
32
+ $log.trace("#{log_tag}: shutdown: done")
33
+ end
34
+
35
+ def forward(envelope, body, destination)
36
+ $log.trace("#{log_tag}: post: start")
37
+ command = destination["type"]
38
+ receiver = destination["to"]
39
+ arguments = destination["arguments"]
40
+ output(receiver, envelope, body, command, arguments)
41
+ $log.trace("#{log_tag}: post: done")
42
+ end
43
+
44
+ private
45
+ def output(receiver, envelope, body, command, arguments)
46
+ $log.trace("#{log_tag}: output: start")
47
+ unless receiver.is_a?(String) && command.is_a?(String)
48
+ $log.trace("#{log_tag}: output: abort: invalid argument",
49
+ :receiver => receiver,
50
+ :command => command)
51
+ return
52
+ end
53
+ unless receiver =~ /\A(.*):(\d+)\/(.*?)(\?.+)?\z/
54
+ raise "format: hostname:port/tag(?params)"
55
+ end
56
+ host = $1
57
+ port = $2
58
+ tag = $3
59
+ params = $4
60
+ output = get_output(host, port, params)
61
+ unless output
62
+ $log.trace("#{log_tag}: output: abort: no output",
63
+ :host => host,
64
+ :port => port,
65
+ :params => params)
66
+ return
67
+ end
68
+ if command =~ /\.result$/
69
+ message = {
70
+ inReplyTo: envelope["id"],
71
+ statusCode: 200,
72
+ type: command,
73
+ body: body
74
+ }
75
+ else
76
+ message = envelope.merge(
77
+ body: body,
78
+ type: command,
79
+ arguments: arguments
80
+ )
81
+ end
82
+ output_tag = "#{tag}.message"
83
+ log_info = "<#{receiver}>:<#{output_tag}>"
84
+ $log.trace("#{log_tag}: output: post: start: #{log_info}")
85
+ output.post(output_tag, message)
86
+ $log.trace("#{log_tag}: output: post: done: #{log_info}")
87
+ $log.trace("#{log_tag}: output: done")
88
+ end
89
+
90
+ def get_output(host, port, params)
91
+ host_port = "#{host}:#{port}"
92
+ @outputs[host_port] ||= {}
93
+ output = @outputs[host_port]
94
+
95
+ has_connection_id = (not params.nil? \
96
+ and params =~ /[\?&;]connection_id=([^&;]+)/)
97
+ if output[:logger].nil? or has_connection_id
98
+ connection_id = $1
99
+ if not has_connection_id or output[:connection_id] != connection_id
100
+ output[:connection_id] = connection_id
101
+ logger = create_logger(:host => host, :port => port.to_i)
102
+ # output[:logger] should be closed if it exists beforehand?
103
+ output[:logger] = logger
104
+ end
105
+ end
106
+
107
+ has_client_session_id = (not params.nil? \
108
+ and params =~ /[\?&;]client_session_id=([^&;]+)/)
109
+ if has_client_session_id
110
+ client_session_id = $1
111
+ # some generic way to handle client_session_id is expected
112
+ end
113
+
114
+ output[:logger]
115
+ end
116
+
117
+ def create_logger(options)
118
+ Fluent::Logger::FluentLogger.new(nil, options)
119
+ end
120
+
121
+ def log_tag
122
+ "[#{Process.ppid}][#{Process.pid}] forwarder"
123
+ end
124
+ end
125
+ end
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
- # Copyright (C) 2013 droonga project
3
+ # Copyright (C) 2013 Droonga Project
4
4
  #
5
5
  # This library is free software; you can redistribute it and/or
6
6
  # modify it under the terms of the GNU Lesser General Public
@@ -15,75 +15,52 @@
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 "groonga"
19
+
20
+ require "droonga/forwarder"
21
+ require "droonga/pluggable"
18
22
  require "droonga/handler_plugin"
19
- require "droonga/command_mapper"
20
- require "droonga/logger"
21
23
 
22
24
  module Droonga
23
25
  class Handler
24
- class << self
25
- def inherited(sub_class)
26
- super
27
- sub_class.instance_variable_set(:@command_mapper, CommandMapper.new)
28
- end
26
+ include Pluggable
29
27
 
30
- def command(name_or_map)
31
- @command_mapper.register(name_or_map)
32
- end
33
-
34
- def method_name(command)
35
- @command_mapper[command]
36
- end
28
+ attr_reader :context, :envelope, :name
37
29
 
38
- def handlable?(command)
39
- not method_name(command).nil?
40
- end
41
- end
42
-
43
- def initialize(worker)
44
- @worker = worker
45
- @context = @worker.context
46
- end
47
-
48
- def post(body, destination=nil)
49
- @worker.post(body, destination)
50
- end
51
-
52
- def envelope
53
- @worker.envelope
54
- end
55
-
56
- def add_route(route)
57
- @worker.add_route(route)
30
+ def initialize(options={})
31
+ @options = options
32
+ @name = options[:name]
33
+ @database_name = options[:database]
34
+ prepare
58
35
  end
59
36
 
60
37
  def shutdown
38
+ $log.trace("#{log_tag}: shutdown: start")
39
+ super
40
+ @forwarder.shutdown
41
+ if @database
42
+ @database.close
43
+ @context.close
44
+ @database = @context = nil
45
+ end
46
+ $log.trace("#{log_tag}: shutdown: done")
61
47
  end
62
48
 
63
- def handlable?(command)
64
- self.class.handlable?(command)
65
- end
66
-
67
- def invoke(command, request, *arguments)
68
- __send__(self.class.method_name(command), request, *arguments)
69
- rescue => exception
70
- Logger.error("error while handling #{command}",
71
- request: request,
72
- arguments: arguments,
73
- exception: exception)
49
+ def prefer_synchronous?(command)
50
+ find_plugin(command).prefer_synchronous?(command)
74
51
  end
75
52
 
76
- def handle(command, request, *arguments)
77
- unless try_handle_as_internal_message(command, request, arguments)
78
- @task = {}
79
- @output_values = {}
80
- invoke(command, request, *arguments)
81
- post(@output_values) unless @output_values.empty?
53
+ def process(envelope)
54
+ $log.trace("#{log_tag}: process: start")
55
+ body, command, arguments = parse_envelope(envelope)
56
+ plugin = find_plugin(command)
57
+ if plugin.nil?
58
+ $log.trace("#{log_tag}: process: done: no plugin: <#{command}>")
59
+ return
82
60
  end
83
- end
84
-
85
- def prefer_synchronous?(command)
86
- return false
61
+ process_command(plugin, command, body, arguments)
62
+ $log.trace("#{log_tag}: process: done: <#{command}>",
63
+ :plugin => plugin.class)
87
64
  end
88
65
 
89
66
  def emit(value, name = nil)
@@ -98,7 +75,31 @@ module Droonga
98
75
  @output_values[name] = value
99
76
  end
100
77
 
101
- def try_handle_as_internal_message(command, request, arguments)
78
+ def post(message, destination)
79
+ @forwarder.forward(envelope, message, destination)
80
+ end
81
+
82
+ private
83
+ def parse_envelope(envelope)
84
+ @envelope = envelope
85
+ envelope["via"] ||= []
86
+ [envelope["body"], envelope["type"], envelope["arguments"]]
87
+ end
88
+
89
+ def prepare
90
+ if @database_name && !@database_name.empty?
91
+ @context = Groonga::Context.new
92
+ @database = @context.open_database(@database_name)
93
+ end
94
+ load_plugins(@options[:handlers] || [])
95
+ @forwarder = Forwarder.new
96
+ end
97
+
98
+ def instantiate_plugin(name)
99
+ HandlerPlugin.repository.instantiate(name, self)
100
+ end
101
+
102
+ def process_command(plugin, command, request, arguments)
102
103
  return false unless request.is_a? Hash
103
104
 
104
105
  @task = request["task"]
@@ -115,14 +116,18 @@ module Droonga
115
116
  @input_name = request["name"]
116
117
  @descendants = request["descendants"]
117
118
 
118
- invoke(command, @body, *arguments)
119
+ plugin.process(command, @body, *arguments)
119
120
  output if @descendants
120
121
  true
121
122
  end
122
123
 
123
124
  def output
124
125
  result = @task["values"]
125
- post(result, @component["post"]) if @component["post"]
126
+ if @component["post"]
127
+ destination = @component["post"]
128
+ destination = envelope["replyTo"] if destination == true
129
+ post(result, destination)
130
+ end
126
131
  @descendants.each do |name, dests|
127
132
  message = {
128
133
  "id" => @id,
@@ -131,10 +136,14 @@ module Droonga
131
136
  }
132
137
  dests.each do |routes|
133
138
  routes.each do |route|
134
- post(message, "to"=>route, "type"=>"proxy")
139
+ post(message, "to"=>route, "type"=>"dispatcher")
135
140
  end
136
141
  end
137
142
  end
138
143
  end
144
+
145
+ def log_tag
146
+ "[#{Process.ppid}][#{Process.pid}] handler"
147
+ end
139
148
  end
140
149
  end