文章目录
- [1. 数据管理模块要管理什么数据?](#1. 数据管理模块要管理什么数据?)
- [2. 数据管理模块如何管理数据?](#2. 数据管理模块如何管理数据?)
- [3. 数据管理模块的具体实现](#3. 数据管理模块的具体实现)
-
- [BackupInfo 数据信息类](#BackupInfo 数据信息类)
-
- [NewBackupInfo ------ 获取各项属性信息](#NewBackupInfo —— 获取各项属性信息)
- [DataManager 数据管理类](#DataManager 数据管理类)
-
- 构造函数
- 析构函数
- [insert ------ 新增](#insert —— 新增)
- [update ------ 修改](#update —— 修改)
- GetOneByURL------通过URL获取单个数据
- GetOneByURL------通过realpath获取单个数据
- [GETALL ------ 获取所有](#GETALL —— 获取所有)
- [Storage ------ 持久化存储实现](#Storage —— 持久化存储实现)
- 具体代码实现
1. 数据管理模块要管理什么数据?
1.文件实际存储路径
(当客户端下载文件时,则从文件中读取数据进行响应)
- 文件压缩包存放路径名
(如果一个文件是非热点文件,就会被压缩,则就为压缩包路径名称)
3.文件是否被压缩的标志位
(判断文件是否已经被压缩了)
4.文件大小
5.文件最后一次修改时间
6.文件最后一次访问时间
7. 文件访问URL中的资源路径path
2. 数据管理模块如何管理数据?
1.用于数据信息访问
(使用hash表在内存中管理数据,以url的path作为key值,来查询内部存储的数据,查询速度快)
2.持久化存储管理
使用json序列化 将 所有数据信息 保存在文件中
3. 数据管理模块的具体实现
BackupInfo 数据信息类
数据信息结构体 BackupInfo_t 包含
pack_flag ------是否压缩标志
fsize ------文件大小
latime ------最后一次访问时间
lmtime ------最后一次修改时间
real_path ------文件实际存储路径名称
pack_path ------压缩包存储路径名称
url_path ------请求资源路径
NewBackupInfo ------ 获取各项属性信息
将 NewBackupInfo 函数的参数 realpath路径名 传入 ,实例化一个 FileUtil类的对象
由于是新创建的文件,所以不用压缩
分别调用 FileUtil类 中的 Filesize(文件大小) 、 LastMtime( 文件最后一次修改时间)、 LastATime( 文件最后一次访问时间)
传入的 realpath 就为 文件实际存储路径名称
想要获取压缩包存储路径名称(pack_path) 则需将文件的前缀名换为 ./pack 后缀为换为.lz
实例化一个 Config类的对象,借助 Config类 的GetpackDir(压缩包存放路径)、GetPackFileSuffix(压缩包后缀名称)
通过前缀 、后缀 再加上 中间的文件名称 即可 获得 压缩包存储路径名称
借助 Config类 的GetDownloadPrefix(URL前缀路径) ,再加上文件名称 即可获得请求资源路径
DataManager 数据管理类
构造函数
输入 man pthread_rwlock_init 查看锁的初始化
第一个参数为 rwlock 为 读写锁
第二个参数为 attr 为属性
将属性设置为NULL即可
析构函数
输入 man pthread_rwlock_init 也可查看锁的销毁
insert ------ 新增
insert插入,想要进行修改就需要 加写锁 即修改table
table作为一个哈希表, info.url 为 key值 info作为value
最后进行解锁即可
update ------ 修改
哈希表的数据不会重复,所以当key值相同时,info会覆盖之前的数据
所以插入和修改的代码是相同的
GetOneByURL------通过URL获取单个数据
先加锁
然后再使用find 查找key值为url的数据
若查找到末尾都没有找到 则返回 false
若找到了 先解锁 再返回 url对应的info
GetOneByURL------通过realpath获取单个数据
realpath不是key值,而是info中的一个成员变量, 所以不能使用find来查找
先加锁 再遍历整个哈希表来查找
若找到了对应的realpath ,则将对应的value放入info中 并解锁 返回true
若遍历整个哈希表 都没找到 ,则解锁 返回false
GETALL ------ 获取所有
同样是先加锁 再遍历整个哈希表
每遍历一次,就向arry数组中插入当前哈希表数据对应的info
遍历完后 进行解锁 返回 true即可
Storage ------ 持久化存储实现
先定义 一个 BackupInfo 类型的 arry数组
并调用 GetAll 获取所有数据 放入 arry数组中
遍历整个arry数组,将当前arry数组中的元素 的 是否压缩标志、 文件大小、最后一次访问时间、 最后一次修改时间、文件实际存储路径名称、 压缩包存储路径名称、请求资源路径 全部放入 item 中
再把 数组元素 item 添加到 root中
定义一个string类型的变量body
通过之前实现好的 Serialize 函数 进行序列化 即将root中的数据 转化到body文件中
通过 _backup_file 数据持久化存储文件 实例化一个对象
再通过FileUtil类中 的 Setcontent 函数 将body写入到 _backup_file 文件中
具体代码实现
data.hpp
cpp
#ifndef _MY_DATA_
#define _MY_DATA_
#include<unordered_map>
#include<pthread.h>
#include"config.hpp"
namespace cloud
{
typedef struct BackupInfo
{
bool pack_flag;//压缩标志
size_t fsize; //文件大小
time_t mtime; //最后一次修改时间
time_t atime; //最后一次访问时间
std::string real_path;//文件实际存储路径
std::string pack_path;//压缩包存储路径名称
std::string url; //请求资源路径
bool NewBackupInfo(const std::string &realpath)//获取各项属性信息
{
FileUtil fu(realpath);
if(fu.Exists()==false)
{
std::cout<<"new backupinfo file not exists" <<std::endl;
return false;
}
Config* config=Config::GetInstance();//创建对象
std::string packdir=config->GetPackDir();//压缩包存放路径
std::string packsuffix=config->GetPackFileSuffix();//压缩包后缀名称
std::string download_prefix =config->GetDownloadPrefix();//URL前缀路径
this->pack_flag=false;
this->fsize=fu.FileSize();
this->mtime=fu.LastMTime();
this->atime=fu.LastATime();
this->real_path=realpath;
this->pack_path = packdir+fu.FileName()+packsuffix;
// ./backdir/a.txt -> ./packdir/a.txt.lz
this->url=download_prefix + fu.FileName();
//./backdir/a.txt -> /download/a.txt
return true;
}
}BackupInfo;
class DataManger
{
private:
std::string _backup_file;//数据持久化存储文件
pthread_rwlock_t _rwlock;//读写锁
std::unordered_map<std::string,BackupInfo> _table;//哈希表
public:
DataManger()//构造函数
{
_backup_file=Config::GetInstance()->GetBackupFile();//数据信息存放文件
pthread_rwlock_init(&_rwlock,NULL);//对读写锁初始化
}
~DataManger()//析构函数
{
pthread_rwlock_destroy(&_rwlock);//对读写锁进行销毁
}
bool Insert(const BackupInfo &info)//新增
{
pthread_rwlock_wrlock(&_rwlock);//加写锁
_table[info.url]=info;
pthread_rwlock_unlock(&_rwlock);//解锁
Storage();
return true;
}
bool update(const BackupInfo& info)//更新
{
pthread_rwlock_wrlock(&_rwlock);//加写锁
_table[info.url]=info;
pthread_rwlock_unlock(&_rwlock);//解锁
Storage();
return true;
}
bool GetOneByURL(const std::string &url,BackupInfo*info)//通过URL获取单个数据
{
pthread_rwlock_wrlock(&_rwlock);//加写锁
//因为url是key值 所以可以直接通过key值来进行查找
auto it=_table.find(url);
if(it==_table.end())
{
return false;
}
*info= it->second;//获取url对应的info
pthread_rwlock_unlock(&_rwlock);//解锁
return true;
}
bool GetOneByRealPath(const std::string &realpath ,BackupInfo*info)//通过realpath获取单个数据
{
pthread_rwlock_wrlock(&_rwlock);//加写锁
auto it=_table.begin();
for(;it!=_table.end();++it)//遍历
{
if(it->second.real_path==realpath)
{
*info=it->second;
pthread_rwlock_unlock(&_rwlock);//解锁
return true;
}
}
pthread_rwlock_unlock(&_rwlock);//解锁
return false;
}
bool GetAll(std::vector<BackupInfo>*arry) //获取所有
{
pthread_rwlock_wrlock(&_rwlock);//加写锁
auto it=_table.begin();
for(;it!=_table.end();++it)//遍历
{
arry->push_back(it->second);
}
pthread_rwlock_unlock(&_rwlock);//解锁
return true;
}
bool Storage()//持久化存储实现
{
//获取所有数据
std::vector<BackupInfo> arry;
this->GetAll(&arry);//获取所有数据放入arry中
//添加到json::value中
Json::Value root;
for(int i=0;i<arry.size();i++)
{
Json::Value item;
item["pack_flag"]= arry[i].pack_flag;
item["fsize"]= (Json::Int64)arry[i].fsize;
item["atime"]= (Json::Int64)arry[i].atime;
item["mtime"]= (Json::Int64)arry[i].mtime;
item["real_path"]= arry[i].real_path;
item["pack_path"]= arry[i].pack_path;
item["url"]= arry[i].url;
root.append(item); //添加数组元素item
}
// 对json::value 序列化
std::string body;
JsonUtil::Serialize(root,&body);//序列化
//写文件
FileUtil fu(_backup_file);//数据持久化存储文件
fu.Setcontent(body);
return true;
}
};
}
#endif