数据管理模块功能:
后续项目需要使用的数据如下
- 文件实际存储路径:当客户端需要下载文件时,从这个文件中进行读取响应
- 文件压缩包存放路径名:如果文件是非热点文件会被压缩
如果客户端需要下载这些文件,需要先进行解压缩,然后返回 - 文件是否被压缩的标记位:判断文件是否被压缩了
- 文件大小,文件最后一次修改时间,文件最后一次访问时间
- 文件访问url中的资源路径path
数据管理模块管理数据方式:
- 用于数据信息访问:使用哈希表,在内存中管理数据,url的path作为key值
- 持久化存储管理:使用json序列化,将所有数据信息保存在文件中(不使用数据库)
数据管理模块被多个线程共享,使用读写锁更好(读共享,写互斥)。每次数据更新都要重新持久化存储,避免数据丢失。每次服务器重启都要加载以前的数据
文件数据结构体设计如下:
#pragma once
#include "./util/fileutil.hpp"
#include <unordered_map>
#include <pthread.h>
#include "./config/config.hpp"
namespace CloudBackups
{struct BackupInfo{bool packflag; // 压缩标记size_t size; // 文件大小time_t mtime; // 最后一次修改时间time_t atime; // 最后一次访问时间std::string real_path; // 实际文件存储位置std::string pack_path; // 文件压缩存储位置std::string url;// 打开文件初始化BackInfoBackupInfo(const std::string &real_path){this->packflag = false;FileUtil file(real_path);if (file.isExit()) // 文件存在时才可以获取下面的信息{this->size = file.filesize();this->mtime = file.last_modify_time();this->atime = file.last_visit_time();this->real_path = real_path;// 获取配置文件的压缩文件路径Config *config = Config::GetInstance();std::string packdir = config->GetPackfileDir(); // 压缩文件根目录std::string suffix = config->GetPackfileSuffix(); // 压缩文件后缀std::string zipname = file.filename() + suffix;this->pack_path = packdir + "/" + zipname; // 压缩文件路径std::string download = config->GetDownloadPrefix();this->url = download + "/" + file.filename(); // 下载请求路径}else{LOG(FATAL, "file not found");}}};
}
数据管理模块设计如下:
#pragma once
#include "./util/fileutil.hpp"
#include <unordered_map>
#include <pthread.h>
#include "./config/config.hpp"
#include "./util/json.hpp"
namespace CloudBackups
{class DataMange{private:pthread_rwlock_t rwlock; // 读写锁,读共享,写互斥std::unordered_map<std::string, BackupInfo> backupMap; // 文件请求路径和对应信息的哈希表std::string backupFile; // 数据持久化信息文件,文件格式为jsonpublic:// 将backupMap持久化存储bool Storage(){// 获取所有数据std::vector<BackupInfo> backups;this->GetAll(backups);// 添加到Json::Value中Json::Value root;for (size_t i = 0; i < backups.size(); i++){Json::Value backup;backup["packflag"] = backups[i].packflag;backup["size"] = Json::Int64(backups[i].size);backup["mtime"] = Json::Int64(backups[i].mtime);backup["atime"] = Json::Int64(backups[i].atime);backup["real_path"] = backups[i].real_path;backup["pack_path"] = backups[i].pack_path;backup["url"] = backups[i].url;root.append(backup);}// 持久化 序列化+保存// 序列化std::string body;JsonUtil::serialize(root, body);// 保存文件FileUtil file(backupFile);file.setContent(body);return true;}// 加载配置信息,初始化backupMapbool InitLoad(){// 读取Json文件FileUtil file(backupFile);if (file.isExit() == false){// 服务器文件信息不存在,无需初始化return true;}std::string body;file.getContent(body);// 反序列化Json::Value root;if (JsonUtil::unserialize(body, root) == true){// 将反序列化的数据写到map上for (int i = 0; i < root.size(); i++){BackupInfo backupInfo;backupInfo.packflag = root[i]["packflag"].asBool();backupInfo.size = root[i]["size"].asInt64();backupInfo.mtime = root[i]["mtime"].asInt64();backupInfo.atime = root[i]["atime"].asInt64();backupInfo.real_path = root[i]["real_path"].asString();backupInfo.pack_path = root[i]["pack_path"].asString();backupInfo.url = root[i]["url"].asString();Insert(backupInfo);}return true;}return false;}DataMange(){backupFile = Config::GetInstance()->GetBackupFile();pthread_rwlock_init(&rwlock, nullptr);InitLoad();}~DataMange(){pthread_rwlock_destroy(&rwlock);}// 数据管理模块插入信息bool Insert(const BackupInfo &backupInfo){pthread_rwlock_wrlock(&rwlock);backupMap[backupInfo.url] = backupInfo;pthread_rwlock_unlock(&rwlock);Storage();return true;}// 更新数据管理模块bool UpDate(const BackupInfo &backupInfo){pthread_rwlock_wrlock(&rwlock);backupMap[backupInfo.url] = backupInfo;pthread_rwlock_unlock(&rwlock);Storage();return true;}// 通过url获取这个文件bool GetByUrl(const std::string &url, BackupInfo &backupInfo){pthread_rwlock_wrlock(&rwlock);auto pos = backupMap.find(url);if (pos == backupMap.end()){LOG(WARNING, "url map not found you url is: " + url);pthread_rwlock_unlock(&rwlock);return false;}backupInfo = pos->second;pthread_rwlock_unlock(&rwlock);return true;}// 通过http uri 获取文件信息bool GetByRealPath(const std::string &real_url, BackupInfo &backupInfo){pthread_rwlock_wrlock(&rwlock);auto pos = backupMap.begin();while (pos != backupMap.end()){if (pos->second.real_path == real_url){backupInfo = pos->second;pthread_rwlock_unlock(&rwlock);return true;}pos++;}LOG(WARNING, "http uti not found you uri is: " + real_url);pthread_rwlock_unlock(&rwlock);return false;}// 获取请求映射下所有文件信息bool GetAll(std::vector<BackupInfo> &backups){pthread_rwlock_wrlock(&rwlock);backups.clear();for (auto &backup : backupMap){backups.push_back(backup.second);}pthread_rwlock_unlock(&rwlock);return true;}};
}
Gitee位置
Github位置