【C/C++】ghost ddl脚本简单实现
目的:本篇是自己用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;
}
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(0 == pidGhost){
//为什么不用system,因为不想子进程fork子进程
if(execl("/bin/sh","sh","-c",ghostCmd.c_str(),(char *) 0)<0){
std::cout<<"卧槽,执行命令失败了"<<std::endl;
}
_exit(127);
}
//另一个子进程,每一秒检查下日志文件,看看是否有锁,有锁就kill,暂时没启用
//等待子进程结束
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
```
执行结果:
程序返回结果
数据库查看结果
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341