温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

【C/C++】ghost ddl脚本简单实现

发布时间:2020-08-09 00:27:16 来源:ITPUB博客 阅读:251 作者:风尘_NULL 栏目:编程语言

目的:本篇是自己用C++实现的ddl的简单脚本(改写自自己的shell,但是还有一部分没完成),用来锻炼自己写C++的能力


头文件exec_ddl.h

```

#include <regex>
#include <cstdlib>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
size_t GetStrCurrTime(std::string &);
#ifndef header_cpp_fun_h
#define header_cpp_fun_h
class CDdlGhost {
private:
//数据库账号,端口,DDL用户,密码,
std::string host;
int port;
std::string user;
std::string password;
std::string database;
std::string tableName;
int threadRunning = 500;
int cthreadRunning = 500;
int maxLagMillis = 3000;
std::string cutOver = "default";
int chunkSize = 1000;
int lockSeconds = 60;
int retries = 3;
static CDdlGhost* instance;
CDdlGhost(std::string host,int port,std::string database,std::string tableName,std::string user,std::string password);

public:
static CDdlGhost* GetSingleInstance(std::string host,int port,std::string database,std::string tableName,std::string user,std::string password);
int GetGhostCmd(std::string sql,std::string &cmd);
int ExecDdlCmd(std::string &cmd);
};
#endif

```


exec_ddl.cpp

```

#include "exec_ddl.h"
//类中静态变量为什么不在类中初始化,是因为静态变量具有外部链接性,文件作用域
CDdlGhost* CDdlGhost::instance = nullptr;

//构造函数
CDdlGhost::CDdlGhost(std::string host,int port,std::string database,std::string tableName,std::string user,std::string password){
    //这里以后正则表达式做安全性过滤
    this->host = host;
    this->port = port;
    this->database = database;
    this->tableName = tableName;
    this->user = user;
    this->password = password;

}
//获取类的单实例函数,这里为什么返回的是指针而不是引用是因为我要用空指针才判断是否单实例
CDdlGhost* CDdlGhost::GetSingleInstance(std::string host,int port,std::string database,std::string tableName,std::string user,std::string password){
    if(nullptr == instance){
        instance = new CDdlGhost(host,port,database,tableName,user,password);
    }

    return instance;

}
//获得表结构更改的命令字符串
int CDdlGhost::GetGhostCmd(std::string sql,std::string &ghostCmd){
    //获取环境变量
    const char* pathEnv = std::getenv("PATH");
    std::string ghostLog;
    //这个变量用来获取当前时间戳
    std::string strTime;
    size_t ret = GetStrCurrTime(strTime);
    if(ret <= 0){
        std::cout<<"获取当前时间戳失败"<<std::endl;
        return 0;
    }
    
    ghostLog=ghostLog+"/data1/upload/ghost_"+tableName+"_"+strTime+".log";
    ghostCmd="gh-ost --ok-to-drop-table --initially-drop-ghost-table --skip-foreign-key-checks --allow-on-master --switch-to-rbr --allow-master-master --exact-rowcount --verbose --initially-drop-old-table ";
    
    ghostCmd=ghostCmd + "--max-load=Threads_running="+std::to_string(threadRunning)+" --critical-load=Threads_running="+std::to_string(cthreadRunning)+" --chunk-size="+std::to_string(chunkSize)+" --cut-over="+cutOver+" --max-lag-millis="+std::to_string(maxLagMillis)+" --cut-over-lock-timeout-seconds="+std::to_string(lockSeconds)+" --default-retries="+std::to_string(retries)+" --host=\'"+host+"' --user='"+user+"' --password='"+password+"' --database='"+database+"'  --table='"+tableName+"' --alter='"+sql+"' --panic-flag-file=/tmp/"+tableName+".ghost.panic.flag --execute  > "+ghostLog+" 2>&1";    

    return 1;
    /*
    if(execl("/bin/sh","sh","-c",ghostCmd.c_str(),(char *) 0)<0){
        std::cout<<"执行ghostCmd失败,语句为:"<<ghostCmd<<std::endl;
        return -2;

    }
    */

}
int CDdlGhost::ExecDdlCmd(std::string &ghostCmd){
    
    pid_t pidGhost;
    int GhostStatus;
    //这里我还要fork一个扫描ghost产生的日志的子进程,但是现在暂时没打开
    //pid_t pidScan;
    
    if((pidGhost = fork()) < 0){
        std::cout<<"pidGhost子进程fork失败"<<std::endl;
        return -2;

    }

    /*
    if((pidScan = fork()) < 0){
        std::cout<<"pidScan子进程fork失败"<<std::endl;
        return -2;
        

    }
    */
    //子进程要执行修改表结构命令了
    if(0 == pidGhost){
        //为什么不用system,因为不想子进程fork子进程
        if(execl("/bin/sh","sh","-c",ghostCmd.c_str(),(char *) 0)<0){
            std::cout<<"卧槽,执行命令失败了"<<std::endl;

        }
        _exit(127);

    }
    //另一个子进程,每一秒检查下日志文件,看看是否有锁,有锁就kill,暂时没启用
    /*
    if(0 == pidScan ){
        while(1){
            int ret = ScanGhostLogLock(std::string &ghostLog);
            if(ret > 0){
                KillSleepOrLongQuery();
            }
            sleep(1);
    }
    */

    /*这里后面会通过一个函数扫描子进程执行的命令的日志,执行完后通知父进程*/     //等待子进程结束
    if(waitpid(pidGhost,&GhostStatus,0) < 0){
        std::cout<<"等待子进程出现异常"<<std::endl;
        return -1;

    }
        
    /*这里以后会通过函数向后台扫描日志进程发送信号,通知其结束*/    

    if(WIFEXITED(GhostStatus)){
        return 0;

    }
    return -3;

}
//获取格式化后的日期字符串
size_t GetStrCurrTime(std::string &strTime){
    time_t now = time(NULL);
    struct tm timeinfo = *localtime(&now);
    char buf[30];
    size_t ret = strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", &timeinfo);
    std::string str(buf);
    strTime = str;
    return ret; }

```



ddl_main.cpp

```

#include <iostream>
#include "exec_ddl.h"
int main(){
    int i=0,ret;
    CDdlGhost *pDdlGhost=CDdlGhost::GetSingleInstance("10.17.4.23",3306,"test","test1","zaixinyuan","test123456");
    if (pDdlGhost == nullptr){
        std::cout<<"分配对象内存失败"<<std::endl;
        return 1;
    }
    std::string ghostCmd;
    i = pDdlGhost->GetGhostCmd("add index cname(c)",ghostCmd);
    ret = pDdlGhost->ExecDdlCmd(ghostCmd);
    std::cout<<"返回结果是:"<<i<<"|"<<ghostCmd<<"|"<<ret<<std::endl;
    if(ret <0){
        std::cout<<"更改表结构失败"<<std::endl;
    }

    delete pDdlGhost;
}

```

编译命令

```

g++ -std=gnu++11 -o ddl_ghost ddl_main.cpp exec_ddl.cpp

```


执行结果:

程序返回结果

【C/C++】ghost ddl脚本简单实现


数据库查看结果

【C/C++】ghost ddl脚本简单实现


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI