Persist the lock table
This commit persists the lock table whenever there is
a change in the lock table during the aquire lock or
release lock.
This commit also restores the locks during start of the
bmcweb as locks are tied up with the session which aquired
the lock.
TestedBy:
Created sessions and acquired multiple locks.
Restart the bmcweb service.
Verified that the locks are persisted per session
Signed-off-by: Sunitha Harish <sunithaharish04@gmail.com>
Change-Id: I081f61922e7c0c24db12efc4d446cdd641856279
diff --git a/include/ibm/locks.hpp b/include/ibm/locks.hpp
index e191959..5b99892 100644
--- a/include/ibm/locks.hpp
+++ b/include/ibm/locks.hpp
@@ -5,6 +5,7 @@
#include <boost/algorithm/string.hpp>
#include <boost/container/flat_map.hpp>
#include <filesystem>
+#include <fstream>
#include <nlohmann/json.hpp>
namespace crow
@@ -34,6 +35,8 @@
using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>;
using SessionFlags = std::pair<SType, SType>;
using ListOfSessionIds = std::vector<std::string>;
+static constexpr const char *fileName =
+ "/var/lib/obmc/bmc-console-mgmt/locks/ibm_mc_persistent_lock_data.json";
class Lock
{
@@ -104,6 +107,18 @@
void releaseLock(const ListOfTransactionIds &);
/*
+ * This API implements the logic to persist the locks that are contained in
+ * the lock table into a json file.
+ */
+ void saveLocks();
+
+ /*
+ * This API implements the logic to load the locks that are present in the
+ * json file into the lock table.
+ */
+ void loadLocks();
+
+ /*
* This function implements the algorithm for checking the respective
* bytes of the resource id based on the lock management algorithm.
*/
@@ -117,6 +132,8 @@
*/
uint32_t generateTransactionId();
+ bool createPersistentLockFilePath();
+
public:
/*
* This function implements the logic for acquiring a lock on a
@@ -150,11 +167,93 @@
Lock()
{
- transactionId = 0;
+ loadLocks();
+ transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
}
} lockObject;
+bool Lock::createPersistentLockFilePath()
+{
+ // The path /var/lib/obmc will be created by initrdscripts
+ // Create the directories for the persistent lock file
+ std::error_code ec;
+ if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt", ec))
+ {
+ std::filesystem::create_directory("/var/lib/obmc/bmc-console-mgmt", ec);
+ }
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Failed to prepare bmc-console-mgmt directory. ec : " << ec;
+ return false;
+ }
+
+ if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt/locks",
+ ec))
+ {
+ std::filesystem::create_directory(
+ "/var/lib/obmc/bmc-console-mgmt/locks", ec);
+ }
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Failed to prepare persistent lock file directory. ec : " << ec;
+ return false;
+ }
+ return true;
+}
+
+void Lock::loadLocks()
+{
+ std::ifstream persistentFile(fileName);
+ if (persistentFile.is_open())
+ {
+ auto data = nlohmann::json::parse(persistentFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "The persistent lock data is available";
+ for (const auto &item : data.items())
+ {
+ BMCWEB_LOG_DEBUG << item.key();
+ BMCWEB_LOG_DEBUG << item.value();
+ LockRequests locks = item.value();
+ lockTable.insert(std::pair<uint32_t, LockRequests>(
+ std::stoul(item.key()), locks));
+ BMCWEB_LOG_DEBUG << "The persistent lock data loaded";
+ }
+ }
+}
+
+void Lock::saveLocks()
+{
+ std::error_code ec;
+ if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt/locks",
+ ec))
+ {
+ if (!createPersistentLockFilePath())
+ {
+ BMCWEB_LOG_DEBUG << "Failed to create lock persistent path";
+ return;
+ }
+ }
+ std::ofstream persistentFile(fileName);
+ // set the permission of the file to 640
+ fs::perms permission =
+ fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read;
+ fs::permissions(fileName, permission);
+ nlohmann::json data;
+ for (const auto &it : lockTable)
+ {
+ data[std::to_string(it.first)] = it.second;
+ }
+ BMCWEB_LOG_DEBUG << "data is " << data;
+ persistentFile << data;
+}
+
RcGetLockList Lock::getLockList(const ListOfSessionIds &listSessionId)
{
@@ -273,6 +372,8 @@
<< id;
}
}
+
+ saveLocks();
}
RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds &refRids,
@@ -405,6 +506,8 @@
lockTable.emplace(std::pair<uint32_t, LockRequests>(
transactionId, refLockRequestStructure));
+ // save the lock in the persistent file
+ saveLocks();
return std::make_pair(false, transactionId);
}
@@ -440,6 +543,9 @@
transactionId = generateTransactionId();
lockTable.emplace(
std::make_pair(transactionId, refLockRequestStructure));
+
+ // save the lock in the persistent file
+ saveLocks();
}
return std::make_pair(false, transactionId);
}