blob: 3bb82b9479e1275b86a874a9983bb180ab884f85 [file] [log] [blame]
manojkiraneda0b631ae2019-12-03 17:54:28 +05301#pragma once
2
Nan Zhou77665bd2022-10-12 20:28:58 +00003#include "ibm/utils.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -08004#include "logging.hpp"
Nan Zhou77665bd2022-10-12 20:28:58 +00005
manojkiraneda0b631ae2019-12-03 17:54:28 +05306#include <boost/container/flat_map.hpp>
Manojkiran Eda55fd1a92020-04-30 19:06:48 +05307#include <boost/endian/conversion.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05008#include <nlohmann/json.hpp>
9
manojkiraneda0b631ae2019-12-03 17:54:28 +053010#include <filesystem>
Sunitha Harish8a3bb712019-12-13 03:48:09 -060011#include <fstream>
Ed Tanous11ba3972022-07-11 09:50:41 -070012#include <variant>
manojkiraneda0b631ae2019-12-03 17:54:28 +053013
14namespace crow
15{
16namespace ibm_mc_lock
17{
18
manojkiraneda0b631ae2019-12-03 17:54:28 +053019using SType = std::string;
20
21/*----------------------------------------
22|Segment flags : LockFlag | SegmentLength|
23------------------------------------------*/
24
25using SegmentFlags = std::vector<std::pair<SType, uint32_t>>;
26
27// Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo
28using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053029using LockRequests = std::vector<LockRequest>;
30using Rc =
31 std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053032using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>;
manojkiraneda402b5712019-12-13 17:07:09 +053033using RcGetLockList =
34 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053035using ListOfTransactionIds = std::vector<uint32_t>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053036using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053037using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>;
38using SessionFlags = std::pair<SType, SType>;
manojkiraneda402b5712019-12-13 17:07:09 +053039using ListOfSessionIds = std::vector<std::string>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053040
41class Lock
42{
Ed Tanous543f4402022-01-06 13:12:53 -080043 uint32_t transactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +053044 boost::container::flat_map<uint32_t, LockRequests> lockTable;
45
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053046 protected:
47 /*
48 * This function implements the logic for validating an incoming
49 * lock request/requests.
50 *
51 * Returns : True (if Valid)
52 * Returns : False (if not a Valid lock request)
53 */
54
Ed Tanous104f09c2022-01-25 09:56:04 -080055 virtual bool isValidLockRequest(const LockRequest& refLockRecord);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053056
57 /*
58 * This function implements the logic of checking if the incoming
59 * multi-lock request is not having conflicting requirements.
60 *
61 * Returns : True (if conflicting)
62 * Returns : False (if not conflicting)
63 */
64
Ed Tanous104f09c2022-01-25 09:56:04 -080065 virtual bool isConflictRequest(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053066 /*
67 * Implements the core algorithm to find the conflicting
68 * lock requests.
69 *
70 * This functions takes two lock requests and check if both
71 * are conflicting to each other.
72 *
73 * Returns : True (if conflicting)
74 * Returns : False (if not conflicting)
75 */
Ed Tanous104f09c2022-01-25 09:56:04 -080076 virtual bool isConflictRecord(const LockRequest& refLockRecord1,
77 const LockRequest& refLockRecord2);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053078
79 /*
80 * This function implements the logic of checking the conflicting
81 * locks from a incoming single/multi lock requests with the already
82 * existing lock request in the lock table.
83 *
84 */
85
Ed Tanous104f09c2022-01-25 09:56:04 -080086 virtual Rc isConflictWithTable(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053087 /*
88 * This function implements the logic of checking the ownership of the
89 * lock from the releaselock request.
90 *
91 * Returns : True (if the requesting HMC & Session owns the lock(s))
92 * Returns : False (if the request HMC or Session does not own the lock(s))
93 */
94
Ed Tanous104f09c2022-01-25 09:56:04 -080095 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds& refRids,
96 const SessionFlags& ids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053097
98 /*
99 * This function validates the the list of transactionID's and returns false
100 * if the transaction ID is not valid & not present in the lock table
101 */
102
Ed Tanous104f09c2022-01-25 09:56:04 -0800103 virtual bool validateRids(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530104
105 /*
106 * This function releases the locks that are already obtained by the
107 * requesting Management console.
108 */
109
Ed Tanous104f09c2022-01-25 09:56:04 -0800110 void releaseLock(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530111
112 Lock()
113 {
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530114 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
115 }
116
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600117 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530118 * This function implements the algorithm for checking the respective
119 * bytes of the resource id based on the lock management algorithm.
120 */
121
Ed Tanous104f09c2022-01-25 09:56:04 -0800122 static bool checkByte(uint64_t resourceId1, uint64_t resourceId2,
123 uint32_t position);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530124
125 /*
126 * This functions implements a counter that generates a unique 32 bit
127 * number for every successful transaction. This number will be used by
128 * the Management Console for debug.
129 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530130 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600131
manojkiraneda0b631ae2019-12-03 17:54:28 +0530132 public:
133 /*
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800134 * Explicitly deleted copy and move constructors
135 */
136 Lock(const Lock&) = delete;
137 Lock(Lock&&) = delete;
138 Lock& operator=(const Lock&) = delete;
139 Lock& operator=(Lock&&) = delete;
140
141 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530142 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530143 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530144 * conflicting requirements & without any conflicting requirement
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500145 * with the existing locks in the lock table.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530146 *
147 */
148
Ed Tanous104f09c2022-01-25 09:56:04 -0800149 RcAcquireLock acquireLock(const LockRequests& lockRequestStructure);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530150
manojkiraneda3b6dea62019-12-13 17:05:36 +0530151 /*
152 * This function implements the logic for releasing the lock that are
153 * owned by a management console session.
154 *
155 * The locks can be released by two ways
156 * - Using list of transaction ID's
157 * - Using a Session ID
158 *
159 * Client can choose either of the ways by using `Type` JSON key.
160 *
161 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800162 RcReleaseLockApi releaseLock(const ListOfTransactionIds& p,
163 const SessionFlags& ids);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530164
manojkiraneda402b5712019-12-13 17:07:09 +0530165 /*
166 * This function implements the logic for getting the list of locks obtained
167 * by a particular management console.
168 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800169 RcGetLockList getLockList(const ListOfSessionIds& listSessionId);
manojkiraneda402b5712019-12-13 17:07:09 +0530170
Ratan Gupta07386c62019-12-14 14:06:09 +0530171 /*
172 * This function is releases all the locks obtained by a particular
173 * session.
174 */
175
Ed Tanous104f09c2022-01-25 09:56:04 -0800176 void releaseLock(const std::string& sessionId);
Ratan Gupta07386c62019-12-14 14:06:09 +0530177
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500178 static Lock& getInstance()
Ratan Gupta07386c62019-12-14 14:06:09 +0530179 {
180 static Lock lockObject;
181 return lockObject;
182 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530183
Ed Tanous4e087512020-09-28 18:41:25 -0700184 virtual ~Lock() = default;
Ratan Gupta07386c62019-12-14 14:06:09 +0530185};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530186
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530188{
Ravi Teja9eef5782023-06-13 11:55:02 +0000189 std::vector<std::pair<uint32_t, LockRequests>> lockList{};
manojkiraneda402b5712019-12-13 17:07:09 +0530190
191 if (!lockTable.empty())
192 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500193 for (const auto& i : listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530194 {
195 auto it = lockTable.begin();
196 while (it != lockTable.end())
197 {
198 // Check if session id of this entry matches with session id
199 // given
200 if (std::get<0>(it->second[0]) == i)
201 {
Ed Tanous62598e32023-07-17 17:06:25 -0700202 BMCWEB_LOG_DEBUG("Session id is found in the locktable");
manojkiraneda402b5712019-12-13 17:07:09 +0530203
204 // Push the whole lock record into a vector for returning
205 // the json
Ed Tanous4e087512020-09-28 18:41:25 -0700206 lockList.emplace_back(it->first, it->second);
manojkiraneda402b5712019-12-13 17:07:09 +0530207 }
208 // Go to next entry in map
209 it++;
210 }
211 }
212 }
213 // we may have found at least one entry with the given session id
214 // return the json list of lock records pertaining to the given
215 // session id, or send an empty list if lock table is empty
Ed Tanous02379d32020-09-15 21:15:44 -0700216 return {lockList};
manojkiraneda402b5712019-12-13 17:07:09 +0530217}
218
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500219inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds& p,
220 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530221{
manojkiraneda3b6dea62019-12-13 17:05:36 +0530222 bool status = validateRids(p);
223
224 if (!status)
225 {
226 // Validation of rids failed
Ed Tanous62598e32023-07-17 17:06:25 -0700227 BMCWEB_LOG_ERROR("releaseLock: Contains invalid request id");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530228 return std::make_pair(false, status);
229 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700230 // Validation passed, check if all the locks are owned by the
231 // requesting HMC
232 auto status2 = isItMyLock(p, ids);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500233 if (!status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530234 {
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500235 return std::make_pair(false, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530236 }
Manojkiran Edaa1ffbb82020-10-28 17:42:21 +0530237 return std::make_pair(true, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530238}
239
Ed Tanousb5a76932020-09-29 16:16:58 -0700240inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530241{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530242 // validate the lock request
243
Ed Tanous9eb808c2022-01-25 10:19:23 -0800244 for (const auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530245 {
246 bool status = isValidLockRequest(lockRecord);
247 if (!status)
248 {
Ed Tanous62598e32023-07-17 17:06:25 -0700249 BMCWEB_LOG_DEBUG("Not a Valid record");
250 BMCWEB_LOG_DEBUG("Bad json in request");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530251 return std::make_pair(true, std::make_pair(status, 0));
252 }
253 }
254 // check for conflict record
255
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500256 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530257 bool status = isConflictRequest(multiRequest);
258
259 if (status)
260 {
Ed Tanous62598e32023-07-17 17:06:25 -0700261 BMCWEB_LOG_DEBUG("There is a conflict within itself");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530262 return std::make_pair(true, std::make_pair(status, 1));
263 }
Ed Tanous62598e32023-07-17 17:06:25 -0700264 BMCWEB_LOG_DEBUG("The request is not conflicting within itself");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530265
Ed Tanous3174e4d2020-10-07 11:41:22 -0700266 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530267
Ed Tanous3174e4d2020-10-07 11:41:22 -0700268 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530269
Ed Tanous62598e32023-07-17 17:06:25 -0700270 BMCWEB_LOG_DEBUG("Done with checking conflict with the locktable");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700271 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530272}
273
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530275{
Ratan Gupta07386c62019-12-14 14:06:09 +0530276 if (!lockTable.empty())
277 {
278 auto it = lockTable.begin();
279 while (it != lockTable.end())
280 {
Ed Tanous26f69762022-01-25 09:49:11 -0800281 if (!it->second.empty())
Ratan Gupta07386c62019-12-14 14:06:09 +0530282 {
283 // Check if session id of this entry matches with session id
284 // given
285 if (std::get<0>(it->second[0]) == sessionId)
286 {
Ed Tanous62598e32023-07-17 17:06:25 -0700287 BMCWEB_LOG_DEBUG("Remove the lock from the locktable "
288 "having sessionID={}",
289 sessionId);
290 BMCWEB_LOG_DEBUG("TransactionID ={}", it->first);
Ratan Gupta07386c62019-12-14 14:06:09 +0530291 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530292 }
293 else
294 {
295 it++;
296 }
297 }
298 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530299 }
300}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500301inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
302 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530303{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530305 {
306 // Just need to compare the client id of the first lock records in the
307 // complete lock row(in the map), because the rest of the lock records
308 // would have the same client id
309
310 std::string expectedClientId = std::get<1>(lockTable[id][0]);
311 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
312
313 if ((expectedClientId == ids.first) &&
314 (expectedSessionId == ids.second))
315 {
316 // It is owned by the currently request hmc
Ed Tanous62598e32023-07-17 17:06:25 -0700317 BMCWEB_LOG_DEBUG("Lock is owned by the current hmc");
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500318 // remove the lock
319 if (lockTable.erase(id) != 0U)
320 {
Ed Tanous62598e32023-07-17 17:06:25 -0700321 BMCWEB_LOG_DEBUG("Removing the locks with transaction ID : {}",
322 id);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500323 }
324 else
325 {
Ed Tanous62598e32023-07-17 17:06:25 -0700326 BMCWEB_LOG_ERROR("Removing the locks from the lock table "
327 "failed, transaction ID: {}",
328 id);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500329 }
manojkiraneda3b6dea62019-12-13 17:05:36 +0530330 }
331 else
332 {
Ed Tanous62598e32023-07-17 17:06:25 -0700333 BMCWEB_LOG_DEBUG("Lock is not owned by the current hmc");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530334 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
335 }
336 }
337 return std::make_pair(true, std::make_pair(0, LockRequest()));
338}
339
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530341{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530343 {
344 auto search = lockTable.find(id);
345
346 if (search != lockTable.end())
347 {
Ed Tanous62598e32023-07-17 17:06:25 -0700348 BMCWEB_LOG_DEBUG("Valid Transaction id");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530349 // continue for the next rid
350 }
351 else
352 {
Ed Tanous62598e32023-07-17 17:06:25 -0700353 BMCWEB_LOG_ERROR("validateRids: At least 1 inValid Request id: {}",
354 id);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530355 return false;
356 }
357 }
358 return true;
359}
360
Ed Tanousb5a76932020-09-29 16:16:58 -0700361inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530362{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530363 // validate the locktype
364
Ed Tanous18f8f602023-07-18 10:07:23 -0700365 if (!((std::get<2>(refLockRecord) == "Read" ||
366 (std::get<2>(refLockRecord) == "Write"))))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530367 {
Ed Tanous62598e32023-07-17 17:06:25 -0700368 BMCWEB_LOG_DEBUG("Validation of LockType Failed");
369 BMCWEB_LOG_DEBUG("Locktype : {}", std::get<2>(refLockRecord));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530370 return false;
371 }
372
Ed Tanous62598e32023-07-17 17:06:25 -0700373 BMCWEB_LOG_DEBUG("{}", static_cast<int>(std::get<4>(refLockRecord).size()));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530374
375 // validate the number of segments
376 // Allowed No of segments are between 2 and 6
377 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
378 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
379 {
Ed Tanous62598e32023-07-17 17:06:25 -0700380 BMCWEB_LOG_DEBUG("Validation of Number of Segments Failed");
Ed Tanous8ece0e42024-01-02 13:16:50 -0800381 BMCWEB_LOG_DEBUG("Number of Segments provided : {}",
Ed Tanous62598e32023-07-17 17:06:25 -0700382 std::get<4>(refLockRecord).size());
manojkiraneda0b631ae2019-12-03 17:54:28 +0530383 return false;
384 }
385
386 int lockFlag = 0;
387 // validate the lockflags & segment length
388
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500389 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530390 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530391 // validate the lock flags
392 // Allowed lockflags are locksame,lockall & dontlock
393
Ed Tanous18f8f602023-07-18 10:07:23 -0700394 if (!((p.first == "LockSame" || (p.first == "LockAll") ||
395 (p.first == "DontLock"))))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530396 {
Ed Tanous62598e32023-07-17 17:06:25 -0700397 BMCWEB_LOG_DEBUG("Validation of lock flags failed");
398 BMCWEB_LOG_DEBUG("{}", p.first);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530399 return false;
400 }
401
402 // validate the segment length
403 // Allowed values of segment length are between 1 and 4
404
405 if (p.second < 1 || p.second > 4)
406 {
Ed Tanous62598e32023-07-17 17:06:25 -0700407 BMCWEB_LOG_DEBUG("Validation of Segment Length Failed");
408 BMCWEB_LOG_DEBUG("{}", p.second);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530409 return false;
410 }
411
Ed Tanous18f8f602023-07-18 10:07:23 -0700412 if ((p.first == "LockSame" || (p.first == "LockAll")))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530413 {
414 ++lockFlag;
415 if (lockFlag >= 2)
416 {
417 return false;
418 }
419 }
420 }
421
manojkiraneda0b631ae2019-12-03 17:54:28 +0530422 return true;
423}
424
Ed Tanousb5a76932020-09-29 16:16:58 -0700425inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530426{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530427 if (lockTable.empty())
428 {
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700429 uint32_t thisTransactionId = generateTransactionId();
Ed Tanous62598e32023-07-17 17:06:25 -0700430 BMCWEB_LOG_DEBUG("{}", thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530431 // Lock table is empty, so we are safe to add the lockrecords
432 // as there will be no conflict
Ed Tanous62598e32023-07-17 17:06:25 -0700433 BMCWEB_LOG_DEBUG("Lock table is empty, so adding the lockrecords");
Patrick Williamsad539542023-05-12 10:10:08 -0500434 lockTable.emplace(thisTransactionId, refLockRequestStructure);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530435
Ed Tanous8a592812022-06-04 09:06:59 -0700436 return std::make_pair(false, thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530437 }
Ed Tanous62598e32023-07-17 17:06:25 -0700438 BMCWEB_LOG_DEBUG(
439 "Lock table is not empty, check for conflict with lock table");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700440 // Lock table is not empty, compare the lockrequest entries with
441 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530442
Ed Tanous3174e4d2020-10-07 11:41:22 -0700443 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530444 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700445 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530446 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700447 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530448 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700449 bool status = isConflictRecord(lockRecord1, lockRecord2);
450 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530451 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700452 return std::make_pair(
453 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530454 }
455 }
456 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530457 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700458
459 // Reached here, so no conflict with the locktable, so we are safe to
460 // add the request records into the lock table
461
462 // Lock table is empty, so we are safe to add the lockrecords
463 // as there will be no conflict
Ed Tanous62598e32023-07-17 17:06:25 -0700464 BMCWEB_LOG_DEBUG(" Adding elements into lock table");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700465 transactionId = generateTransactionId();
466 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
467
manojkiraneda0b631ae2019-12-03 17:54:28 +0530468 return std::make_pair(false, transactionId);
469}
470
Ed Tanousb5a76932020-09-29 16:16:58 -0700471inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530472{
473 // check for all the locks coming in as a part of single request
474 // return conflict if any two lock requests are conflicting
475
476 if (refLockRequestStructure.size() == 1)
477 {
Ed Tanous62598e32023-07-17 17:06:25 -0700478 BMCWEB_LOG_DEBUG("Only single lock request, so there is no conflict");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530479 // This means , we have only one lock request in the current
480 // request , so no conflict within the request
481 return false;
482 }
483
Ed Tanous62598e32023-07-17 17:06:25 -0700484 BMCWEB_LOG_DEBUG(
485 "There are multiple lock requests coming in a single request");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700486
487 // There are multiple requests a part of one request
488
489 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530490 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700491 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530492 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700493 const LockRequest& p = refLockRequestStructure[i];
494 const LockRequest& q = refLockRequestStructure[j];
495 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530496
Ed Tanous3174e4d2020-10-07 11:41:22 -0700497 if (status)
498 {
499 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530500 }
501 }
502 }
503 return false;
504}
505
506// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500507// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530508// the content by bytes mentioned by a uint32_t number.
509
510// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500511// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530512// bytes in the resourceid based on the segment length.
Ravi Teja9eef5782023-06-13 11:55:02 +0000513inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
514 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530515{
Ravi Teja9eef5782023-06-13 11:55:02 +0000516 if (position >= sizeof(resourceId1))
517 {
518 return false;
519 }
Patrick Williams26b36302023-05-10 17:29:00 -0500520
Ravi Teja9eef5782023-06-13 11:55:02 +0000521 uint8_t pPosition = 0;
522 uint8_t qPosition = 0;
523 pPosition = 0xFF & (resourceId1 >> (8 * position));
524 qPosition = 0xFF & (resourceId2 >> (8 * position));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530525
Ed Tanousdcf2ebc2022-01-25 10:07:45 -0800526 return pPosition == qPosition;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530527}
528
Ed Tanousb5a76932020-09-29 16:16:58 -0700529inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
530 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530531{
532 // No conflict if both are read locks
533
Ed Tanous18f8f602023-07-18 10:07:23 -0700534 if (std::get<2>(refLockRecord1) == "Read" &&
535 std::get<2>(refLockRecord2) == "Read")
manojkiraneda0b631ae2019-12-03 17:54:28 +0530536 {
Ed Tanous62598e32023-07-17 17:06:25 -0700537 BMCWEB_LOG_DEBUG("Both are read locks, no conflict");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530538 return false;
539 }
540
Ed Tanous3174e4d2020-10-07 11:41:22 -0700541 uint32_t i = 0;
542 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530543 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700544 // return conflict when any of them is try to lock all resources
545 // under the current resource level.
Ed Tanous18f8f602023-07-18 10:07:23 -0700546 if (p.first == "LockAll" ||
547 std::get<4>(refLockRecord2)[i].first == "LockAll")
manojkiraneda0b631ae2019-12-03 17:54:28 +0530548 {
Ed Tanous62598e32023-07-17 17:06:25 -0700549 BMCWEB_LOG_DEBUG(
550 "Either of the Comparing locks are trying to lock all "
551 "resources under the current resource level");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700552 return true;
553 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530554
Ed Tanous3174e4d2020-10-07 11:41:22 -0700555 // determine if there is a lock-all-with-same-segment-size.
556 // If the current segment sizes are the same,then we should fail.
557
Ed Tanous18f8f602023-07-18 10:07:23 -0700558 if ((p.first == "LockSame" ||
559 std::get<4>(refLockRecord2)[i].first == "LockSame") &&
Ed Tanous3174e4d2020-10-07 11:41:22 -0700560 (p.second == std::get<4>(refLockRecord2)[i].second))
561 {
562 return true;
563 }
564
565 // if segment lengths are not the same, it means two different locks
566 // So no conflict
567 if (p.second != std::get<4>(refLockRecord2)[i].second)
568 {
Ed Tanous62598e32023-07-17 17:06:25 -0700569 BMCWEB_LOG_DEBUG("Segment lengths are not same");
570 BMCWEB_LOG_DEBUG("Segment 1 length : {}", p.second);
571 BMCWEB_LOG_DEBUG("Segment 2 length : {}",
572 std::get<4>(refLockRecord2)[i].second);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700573 return false;
574 }
575
576 // compare segment data
577
Ed Tanous8a592812022-06-04 09:06:59 -0700578 for (uint32_t j = 0; j < p.second; j++)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700579 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500580 // if the segment data is different, then the locks is on a
581 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700582 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500583 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700584 // the Management Console in such a way that, the first byte
585 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500586 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700587 // resourceID into Big Endian before processing further.
588 if (!(checkByte(
589 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
590 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
Ed Tanous8a592812022-06-04 09:06:59 -0700591 j)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530592 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530593 return false;
594 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530595 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700596
597 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530598 }
599
Sunitha Harish41bb02b2022-08-08 03:12:15 -0500600 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530601}
602
Ratan Gupta07386c62019-12-14 14:06:09 +0530603inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530604{
605 ++transactionId;
606 return transactionId;
607}
608
609} // namespace ibm_mc_lock
610} // namespace crow