droonga-engine 1.0.4 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -2
  3. data/Gemfile +1 -1
  4. data/LICENSE.txt +1 -1
  5. data/Rakefile +1 -1
  6. data/benchmark/benchmark.rb +1 -1
  7. data/benchmark/utils.rb +1 -1
  8. data/benchmark/watch/benchmark-notify.rb +1 -1
  9. data/benchmark/watch/benchmark-publish.rb +1 -1
  10. data/benchmark/watch/benchmark-scan.rb +1 -1
  11. data/bin/droonga-engine +1 -1
  12. data/bin/droonga-engine-absorb-data +48 -8
  13. data/bin/droonga-engine-catalog-generate +1 -1
  14. data/bin/droonga-engine-catalog-modify +1 -1
  15. data/bin/droonga-engine-data-publisher +66 -0
  16. data/bin/droonga-engine-join +72 -17
  17. data/bin/droonga-engine-serf-event-handler +1 -1
  18. data/bin/droonga-engine-service +1 -1
  19. data/bin/droonga-engine-unjoin +11 -4
  20. data/bin/droonga-engine-worker +20 -0
  21. data/doc/text/news.md +8 -0
  22. data/droonga-engine.gemspec +3 -3
  23. data/lib/droonga/adapter.rb +1 -1
  24. data/lib/droonga/adapter_runner.rb +1 -1
  25. data/lib/droonga/address.rb +69 -0
  26. data/lib/droonga/buffered_tcp_socket.rb +44 -22
  27. data/lib/droonga/catalog/base.rb +1 -1
  28. data/lib/droonga/catalog/collection_volume.rb +1 -1
  29. data/lib/droonga/catalog/dataset.rb +8 -8
  30. data/lib/droonga/catalog/errors.rb +1 -1
  31. data/lib/droonga/catalog/schema.rb +1 -1
  32. data/lib/droonga/catalog/single_volume.rb +6 -8
  33. data/lib/droonga/catalog/slice.rb +1 -1
  34. data/lib/droonga/catalog/version1.rb +2 -2
  35. data/lib/droonga/catalog/version2.rb +6 -6
  36. data/lib/droonga/catalog/version2_validator.rb +1 -1
  37. data/lib/droonga/catalog/volume.rb +1 -1
  38. data/lib/droonga/catalog/volume_collection.rb +2 -2
  39. data/lib/droonga/catalog_generator.rb +49 -53
  40. data/lib/droonga/catalog_loader.rb +1 -1
  41. data/lib/droonga/collector.rb +1 -1
  42. data/lib/droonga/collector_message.rb +1 -1
  43. data/lib/droonga/collector_runner.rb +1 -1
  44. data/lib/droonga/collectors/and.rb +1 -1
  45. data/lib/droonga/collectors/or.rb +1 -1
  46. data/lib/droonga/collectors/sum.rb +1 -1
  47. data/lib/droonga/collectors.rb +1 -1
  48. data/lib/droonga/command/droonga_engine.rb +103 -55
  49. data/lib/droonga/command/droonga_engine_service.rb +22 -67
  50. data/lib/droonga/command/droonga_engine_worker.rb +232 -0
  51. data/lib/droonga/command/serf_event_handler.rb +126 -46
  52. data/lib/droonga/data_absorber.rb +32 -14
  53. data/lib/droonga/dispatcher.rb +15 -11
  54. data/lib/droonga/distributed_command_planner.rb +1 -1
  55. data/lib/droonga/distributor.rb +1 -1
  56. data/lib/droonga/engine/version.rb +2 -2
  57. data/lib/droonga/engine.rb +8 -3
  58. data/lib/droonga/engine_state.rb +15 -6
  59. data/lib/droonga/error.rb +1 -1
  60. data/lib/droonga/error_messages.rb +1 -1
  61. data/lib/droonga/event_loop.rb +1 -1
  62. data/lib/droonga/farm.rb +9 -1
  63. data/lib/droonga/file_observer.rb +1 -1
  64. data/lib/droonga/fluent_message_receiver.rb +11 -5
  65. data/lib/droonga/fluent_message_sender.rb +14 -17
  66. data/lib/droonga/forwarder.rb +23 -13
  67. data/lib/droonga/handler.rb +1 -1
  68. data/lib/droonga/handler_message.rb +1 -1
  69. data/lib/droonga/handler_messenger.rb +2 -2
  70. data/lib/droonga/handler_runner.rb +2 -2
  71. data/lib/droonga/input_message.rb +1 -1
  72. data/lib/droonga/internal_fluent_message_receiver.rb +3 -2
  73. data/lib/droonga/job_protocol.rb +1 -1
  74. data/lib/droonga/job_pusher.rb +1 -1
  75. data/lib/droonga/job_receiver.rb +1 -1
  76. data/lib/droonga/line_buffer.rb +1 -1
  77. data/lib/droonga/live_nodes_list_loader.rb +1 -1
  78. data/lib/droonga/loggable.rb +1 -1
  79. data/lib/droonga/logger.rb +3 -3
  80. data/lib/droonga/message_matcher.rb +1 -1
  81. data/lib/droonga/output_message.rb +1 -1
  82. data/lib/droonga/path.rb +5 -1
  83. data/lib/droonga/planner.rb +1 -1
  84. data/lib/droonga/pluggable.rb +1 -1
  85. data/lib/droonga/plugin/metadata/adapter_input_message.rb +1 -1
  86. data/lib/droonga/plugin/metadata/adapter_output_message.rb +1 -1
  87. data/lib/droonga/plugin/metadata/collector_message.rb +1 -1
  88. data/lib/droonga/plugin/metadata/handler_action.rb +1 -1
  89. data/lib/droonga/plugin/metadata/input_message.rb +1 -1
  90. data/lib/droonga/plugin.rb +2 -1
  91. data/lib/droonga/plugin_loader.rb +1 -1
  92. data/lib/droonga/plugin_registry.rb +3 -1
  93. data/lib/droonga/plugins/basic.rb +1 -1
  94. data/lib/droonga/plugins/crud.rb +1 -1
  95. data/lib/droonga/plugins/dump.rb +13 -2
  96. data/lib/droonga/plugins/error.rb +1 -1
  97. data/lib/droonga/plugins/groonga/column_create.rb +1 -1
  98. data/lib/droonga/plugins/groonga/column_list.rb +1 -1
  99. data/lib/droonga/plugins/groonga/column_remove.rb +1 -1
  100. data/lib/droonga/plugins/groonga/column_rename.rb +1 -1
  101. data/lib/droonga/plugins/groonga/delete.rb +1 -1
  102. data/lib/droonga/plugins/groonga/generic_command.rb +1 -1
  103. data/lib/droonga/plugins/groonga/generic_response.rb +1 -1
  104. data/lib/droonga/plugins/groonga/select.rb +1 -1
  105. data/lib/droonga/plugins/groonga/table_create.rb +1 -1
  106. data/lib/droonga/plugins/groonga/table_list.rb +1 -1
  107. data/lib/droonga/plugins/groonga/table_remove.rb +1 -1
  108. data/lib/droonga/plugins/groonga.rb +1 -1
  109. data/lib/droonga/plugins/search/distributed_search_planner.rb +1 -1
  110. data/lib/droonga/plugins/search.rb +1 -1
  111. data/lib/droonga/plugins/system.rb +1 -1
  112. data/lib/droonga/plugins/watch.rb +1 -1
  113. data/lib/droonga/{service_control_protocol.rb → process_control_protocol.rb} +2 -2
  114. data/lib/droonga/process_supervisor.rb +91 -0
  115. data/lib/droonga/processor.rb +1 -1
  116. data/lib/droonga/reducer.rb +1 -1
  117. data/lib/droonga/replier.rb +2 -2
  118. data/lib/droonga/safe_file_writer.rb +1 -1
  119. data/lib/droonga/schema_applier.rb +1 -1
  120. data/lib/droonga/searcher/mecab_filter.rb +1 -1
  121. data/lib/droonga/searcher.rb +31 -19
  122. data/lib/droonga/serf.rb +81 -14
  123. data/lib/droonga/serf_downloader.rb +2 -2
  124. data/lib/droonga/session.rb +1 -1
  125. data/lib/droonga/single_step.rb +1 -1
  126. data/lib/droonga/single_step_definition.rb +1 -1
  127. data/lib/droonga/slice.rb +30 -28
  128. data/lib/droonga/status_code.rb +1 -1
  129. data/lib/droonga/step_runner.rb +1 -1
  130. data/lib/droonga/supervisor.rb +170 -0
  131. data/lib/droonga/sweeper.rb +1 -1
  132. data/lib/droonga/test/stub_handler.rb +1 -1
  133. data/lib/droonga/test/stub_handler_message.rb +1 -1
  134. data/lib/droonga/test/stub_handler_messenger.rb +1 -1
  135. data/lib/droonga/test/stub_planner.rb +1 -1
  136. data/lib/droonga/test.rb +1 -1
  137. data/lib/droonga/watch_schema.rb +2 -2
  138. data/lib/droonga/watcher.rb +1 -1
  139. data/lib/droonga/worker_process_agent.rb +111 -0
  140. data/sample/cluster/Rakefile +150 -0
  141. data/test/command/config/default/catalog.json +1 -34
  142. data/test/command/config/version1/catalog.json +3 -12
  143. data/test/command/run-test.rb +1 -1
  144. data/test/command/suite/dump/column/index.expected +19 -82
  145. data/test/command/suite/dump/column/scalar.expected +5 -36
  146. data/test/command/suite/dump/column/vector.expected +5 -39
  147. data/test/command/suite/dump/record/vector/reference.expected +24 -93
  148. data/test/command/suite/dump/table/array.expected +0 -19
  149. data/test/command/suite/dump/table/double_array_trie.expected +0 -20
  150. data/test/command/suite/dump/table/hash.expected +0 -20
  151. data/test/command/suite/dump/table/patricia_trie.expected +0 -20
  152. data/test/command/suite/search/condition/query/nonexistent_column.expected +0 -11
  153. data/test/command/suite/search/condition/query/syntax_error.expected +0 -11
  154. data/test/command/suite/search/error/unknown-source.expected +0 -12
  155. data/test/command/suite/search/output/attributes/invalid.expected +0 -10
  156. data/test/command/suite/search/output/attributes/reference_vector.catalog.json +27 -0
  157. data/test/command/suite/search/output/attributes/reference_vector.expected +30 -0
  158. data/test/command/suite/search/output/attributes/reference_vector.test +32 -0
  159. data/test/command/suite/watch/subscribe.catalog.json +23 -0
  160. data/test/command/suite/watch/subscribe.test +2 -0
  161. data/test/command/suite/watch/unsubscribe.catalog.json +23 -0
  162. data/test/command/suite/watch/unsubscribe.test +2 -0
  163. data/test/performance/run-test.rb +1 -1
  164. data/test/unit/catalog/test_collection_volume.rb +1 -1
  165. data/test/unit/catalog/test_dataset.rb +1 -1
  166. data/test/unit/catalog/test_schema.rb +1 -1
  167. data/test/unit/catalog/test_single_volume.rb +27 -19
  168. data/test/unit/catalog/test_slice.rb +2 -2
  169. data/test/unit/catalog/test_version1.rb +1 -1
  170. data/test/unit/catalog/test_version2.rb +1 -1
  171. data/test/unit/catalog/test_version2_validator.rb +1 -1
  172. data/test/unit/catalog/test_volume_collection.rb +1 -1
  173. data/test/unit/helper/distributed_search_planner_helper.rb +1 -1
  174. data/test/unit/helper/fixture.rb +1 -1
  175. data/test/unit/helper/plugin_helper.rb +1 -1
  176. data/test/unit/helper/sandbox.rb +1 -1
  177. data/test/unit/helper/stub_worker.rb +1 -1
  178. data/test/unit/helper/watch_helper.rb +1 -1
  179. data/test/unit/helper.rb +1 -1
  180. data/test/unit/plugins/crud/test_add.rb +1 -1
  181. data/test/unit/plugins/groonga/select/test_adapter_input.rb +1 -1
  182. data/test/unit/plugins/groonga/select/test_adapter_output.rb +1 -1
  183. data/test/unit/plugins/groonga/test_column_create.rb +1 -1
  184. data/test/unit/plugins/groonga/test_column_list.rb +1 -1
  185. data/test/unit/plugins/groonga/test_column_remove.rb +1 -1
  186. data/test/unit/plugins/groonga/test_column_rename.rb +1 -1
  187. data/test/unit/plugins/groonga/test_delete.rb +1 -1
  188. data/test/unit/plugins/groonga/test_table_create.rb +1 -1
  189. data/test/unit/plugins/groonga/test_table_list.rb +1 -1
  190. data/test/unit/plugins/groonga/test_table_remove.rb +1 -1
  191. data/test/unit/plugins/search/planner/test_basic.rb +1 -1
  192. data/test/unit/plugins/search/planner/test_group_by.rb +1 -1
  193. data/test/unit/plugins/search/planner/test_output.rb +1 -1
  194. data/test/unit/plugins/search/planner/test_sort_by.rb +1 -1
  195. data/test/unit/plugins/search/test_collector.rb +1 -1
  196. data/test/unit/plugins/search/test_handler.rb +1 -1
  197. data/test/unit/plugins/search/test_planner.rb +1 -1
  198. data/test/unit/plugins/system/test_status.rb +1 -1
  199. data/test/unit/plugins/test_basic.rb +1 -1
  200. data/test/unit/plugins/test_groonga.rb +1 -1
  201. data/test/unit/plugins/test_watch.rb +1 -1
  202. data/test/unit/run-test.rb +1 -1
  203. data/test/unit/test_address.rb +53 -0
  204. data/test/unit/test_catalog_generator.rb +59 -1
  205. data/test/unit/test_line_buffer.rb +1 -1
  206. data/test/unit/test_message_matcher.rb +1 -1
  207. data/test/unit/test_schema_applier.rb +1 -1
  208. data/test/unit/test_sweeper.rb +1 -1
  209. data/test/unit/test_watch_schema.rb +1 -1
  210. data/test/unit/test_watcher.rb +1 -1
  211. metadata +39 -24
  212. data/lib/droonga/server.rb +0 -45
  213. data/lib/droonga/worker.rb +0 -66
  214. data/sample/cluster/catalog.json +0 -42
  215. data/test/command/config/default/fluentd.conf +0 -11
  216. data/test/command/config/version1/fluentd.conf +0 -11
@@ -11,7 +11,7 @@
11
11
  #
12
12
  # You should have received a copy of the GNU Lesser General Public
13
13
  # License along with this library; if not, write to the Free Software
14
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
15
 
16
16
  require "json"
17
17
 
@@ -34,14 +34,22 @@ module Droonga
34
34
  @serf = ENV["SERF"] || Serf.path
35
35
  @serf_rpc_address = ENV["SERF_RPC_ADDRESS"] || "127.0.0.1:7373"
36
36
  @serf_name = ENV["SERF_SELF_NAME"]
37
+ @response = {
38
+ "log" => []
39
+ }
37
40
  end
38
41
 
39
42
  def run
40
43
  parse_event
41
- return true unless event_for_me?
44
+ unless event_for_me?
45
+ log(" => ignoring event not for me")
46
+ output_response
47
+ return true
48
+ end
42
49
 
43
50
  process_event
44
51
  output_live_nodes
52
+ output_response
45
53
  true
46
54
  end
47
55
 
@@ -53,11 +61,13 @@ module Droonga
53
61
  when "user"
54
62
  @event_sub_name = ENV["SERF_USER_EVENT"]
55
63
  @payload = JSON.parse($stdin.gets)
56
- puts "event sub name = #{@event_sub_name}"
64
+ log("event sub name = #{@event_sub_name}")
57
65
  when "query"
58
66
  @event_sub_name = ENV["SERF_QUERY_NAME"]
59
67
  @payload = JSON.parse($stdin.gets)
60
- puts "event sub name = #{@event_sub_name}"
68
+ log("event sub name = #{@event_sub_name}")
69
+ when "member-join", "member-leave", "member-update", "member-reap"
70
+ output_live_nodes
61
71
  end
62
72
  end
63
73
 
@@ -72,6 +82,8 @@ module Droonga
72
82
  case @event_sub_name
73
83
  when "change_role"
74
84
  save_status(:role, @payload["role"])
85
+ when "report_status"
86
+ report_status
75
87
  when "join"
76
88
  join
77
89
  when "set_replicas"
@@ -82,9 +94,17 @@ module Droonga
82
94
  remove_replicas
83
95
  when "absorb_data"
84
96
  absorb_data
97
+ when "publish_catalog"
98
+ publish_catalog
99
+ when "unpublish_catalog"
100
+ unpublish_catalog
85
101
  end
86
102
  end
87
103
 
104
+ def output_response
105
+ puts JSON.generate(@response)
106
+ end
107
+
88
108
  def host
89
109
  @serf_name.split(":").first
90
110
  end
@@ -96,9 +116,13 @@ module Droonga
96
116
  hosts
97
117
  end
98
118
 
119
+ def report_status
120
+ @response["value"] = status(@payload["key"].to_sym)
121
+ end
122
+
99
123
  def join
100
124
  type = @payload["type"]
101
- puts "type = #{type}"
125
+ log("type = #{type}")
102
126
  case type
103
127
  when "replica"
104
128
  join_as_replica
@@ -106,55 +130,106 @@ module Droonga
106
130
  end
107
131
 
108
132
  def join_as_replica
109
- source = @payload["source"]
110
- return unless source
133
+ source_node = @payload["source"]
134
+ return unless source_node
111
135
 
112
- puts "source = #{source}"
136
+ log("source_node = #{source_node}")
113
137
 
114
- generator = create_current_catalog_generator
115
- dataset = generator.dataset_for_host(source) ||
138
+ source_host = source_node.split(":").first
139
+
140
+ # fetch_port = @payload["fetch_port"]
141
+ # catalog = fetch_catalog(source_node, fetch_port)
142
+ catalog = JSON.parse(Path.catalog.read) #XXX workaround until "fetch" become available
143
+
144
+ generator = create_current_catalog_generator(catalog)
145
+ dataset = generator.dataset_for_host(source_host) ||
116
146
  generator.dataset_for_host(host)
117
147
  return unless dataset
118
148
 
149
+ # restart self with the fetched catalog.
150
+ SafeFileWriter.write(Path.catalog, JSON.pretty_generate(catalog))
151
+
119
152
  dataset_name = dataset.name
120
153
  tag = dataset.replicas.tag
121
154
  port = dataset.replicas.port
122
155
  other_hosts = dataset.replicas.hosts
123
156
 
124
- puts "dataset = #{dataset_name}"
125
- puts "port = #{port}"
126
- puts "tag = #{tag}"
157
+ log("dataset = #{dataset_name}")
158
+ log("port = #{port}")
159
+ log("tag = #{tag}")
127
160
 
128
161
  if @payload["copy"]
129
- puts "starting to copy data from #{source}"
162
+ log("starting to copy data from #{source_host}")
130
163
 
131
164
  modify_catalog do |modifier|
132
165
  modifier.datasets[dataset_name].replicas.hosts = [host]
133
166
  end
134
- sleep(1) # wait for restart
167
+ sleep(5) #TODO: wait for restart. this should be done more safely, to avoid starting of absorbing with old catalog.json.
135
168
 
169
+ save_status(:absorbing, true)
136
170
  DataAbsorber.absorb(:dataset => dataset_name,
137
- :source_host => source,
171
+ :source_host => source_host,
138
172
  :destination_host => host,
139
173
  :port => port,
140
174
  :tag => tag)
175
+ delete_status(:absorbing)
141
176
  sleep(1)
142
177
  end
143
178
 
144
- puts "joining to the cluster: update myself"
179
+ log("joining to the cluster: update myself")
145
180
 
146
181
  modify_catalog do |modifier|
147
182
  modifier.datasets[dataset_name].replicas.hosts += other_hosts
148
183
  modifier.datasets[dataset_name].replicas.hosts.uniq!
149
184
  end
150
- sleep(1) # wait for restart
185
+ end
186
+
187
+ def fetch_catalog(source_node, port)
188
+ source_host = source_node.split(":").first
189
+
190
+ url = "http://#{source_host}:#{port}"
191
+ connection = Faraday.new(url) do |builder|
192
+ builder.response(:follow_redirects)
193
+ builder.adapter(Faraday.default_adapter)
194
+ end
195
+ response = connection.get("/catalog.json")
196
+ catalog = response.body
197
+
198
+ JSON.parse(catalog)
199
+ end
200
+
201
+ def publish_catalog
202
+ port = @payload["port"]
203
+ return unless port
204
+
205
+ env = {}
206
+ publisher_command_line = [
207
+ "droonga-engine-data-publisher",
208
+ "--base-dir", Path.base.to_s,
209
+ "--port", port.to_s,
210
+ "--published-file", Path.catalog.to_s
211
+ ]
212
+ pid = spawn(env, *publisher_command_line)
213
+ Process.detach(pid)
214
+ sleep(1) # wait until the directory is published
215
+
216
+ published_dir = Path.published(port)
217
+ pid_file = published_dir + ".pid"
218
+
219
+ File.open(pid_file.to_s, "w") do |file|
220
+ file.puts(pid)
221
+ end
222
+ end
151
223
 
152
- puts "joining to the cluster: update others"
224
+ def unpublish_catalog
225
+ port = @payload["port"]
226
+ return unless port
153
227
 
154
- source_node = "#{source}:#{port}/#{tag}"
155
- Serf.send_query(source_node, "add_replicas",
156
- "dataset" => dataset_name,
157
- "hosts" => [host])
228
+ published_dir = Path.published(port)
229
+ pid_file = published_dir + ".pid"
230
+ pid = pid_file.read.to_i
231
+
232
+ Process.kill("INT", pid)
158
233
  end
159
234
 
160
235
  def set_replicas
@@ -164,7 +239,7 @@ module Droonga
164
239
  hosts = given_hosts
165
240
  return unless hosts
166
241
 
167
- puts "new replicas: #{hosts.join(",")}"
242
+ log("new replicas: #{hosts.join(",")}")
168
243
 
169
244
  modify_catalog do |modifier|
170
245
  modifier.datasets[dataset].replicas.hosts = hosts
@@ -181,7 +256,7 @@ module Droonga
181
256
  hosts -= [host]
182
257
  return if hosts.empty?
183
258
 
184
- puts "adding replicas: #{hosts.join(",")}"
259
+ log("adding replicas: #{hosts.join(",")}")
185
260
 
186
261
  modify_catalog do |modifier|
187
262
  modifier.datasets[dataset].replicas.hosts += hosts
@@ -196,7 +271,7 @@ module Droonga
196
271
  hosts = given_hosts
197
272
  return unless hosts
198
273
 
199
- puts "removing replicas: #{hosts.join(",")}"
274
+ log("removing replicas: #{hosts.join(",")}")
200
275
 
201
276
  modify_catalog do |modifier|
202
277
  modifier.datasets[dataset].replicas.hosts -= hosts
@@ -209,19 +284,17 @@ module Droonga
209
284
  SafeFileWriter.write(Path.catalog, JSON.pretty_generate(generator.generate))
210
285
  end
211
286
 
212
- def create_current_catalog_generator
213
- current_catalog = JSON.parse(Path.catalog.read)
287
+ def create_current_catalog_generator(current_catalog=nil)
288
+ current_catalog ||= JSON.parse(Path.catalog.read)
214
289
  generator = CatalogGenerator.new
215
290
  generator.load(current_catalog)
216
291
  end
217
292
 
218
293
  def absorb_data
219
- return unless event_for_me?
220
-
221
294
  source = @payload["source"]
222
295
  return unless source
223
296
 
224
- puts "start to absorb data from #{source}"
297
+ log("start to absorb data from #{source}")
225
298
 
226
299
  dataset_name = @payload["dataset"]
227
300
  port = @payload["port"]
@@ -240,29 +313,22 @@ module Droonga
240
313
  tag = dataset.replicas.tag
241
314
  end
242
315
 
243
- puts "dataset = #{dataset_name}"
244
- puts "port = #{port}"
245
- puts "tag = #{tag}"
316
+ log("dataset = #{dataset_name}")
317
+ log("port = #{port}")
318
+ log("tag = #{tag}")
246
319
 
320
+ save_status(:absorbing, true)
247
321
  DataAbsorber.absorb(:dataset => dataset_name,
248
322
  :source_host => source,
249
323
  :destination_host => host,
250
324
  :port => port,
251
- :tag => tag)
325
+ :tag => tag,
326
+ :client => "droonga-send")
327
+ delete_status(:absorbing)
252
328
  end
253
329
 
254
330
  def live_nodes
255
- nodes = {}
256
- members = `#{@serf} members -rpc-addr #{@serf_rpc_address}`
257
- members.each_line do |member|
258
- name, address, status, = member.strip.split(/\s+/)
259
- if status == "alive"
260
- nodes[name] = {
261
- "serfAddress" => address,
262
- }
263
- end
264
- end
265
- nodes
331
+ Serf.live_nodes(@serf_name)
266
332
  end
267
333
 
268
334
  def output_live_nodes
@@ -272,11 +338,25 @@ module Droonga
272
338
  SafeFileWriter.write(path, file_contents)
273
339
  end
274
340
 
341
+ def status(key)
342
+ Serf.status(key)
343
+ end
344
+
275
345
  def save_status(key, value)
276
346
  status = Serf.load_status
277
347
  status[key] = value
278
348
  SafeFileWriter.write(Serf.status_file, JSON.pretty_generate(status))
279
349
  end
350
+
351
+ def delete_status(key)
352
+ status = Serf.load_status
353
+ status.delete(key)
354
+ SafeFileWriter.write(Serf.status_file, JSON.pretty_generate(status))
355
+ end
356
+
357
+ def log(message)
358
+ @response["log"] << message
359
+ end
280
360
  end
281
361
  end
282
362
  end
@@ -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 "open3"
17
17
 
@@ -28,25 +28,43 @@ module Droonga
28
28
  drndump_options += ["--receiver-host", params[:destination_host]]
29
29
  drndump_options += ["--receiver-port", params[:receiver_port].to_s] if params[:receiver_port]
30
30
 
31
+ #TODO: We should use droonga-send instead of droonga-request,
32
+ # because droonga-request is too slow.
33
+ # However, to do it, we have to implement an API to know
34
+ # that all messages sent by droonga-send are completely
35
+ # processed.
31
36
  client = params[:client] || "droonga-request"
32
37
  client_options = []
33
- client_options += ["--host", params[:destination_host]]
34
- client_options += ["--port", params[:port].to_s] if params[:port]
35
- client_options += ["--tag", params[:tag]] if params[:tag]
36
- client_options += ["--receiver-host", params[:destination_host]]
37
- client_options += ["--receiver-port", params[:receiver_port].to_s] if params[:receiver_port]
38
+ if client.include?("droonga-request")
39
+ client_options += ["--host", params[:destination_host]]
40
+ client_options += ["--port", params[:port].to_s] if params[:port]
41
+ client_options += ["--tag", params[:tag]] if params[:tag]
42
+ client_options += ["--receiver-host", params[:destination_host]]
43
+ client_options += ["--receiver-port", params[:receiver_port].to_s] if params[:receiver_port]
44
+ elsif client.include?("droonga-send")
45
+ #XXX Don't use round-robin with multiple endpoints
46
+ # even if there are too much data.
47
+ # Schema and indexes must be sent to just one endpoint
48
+ # to keep their order, but currently there is no way to
49
+ # extract only schema and indexes via drndump.
50
+ # So, we always use just one endpoint for now,
51
+ # even if there are too much data.
52
+ server = "droonga:#{params[:destination_host]}"
53
+ server = "#{server}:#{params[:port].to_s}" if params[:port]
54
+ server = "#{server}/#{params[:tag].to_s}" if params[:tag]
55
+ client_options += ["--server", server]
56
+ else
57
+ raise ArgumentError.new("Unknwon type client: #{client}")
58
+ end
38
59
 
39
60
  drndump_command_line = [drndump] + drndump_options
40
61
  client_command_line = [client] + client_options
41
62
 
42
- Open3.popen3(*drndump_command_line) do |dump_in, dump_out, dump_error, dump_thread|
43
- dump_in.close
44
- Open3.popen3(*client_command_line) do |client_in, client_out, client_error, client_thread|
45
- client_out.close
46
- dump_out.each do |dump|
47
- yield dump if block_given?
48
- client_in.puts(dump)
49
- end
63
+ env = {}
64
+ Open3.pipeline_r([env, *drndump_command_line],
65
+ [env, *client_command_line]) do |last_stdout, thread|
66
+ last_stdout.each do |output|
67
+ yield output if block_given?
50
68
  end
51
69
  end
52
70
  end
@@ -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 "tsort"
17
17
 
@@ -63,6 +63,9 @@ module Droonga
63
63
  end
64
64
 
65
65
  def start
66
+ @farm.on_ready = lambda do
67
+ @engine_state.on_ready
68
+ end
66
69
  @farm.start
67
70
  end
68
71
 
@@ -143,10 +146,10 @@ module Droonga
143
146
  else
144
147
  steps = message["steps"]
145
148
  if steps
146
- session_planner = SessionPlanner.new(self, steps)
149
+ session_planner = SessionPlanner.new(@engine_state, steps)
147
150
  dataset = message["dataset"] || @message["dataset"]
148
151
  collector_runner = @collector_runners[dataset]
149
- session = session_planner.create_session(id, collector_runner)
152
+ session = session_planner.create_session(id, self, collector_runner)
150
153
  @engine_state.register_session(id, session)
151
154
  else
152
155
  logger.error("no steps error: id=#{id}, message=#{message}")
@@ -175,7 +178,7 @@ module Droonga
175
178
  steps.each do |step|
176
179
  dataset = @catalog.dataset(step["dataset"])
177
180
  if dataset
178
- routes = dataset.get_routes(step, @engine_state.live_nodes)
181
+ routes = dataset.compute_routes(step, @engine_state.live_nodes)
179
182
  step["routes"] = routes
180
183
  else
181
184
  step["routes"] ||= [id]
@@ -279,24 +282,24 @@ module Droonga
279
282
  end
280
283
 
281
284
  def log_tag
282
- "[#{Process.ppid}][#{Process.pid}] dispatcher"
285
+ "dispatcher"
283
286
  end
284
287
 
285
288
  class SessionPlanner
286
289
  attr_reader :steps
287
290
 
288
- def initialize(dispatcher, steps)
289
- @dispatcher = dispatcher
291
+ def initialize(engine_state, steps)
292
+ @engine_state = engine_state
290
293
  @steps = steps
291
294
  end
292
295
 
293
- def create_session(id, collector_runner)
296
+ def create_session(id, dispatcher, collector_runner)
294
297
  resolve_descendants
295
298
  tasks = []
296
299
  inputs = {}
297
300
  @steps.each do |step|
298
301
  step["routes"].each do |route|
299
- next unless @dispatcher.local?(route)
302
+ next unless @engine_state.local_route?(route)
300
303
  task = {
301
304
  "route" => route,
302
305
  "step" => step,
@@ -310,7 +313,7 @@ module Droonga
310
313
  end
311
314
  end
312
315
  end
313
- Session.new(id, @dispatcher, collector_runner, tasks, inputs)
316
+ Session.new(id, dispatcher, collector_runner, tasks, inputs)
314
317
  end
315
318
 
316
319
  def resolve_descendants
@@ -328,7 +331,8 @@ module Droonga
328
331
  (step["outputs"] || []).each do |output|
329
332
  descendants[output] = []
330
333
  @descendants[output].each do |index|
331
- @steps[index]["n_of_expects"] += step["routes"].size
334
+ live_routes = @engine_state.remove_dead_routes(step["routes"])
335
+ @steps[index]["n_of_expects"] += live_routes.size
332
336
  descendants[output].concat(@steps[index]["routes"])
333
337
  end
334
338
  end
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # You should have received a copy of the GNU Lesser General Public
15
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
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
  module Droonga
19
19
  class DistributedCommandPlanner
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # You should have received a copy of the GNU Lesser General Public
15
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
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
  require "tsort"
19
19
 
@@ -11,10 +11,10 @@
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
  module Droonga
17
17
  class Engine
18
- VERSION = "1.0.4"
18
+ VERSION = "1.0.5"
19
19
  end
20
20
  end
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # You should have received a copy of the GNU Lesser General Public
15
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
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
  require "time"
19
19
  require "fileutils"
@@ -29,6 +29,7 @@ module Droonga
29
29
  class Engine
30
30
  include Loggable
31
31
 
32
+ attr_writer :on_ready
32
33
  def initialize(loop, name, internal_name)
33
34
  @state = EngineState.new(loop, name, internal_name)
34
35
  @catalog = load_catalog
@@ -38,10 +39,14 @@ module Droonga
38
39
  @live_nodes_list_observer.on_change = lambda do
39
40
  @state.live_nodes = load_live_nodes
40
41
  end
42
+ @on_ready = nil
41
43
  end
42
44
 
43
45
  def start
44
46
  logger.trace("start: start")
47
+ @state.on_ready = lambda do
48
+ @on_ready.call if @on_ready
49
+ end
45
50
  @state.start
46
51
  @live_nodes_list_observer.start
47
52
  @dispatcher.start
@@ -87,7 +92,7 @@ module Droonga
87
92
  loader = CatalogLoader.new(catalog_path.to_s)
88
93
  catalog = loader.load
89
94
  logger.info("catalog loaded",
90
- :path => catalog_path,
95
+ :path => catalog_path.to_s,
91
96
  :mtime => catalog_path.mtime)
92
97
  catalog
93
98
  end
@@ -97,7 +102,7 @@ module Droonga
97
102
  loader = LiveNodesListLoader.new(path)
98
103
  live_nodes = loader.load
99
104
  logger.info("live-nodes loaded",
100
- :path => path,
105
+ :path => path.to_s,
101
106
  :mtime => path.mtime)
102
107
  live_nodes
103
108
  end
@@ -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 "English"
17
17
 
@@ -31,21 +31,22 @@ module Droonga
31
31
  attr_reader :internal_name
32
32
  attr_reader :forwarder
33
33
  attr_reader :replier
34
+ attr_writer :on_ready
34
35
  attr_accessor :on_finish
35
36
  attr_accessor :catalog
36
- attr_writer :dead_nodes
37
37
  def initialize(loop, name, internal_name)
38
38
  @loop = loop
39
39
  @name = name
40
40
  @internal_name = internal_name
41
41
  @sessions = {}
42
42
  @current_id = 0
43
- @forwarder = Forwarder.new(@loop)
44
- @forwarder.resume
43
+ @forwarder = Forwarder.new(@loop, :buffering => true)
45
44
  @replier = Replier.new(@forwarder)
45
+ @on_ready = nil
46
46
  @on_finish = nil
47
47
  @catalog = nil
48
48
  @live_nodes = nil
49
+ @dead_nodes = []
49
50
  end
50
51
 
51
52
  def start
@@ -111,13 +112,21 @@ module Droonga
111
112
  end
112
113
 
113
114
  def live_nodes=(nodes)
115
+ old_live_nodes = @live_nodes
114
116
  @live_nodes = nodes
115
117
  @dead_nodes = all_nodes - @live_nodes
118
+ @forwarder.resume if old_live_nodes != @live_nodes
116
119
  @live_nodes
117
120
  end
118
121
 
119
- def dead_nodes
120
- @dead_nodes || []
122
+ def remove_dead_routes(routes)
123
+ routes.reject do |route|
124
+ @dead_nodes.include?(farm_path(route))
125
+ end
126
+ end
127
+
128
+ def on_ready
129
+ @on_ready.call if @on_ready
121
130
  end
122
131
 
123
132
  private
data/lib/droonga/error.rb CHANGED
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # You should have received a copy of the GNU Lesser General Public
15
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
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
  module Droonga
19
19
  class Error < StandardError
@@ -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 "droonga/error"
17
17
  require "droonga/status_code"
@@ -13,7 +13,7 @@
13
13
  #
14
14
  # You should have received a copy of the GNU Lesser General Public
15
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
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
  require "coolio"
19
19