From d79405cdb712a3dfeea480599c6defb9f22d11c3 Mon Sep 17 00:00:00 2001 From: Florian Fischer <florian.fischer@muhq.space> Date: Mon, 21 Feb 2022 19:29:39 +0100 Subject: [PATCH] generalize LogBuffer to MappedFileBuffer --- .../MappedFileBuffer.cpp} | 46 +++++++++---------- emper/lib/MappedFileBuffer.hpp | 34 ++++++++++++++ emper/lib/meson.build | 1 + emper/log/LogBuffer.hpp | 30 +++--------- emper/log/meson.build | 1 - 5 files changed, 64 insertions(+), 48 deletions(-) rename emper/{log/LogBuffer.cpp => lib/MappedFileBuffer.cpp} (73%) create mode 100644 emper/lib/MappedFileBuffer.hpp diff --git a/emper/log/LogBuffer.cpp b/emper/lib/MappedFileBuffer.cpp similarity index 73% rename from emper/log/LogBuffer.cpp rename to emper/lib/MappedFileBuffer.cpp index 94bd3f7b..320e1253 100644 --- a/emper/log/LogBuffer.cpp +++ b/emper/lib/MappedFileBuffer.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2020 Florian Schmaus -#include "LogBuffer.hpp" +// Copyright © 2021-2022 Florian Fischer +#include "lib/MappedFileBuffer.hpp" #include <fcntl.h> #include <sys/mman.h> @@ -12,17 +12,17 @@ #include "Common.hpp" -namespace emper::log { +namespace emper::lib { -LogBuffer::LogBuffer(const std::string& logFile) : logFile(logFile) { - logFd = open(logFile.c_str(), O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (logFd == -1) { - DIE_MSG_ERRNO("opening log file " << logFile << " failed"); +MappedFileBuffer::MappedFileBuffer(const std::string& file) : file(file) { + fd = open(file.c_str(), O_RDWR | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd == -1) { + DIE_MSG_ERRNO("opening file " << file << " failed"); } for (size_t i = 0; i < BUFFER_COUNT; ++i) { const auto off = static_cast<off_t>(i * BUFFER_SIZE); - void* res = mmap(nullptr, BUFFER_SIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, logFd, off); + void* res = mmap(nullptr, BUFFER_SIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, fd, off); // NOLINTNEXTLINE(performance-no-int-to-ptr) if (res == MAP_FAILED) { DIE_MSG_ERRNO("mmap failed"); @@ -30,19 +30,19 @@ LogBuffer::LogBuffer(const std::string& logFile) : logFile(logFile) { bufs[i] = static_cast<char*>(res); } - if (ftruncate(logFd, BUFFER_COUNT * BUFFER_SIZE)) { - DIE_MSG_ERRNO("initial log file " << logFile << "truncation failed"); + if (ftruncate(fd, BUFFER_COUNT * BUFFER_SIZE)) { + DIE_MSG_ERRNO("initial mapped file " << file << "truncation failed"); } } -void LogBuffer::trim() { +void MappedFileBuffer::trim() { const auto finalPos = static_cast<off_t>(bufPos.load(std::memory_order_relaxed)); - if (ftruncate(logFd, finalPos)) { - DIE_MSG_ERRNO("trimming log file " << logFile << " failed"); + if (ftruncate(fd, finalPos)) { + DIE_MSG_ERRNO("trimming mapped file " << file << " failed"); } } -LogBuffer::~LogBuffer() { +MappedFileBuffer::~MappedFileBuffer() { trim(); for (auto* buf : bufs) { @@ -51,10 +51,10 @@ LogBuffer::~LogBuffer() { } } - close(logFd); + close(fd); } -void LogBuffer::log(const std::string& message) { +void MappedFileBuffer::put(const std::string& message) { const size_t messageLen = message.size(); const size_t startPos = bufPos.fetch_add(messageLen, std::memory_order_relaxed); const size_t endPos = startPos + messageLen - 1; @@ -104,16 +104,16 @@ void LogBuffer::log(const std::string& message) { // Therefore at bufPos = BUFFER_SIZE + 1 we are in the second active buffer const size_t nthActive = (endPos / BUFFER_SIZE) + 1; - // Our log file has the size of all ever active buffers plus the new fresh one - const auto logFileSize = static_cast<off_t>((nthActive + 1) * BUFFER_SIZE); + // Our mapped file has the size of all ever active buffers plus the new fresh one + const auto fileSize = static_cast<off_t>((nthActive + 1) * BUFFER_SIZE); - // Grow the log file - if (ftruncate(logFd, logFileSize)) { - DIE_MSG_ERRNO("growing log file " << logFile << " failed"); + // Grow the mapped file + if (ftruncate(fd, fileSize)) { + DIE_MSG_ERRNO("growing mapped file " << file << " failed"); } const auto nextOffset = static_cast<off_t>(nthActive * BUFFER_SIZE); - void* res = mmap(nullptr, BUFFER_SIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, logFd, nextOffset); + void* res = mmap(nullptr, BUFFER_SIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, fd, nextOffset); // NOLINTNEXTLINE(performance-no-int-to-ptr) if (res == MAP_FAILED) { DIE_MSG_ERRNO("mmap of fresh buffer failed"); @@ -125,4 +125,4 @@ void LogBuffer::log(const std::string& message) { } } -} // namespace emper::log +} // namespace emper::lib diff --git a/emper/lib/MappedFileBuffer.hpp b/emper/lib/MappedFileBuffer.hpp new file mode 100644 index 00000000..f267fa8d --- /dev/null +++ b/emper/lib/MappedFileBuffer.hpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2021-2022 Florian Fischer +#pragma once + +#include <atomic> +#include <cstddef> +#include <string> + +namespace emper::lib { +class MappedFileBuffer { + // We use a triple buffer scheme, where one buffer is active, one is old and one is fresh + // The old buffer gets remapped by the first accessing the fresh buffer + static const int BUFFER_COUNT = 3; + // Use 1GB buffers to reduce the risk of using an unmapped one + static const size_t BUFFER_SIZE = 1 << 30; + + char* bufs[BUFFER_COUNT]; + + std::atomic<size_t> bufPos = 0; + + std::string file; + int fd; + + auto getBuf(size_t pos) -> char* { return bufs[(pos / BUFFER_SIZE) % BUFFER_COUNT]; } + + void trim(); + + public: + MappedFileBuffer(const std::string& file); + ~MappedFileBuffer(); + + void put(const std::string& message); +}; +} // namespace emper::lib diff --git a/emper/lib/meson.build b/emper/lib/meson.build index 3aa7f195..16a4c6a5 100644 --- a/emper/lib/meson.build +++ b/emper/lib/meson.build @@ -2,6 +2,7 @@ emper_cpp_sources += files( 'DebugUtil.cpp', 'env.cpp', 'LinuxVersion.cpp', + 'MappedFileBuffer.cpp', 'util.cpp', ) diff --git a/emper/log/LogBuffer.hpp b/emper/log/LogBuffer.hpp index f4149ee9..ea20674f 100644 --- a/emper/log/LogBuffer.hpp +++ b/emper/log/LogBuffer.hpp @@ -1,34 +1,16 @@ // SPDX-License-Identifier: LGPL-3.0-or-later -// Copyright © 2021 Florian Fischer +// Copyright © 2021-2022 Florian Fischer #pragma once -#include <atomic> -#include <cstddef> #include <string> -namespace emper::log { -class LogBuffer { - // We use a triple buffer scheme, where one buffer is active, one is old and one is fresh - // The old buffer gets remapped by the first accessing the fresh buffer - static const int BUFFER_COUNT = 3; - // Use 1GB buffers to reduce the risk of using an unmapped one - static const size_t BUFFER_SIZE = 1 << 30; - - char* bufs[BUFFER_COUNT]; - - std::atomic<size_t> bufPos = 0; - - std::string logFile; - int logFd; - - auto getBuf(size_t pos) -> char* { return bufs[(pos / BUFFER_SIZE) % BUFFER_COUNT]; } - - void trim(); +#include "lib/MappedFileBuffer.hpp" +namespace emper::log { +class LogBuffer : emper::lib::MappedFileBuffer { public: - LogBuffer(const std::string& logFile); - ~LogBuffer(); + LogBuffer(const std::string& logFile) : MappedFileBuffer(logFile) {} - void log(const std::string& message); + void log(const std::string& message) { put(message); }; }; } // namespace emper::log diff --git a/emper/log/meson.build b/emper/log/meson.build index 6de1e134..cef2f999 100644 --- a/emper/log/meson.build +++ b/emper/log/meson.build @@ -1,4 +1,3 @@ emper_cpp_sources += files( 'log.cpp', - 'LogBuffer.cpp', ) -- GitLab