tyrantmanager 1.3.2 → 1.4.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.
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