PEL: Add subscriptions for new and deleted PELs
Add functionality to the Repository class to be able to call functions
provided by others when PELs are added or removed from the repository.
This will be used in the future for things like knowing when a new PEL
is added so it can be sent to the host.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I2effc9d5fa9a38890311a88bcfb07eed1292a453
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index 21b0243..aaa6a87 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -128,6 +128,8 @@
using pelID = LogID::Pel;
using obmcID = LogID::Obmc;
_idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path);
+
+ processAddCallbacks(*pel);
}
void Repository::remove(const LogID& id)
@@ -137,6 +139,8 @@
{
fs::remove(pel->second);
_idsToPELs.erase(pel);
+
+ processDeleteCallbacks(id.pelID.id);
}
}
@@ -198,5 +202,39 @@
}
}
+void Repository::processAddCallbacks(const PEL& pel) const
+{
+ for (auto& [name, func] : _addSubscriptions)
+ {
+ try
+ {
+ func(pel);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("PEL Repository add callback exception",
+ entry("NAME=%s", name.c_str()),
+ entry("ERROR=%s", e.what()));
+ }
+ }
+}
+
+void Repository::processDeleteCallbacks(uint32_t id) const
+{
+ for (auto& [name, func] : _deleteSubscriptions)
+ {
+ try
+ {
+ func(id);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("PEL Repository delete callback exception",
+ entry("NAME=%s", name.c_str()),
+ entry("ERROR=%s", e.what()));
+ }
+ }
+}
+
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/repository.hpp b/extensions/openpower-pels/repository.hpp
index a1d4a24..78ab174 100644
--- a/extensions/openpower-pels/repository.hpp
+++ b/extensions/openpower-pels/repository.hpp
@@ -168,6 +168,68 @@
*/
void for_each(ForEachFunc func) const;
+ using AddCallback = std::function<void(const PEL&)>;
+
+ /**
+ * @brief Subscribe to PELs being added to the repository.
+ *
+ * Every time a PEL is added to the repository, the provided
+ * function will be called with the new PEL as the argument.
+ *
+ * The function must be of type void(const PEL&).
+ *
+ * @param[in] name - The subscription name
+ * @param[in] func - The callback function
+ */
+ void subscribeToAdds(const std::string& name, AddCallback func)
+ {
+ if (_addSubscriptions.find(name) == _addSubscriptions.end())
+ {
+ _addSubscriptions.emplace(name, func);
+ }
+ }
+
+ /**
+ * @brief Unsubscribe from new PELs.
+ *
+ * @param[in] name - The subscription name
+ */
+ void unsubscribeFromAdds(const std::string& name)
+ {
+ _addSubscriptions.erase(name);
+ }
+
+ using DeleteCallback = std::function<void(uint32_t)>;
+
+ /**
+ * @brief Subscribe to PELs being deleted from the repository.
+ *
+ * Every time a PEL is deleted from the repository, the provided
+ * function will be called with the PEL ID as the argument.
+ *
+ * The function must be of type void(const uint32_t).
+ *
+ * @param[in] name - The subscription name
+ * @param[in] func - The callback function
+ */
+ void subscribeToDeletes(const std::string& name, DeleteCallback func)
+ {
+ if (_deleteSubscriptions.find(name) == _deleteSubscriptions.end())
+ {
+ _deleteSubscriptions.emplace(name, func);
+ }
+ }
+
+ /**
+ * @brief Unsubscribe from deleted PELs.
+ *
+ * @param[in] name - The subscription name
+ */
+ void unsubscribeFromDeletes(const std::string& name)
+ {
+ _deleteSubscriptions.erase(name);
+ }
+
private:
/**
* @brief Finds an entry in the _idsToPELs map.
@@ -183,6 +245,20 @@
}
/**
+ * @brief Call any subscribed functions for new PELs
+ *
+ * @param[in] pel - The new PEL
+ */
+ void processAddCallbacks(const PEL& pel) const;
+
+ /**
+ * @brief Call any subscribed functions for deleted PELs
+ *
+ * @param[in] id - The ID of the deleted PEL
+ */
+ void processDeleteCallbacks(uint32_t id) const;
+
+ /**
* @brief Restores the _idsToPELs map on startup based on the existing
* PEL data files.
*/
@@ -197,6 +273,16 @@
* @brief A map of the PEL/OBMC IDs to the PEL data files.
*/
std::map<LogID, std::filesystem::path> _idsToPELs;
+
+ /**
+ * @brief Subcriptions for new PELs.
+ */
+ std::map<std::string, AddCallback> _addSubscriptions;
+
+ /**
+ * @brief Subscriptions for deleted PELs.
+ */
+ std::map<std::string, DeleteCallback> _deleteSubscriptions;
};
} // namespace pels
diff --git a/test/openpower-pels/repository_test.cpp b/test/openpower-pels/repository_test.cpp
index 0c927f6..34de855 100644
--- a/test/openpower-pels/repository_test.cpp
+++ b/test/openpower-pels/repository_test.cpp
@@ -212,3 +212,46 @@
repo.for_each(f2);
EXPECT_EQ(ids.size(), 1);
}
+
+TEST_F(RepositoryTest, TestSubscriptions)
+{
+ std::vector<uint32_t> added;
+ std::vector<uint32_t> removed;
+
+ Repository::AddCallback ac = [&added](const PEL& pel) {
+ added.push_back(pel.id());
+ };
+
+ Repository::DeleteCallback dc = [&removed](uint32_t id) {
+ removed.push_back(id);
+ };
+
+ Repository repo{repoPath};
+ repo.subscribeToAdds("test", ac);
+ repo.subscribeToDeletes("test", dc);
+
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data);
+ auto pelID = pel->id();
+ repo.add(pel);
+
+ EXPECT_EQ(added.size(), 1);
+
+ using ID = Repository::LogID;
+ ID id{ID::Pel(pelID)};
+ repo.remove(id);
+
+ EXPECT_EQ(removed.size(), 1);
+
+ repo.unsubscribeFromAdds("test");
+ repo.unsubscribeFromDeletes("test");
+
+ added.clear();
+ removed.clear();
+
+ repo.add(pel);
+ EXPECT_EQ(added.size(), 0);
+
+ repo.remove(id);
+ EXPECT_EQ(removed.size(), 0);
+}