#!/usr/bin/perl # # Gross hack to "re-master" or "re-parent" MySQL hosts before 4.1.1 # which has the wonderful "SLAVE START UNTIL" command. (the UNTIL part is new) # # Basically, if you have B and C both replicating from A, how do you make C # replicate from B instead of A? # # Constraints: # # -- can't touch A. # -- can't copy files from A or B to C, since C is a different file format # (InnoDB instead of MyISAM) # # Solution: # # Keep watching the replication position of B and C until they're the same. # Then stop the replication thread in both, verify they're still the same, # then make C feed off B instead. (this requires that B is already setup # to log-master-updates and log-bin) # # Go ugly hacks! # # (There's a lot of LJ-specific code in here, but you should figure out # what it does and how to write a non-LJ equivalent. Like, DBI->connect # instead of the LJ-low-level $LJ::DBIRole->get_dbh_conn) # use strict; use Time::HiRes qw ( sleep ); use Data::Dumper; require "$ENV{LJHOME}/cgi-bin/ljlib.pl"; my $dbh = LJ::get_dbh("master"); die "Can't get master db handle\n" unless $dbh; my %db; # name -> dbinfo hashref my $sth; $sth = $dbh->prepare("SELECT dbid, name, masterid, rootfdsn FROM dbinfo"); $sth->execute; while ($_ = $sth->fetchrow_hashref) { $db{$_->{'name'}} = $_; } my $dba = $db{'gm2'} or die "No dba"; my %dba_info = ("host" => "10.0.0.67", "pass" => "REPLICATION_USERNAME", "user" => "REPLICATION_PASSWORD", ); my $dbb = $db{'garrison'} or die "No dbb"; my $dbha = $LJ::DBIRole->get_dbh_conn($dba->{'rootfdsn'}) or die "No dbha"; my $dbhb = $LJ::DBIRole->get_dbh_conn($dbb->{'rootfdsn'}) or die "No dbhb"; my $get_both = sub { my $ret = []; $ret->[0] = $dbha->selectrow_hashref("SHOW SLAVE STATUS"); $ret->[1] = $dbhb->selectrow_hashref("SHOW SLAVE STATUS"); return $ret; }; my $compare = sub { my $v = shift; my $sa = $v->[0]; my $sb = $v->[1]; return ($sa->{'Relay_Master_Log_File'} eq $sb->{'Relay_Master_Log_File'} && $sa->{'Exec_master_log_pos'} == $sb->{'Exec_master_log_pos'}); }; my $slave = sub { my $action = shift; $dbha->do("SLAVE $action"); $dbhb->do("SLAVE $action"); }; $| = 1; while (1) { my $va = $get_both->(); print "."; if ($compare->($va)) { print "\n"; print "Match! at $va->[0]{'Exec_master_log_pos'}\n"; $slave->("STOP"); my $vb = $get_both->(); my $success = 0; if ($compare->($vb)) { print " Synced both!\n"; my $ma = $dbha->selectrow_hashref("SHOW MASTER STATUS"); print Dumper($ma); #Position, File my $sql = "CHANGE MASTER TO MASTER_HOST=?, MASTER_USER=?, MASTER_PASSWORD=?, ". "MASTER_LOG_FILE=?, MASTER_LOG_POS=$ma->{'Position'}"; $dbhb->do($sql, undef, $dba_info{'host'}, $dba_info{'user'}, $dba_info{'pass'}, $ma->{'File'}); if ($dbhb->err) { print "ERROR: " . $dbhb->errstr . "\n"; } else { print "Success, probably.\n"; } $slave->("START"); print "ENDING.\n"; exit 0; } $slave->("START"); } sleep (0.2); }