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