Add serialization to the Callout class
Adding serialize() and deserialize() APIs to the callout
class to save and restore the class data persistently.
The APIs take the directory to store the files in, and the
filename itself will be the ID, which is the callout number.
For example, a path could be:
/var/lib/ibm-logging/errors/5/callouts/0.
Tested: Passes the testcases in future commit.
Change-Id: I526f6483df71dbceac3a33f7ce8872f6914bcd9d
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/callout.cpp b/callout.cpp
index ef72414..7c0310e 100644
--- a/callout.cpp
+++ b/callout.cpp
@@ -12,13 +12,72 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <cereal/archives/binary.hpp>
+#include <cereal/types/string.hpp>
+#include <cereal/types/vector.hpp>
+#include <cereal/types/tuple.hpp>
+#include <experimental/filesystem>
+#include <fstream>
+#include <phosphor-logging/log.hpp>
#include "callout.hpp"
+#include "config.h"
+#include "dbus.hpp"
+
+CEREAL_CLASS_VERSION(ibm::logging::Callout, CALLOUT_CLASS_VERSION);
namespace ibm
{
namespace logging
{
+using namespace phosphor::logging;
+
+/**
+ * Function required by Cereal for saving data
+ *
+ * @param[in] archive - the Cereal archive object
+ * @param[in] callout - the object to save
+ * @param[in] version - the version of the persisted data
+ */
+template <class Archive>
+void save(Archive& archive, const Callout& callout, const std::uint32_t version)
+{
+ archive(callout.id(), callout.ts(), callout.path(), callout.buildDate(),
+ callout.manufacturer(), callout.model(), callout.partNumber(),
+ callout.serialNumber());
+}
+
+/**
+ * Function required by Cereal for restoring data into an object
+ *
+ * @param[in] archive - the Cereal archive object
+ * @param[in] callout - the callout object to restore
+ * @param[in] version - the version of the persisted data
+ */
+template <class Archive>
+void load(Archive& archive, Callout& callout, const std::uint32_t version)
+{
+ size_t id;
+ uint64_t timestamp;
+ std::string inventoryPath;
+ std::string build;
+ std::string mfgr;
+ std::string model;
+ std::string pn;
+ std::string sn;
+
+ archive(id, timestamp, inventoryPath, build, mfgr, model, pn, sn);
+
+ callout.id(id);
+ callout.ts(timestamp);
+ callout.path(inventoryPath);
+ callout.buildDate(build);
+ callout.manufacturer(mfgr);
+ callout.model(model);
+ callout.partNumber(pn);
+ callout.serialNumber(sn);
+}
+
Callout::Callout(sdbusplus::bus::bus& bus, const std::string& objectPath,
size_t id, uint64_t timestamp) :
CalloutObject(bus, objectPath.c_str(), true),
@@ -66,5 +125,61 @@
emit_object_added();
}
+
+void Callout::serialize(const fs::path& dir)
+{
+ auto path = getFilePath(dir);
+ std::ofstream stream(path.c_str(), std::ios::binary);
+ cereal::BinaryOutputArchive oarchive(stream);
+
+ oarchive(*this);
+}
+
+bool Callout::deserialize(const fs::path& dir)
+{
+ auto path = getFilePath(dir);
+
+ if (!fs::exists(path))
+ {
+ return false;
+ }
+
+ // Save the current ID and timestamp and then use them after
+ // deserialization to check that the data we are restoring
+ // is for the correct error log.
+
+ auto originalID = entryID;
+ auto originalTS = timestamp;
+
+ try
+ {
+ std::ifstream stream(path.c_str(), std::ios::binary);
+ cereal::BinaryInputArchive iarchive(stream);
+
+ iarchive(*this);
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>(e.what());
+ log<level::ERR>("Failed trying to restore a Callout object",
+ entry("PATH=%s", path.c_str()));
+ fs::remove(path);
+ return false;
+ }
+
+ if ((entryID != originalID) || (timestamp != originalTS))
+ {
+ log<level::INFO>(
+ "Timestamp or ID mismatch in persisted Callout. Discarding",
+ entry("PATH=%s", path.c_str()), entry("PERSISTED_ID=%lu", entryID),
+ entry("EXPECTED_ID=%lu", originalID),
+ entry("PERSISTED_TS=%llu", timestamp),
+ entry("EXPECTED_TS=%llu", originalTS));
+ fs::remove(path);
+ return false;
+ }
+
+ return true;
+}
}
}