[wpiutil] DataLog: Stop logging if insufficient free space (#5699)

The threshold is set to 5 MB.
This commit is contained in:
Peter Johnson
2023-10-01 14:01:49 -07:00
committed by GitHub
parent 48facb9cef
commit 8d2cbfce16
2 changed files with 75 additions and 27 deletions

View File

@@ -40,6 +40,22 @@ static constexpr size_t kBlockSize = 16 * 1024;
static constexpr size_t kMaxBufferCount = 1024 * 1024 / kBlockSize;
static constexpr size_t kMaxFreeCount = 256 * 1024 / kBlockSize;
static constexpr size_t kRecordMaxHeaderSize = 17;
static constexpr uintmax_t kMinFreeSpace = 5 * 1024 * 1024;
static std::string FormatBytesSize(uintmax_t value) {
static constexpr uintmax_t kKiB = 1024;
static constexpr uintmax_t kMiB = kKiB * 1024;
static constexpr uintmax_t kGiB = kMiB * 1024;
if (value >= kGiB) {
return fmt::format("{:.1f} GiB", static_cast<double>(value) / kGiB);
} else if (value >= kMiB) {
return fmt::format("{:.1f} MiB", static_cast<double>(value) / kMiB);
} else if (value >= kKiB) {
return fmt::format("{:.1f} KiB", static_cast<double>(value) / kKiB);
} else {
return fmt::format("{} B", value);
}
}
template <typename T>
static unsigned int WriteVarInt(uint8_t* buf, T val) {
@@ -256,32 +272,42 @@ void DataLog::WriterThreadMain(std::string_view dir) {
filename = MakeRandomFilename();
}
// try preferred filename, or randomize it a few times, before giving up
fs::file_t f;
for (int i = 0; i < 5; ++i) {
// open file for append
#ifdef _WIN32
// WIN32 doesn't allow combination of CreateNew and Append
f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
fs::OF_None);
#else
f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
fs::OF_Append);
#endif
if (ec) {
WPI_ERROR(m_msglog, "Could not open log file '{}': {}",
(dirPath / filename).string(), ec.message());
// try again with random filename
filename = MakeRandomFilename();
} else {
break;
}
}
fs::file_t f = fs::kInvalidFile;
if (f == fs::kInvalidFile) {
WPI_ERROR(m_msglog, "Could not open log file, no log being saved");
// get free space
uintmax_t freeSpace = fs::space(dirPath).available;
if (freeSpace < kMinFreeSpace) {
WPI_ERROR(m_msglog,
"Insufficient free space ({} available), no log being saved",
FormatBytesSize(freeSpace));
} else {
WPI_INFO(m_msglog, "Logging to '{}'", (dirPath / filename).string());
// try preferred filename, or randomize it a few times, before giving up
for (int i = 0; i < 5; ++i) {
// open file for append
#ifdef _WIN32
// WIN32 doesn't allow combination of CreateNew and Append
f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
fs::OF_None);
#else
f = fs::OpenFileForWrite(dirPath / filename, ec, fs::CD_CreateNew,
fs::OF_Append);
#endif
if (ec) {
WPI_ERROR(m_msglog, "Could not open log file '{}': {}",
(dirPath / filename).string(), ec.message());
// try again with random filename
filename = MakeRandomFilename();
} else {
break;
}
}
if (f == fs::kInvalidFile) {
WPI_ERROR(m_msglog, "Could not open log file, no log being saved");
} else {
WPI_INFO(m_msglog, "Logging to '{}' ({} free space)",
(dirPath / filename).string(), FormatBytesSize(freeSpace));
}
}
// write header (version 1.0)
@@ -300,6 +326,8 @@ void DataLog::WriterThreadMain(std::string_view dir) {
}
std::vector<Buffer> toWrite;
int freeSpaceCount = 0;
bool blocked = false;
std::unique_lock lock{m_mutex};
while (m_active) {
@@ -309,7 +337,7 @@ void DataLog::WriterThreadMain(std::string_view dir) {
doFlush = true;
}
if (!m_newFilename.empty()) {
if (!m_newFilename.empty() && f != fs::kInvalidFile) {
auto newFilename = std::move(m_newFilename);
m_newFilename.clear();
lock.unlock();
@@ -337,10 +365,27 @@ void DataLog::WriterThreadMain(std::string_view dir) {
// swap outgoing with empty vector
toWrite.swap(m_outgoing);
if (f != fs::kInvalidFile) {
if (f != fs::kInvalidFile && !blocked) {
lock.unlock();
// update free space every 10 flushes (in case other things are writing)
if (++freeSpaceCount >= 10) {
freeSpaceCount = 0;
freeSpace = fs::space(dirPath).available;
}
// write buffers to file
for (auto&& buf : toWrite) {
// stop writing when we go below the minimum free space
freeSpace -= buf.GetData().size();
if (freeSpace < kMinFreeSpace) {
[[unlikely]] WPI_ERROR(
m_msglog,
"Stopped logging due to low free space ({} available)",
FormatBytesSize(freeSpace));
blocked = true;
break;
}
WriteToFile(f, buf.GetData(), filename, m_msglog);
}
@@ -351,6 +396,9 @@ void DataLog::WriterThreadMain(std::string_view dir) {
::fsync(f);
#endif
lock.lock();
if (blocked) {
[[unlikely]] m_paused = true;
}
}
// release buffers back to free list