邊看MHA源碼邊學Perl語言之三 NodeUtil.pm

來源:互聯網
上載者:User

標籤:--   target   返回   ons   att   details   從庫   訊息   article   

邊看MHA源碼邊學Perl語言之三 NodeUtil.pmNodeUtil.pm源碼分析

MHA的代碼分為mha4mysql-manager(管理節點)和mha4mysql-node(資料庫節點)兩部分,可能有些人認為mha4mysql-node只需要安裝在資料庫節點就可以了,但通過源碼可看出,在管理點節也是需要安裝node節點,因為在manager節點也會調用NodeUtil中的方法.以下為加過comment的mha4mysql-node的代碼:

#!/usr/bin/env perl#  Copyright (C) 2011 DeNA Co.,Ltd.##  This program is free software; you can redistribute it and/or modify#  it under the terms of the GNU General Public License as published by#  the Free Software Foundation; either version 2 of the License, or#  (at your option) any later version.##  This program is distributed in the hope that it will be useful,#  but WITHOUT ANY WARRANTY; without even the implied warranty of#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the#  GNU General Public License for more details.##  You should have received a copy of the GNU General Public License#   along with this program; if not, write to the Free Software#  Foundation, Inc.,#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA# 聲明包名package MHA::NodeUtil;# Perl 浪起來太可怕了,所以建議使用嚴格文法格式use strict;use warnings FATAL => ‘all‘;# 引入package,如果在Perl的lib路徑中找不到相應的檔案,則會報錯use Carp qw(croak);use MHA::NodeConst;use File::Path;use Errno();# 當目錄不存時,建立此目錄.sub create_dir_if($) {  my $dir = shift;  #判斷目錄不存時才建立  if ( !-d $dir ) {    eval {      print "Creating directory $dir.. ";      mkpath($dir);      print "done.\n";    };    # [email protected]為eval命令的錯誤訊息.如果為空白,則表示上一次eval命令執行成功    if ([email protected]) {      # 細節處理: [email protected] 是全域的,為了防止影響到其它程式,所有先把值賦給局部變數 $e 後,再 undef 進行重設      my $e = [email protected];      undef [email protected];      # 目錄已存在,這裡邏輯有點問題,因為已經有判斷目錄不存在才會到這裡      if ( -d $dir ) {        print "ok. already exists.\n";      }      else {        # 輸出錯誤資訊,使用croak會輸出指令碼名稱,代碼位置等有用的調試資訊,更方便的找到問題        croak "failed to create dir:$dir:$e";      }    }  }}# 對比本機和遠程主機檔案是否一致# 參數1:本機檔案# 參數2:遠程主機上的檔案# 參數3:ssh user# 參數4:遠程主機IP# 參數5:遠程主機port,預設為 22# 傳回值:# 1:檔案不存在# 2:檔案不一致# 0:檔案一致# Compare file checksum between local and remote hostsub compare_checksum {  my $local_file  = shift;  my $remote_path = shift;  my $ssh_user    = shift;  my $ssh_host    = shift;  my $ssh_port    = shift;  # 預設連接埠號碼  $ssh_port = 22 unless ($ssh_port);  my $local_md5 = `md5sum $local_file`;  return 1 if ($?);  chomp($local_md5);  $local_md5 = substr( $local_md5, 0, 32 );  my $ssh_user_host = $ssh_user . ‘@‘ . $ssh_host;  my $remote_md5 =`ssh $MHA::NodeConst::SSH_OPT_ALIVE -p $ssh_port $ssh_user_host \"md5sum $remote_path\"`;  return 1 if ($?);  chomp($remote_md5);  $remote_md5 = substr( $remote_md5, 0, 32 );  return 2 if ( $local_md5 ne $remote_md5 );  return 0;}# 本地檔案複製到遠程主機上# 參數:略sub file_copy {  my $to_remote   = shift;  my $local_file  = shift;  my $remote_file = shift;  my $ssh_user    = shift;  my $ssh_host    = shift;  my $log_output  = shift;  my $ssh_port    = shift;  $ssh_port = 22 unless ($ssh_port);  my $ssh_user_host = $ssh_user . ‘@‘ . $ssh_host;  my ( $from, $to );  if ($to_remote) {    $from = $local_file;    $to   = "$ssh_user_host:$remote_file";  }  else {    $to   = $local_file;    $from = "$ssh_user_host:$remote_file";  }  my $max_retries = 3;  my $retry_count = 0;  my $copy_fail   = 1;  my $copy_command =    "scp $MHA::NodeConst::SSH_OPT_ALIVE -P $ssh_port $from $to";  if ($log_output) {    $copy_command .= " >> $log_output 2>&1";  }  while ( $retry_count < $max_retries ) {    if (      system($copy_command)      || compare_checksum(        $local_file, $remote_file, $ssh_user, $ssh_host, $ssh_port      )      )    {      my $msg = "Failed copy or checksum. Retrying..";      if ($log_output) {        system("echo $msg >> $log_output 2>&1");      }      else {        print "$msg\n";      }      $retry_count++;    }    else {      $copy_fail = 0;      last;    }  }  return $copy_fail;}# 拆分錯誤碼為高8位和低8位sub system_rc($) {  my $rc   = shift;  my $high = $rc >> 8;  my $low  = $rc & 255;  return ( $high, $low );}# 當檔案不存時,建立一個空檔案sub create_file_if {  my $file = shift;  if ( $file && ( !-f $file ) ) {    open( my $out, ">", $file ) or croak "$!:$file";    close($out);  }}# 當檔案存在時,刪除一個檔案sub drop_file_if($) {  my $file = shift;  if ( $file && -f $file ) {    unlink $file or croak "$!:$file";  }}# 解析host的IP地址sub get_ip {  my $host = shift;  my ( $bin_addr_host, $addr_host );  if ( defined($host) ) {    $bin_addr_host = gethostbyname($host);    unless ($bin_addr_host) {      croak "Failed to get IP address on host $host!\n";    }    $addr_host = sprintf( "%vd", $bin_addr_host );    return $addr_host;  }  return;}# 擷取系統目前時間,精確到秒sub current_time() {  my ( $sec, $min, $hour, $mday, $mon, $year ) = localtime();  $mon  += 1;  $year += 1900;  my $val = sprintf( "%d-%02d-%02d %02d:%02d:%02d",    $year, $mon, $mday, $hour, $min, $sec );  return $val;}# 檢查manager的版本,低於node版本時,直接報錯並退出.sub check_manager_version {  my $manager_version = shift;  if ( $manager_version < $MHA::NodeConst::MGR_MIN_VERSION ) {    croak"MHA Manager version is $manager_version, but must be $MHA::NodeConst::MGR_MIN_VERSION or higher.\n";  }}# 從字串中解析出mysql的版本號碼,只取數字,便於比較版本大小# $str = "SELECT VERSION() AS Value"sub parse_mysql_version($) {  my $str = shift;  my $result = sprintf( ‘%03d%03d%03d‘, $str =~ m/(\d+)/g );  return $result;}# 從字串中解析出mysql的主要版本號,只取數字,便於比較版本大小# $str = "SELECT VERSION() AS Value"sub parse_mysql_major_version($) {  my $str = shift;  my $result = sprintf( ‘%03d%03d‘, $str =~ m/(\d+)/g );  return $result;}# 比較$my_version是否高於$target_version# mysql 主從結構 從庫版本要高於主庫版本sub mysql_version_ge {  my ( $my_version, $target_version ) = @_;  my $result =    parse_mysql_version($my_version) ge parse_mysql_version($target_version)    ? 1    : 0;  return $result;}# shell需轉義的特殊字元數組my @shell_escape_chars = (  ‘"‘, ‘!‘, ‘#‘, ‘&‘, ‘;‘, ‘`‘, ‘|‘,    ‘*‘,  ‘?‘, ‘~‘, ‘<‘, ‘>‘, ‘^‘, ‘(‘, ‘)‘,    ‘[‘,  ‘]‘, ‘{‘, ‘}‘, ‘$‘, ‘,‘, ‘ ‘, ‘\x0A‘, ‘\xFF‘);# 反轉義shell的特殊字元sub unescape_for_shell {  my $str = shift;  if ( !index( $str, ‘\\\\‘ ) ) {    return $str;  }  foreach my $c (@shell_escape_chars) {    my $x       = quotemeta($c);    my $pattern = "\\\\(" . $x . ")";    $str =~ s/$pattern/$1/g;  }  return $str;}# 轉義shell的特殊字元sub escape_for_shell {  my $str = shift;  my $ret = "";  foreach my $c ( split //, $str ) {    my $x      = $c;    my $escape = 0;    foreach my $e (@shell_escape_chars) {      if ( $e eq $x ) {        $escape = 1;        last;      }    }    if ( $x eq "‘" ) {      $x =~ s/‘/‘\\‘‘/;    }    if ( $x eq "\\" ) {      $x = "\\\\";    }    if ($escape) {      $x = "\\" . $x;    }    $ret .= "$x";  }  $ret = "‘" . $ret . "‘";  return $ret;}# 轉義mysql_command的特殊字元sub escape_for_mysql_command {  my $str = shift;  my $ret = "";  foreach my $c ( split //, $str ) {    my $x = $c;    if ( $x eq "‘" ) {      $x =~ s/‘/‘\\‘‘/;    }    $ret .= $x;  }  $ret = "‘" . $ret . "‘";  return $ret;}# mysql終端命令的預先處理sub client_cli_prefix {  my ( $exe, $bindir, $libdir ) = @_;  croak "unexpected client binary $exe\n" unless $exe =~ /^mysql(?:binlog)?$/;  my %env = ( LD_LIBRARY_PATH => $libdir );  my $cli = $exe;  if ($bindir) {    if ( ref $bindir eq "ARRAY" ) {      $env{‘PATH‘} = $bindir;    }    elsif ( ref $bindir eq "" ) {      $cli = escape_for_shell("$bindir/$exe");    }  }  for my $k ( keys %env ) {    if ( my $v = $env{$k} ) {      my @dirs = ref $v eq "ARRAY" ? @{$v} : ( ref $v eq "" ? ($v) : () );      @dirs = grep { $_ && !/:/ } @dirs;      if (@dirs) {        $cli = "$k="          . join( ":", ( map { escape_for_shell($_) } @dirs ), "\$$k" )          . " $cli";      }    }  }  # $cli .= " --no-defaults";  return $cli;}1;
NodeUtil.pm小結

通過上一節,我們已經對perl有了基本的瞭解,相信看在NodeUtil的源碼時,就會輕鬆很多,裡面都是一些顧名思義的方法,具體調用執行個體代碼就留給各位看官自由發揮了.

唯一一個值得提及的重點是perl的Regex處理,但這個網上已經有相當然的教程,這裡就不重複去講解了,給大家兩個地址:

入門版:

http://www.runoob.com/perl/perl-regular-expressions.html

詳細版:

http://blog.csdn.net/eroswang/article/details/1812528

邊看MHA源碼邊學Perl語言之三 NodeUtil.pm

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.