summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac11
-rw-r--r--src/Makefile.am4
-rw-r--r--src/event_entry.hpp11
-rw-r--r--src/event_manager.cpp58
-rw-r--r--src/event_manager.hpp5
-rw-r--r--src/event_serialize.cpp97
-rw-r--r--src/event_serialize.hpp30
-rw-r--r--src/main.cpp2
-rw-r--r--src/test/Makefile.am1
9 files changed, 214 insertions, 5 deletions
diff --git a/configure.ac b/configure.ac
index f5e8b3a..d0adf4e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,5 +70,16 @@ AC_ARG_VAR(MAX_EVENTS, [Maximum number of events.])
AS_IF([test "x$MAX_EVENTS" == "x"], [MAX_EVENTS=20])
AC_DEFINE_UNQUOTED([MAX_EVENTS], [$MAX_EVENTS], [Maximum number of events.])
+AC_ARG_VAR(CLASS_VERSION, [Class version to register with Cereal])
+AS_IF([test "x$CLASS_VERSION" == "x"], [CLASS_VERSION=1])
+AC_DEFINE_UNQUOTED([CLASS_VERSION], [$CLASS_VERSION], [Class version to register with Cereal])
+
+AC_ARG_VAR(EVENTS_PERSIST_PATH, [Path of directory housing persisted events.])
+AS_IF([test "x$EVENTS_PERSIST_PATH" == "x"], \
+ [EVENTS_PERSIST_PATH="/var/lib/phosphor-dbus-monitor/events"])
+AC_DEFINE_UNQUOTED([EVENTS_PERSIST_PATH], ["$EVENTS_PERSIST_PATH"], \
+ [Path of directory housing persisted events])
+
+
AC_CONFIG_FILES([Makefile src/Makefile src/test/Makefile mslverify/Makefile])
AC_OUTPUT
diff --git a/src/Makefile.am b/src/Makefile.am
index 73ebca8..e5827e6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,9 @@ phosphor_dbus_monitor_SOURCES = \
main.cpp \
propertywatch.cpp \
resolve_errors.cpp \
- event_manager.cpp
+ event_manager.cpp \
+ event_serialize.cpp
+
phosphor_dbus_monitor_LDADD = \
$(SDBUSPLUS_LIBS) \
$(PHOSPHOR_DBUS_INTERFACES_LIBS) \
diff --git a/src/event_entry.hpp b/src/event_entry.hpp
index e39f1e2..899e5ec 100644
--- a/src/event_entry.hpp
+++ b/src/event_entry.hpp
@@ -50,6 +50,17 @@ class Entry : public EntryIface
this->emit_object_added();
}
+ /** @brief Constructor to create an empty event object with only
+ * timestamp, caller should make a call to emit added signal.
+ * @param[in] path - Path to attach at.
+ * @param[in] timestamp - timestamp when the event created.
+ */
+ Entry(const std::string& path, uint64_t eventTimestamp) :
+ EntryIface(SDBusPlus::getBus(), path.c_str(), true), objectPath(path)
+ {
+ timestamp(eventTimestamp);
+ }
+
/** @brief Path of Object. */
std::string objectPath;
};
diff --git a/src/event_manager.cpp b/src/event_manager.cpp
index 6e7d302..57a8478 100644
--- a/src/event_manager.cpp
+++ b/src/event_manager.cpp
@@ -17,6 +17,7 @@
#include "config.h"
#include "event.hpp"
#include "event_manager.hpp"
+#include "event_serialize.hpp"
#include <experimental/filesystem>
@@ -66,13 +67,62 @@ void Manager::create(const std::string& eventName,
// event.
if (eventQueue.size() == MAX_EVENTS)
{
+ fs::path eventPath(EVENTS_PERSIST_PATH);
+ eventPath /= eventName;
+ eventPath /= std::to_string(eventQueue.front()->timestamp());
eventQueue.pop();
+ std::error_code ec;
+ fs::remove(eventPath, ec);
}
- eventQueue.emplace(std::make_unique<Entry>(objPath,
- ms, // Milliseconds since 1970
- std::move(msg),
- std::move(additionalData)));
+ auto event =
+ std::make_unique<Entry>(objPath,
+ ms, // Milliseconds since 1970
+ std::move(msg), std::move(additionalData));
+ serialize(*event, eventName);
+ eventQueue.push(std::move(event));
+}
+
+void Manager::restore()
+{
+ if (!fs::exists(EVENTS_PERSIST_PATH) || fs::is_empty(EVENTS_PERSIST_PATH))
+ {
+ return;
+ }
+
+ for (auto& eventFile :
+ fs::recursive_directory_iterator(EVENTS_PERSIST_PATH))
+ {
+ if (!fs::is_regular_file(eventFile))
+ {
+ continue;
+ }
+
+ EventQueue events;
+
+ auto eventPath = eventFile.path().string();
+ auto pos1 = eventPath.rfind("/");
+ auto pos2 = eventPath.rfind("/", pos1 - 1) + 1;
+ auto eventName = eventPath.substr(pos2, (pos1 - pos2));
+ auto validEvent = false;
+ auto timestamp = eventFile.path().filename().string();
+ auto tsNum = std::stoll(timestamp);
+ auto objPath =
+ std::string(OBJ_EVENT) + '/' + eventName + '/' + timestamp;
+
+ auto event = std::make_unique<Entry>(objPath, tsNum);
+ if (deserialize(eventFile.path(), *event))
+ {
+ event->emit_object_added();
+ events.push(std::move(event));
+ validEvent = true;
+ }
+
+ if (validEvent)
+ {
+ eventMap[eventName] = std::move(events);
+ }
+ }
}
Manager& getManager()
diff --git a/src/event_manager.hpp b/src/event_manager.hpp
index a177739..a4ccf18 100644
--- a/src/event_manager.hpp
+++ b/src/event_manager.hpp
@@ -38,6 +38,11 @@ class Manager
const std::string& objectPath, const std::string& propertyName,
const std::string& propertyValue);
+ /** @brief Construct event d-bus objects from their persisted
+ * representations.
+ */
+ void restore();
+
private:
using EventName = std::string;
/** @brief Queue of events */
diff --git a/src/event_serialize.cpp b/src/event_serialize.cpp
new file mode 100644
index 0000000..c7e78d9
--- /dev/null
+++ b/src/event_serialize.cpp
@@ -0,0 +1,97 @@
+#include <cereal/types/string.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/archives/binary.hpp>
+#include <fstream>
+
+#include "event_serialize.hpp"
+#include <phosphor-logging/log.hpp>
+#include "config.h"
+
+// Register class version
+// From cereal documentation;
+// "This macro should be placed at global scope"
+CEREAL_CLASS_VERSION(phosphor::events::Entry, CLASS_VERSION);
+
+namespace phosphor
+{
+namespace events
+{
+
+using namespace phosphor::logging;
+
+/** @brief Function required by Cereal to perform serialization.
+ * @tparam Archive - Cereal archive type (binary in our case).
+ * @param[in] archive - reference to Cereal archive.
+ * @param[in] event - const reference to event entry.
+ * @param[in] version - Class version that enables handling
+ * a serialized data across code levels
+ */
+template <class Archive>
+void save(Archive& archive, const Entry& event, const std::uint32_t version)
+{
+ archive(event.timestamp(), event.message(), event.additionalData());
+}
+
+/** @brief Function required by Cereal to perform deserialization.
+ * @tparam Archive - Cereal archive type (binary in our case).
+ * @param[in] archive - reference to Cereal archive.
+ * @param[in] event - reference to event entry.
+ * @param[in] version - Class version that enables handling
+ * a serialized data across code levels
+ */
+template <class Archive>
+void load(Archive& archive, Entry& event, const std::uint32_t version)
+{
+ using namespace sdbusplus::xyz::openbmc_project::Logging::server;
+
+ uint64_t timestamp{};
+ std::string message{};
+ std::vector<std::string> additionalData{};
+
+ archive(timestamp, message, additionalData);
+
+ event.timestamp(timestamp);
+ event.message(message);
+ event.additionalData(additionalData);
+}
+
+fs::path serialize(const Entry& event, const std::string& eventName)
+{
+ fs::path dir(EVENTS_PERSIST_PATH);
+ auto path = dir / eventName;
+ fs::create_directories(path);
+ path /= std::to_string(event.timestamp());
+ std::ofstream os(path.string(), std::ios::binary);
+ cereal::BinaryOutputArchive oarchive(os);
+ oarchive(event);
+ return path;
+}
+
+bool deserialize(const fs::path& path, Entry& event)
+{
+ try
+ {
+ if (fs::exists(path))
+ {
+ std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
+ cereal::BinaryInputArchive iarchive(is);
+ iarchive(event);
+ return true;
+ }
+ return false;
+ }
+ catch (cereal::Exception& e)
+ {
+ log<level::ERR>(e.what());
+ std::error_code ec;
+ fs::remove(path, ec);
+ return false;
+ }
+ catch (const fs::filesystem_error& e)
+ {
+ return false;
+ }
+}
+
+} // namespace event
+} // namespace phosphor
diff --git a/src/event_serialize.hpp b/src/event_serialize.hpp
new file mode 100644
index 0000000..f052845
--- /dev/null
+++ b/src/event_serialize.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <experimental/filesystem>
+#include "event_entry.hpp"
+#include "config.h"
+
+namespace phosphor
+{
+namespace events
+{
+
+namespace fs = std::experimental::filesystem;
+
+/** @brief Serialize and persist event d-bus object
+ * @param[in] event - const reference to event entry.
+ * @param[in] eventName - Name of the event.
+ * @return fs::path - pathname of persisted events file
+ */
+fs::path serialize(const Entry& event, const std::string& eventName);
+
+/** @brief Deserialze a persisted event into a d-bus object
+ * @param[in] path - pathname of persisted event file
+ * @param[in] event - reference to event object which is the target of
+ * deserialization.
+ * @return bool - true if the deserialization was successful, false otherwise.
+ */
+bool deserialize(const fs::path& path, Entry& event);
+
+} // namespace events
+} // namespace phosphor
diff --git a/src/main.cpp b/src/main.cpp
index 5e191e1..68cef3e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -43,6 +43,8 @@ int main(void)
sdbusplus::server::manager::manager objManager(bus, OBJ_EVENT);
bus.request_name(BUSNAME_EVENT);
+ phosphor::events::getManager().restore();
+
for (auto& watch : ConfigPropertyWatches::get())
{
watch->start();
diff --git a/src/test/Makefile.am b/src/test/Makefile.am
index 717bacc..8f3cd02 100644
--- a/src/test/Makefile.am
+++ b/src/test/Makefile.am
@@ -199,4 +199,5 @@ callbacktest_LDADD = \
$(builddir)/../elog.o \
$(builddir)/../resolve_errors.o \
$(builddir)/../event_manager.o \
+ $(builddir)/../event_serialize.o \
-lstdc++fs
OpenPOWER on IntegriCloud