fluent-plugin-droonga 0.0.2 → 0.7.0

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