录像空间管理
This commit is contained in:
parent
4705890d04
commit
9cff02f30c
@ -60,6 +60,10 @@ class RecordManager
|
||||
|
||||
bool loadSrsConfig(); // 解析配置文件,填充 record_dir_ 和 dvr_duration_sec_
|
||||
|
||||
void removeExpiredDays();
|
||||
void removeOldestHoursUntilSafe();
|
||||
void cleanupStorage();
|
||||
|
||||
// === 文件列表索引 ===
|
||||
std::unordered_map<std::string, std::vector<RecordFileInfo>> index_;
|
||||
std::mutex index_mutex_;
|
||||
@ -76,6 +80,10 @@ class RecordManager
|
||||
std::thread scan_thread_;
|
||||
std::atomic<bool> running_{false};
|
||||
int scan_interval_sec_ = 60;
|
||||
|
||||
// ==== Storage management config ====
|
||||
int retention_days_ = 14; // 保留最近 N 天
|
||||
double usage_threshold_ = 0.90; // 超过 90% 就进行空间清理
|
||||
};
|
||||
|
||||
extern std::shared_ptr<RecordManager> g_record_manager;
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#include "record_manager.hpp"
|
||||
|
||||
#include <sys/statvfs.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
@ -123,6 +125,153 @@ bool RecordManager::loadSrsConfig()
|
||||
return true;
|
||||
}
|
||||
|
||||
void RecordManager::removeExpiredDays()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
|
||||
|
||||
for (auto& streamEntry : fs::directory_iterator(record_dir_))
|
||||
{
|
||||
if (!streamEntry.is_directory()) continue;
|
||||
|
||||
for (auto& dayEntry : fs::directory_iterator(streamEntry))
|
||||
{
|
||||
if (!dayEntry.is_directory()) continue;
|
||||
|
||||
std::string dayName = dayEntry.path().filename().string(); // 2025-11-14
|
||||
std::tm tm{};
|
||||
|
||||
if (sscanf(dayName.c_str(), "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) continue;
|
||||
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
time_t dayTime = mktime(&tm);
|
||||
|
||||
double daysOld = difftime(now, dayTime) / 86400.0;
|
||||
|
||||
if (daysOld > retention_days_)
|
||||
{
|
||||
LOG_WARN("[RecordManager] Removing expired day: " + dayEntry.path().string());
|
||||
fs::remove_all(dayEntry.path());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RecordManager::removeOldestHoursUntilSafe()
|
||||
{
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// 1) 检查磁盘
|
||||
struct statvfs vfs{};
|
||||
if (statvfs(record_dir_.c_str(), &vfs) != 0) return;
|
||||
|
||||
double used = 1.0 - (double)vfs.f_bavail / (double)vfs.f_blocks;
|
||||
if (used < usage_threshold_) break;
|
||||
|
||||
// 2) 找全盘最旧的 day
|
||||
fs::path oldestDay;
|
||||
time_t oldestTime = 0;
|
||||
|
||||
for (auto& streamDir : fs::directory_iterator(record_dir_))
|
||||
{
|
||||
if (!streamDir.is_directory()) continue;
|
||||
|
||||
for (auto& dayDir : fs::directory_iterator(streamDir))
|
||||
{
|
||||
if (!dayDir.is_directory()) continue;
|
||||
|
||||
std::string dayName = dayDir.path().filename().string();
|
||||
std::tm tm{};
|
||||
if (sscanf(dayName.c_str(), "%d-%d-%d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) != 3) continue;
|
||||
|
||||
tm.tm_year -= 1900;
|
||||
tm.tm_mon -= 1;
|
||||
time_t t = mktime(&tm);
|
||||
|
||||
if (oldestDay.empty() || t < oldestTime)
|
||||
{
|
||||
oldestTime = t;
|
||||
oldestDay = dayDir.path();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldestDay.empty())
|
||||
{
|
||||
LOG_WARN("[RecordManager] No day folder found for hour cleanup.");
|
||||
break;
|
||||
}
|
||||
|
||||
// ---- 找该 day 下最旧的 hour ----
|
||||
fs::path oldestHour;
|
||||
int oldestHourValue = -1;
|
||||
|
||||
for (auto& hourDir : fs::directory_iterator(oldestDay))
|
||||
{
|
||||
if (!hourDir.is_directory()) continue;
|
||||
|
||||
std::string hourName = hourDir.path().filename().string();
|
||||
int h = -1;
|
||||
if (sscanf(hourName.c_str(), "%d", &h) != 1) continue;
|
||||
|
||||
if (oldestHourValue == -1 || h < oldestHourValue)
|
||||
{
|
||||
oldestHourValue = h;
|
||||
oldestHour = hourDir.path();
|
||||
}
|
||||
}
|
||||
|
||||
if (oldestHour.empty())
|
||||
{
|
||||
LOG_WARN("[RecordManager] Day empty, remove whole day: " + oldestDay.string());
|
||||
fs::remove_all(oldestDay);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ---- 删除最旧 hour ----
|
||||
LOG_WARN("[RecordManager] Removing oldest hour: " + oldestHour.string());
|
||||
fs::remove_all(oldestHour);
|
||||
|
||||
// 如果此 day 已空 → 删除 day 目录
|
||||
if (fs::is_empty(oldestDay))
|
||||
{
|
||||
LOG_WARN("[RecordManager] Removing empty day: " + oldestDay.string());
|
||||
fs::remove_all(oldestDay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RecordManager::cleanupStorage()
|
||||
{
|
||||
struct statvfs vfs{};
|
||||
if (statvfs(record_dir_.c_str(), &vfs) != 0)
|
||||
{
|
||||
LOG_ERROR("[RecordManager] statvfs failed for " + record_dir_);
|
||||
return;
|
||||
}
|
||||
|
||||
double used = 1.0 - (double)vfs.f_bavail / (double)vfs.f_blocks;
|
||||
|
||||
// 1) 删除超期天
|
||||
removeExpiredDays();
|
||||
|
||||
// 重新检查磁盘
|
||||
if (statvfs(record_dir_.c_str(), &vfs) == 0)
|
||||
{
|
||||
used = 1.0 - (double)vfs.f_bavail / (double)vfs.f_blocks;
|
||||
}
|
||||
|
||||
// 2) 使用率仍超 → 按小时清理
|
||||
if (used >= usage_threshold_)
|
||||
{
|
||||
removeOldestHoursUntilSafe();
|
||||
}
|
||||
}
|
||||
|
||||
void RecordManager::startAutoScan(int interval_sec)
|
||||
{
|
||||
scan_interval_sec_ = interval_sec;
|
||||
@ -141,6 +290,7 @@ void RecordManager::startAutoScan(int interval_sec)
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
|
||||
this->scanAll();
|
||||
this->cleanupStorage();
|
||||
LOG_INFO("[RecordManager] scanAll() completed.");
|
||||
|
||||
// 休眠剩余时间(支持快速退出)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user