-
Notifications
You must be signed in to change notification settings - Fork 1
/
BackgroundWorker.cpp
121 lines (98 loc) · 3.63 KB
/
BackgroundWorker.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include "BackgroundWorker.h"
#include "DataEngine.h"
#include "DataSerializer.h"
#include "Logger.h"
#include "StatisticsPrinter.h"
#include <chrono>
void BackgroundWorker::run(const DataEngine& engine, const std::string& databaseFilename)
{
LOG_INFO << "BackgroundWorker: begin" << std::endl;
using namespace std::chrono_literals;
using clock = std::chrono::high_resolution_clock;
using time_point = std::chrono::time_point<clock>;
constexpr auto timeBetweenStatsPrints = 5s;
constexpr auto timeBetweenDataSaves = 14s;
static_assert(timeBetweenDataSaves >= timeBetweenStatsPrints);
StatisticsPrinter printer;
auto lastPrintTime = clock::now();
auto lastSaveTime = lastPrintTime;
while (true)
{
const auto printTime = clock::now();
{
const auto printSecondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(printTime - lastPrintTime);
const auto stats = engine.get_global_statistics();
printer.print_statistics(stats.m_reads, stats.m_writes, static_cast<unsigned>(printSecondsElapsed.count()));
lastPrintTime = printTime;
}
const auto saveTime = clock::now();
if (saveTime - lastSaveTime >= timeBetweenDataSaves)
{
const auto saveSecondsElapsed = std::chrono::duration_cast<std::chrono::seconds>(saveTime - lastSaveTime);
LOG_INFO << "BackgroundWorker: save data to file after " << saveSecondsElapsed.count() << " seconds" << std::endl;
const size_t savedRecordCount = store_data(engine, databaseFilename);
LOG_INFO << "BackgroundWorker: saved " << savedRecordCount << " DB records to file " << databaseFilename << std::endl;
lastSaveTime = saveTime;
}
{
std::unique_lock lock(m_protect);
const bool terminating = m_conditional.wait_until(
lock,
printTime + timeBetweenStatsPrints,
[this] { return m_terminating; }
);
if (terminating)
{
break;
}
}
}
LOG_INFO << "BackgroundWorker: end" << std::endl;
}
void BackgroundWorker::stop_notify()
{
LOG_INFO << "BackgroundWorker: stop_notify: begin" << std::endl;
{
const std::lock_guard lock(m_protect);
m_terminating = true;
}
m_conditional.notify_all();
LOG_INFO << "BackgroundWorker: stop_notify: end" << std::endl;
}
size_t BackgroundWorker::initial_load_data(DataEngine& engine, const std::string& databaseFilename)
{
size_t recordCount = 0;
auto loadVisitor = [&engine, &recordCount](const std::string_view name, const std::string_view value)
{
engine.initial_set(name, value);
++recordCount;
return;
};
const bool ok = DataSerializer::load(databaseFilename, loadVisitor);
if (!ok)
{
LOG_ERROR << "DataSerializer::load() failed" << std::endl;
return recordCount;
}
return recordCount;
}
size_t BackgroundWorker::store_data(const DataEngine& engine, const std::string& databaseFilename)
{
size_t recordCount = 0;
DataSerializer::Document document;
const std::function<DataEngine::EnumerateVisitorProc> visitor =
[&document, &recordCount](const std::string_view name, const std::string_view value)
{
document.add(name, value);
++recordCount;
return;
};
engine.enumerate(visitor);
const bool ok = DataSerializer::save(databaseFilename, document);
if (!ok)
{
LOG_ERROR << "DataSerializer::save() failed" << std::endl;
return recordCount;
}
return recordCount;
}