droonga-engine 1.0.8 → 1.0.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e7b344e7b567ecc524d5f5cfb52ed6a67342a672
4
- data.tar.gz: 79ecc5c743f0f01f350a1855d55368dc024515a9
3
+ metadata.gz: f2574dab76722981c14a23373e838f1e01d18220
4
+ data.tar.gz: 9776825164dda315f20af0f0d610d2391cce93fd
5
5
  SHA512:
6
- metadata.gz: 1f94a76e05f59f76bbd6e92774bd928c10a01c8c731df1e9b548a0b255b61abfab538e3c374d1e1fd74244639cb140d9913ee09649226a2226ad54d458afd0a2
7
- data.tar.gz: 343bf2deb3d726858be67b61f222689535b939ea1ecce9d564f8f69a474e41cd22190600cf95e0b2e42f3e609ff244f44fcd9fafc946901fb2a89197de33a0b7
6
+ metadata.gz: 55b359cab3e5ca1bd0b7008233c54bbf413d27b97ee8d179ca09be701fa4f2749935cb37eaf743bfb0099600794c80d319edce22bedde28b69f685d944c8f193
7
+ data.tar.gz: 09add0504d2886e51065af0c09a4d350db98c8fe07e9a6de6f317ca08af34971016f57c2ac3706d4317df110d125077045c8973c996f4bda382a187cd903ffa0
@@ -18,6 +18,7 @@
18
18
  require "ostruct"
19
19
  require "optparse"
20
20
  require "open3"
21
+ require "socket"
21
22
 
22
23
  require "droonga/engine/version"
23
24
  require "droonga/catalog_generator"
@@ -34,6 +35,7 @@ class AbsorbDataCommand
34
35
 
35
36
  puts "Start to absorb data from #{@options.source_host}"
36
37
  puts " to #{@options.destination_host}"
38
+ puts " via #{@options.receiver_host} (this host)"
37
39
  puts " dataset = #{@options.dataset}"
38
40
  puts " port = #{@options.port}"
39
41
  puts " tag = #{@options.tag}"
@@ -57,6 +59,7 @@ class AbsorbDataCommand
57
59
  options.tag = Droonga::CatalogGenerator::DEFAULT_TAG
58
60
  options.dataset = Droonga::CatalogGenerator::DEFAULT_DATASET
59
61
  options.remote = true
62
+ options.receiver_host = Socket.gethostname
60
63
  options.messages_per_second = Droonga::DataAbsorber::DEFAULT_MESSAGES_PER_SECOND
61
64
  parser = OptionParser.new
62
65
  parser.version = Droonga::Engine::VERSION
@@ -71,6 +74,11 @@ class AbsorbDataCommand
71
74
  "Host name of this cluster to be connected.") do |host|
72
75
  options.destination_host = host
73
76
  end
77
+ parser.on("--receiver-host=HOST",
78
+ "Host name of this computer.",
79
+ "(#{options.receiver_host})") do |host|
80
+ options.receiver_host = host
81
+ end
74
82
  parser.on("--port=PORT", Integer,
75
83
  "Port number of the source cluster to be connected.",
76
84
  "(#{options.port})") do |port|
@@ -139,6 +147,7 @@ class AbsorbDataCommand
139
147
  :dataset => @options.dataset,
140
148
  :source_host => @options.source_host,
141
149
  :destination_host => @options.destination_host,
150
+ :receiver_host => @options.receiver_host,
142
151
  :port => @options.port,
143
152
  :tag => @options.tag,
144
153
  :messages_per_second => @options.messages_per_second,
@@ -18,6 +18,7 @@
18
18
  require "slop"
19
19
  require "json"
20
20
  require "pathname"
21
+ require "socket"
21
22
 
22
23
  require "droonga/engine/version"
23
24
  require "droonga/path"
@@ -30,6 +31,12 @@ class JoinCommand
30
31
  def run
31
32
  parse_options
32
33
  trap_signals
34
+
35
+ puts "Start to join a new node #{@options[:host]}"
36
+ puts " to the cluster of #{@options["replica-source-host"]}"
37
+ puts " via #{@options["receiver-host"]} (this host)"
38
+ puts ""
39
+
33
40
  set_node_role
34
41
  do_join
35
42
  sleep(5) #TODO: wait for restarting of the joining node. this should be done more safely.
@@ -54,6 +61,9 @@ class JoinCommand
54
61
  option.on("replica-source-host=",
55
62
  "Host name of the soruce node in the cluster to be connected.",
56
63
  :required => true)
64
+ option.on("receiver-host=",
65
+ "Host name of this host.",
66
+ :default => Socket.gethostname)
57
67
  option.on(:dataset=,
58
68
  "Dataset name of for the node to be joined.",
59
69
  :default => Droonga::CatalogGenerator::DEFAULT_DATASET)
@@ -101,6 +111,7 @@ class JoinCommand
101
111
  :dataset => @options[:dataset],
102
112
  :source_host => @options["replica-source-host"],
103
113
  :destination_host => @options[:host],
114
+ :receiver_host => @options["receiver-host"],
104
115
  :port => @options[:port],
105
116
  :tag => @options[:tag],
106
117
  :messages_per_second => @options["records-per-second"],
@@ -15,96 +15,121 @@
15
15
  # License along with this library; if not, write to the Free Software
16
16
  # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
- require "ostruct"
19
- require "optparse"
18
+ require "slop"
20
19
  require "json"
21
20
  require "pathname"
22
21
 
23
22
  require "droonga/engine/version"
24
23
  require "droonga/path"
24
+ require "droonga/catalog_fetcher"
25
25
  require "droonga/catalog_generator"
26
- require "droonga/safe_file_writer"
27
- require "droonga/service_installation"
28
26
  require "droonga/serf"
29
27
 
30
- service_installation = Droonga::ServiceInstallation.new
31
- service_installation.ensure_using_service_base_directory
32
-
33
- options = OpenStruct.new
34
- options.base_dir = ENV[Droonga::Path::BASE_DIR_ENV_NAME] || Dir.pwd
35
-
36
- parser = OptionParser.new
37
- parser.version = Droonga::Engine::VERSION
38
-
39
- parser.on("--base-dir=PATH",
40
- "Path to the base directory the catalog.json is located in.",
41
- "(#{options.base_dir})") do |path|
42
- options.base_dir = path
43
- end
44
- parser.on("--host=HOST",
45
- "Host name of the replica removed from cluster.") do |host|
46
- options.replica_remove_host = host
47
- end
48
-
49
- parser.parse!(ARGV)
50
-
51
-
52
- base_dir = Pathname(options.base_dir).expand_path
53
- ENV[Droonga::Path::BASE_DIR_ENV_NAME] = base_dir.to_s
54
-
55
-
56
- catalog_path = Droonga::Path.catalog
57
- unless catalog_path.exist?
58
- raise "Cannot load 'catalog.json'. You must specify correct path " +
59
- "to the base directory via --base-dir option."
60
- end
61
-
62
- unless options.replica_remove_host
63
- raise "You must specify the host name or the IP address of a node to " +
64
- "be removed from the cluster via --replica-remove-host option."
65
- end
66
-
67
- unless service_installation.have_read_permission?
68
- puts("You have no permission to read files under " +
69
- "<#{Droonga::Path.base.to_s}>.")
70
- puts("Try again with right permission.")
71
- exit(false)
72
- end
73
-
74
- source_catalog = JSON.parse(catalog_path.read)
75
- generator = Droonga::CatalogGenerator.new
76
- generator.load(source_catalog)
77
-
78
- dataset = generator.dataset_for_host(options.replica_remove_host)
79
- unless dataset
80
- raise "Specified host #{options.replica_remove_host} is not a member of "+
81
- "the cluster. You must specify correct host via --replica-remove-host " +
82
- "option."
28
+ class UnjoinCommand
29
+ def run
30
+ parse_options
31
+
32
+ puts "Start to unjoin a node #{@options[:host]}"
33
+ puts " by #{@options["receiver-host"]} (this host)"
34
+ puts ""
35
+
36
+ do_unjoin
37
+
38
+ puts("Done.")
39
+ exit(true)
40
+ end
41
+
42
+ private
43
+ def parse_options
44
+ options = Slop.parse(:help => true) do |option|
45
+ option.on(:host=,
46
+ "Host name of the replica removed from cluster.",
47
+ :required => true)
48
+ option.on("receiver-host=",
49
+ "Host name of this host.",
50
+ :default => Socket.gethostname)
51
+ option.on(:dataset=,
52
+ "Dataset name of for the node to be unjoined.",
53
+ :default => Droonga::CatalogGenerator::DEFAULT_DATASET)
54
+ option.on(:port=,
55
+ "Port number of the source cluster to be connected.",
56
+ :as => Integer,
57
+ :default => Droonga::CatalogGenerator::DEFAULT_PORT)
58
+ option.on(:tag=,
59
+ "Tag name of the soruce cluster to be connected.",
60
+ :default => Droonga::CatalogGenerator::DEFAULT_TAG)
61
+ end
62
+ @options = options
63
+ rescue Slop::MissingOptionError => error
64
+ $stderr.puts(error)
65
+ exit(false)
66
+ end
67
+
68
+ def replica_remove_host
69
+ @options[:host]
70
+ end
71
+
72
+ def tag
73
+ @options[:tag]
74
+ end
75
+
76
+ def port
77
+ @options[:port]
78
+ end
79
+
80
+ def dataset_name
81
+ @options[:dataset]
82
+ end
83
+
84
+ def replica_remove_node
85
+ "#{replica_remove_host}:#{port}/#{tag}"
86
+ end
87
+
88
+ def fetch_catalog
89
+ fetcher = Droonga::CatalogFetcher.new(:host => replica_remove_host,
90
+ :port => port,
91
+ :tag => tag,
92
+ :receiver_host => @options["receiver-host"])
93
+ fetcher.fetch(:dataset => dataset_name)
94
+ end
95
+
96
+ def remaining_node
97
+ @remaining_node ||= detect_remaining_node
98
+ end
99
+
100
+ def detect_remaining_node
101
+ catalog = fetch_catalog
102
+ generator = Droonga::CatalogGenerator.new
103
+ generator.load(catalog)
104
+
105
+ dataset = generator.dataset_for_host(replica_remove_host)
106
+ unless dataset
107
+ raise "Specified host #{replica_remove_host} is not a member of "+
108
+ "the cluster. You must specify correct host via --replica-remove-host " +
109
+ "option."
110
+ end
111
+
112
+ other_hosts = dataset.replicas.hosts
113
+
114
+ remaining_host = other_hosts.first || replica_remove_host
115
+ "#{remaining_host}:#{port}/#{tag}"
116
+ end
117
+
118
+ def run_remote_command(target, command, options)
119
+ serf = Droonga::Serf.new(nil, target)
120
+ result = serf.send_query(command, options)
121
+ puts(result[:result])
122
+ puts(result[:error]) unless result[:error].empty?
123
+ result[:response]
124
+ end
125
+
126
+ def do_unjoin
127
+ puts "Unjoining replica from the cluster..."
128
+
129
+ run_remote_command(remaining_node, "unjoin",
130
+ "dataset" => dataset_name,
131
+ "hosts" => [replica_remove_host])
132
+ end
83
133
  end
84
134
 
85
- options.dataset = dataset.name
86
- options.tag = dataset.replicas.tag
87
- options.port = dataset.replicas.port
88
- options.other_hosts = dataset.replicas.hosts
89
-
90
- remaining_host = options.other_hosts.first || options.replica_remove_host
91
- options.remaining_node = "#{remaining_host}:#{options.port}/#{options.tag}"
92
-
93
-
94
- def run_remote_command(target, command, options)
95
- serf = Droonga::Serf.new(nil, target)
96
- result = serf.send_query(command, options)
97
- puts result[:result]
98
- puts result[:error] unless result[:error].empty?
99
- end
100
-
101
-
102
- puts "Unjoining replica from the cluster..."
103
-
104
- run_remote_command(options.remaining_node, "remove_replicas",
105
- "dataset" => options.dataset,
106
- "hosts" => [options.replica_remove_host])
107
-
108
- puts "Done."
109
-
110
- exit(true)
135
+ UnjoinCommand.new.run
@@ -38,7 +38,7 @@ Gem::Specification.new do |gem|
38
38
  gem.add_dependency "archive-zip"
39
39
  gem.add_dependency "cool.io"
40
40
  gem.add_dependency "drndump"
41
- gem.add_dependency "droonga-client", ">= 0.2.0"
41
+ gem.add_dependency "droonga-client", ">= 0.1.9"
42
42
  gem.add_dependency "droonga-message-pack-packer", ">= 1.0.2"
43
43
  gem.add_dependency "groonga-command-parser"
44
44
  gem.add_dependency "faraday"
@@ -16,6 +16,7 @@
16
16
  require "digest/sha1"
17
17
  require "zlib"
18
18
  require "time"
19
+ require "digest"
19
20
  require "droonga/error_messages"
20
21
  require "droonga/catalog/errors"
21
22
 
@@ -37,7 +38,16 @@ module Droonga
37
38
  datasets[name]
38
39
  end
39
40
 
41
+ def cluster_id
42
+ @cluster_id ||= calculate_cluster_id
43
+ end
44
+
40
45
  private
46
+ def calculate_cluster_id
47
+ raw_id = all_nodes.sort.join(",")
48
+ Digest::SHA1.hexdigest(raw_id)
49
+ end
50
+
41
51
  def migrate_database_location(current_db_path, device, name)
42
52
  return if current_db_path.exist?
43
53
 
@@ -13,6 +13,8 @@
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"
17
+
16
18
  require "droonga/client"
17
19
 
18
20
  require "droonga/address"
@@ -43,7 +45,7 @@ module Droonga
43
45
  :tag => Address::DEFAULT_TAG,
44
46
  :protocol => :droonga,
45
47
  :timeout => 1,
46
- :receiver_host => "127.0.0.1",
48
+ :receiver_host => Socket.gethostname,
47
49
  :receiver_port => 0,
48
50
  }
49
51
  end
@@ -382,6 +382,7 @@ module Droonga
382
382
  catalog_observer = FileObserver.new(@loop, Path.catalog)
383
383
  catalog_observer.on_change = lambda do
384
384
  restart_graceful
385
+ @serf.update_cluster_id if @serf and @serf.running?
385
386
  end
386
387
  catalog_observer.start
387
388
  catalog_observer
@@ -327,7 +327,6 @@ module Droonga
327
327
  end
328
328
 
329
329
  @serf.join(*hosts)
330
- #XXX Now we should restart serf agent to remove unjoined nodes from the list of members...
331
330
  end
332
331
  end
333
332
 
@@ -359,8 +358,28 @@ module Droonga
359
358
  modifier.datasets[dataset].replicas.hosts -= hosts
360
359
  @service_installation.ensure_correct_file_permission(file)
361
360
  end
361
+ end
362
+ end
363
+
364
+ class Unjoin < ModifyReplicasBase
365
+ def process
366
+ return if dataset.nil? or hosts.nil?
367
+
368
+ log("unjoining replicas: #{hosts.join(",")}")
362
369
 
363
- #XXX Now we should restart serf agent to remove unjoined nodes from the list of members...
370
+ CatalogModifier.modify do |modifier, file|
371
+ if unjoining_node?
372
+ modifier.datasets[dataset].replicas.hosts = hosts
373
+ else
374
+ modifier.datasets[dataset].replicas.hosts -= hosts
375
+ end
376
+ @service_installation.ensure_correct_file_permission(file)
377
+ end
378
+ end
379
+
380
+ private
381
+ def unjoining_node?
382
+ hosts.include?(host)
364
383
  end
365
384
  end
366
385
 
@@ -77,6 +77,8 @@ module Droonga
77
77
  Remote::SetStatus
78
78
  when "join"
79
79
  Remote::Join
80
+ when "unjoin"
81
+ Remote::Unjoin
80
82
  when "set_replicas"
81
83
  Remote::SetReplicas
82
84
  when "add_replicas"
@@ -52,6 +52,7 @@ module Droonga
52
52
 
53
53
  @source_host = @params[:source_host]
54
54
  @destination_host = @params[:destination_host]
55
+ @receiver_host = @params[:receiver_host] || @destination_host
55
56
 
56
57
  @receiver_port = @params[:receiver_port]
57
58
  end
@@ -115,7 +116,7 @@ module Droonga
115
116
  :port => @port,
116
117
  :tag => @tag,
117
118
  :progocol => :droonga,
118
- :receiver_host => @destination_host,
119
+ :receiver_host => @receiver_host,
119
120
  :receiver_port => 0,
120
121
  }
121
122
  @source_client ||= Droonga::Client.new(options)
@@ -127,7 +128,7 @@ module Droonga
127
128
  :port => @port,
128
129
  :tag => @tag,
129
130
  :progocol => :droonga,
130
- :receiver_host => @destination_host,
131
+ :receiver_host => @receiver_host,
131
132
  :receiver_port => 0,
132
133
  }
133
134
  @destination_client ||= Droonga::Client.new(options)
@@ -152,7 +153,7 @@ module Droonga
152
153
  options += ["--port", @port]
153
154
  options += ["--tag", @tag]
154
155
  options += ["--dataset", @dataset]
155
- options += ["--receiver-host", @destination_host]
156
+ options += ["--receiver-host", @receiver_host]
156
157
  options += ["--receiver-port", @receiver_port] if @receiver_port
157
158
  options.collect(&:to_s)
158
159
  end
@@ -162,7 +163,7 @@ module Droonga
162
163
  options += ["--host", @destination_host]
163
164
  options += ["--port", @port]
164
165
  options += ["--tag", @tag]
165
- options += ["--receiver-host", @destination_host]
166
+ options += ["--receiver-host", @receiver_host]
166
167
  options += ["--receiver-port", @receiver_port] if @receiver_port
167
168
  options.collect(&:to_s)
168
169
  end
@@ -252,7 +253,7 @@ module Droonga
252
253
  fetcher = CatalogFetcher.new(:host => @source_host,
253
254
  :port => @port,
254
255
  :tag => @tag,
255
- :receiver_host => @destination_host)
256
+ :receiver_host => @receiver_host)
256
257
  fetcher.fetch(:dataset => @dataset)
257
258
  end
258
259
 
@@ -15,6 +15,6 @@
15
15
 
16
16
  module Droonga
17
17
  class Engine
18
- VERSION = "1.0.8"
18
+ VERSION = "1.0.9"
19
19
  end
20
20
  end
data/lib/droonga/serf.rb CHANGED
@@ -71,6 +71,7 @@ module Droonga
71
71
  "-event-handler", "droonga-engine-serf-event-handler",
72
72
  "-log-level", log_level,
73
73
  "-tag", "role=engine",
74
+ "-tag", "cluster_id=#{cluster_id}",
74
75
  *retry_joins)
75
76
  logger.trace("start: done")
76
77
  end
@@ -87,6 +88,13 @@ module Droonga
87
88
  logger.trace("stop: done")
88
89
  end
89
90
 
91
+ def restart
92
+ logger.trace("restart: start")
93
+ stop
94
+ start
95
+ logger.trace("restart: done")
96
+ end
97
+
90
98
  def join(*hosts)
91
99
  ensure_serf
92
100
  nodes = hosts.collect do |host|
@@ -123,8 +131,10 @@ module Droonga
123
131
  result = run_once("members", "-format", "json")
124
132
  result[:result] = JSON.parse(result[:result])
125
133
  members = result[:result]
134
+ current_cluster_id = cluster_id
126
135
  members["members"].each do |member|
127
- if member["status"] == "alive"
136
+ if member["status"] == "alive" and
137
+ member["tags"]["cluster_id"] == current_cluster_id
128
138
  nodes[member["name"]] = {
129
139
  "serfAddress" => member["addr"],
130
140
  "tags" => member["tags"],
@@ -134,6 +144,21 @@ module Droonga
134
144
  nodes
135
145
  end
136
146
 
147
+ def set_tag(name, value)
148
+ ensure_serf
149
+ run_once("tags", "-set", "#{name}=#{value}")
150
+ end
151
+
152
+ def update_cluster_id
153
+ set_tag("cluster_id", cluster_id)
154
+ end
155
+
156
+ def cluster_id
157
+ loader = CatalogLoader.new(Path.catalog.to_s)
158
+ catalog = loader.load
159
+ catalog.cluster_id
160
+ end
161
+
137
162
  private
138
163
  def ensure_serf
139
164
  @serf = find_system_serf
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: droonga-engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.8
4
+ version: 1.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Droonga Project
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-28 00:00:00.000000000 Z
11
+ date: 2014-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: archive-zip
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.2.0
61
+ version: 0.1.9
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.2.0
68
+ version: 0.1.9
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: droonga-message-pack-packer
71
71
  requirement: !ruby/object:Gem::Requirement