Skip to content

Commit

Permalink
[wpiutil] DataLog: Stop logging if insufficient free space (wpilibsui…
Browse files Browse the repository at this point in the history
…te#5699)

The threshold is set to 5 MB.
  • Loading branch information
PeterJohnson authored Oct 1, 2023
1 parent 48facb9 commit 8d2cbfc
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 24 deletions.
2 changes: 1 addition & 1 deletion wpilibc/src/main/native/cpp/DataLogManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Thread::~Thread() {
void Thread::Main() {
// based on free disk space, scan for "old" FRC_*.wpilog files and remove
{
uintmax_t freeSpace = fs::space(m_logDir).free;
uintmax_t freeSpace = fs::space(m_logDir).available;
if (freeSpace < kFreeSpaceThreshold) {
// Delete oldest FRC_*.wpilog files (ignore FRC_TBD_*.wpilog as we just
// created one)
Expand Down
94 changes: 71 additions & 23 deletions wpiutil/src/main/native/cpp/DataLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
fs::file_t f = fs::kInvalidFile;

// 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 {
// 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);
// 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);
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 (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 '{}'", (dirPath / filename).string());
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)
Expand All @@ -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) {
Expand All @@ -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();
Expand Down Expand Up @@ -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);
}

Expand All @@ -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
Expand Down

0 comments on commit 8d2cbfc

Please sign in to comment.