后台进程(守护进程)自动备份PostgreSQL数据库

从当前目录中读取ini配置文件的登录数据库必要的参数,登录数据库后获取两次备份的间隔天数,然后启动一个线程隔1分钟检查一下是否需要备份。

之前查资料查了好久,才找到

"pg_dump \"host=%s port=%d user=%s password=%s dbname=%s\" > db_bak\\%s.bak"

这种可以避免输入密码,实现自动备份(不用配置环境变量或改动数据库的登录权限)

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#include "inc/libpq-fe.h"
#include <time.h>
 
#pragma comment(linker, "/subsystem:windows /entry:mainCRTStartup")
#pragma comment(lib, "lib/libpq.lib")
 
#define DIRECTORY "db_bak"
#define INIFILE "sysinfo.ini"
#define CONNINFO "host=localhost port=5432 user=postgres password=123456 dbname=DB_SPS"
#define QUERYSQL "select sys_val from tb_sysinfo where sys_key=\'backup_interval_time\'"
#define SPACEUNIT (60*60*24)

// BEGTIME:00 ~ ENDTIME:59
#define BEGTIME 2
#define ENDTIME 3

typedef struct tagArgs
{
	int t_space;
	char db_ip[16];
	char db_name[10];
	char db_user[10];
	char db_passwd[10];
	unsigned short db_port;
}Args;

unsigned int __stdcall ThreadCheckAndSave(void* arglist)
{
	struct tm tlasttime = {0}, tcurtime = {0};
	time_t lasttime = 0, curtime = 0;
	Args args = {0};
	char cmd[256] = {0}, strtime[256] = {0};

	if(arglist == NULL)
	{
		printf("error for begin and space args !\n");
		_endthreadex(1);
	}
	memcpy(&args,arglist,sizeof(args));

	lasttime = time(NULL);
	do{
		curtime = time(NULL);
		if((difftime(curtime,lasttime)/SPACEUNIT) > args.t_space)
		{
			localtime_s(&tcurtime,&curtime);
			if(tcurtime.tm_hour >= BEGTIME && tcurtime.tm_hour <= ENDTIME)
			{
				//备份
				memset(cmd,0,sizeof(cmd));
				memset(strtime,0,sizeof(strtime));
				localtime_s(&tcurtime, &curtime);
				strftime(strtime,sizeof(strtime),"%Y-%m-%d(%H_%M_%S)",&tcurtime);
				CreateDirectoryA(DIRECTORY,NULL);
				sprintf(cmd,"pg_dump \"host=%s port=%d user=%s password=%s dbname=%s\" > db_bak\\%s.bak",
										args.db_ip,
										args.db_port,
										args.db_user,
										args.db_passwd,
										args.db_name,
										strtime);
				system(cmd);
				lasttime = curtime;
			}
			Sleep(60000);
		}
	}while(true);

	_endthreadex(0);
	return 0;
}

int main(int argc, const char* argv[])
{
	PGconn* conn = NULL;
	PGresult* result = NULL;
	char* getstr = NULL;
	
	Args args = {0};
	HANDLE hthread = NULL;
	char inipath[MAX_PATH] = {0};
	char strsql[MAX_PATH] = {0};

	GetCurrentDirectoryA(sizeof(inipath),inipath);
	strcat(inipath,"\\");
	strcat(inipath,INIFILE);
	GetPrivateProfileStringA("db","#ip","127.0.0.1",args.db_ip,sizeof(args.db_ip),inipath);
	GetPrivateProfileStringA("db","#name","",args.db_name,sizeof(args.db_name),inipath);
	GetPrivateProfileStringA("db","#user","",args.db_user,sizeof(args.db_user),inipath);
	GetPrivateProfileStringA("db","#passwd","",args.db_passwd,sizeof(args.db_passwd),inipath);
	args.db_port = GetPrivateProfileIntA("db","#port",0,inipath);
	sprintf(strsql,"host=%s port=%d user=%s password=%s dbname=%s",args.db_ip,args.db_port,args.db_user,args.db_passwd,args.db_name);

	conn = PQconnectdb(strsql);
	if(PQstatus(conn) != CONNECTION_OK)
		goto END;
	result = PQexec(conn,QUERYSQL);
	if(PQresultStatus(result) != PGRES_TUPLES_OK)
		goto END;
	//获取配置参数
	getstr = PQgetvalue(result,0,0);
	if(getstr == NULL)
		goto END;
	args.t_space = atoi(getstr);

	//循环检查备份数据库
	hthread = (HANDLE)_beginthreadex(NULL,0,ThreadCheckAndSave,&args,CREATE_SUSPENDED,NULL);
	SetPriorityClass(GetCurrentProcess(),BELOW_NORMAL_PRIORITY_CLASS);
	//SetThreadPriority(hthread,THREAD_PRIORITY_IDLE);
	ResumeThread(hthread);

END:
	if(result != NULL)
	{
		printf("PQexec : %s\n", PQerrorMessage(conn));
		PQclear(result);
		result = NULL;
	}
	if(conn != NULL)
	{
		printf("PQconn : %s\n", PQerrorMessage(conn));
		PQfinish(conn);
		conn = NULL;
	}
	if(hthread != NULL)
		WaitForSingleObject(hthread,INFINITE);
	else
		return -1;

	return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杨建荣的学习笔记

11g rac配置scan ip(r6笔记第30天)

如果是从10g转战11g rac就会发现很多不同之处,其中一个比较大的改变就是在11g中有了一个新特性scan,其实这是一个简称,完整的名称为:SCAN(Si...

2384
来自专栏数据和云

返璞归真:实例会话RAC条件下的笛卡尔积种参数可能性

? 杨廷琨(yangtingkun) 云和恩墨 CTO 高级咨询顾问,Oracle ACE 总监,ITPUB Oracle 数据库管理版版主 参数文件是Or...

26710
来自专栏Aloys的开发之路

Oracle系统表整理+常用SQL语句收集

-- DBA/ALL/USER/V_$/GV_$/SESSION/INDEX开头的绝大部分都是视图 -- DBA_TABLES意为DBA拥有的或可以访问的所有...

18210
来自专栏Ken的杂谈

CentOS 7下InfluxDB部署与使用入门

InfluxDB里存储的数据被称为时间序列数据,InfluxDB存储方式跟传统关系型数据库不同的是:传统关系型数据库通过数据库+表+字段组织数据,InfluxD...

574
来自专栏祝威廉

使用StreamingPro 快速构建Spark SQL on CarbonData

CarbonData已经发布了1.0版本,变更还是很快的,这个版本已经移除了kettle了,使得部署和使用 变得很简单,而且支持1.6+ ,2.0+等多个Spa...

641
来自专栏张戈的专栏

MySQL错误修复记录:Table xx is marked as crashed and should be repaired

昨晚入睡后,收到松哥的 QQ 消息,说松松商城打开报错,于是手机 QQ 上打开了首页地址,发现有如下报错: ? MySQL server error repor...

37811
来自专栏.NET技术

经典SQL语句大全之数据开发

1.按姓氏笔画排序: Select * From TableName Order By CustomerName Collate Chinese_PRC_Str...

1165
来自专栏逸鹏说道

在SQL Server里如何进行页级别的恢复

在今天的文章里我想谈下每个DBA应该知道的一个重要话题:在SQL Server里如何进行页级别还原操作。假设在SQL Server里你有一个损坏的页,你要从最近...

2445
来自专栏杨建荣的学习笔记

insert中启用错误日志的问题及分析(r2第10天)

在平时的工作中,有时候需要insert一批数据,这些数据可能是临时表,外部表,普通表,子查询等形式,类似下面的格式 insert into xxxx (sele...

2629
来自专栏杨建荣的学习笔记

关于primary key和unique index的奇怪问题 (58天)

今天一个dba交给我一个问题,让我帮忙查一下。说有个脚本运行的时候有错,让我看看是什么原因。 脚本的思路如下: 先drop PK,FK之类的constraint...

26412

扫描关注云+社区