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

发布时间:2025-09-01 01:04:06 作者:益华网络 来源:undefined 浏览量(0) 点赞(0)
摘要:目的:本篇是自己用C++实现的ddl的简单脚本(改写自自己的shell,但是还有一部分没完成),用来锻炼自己写C++的能力 头文件exec_ddl.h

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

头文件exec_ddl.h

```

#include

#include

#include

#include

#include

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<<"获取当前时间戳失败"<

        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失败,语句为:"<

        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失败"<

        return -2;

    }

    /*

    if((pidScan = fork()) < 0){

        std::cout<<"pidScan子进程fork失败"<

        return -2;

    }

    */

    //子进程要执行修改表结构命令了

    if(0 == pidGhost){

        //为什么不用system,因为不想子进程fork子进程

        if(execl("/bin/sh","sh","-c",ghostCmd.c_str(),(char *) 0)<0){

            std::cout<<"卧槽,执行命令失败了"<

        }

        _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<<"等待子进程出现异常"<

        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

#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<<"分配对象内存失败"<

        return 1;

    }

    std::string ghostCmd;

    i = pDdlGhost->GetGhostCmd("add index cname(c)",ghostCmd);

    ret = pDdlGhost->ExecDdlCmd(ghostCmd);

    std::cout<<"返回结果是:"<

    if(ret <0){

        std::cout<<"更改表结构失败"<

    }

    delete pDdlGhost;

}

```

编译命令

```

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

```

执行结果:

程序返回结果

数据库查看结果

二维码

扫一扫,关注我们

声明:本文由【益华网络】编辑上传发布,转载此文章须经作者同意,并请附上出处【益华网络】及本页链接。如内容、图片有任何版权问题,请联系我们进行处理。

感兴趣吗?

欢迎联系我们,我们愿意为您解答任何有关网站疑难问题!

您身边的【网站建设专家】

搜索千万次不如咨询1次

主营项目:网站建设,手机网站,响应式网站,SEO优化,小程序开发,公众号系统,软件开发等

立即咨询 15368564009
在线客服
嘿,我来帮您!