【云备份】服务端模块-数据管理模块

代码

#ifndef __MY_DATA__
#define __MY_DATA__
#include <unordered_map>
#include <pthread.h>
#include "fileUtil.hpp"
#include "config.hpp"

namespace cloudBackup
{
	// 已备份的文件的属性信息  backup file Attribute information
	typedef struct BackupAInfo // 都需要管理哪些信息
	{
		bool _isZipped;			 // 是否被压缩
		size_t _fsize;			 // 文件大小
		time_t _atime;			 // 最后一次访问
		time_t _ctime;			 // 最后一次状态改变
		time_t _mtime;			 // 最后一次修改
		std::string _backupPath; // 备份文件存放路径
		std::string _zipPath;	 // 压缩包存放路径
		std::string _url;		 // 客户端http请求url路径 demo

		// BackupAInfo对象obj调用此函数 目的是设置filename文件的属性信息
		bool NewBackupAInfo(const std::string &filename)
		{
			// 无法为不存在的文件添加属性信息
			FileUtil fileUtil(filename);
			if (fileUtil.Exists() == false)
			{
				Log::log(Error, "BackupInfo::NewBackupAInfo file not exists!: %s: %d", strerror(errno), errno);
				return false;
			}

			// 从配置文件读取相关信息
			Config *config = Config::GetInstance();
			std::string zipDir = config->GetZipDir();
			std::string zipSuffix = config->GetZipSuffix();
			std::string urlPrefix = config->GetUrlPrefix();

			this->_isZipped = false;
			this->_fsize = fileUtil.FileSize();
			this->_atime = fileUtil.LastATime();
			this->_ctime = fileUtil.LastCTime();
			this->_mtime = fileUtil.LastMTime();
			this->_backupPath = filename;
			this->_zipPath = zipDir + fileUtil.FileName() + zipSuffix; // ./zipDir/a.txt.lz
			this->_url = urlPrefix + fileUtil.FileName();			   // download/a.txt

			return true;
		}

		void showMsg()
		{
			std::cout << "_isZipped: " << _isZipped << std::endl;
			std::cout << "_fsize: " << _fsize << std::endl;
			std::cout << "_atime: " << _atime << std::endl;
			std::cout << "_ctime: " << _ctime << std::endl;
			std::cout << "_mtime: " << _mtime << std::endl;
			std::cout << "_backupPath: " << _backupPath << std::endl;
			std::cout << "_zipPath: " << _zipPath << std::endl;
			std::cout << "_url: " << _url << std::endl;
		}
	} BackupAInfo;

	// 数据管理类 怎么管理
	class DataManager
	{
	private:
		// 该文件存储诸多已备份文件的属性信息 json对象序列化成str保存在该文件
		std::string _backupAInfoFile;
		// 使用hash表在内存中管理数据 以url作为key值--查询速度快
		std::unordered_map<std::string, BackupAInfo> _table;
		// 读写锁:读共享 写互斥
		pthread_rwlock_t _rwlock;
		/*
		以URL为key BackupAInfo为val 使用哈希表管理 查询速度快
		url作为key:浏览器下载文件的时候总是以url作为请求
		*/
	public:
		DataManager()
		{
			// 成员属性初始化
			_backupAInfoFile = Config::GetInstance()->GetBackupAInfoFName(); // 获取存放备份文件属性信息的文件
			pthread_rwlock_init(&_rwlock, NULL);							 // 初始化读写锁
			InitLoad();
		}

		~DataManager()
		{
			pthread_rwlock_destroy(&_rwlock); // 销毁读写锁
		}

		// 每次程序运行前 从 存放备份文件属性信息的文件中 中读取数据至内存中的哈希表
		// 服务端初次运行时 _backupAInfoFile文件不存在 函数一路调用直到setContent才创建backupAInfo.dat
		// 服务端启动后 当备份文件增多 里面的信息就会不断增多
		bool InitLoad() // 备份文件属性信息 从文件->内存
		{
			// 1. 将备份文件属性信息读取出来存至content binary->str
			FileUtil fileUtil(_backupAInfoFile);
			// 存放备份文件属性信息的文件 不存在(首次启动) 无须load 函数返回
			if (fileUtil.Exists() == false)
			{
				Log::log(Info, "DataManager::InitLoad file not exist, no need to load: %s: %d", strerror(errno), errno);
				return true;
			}
			std::string content;
			fileUtil.GetContent(&content);

			// 2. str反序列化成json对象 str->json
			Json::Value root;
			JsonUtil::Deserialize(content, &root);

			// 3. 将反序列化得到的Json::Value中的数据添加到table中
			for (int i = 0; i < root.size(); i++)
			{
				BackupAInfo info;
				info._isZipped = root[i]["_isZipped"].asBool();
				info._fsize = root[i]["_fsize"].asInt64();
				info._atime = root[i]["_atime"].asInt64();
				info._ctime = root[i]["_ctime"].asInt64();
				info._mtime = root[i]["_mtime"].asInt64();
				info._zipPath = root[i]["_zipPath"].asString();
				info._backupPath = root[i]["_backupPath"].asString();
				info._url = root[i]["_url"].asString();

				Insert_Table(info);
			}
			return true;
		}

		// 将一个个 文件属性信息插入到表中
		bool Insert_Table(const BackupAInfo &info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			_table[info._url] = info;
			pthread_rwlock_unlock(&_rwlock);

			Storage();
			return true;
		}

		// 每次数据新增或修改后重新进行持久化存储 避免数据丢失
		bool Storage()
		{
			// 1. 获取当前表中的所有的BackupAInfo
			std::vector<BackupAInfo> array;
			this->GetAllBackupAInfo(&array);

			// 2. 添加到Json::Value
			Json::Value root;
			for (int i = 0; i < array.size(); i++)
			{
				Json::Value item;
				item["_isZipped"] = array[i]._isZipped;
				item["_fsize"] = (Json::Int64)array[i]._fsize;
				item["_atime"] = (Json::Int64)array[i]._atime;
				item["_ctime"] = (Json::Int64)array[i]._ctime;
				item["_mtime"] = (Json::Int64)array[i]._mtime;
				item["_backupPath"] = array[i]._backupPath;
				item["_zipPath"] = array[i]._zipPath;
				item["_url"] = array[i]._url;

				root.append(item); // 添加数组元素
			}

			// 3. Json::Value序列化成字符串
			std::string content;
			JsonUtil::Serialize(root, &content);

			// 4. 写文件
			FileUtil fileUtil(_backupAInfoFile);
			fileUtil.SetContent(content);

			return true;
		}

		// 获取当前表中的所有的BackupAInfo 存入array
		bool GetAllBackupAInfo(std::vector<BackupAInfo> *array)
		{
			pthread_rwlock_wrlock(&_rwlock);

			for (auto it = _table.begin(); it != _table.end(); ++it)
				array->push_back(it->second);

			pthread_rwlock_unlock(&_rwlock);
			return true;
		}

		bool Update(const BackupAInfo &info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			_table[info._url] = info;
			pthread_rwlock_unlock(&_rwlock);
			Storage();
			return true;
		}

		bool GetOneByURL(const std::string &url, BackupAInfo *info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			// url是key值 直接通过find进行查找
			auto it = _table.find(url);
			if (it == _table.end())
			{
				pthread_rwlock_unlock(&_rwlock);
				Log::log(Error, "DataManager::GetOneByURL not find url-?: %s: %d", strerror(errno), errno);
				return false;
			}
			*info = it->second;
			pthread_rwlock_unlock(&_rwlock);
			return true;
		}

		bool GetOneByRealPath(const std::string &filename, BackupAInfo *info)
		{
			pthread_rwlock_wrlock(&_rwlock);
			for (auto it = _table.begin(); it != _table.end(); ++it)
			{
				if (it->second._backupPath == filename)
				{
					*info = it->second;
					pthread_rwlock_unlock(&_rwlock);
					return true;
				}
			}
			pthread_rwlock_unlock(&_rwlock);
			Log::log(Error, "DataManager::GetOneByRealPath not find realpath-?: %s: %d", strerror(errno), errno);

			return false;
		}
	};
}
#endif //__MY_DATA__

测试代码

#include "fileUtil.hpp"
#include "jsonUtil.hpp"
#include "config.hpp"
#include "data.hpp"
// #include "hot.hpp"
// #include "service.hpp"
#include <thread>
using namespace std;
void DataTest(const std::string &filename)
{
	// 假设命令行参数传来的文件是备份文件 为该文件设置备份信息
	std::cout << "NewBackupAInfo " << std::endl;
	cloudBackup::BackupAInfo info;
	info.NewBackupAInfo(filename);
	info.showMsg();
	std::cout << std::endl;

	// 将备份文件信息添加到表中 与url形成映射
	// dataManager一旦实例化 调用构造 获取存放备份文件属性信息的文件名
	// 把备份文件属性信息从文件加载到内存(hashMap)
	std::cout << " GetOneByURL" << std::endl;
	cloudBackup::DataManager dataManager;
	dataManager.Insert_Table(info);
	cloudBackup::BackupAInfo tmp;
	dataManager.GetOneByURL("/download/makefile", &tmp);
	tmp.showMsg();
	std::cout << std::endl;

	std::cout << "GetAllBackupAInfo " << std::endl;
	std::vector<cloudBackup::BackupAInfo> array;
	dataManager.GetAllBackupAInfo(&array);
	for (auto &a : array)
		a.showMsg();
	std::cout << std::endl;

	std::cout << "info._isZipped = true " << std::endl;
	info._isZipped = true;
	dataManager.Update(info);
	array.clear();
	dataManager.GetAllBackupAInfo(&array);
	for (auto &a : array)
		a.showMsg();
	std::cout << std::endl;

	std::cout << "GetOneByRealPath" << std::endl;
	dataManager.GetOneByRealPath(filename, &tmp);
	tmp.showMsg();
	std::cout << std::endl;
}
int main(int argc, char *argv[])
{
	// FileUtilTest(argv[1]);
	//  JsonUtilTest();
	//  ConfigTest();
	DataTest(argv[1]);

	return 0;
}

数据管理总结

  1. backupAInfo.dat:存放的是备份文件属性信息。其中的reqDownloadPath是备份文件被用户通过浏览器下载时候的http请求资源路径。

在这里插入图片描述

  1. std::unordered_map<std::string, BackupAInfo> _table;存放:以reqDownloadPath为key,以backupAInfo_root对象为value的键值对
  2. 代码总体

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿猿收手吧!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值