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
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014 Droonga Project
1
+ # Copyright (C) 2014-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
@@ -20,7 +20,7 @@ register_service() {
20
20
 
21
21
  #TODO: we should migrate to systemd in near future...
22
22
 
23
- curl -o /etc/rc.d/init.d/$NAME $(download_url "install/centos/$NAME")
23
+ curl -s -o /etc/rc.d/init.d/$NAME $(download_url "install/centos/$NAME")
24
24
  if [ $? -ne 0 ]; then
25
25
  echo "ERROR: Failed to download service script!"
26
26
  exit 1
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014 Droonga Project
1
+ # Copyright (C) 2014-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
@@ -18,7 +18,7 @@ register_service() {
18
18
  local USER=$2
19
19
  local GROUP=$3
20
20
 
21
- curl -o /etc/init.d/$NAME $(download_url "install/debian/$NAME")
21
+ curl -s -o /etc/init.d/$NAME $(download_url "install/debian/$NAME")
22
22
  if [ $? -ne 0 ]; then
23
23
  echo "ERROR: Failed to download service script!"
24
24
  exit 1
@@ -1,4 +1,4 @@
1
- # Copyright (C) 2014 Droonga Project
1
+ # Copyright (C) 2014-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,7 +13,7 @@
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 "socket"
16
+ require "droonga/node_name"
17
17
 
18
18
  module Droonga
19
19
  class Address
@@ -24,49 +24,51 @@ module Droonga
24
24
  :host => $1,
25
25
  :port => $2.to_i,
26
26
  :tag => $3,
27
- :name => $4
27
+ :local_name => $4
28
28
  }
29
29
  new(components)
30
30
  else
31
- format = "${host_name}:${port_number}/${tag}.${name}"
31
+ format = "${host_name}:${port_number}/${tag}.${local_name}"
32
32
  message = "volume address must be <#{format}> format: <#{string}>"
33
33
  raise ArgumentError, message
34
34
  end
35
35
  end
36
36
  end
37
37
 
38
- DEFAULT_HOST = Socket.gethostname
39
- DEFAULT_HOST.force_encoding("US-ASCII") if DEFAULT_HOST.ascii_only?
40
- DEFAULT_PORT = 10031
41
- DEFAULT_TAG = "droonga"
42
-
43
- attr_reader :host
44
- attr_reader :port
45
- attr_reader :tag
46
- attr_reader :name
38
+ attr_reader :local_name
47
39
  def initialize(components={})
48
- @host = components[:host] || DEFAULT_HOST
49
- @port = components[:port] || DEFAULT_PORT
50
- @tag = components[:tag] || DEFAULT_TAG
51
- @name = components[:name]
40
+ @node_name = NodeName.new(components)
41
+ @local_name = components[:local_name]
42
+ end
43
+
44
+ def host
45
+ @node_name.host
46
+ end
47
+
48
+ def port
49
+ @node_name.port
50
+ end
51
+
52
+ def tag
53
+ @node_name.tag
54
+ end
55
+
56
+ def node
57
+ @node_name.node
52
58
  end
53
59
 
54
60
  def to_s
55
- string = node
56
- string << ".#{@name}" if @name
61
+ string = @node_name.node
62
+ string << ".#{@local_name}" if @local_name
57
63
  string
58
64
  end
59
65
 
60
66
  def to_a
61
- [@host, @port, @tag, @name]
67
+ @node_name.to_a + [@local_name]
62
68
  end
63
69
 
64
70
  def ==(other)
65
71
  other.is_a?(self.class) and to_a == other.to_a
66
72
  end
67
-
68
- def node
69
- "#{@host}:#{@port}/#{@tag}"
70
- end
71
73
  end
72
74
  end
@@ -18,11 +18,15 @@
18
18
  require "coolio"
19
19
 
20
20
  require "droonga/loggable"
21
+ require "droonga/timestamp"
21
22
 
22
23
  module Droonga
23
24
  class BufferedTCPSocket < Coolio::TCPSocket
24
25
  include Loggable
25
26
 
27
+ class AlreadyInWritingByOthers < StandardError
28
+ end
29
+
26
30
  def initialize(socket, data_directory)
27
31
  super(socket)
28
32
  @data_directory = data_directory
@@ -34,7 +38,8 @@ module Droonga
34
38
  end
35
39
 
36
40
  def write(data)
37
- chunk = Chunk.new(@data_directory, data, Time.now, 0)
41
+ chunk = Chunk.new(:directory => @data_directory,
42
+ :data => data)
38
43
  chunk.buffering
39
44
  @_write_buffer << chunk
40
45
  schedule_write
@@ -45,19 +50,35 @@ module Droonga
45
50
  until @_write_buffer.empty?
46
51
  chunk = @_write_buffer.shift
47
52
  begin
53
+ chunk.writing
54
+ logger.trace("Sending...", :data => chunk.data)
48
55
  written_size = @_io.write_nonblock(chunk.data)
49
56
  if written_size == chunk.data.bytesize
50
57
  chunk.written
58
+ logger.trace("Completely sent.")
51
59
  else
52
60
  chunk.written_partial(written_size)
61
+ logger.trace("Partially sent. Retry later.",
62
+ :written => written_size,
63
+ :rest => chunk.data.bytesize)
53
64
  @_write_buffer.unshift(chunk)
54
65
  break
55
66
  end
67
+ rescue AlreadyInWritingByOthers
68
+ logger.trace("Chunk is already in sending by another process.")
56
69
  rescue Errno::EINTR
57
70
  @_write_buffer.unshift(chunk)
71
+ chunk.failed
72
+ logger.trace("Failed to send chunk. Retry later.",
73
+ :chunk => chunk,
74
+ :errpr => "Errno::EINTR")
58
75
  return
59
- rescue SystemCallError, IOError, SocketError
76
+ rescue SystemCallError, IOError, SocketError => exception
60
77
  @_write_buffer.unshift(chunk)
78
+ chunk.failed
79
+ logger.trace("Failed to send chunk. Retry later.",
80
+ :chunk => chunk,
81
+ :exception => exception)
61
82
  return close
62
83
  end
63
84
  end
@@ -108,24 +129,30 @@ module Droonga
108
129
 
109
130
  class Chunk
110
131
  SUFFIX = ".chunk"
132
+ WRITING_SUFFIX = ".writing"
111
133
 
112
134
  class << self
113
135
  def load(path)
114
136
  data_directory = path.dirname
115
- time_stamp1, time_stamp2, revision, = path.basename.to_s.split(".", 4)
137
+ time_stamp1, time_stamp2, uniqueness, revision, = path.basename.to_s.split(".", 5)
116
138
  data = path.open("rb") {|file| file.read}
117
139
  time_stamp = Time.iso8601("#{time_stamp1}.#{time_stamp2}")
118
140
  revision = Integer(revision)
119
- new(data_directory, data, time_stamp, revision)
141
+ new(:directory => data_directory,
142
+ :data => data,
143
+ :time_stamp => time_stamp,
144
+ :uniqueness => uniqueness,
145
+ :revision => revision)
120
146
  end
121
147
  end
122
148
 
123
149
  attr_reader :data, :time_stamp
124
- def initialize(data_directory, data, time_stamp, revision)
125
- @data_directory = data_directory
126
- @data = data
127
- @time_stamp = time_stamp.utc
128
- @revision = revision
150
+ def initialize(params)
151
+ @data_directory = params[:directory]
152
+ @data = params[:data]
153
+ @time_stamp = params[:time_stamp] || Time.now
154
+ @uniqueness = params[:uniqueness]
155
+ @revision = params[:revision] || 0
129
156
  end
130
157
 
131
158
  def buffering
@@ -134,8 +161,23 @@ module Droonga
134
161
  end
135
162
  end
136
163
 
164
+ def writing
165
+ raise AlreadyInWritingByOthers.new if writing?
166
+ FileUtils.mv(path.to_s, writing_path.to_s)
167
+ end
168
+
169
+ def writing?
170
+ not path.exist?
171
+ end
172
+
173
+ def failed
174
+ return unless writing?
175
+ FileUtils.mv(writing_path.to_s, path.to_s)
176
+ end
177
+
137
178
  def written
138
179
  FileUtils.rm_f(path.to_s)
180
+ FileUtils.rm_f(writing_path.to_s)
139
181
  end
140
182
 
141
183
  def written_partial(size)
@@ -147,7 +189,20 @@ module Droonga
147
189
 
148
190
  private
149
191
  def path
150
- @data_directory + "#{@time_stamp.iso8601(6)}.#{@revision}.#{SUFFIX}"
192
+ @path ||= create_chunk_file_path
193
+ end
194
+
195
+ def writing_path
196
+ @writing_path ||= Pathname("#{path.to_s}#{WRITING_SUFFIX}")
197
+ end
198
+
199
+ def create_chunk_file_path
200
+ basename = Timestamp.stringify(@time_stamp)
201
+ if @uniqueness
202
+ @data_directory + "#{basename}.#{@uniqueness}.#{@revision}#{SUFFIX}"
203
+ else
204
+ Path.unique_file_path(@data_directory, basename, "#{@revision}#{SUFFIX}")
205
+ end
151
206
  end
152
207
  end
153
208
  end
@@ -24,10 +24,10 @@ module Droonga
24
24
  module Catalog
25
25
  class Base
26
26
  attr_reader :path, :base_path
27
- def initialize(data, path)
28
- @data = data
29
- @path = path
30
- @base_path = File.dirname(path)
27
+ def initialize(raw, path)
28
+ @raw = raw
29
+ @path = path || "/tmp/temporary-catalog.json"
30
+ @base_path = File.dirname(@path)
31
31
  end
32
32
 
33
33
  def have_dataset?(name)
@@ -44,8 +44,11 @@ module Droonga
44
44
 
45
45
  private
46
46
  def calculate_cluster_id
47
- raw_id = all_nodes.sort.join(",")
48
- Digest::SHA1.hexdigest(raw_id)
47
+ raw_id = []
48
+ datasets.each do |name, dataset|
49
+ raw_id << "#{name}-#{dataset.all_nodes.sort.join(",")}"
50
+ end
51
+ Digest::SHA1.hexdigest(raw_id.sort.join("|"))
49
52
  end
50
53
 
51
54
  def migrate_database_location(current_db_path, device, name)
@@ -15,7 +15,6 @@
15
15
 
16
16
  require "droonga/catalog/schema"
17
17
  require "droonga/catalog/volume"
18
- require "droonga/catalog/volume_collection"
19
18
 
20
19
  module Droonga
21
20
  module Catalog
@@ -24,80 +23,57 @@ module Droonga
24
23
 
25
24
  attr_reader :name
26
25
 
27
- def initialize(name, data)
26
+ def initialize(name, raw)
28
27
  @name = name
29
- @data = data
28
+ @raw = raw
30
29
  @schema = nil
31
30
  end
32
31
 
33
32
  # provided for compatibility
34
33
  def [](key)
35
- @data[key]
34
+ @raw[key]
36
35
  end
37
36
 
38
37
  # provided for compatibility
39
38
  def []=(key, value)
40
- @data[key] = value
39
+ @raw[key] = value
41
40
  end
42
41
 
43
42
  def schema
44
- @schema ||= Schema.new(@name, @data["schema"])
43
+ @schema ||= Schema.new(@name, @raw["schema"])
45
44
  end
46
45
 
47
46
  def plugins
48
- @data["plugins"] || []
47
+ @raw["plugins"] || []
49
48
  end
50
49
 
51
50
  def fact
52
- @data["fact"]
51
+ @raw["fact"]
53
52
  end
54
53
 
55
54
  def n_workers
56
- @data["nWorkers"] || 0
55
+ @raw["nWorkers"] || 0
57
56
  end
58
57
 
58
+ #XXX Currently, dataset has a property named "replicas" so
59
+ # can be parsed as a ReplicasVolume.
60
+ # We must introduce a new property "volume" to provide
61
+ # ReplicasVolume safely.
59
62
  def replicas
60
- @replicas ||= VolumeCollection.new(create_volumes(@data["replicas"]))
63
+ @replicas ||= ReplicasVolume.new(self, @raw)
61
64
  end
62
65
 
63
66
  def all_nodes
64
67
  @all_nodes ||= replicas.all_nodes
65
68
  end
66
69
 
67
- def compute_routes(message, live_nodes)
68
- routes = []
69
- case message["type"]
70
- when "broadcast"
71
- volumes = replicas.select(message["replica"].to_sym, live_nodes)
72
- volumes.each do |volume|
73
- slices = volume.select_slices
74
- slices.each do |slice|
75
- routes << slice.volume.address.to_s
76
- end
77
- end
78
- when "scatter"
79
- volumes = replicas.select(message["replica"].to_sym, live_nodes)
80
- volumes.each do |volume|
81
- slice = volume.choose_slice(message["record"])
82
- routes << slice.volume.address.to_s
83
- end
84
- end
85
- routes
70
+ def compute_routes(message, active_nodes)
71
+ @replicas.compute_routes(message, active_nodes)
86
72
  end
87
73
 
88
- def single_slice?
74
+ def sliced?
89
75
  # TODO: Support slice key
90
- replicas.all? do |volume|
91
- volume.is_a?(SingleVolume) or
92
- volume.slices.size == 1
93
- end
94
- end
95
-
96
- private
97
- def create_volumes(raw_volumes)
98
- raw_volumes.collect do |raw_volume|
99
- Volume.create(self, raw_volume)
100
- end
76
+ @replicas.sliced?
101
77
  end
102
78
  end
103
79
  end
@@ -0,0 +1,64 @@
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 "socket"
17
+
18
+ require "droonga/client"
19
+
20
+ require "droonga/node_name"
21
+ require "droonga/catalog/dataset"
22
+
23
+ module Droonga
24
+ module Catalog
25
+ class Fetcher
26
+ class EmptyResponse < StandardError
27
+ end
28
+
29
+ class EmptyCatalog < StandardError
30
+ end
31
+
32
+ def initialize(client_options)
33
+ @client_options = default_options.merge(client_options)
34
+ end
35
+
36
+ def fetch(options={})
37
+ message = {
38
+ "dataset" => options[:dataset] || Catalog::Dataset::DEFAULT_NAME,
39
+ "type" => "catalog.fetch"
40
+ }
41
+ response = nil
42
+ Droonga::Client.open(@client_options) do |client|
43
+ response = client.request(message)
44
+ end
45
+ raise EmptyResponse.new unless response
46
+ raise EmptyCatalog.new unless response["body"]
47
+ response["body"]
48
+ end
49
+
50
+ private
51
+ def default_options
52
+ {
53
+ :host => "127.0.0.1",
54
+ :port => NodeName::DEFAULT_PORT,
55
+ :tag => NodeName::DEFAULT_TAG,
56
+ :protocol => :droonga,
57
+ :timeout => 1,
58
+ :receiver_host => Socket.gethostname,
59
+ :receiver_port => 0,
60
+ }
61
+ end
62
+ end
63
+ end
64
+ end