tyrantmanager 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.rdoc CHANGED
@@ -1,4 +1,9 @@
1
1
  = Changelog
2
+ == Version 1.4.0 2010-01-19
3
+
4
+ * add 'archive-ulogs' command to allow for compression or removal of ulogs no
5
+ longer needed for replication
6
+
2
7
  == Version 1.3.2 2010-01-04
3
8
 
4
9
  * update logging and main dependencies
@@ -109,6 +109,35 @@ class TyrantManager
109
109
  run { ::TyrantManager::Cli.run_command_with_params( 'list', params ) }
110
110
  }
111
111
 
112
+ mode( 'archive-ulogs' ) {
113
+ description "Archive the ulog files that are no longer necessary for replication"
114
+ mixin :option_home
115
+ mixin :option_log_level
116
+ mixin :argument_instances
117
+
118
+ option( 'archive-method' ) {
119
+ description "The method of archiving, compress, or delete. Choosing 'delete' will also delete previously 'compressed' ulog files."
120
+ argument :required
121
+ validate { |m| %w[ compress delete ].include?( m.downcase ) }
122
+ default "compress"
123
+ }
124
+
125
+ option( 'dry-run' ) {
126
+ description "Do not archive, just show the commands"
127
+ default false
128
+ }
129
+
130
+ option( 'slaves' ) {
131
+ description "Comma separated list of slave instances connection strings host:port,host:port,..."
132
+ argument :required
133
+ cast :list_of_string
134
+ }
135
+
136
+ run { ::TyrantManager::Cli.run_command_with_params( 'archive-ulogs', params ) }
137
+
138
+ }
139
+
140
+
112
141
  #--- Mixins ---
113
142
  mixin :option_home do
114
143
  option( :home ) do
@@ -117,3 +117,4 @@ require 'tyrant_manager/commands/status'
117
117
  require 'tyrant_manager/commands/stats'
118
118
  require 'tyrant_manager/commands/list'
119
119
  require 'tyrant_manager/commands/replication_status'
120
+ require 'tyrant_manager/commands/archive_ulogs'
@@ -0,0 +1,156 @@
1
+ require 'tyrant_manager/command'
2
+ require 'socket'
3
+
4
+ class TyrantManager
5
+ module Commands
6
+ #
7
+ # Archive ulog files that are no longer used for replication.
8
+ #
9
+ # You must give the list of slave connection strings on the commandline, or
10
+ # if the server is in a single master-master relationship, then you can
11
+ # allow tyrantmanager to figure that out and do the right thing.
12
+ #
13
+ # Give the slaves of a particular master
14
+ #
15
+ # tyrantmanager archive-ulogs master1 --slaves slave1:11011,slave2:11012,slave3:11013
16
+ #
17
+ # Or if there is a master-master relationship tyrant manager can figure it
18
+ # out.
19
+ #
20
+ # tyrantmanager archive-ulogs master1
21
+ #
22
+ #
23
+ class ArchiveUlogs < Command
24
+ def self.command_name
25
+ 'archive-ulogs'
26
+ end
27
+
28
+ def run
29
+ instance_slaves = determine_master_slave_mappings( options['slaves'] )
30
+
31
+ manager.each_instance( options['instances'] ) do |instance|
32
+ if instance.is_master_master? then
33
+ manager.logger.debug "#{instance.name} is master_master"
34
+ instance_slaves[instance.connection_string] << instance.master_connection
35
+ end
36
+ slave_connections = instance_slaves[instance.connection_string]
37
+
38
+ potential_removals = potential_ulog_archive_files( instance )
39
+ manager.logger.info "Checking #{slave_connections.size} slaves of #{instance.name}"
40
+
41
+ slave_connections.each do |conn|
42
+ potential_removals = trim_potential_removals( instance, potential_removals, conn )
43
+ end
44
+
45
+ archive_files_with_method( potential_removals.keys.sort, options['archive-method'] )
46
+
47
+ end
48
+ end
49
+
50
+ #
51
+ # Archive each of the files in the list with the given method
52
+ #
53
+ def archive_files_with_method( list, method )
54
+ list.each do |fname|
55
+ leader = (options['dry-run']) ? "(dry-run)" : ""
56
+ if "delete" == method then
57
+ File.unlink( fname ) unless options['dry-run']
58
+ manager.logger.info "deleted #{leader} #{fname}"
59
+ else
60
+ if File.extname( fname ) == ".ulog" then
61
+ %x[ gzip #{fname} ] unless options['dry-run']
62
+ manager.logger.info "#{leader} compressed #{fname}"
63
+ else
64
+ manager.logger.info "#{leader} already compressed #{fname}"
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ #
71
+ # Remove all items from the potential removals list that have a timestamp
72
+ # that is newer than the last replication timestamp of the tyrant
73
+ # connection
74
+ #
75
+ def trim_potential_removals( master_instance, potential, slave_conn )
76
+ slave_stat = slave_conn.stat
77
+ milliseconds = Float( slave_stat['rts'] )
78
+ last_replication_at = Time.at( milliseconds / 1_000_000 )
79
+
80
+ manager.logger.debug "Slave #{slave_conn.host}:#{slave_conn.port} last replicated at #{last_replication_at.strftime("%Y-%m-%d %H:%M:%S")} from #{master_instance.connection_string}"
81
+
82
+ if milliseconds.to_i == 0 then
83
+ manager.logger.warn "It appears that the slave at #{slave_conn.host}:#{slave_conn.port} has never replicated"
84
+ manager.logger.warn "This means that no ulogs on the master will be removed, since there is no evidence of replication."
85
+ manager.logger.warn "It may be necessary to force a replication by inserting a record into the master:"
86
+ manager.logger.warn ""
87
+ manager.logger.warn " tcrmgr put -port #{master_instance.configuration.port} #{master_instance.configuration.host} __tyrant_manager.force_replication_at #{Time.now.utc.to_i}"
88
+ manager.logger.warn ""
89
+ manager.logger.warn "And then removing that record if you so choose:"
90
+ manager.logger.warn ""
91
+ manager.logger.warn " tcrmgr out -port #{master_instance.configuration.port} #{master_instance.configuration.host} __tyrant_manager.force_replication_at"
92
+ manager.logger.warn ""
93
+ end
94
+
95
+ manager.logger.debug "Trimming ulog files that are newer than #{last_replication_at.strftime("%Y-%m-%d %H:%M:%S")}"
96
+
97
+ trimmed_potential = remove_newer_than( potential, last_replication_at )
98
+ end
99
+
100
+ #
101
+ # Filter all the ulogs from the list whose value is greater than the input
102
+ # time.
103
+ #
104
+ def remove_newer_than( potential, whence )
105
+ potential.keys.sort.each do |fname|
106
+ if potential[fname] > whence then
107
+ potential.delete( fname )
108
+ end
109
+ end
110
+ return potential
111
+ end
112
+
113
+ #
114
+ # The list of potential files to remove from the ulog directory. This is
115
+ # all the files in the ulog directory, minus the last one lexically.
116
+ #
117
+ # A hash of filename => File.mtime values is returned
118
+ #
119
+ def potential_ulog_archive_files( instance )
120
+ names = instance.ulog_files[0..-2]
121
+ names += Dir.glob( "#{instance.ulog_dir}/*.ulog.gz" )
122
+ potential = {}
123
+ names.each do |name|
124
+ potential[name] = File.mtime( name )
125
+ end
126
+ return potential
127
+ end
128
+
129
+ # Given a list of slaves, create a hash that has as the key, the instance
130
+ # connection string of a master, as as the value, an array of
131
+ # Rufus::Tokyo::Tyrant connections.
132
+ #
133
+ def determine_master_slave_mappings( list_of_slaves )
134
+ master_to_slaves = Hash.new{ |h,k| h[k] = [] }
135
+
136
+ list_of_slaves ||= []
137
+ list_of_slaves.each do |connection_string|
138
+ host, port = connection_string.split(":")
139
+ conn = Rufus::Tokyo::Tyrant.new( host, port.to_i )
140
+ stat = conn.stat
141
+ master_host = stat['mhost']
142
+ master_port = stat['mport']
143
+ if master_host and master_port then
144
+ master_to_slaves["#{master_host}:#{master_port}"] << conn
145
+ else
146
+ manager.logger.warn "Slave #{connection_string} does not have a master server configured, skipping using it as a slave"
147
+ end
148
+ end
149
+
150
+ return master_to_slaves
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+
@@ -7,20 +7,17 @@ class TyrantManager
7
7
  #
8
8
  class List < Command
9
9
  def run
10
- manager.each_instance do |instance|
11
- ilist = options['instances']
12
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
13
- parts = []
14
- parts << ("%20s" % instance.name)
15
- parts << "port #{instance.configuration.port}"
16
- parts << instance.home_dir
10
+ manager.each_instance( options['instances'] ) do |instance|
11
+ parts = []
12
+ parts << ("%20s" % instance.name)
13
+ parts << "port #{instance.configuration.port}"
14
+ parts << instance.home_dir
17
15
 
18
- if instance.configuration.master_server then
19
- parts << "server id #{"%2d" % instance.configuration.server_id}"
20
- parts << "replicating from #{instance.configuration.master_server}:#{instance.configuration.master_port}"
21
- end
22
- puts parts.join(" : ")
16
+ if instance.configuration.master_server then
17
+ parts << "server id #{"%2d" % instance.configuration.server_id}"
18
+ parts << "replicating from #{instance.configuration.master_server}:#{instance.configuration.master_port}"
23
19
  end
20
+ puts parts.join(" : ")
24
21
  end
25
22
  end
26
23
  end
@@ -12,12 +12,10 @@ class TyrantManager
12
12
  end
13
13
 
14
14
  def run
15
- manager.each_instance do |instance|
16
- ilist = options['instances']
17
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
18
- if instance.running? and instance.is_slave? then
19
- s_stat = instance.stat
20
- logger.info "#{instance.name} is replicating from #{s_stat['mhost']}:#{s_stat['mport']}"
15
+ manager.each_instance( options['instances'] ) do |instance|
16
+ if instance.running? and instance.is_slave? then
17
+ s_stat = instance.stat
18
+ logger.info "#{instance.name} is replicating from #{s_stat['mhost']}:#{s_stat['mport']}"
21
19
  if m_conn = validate_master_connection( instance ) then
22
20
  if validate_master_master( instance.connection, m_conn ) then
23
21
  m_stat = m_conn.stat
@@ -30,10 +28,10 @@ class TyrantManager
30
28
  end
31
29
 
32
30
  p_stat = primary.stat
33
- p_name = "#{ip_of( primary.host )}:#{primary.port}"
31
+ p_name = "#{manager.ip_of( primary.host )}:#{primary.port}"
34
32
 
35
33
  f_stat = failover.stat
36
- f_name = "#{ip_of( failover.host )}:#{failover.port}"
34
+ f_name = "#{manager.ip_of( failover.host )}:#{failover.port}"
37
35
 
38
36
  n_width = [ p_name.length, f_name.length ].max
39
37
 
@@ -41,8 +39,7 @@ class TyrantManager
41
39
  logger.info " Failover master : #{f_name} -> #{f_stat['rnum']} records, last replicated #{failover.stat['delay']} seconds ago"
42
40
  end
43
41
  end
44
- logger.info ""
45
- end
42
+ logger.info ""
46
43
  end
47
44
  end
48
45
  end
@@ -55,26 +52,20 @@ class TyrantManager
55
52
 
56
53
  if ( m_stat['mhost'] and m_stat['mport'] ) then
57
54
  logger.info " #{s_stat['mhost']}:#{s_stat['mport']} is replicating from #{m_stat['mhost']}:#{m_stat['mport']}"
58
- mm_ip = ip_of( m_stat['mhost'] )
59
- s_ip = ip_of( slave.host )
55
+ mm_ip = manager.ip_of( m_stat['mhost'] )
56
+ s_ip = manager.ip_of( slave.host )
60
57
  if ( s_ip == mm_ip ) and ( slave.port == m_stat['mport'].to_i ) then
61
58
  #logger.info " - this is a good master-master relationship"
62
59
  return true
63
60
  else
64
61
  logger.error " Unsupported replication configuration!!!"
65
62
  logger.error " (original hostnames) #{slave.host}:#{slave.port} -> #{(master.host)}:#{master.port} -> #{m_stat['mhost']}:#{m_stat['mport']}"
66
- logger.error " (hostnames resolved) #{s_ip}:#{slave.port} -> #{ip_of(master.host)}:#{master.port} -> #{ip_of(m_stat['mhost'])}:#{m_stat['mport']}"
63
+ logger.error " (hostnames resolved) #{s_ip}:#{slave.port} -> #{manager.ip_of(master.host)}:#{master.port} -> #{manager.ip_of(m_stat['mhost'])}:#{m_stat['mport']}"
67
64
  return false
68
65
  end
69
66
  end
70
67
  end
71
68
 
72
- def ip_of( hostname )
73
- hostname = Socket.gethostname if %w[ localhost 0.0.0.0 ].include?( hostname )
74
- addr_info = Socket.getaddrinfo( hostname, 1978, "AF_INET" )
75
- return addr_info.first[3]
76
- end
77
-
78
69
  def validate_master_connection( slave )
79
70
  begin
80
71
  m_conn = slave.master_connection
@@ -6,24 +6,21 @@ class TyrantManager
6
6
  #
7
7
  class Start < Command
8
8
  def run
9
- manager.each_instance do |instance|
10
- ilist = options['instances']
11
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
12
- parts = [ "Starting #{instance.name}" ]
13
- parts << instance.start_command
9
+ manager.each_instance( options['instances'] ) do |instance|
10
+ parts = [ "Starting #{instance.name}" ]
11
+ parts << instance.start_command
14
12
 
15
- if options['dry-run'] then
16
- parts << "(dry-run)"
17
- logger.info parts.join(" : ")
13
+ if options['dry-run'] then
14
+ parts << "(dry-run)"
15
+ logger.info parts.join(" : ")
18
16
 
19
- elsif not instance.running? then
20
- logger.info parts.join(" : ")
21
- Dir.chdir( instance.home_dir ) do
22
- instance.start
23
- end
24
- else
25
- logger.info "Instance #{instance.name} already running"
17
+ elsif not instance.running? then
18
+ logger.info parts.join(" : ")
19
+ Dir.chdir( instance.home_dir ) do
20
+ instance.start
26
21
  end
22
+ else
23
+ logger.info "Instance #{instance.name} already running"
27
24
  end
28
25
  end
29
26
  end
@@ -6,17 +6,15 @@ class TyrantManager
6
6
  #
7
7
  class Stats < Command
8
8
  def run
9
- manager.each_instance do |instance|
10
- ilist = options['instances']
11
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
12
- puts "Instance #{instance.name} at #{instance.home_dir}"
13
- stats = instance.stat
14
- stats.keys.sort.each do |k|
15
- lhs = k.ljust(10, ".")
16
- puts " #{lhs} #{stats[k]}"
17
- end
18
- puts
9
+ manager.each_instance( options['instances'] ) do |instance|
10
+ puts "Instance #{instance.name} at #{instance.home_dir}"
11
+ stats = instance.stat
12
+ max_width = stats.keys.collect { |k| k.length }.sort.last + 2
13
+ stats.keys.sort.each do |k|
14
+ lhs = k.ljust(max_width, ".")
15
+ puts " #{lhs} #{stats[k]}"
19
16
  end
17
+ puts
20
18
  end
21
19
  end
22
20
  end
@@ -10,14 +10,11 @@ class TyrantManager
10
10
  end
11
11
 
12
12
  def run
13
- manager.each_instance do |instance|
14
- ilist = options['instances']
15
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
16
- if instance.running? then
17
- logger.info "#{instance.name} is running as pid #{instance.pid}"
18
- else
19
- logger.info "#{instance.name} is not running, or its pid file is gone"
20
- end
13
+ manager.each_instance( options['instances'] ) do |instance|
14
+ if instance.running? then
15
+ logger.info "#{instance.name} is running as pid #{instance.pid}"
16
+ else
17
+ logger.info "#{instance.name} is not running, or its pid file is gone"
21
18
  end
22
19
  end
23
20
  end
@@ -6,15 +6,12 @@ class TyrantManager
6
6
  #
7
7
  class Stop < Command
8
8
  def run
9
- manager.each_instance do |instance|
10
- ilist = options['instances']
11
- if ilist == %w[ all ] or ilist.include?( instance.name ) then
12
- if File.exist?( instance.pid_file ) then
13
- logger.info "Stopping #{instance.name} : pid #{instance.pid}"
14
- instance.stop
15
- else
16
- logger.info "Stopping #{instance.name} : no pid file, nothing to do"
17
- end
9
+ manager.each_instance( options['instances'] ) do |instance|
10
+ if File.exist?( instance.pid_file ) then
11
+ logger.info "Stopping #{instance.name} : pid #{instance.pid}"
12
+ instance.stop
13
+ else
14
+ logger.info "Stopping #{instance.name} : no pid file, nothing to do"
18
15
  end
19
16
  end
20
17
  end
@@ -152,6 +152,13 @@ class TyrantManager
152
152
  @ulog_dir ||= append_to_home_if_not_absolute( configuration.ulog_dir )
153
153
  end
154
154
 
155
+ #
156
+ # The list of .ulog files that are in the ulog/ directory
157
+ #
158
+ def ulog_files
159
+ Dir.glob( "#{ulog_dir}/*.ulog" ).sort
160
+ end
161
+
155
162
  #
156
163
  # The lua extension file
157
164
  #
@@ -369,13 +376,21 @@ class TyrantManager
369
376
  tclass.new( configuration.host, configuration.port.to_i )
370
377
  end
371
378
 
379
+ #
380
+ # Return the host:port connection string of the instance
381
+ #
382
+ def connection_string
383
+ "#{configuration.host}:#{configuration.port}"
384
+ end
385
+
372
386
  #
373
387
  # Is this instance a slave of another server? This means it could be in a
374
- # master-slave or master-master relationship
388
+ # master-slave or master-master relationship. returns true or false
389
+ # explicitly
375
390
  #
376
391
  def is_slave?
377
392
  s = connection.stat
378
- return (s['mhost'] and s['mport'])
393
+ return ((s['mhost'] and s['mport']) ? true : false )
379
394
  end
380
395
 
381
396
  #
@@ -389,6 +404,27 @@ class TyrantManager
389
404
  return nil
390
405
  end
391
406
 
407
+ #
408
+ # Is this instance in a master-master relationship with another server.
409
+ # This means that it is a slave, and its master server is also a slave of
410
+ # this server
411
+ #
412
+ def is_master_master?
413
+ if mc = self.master_connection then
414
+ mstat = mc.stat
415
+ mslave_host = manager.ip_of(mstat['mhost'])
416
+ mslave_port = mstat['mport']
417
+
418
+ mslave_conn_string = "#{mslave_host}:#{mslave_port}"
419
+
420
+ my_host = manager.ip_of( configuration.host )
421
+ my_conn_string = "#{my_host}:#{configuration.port}"
422
+ logger.debug "#is_master_master? -> my_conn_string = #{my_conn_string} mslave_conn_string = #{mslave_conn_string}"
423
+
424
+ return (my_conn_string == mslave_conn_string)
425
+ end
426
+ return false
427
+ end
392
428
 
393
429
  private
394
430
 
@@ -0,0 +1,9 @@
1
+ class TyrantManager
2
+ module Util
3
+ def ip_of( hostname )
4
+ hostname = Socket.gethostname if %w[ localhost 0.0.0.0 ].include?( hostname )
5
+ addr_info = Socket.getaddrinfo( hostname, 1978, "AF_INET" )
6
+ return addr_info.first[3]
7
+ end
8
+ end
9
+ end
@@ -6,8 +6,8 @@
6
6
  class TyrantManager
7
7
  module Version
8
8
  MAJOR = 1
9
- MINOR = 3
10
- BUILD = 2
9
+ MINOR = 4
10
+ BUILD = 0
11
11
 
12
12
  def to_a
13
13
  [MAJOR, MINOR, BUILD]
@@ -7,10 +7,12 @@ require 'rubygems'
7
7
  require 'loquacious'
8
8
  require 'tyrant_manager/version'
9
9
  require 'tyrant_manager/paths'
10
+ require 'tyrant_manager/util'
10
11
  require 'tyrant_manager/log'
11
12
 
12
13
  class TyrantManager
13
14
  include TyrantManager::Paths
15
+ include TyrantManager::Util
14
16
 
15
17
  class Error < StandardError; end
16
18
 
@@ -135,6 +137,8 @@ class TyrantManager
135
137
  end
136
138
  return TyrantManager.new( dir )
137
139
  end
140
+
141
+
138
142
  end
139
143
 
140
144
  #
@@ -211,9 +215,17 @@ class TyrantManager
211
215
  return @instances
212
216
  end
213
217
 
214
- def each_instance
218
+ # Yield each instance that exists in the limit list, if the limit exists.
219
+ # If the limit does not exist then yield each instance.
220
+ #
221
+ def each_instance( limit = %w[ all ])
222
+ limit = [ limit ].flatten
223
+ every = (limit.first == "all")
224
+
215
225
  instances.keys.sort.each do |name|
216
- yield instances[name]
226
+ if every or limit.include?( name ) then
227
+ yield instances[name]
228
+ end
217
229
  end
218
230
  end
219
231
 
@@ -5,17 +5,44 @@ require 'tyrant_manager/tyrant_instance'
5
5
 
6
6
  describe TyrantManager::TyrantInstance do
7
7
  before( :each ) do
8
- @tdir = File.join( temp_dir, 'tyrant' )
8
+ @tyrant_manager_dir = File.join( temp_dir, 'tyrant' )
9
+
10
+ @instances = {
11
+ 'standalone' => nil,
12
+ 'slave_1' => nil,
13
+ 'master_master_1' => nil,
14
+ 'master_master_2' => nil
15
+ }
16
+
9
17
  TyrantManager::Log.silent {
10
- @mgr = TyrantManager.setup( @tdir )
11
- @idir = @mgr.instances_path( "test" )
12
- @tyrant = TyrantManager::TyrantInstance.setup( @idir )
13
- @tyrant.manager = @mgr
18
+
19
+ @mgr = TyrantManager.setup( @tyrant_manager_dir)
20
+
21
+ @instances.keys.each_with_index do |name, idx|
22
+ idir = @mgr.instances_path( name )
23
+ tyrant = TyrantManager::TyrantInstance.setup( idir )
24
+ tyrant.manager = @mgr
25
+ tyrant.configuration.port += idx
26
+ tyrant.configuration.server_id = tyrant.configuration.port
27
+ @instances[name] = tyrant
28
+ end
14
29
  }
30
+
31
+ # set the slave_1 to be a slave of the standalone
32
+ @instances['slave_1'].configuration.master_server = "localhost"
33
+ @instances['slave_1'].configuration.master_port = @instances['standalone'].configuration.port
34
+
35
+ # set the master_master pairs into a master_master relationship
36
+ @instances['master_master_1'].configuration.master_server = "localhost"
37
+ @instances['master_master_1'].configuration.master_port = @instances['master_master_2'].configuration.port
38
+
39
+ @instances['master_master_2'].configuration.master_server = "localhost"
40
+ @instances['master_master_2'].configuration.master_port = @instances['master_master_1'].configuration.port
41
+
15
42
  end
16
43
 
17
44
  after( :each ) do
18
- FileUtils.rm_rf @tdir
45
+ FileUtils.rm_rf @tyrant_manager_dir
19
46
  end
20
47
 
21
48
  it "raises an exception if given an invalid directory on initialization" do
@@ -23,55 +50,95 @@ describe TyrantManager::TyrantInstance do
23
50
  end
24
51
 
25
52
  it "#config_file" do
26
- @tyrant.config_file.should == File.join( @tdir, "instances", "test", "config.rb" )
27
- File.exist?( @tyrant.config_file ).should == true
53
+ @instances['standalone'].config_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "config.rb" )
54
+ File.exist?( @instances['standalone'].config_file ).should == true
28
55
  end
29
56
 
30
57
  it "#configuration" do
31
- @tyrant.configuration.should_not == nil
58
+ @instances['standalone'].configuration.should_not == nil
32
59
  end
33
60
 
34
61
  it "#pid_file" do
35
- @tyrant.pid_file.should == File.join( @tdir, "instances", "test", "test.pid" )
62
+ @instances['standalone'].pid_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "standalone.pid" )
36
63
  end
37
64
 
38
65
  it "#log_file" do
39
- @tyrant.log_file.should == File.join( @tdir, "instances", "test", "log", "test.log" )
66
+ @instances['standalone'].log_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "log", "standalone.log" )
40
67
  end
41
68
 
42
69
  it "#replication_timestamp_file" do
43
- @tyrant.replication_timestamp_file.should == File.join( @tdir, "instances", "test", "test.rts" )
70
+ @instances['standalone'].replication_timestamp_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "standalone.rts" )
44
71
  end
45
72
 
46
73
  it "#lua_extension_file" do
47
- @tyrant.lua_extension_file.should == File.join( @tdir, "instances", "test", "lua", "test.lua" )
74
+ @instances['standalone'].lua_extension_file.should == File.join( @tyrant_manager_dir, "instances", "standalone", "lua", "standalone.lua" )
48
75
  end
49
76
 
50
77
  it "#data_dir" do
51
- @tyrant.data_dir.should == File.join( @tdir, "instances", "test", "data" )
78
+ @instances['standalone'].data_dir.should == File.join( @tyrant_manager_dir, "instances", "standalone", "data" )
52
79
  end
53
80
 
54
81
  describe "against running instances" do
55
82
  before( :each ) do
56
- @tyrant.start
57
- start = Time.now
58
- loop do
59
- break if @tyrant.running?
60
- sleep 0.1
61
- break if (Time.now - start) > 2
83
+ @instances.each_pair do |name, instance|
84
+ instance.start
85
+ start = Time.now
86
+ #print "#{name} : starting ->"
87
+ loop do
88
+ break if instance.running?
89
+ #print "+"
90
+ $stdout.flush
91
+ sleep 0.1
92
+ break if (Time.now - start) > 3
93
+ end
94
+ #puts
62
95
  end
63
96
  end
64
97
 
65
98
  after( :each ) do
66
- @tyrant.stop
99
+ @instances.each_pair do |name, instance|
100
+ instance.stop
101
+ start = Time.now
102
+ #print "#{name} : stopping ->"
103
+ loop do
104
+ break unless instance.running?
105
+ #print "-"
106
+ $stdout.flush
107
+ sleep 0.1
108
+ break if (Time.now - start) > 3
109
+ end
110
+ #puts
111
+ end
112
+ end
113
+
114
+ it "#is_running?" do
115
+ @instances.each_pair do |name, instance|
116
+ [ name, instance.running? ].should == [ name, true ]
117
+ end
118
+ end
119
+
120
+ it "#is_slave? when it is NOT a slave" do
121
+ @instances['standalone'].running?.should == true
122
+ @instances['standalone'].is_slave?.should == false
123
+ end
124
+
125
+ it "#is_slave? when it IS a slave" do
126
+ @instances['slave_1'].running?.should == true
127
+ @instances['slave_1'].is_slave?.should == true
67
128
  end
68
129
 
69
- it "#is_slave?" do
70
- @tyrant.running?.should == true
71
- @tyrant.should_not be_is_slave
72
- @tyrant.stop
130
+ it "#is_master_master? when it is NOT in a master_master relationship" do
131
+ @instances['slave_1'].running?.should == true
132
+ @instances['slave_1'].is_master_master?.should == false
73
133
  end
74
134
 
135
+ it "#is_master_master? when it IS in a master_master relationship" do
136
+ @instances['master_master_1'].running?.should == true
137
+ @instances['master_master_1'].is_master_master?.should == true
138
+
139
+ @instances['master_master_2'].running?.should == true
140
+ @instances['master_master_2'].is_master_master?.should == true
141
+ end
75
142
  end
76
143
 
77
144
 
@@ -84,23 +151,23 @@ describe TyrantManager::TyrantInstance do
84
151
  'table' => "tct"
85
152
  }.each_pair do |db_type, db_ext|
86
153
  it "db_type of #{db_type} is db file with ext #{db_ext}" do
87
- f = @tyrant.db_file( db_type )
154
+ f = @instances['standalone'].db_file( db_type )
88
155
  if f.size == 1 then
89
156
  f.should == db_ext
90
157
  else
91
- f.should == File.join( @tdir, "instances", "test", "data", "test.#{db_ext}" )
158
+ f.should == File.join( @tyrant_manager_dir, "instances", "standalone", "data", "standalone.#{db_ext}" )
92
159
  end
93
160
  end
94
161
  end
95
162
  end
96
163
 
97
164
  it "#ulog_dir" do
98
- @tyrant.ulog_dir.should == File.join( @tdir, "instances", "test", "ulog" )
165
+ @instances['standalone'].ulog_dir.should == File.join( @tyrant_manager_dir, "instances", "standalone", "ulog" )
99
166
  end
100
167
 
101
168
 
102
169
  it "#start_command" do
103
- @tyrant.start_command.should =~ /^ttserver/
170
+ @instances['standalone'].start_command.should =~ /^ttserver/
104
171
  end
105
172
 
106
173
  end
@@ -51,7 +51,7 @@ describe TyrantManager do
51
51
  @mgr.configuration.ttserver.should == "ttserver"
52
52
  end
53
53
 
54
- it "knows all its instances" do
54
+ it "iterates over all its instances" do
55
55
  3.times do |x|
56
56
  idir = @mgr.instances_path( "test#{x}" )
57
57
  TyrantManager::TyrantInstance.setup( idir )
@@ -66,4 +66,21 @@ describe TyrantManager do
66
66
 
67
67
  names.sort.should == %w[ test0 test1 test2 ]
68
68
  end
69
+
70
+ it "iterates over a subset of instances" do
71
+ 3.times do |x|
72
+ idir = @mgr.instances_path( "test#{x}" )
73
+ TyrantManager::TyrantInstance.setup( idir )
74
+ end
75
+
76
+ @mgr.instances.size.should == 3
77
+ names = []
78
+ @mgr.each_instance( %w[ test0 test2] ) do |i|
79
+ i.name.should =~ /test\d/
80
+ names << i.name
81
+ end
82
+
83
+ names.sort.should == %w[ test0 test2 ]
84
+ end
85
+
69
86
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tyrantmanager
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.2
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Hinegardner
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-01-04 00:00:00 -07:00
12
+ date: 2010-01-21 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -88,6 +88,7 @@ extra_rdoc_files:
88
88
  - LICENSE
89
89
  - lib/tyrant_manager/cli.rb
90
90
  - lib/tyrant_manager/command.rb
91
+ - lib/tyrant_manager/commands/archive_ulogs.rb
91
92
  - lib/tyrant_manager/commands/create_instance.rb
92
93
  - lib/tyrant_manager/commands/list.rb
93
94
  - lib/tyrant_manager/commands/replication_status.rb
@@ -99,6 +100,7 @@ extra_rdoc_files:
99
100
  - lib/tyrant_manager/paths.rb
100
101
  - lib/tyrant_manager/runner.rb
101
102
  - lib/tyrant_manager/tyrant_instance.rb
103
+ - lib/tyrant_manager/util.rb
102
104
  - lib/tyrant_manager/version.rb
103
105
  - lib/tyrant_manager.rb
104
106
  - lib/tyrantmanager.rb
@@ -106,6 +108,7 @@ files:
106
108
  - bin/tyrantmanager
107
109
  - lib/tyrant_manager/cli.rb
108
110
  - lib/tyrant_manager/command.rb
111
+ - lib/tyrant_manager/commands/archive_ulogs.rb
109
112
  - lib/tyrant_manager/commands/create_instance.rb
110
113
  - lib/tyrant_manager/commands/list.rb
111
114
  - lib/tyrant_manager/commands/replication_status.rb
@@ -117,6 +120,7 @@ files:
117
120
  - lib/tyrant_manager/paths.rb
118
121
  - lib/tyrant_manager/runner.rb
119
122
  - lib/tyrant_manager/tyrant_instance.rb
123
+ - lib/tyrant_manager/util.rb
120
124
  - lib/tyrant_manager/version.rb
121
125
  - lib/tyrant_manager.rb
122
126
  - lib/tyrantmanager.rb