PEL: Run a user defined function on every PEL
Add a for_each() function to the PEL repository that takes a user
defined function that will be run on every PEL, unless that function
says to stop early.
The user defined function is a std::function<bool>(const PEL&);
For example, to save up to 100 IDs in the repo into a vector:
std::vector<uint32_t> ids;
ForEachFunc f = [&ids](const PEL& pel) {
ids.push_back(pel.id());
return ids.size() == 100 ? true : false;
};
repo.for_each(f);
This will be used to find which PELs still need to be sent up to the
host after a reboot, among other things.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ic60525a8ab3dd593ba37e43a6cb0b3db8dda7cee
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index 81832dd..21b0243 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -162,5 +162,41 @@
return std::nullopt;
}
+void Repository::for_each(ForEachFunc func) const
+{
+ for (const auto& [id, path] : _idsToPELs)
+ {
+ std::ifstream file{path};
+
+ if (!file.good())
+ {
+ auto e = errno;
+ log<level::ERR>("Repository::for_each: Unable to open PEL file",
+ entry("ERRNO=%d", e),
+ entry("PATH=%s", path.c_str()));
+ continue;
+ }
+
+ std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
+ std::istreambuf_iterator<char>()};
+ file.close();
+
+ PEL pel{data};
+
+ try
+ {
+ if (func(pel))
+ {
+ break;
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Repository::for_each function exception",
+ entry("ERROR=%s", e.what()));
+ }
+ }
+}
+
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/repository.hpp b/extensions/openpower-pels/repository.hpp
index d153400..a1d4a24 100644
--- a/extensions/openpower-pels/repository.hpp
+++ b/extensions/openpower-pels/repository.hpp
@@ -148,6 +148,26 @@
*/
std::optional<std::vector<uint8_t>> getPELData(const LogID& id);
+ using ForEachFunc = std::function<bool(const PEL&)>;
+
+ /**
+ * @brief Run a user defined function on every PEL in the repository.
+ *
+ * ForEachFunc takes a const PEL reference, and should return
+ * true to stop iterating and return out of for_each.
+ *
+ * For example, to save up to 100 IDs in the repo into a vector:
+ *
+ * std::vector<uint32_t> ids;
+ * ForEachFunc f = [&ids](const PEL& pel) {
+ * ids.push_back(pel.id());
+ * return ids.size() == 100 ? true : false;
+ * };
+ *
+ * @param[in] func - The function to run.
+ */
+ void for_each(ForEachFunc func) const;
+
private:
/**
* @brief Finds an entry in the _idsToPELs map.
diff --git a/test/openpower-pels/repository_test.cpp b/test/openpower-pels/repository_test.cpp
index 118cb12..0c927f6 100644
--- a/test/openpower-pels/repository_test.cpp
+++ b/test/openpower-pels/repository_test.cpp
@@ -176,3 +176,39 @@
ASSERT_TRUE(pelData);
EXPECT_EQ(dataCopy, *pelData);
}
+
+TEST_F(RepositoryTest, TestForEach)
+{
+ Repository repo{repoPath};
+
+ // Add 2 PELs
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data);
+ repo.add(pel);
+
+ pel = std::make_unique<PEL>(data);
+ pel->assignID();
+ pel->setCommitTime();
+ repo.add(pel);
+
+ // Make a function that saves the IDs
+ std::vector<uint32_t> ids;
+ Repository::ForEachFunc f1 = [&ids](const PEL& pel) {
+ ids.push_back(pel.id());
+ return false;
+ };
+
+ repo.for_each(f1);
+
+ EXPECT_EQ(ids.size(), 2);
+
+ // Stop after the first time in.
+ Repository::ForEachFunc f2 = [&ids](const PEL& pel) {
+ ids.push_back(pel.id());
+ return true;
+ };
+
+ ids.clear();
+ repo.for_each(f2);
+ EXPECT_EQ(ids.size(), 1);
+}