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,245 @@
1
+ # Copyright (C) 2014 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 "time"
17
+
18
+ require "droonga/node_name"
19
+ require "droonga/catalog/dataset"
20
+
21
+ module Droonga
22
+ module Catalog
23
+ class Generator
24
+ DEFAULT_DATASET = Catalog::Dataset::DEFAULT_NAME
25
+ DEFAULT_HOSTS = [NodeName::DEFAULT_HOST]
26
+ DEFAULT_N_WORKERS = 4
27
+ DEFAULT_N_SLICES = 1
28
+ DEFAULT_PLUGINS = ["groonga", "search", "crud", "dump", "system", "catalog"]
29
+ DEFAULT_PORT = NodeName::DEFAULT_PORT
30
+ DEFAULT_TAG = NodeName::DEFAULT_TAG
31
+
32
+ attr_reader :datasets
33
+
34
+ class << self
35
+ def generate(datasets_params)
36
+ generator = new
37
+ datasets_params.each do |name, params|
38
+ generator.add_dataset(name, params)
39
+ end
40
+ generator.generate
41
+ end
42
+ end
43
+
44
+ def initialize
45
+ @version = 2
46
+ @effective_date = Time.now
47
+ @datasets = {}
48
+ end
49
+
50
+ def add_dataset(name, options)
51
+ @datasets[name] = Dataset.new(name, options)
52
+ end
53
+
54
+ def generate
55
+ {
56
+ "version" => @version,
57
+ "effectiveDate" => @effective_date.iso8601,
58
+ "datasets" => catalog_datasets,
59
+ }
60
+ end
61
+
62
+ def load(catalog)
63
+ catalog["datasets"].each do |name, catalog_dataset|
64
+ load_dataset(name, catalog_dataset)
65
+ end
66
+ self
67
+ end
68
+
69
+ def dataset_for_host(host)
70
+ @datasets.each do |name, dataset|
71
+ if dataset.replicas.hosts.include?(host)
72
+ return dataset
73
+ end
74
+ end
75
+ nil
76
+ end
77
+
78
+ def modify(dataset_modifications)
79
+ dataset_modifications.each do |name, modification|
80
+ dataset = @datasets[name]
81
+ next unless dataset
82
+
83
+ replicas = dataset.replicas
84
+
85
+ if modification[:replica_hosts]
86
+ replicas.hosts = modification[:replica_hosts]
87
+ end
88
+
89
+ if modification[:add_replica_hosts]
90
+ replicas.hosts += modification[:add_replica_hosts]
91
+ replicas.hosts.uniq!
92
+ end
93
+
94
+ if modification[:remove_replica_hosts]
95
+ replicas.hosts -= modification[:remove_replica_hosts]
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+ def catalog_datasets
102
+ catalog_datasets = {}
103
+ @datasets.each do |name, dataset|
104
+ catalog_datasets[name] = dataset.to_catalog
105
+ end
106
+ catalog_datasets
107
+ end
108
+
109
+ def load_dataset(name, catalog_dataset)
110
+ options = {}
111
+ options[:n_workers] = catalog_dataset["nWorkers"]
112
+ options[:plugins] = catalog_dataset["plugins"]
113
+ options[:schema] = catalog_dataset["schema"]
114
+ options[:fact] = catalog_dataset["fact"]
115
+ options[:replicas] = catalog_dataset["replicas"]
116
+ add_dataset(name, options)
117
+ end
118
+
119
+ class Dataset
120
+ attr_reader :name
121
+
122
+ def initialize(name, options)
123
+ @name = name
124
+ @options = options
125
+ end
126
+
127
+ def n_workers
128
+ @options[:n_workers] || DEFAULT_N_WORKERS
129
+ end
130
+
131
+ def plugins
132
+ @options[:plugins] || DEFAULT_PLUGINS
133
+ end
134
+
135
+ def schema
136
+ @options[:schema] || {}
137
+ end
138
+
139
+ def fact
140
+ @options[:fact]
141
+ end
142
+
143
+ def replicas
144
+ @replicas ||= create_replicas
145
+ end
146
+
147
+ def to_catalog
148
+ catalog = {
149
+ "nWorkers" => n_workers,
150
+ "plugins" => plugins,
151
+ "schema" => schema,
152
+ "replicas" => replicas.to_catalog,
153
+ }
154
+ catalog["fact"] = fact if fact
155
+ catalog
156
+ end
157
+
158
+ private
159
+ def create_replicas
160
+ catalog_replicas = @options[:replicas]
161
+ if catalog_replicas
162
+ replicas = Replicas.new
163
+ replicas.load(catalog_replicas)
164
+ replicas
165
+ else
166
+ Replicas.new(@options)
167
+ end
168
+ end
169
+ end
170
+
171
+ class Replicas
172
+ attr_accessor :hosts
173
+ attr_reader :port, :tag, :n_slices
174
+
175
+ def initialize(options={})
176
+ @hosts = options[:hosts] || DEFAULT_HOSTS
177
+ @port = options[:port]
178
+ @tag = options[:tag]
179
+ @n_slices = options[:n_slices]
180
+ end
181
+
182
+ def load(catalog_replicas)
183
+ dataset = Catalog::Dataset.new("temporary",
184
+ "replicas" => catalog_replicas)
185
+ @hosts = dataset.replicas.collect do |replica|
186
+ replica.slices.first.volume.address.host
187
+ end
188
+ collection_volume = dataset.replicas.first
189
+ slices = collection_volume.slices
190
+ @n_slices = slices.size
191
+ single_volume_address = slices.first.volume.address
192
+ @port = single_volume_address.port
193
+ @tag = single_volume_address.tag
194
+ end
195
+
196
+ def to_catalog
197
+ catalog_replicas = []
198
+ @hosts.each do |host|
199
+ replica = Replica.new(host, :port => @port,
200
+ :tag => @tag,
201
+ :n_slices => @n_slices)
202
+ catalog_replicas << replica.to_catalog
203
+ end
204
+ catalog_replicas
205
+ end
206
+ end
207
+
208
+ class Replica
209
+ def initialize(host, options={})
210
+ @host = host
211
+ @port = options[:port] || DEFAULT_PORT
212
+ @tag = options[:tag] || DEFAULT_TAG
213
+ @n_slices = options[:n_slices] || DEFAULT_N_SLICES
214
+ end
215
+
216
+ def to_catalog
217
+ slices = []
218
+ @n_slices.times do |i|
219
+ slices << catalog_slice(i)
220
+ end
221
+ {
222
+ "dimension" => "_key",
223
+ "slicer" => "hash",
224
+ "slices" => slices,
225
+ }
226
+ end
227
+
228
+ private
229
+ def catalog_slice(nth_slice)
230
+ local_name = "%03d" % nth_slice
231
+ {
232
+ "weight" => weight,
233
+ "volume" => {
234
+ "address" => "#{@host}:#{@port}/#{@tag}.#{local_name}",
235
+ },
236
+ }
237
+ end
238
+
239
+ def weight
240
+ @weight ||= 100 / @n_slices
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (C) 2013-2014 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 "json"
17
+
18
+ require "droonga/catalog/version1"
19
+ require "droonga/catalog/version2"
20
+
21
+ module Droonga
22
+ module Catalog
23
+ class Loader
24
+ def initialize(path=nil)
25
+ @path = path
26
+ end
27
+
28
+ def load
29
+ unless @path
30
+ raise Error.new("nothing specified")
31
+ end
32
+
33
+ data = nil
34
+ begin
35
+ data = File.open(@path) do |file|
36
+ JSON.parse(file.read)
37
+ end
38
+ rescue Errno::ENOENT => error
39
+ raise Error.new("Missing catalog file #{@path}")
40
+ rescue JSON::ParserError => error
41
+ raise Error.new("Syntax error in #{@path}:\n#{error.to_s}")
42
+ end
43
+ parse(data)
44
+ end
45
+
46
+ def parse(data)
47
+ unless data.is_a?(Hash)
48
+ raise Error.new("Root element of catalog must be an object in #{@path}: " +
49
+ "#{JSON.generate(data)}")
50
+ end
51
+
52
+ version = data["version"]
53
+ case version
54
+ when 1
55
+ Catalog::Version1.new(data, @path)
56
+ when 2
57
+ Catalog::Version2.new(data, @path)
58
+ when nil
59
+ raise Error.new("Catalog version must be specified in #{@path}")
60
+ else
61
+ raise Error.new("Unsupported catalog version <#{version}> is specified in #{@path}")
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -16,29 +16,22 @@
16
16
  require "json"
17
17
 
18
18
  require "droonga/path"
19
- require "droonga/catalog_generator"
19
+ require "droonga/catalog/generator"
20
20
  require "droonga/safe_file_writer"
21
21
 
22
22
  module Droonga
23
- class CatalogModifier
24
- class << self
25
- def modify
26
- new.modify do |generator, file|
27
- yield(generator, file)
28
- end
23
+ module Catalog
24
+ class Modifier
25
+ def initialize(source_catalog)
26
+ @generator = Catalog::Generator.new
27
+ @generator.load(source_catalog)
29
28
  end
30
- end
31
29
 
32
- def initialize
33
- @generator = CatalogGenerator.new
34
- @catalog = JSON.parse(Path.catalog.read)
35
- @generator.load(@catalog)
36
- end
37
-
38
- def modify
39
- SafeFileWriter.write(Path.catalog) do |output, file|
40
- yield(@generator, file)
41
- output.puts(JSON.pretty_generate(@generator.generate))
30
+ def modify
31
+ SafeFileWriter.write(Path.catalog) do |output, file|
32
+ yield(@generator, file)
33
+ output.puts(JSON.pretty_generate(@generator.generate))
34
+ end
42
35
  end
43
36
  end
44
37
  end
@@ -0,0 +1,123 @@
1
+ # Copyright (C) 2014 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 Catalog
18
+ class ReplicasVolume
19
+ include Enumerable
20
+
21
+ def initialize(dataset, raw)
22
+ @dataset = dataset
23
+ @raw = raw
24
+ end
25
+
26
+ def each(&block)
27
+ replicas.each(&block)
28
+ end
29
+
30
+ def ==(other)
31
+ other.is_a?(self.class) and
32
+ to_a == other.to_a
33
+ end
34
+
35
+ def eql?(other)
36
+ self == other
37
+ end
38
+
39
+ def hash
40
+ to_a.hash
41
+ end
42
+
43
+ def select(how=nil, active_nodes=nil)
44
+ case how
45
+ when :top
46
+ replicas = live_replicas(active_nodes)
47
+ if replicas.empty?
48
+ []
49
+ else
50
+ [replicas.first]
51
+ end
52
+ when :random
53
+ replicas = live_replicas(active_nodes)
54
+ if replicas.empty?
55
+ []
56
+ else
57
+ [replicas.sample]
58
+ end
59
+ when :all
60
+ live_replicas(active_nodes)
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ def replicas
67
+ @replicas ||= create_replicas
68
+ end
69
+
70
+ def all_nodes
71
+ @all_nodes ||= collect_all_nodes
72
+ end
73
+
74
+ def live_replicas(active_nodes=nil)
75
+ return replicas unless active_nodes
76
+
77
+ replicas.select do |volume|
78
+ dead_nodes = volume.all_nodes - active_nodes
79
+ dead_nodes.empty?
80
+ end
81
+ end
82
+
83
+ def compute_routes(message, active_nodes)
84
+ routes = []
85
+ case message["type"]
86
+ when "broadcast"
87
+ replicas = select(message["replica"].to_sym, active_nodes)
88
+ replicas.each do |volume|
89
+ routes.concat(volume.compute_routes(message, active_nodes))
90
+ end
91
+ when "scatter"
92
+ #TODO: we should choose suitable replica from differently sliced replicas.
93
+ replicas = select(message["replica"].to_sym, active_nodes)
94
+ replicas.each do |volume|
95
+ routes.concat(volume.compute_routes(message, active_nodes))
96
+ end
97
+ end
98
+ routes
99
+ end
100
+
101
+ def sliced?
102
+ replicas.any? do |volume|
103
+ volume.sliced?
104
+ end
105
+ end
106
+
107
+ private
108
+ def create_replicas
109
+ @raw["replicas"].collect do |raw_replica|
110
+ Catalog::Volume.create(@dataset, raw_replica)
111
+ end
112
+ end
113
+
114
+ def collect_all_nodes
115
+ nodes = []
116
+ replicas.each do |volume|
117
+ nodes.concat(volume.all_nodes)
118
+ end
119
+ nodes.sort.uniq
120
+ end
121
+ end
122
+ end
123
+ end