mirror of
https://github.com/scottlamb/moonfire-nvr.git
synced 2024-12-26 07:05:56 -05:00
Add helper for adjusting date-to-duration map.
The helper isn't used yet. The goal is to export this on /camera/<uuid>/ as described in a TODO in design/api.md. The next step is to keep MoonfireDatabase::CameraData::days up-to-date: * Init: call on every recording (replacing the current aggregated query with a recording-by-recording query) * InsertRecording, DeleteRecordings: call for added/removed recordings then return it from GetCamera and pass it along to the client in WebInterface::HandleJsonCameraDetail.
This commit is contained in:
parent
a7bfb00083
commit
292bcbaad5
@ -28,6 +28,8 @@
|
||||
//
|
||||
// moonfire-db-test.cc: tests of the moonfire-db.h interface.
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
@ -232,6 +234,63 @@ class MoonfireDbTest : public testing::Test {
|
||||
std::unique_ptr<MoonfireDatabase> mdb_;
|
||||
};
|
||||
|
||||
TEST(AdjustDaysMapTest, Basic) {
|
||||
std::map<std::string, int64_t> days;
|
||||
|
||||
// Create a day.
|
||||
const int64_t kTestTime = INT64_C(130647162600000); // 2015-12-31 23:59:00
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 60 * kTimeUnitsPerSecond, 1, &days);
|
||||
EXPECT_THAT(days, testing::ElementsAre(std::make_pair(
|
||||
"2015-12-31", 60 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Add to a day.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 60 * kTimeUnitsPerSecond, 1, &days);
|
||||
EXPECT_THAT(days, testing::ElementsAre(std::make_pair(
|
||||
"2015-12-31", 120 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Subtract from a day.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 60 * kTimeUnitsPerSecond, -1, &days);
|
||||
EXPECT_THAT(days, testing::ElementsAre(std::make_pair(
|
||||
"2015-12-31", 60 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Remove a day.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 60 * kTimeUnitsPerSecond, -1, &days);
|
||||
EXPECT_THAT(days, testing::ElementsAre());
|
||||
|
||||
// Create two days.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 3 * 60 * kTimeUnitsPerSecond, 1, &days);
|
||||
EXPECT_THAT(days,
|
||||
testing::ElementsAre(
|
||||
std::make_pair("2015-12-31", 1 * 60 * kTimeUnitsPerSecond),
|
||||
std::make_pair("2016-01-01", 2 * 60 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Add to two days.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 3 * 60 * kTimeUnitsPerSecond, 1, &days);
|
||||
EXPECT_THAT(days,
|
||||
testing::ElementsAre(
|
||||
std::make_pair("2015-12-31", 2 * 60 * kTimeUnitsPerSecond),
|
||||
std::make_pair("2016-01-01", 4 * 60 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Subtract from two days.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 3 * 60 * kTimeUnitsPerSecond, -1, &days);
|
||||
EXPECT_THAT(days,
|
||||
testing::ElementsAre(
|
||||
std::make_pair("2015-12-31", 1 * 60 * kTimeUnitsPerSecond),
|
||||
std::make_pair("2016-01-01", 2 * 60 * kTimeUnitsPerSecond)));
|
||||
|
||||
// Remove two days.
|
||||
moonfire_nvr::internal::AdjustDaysMap(
|
||||
kTestTime, kTestTime + 3 * 60 * kTimeUnitsPerSecond, -1, &days);
|
||||
EXPECT_THAT(days, testing::ElementsAre());
|
||||
}
|
||||
|
||||
// Basic test of running some queries on an empty database.
|
||||
TEST_F(MoonfireDbTest, EmptyDatabase) {
|
||||
std::string error_message;
|
||||
@ -337,7 +396,6 @@ TEST_F(MoonfireDbTest, FullLifecycle) {
|
||||
EXPECT_TRUE(mdb_->ListReservedSampleFiles(&reserved, &error_message))
|
||||
<< error_message;
|
||||
EXPECT_THAT(reserved, testing::UnorderedElementsAre(uuids[0], uuids[1]));
|
||||
LOG(INFO) << "after delete";
|
||||
ExpectNoRecordings(camera_uuid);
|
||||
|
||||
EXPECT_TRUE(mdb_->MarkSampleFilesDeleted(uuids, &error_message))
|
||||
@ -355,5 +413,10 @@ int main(int argc, char **argv) {
|
||||
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
// The calendar day math assumes this timezone.
|
||||
CHECK_EQ(0, setenv("TZ", "America/Los_Angeles", 1)) << strerror(errno);
|
||||
tzset();
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
@ -33,6 +33,8 @@
|
||||
|
||||
#include "moonfire-db.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <glog/logging.h>
|
||||
@ -43,6 +45,78 @@
|
||||
|
||||
namespace moonfire_nvr {
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper for AdjustDaysMap.
|
||||
void AdjustDay(const std::string &day, int64_t delta,
|
||||
std::map<std::string, int64_t> *days) {
|
||||
auto it = days->find(day);
|
||||
if (it != days->end()) {
|
||||
it->second += delta;
|
||||
DCHECK_GE(it->second, 0) << day << ", " << delta;
|
||||
if (it->second == 0) {
|
||||
days->erase(it);
|
||||
}
|
||||
} else {
|
||||
days->insert(it, std::make_pair(day, delta));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace internal {
|
||||
|
||||
void AdjustDaysMap(int64_t start_time_90k, int64_t end_time_90k, int sign,
|
||||
std::map<std::string, int64_t> *days) {
|
||||
// There will always be at most two days adjusted, because
|
||||
// kMaxRecordingDuration is less than a day (even during spring forward).
|
||||
DCHECK_LT(start_time_90k, end_time_90k);
|
||||
DCHECK_LE(end_time_90k - start_time_90k, kMaxRecordingDuration);
|
||||
static_assert(kMaxRecordingDuration <= 23 * 60 * kTimeUnitsPerSecond,
|
||||
"max duration should be less than a (spring-forward) day");
|
||||
|
||||
// Fill |buf| with the first day.
|
||||
struct tm mytm;
|
||||
memset(&mytm, 0, sizeof(mytm));
|
||||
time_t start_ts = start_time_90k / kTimeUnitsPerSecond;
|
||||
localtime_r(&start_ts, &mytm);
|
||||
const char kFmt[] = "%Y-%m-%d";
|
||||
char buf[sizeof("YYYY-mm-DD")];
|
||||
strftime(buf, sizeof(buf), kFmt, &mytm);
|
||||
|
||||
// Determine the start of the next day.
|
||||
// Note that mktime(3) normalizes tm_mday, so this should work on the last
|
||||
// day of the month/year.
|
||||
mytm.tm_isdst = -1;
|
||||
mytm.tm_hour = 0;
|
||||
mytm.tm_min = 0;
|
||||
mytm.tm_sec = 0;
|
||||
++mytm.tm_mday;
|
||||
auto boundary_90k = kTimeUnitsPerSecond * static_cast<int64_t>(mktime(&mytm));
|
||||
|
||||
// Adjust the first day.
|
||||
auto first_day_delta =
|
||||
sign * (std::min(end_time_90k, boundary_90k) - start_time_90k);
|
||||
DCHECK_NE(first_day_delta, 0) << "start=" << start_time_90k
|
||||
<< ", end=" << end_time_90k;
|
||||
AdjustDay(buf, first_day_delta, days);
|
||||
|
||||
if (end_time_90k <= boundary_90k) {
|
||||
return; // no second day.
|
||||
}
|
||||
|
||||
// Fill |buf| with the second day.
|
||||
strftime(buf, sizeof(buf), kFmt, &mytm);
|
||||
|
||||
// Adjust the second day.
|
||||
auto second_day_delta = sign * (end_time_90k - boundary_90k);
|
||||
DCHECK_NE(second_day_delta, 0) << "start=" << start_time_90k
|
||||
<< ", end=" << end_time_90k;
|
||||
AdjustDay(buf, second_day_delta, days);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
bool MoonfireDatabase::Init(Database *db, std::string *error_message) {
|
||||
CHECK(db_ == nullptr);
|
||||
db_ = db;
|
||||
|
@ -225,6 +225,12 @@ class MoonfireDatabase {
|
||||
int64_t max_end_time_90k = -1;
|
||||
int64_t total_sample_file_bytes = -1;
|
||||
int64_t total_duration_90k = -1;
|
||||
|
||||
// A map of calendar days (in the local timezone, "YYYY-mm-DD") to the
|
||||
// total duration (in 90k units) of recorded data in the day. A day is
|
||||
// present in the map ff the value is non-zero.
|
||||
// TODO: actually fill this.
|
||||
std::map<std::string, int64_t> days;
|
||||
};
|
||||
|
||||
enum class ReservationState { kWriting = 0, kDeleting = 1 };
|
||||
@ -253,6 +259,15 @@ class MoonfireDatabase {
|
||||
std::map<int64_t, VideoSampleEntry> video_sample_entries_;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Adjust a day-to-duration map (see MoonfireDatabase::CameraData::days_)
|
||||
// to reflect a recording.
|
||||
void AdjustDaysMap(int64_t start_time_90k, int64_t end_time_90k, int sign,
|
||||
std::map<std::string, int64_t> *days);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace moonfire_nvr
|
||||
|
||||
#endif // MOONFIRE_NVR_MOONFIRE_DB_H
|
||||
|
Loading…
Reference in New Issue
Block a user