fluent-plugin-droonga 0.7.0 → 0.8.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 (163) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -4
  3. data/benchmark/watch/benchmark-notify.rb +2 -2
  4. data/benchmark/watch/benchmark-scan.rb +3 -0
  5. data/benchmark/watch/fluentd.conf +0 -1
  6. data/fluent-plugin-droonga.gemspec +2 -3
  7. data/lib/droonga/catalog.rb +10 -124
  8. data/lib/droonga/catalog/base.rb +140 -0
  9. data/lib/droonga/catalog/version1.rb +23 -0
  10. data/lib/droonga/catalog_loader.rb +33 -0
  11. data/lib/droonga/collector.rb +2 -71
  12. data/lib/droonga/collector_plugin.rb +2 -34
  13. data/lib/droonga/dispatcher.rb +141 -196
  14. data/lib/droonga/distribution_planner.rb +76 -0
  15. data/lib/droonga/distributor.rb +5 -7
  16. data/lib/droonga/distributor_plugin.rb +23 -15
  17. data/lib/droonga/engine.rb +2 -2
  18. data/lib/droonga/event_loop.rb +46 -0
  19. data/lib/droonga/farm.rb +9 -5
  20. data/lib/droonga/fluent_message_sender.rb +84 -0
  21. data/lib/droonga/forwarder.rb +43 -53
  22. data/lib/droonga/handler.rb +20 -68
  23. data/lib/droonga/handler_message.rb +61 -0
  24. data/lib/droonga/handler_messenger.rb +92 -0
  25. data/lib/droonga/handler_plugin.rb +10 -12
  26. data/lib/droonga/input_adapter.rb +52 -0
  27. data/lib/droonga/{adapter.rb → input_adapter_plugin.rb} +7 -13
  28. data/lib/droonga/input_message.rb +11 -11
  29. data/lib/droonga/logger.rb +4 -3
  30. data/lib/droonga/message_pack_packer.rb +62 -0
  31. data/lib/droonga/message_processing_error.rb +54 -0
  32. data/lib/droonga/message_pusher.rb +60 -0
  33. data/lib/droonga/message_receiver.rb +61 -0
  34. data/lib/droonga/output_adapter.rb +53 -0
  35. data/lib/droonga/{adapter_plugin.rb → output_adapter_plugin.rb} +3 -21
  36. data/lib/droonga/output_message.rb +37 -0
  37. data/lib/droonga/partition.rb +27 -5
  38. data/lib/droonga/pluggable.rb +9 -4
  39. data/lib/droonga/plugin.rb +12 -3
  40. data/lib/droonga/plugin/collector/basic.rb +91 -18
  41. data/lib/droonga/plugin/distributor/crud.rb +9 -9
  42. data/lib/droonga/plugin/distributor/distributed_search_planner.rb +401 -0
  43. data/lib/droonga/plugin/distributor/groonga.rb +5 -5
  44. data/lib/droonga/plugin/distributor/search.rb +4 -246
  45. data/lib/droonga/plugin/distributor/watch.rb +11 -6
  46. data/lib/droonga/plugin/handler/add.rb +69 -7
  47. data/lib/droonga/plugin/handler/groonga.rb +6 -6
  48. data/lib/droonga/plugin/handler/search.rb +5 -3
  49. data/lib/droonga/plugin/handler/watch.rb +19 -13
  50. data/lib/droonga/plugin/{adapter → input_adapter}/groonga.rb +5 -11
  51. data/lib/droonga/plugin/{adapter → input_adapter}/groonga/select.rb +2 -36
  52. data/lib/droonga/plugin/output_adapter/groonga.rb +30 -0
  53. data/lib/droonga/plugin/output_adapter/groonga/select.rb +54 -0
  54. data/lib/droonga/plugin_loader.rb +2 -2
  55. data/lib/droonga/processor.rb +21 -23
  56. data/lib/droonga/replier.rb +40 -0
  57. data/lib/droonga/searcher.rb +298 -174
  58. data/lib/droonga/server.rb +0 -67
  59. data/lib/droonga/session.rb +85 -0
  60. data/lib/droonga/test.rb +21 -0
  61. data/lib/droonga/test/stub_distributor.rb +31 -0
  62. data/lib/droonga/test/stub_handler.rb +37 -0
  63. data/lib/droonga/test/stub_handler_message.rb +35 -0
  64. data/lib/droonga/test/stub_handler_messenger.rb +34 -0
  65. data/lib/droonga/time_formatter.rb +37 -0
  66. data/lib/droonga/watcher.rb +1 -0
  67. data/lib/droonga/worker.rb +16 -19
  68. data/lib/fluent/plugin/out_droonga.rb +9 -9
  69. data/lib/groonga_command_converter.rb +5 -5
  70. data/sample/cluster/catalog.json +1 -1
  71. data/test/command/config/default/catalog.json +19 -1
  72. data/test/command/fixture/event.jsons +41 -0
  73. data/test/command/fixture/user-table.jsons +9 -0
  74. data/test/command/run-test.rb +2 -2
  75. data/test/command/suite/add/error/invalid-integer.expected +20 -0
  76. data/test/command/suite/add/error/invalid-integer.test +12 -0
  77. data/test/command/suite/add/error/invalid-time.expected +20 -0
  78. data/test/command/suite/add/error/invalid-time.test +12 -0
  79. data/test/command/suite/add/error/missing-key.expected +13 -0
  80. data/test/command/suite/add/error/missing-key.test +16 -0
  81. data/test/command/suite/add/error/missing-table.expected +13 -0
  82. data/test/command/suite/add/error/missing-table.test +16 -0
  83. data/test/command/suite/add/error/unknown-column.expected +20 -0
  84. data/test/command/suite/add/error/unknown-column.test +12 -0
  85. data/test/command/suite/add/error/unknown-table.expected +13 -0
  86. data/test/command/suite/add/error/unknown-table.test +17 -0
  87. data/test/command/suite/add/minimum.expected +1 -3
  88. data/test/command/suite/add/with-values.expected +1 -3
  89. data/test/command/suite/add/without-key.expected +1 -3
  90. data/test/command/suite/message/error/missing-dataset.expected +13 -0
  91. data/test/command/suite/message/error/missing-dataset.test +5 -0
  92. data/test/command/suite/message/error/unknown-command.expected +13 -0
  93. data/test/command/suite/message/error/unknown-command.test +6 -0
  94. data/test/command/suite/message/error/unknown-dataset.expected +13 -0
  95. data/test/command/suite/message/error/unknown-dataset.test +6 -0
  96. data/test/command/suite/search/{array-attribute-label.expected → attributes/array.expected} +0 -0
  97. data/test/command/suite/search/{array-attribute-label.test → attributes/array.test} +0 -0
  98. data/test/command/suite/search/{hash-attribute-label.expected → attributes/hash.expected} +0 -0
  99. data/test/command/suite/search/{hash-attribute-label.test → attributes/hash.test} +0 -0
  100. data/test/command/suite/search/{condition-nested.expected → condition/nested.expected} +0 -0
  101. data/test/command/suite/search/{condition-nested.test → condition/nested.test} +0 -0
  102. data/test/command/suite/search/{condition-query.expected → condition/query.expected} +0 -0
  103. data/test/command/suite/search/{condition-query.test → condition/query.test} +0 -0
  104. data/test/command/suite/search/{condition-script.expected → condition/script.expected} +0 -0
  105. data/test/command/suite/search/{condition-script.test → condition/script.test} +0 -0
  106. data/test/command/suite/search/error/cyclic-source.expected +18 -0
  107. data/test/command/suite/search/error/cyclic-source.test +12 -0
  108. data/test/command/suite/search/error/deeply-cyclic-source.expected +21 -0
  109. data/test/command/suite/search/error/deeply-cyclic-source.test +15 -0
  110. data/test/command/suite/search/error/missing-source-parameter.expected +17 -0
  111. data/test/command/suite/search/error/missing-source-parameter.test +11 -0
  112. data/test/command/suite/search/error/unknown-source.expected +18 -0
  113. data/test/command/suite/search/error/unknown-source.test +12 -0
  114. data/test/command/suite/search/{minimum.expected → group/count.expected} +2 -1
  115. data/test/command/suite/search/{minimum.test → group/count.test} +5 -3
  116. data/test/command/suite/search/group/limit.expected +19 -0
  117. data/test/command/suite/search/group/limit.test +20 -0
  118. data/test/command/suite/search/group/string.expected +36 -0
  119. data/test/command/suite/search/group/string.test +44 -0
  120. data/test/command/suite/search/{chained-queries.expected → multiple/chained.expected} +0 -0
  121. data/test/command/suite/search/{chained-queries.test → multiple/chained.test} +0 -0
  122. data/test/command/suite/search/{multiple-queries.expected → multiple/parallel.expected} +0 -0
  123. data/test/command/suite/search/{multiple-queries.test → multiple/parallel.test} +0 -0
  124. data/test/command/suite/search/{output-range.expected → range/only-output.expected} +0 -0
  125. data/test/command/suite/search/{output-range.test → range/only-output.test} +0 -0
  126. data/test/command/suite/search/{sort-range.expected → range/only-sort.expected} +0 -0
  127. data/test/command/suite/search/{sort-range.test → range/only-sort.test} +0 -0
  128. data/test/command/suite/search/{sort-and-output-range.expected → range/sort-and-output.expected} +0 -0
  129. data/test/command/suite/search/{sort-and-output-range.test → range/sort-and-output.test} +0 -0
  130. data/test/command/suite/search/range/too-large-output-offset.expected +16 -0
  131. data/test/command/suite/search/range/too-large-output-offset.test +25 -0
  132. data/test/command/suite/search/range/too-large-sort-offset.expected +16 -0
  133. data/test/command/suite/search/range/too-large-sort-offset.test +28 -0
  134. data/test/command/suite/search/response/records/value/time.expected +24 -0
  135. data/test/command/suite/search/response/records/value/time.test +24 -0
  136. data/test/command/suite/search/sort/default-offset-limit.expected +43 -0
  137. data/test/command/suite/search/sort/default-offset-limit.test +26 -0
  138. data/test/command/suite/search/{sort-with-invisible-column.expected → sort/invisible-column.expected} +0 -0
  139. data/test/command/suite/search/{sort-with-invisible-column.test → sort/invisible-column.test} +0 -0
  140. data/test/command/suite/watch/subscribe.expected +12 -0
  141. data/test/command/suite/watch/subscribe.test +9 -0
  142. data/test/command/suite/watch/unsubscribe.expected +12 -0
  143. data/test/command/suite/watch/unsubscribe.test +9 -0
  144. data/test/unit/{test_catalog.rb → catalog/test_version1.rb} +12 -4
  145. data/test/unit/fixtures/{catalog.json → catalog/version1.json} +0 -0
  146. data/test/unit/helper.rb +2 -0
  147. data/test/unit/plugin/collector/test_basic.rb +289 -33
  148. data/test/unit/plugin/distributor/test_search.rb +176 -861
  149. data/test/unit/plugin/distributor/test_search_planner.rb +1102 -0
  150. data/test/unit/plugin/handler/groonga/test_column_create.rb +17 -13
  151. data/test/unit/plugin/handler/groonga/test_table_create.rb +10 -10
  152. data/test/unit/plugin/handler/test_add.rb +74 -11
  153. data/test/unit/plugin/handler/test_groonga.rb +15 -1
  154. data/test/unit/plugin/handler/test_search.rb +33 -17
  155. data/test/unit/plugin/handler/test_watch.rb +43 -27
  156. data/test/unit/run-test.rb +2 -0
  157. data/test/unit/test_message_pack_packer.rb +51 -0
  158. data/test/unit/test_time_formatter.rb +29 -0
  159. metadata +208 -110
  160. data/lib/droonga/job_queue.rb +0 -87
  161. data/lib/droonga/job_queue_schema.rb +0 -65
  162. data/test/unit/test_adapter.rb +0 -51
  163. data/test/unit/test_job_queue_schema.rb +0 -45
@@ -22,9 +22,8 @@ module Droonga
22
22
  extend PluginRegisterable
23
23
 
24
24
  attr_reader :task, :input_name, :component, :output_values, :body, :output_names
25
- def initialize(dispatcher)
25
+ def initialize
26
26
  super()
27
- @dispatcher = dispatcher
28
27
  end
29
28
 
30
29
  def process(command, message)
@@ -39,44 +38,13 @@ module Droonga
39
38
  @id = message["id"]
40
39
  @value = message["value"]
41
40
  @input_name = message["name"]
42
- @descendants = message["descendants"]
43
41
  super(command, @value)
44
- output if @descendants
45
42
  true
46
43
  end
47
44
 
48
45
  # TODO: consider better name
49
- def emit(value, name=nil)
50
- unless name
51
- if @output_names
52
- name = @output_names.first
53
- else
54
- @output_values = @task["values"] = value
55
- return
56
- end
57
- end
46
+ def emit(name, value)
58
47
  @output_values[name] = value
59
48
  end
60
-
61
- def post(message, destination=nil)
62
- @dispatcher.post(message, destination)
63
- end
64
-
65
- def output
66
- result = @task["values"]
67
- post(result, @component["post"]) if @component["post"]
68
- @descendants.each do |name, dests|
69
- message = {
70
- "id" => @id,
71
- "input" => name,
72
- "value" => result[name]
73
- }
74
- dests.each do |routes|
75
- routes.each do |route|
76
- post(message, "to"=>route, "type"=>"dispatcher")
77
- end
78
- end
79
- end
80
- end
81
49
  end
82
50
  end
@@ -15,149 +15,185 @@
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 'tsort'
19
- require "droonga/adapter"
18
+ require "English"
19
+ require "tsort"
20
+
21
+ require "droonga/input_adapter"
22
+ require "droonga/output_adapter"
20
23
  require "droonga/distributor"
21
24
  require "droonga/catalog"
22
25
  require "droonga/collector"
23
26
  require "droonga/farm"
24
- require "droonga/input_message"
27
+ require "droonga/session"
28
+ require "droonga/replier"
29
+ require "droonga/message_processing_error"
25
30
 
26
31
  module Droonga
27
32
  class Dispatcher
28
- attr_reader :name, :envelope, :collectors
33
+ attr_reader :name
34
+
35
+ class MissingDatasetParameter < BadRequest
36
+ def initialize
37
+ super("\"dataset\" must be specified.")
38
+ end
39
+ end
40
+
41
+ class UnknownCommand < BadRequest
42
+ def initialize(command, dataset)
43
+ super("The command #{command.inspect} is not available " +
44
+ "for the dataset #{dataset.inspect}.")
45
+ end
46
+ end
29
47
 
30
48
  def initialize(options)
31
49
  @options = options
32
50
  @name = @options[:name]
33
- @farm = Farm.new(name)
34
- @collectors = {}
51
+ @sessions = {}
35
52
  @current_id = 0
36
53
  @local = Regexp.new("^#{@name}")
37
- @adapter = Adapter.new(self,
38
- :adapters => Droonga.catalog.option("plugins"))
39
- @forwarder = Forwarder.new
54
+ @input_adapter =
55
+ InputAdapter.new(self, :plugins => Droonga.catalog.option("plugins"))
56
+ @output_adapter =
57
+ OutputAdapter.new(self, :plugins => Droonga.catalog.option("plugins"))
58
+ @loop = EventLoop.new
59
+ @farm = Farm.new(name, @loop, :dispatcher => self)
60
+ @forwarder = Forwarder.new(@loop)
61
+ @replier = Replier.new(@forwarder)
40
62
  @distributor = Distributor.new(self, @options)
63
+ @collector = Collector.new
41
64
  end
42
65
 
43
66
  def start
67
+ @forwarder.start
44
68
  @farm.start
69
+ @loop_thread = Thread.new do
70
+ @loop.run
71
+ end
45
72
  end
46
73
 
47
74
  def shutdown
48
75
  @forwarder.shutdown
49
76
  @distributor.shutdown
50
- @adapter.shutdown
77
+ @collector.shutdown
78
+ @input_adapter.shutdown
79
+ @output_adapter.shutdown
51
80
  @farm.shutdown
81
+ @loop.stop
82
+ @loop_thread.join
52
83
  end
53
84
 
54
- def add_route(route)
55
- envelope["via"].push(route)
56
- end
57
-
58
- def handle_envelope(envelope)
59
- @envelope = envelope
60
- if envelope["type"] == "dispatcher"
61
- handle(envelope["body"], envelope["arguments"])
85
+ def process_message(message)
86
+ @message = message
87
+ if message["type"] == "dispatcher"
88
+ process_internal_message(message["body"])
62
89
  else
63
- process_input_message(envelope)
64
- end
65
- end
66
-
67
- def post(body, destination=nil)
68
- $log.trace("#{log_tag}: post: start")
69
- route = nil
70
- unless is_route?(destination)
71
- route = envelope["via"].pop
72
- destination = route
73
- end
74
- unless is_route?(destination)
75
- destination = envelope["replyTo"]
76
- end
77
- command = nil
78
- receiver = nil
79
- arguments = nil
80
- synchronous = nil
81
- case destination
82
- when String
83
- command = destination
84
- when Hash
85
- command = destination["type"]
86
- receiver = destination["to"]
87
- arguments = destination["arguments"]
88
- synchronous = destination["synchronous"]
89
- end
90
- if receiver
91
- @forwarder.forward(envelope, body,
92
- "type" => command,
93
- "to" => receiver,
94
- "arguments" => arguments)
95
- else
96
- if command == "dispatcher"
97
- handle(body, arguments)
98
- elsif @adapter.processable?(command)
99
- @adapter.process(command, body, *arguments)
100
- else
101
- @distributor.distribute(envelope.merge("type" => command,
102
- "body" => body))
90
+ begin
91
+ assert_valid_message
92
+ process_input_message(message)
93
+ rescue MessageProcessingError => error
94
+ reply("statusCode" => error.status_code,
95
+ "body" => error.response_body)
103
96
  end
104
97
  end
105
- add_route(route) if route
106
- $log.trace("#{log_tag}: post: done")
107
98
  end
108
99
 
109
- def handle(message, arguments)
110
- case message
111
- when Array
112
- handle_incoming_message(message)
113
- when Hash
114
- handle_internal_message(message)
115
- end
100
+ def forward(message, destination)
101
+ $log.trace("#{log_tag}: forward start")
102
+ @forwarder.forward(message, destination)
103
+ $log.trace("#{log_tag}: forward done")
116
104
  end
117
105
 
118
- def handle_incoming_message(message)
119
- id = generate_id
120
- planner = Planner.new(self, message)
121
- destinations = planner.resolve(id)
122
- components = planner.components
123
- message = { "id" => id, "components" => components }
124
- destinations.each do |destination, frequency|
125
- dispatch(message, destination)
126
- end
106
+ # Replies response to replyTo.
107
+ #
108
+ # @param [Hash] message
109
+ # The message to be replied. See {Replier#reply} for available keys.
110
+ #
111
+ # The key-value pairs in request message are used as the default
112
+ # key-value pairs. For example, if the passed message doesn't
113
+ # include `id` key, `id` key's value is used in request message.
114
+ #
115
+ # @return [void]
116
+ #
117
+ # @see Replier#reply
118
+ def reply(message)
119
+ adapted_message = @output_adapter.adapt(@message.merge(message))
120
+ return if adapted_message["replyTo"].nil?
121
+ @replier.reply(adapted_message)
127
122
  end
128
123
 
129
- def handle_internal_message(message)
124
+ def process_internal_message(message)
130
125
  id = message["id"]
131
- collector = @collectors[id]
132
- unless collector
126
+ session = @sessions[id]
127
+ if session
128
+ session.receive(message["input"], message["value"])
129
+ else
133
130
  components = message["components"]
134
131
  if components
135
132
  planner = Planner.new(self, components)
136
- collector = planner.get_collector(id)
133
+ session = planner.create_session(id, @collector)
134
+ @sessions[id] = session
137
135
  else
138
136
  #todo: take cases receiving result before its query into account
139
137
  end
138
+ session.start
140
139
  end
141
- collector.handle(message["input"], message["value"])
140
+ @sessions.delete(id) if session.done?
142
141
  end
143
142
 
144
143
  def dispatch(message, destination)
145
144
  if local?(destination)
146
- handle_internal_message(message)
145
+ process_internal_message(message)
147
146
  else
148
- post(message, "to"=>farm_path(destination), "type"=>"dispatcher")
147
+ @forwarder.forward(@message.merge("body" => message),
148
+ "type" => "dispatcher",
149
+ "to" => destination)
149
150
  end
150
151
  end
151
152
 
152
- def deliver(id, route, message, type, synchronous)
153
- if id == route
154
- post(message, "type" => type, "synchronous"=> synchronous)
155
- else
156
- envelope = @envelope.merge("body" => message, "type" => type)
157
- @farm.process(route, envelope, synchronous)
153
+ def dispatch_components(components)
154
+ id = generate_id
155
+ destinations = {}
156
+ components.each do |component|
157
+ dataset = component["dataset"]
158
+ if dataset
159
+ routes = Droonga.catalog.get_routes(dataset, component)
160
+ component["routes"] = routes
161
+ else
162
+ component["routes"] ||= [id]
163
+ end
164
+ routes = component["routes"]
165
+ routes.each do |route|
166
+ destinations[farm_path(route)] = true
167
+ end
168
+ end
169
+ dispatch_message = { "id" => id, "components" => components }
170
+ destinations.each_key do |destination|
171
+ dispatch(dispatch_message, destination)
158
172
  end
159
173
  end
160
174
 
175
+ def process_local_message(local_message)
176
+ task = local_message["task"]
177
+ partition_name = task["route"]
178
+ component = task["component"]
179
+ command = component["command"]
180
+ descendants = {}
181
+ component["descendants"].each do |name, routes|
182
+ descendants[name] = routes.collect do |route|
183
+ farm_path(route)
184
+ end
185
+ end
186
+ local_message["descendants"] = descendants
187
+ farm_message = @message.merge("body" => local_message,
188
+ "type" => command)
189
+ @farm.process(partition_name, farm_message)
190
+ end
191
+
192
+ def local?(route)
193
+ route =~ @local
194
+ end
195
+
196
+ private
161
197
  def generate_id
162
198
  id = @current_id
163
199
  @current_id = id.succ
@@ -166,38 +202,21 @@ module Droonga
166
202
 
167
203
  def farm_path(route)
168
204
  if route =~ /\A.*:\d+\/[^\.]+/
169
- $&
205
+ $MATCH
170
206
  else
171
207
  route
172
208
  end
173
209
  end
174
210
 
175
- def local?(route)
176
- route =~ @local
177
- end
178
-
179
- private
180
- def is_route?(route)
181
- route.is_a?(String) || route.is_a?(Hash)
211
+ def process_input_message(message)
212
+ adapted_message = @input_adapter.adapt(message)
213
+ @distributor.process(adapted_message["type"], adapted_message)
214
+ rescue Droonga::Pluggable::UnknownPlugin => error
215
+ raise UnknownCommand.new(error.command, message["dataset"])
182
216
  end
183
217
 
184
- def apply_input_adapters(envelope)
185
- adapted_envelope = envelope
186
- loop do
187
- input_message = InputMessage.new(adapted_envelope)
188
- command = input_message.command
189
- break unless @adapter.processable?(command)
190
- @adapter.process(command, input_message)
191
- new_command = input_message.command
192
- adapted_envelope = input_message.adapted_envelope
193
- break if command == new_command
194
- end
195
- adapted_envelope
196
- end
197
-
198
- def process_input_message(envelope)
199
- adapted_envelope = apply_input_adapters(envelope)
200
- @distributor.distribute(adapted_envelope)
218
+ def assert_valid_message
219
+ raise MissingDatasetParameter.new unless @message.include?("dataset")
201
220
  end
202
221
 
203
222
  def log_tag
@@ -206,65 +225,13 @@ module Droonga
206
225
 
207
226
  class Planner
208
227
  attr_reader :components
209
- class UndefinedInputError < StandardError
210
- attr_reader :input
211
- def initialize(input)
212
- @input = input
213
- super("undefined input assigned: <#{input}>")
214
- end
215
- end
216
228
 
217
- class CyclicComponentsError < StandardError
218
- attr_reader :components
219
- def initialize(components)
220
- @components = components
221
- super("cyclic components found: <#{components}>")
222
- end
223
- end
224
-
225
- include TSort
226
229
  def initialize(dispatcher, components)
227
230
  @dispatcher = dispatcher
228
231
  @components = components
229
232
  end
230
233
 
231
- def resolve(id)
232
- @dependency = {}
233
- @components.each do |component|
234
- @dependency[component] = component["inputs"]
235
- next unless component["outputs"]
236
- component["outputs"].each do |output|
237
- @dependency[output] = [component]
238
- end
239
- end
240
- @components = []
241
- each_strongly_connected_component do |cs|
242
- raise CyclicComponentsError.new(cs) if cs.size > 1
243
- @components.concat(cs) unless cs.first.is_a? String
244
- end
245
- resolve_routes(id)
246
- end
247
-
248
- def resolve_routes(id)
249
- local = [id]
250
- destinations = Hash.new(0)
251
- @components.each do |component|
252
- dataset = component["dataset"]
253
- routes =
254
- if dataset
255
- Droonga.catalog.get_routes(dataset, component)
256
- else
257
- local
258
- end
259
- routes.each do |route|
260
- destinations[@dispatcher.farm_path(route)] += 1
261
- end
262
- component["routes"] = routes
263
- end
264
- return destinations
265
- end
266
-
267
- def get_collector(id)
234
+ def create_session(id, collector)
268
235
  resolve_descendants
269
236
  tasks = []
270
237
  inputs = {}
@@ -284,9 +251,7 @@ module Droonga
284
251
  end
285
252
  end
286
253
  end
287
- collector = Collector.new(id, @dispatcher, @components, tasks, inputs)
288
- @dispatcher.collectors[id] = collector
289
- return collector
254
+ Session.new(id, @dispatcher, collector, tasks, inputs)
290
255
  end
291
256
 
292
257
  def resolve_descendants
@@ -300,35 +265,15 @@ module Droonga
300
265
  component["n_of_expects"] = 0
301
266
  end
302
267
  @components.each do |component|
303
- descendants = get_descendants(component)
304
- component["descendants"] = descendants
305
- descendants.each do |key, indices|
306
- indices.each do |index|
268
+ descendants = {}
269
+ (component["outputs"] || []).each do |output|
270
+ descendants[output] = []
271
+ @descendants[output].each do |index|
307
272
  @components[index]["n_of_expects"] += component["routes"].size
273
+ descendants[output].concat(@components[index]["routes"])
308
274
  end
309
275
  end
310
- end
311
- end
312
-
313
- def get_descendants(component)
314
- return {} unless component["outputs"]
315
- descendants = {}
316
- component["outputs"].each do |output|
317
- descendants[output] = @descendants[output]
318
- end
319
- descendants
320
- end
321
-
322
- def tsort_each_node(&block)
323
- @dependency.each_key(&block)
324
- end
325
-
326
- def tsort_each_child(node, &block)
327
- if node.is_a? String and @dependency[node].nil?
328
- raise UndefinedInputError.new(node)
329
- end
330
- if @dependency[node]
331
- @dependency[node].each(&block)
276
+ component["descendants"] = descendants
332
277
  end
333
278
  end
334
279
  end