droonga-engine 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/bin/droonga-engine-absorb-data +2 -1
  3. data/bin/droonga-engine-catalog-generate +21 -5
  4. data/bin/droonga-engine-catalog-modify +22 -6
  5. data/bin/droonga-engine-configure +215 -0
  6. data/bin/droonga-engine-join +48 -123
  7. data/bin/droonga-engine-unjoin +14 -1
  8. data/doc/text/news.md +21 -0
  9. data/droonga-engine.gemspec +12 -10
  10. data/install/centos/droonga-engine +60 -0
  11. data/install/centos/functions.sh +35 -0
  12. data/install/debian/droonga-engine +155 -0
  13. data/install/debian/functions.sh +33 -0
  14. data/install.sh +360 -0
  15. data/lib/droonga/address.rb +3 -1
  16. data/lib/droonga/catalog/dataset.rb +2 -0
  17. data/lib/droonga/catalog/version1.rb +16 -3
  18. data/lib/droonga/catalog/version2.rb +16 -3
  19. data/lib/droonga/catalog_fetcher.rb +51 -0
  20. data/lib/droonga/catalog_generator.rb +6 -5
  21. data/lib/droonga/catalog_modifier.rb +45 -0
  22. data/lib/droonga/command/droonga_engine.rb +96 -29
  23. data/lib/droonga/command/droonga_engine_service.rb +5 -0
  24. data/lib/droonga/command/remote.rb +368 -0
  25. data/lib/droonga/command/serf_event_handler.rb +37 -304
  26. data/lib/droonga/dispatcher.rb +15 -1
  27. data/lib/droonga/engine/version.rb +1 -1
  28. data/lib/droonga/engine.rb +11 -4
  29. data/lib/droonga/engine_state.rb +2 -0
  30. data/lib/droonga/farm.rb +14 -5
  31. data/lib/droonga/fluent_message_receiver.rb +23 -6
  32. data/lib/droonga/fluent_message_sender.rb +5 -1
  33. data/lib/droonga/node_status.rb +67 -0
  34. data/lib/droonga/path.rb +28 -4
  35. data/lib/droonga/plugins/catalog.rb +40 -0
  36. data/lib/droonga/safe_file_writer.rb +1 -1
  37. data/lib/droonga/searcher.rb +3 -15
  38. data/lib/droonga/serf.rb +17 -32
  39. data/lib/droonga/serf_downloader.rb +26 -1
  40. data/lib/droonga/service_installation.rb +123 -0
  41. data/lib/droonga/session.rb +4 -0
  42. data/lib/droonga/slice.rb +22 -12
  43. data/lib/droonga/supervisor.rb +16 -2
  44. data/lib/droonga/worker_process_agent.rb +13 -1
  45. data/sample/droonga-engine.yaml +5 -0
  46. data/test/command/config/default/catalog.json +1 -1
  47. data/test/command/config/default/droonga-engine.yaml +4 -0
  48. data/test/command/config/version1/catalog.json +1 -1
  49. data/test/command/suite/catalog/fetch.expected +64 -0
  50. data/test/command/suite/catalog/fetch.test +6 -0
  51. data/test/unit/catalog/test_version1.rb +2 -2
  52. data/test/unit/catalog/test_version2.rb +3 -3
  53. data/test/unit/helper/sandbox.rb +3 -1
  54. data/test/unit/plugins/catalog/test_fetch.rb +76 -0
  55. data/test/unit/test_catalog_generator.rb +7 -3
  56. metadata +74 -27
  57. data/bin/droonga-engine-data-publisher +0 -66
data/lib/droonga/path.rb CHANGED
@@ -34,6 +34,10 @@ module Droonga
34
34
  ENV[BASE_DIR_ENV_NAME] = new_base
35
35
  end
36
36
 
37
+ def databases
38
+ base + "database"
39
+ end
40
+
37
41
  def state
38
42
  base + "state"
39
43
  end
@@ -50,18 +54,38 @@ module Droonga
50
54
  state + "effective-message.timestamp"
51
55
  end
52
56
 
57
+ def config
58
+ base + "droonga-engine.yaml"
59
+ end
60
+
61
+ def default_pid_file
62
+ base + "droonga-engine.pid"
63
+ end
64
+
65
+ def default_log_file
66
+ base + "droonga-engine.log"
67
+ end
68
+
53
69
  def catalog
54
70
  base_file_name = ENV["DROONGA_CATALOG"] || "catalog.json"
55
71
  Pathname.new(base_file_name).expand_path(base)
56
72
  end
57
73
 
58
- def published(suffix)
59
- base + "published-#{suffix}"
60
- end
61
-
62
74
  def buffer
63
75
  state + "buffer"
64
76
  end
77
+
78
+ def serf_event_handler_errors
79
+ state + "serf-event-handler-errors"
80
+ end
81
+
82
+ def serf_event_handler_error_file
83
+ now = Time.now
84
+ name = sprintf("%04d-%02d-%02d_%02d-%02d-%02d.%d.error",
85
+ now.year, now.month, now.day,
86
+ now.hour, now.min, now.sec, now.nsec)
87
+ serf_event_handler_errors + name
88
+ end
65
89
  end
66
90
  end
67
91
  end
@@ -0,0 +1,40 @@
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 "droonga/plugin"
17
+ require "droonga/path"
18
+
19
+ module Droonga
20
+ module Plugins
21
+ module Catalog
22
+ extend Plugin
23
+ register("catalog")
24
+
25
+ class FetchHandler < Droonga::Handler
26
+ action.synchronous = false
27
+
28
+ def handle(message)
29
+ JSON.parse(Path.catalog.read)
30
+ end
31
+ end
32
+
33
+ define_single_step do |step|
34
+ step.name = "catalog.fetch"
35
+ step.handler = FetchHandler
36
+ step.collector = Collectors::Or
37
+ end
38
+ end
39
+ end
40
+ end
@@ -26,7 +26,7 @@ module Droonga
26
26
  FileUtils.mkdir_p(path.dirname.to_s)
27
27
  Tempfile.open(path.basename.to_s, path.dirname.to_s, "w") do |output|
28
28
  if block_given?
29
- yield(output)
29
+ yield(output, output.path)
30
30
  else
31
31
  output.write(contents)
32
32
  end
@@ -82,26 +82,14 @@ module Droonga
82
82
  def search(queries)
83
83
  outputs = nil
84
84
  logger.trace("search: start", :queries => queries)
85
- # TODO: THIS IS JUST A WORKAROUND! We should remove it ASAP!
86
- disable_gc do
87
- @context.push_memory_pool do
88
- outputs = process_queries(queries)
89
- end
85
+ @context.push_memory_pool do
86
+ outputs = process_queries(queries)
90
87
  end
91
88
  logger.trace("search: done")
92
- return outputs
89
+ outputs
93
90
  end
94
91
 
95
92
  private
96
- def disable_gc
97
- GC.disable
98
- begin
99
- yield
100
- ensure
101
- GC.enable
102
- end
103
- end
104
-
105
93
  def process_queries(queries)
106
94
  logger.trace("process_queries: start")
107
95
  if queries.nil? or queries.empty?
data/lib/droonga/serf.rb CHANGED
@@ -22,6 +22,7 @@ require "open3"
22
22
  require "droonga/path"
23
23
  require "droonga/loggable"
24
24
  require "droonga/catalog_loader"
25
+ require "droonga/node_status"
25
26
  require "droonga/serf_downloader"
26
27
  require "droonga/line_buffer"
27
28
 
@@ -43,32 +44,6 @@ module Droonga
43
44
  def path
44
45
  Droonga::Path.base + "serf"
45
46
  end
46
-
47
- def status_file
48
- Droonga::Path.state + "status_file"
49
- end
50
-
51
- def load_status
52
- if status_file.exist?
53
- contents = status_file.read
54
- unless contents.empty?
55
- return JSON.parse(contents, :symbolize_names => true)
56
- end
57
- end
58
- {}
59
- end
60
-
61
- def status(key)
62
- load_status[key]
63
- end
64
-
65
- def send_query(name, query, payload)
66
- new(nil, name).send_query(query, payload)
67
- end
68
-
69
- def live_nodes(name)
70
- new(nil, name).live_nodes
71
- end
72
47
  end
73
48
 
74
49
  include Loggable
@@ -111,11 +86,20 @@ module Droonga
111
86
  logger.trace("stop: done")
112
87
  end
113
88
 
89
+ def join(*hosts)
90
+ ensure_serf
91
+ nodes = hosts.collect do |host|
92
+ "#{host}:#{port}"
93
+ end
94
+ run_once("join", *nodes)
95
+ end
96
+
114
97
  def send_query(query, payload)
115
98
  ensure_serf
116
99
  options = ["-format", "json"] + additional_options_from_payload(payload)
117
100
  options += [query, JSON.generate(payload)]
118
101
  result = run_once("query", *options)
102
+ result[:result] = JSON.parse(result[:result])
119
103
  if payload["node"]
120
104
  responses = result[:result]["Responses"]
121
105
  response = responses[payload["node"]]
@@ -135,7 +119,8 @@ module Droonga
135
119
  def live_nodes
136
120
  ensure_serf
137
121
  nodes = {}
138
- result= run_once("members", "-format", "json")
122
+ result = run_once("members", "-format", "json")
123
+ result[:result] = JSON.parse(result[:result])
139
124
  members = result[:result]
140
125
  members["members"].each do |member|
141
126
  if member["status"] == "alive"
@@ -212,13 +197,13 @@ module Droonga
212
197
  "#{extract_host(@name)}:7373"
213
198
  end
214
199
 
215
- def status
216
- @status ||= self.class.load_status
200
+ def node_status
201
+ @node_status ||= NodeStatus.new
217
202
  end
218
203
 
219
204
  def role
220
- if status[:role]
221
- role = status[:role].to_sym
205
+ if node_status.have?(:role)
206
+ role = node_status.get(:role).to_sym
222
207
  if self.class::ROLE.key?(role)
223
208
  return role
224
209
  end
@@ -282,7 +267,7 @@ module Droonga
282
267
  def run_once
283
268
  stdout, stderror, status = Open3.capture3(@serf, @command, *@options, :pgroup => true)
284
269
  {
285
- :result => JSON.parse(stdout),
270
+ :result => stdout,
286
271
  :error => stderror,
287
272
  :status => status,
288
273
  }
@@ -27,8 +27,15 @@ module Droonga
27
27
  class SerfDownloader
28
28
  include Loggable
29
29
 
30
+ class DownloadFailed < StandardError
31
+ end
32
+
33
+ MAX_RETRY_COUNT = 5
34
+ RETRY_INTERVAL = 10
35
+
30
36
  def initialize(output_path)
31
37
  @output_path = output_path
38
+ @retry_count = 0
32
39
  end
33
40
 
34
41
  def download
@@ -49,6 +56,24 @@ module Droonga
49
56
  FileUtils.mv("#{dir}/serf", absolete_output_path.to_s)
50
57
  FileUtils.chmod(0755, absolete_output_path.to_s)
51
58
  end
59
+ rescue Archive::Zip::UnzipError => archive_error
60
+ logger.warn("Downloaded zip file is broken.")
61
+ if @retry_count < MAX_RETRY_COUNT
62
+ @retry_count += 1
63
+ sleep(RETRY_INTERVAL * @retry_count)
64
+ download
65
+ else
66
+ raise DownloadFailed.new("Couldn't download serf executable. Try it later.")
67
+ end
68
+ rescue Faraday::ConnectionFailed => network_error
69
+ logger.warn("Connection failed.")
70
+ if @retry_count < MAX_RETRY_COUNT
71
+ @retry_count += 1
72
+ sleep(RETRY_INTERVAL * @retry_count)
73
+ download
74
+ else
75
+ raise DownloadFailed.new("Couldn't download serf executable. Try it later.")
76
+ end
52
77
  end
53
78
 
54
79
  private
@@ -77,7 +102,7 @@ module Droonga
77
102
  when /x86_64|x64/
78
103
  @architecture = "amd64"
79
104
  when /i\d86/
80
- @architecture = "i386"
105
+ @architecture = "386"
81
106
  else
82
107
  raise "Unsupported architecture: #{RUBY_PLATFORM}"
83
108
  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
+ require "fileutils"
17
+
18
+ require "droonga/path"
19
+
20
+ module Droonga
21
+ class ServiceInstallation
22
+ class << self
23
+ end
24
+
25
+ class NotInstalledAsService < StandardError
26
+ end
27
+
28
+ def user_name
29
+ "droonga-engine"
30
+ end
31
+
32
+ def group_name
33
+ "droonga"
34
+ end
35
+
36
+ def base_directory
37
+ @base_directory ||= Pathname("/home/#{user_name}/droonga")
38
+ end
39
+
40
+ def ensure_using_service_base_directory
41
+ if user_exist?
42
+ Path.base = base_directory.to_s
43
+ end
44
+ end
45
+
46
+ def have_read_permission?
47
+ test_file = Path.config
48
+ begin
49
+ test_file.read
50
+ rescue Errno::EACCES => error
51
+ return false
52
+ end
53
+ true
54
+ end
55
+
56
+ def have_write_permission?
57
+ test_file = Path.base + "#{Time.now.to_i}.test"
58
+ begin
59
+ FileUtils.mkdir_p(Path.base)
60
+ FileUtils.touch(test_file.to_s)
61
+ rescue Errno::EACCES => error
62
+ end
63
+ unless test_file.exist?
64
+ return false
65
+ end
66
+ FileUtils.rm_f(test_file.to_s)
67
+ true
68
+ end
69
+
70
+ def user_exist?
71
+ system("id", user_name,
72
+ :out => "/dev/null",
73
+ :err => "/dev/null")
74
+ end
75
+
76
+ def installed_as_service?
77
+ return false unless user_exist?
78
+
79
+ #TODO: we should support systemd also...
80
+ succeeded = system("service", "droonga-engine", "status",
81
+ :out => "/dev/null",
82
+ :err => "/dev/null")
83
+ return true if succeeded
84
+
85
+ #TODO: we should support systemd also...
86
+ result = `service droonga-engine status`
87
+ result.include?("running") or \
88
+ result.include?("droonga-engine is stopped") or \
89
+ result.include?("droonga-engine dead")
90
+ end
91
+
92
+ def ensure_correct_file_permission(file)
93
+ if user_exist?
94
+ FileUtils.chown_R(user_name, group_name, file)
95
+ FileUtils.chmod_R("go+r", file)
96
+ end
97
+ end
98
+
99
+ def running?(pid_file_path=nil)
100
+ raise NotInstalledAsService.new unless installed_as_service?
101
+ #TODO: we should support systemd also...
102
+ system("service", "droonga-engine", "status",
103
+ :out => "/dev/null",
104
+ :err => "/dev/null")
105
+ end
106
+
107
+ def start
108
+ raise NotInstalledAsService.new unless installed_as_service?
109
+ #TODO: we should support systemd also...
110
+ system("service", "droonga-engine", "start",
111
+ :out => "/dev/null",
112
+ :err => "/dev/null")
113
+ end
114
+
115
+ def stop
116
+ raise NotInstalledAsService.new unless installed_as_service?
117
+ #TODO: we should support systemd also...
118
+ system("service", "droonga-engine", "stop",
119
+ :out => "/dev/null",
120
+ :err => "/dev/null")
121
+ end
122
+ end
123
+ end
@@ -13,8 +13,12 @@
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 "droonga/loggable"
17
+
16
18
  module Droonga
17
19
  class Session
20
+ include Loggable
21
+
18
22
  def initialize(id, dispatcher, collector_runner, tasks, inputs)
19
23
  @id = id
20
24
  @dispatcher = dispatcher
data/lib/droonga/slice.rb CHANGED
@@ -24,7 +24,7 @@ module Droonga
24
24
  class Slice
25
25
  include Loggable
26
26
 
27
- attr_accessor :on_ready
27
+ attr_writer :on_ready
28
28
  def initialize(dataset, loop, options={})
29
29
  @dataset = dataset
30
30
  @loop = loop
@@ -44,12 +44,29 @@ module Droonga
44
44
  start_supervisor
45
45
  end
46
46
 
47
- def shutdown
48
- logger.trace("shutdown: start")
49
- shutdown_supervisor if @supervisor
47
+ def stop_gracefully
48
+ logger.trace("stop_gracefully: start")
49
+ on_stop = lambda do
50
+ @job_pusher.shutdown
51
+ @processor.shutdown
52
+ yield if block_given?
53
+ end
54
+ if @supervisor
55
+ @supervisor.stop_gracefully do
56
+ on_stop.call
57
+ end
58
+ else
59
+ on_stop.call
60
+ end
61
+ logger.trace("stop_gracefully: done")
62
+ end
63
+
64
+ def stop_immediately
65
+ logger.trace("stop_immediately: start")
66
+ @supervisor.stop_immediately if @supervisor
50
67
  @job_pusher.shutdown
51
68
  @processor.shutdown
52
- logger.trace("shutdown: done")
69
+ logger.trace("stop_immediately: done")
53
70
  end
54
71
 
55
72
  def process(message)
@@ -106,13 +123,6 @@ module Droonga
106
123
  @supervisor.start
107
124
  end
108
125
 
109
- def shutdown_supervisor
110
- logger.trace("supervisor: shutdown: start")
111
- @supervisor.stop_gracefully
112
- logger.trace("supervisor: shutdown: done")
113
- end
114
-
115
- private
116
126
  def on_ready
117
127
  @on_ready.call if @on_ready
118
128
  end
@@ -45,9 +45,18 @@ module Droonga
45
45
  end
46
46
 
47
47
  def stop_gracefully
48
+ logger.trace("stop_gracefully: start")
49
+ n_worker_runners = @worker_runners.size
50
+ n_done_worker_runners = 0
48
51
  @worker_runners.each do |worker_runner|
49
- worker_runner.stop_gracefully
52
+ worker_runner.stop_gracefully do
53
+ n_done_worker_runners += 1
54
+ if n_done_worker_runners == n_worker_runners
55
+ yield if block_given?
56
+ end
57
+ end
50
58
  end
59
+ logger.trace("stop_gracefully: done")
51
60
  end
52
61
 
53
62
  def stop_immediately
@@ -87,6 +96,7 @@ module Droonga
87
96
  @config = config
88
97
  @on_ready = nil
89
98
  @on_failure = nil
99
+ @stop_gracefully_callback = nil
90
100
  end
91
101
 
92
102
  def start
@@ -117,8 +127,11 @@ module Droonga
117
127
  @supervisor.start
118
128
  end
119
129
 
120
- def stop_gracefully
130
+ def stop_gracefully(&block)
131
+ logger.trace("stop_gracefully: start")
121
132
  @supervisor.stop_gracefully
133
+ @stop_gracefully_callback = block
134
+ logger.trace("stop_gracefully: done")
122
135
  end
123
136
 
124
137
  def stop_immediately
@@ -159,6 +172,7 @@ module Droonga
159
172
  @success = status.success?
160
173
  @supervisor.stop
161
174
  on_failure unless success?
175
+ @stop_gracefully_callback.call if @stop_gracefully_callback
162
176
  end
163
177
 
164
178
  private
@@ -17,10 +17,12 @@ require "coolio"
17
17
 
18
18
  require "droonga/process_control_protocol"
19
19
  require "droonga/line_buffer"
20
+ require "droonga/loggable"
20
21
 
21
22
  module Droonga
22
23
  class WorkerProcessAgent
23
24
  include ProcessControlProtocol
25
+ include Loggable
24
26
 
25
27
  def initialize(loop, input, output)
26
28
  @loop = loop
@@ -31,20 +33,26 @@ module Droonga
31
33
  end
32
34
 
33
35
  def start
36
+ logger.trace("start: start")
34
37
  @loop.attach(@input)
35
38
  @loop.attach(@output)
39
+ logger.trace("start: done")
36
40
  end
37
41
 
38
42
  def stop
43
+ logger.trace("stop: start")
39
44
  if @output
40
45
  @output, output = nil, @output
41
46
  output.write(Messages::FINISH)
42
- output.close
47
+ output.on_write_complete do
48
+ output.close
49
+ end
43
50
  end
44
51
  if @input
45
52
  @input, input = nil, @input
46
53
  input.close
47
54
  end
55
+ logger.trace("stop: done")
48
56
  end
49
57
 
50
58
  def ready
@@ -107,5 +115,9 @@ module Droonga
107
115
  def on_stop_immediately
108
116
  @on_stop_immediately.call if @on_stop_immediately
109
117
  end
118
+
119
+ def log_tag
120
+ "worker_process_agent"
121
+ end
110
122
  end
111
123
  end
@@ -0,0 +1,5 @@
1
+ host: 192.168.0.10
2
+ port: 10031
3
+ tag: droonga
4
+ log_file: droonga-engine.log
5
+ log_level: info
@@ -4,7 +4,7 @@
4
4
  "datasets": {
5
5
  "Default": {
6
6
  "nWorkers": 2,
7
- "plugins": ["groonga", "crud", "search", "dump", "system"],
7
+ "plugins": ["groonga", "crud", "search", "dump", "system", "catalog"],
8
8
  "replicas": [
9
9
  {
10
10
  "dimension": "_key",
@@ -0,0 +1,4 @@
1
+ host: 127.0.0.1
2
+ port: 10031
3
+ tag: droonga
4
+ daemon: false
@@ -11,7 +11,7 @@
11
11
  "datasets": {
12
12
  "Default": {
13
13
  "workers": 2,
14
- "plugins": ["groonga", "crud", "search", "dump", "system"],
14
+ "plugins": ["groonga", "crud", "search", "dump", "system", "catalog"],
15
15
  "number_of_replicas": 2,
16
16
  "number_of_partitions": 2,
17
17
  "partition_key": "_key",
@@ -0,0 +1,64 @@
1
+ {
2
+ "inReplyTo": "request-id",
3
+ "statusCode": 200,
4
+ "type": "catalog.fetch.result",
5
+ "body": {
6
+ "version": 2,
7
+ "effectiveDate": "2014-02-28T00:00:00Z",
8
+ "datasets": {
9
+ "Default": {
10
+ "nWorkers": 2,
11
+ "plugins": [
12
+ "groonga",
13
+ "crud",
14
+ "search",
15
+ "dump",
16
+ "system",
17
+ "catalog"
18
+ ],
19
+ "replicas": [
20
+ {
21
+ "dimension": "_key",
22
+ "slicer": "hash",
23
+ "slices": [
24
+ {
25
+ "label": "slice000",
26
+ "weight": 50,
27
+ "volume": {
28
+ "address": "127.0.0.1:23003/droonga.000"
29
+ }
30
+ },
31
+ {
32
+ "label": "slice001",
33
+ "weight": 50,
34
+ "volume": {
35
+ "address": "127.0.0.1:23003/droonga.001"
36
+ }
37
+ }
38
+ ]
39
+ },
40
+ {
41
+ "dimension": "_key",
42
+ "slicer": "hash",
43
+ "slices": [
44
+ {
45
+ "label": "slice010",
46
+ "weight": 50,
47
+ "volume": {
48
+ "address": "127.0.0.1:23003/droonga.010"
49
+ }
50
+ },
51
+ {
52
+ "label": "slice011",
53
+ "weight": 50,
54
+ "volume": {
55
+ "address": "127.0.0.1:23003/droonga.011"
56
+ }
57
+ }
58
+ ]
59
+ }
60
+ ]
61
+ }
62
+ }
63
+ }
64
+ }
@@ -0,0 +1,6 @@
1
+ #@require-catalog-version 2
2
+ {
3
+ "type": "catalog.fetch",
4
+ "dataset": "Default",
5
+ "body": {}
6
+ }