Merge "Track message_bridge client UUID and connection counts and time"
diff --git a/aos/BUILD b/aos/BUILD
index 9049e08..8a8a19a 100644
--- a/aos/BUILD
+++ b/aos/BUILD
@@ -409,6 +409,7 @@
deps = [
"//aos:macros",
"//aos/containers:resizeable_buffer",
+ "//aos/util:file",
"@com_github_google_flatbuffers//:flatbuffers",
"@com_github_google_glog//:glog",
"@com_google_absl//absl/strings",
@@ -581,6 +582,7 @@
":json_to_flatbuffer",
":json_to_flatbuffer_fbs",
"//aos/testing:googletest",
+ "//aos/testing:tmpdir",
],
)
diff --git a/aos/flatbuffers.h b/aos/flatbuffers.h
index 68a8ad5..cdf5339 100644
--- a/aos/flatbuffers.h
+++ b/aos/flatbuffers.h
@@ -7,6 +7,7 @@
#include "absl/types/span.h"
#include "aos/containers/resizeable_buffer.h"
#include "aos/macros.h"
+#include "aos/util/file.h"
#include "flatbuffers/flatbuffers.h" // IWYU pragma: export
#include "glog/logging.h"
@@ -501,6 +502,31 @@
span.size());
}
+// MMap a flatbuffer on disk.
+template <typename T>
+class FlatbufferMMap : public NonSizePrefixedFlatbuffer<T> {
+ public:
+ // Builds a Flatbuffer by mmaping the data from a flatbuffer saved on disk.
+ FlatbufferMMap(const std::string &flatbuffer_path,
+ util::FileOptions options = util::FileOptions::kReadable) {
+ span_ = util::MMapFile(flatbuffer_path, options);
+ }
+
+ // Copies the reference to the mapped memory.
+ FlatbufferMMap(const FlatbufferMMap &) = default;
+ FlatbufferMMap &operator=(const FlatbufferMMap<T> &other) = default;
+
+ // Moves the reference to the mapped memory from one pointer to another.
+ FlatbufferMMap(FlatbufferMMap &&) = default;
+ FlatbufferMMap &operator=(FlatbufferMMap<T> &&other) = default;
+
+ absl::Span<uint8_t> span() override { return *span_; }
+ absl::Span<const uint8_t> span() const override { return *span_; }
+
+ private:
+ std::shared_ptr<absl::Span<uint8_t>> span_;
+};
+
} // namespace aos
#endif // AOS_FLATBUFFERS_H_
diff --git a/aos/flatbuffers_test.cc b/aos/flatbuffers_test.cc
index e3030f1..ae8d6e6 100644
--- a/aos/flatbuffers_test.cc
+++ b/aos/flatbuffers_test.cc
@@ -1,9 +1,10 @@
#include "aos/flatbuffers.h"
-#include "gtest/gtest.h"
-
+#include "absl/strings/str_cat.h"
#include "aos/json_to_flatbuffer.h"
#include "aos/json_to_flatbuffer_generated.h"
+#include "aos/testing/tmpdir.h"
+#include "gtest/gtest.h"
namespace aos {
namespace testing {
@@ -21,5 +22,59 @@
EXPECT_FALSE(empty.Verify());
}
+// Tests the ability to map a flatbuffer on disk to memory
+TEST(FlatbufferMMapTest, Verify) {
+ FlatbufferDetachedBuffer<Configuration> fb =
+ JsonToFlatbuffer<Configuration>("{\"foo_int\": 3}");
+
+ const std::string fb_path = absl::StrCat(TestTmpDir(), "/fb.bfbs");
+ WriteFlatbufferToFile(fb_path, fb);
+
+ FlatbufferMMap<Configuration> fb_mmap(fb_path);
+ EXPECT_TRUE(fb.Verify());
+ EXPECT_TRUE(fb_mmap.Verify());
+ ASSERT_EQ(fb_mmap.message().foo_int(), 3);
+
+ // Verify that copying works
+ {
+ FlatbufferMMap<Configuration> fb_mmap2(fb_path);
+ fb_mmap2 = fb_mmap;
+ EXPECT_TRUE(fb_mmap.Verify());
+ EXPECT_TRUE(fb_mmap2.Verify());
+ ASSERT_EQ(fb_mmap2.message().foo_int(), 3);
+ ASSERT_EQ(fb_mmap.message().foo_int(), 3);
+ }
+ EXPECT_TRUE(fb_mmap.Verify());
+ ASSERT_EQ(fb_mmap.message().foo_int(), 3);
+
+ // Verify that moving works
+ {
+ FlatbufferMMap<Configuration> fb_mmap3(fb_path);
+ fb_mmap3 = std::move(fb_mmap);
+ EXPECT_TRUE(fb_mmap3.Verify());
+ ASSERT_EQ(fb_mmap3.message().foo_int(), 3);
+ }
+}
+
+// Tests the ability to modify a flatbuffer mmaped from on disk in memory
+TEST(FlatbufferMMapTest, Writeable) {
+ FlatbufferDetachedBuffer<Configuration> fb =
+ JsonToFlatbuffer<Configuration>("{\"foo_int\": 3}");
+
+ const std::string fb_path = absl::StrCat(TestTmpDir(), "/fb.bfbs");
+ WriteFlatbufferToFile(fb_path, fb);
+
+ {
+ FlatbufferMMap<Configuration> fb_mmap(fb_path,
+ util::FileOptions::kWriteable);
+ fb_mmap.mutable_message()->mutate_foo_int(5);
+ }
+
+ {
+ FlatbufferMMap<Configuration> fb_mmap(fb_path);
+ EXPECT_EQ(fb_mmap.message().foo_int(), 5);
+ }
+}
+
} // namespace testing
} // namespace aos
diff --git a/aos/util/BUILD b/aos/util/BUILD
index 59dec18..daacba1 100644
--- a/aos/util/BUILD
+++ b/aos/util/BUILD
@@ -246,6 +246,7 @@
"//aos/scoped:scoped_fd",
"@com_github_google_glog//:glog",
"@com_google_absl//absl/strings",
+ "@com_google_absl//absl/types:span",
],
)
diff --git a/aos/util/file.cc b/aos/util/file.cc
index 4473d4d..317206e 100644
--- a/aos/util/file.cc
+++ b/aos/util/file.cc
@@ -2,6 +2,7 @@
#include <fcntl.h>
#include <fts.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -151,5 +152,30 @@
}
}
+std::shared_ptr<absl::Span<uint8_t>> MMapFile(const std::string &path,
+ FileOptions options) {
+ int fd =
+ open(path.c_str(), options == FileOptions::kReadable ? O_RDONLY : O_RDWR);
+ PCHECK(fd != -1) << "Unable to open file " << path;
+ struct stat sb;
+ PCHECK(fstat(fd, &sb) != -1) << ": Unable to get file size of " << path;
+ uint8_t *start = reinterpret_cast<uint8_t *>(mmap(
+ NULL, sb.st_size,
+ options == FileOptions::kReadable ? PROT_READ : (PROT_READ | PROT_WRITE),
+ MAP_SHARED, fd, 0));
+ CHECK(start != MAP_FAILED) << ": Unable to open mapping to file " << path;
+ std::shared_ptr<absl::Span<uint8_t>> span =
+ std::shared_ptr<absl::Span<uint8_t>>(
+ new absl::Span<uint8_t>(start, sb.st_size),
+ [](absl::Span<uint8_t> *span) {
+ PCHECK(msync(span->data(), span->size(), MS_SYNC) == 0)
+ << ": Failed to flush data before unmapping.";
+ PCHECK(munmap(span->data(), span->size()) != -1);
+ delete span;
+ });
+ close(fd);
+ return span;
+}
+
} // namespace util
} // namespace aos
diff --git a/aos/util/file.h b/aos/util/file.h
index 8089225..2d37ec2 100644
--- a/aos/util/file.h
+++ b/aos/util/file.h
@@ -2,9 +2,12 @@
#define AOS_UTIL_FILE_H_
#include <sys/stat.h>
+
+#include <memory>
#include <string>
#include <string_view>
+#include "absl/types/span.h"
#include "glog/logging.h"
namespace aos {
@@ -32,6 +35,12 @@
// runs across.
void UnlinkRecursive(std::string_view path);
+enum class FileOptions { kReadable, kWriteable };
+
+// Maps file from disk into memory
+std::shared_ptr<absl::Span<uint8_t>> MMapFile(
+ const std::string &path, FileOptions options = FileOptions::kReadable);
+
} // namespace util
} // namespace aos