droonga-engine 1.0.9 → 1.1.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/benchmark/timer-watcher/benchmark.rb +44 -0
  4. data/bin/droonga-engine-absorb-data +246 -187
  5. data/bin/droonga-engine-catalog-generate +12 -12
  6. data/bin/droonga-engine-catalog-modify +4 -4
  7. data/bin/droonga-engine-join +352 -171
  8. data/bin/droonga-engine-set-role +54 -0
  9. data/bin/droonga-engine-unjoin +107 -112
  10. data/droonga-engine.gemspec +3 -3
  11. data/install.sh +55 -36
  12. data/install/centos/functions.sh +2 -2
  13. data/install/debian/functions.sh +2 -2
  14. data/lib/droonga/address.rb +26 -24
  15. data/lib/droonga/buffered_tcp_socket.rb +65 -10
  16. data/lib/droonga/catalog/base.rb +9 -6
  17. data/lib/droonga/catalog/dataset.rb +17 -41
  18. data/lib/droonga/catalog/fetcher.rb +64 -0
  19. data/lib/droonga/catalog/generator.rb +245 -0
  20. data/lib/droonga/catalog/loader.rb +66 -0
  21. data/lib/droonga/{catalog_modifier.rb → catalog/modifier.rb} +11 -18
  22. data/lib/droonga/catalog/replicas_volume.rb +123 -0
  23. data/lib/droonga/catalog/schema.rb +37 -37
  24. data/lib/droonga/catalog/single_volume.rb +11 -3
  25. data/lib/droonga/catalog/slice.rb +10 -6
  26. data/lib/droonga/catalog/{collection_volume.rb → slices_volume.rb} +47 -11
  27. data/lib/droonga/catalog/version1.rb +47 -19
  28. data/lib/droonga/catalog/version2.rb +11 -10
  29. data/lib/droonga/catalog/version2_validator.rb +4 -4
  30. data/lib/droonga/catalog/volume.rb +17 -5
  31. data/lib/droonga/changable.rb +25 -0
  32. data/lib/droonga/cluster.rb +237 -0
  33. data/lib/droonga/collector_runner.rb +4 -0
  34. data/lib/droonga/collectors.rb +2 -1
  35. data/lib/droonga/collectors/recursive_sum.rb +26 -0
  36. data/lib/droonga/command/droonga_engine.rb +404 -127
  37. data/lib/droonga/command/droonga_engine_service.rb +47 -11
  38. data/lib/droonga/command/droonga_engine_worker.rb +21 -1
  39. data/lib/droonga/command/remote_command_base.rb +78 -0
  40. data/lib/droonga/command/serf_event_handler.rb +29 -20
  41. data/lib/droonga/data_absorber_client.rb +222 -0
  42. data/lib/droonga/database_scanner.rb +106 -0
  43. data/lib/droonga/{live_nodes_list_loader.rb → deferrable.rb} +11 -24
  44. data/lib/droonga/differ.rb +58 -0
  45. data/lib/droonga/dispatcher.rb +155 -32
  46. data/lib/droonga/distributed_command_planner.rb +9 -11
  47. data/lib/droonga/engine.rb +83 -78
  48. data/lib/droonga/engine/version.rb +1 -1
  49. data/lib/droonga/engine_node.rb +301 -0
  50. data/lib/droonga/engine_state.rb +62 -40
  51. data/lib/droonga/farm.rb +44 -5
  52. data/lib/droonga/file_observer.rb +16 -12
  53. data/lib/droonga/fluent_message_receiver.rb +98 -29
  54. data/lib/droonga/fluent_message_sender.rb +30 -23
  55. data/lib/droonga/forward_buffer.rb +160 -0
  56. data/lib/droonga/forwarder.rb +73 -40
  57. data/lib/droonga/handler.rb +7 -6
  58. data/lib/droonga/handler_messenger.rb +15 -6
  59. data/lib/droonga/handler_runner.rb +6 -1
  60. data/lib/droonga/internal_fluent_message_receiver.rb +28 -8
  61. data/lib/droonga/job_pusher.rb +10 -7
  62. data/lib/droonga/job_receiver.rb +6 -4
  63. data/lib/droonga/logger.rb +7 -1
  64. data/lib/droonga/node_name.rb +90 -0
  65. data/lib/droonga/node_role.rb +72 -0
  66. data/lib/droonga/path.rb +34 -9
  67. data/lib/droonga/planner.rb +73 -7
  68. data/lib/droonga/plugin/async_command.rb +154 -0
  69. data/lib/droonga/plugins/catalog.rb +1 -0
  70. data/lib/droonga/plugins/crud.rb +22 -6
  71. data/lib/droonga/plugins/dump.rb +66 -135
  72. data/lib/droonga/plugins/groonga/delete.rb +13 -0
  73. data/lib/droonga/plugins/search/distributed_search_planner.rb +4 -4
  74. data/lib/droonga/plugins/system.rb +5 -26
  75. data/lib/droonga/plugins/system/absorb_data.rb +405 -0
  76. data/lib/droonga/plugins/system/statistics.rb +71 -0
  77. data/lib/droonga/plugins/system/status.rb +53 -0
  78. data/lib/droonga/process_control_protocol.rb +3 -1
  79. data/lib/droonga/process_supervisor.rb +32 -15
  80. data/lib/droonga/reducer.rb +69 -0
  81. data/lib/droonga/safe_file_writer.rb +1 -1
  82. data/lib/droonga/serf.rb +207 -276
  83. data/lib/droonga/serf/agent.rb +228 -0
  84. data/lib/droonga/serf/command.rb +94 -0
  85. data/lib/droonga/serf/downloader.rb +120 -0
  86. data/lib/droonga/serf/remote_command.rb +348 -0
  87. data/lib/droonga/serf/tag.rb +56 -0
  88. data/lib/droonga/service_installation.rb +2 -2
  89. data/lib/droonga/session.rb +49 -1
  90. data/lib/droonga/single_step.rb +6 -11
  91. data/lib/droonga/single_step_definition.rb +32 -1
  92. data/lib/droonga/slice.rb +14 -9
  93. data/lib/droonga/supervisor.rb +27 -20
  94. data/lib/droonga/test/stub_handler_messenger.rb +2 -1
  95. data/lib/droonga/timestamp.rb +69 -0
  96. data/lib/droonga/worker_process_agent.rb +33 -15
  97. data/sample/cluster-state.json +8 -0
  98. data/sample/cluster/Rakefile +30 -6
  99. data/test/command/fixture/integer-key-table.jsons +11 -0
  100. data/test/command/fixture/string-key-table.jsons +11 -0
  101. data/test/command/run-test.rb +4 -0
  102. data/test/command/suite/add/error/invalid-integer.expected +3 -3
  103. data/test/command/suite/add/error/invalid-time.expected +3 -3
  104. data/test/command/suite/add/{minimum.expected → key-integer.expected} +0 -0
  105. data/test/command/suite/add/{minimum.test → key-integer.test} +0 -0
  106. data/test/command/suite/add/key-string.expected +6 -0
  107. data/test/command/suite/add/key-string.test +9 -0
  108. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.expected +6 -0
  109. data/test/command/suite/add/mismatched-key-type/acceptable/integer-for-string.test +9 -0
  110. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.expected +6 -0
  111. data/test/command/suite/add/mismatched-key-type/acceptable/string-for-integer.test +9 -0
  112. data/test/command/suite/add/without-values.expected +6 -0
  113. data/test/command/suite/add/without-values.test +11 -0
  114. data/test/command/suite/dump/column/index.expected +33 -1
  115. data/test/command/suite/dump/column/index.test +1 -0
  116. data/test/command/suite/dump/column/scalar.expected +29 -1
  117. data/test/command/suite/dump/column/scalar.test +1 -0
  118. data/test/command/suite/dump/column/vector.expected +29 -1
  119. data/test/command/suite/dump/column/vector.test +1 -0
  120. data/test/command/suite/dump/record/scalar.catalog.json +12 -0
  121. data/test/command/suite/dump/record/scalar.expected +84 -0
  122. data/test/command/suite/dump/record/scalar.test +16 -0
  123. data/test/command/suite/dump/record/vector/reference.expected +83 -1
  124. data/test/command/suite/dump/record/vector/reference.test +1 -0
  125. data/test/command/suite/dump/table/array.expected +27 -1
  126. data/test/command/suite/dump/table/array.test +1 -0
  127. data/test/command/suite/dump/table/double_array_trie.expected +27 -1
  128. data/test/command/suite/dump/table/double_array_trie.test +1 -0
  129. data/test/command/suite/dump/table/hash.expected +27 -1
  130. data/test/command/suite/dump/table/hash.test +1 -0
  131. data/test/command/suite/dump/table/patricia_trie.expected +27 -1
  132. data/test/command/suite/dump/table/patricia_trie.test +1 -0
  133. data/test/command/suite/groonga/delete/{success.expected → key-integer.expected} +0 -0
  134. data/test/command/suite/groonga/delete/key-integer.test +17 -0
  135. data/test/command/suite/groonga/delete/key-string.expected +19 -0
  136. data/test/command/suite/groonga/delete/{success.test → key-string.test} +4 -6
  137. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.expected +19 -0
  138. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/integer-for-string.test +17 -0
  139. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.expected +19 -0
  140. data/test/command/suite/groonga/delete/mismatched-type-key/acceptable/string-for-integer.test +17 -0
  141. data/test/command/suite/message/error/missing-dataset.test +1 -0
  142. data/test/command/suite/system/absorb-data/records.catalog.json +58 -0
  143. data/test/command/suite/system/absorb-data/records.expected +32 -0
  144. data/test/command/suite/system/absorb-data/records.test +24 -0
  145. data/test/command/suite/system/statistics/object/count/empty.expected +11 -0
  146. data/test/command/suite/system/statistics/object/count/empty.test +12 -0
  147. data/test/command/suite/system/statistics/object/count/per-volume/empty.catalog.json +36 -0
  148. data/test/command/suite/system/statistics/object/count/per-volume/empty.expected +19 -0
  149. data/test/command/suite/system/statistics/object/count/per-volume/empty.test +12 -0
  150. data/test/command/suite/system/statistics/object/count/per-volume/record.catalog.json +40 -0
  151. data/test/command/suite/system/statistics/object/count/per-volume/record.expected +19 -0
  152. data/test/command/suite/system/statistics/object/count/per-volume/record.test +23 -0
  153. data/test/command/suite/system/statistics/object/count/per-volume/schema.catalog.json +40 -0
  154. data/test/command/suite/system/statistics/object/count/per-volume/schema.expected +19 -0
  155. data/test/command/suite/system/statistics/object/count/per-volume/schema.test +13 -0
  156. data/test/command/suite/system/statistics/object/count/record.catalog.json +12 -0
  157. data/test/command/suite/system/statistics/object/count/record.expected +11 -0
  158. data/test/command/suite/system/statistics/object/count/record.test +23 -0
  159. data/test/command/suite/system/statistics/object/count/schema.catalog.json +12 -0
  160. data/test/command/suite/system/statistics/object/count/schema.expected +11 -0
  161. data/test/command/suite/system/statistics/object/count/schema.test +13 -0
  162. data/test/command/suite/system/status.expected +3 -2
  163. data/test/unit/catalog/test_dataset.rb +4 -1
  164. data/test/unit/{test_catalog_generator.rb → catalog/test_generator.rb} +2 -2
  165. data/test/unit/catalog/test_replicas_volume.rb +79 -0
  166. data/test/unit/catalog/test_single_volume.rb +2 -2
  167. data/test/unit/catalog/test_slice.rb +33 -1
  168. data/test/unit/catalog/{test_collection_volume.rb → test_slices_volume.rb} +72 -11
  169. data/test/unit/catalog/test_version2.rb +3 -0
  170. data/test/unit/helper/distributed_search_planner_helper.rb +2 -2
  171. data/test/unit/plugins/catalog/test_fetch.rb +4 -4
  172. data/test/unit/plugins/crud/test_add.rb +44 -4
  173. data/test/unit/plugins/groonga/test_column_create.rb +4 -4
  174. data/test/unit/plugins/groonga/test_column_list.rb +4 -4
  175. data/test/unit/plugins/groonga/test_column_remove.rb +4 -4
  176. data/test/unit/plugins/groonga/test_column_rename.rb +4 -4
  177. data/test/unit/plugins/groonga/test_delete.rb +73 -10
  178. data/test/unit/plugins/groonga/test_table_create.rb +4 -4
  179. data/test/unit/plugins/groonga/test_table_list.rb +4 -4
  180. data/test/unit/plugins/groonga/test_table_remove.rb +4 -4
  181. data/test/unit/plugins/search/test_handler.rb +4 -4
  182. data/test/unit/plugins/search/test_planner.rb +4 -2
  183. data/test/unit/plugins/system/test_status.rb +31 -15
  184. data/test/unit/plugins/test_watch.rb +16 -16
  185. data/test/unit/test_address.rb +4 -4
  186. metadata +134 -35
  187. data/lib/droonga/catalog/volume_collection.rb +0 -79
  188. data/lib/droonga/catalog_fetcher.rb +0 -53
  189. data/lib/droonga/catalog_generator.rb +0 -243
  190. data/lib/droonga/catalog_loader.rb +0 -56
  191. data/lib/droonga/command/remote.rb +0 -404
  192. data/lib/droonga/data_absorber.rb +0 -264
  193. data/lib/droonga/node_status.rb +0 -71
  194. data/lib/droonga/serf_downloader.rb +0 -115
  195. data/test/unit/catalog/test_volume_collection.rb +0 -78
@@ -0,0 +1,106 @@
1
+ # Copyright (C) 2015 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
+
16
+ require "groonga"
17
+
18
+ module Droonga
19
+ module DatabaseScanner
20
+ def n_tables
21
+ n_tables = 0
22
+ each_table do |table|
23
+ n_tables += 1
24
+ end
25
+ n_tables
26
+ end
27
+
28
+ def n_columns
29
+ n_columns = 0
30
+ each_table do |table|
31
+ n_columns += table.columns.size
32
+ end
33
+ n_columns
34
+ end
35
+
36
+ def n_records
37
+ n_records = 0
38
+ each_table do |table|
39
+ unless index_only_table?(table)
40
+ n_records += table.size
41
+ end
42
+ end
43
+ n_records
44
+ end
45
+
46
+ def total_n_objects
47
+ n_tables = 0
48
+ n_columns = 0
49
+ n_records = 0
50
+ each_table do |table|
51
+ n_tables += 1
52
+ n_columns += table.columns.size
53
+ unless index_only_table?(table)
54
+ n_records += table.size
55
+ end
56
+ end
57
+ n_tables + n_columns + n_records
58
+ end
59
+
60
+ def each_table(&block)
61
+ options = {
62
+ :ignore_missing_object => true,
63
+ :order_by => :key,
64
+ }
65
+ reference_tables = []
66
+ @context.database.each(options) do |object|
67
+ next unless table?(object)
68
+ if reference_table?(object)
69
+ reference_tables << object
70
+ next
71
+ end
72
+ yield(object)
73
+ end
74
+ reference_tables.each do |reference_table|
75
+ yield(object)
76
+ end
77
+ end
78
+
79
+ def table?(object)
80
+ object.is_a?(::Groonga::Table)
81
+ end
82
+
83
+ def reference_table?(table)
84
+ table.support_key? and table?(table.domain)
85
+ end
86
+
87
+ def index_only_table?(table)
88
+ return false if table.columns.empty?
89
+ table.columns.all? do |column|
90
+ index_column?(column)
91
+ end
92
+ end
93
+
94
+ def index_column?(column)
95
+ column.is_a?(::Groonga::IndexColumn)
96
+ end
97
+
98
+ def each_index_columns(&block)
99
+ each_table do |table|
100
+ table.columns.each do |column|
101
+ yield(column) if index_column?(column)
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014 Droonga Project
1
+ # Copyright (C) 2015 Droonga Project
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -13,36 +13,23 @@
13
13
  # License along with this library; if not, write to the Free Software
14
14
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
15
 
16
- require "pathname"
17
- require "json"
18
-
19
16
  module Droonga
20
- class LiveNodesListLoader
21
- def initialize(path)
22
- @path = path
23
- end
17
+ module Deferrable
18
+ attr_writer :on_ready, :on_failure
24
19
 
25
- def load
26
- list = parse
27
- list.keys
20
+ def wait_until_ready(target)
21
+ target.on_ready = lambda do
22
+ on_ready
23
+ end
28
24
  end
29
25
 
30
26
  private
31
- def parse
32
- return default_list unless @path.exist?
33
-
34
- contents = @path.read
35
- return default_list if contents.empty?
36
-
37
- begin
38
- JSON.parse(contents)
39
- rescue JSON::ParserError
40
- default_list
41
- end
27
+ def on_ready
28
+ @on_ready.call if @on_ready
42
29
  end
43
30
 
44
- def default_list
45
- {}
31
+ def on_failure
32
+ @on_failure.call if @on_failure
46
33
  end
47
34
  end
48
35
  end
@@ -0,0 +1,58 @@
1
+ # Copyright (C) 2015 Droonga Project
2
+ #
3
+ # This library is free software; you can redistribute it and/or
4
+ # modify it under the terms of the GNU Lesser General Public
5
+ # License version 2.1 as published by the Free Software Foundation.
6
+ #
7
+ # This library is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10
+ # Lesser General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU Lesser General Public
13
+ # License along with this library; if not, write to the Free Software
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15
+
16
+ module Droonga
17
+ module Differ
18
+ class << self
19
+ def diff(a, b)
20
+ unless a.class == b.class
21
+ return "#{a.inspect} <=> #{b.inspect}"
22
+ end
23
+ case a
24
+ when Hash
25
+ diff_hashes(a, b)
26
+ when Array
27
+ diff_arrays(a, b)
28
+ else
29
+ if a == b
30
+ nil
31
+ else
32
+ "#{a.inspect} <=> #{b.inspect}"
33
+ end
34
+ end
35
+ end
36
+
37
+ def diff_hashes(a, b)
38
+ difference = {}
39
+ (a.keys + b.keys).uniq.each do |key|
40
+ unless a[key] == b[key]
41
+ difference[key] = diff(a[key], b[key])
42
+ end
43
+ end
44
+ difference
45
+ end
46
+
47
+ def diff_arrays(a, b)
48
+ difference = {}
49
+ [a.size, b.size].max.times do |index|
50
+ unless a[index] == b[index]
51
+ difference[index] = diff(a[index], b[index])
52
+ end
53
+ end
54
+ difference
55
+ end
56
+ end
57
+ end
58
+ end
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2013-2014 Droonga Project
1
+ # Copyright (C) 2013-2015 Droonga Project
2
2
  #
3
3
  # This library is free software; you can redistribute it and/or
4
4
  # modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,7 @@ require "droonga/farm"
23
23
  require "droonga/session"
24
24
  require "droonga/error_messages"
25
25
  require "droonga/distributor"
26
+ require "droonga/node_role"
26
27
 
27
28
  module Droonga
28
29
  class Dispatcher
@@ -46,30 +47,32 @@ module Droonga
46
47
  end
47
48
  end
48
49
 
49
- attr_reader :engine_state
50
+ attr_reader :engine_state, :cluster
50
51
 
51
- def initialize(engine_state, catalog)
52
+ def initialize(engine_state, cluster, catalog)
52
53
  @engine_state = engine_state
54
+ @cluster = cluster
53
55
  @forwarder = @engine_state.forwarder
54
56
  @replier = @engine_state.replier
55
57
  @catalog = catalog
56
58
  @adapter_runners = create_adapter_runners
57
59
  @farm = Farm.new(@engine_state.name, @catalog, @engine_state.loop,
58
60
  :engine_state => @engine_state,
61
+ :cluster => @cluster,
59
62
  :dispatcher => self,
60
- :forwarder => @forwarder)
63
+ :forwarder => @forwarder,
64
+ :internal_connection_lifetime =>
65
+ @engine_state.internal_connection_lifetime)
66
+ @engine_state.wait_until_ready(@farm)
61
67
  @collector_runners = create_collector_runners
62
68
  @step_runners = create_step_runners
63
69
  end
64
70
 
65
71
  def start
66
- @farm.on_ready = lambda do
67
- @engine_state.on_ready
68
- end
69
72
  @farm.start
70
73
  end
71
74
 
72
- def stop_gracefully(&on_stop)
75
+ def stop_gracefully(&block)
73
76
  logger.trace("stop_gracefully: start")
74
77
  @collector_runners.each_value do |collector_runner|
75
78
  collector_runner.shutdown
@@ -77,8 +80,10 @@ module Droonga
77
80
  @adapter_runners.each_value do |adapter_runner|
78
81
  adapter_runner.shutdown
79
82
  end
80
- @farm.stop_gracefully(&on_stop)
81
- logger.trace("stop_gracefully: done")
83
+ @farm.stop_gracefully do
84
+ yield
85
+ logger.trace("stop_gracefully: done")
86
+ end
82
87
  end
83
88
 
84
89
  def stop_immediately
@@ -89,11 +94,16 @@ module Droonga
89
94
  @adapter_runners.each_value do |adapter_runner|
90
95
  adapter_runner.shutdown
91
96
  end
92
- @farm.shutdown
97
+ @farm.stop_immediately
93
98
  logger.trace("stop_immediately: done")
94
99
  end
95
100
 
101
+ def refresh_node_reference
102
+ @farm.refresh_node_reference
103
+ end
104
+
96
105
  def process_message(message)
106
+ logger.trace("process_message: start", :message => message)
97
107
  @message = message
98
108
  if message["type"] == "dispatcher"
99
109
  process_internal_message(message["body"])
@@ -111,11 +121,16 @@ module Droonga
111
121
  "body" => formatted_error.response_body)
112
122
  end
113
123
  end
124
+ logger.trace("process_message: done")
114
125
  end
115
126
 
116
127
  def forward(message, destination)
117
128
  logger.trace("forward start")
118
- @forwarder.forward(message, destination)
129
+ if local_route?(destination) or direct_route?(destination)
130
+ @forwarder.forward(message, destination)
131
+ else
132
+ @cluster.forward(message, destination)
133
+ end
119
134
  logger.trace("forward done")
120
135
  end
121
136
 
@@ -153,82 +168,147 @@ module Droonga
153
168
  end
154
169
 
155
170
  def process_internal_message(message)
171
+ logger.trace("process_internal_message: start", :message => message)
156
172
  id = message["id"]
157
173
  session = @engine_state.find_session(id)
158
174
  if session
159
175
  session.receive(message["input"], message["value"])
160
176
  else
177
+ logger.trace("process_internal_message: no session")
161
178
  steps = message["steps"]
162
179
  if steps
163
- session_planner = SessionPlanner.new(@engine_state, steps)
180
+ session_planner = SessionPlanner.new(@engine_state, @cluster, steps)
164
181
  dataset = message["dataset"] || @message["dataset"]
165
182
  collector_runner = @collector_runners[dataset]
166
183
  session = session_planner.create_session(id, self, collector_runner)
167
- @engine_state.register_session(id, session)
184
+ if session.need_result?
185
+ timeout = message["timeout"] ||
186
+ @engine_state.internal_connection_lifetime
187
+ @engine_state.register_session(id, session,
188
+ :timeout => timeout)
189
+ session.start
190
+ logger.trace("process_internal_message: waiting for results")
191
+ else
192
+ session.start
193
+ session.finish
194
+ session = nil
195
+ logger.trace("process_internal_message: no need to wait for results")
196
+ end
168
197
  else
169
- logger.error("no steps error: id=#{id}, message=#{message}")
198
+ logger.error("no steps error", :id => id, :message => message)
170
199
  return
171
200
  #todo: take cases receiving result before its query into account
172
201
  end
173
- session.start
174
202
  end
175
- @engine_state.unregister_session(id) if session.done?
203
+ @engine_state.unregister_session(id) if session and session.done?
204
+ logger.trace("process_internal_message: done")
176
205
  end
177
206
 
178
207
  def dispatch(message, destination)
179
- if local?(destination)
208
+ logger.trace("dispatch: start", :message => message, :destination => destination)
209
+ if local_route?(destination)
180
210
  process_internal_message(message)
181
211
  else
182
- @forwarder.forward(@message.merge("body" => message),
183
- "type" => "dispatcher",
184
- "to" => destination)
212
+ forward_message = @message.merge("body" => message)
213
+ forward_destination = {
214
+ "type" => "dispatcher",
215
+ "to" => destination,
216
+ }
217
+ if direct_route?(forward_destination)
218
+ @forwarder.forward(forward_message, forward_destination)
219
+ else
220
+ @cluster.forward(forward_message, forward_destination)
221
+ end
185
222
  end
223
+ logger.trace("dispatch: done")
186
224
  end
187
225
 
188
226
  def dispatch_steps(steps)
227
+ logger.trace("dispatch_steps: start", :steps => steps)
189
228
  id = @engine_state.generate_id
190
229
 
191
230
  destinations = []
231
+ timeout = nil
192
232
  steps.each do |step|
233
+ calculated_timeout = timeout_from_step(step)
234
+ if calculated_timeout
235
+ timeout = calculated_timeout
236
+ end
237
+
193
238
  dataset = @catalog.dataset(step["dataset"])
194
239
  if dataset
195
- routes = dataset.compute_routes(step, @engine_state.live_nodes)
196
- step["routes"] = routes
240
+ if write_step?(step)
241
+ step["write"] = true
242
+ target_nodes = @cluster.writable_nodes
243
+ if target_nodes.empty?
244
+ logger.error("there is no node to dispath a write step!",
245
+ :my_role => NodeRole.mine,
246
+ :all_nodes => @cluster.engine_nodes.collect(&:to_json),
247
+ :step => step)
248
+ end
249
+ else
250
+ target_nodes = @cluster.readable_nodes
251
+ if target_nodes.empty?
252
+ logger.error("there is no node to dispath a read step!",
253
+ :my_role => NodeRole.mine,
254
+ :all_nodes => @cluster.engine_nodes.collect(&:to_json),
255
+ :step => step)
256
+ end
257
+ end
258
+ routes = dataset.compute_routes(step, target_nodes)
259
+ step["routes"] = routes.collect do |route|
260
+ internal_route(route)
261
+ end
197
262
  else
198
263
  step["routes"] ||= [id]
199
264
  end
265
+
200
266
  destinations += step["routes"].collect do |route|
201
- farm_path(route)
267
+ internal_farm_path(route)
202
268
  end
203
269
  end
204
270
 
205
- dispatch_message = { "id" => id, "steps" => steps }
271
+ dispatch_message = {
272
+ "id" => id,
273
+ "steps" => steps,
274
+ "timeout" => timeout,
275
+ }
206
276
  destinations.uniq.each do |destination|
207
277
  dispatch(dispatch_message, destination)
208
278
  end
279
+
280
+ logger.trace("dispatch_steps: done")
209
281
  end
210
282
 
211
283
  def process_local_message(local_message)
284
+ logger.trace("process_local_message: start", :steps => local_message)
212
285
  task = local_message["task"]
213
286
  slice_name = task["route"]
287
+ slice_name = public_route(slice_name)
214
288
  step = task["step"]
215
289
  command = step["command"]
216
290
  descendants = {}
217
291
  step["descendants"].each do |name, routes|
218
292
  descendants[name] = routes.collect do |route|
219
- farm_path(route)
293
+ internal_farm_path(route)
220
294
  end
221
295
  end
222
296
  local_message["descendants"] = descendants
223
297
  farm_message = @message.merge("body" => local_message,
224
298
  "type" => command)
225
299
  @farm.process(slice_name, farm_message)
300
+ logger.trace("process_local_message: done")
226
301
  end
227
302
 
228
- def local?(route)
303
+ def local_route?(route)
229
304
  @engine_state.local_route?(route)
230
305
  end
231
306
 
307
+ def direct_route?(route)
308
+ receiver = route["to"]
309
+ not @cluster.engine_node_names.include?(receiver)
310
+ end
311
+
232
312
  def write_step?(step)
233
313
  return false unless step["dataset"]
234
314
 
@@ -241,12 +321,46 @@ module Droonga
241
321
  step_definition.write?
242
322
  end
243
323
 
324
+ def timeout_from_step(step)
325
+ return nil unless step["dataset"]
326
+
327
+ step_runner = @step_runners[step["dataset"]]
328
+ return nil unless step_runner
329
+
330
+ step_definition = step_runner.find(step["command"])
331
+ return nil unless step_definition
332
+
333
+ step_definition.timeout_for_step(step)
334
+ end
335
+
244
336
  private
245
- def farm_path(route)
246
- @engine_state.farm_path(route)
337
+ def internal_route(route)
338
+ @engine_state.internal_route(route)
339
+ end
340
+
341
+ def public_route(route)
342
+ @engine_state.public_route(route)
343
+ end
344
+
345
+ def internal_farm_path(route)
346
+ @engine_state.internal_farm_path(route)
347
+ end
348
+
349
+ def public_farm_path(route)
350
+ @engine_state.public_farm_path(route)
351
+ end
352
+
353
+ def acceptable_role?(message)
354
+ return true unless message["targetRole"]
355
+ role = message["targetRole"].downcase
356
+ role == NodeRole::ANY or role == NodeRole.mine
247
357
  end
248
358
 
249
359
  def process_input_message(message)
360
+ unless acceptable_role?(message)
361
+ @cluster.bounce(message)
362
+ return
363
+ end
250
364
  dataset = message["dataset"]
251
365
  adapter_runner = @adapter_runners[dataset]
252
366
  adapted_message = adapter_runner.adapt_input(message)
@@ -255,6 +369,7 @@ module Droonga
255
369
  distributor = Distributor.new(self, plan)
256
370
  distributor.distribute
257
371
  rescue Droonga::UnsupportedMessageError => error
372
+ logger.trace("process_input_message: rescue", :error => error)
258
373
  target_message = error.message
259
374
  raise UnknownType.new(target_message["type"], target_message["dataset"])
260
375
  end
@@ -302,8 +417,9 @@ module Droonga
302
417
  class SessionPlanner
303
418
  attr_reader :steps
304
419
 
305
- def initialize(engine_state, steps)
420
+ def initialize(engine_state, cluster, steps)
306
421
  @engine_state = engine_state
422
+ @cluster = cluster
307
423
  @steps = steps
308
424
  end
309
425
 
@@ -345,14 +461,21 @@ module Droonga
345
461
  (step["outputs"] || []).each do |output|
346
462
  descendants[output] = []
347
463
  @descendants[output].each do |index|
348
- live_routes = @engine_state.remove_dead_routes(step["routes"])
349
- @steps[index]["n_of_expects"] += live_routes.size
464
+ responsive_routes = select_responsive_routes(step["routes"])
465
+ @steps[index]["n_of_expects"] += responsive_routes.size
350
466
  descendants[output].concat(@steps[index]["routes"])
351
467
  end
352
468
  end
353
469
  step["descendants"] = descendants
354
470
  end
355
471
  end
472
+
473
+ def select_responsive_routes(routes)
474
+ selected_nodes = @cluster.readable_nodes
475
+ routes.select do |route|
476
+ selected_nodes.include?(@engine_state.public_farm_path(route))
477
+ end
478
+ end
356
479
  end
357
480
  end
358
481
  end