blob: 7a161fc754771fd7a1ed28f94a747b804ad1b3b9 [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
Ed Tanous11ba3972022-07-11 09:50:41 -07006#include <boost/algorithm/string/predicate.hpp>
manojkiraneda0b631ae2019-12-03 17:54:28 +05307#include <boost/container/flat_map.hpp>
Manojkiran Eda55fd1a92020-04-30 19:06:48 +05308#include <boost/endian/conversion.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -05009#include <nlohmann/json.hpp>
10
manojkiraneda0b631ae2019-12-03 17:54:28 +053011#include <filesystem>
Sunitha Harish8a3bb712019-12-13 03:48:09 -060012#include <fstream>
Ed Tanous11ba3972022-07-11 09:50:41 -070013#include <variant>
manojkiraneda0b631ae2019-12-03 17:54:28 +053014
15namespace crow
16{
17namespace ibm_mc_lock
18{
19
manojkiraneda0b631ae2019-12-03 17:54:28 +053020using SType = std::string;
21
22/*----------------------------------------
23|Segment flags : LockFlag | SegmentLength|
24------------------------------------------*/
25
26using SegmentFlags = std::vector<std::pair<SType, uint32_t>>;
27
28// Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo
29using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053030using LockRequests = std::vector<LockRequest>;
31using Rc =
32 std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053033using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>;
manojkiraneda402b5712019-12-13 17:07:09 +053034using RcGetLockList =
35 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053036using ListOfTransactionIds = std::vector<uint32_t>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053037using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053038using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>;
39using SessionFlags = std::pair<SType, SType>;
manojkiraneda402b5712019-12-13 17:07:09 +053040using ListOfSessionIds = std::vector<std::string>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053041
42class Lock
43{
Ed Tanous543f4402022-01-06 13:12:53 -080044 uint32_t transactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +053045 boost::container::flat_map<uint32_t, LockRequests> lockTable;
46
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053047 protected:
48 /*
49 * This function implements the logic for validating an incoming
50 * lock request/requests.
51 *
52 * Returns : True (if Valid)
53 * Returns : False (if not a Valid lock request)
54 */
55
Ed Tanous104f09c2022-01-25 09:56:04 -080056 virtual bool isValidLockRequest(const LockRequest& refLockRecord);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053057
58 /*
59 * This function implements the logic of checking if the incoming
60 * multi-lock request is not having conflicting requirements.
61 *
62 * Returns : True (if conflicting)
63 * Returns : False (if not conflicting)
64 */
65
Ed Tanous104f09c2022-01-25 09:56:04 -080066 virtual bool isConflictRequest(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053067 /*
68 * Implements the core algorithm to find the conflicting
69 * lock requests.
70 *
71 * This functions takes two lock requests and check if both
72 * are conflicting to each other.
73 *
74 * Returns : True (if conflicting)
75 * Returns : False (if not conflicting)
76 */
Ed Tanous104f09c2022-01-25 09:56:04 -080077 virtual bool isConflictRecord(const LockRequest& refLockRecord1,
78 const LockRequest& refLockRecord2);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053079
80 /*
81 * This function implements the logic of checking the conflicting
82 * locks from a incoming single/multi lock requests with the already
83 * existing lock request in the lock table.
84 *
85 */
86
Ed Tanous104f09c2022-01-25 09:56:04 -080087 virtual Rc isConflictWithTable(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053088 /*
89 * This function implements the logic of checking the ownership of the
90 * lock from the releaselock request.
91 *
92 * Returns : True (if the requesting HMC & Session owns the lock(s))
93 * Returns : False (if the request HMC or Session does not own the lock(s))
94 */
95
Ed Tanous104f09c2022-01-25 09:56:04 -080096 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds& refRids,
97 const SessionFlags& ids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053098
99 /*
100 * This function validates the the list of transactionID's and returns false
101 * if the transaction ID is not valid & not present in the lock table
102 */
103
Ed Tanous104f09c2022-01-25 09:56:04 -0800104 virtual bool validateRids(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530105
106 /*
107 * This function releases the locks that are already obtained by the
108 * requesting Management console.
109 */
110
Ed Tanous104f09c2022-01-25 09:56:04 -0800111 void releaseLock(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530112
113 Lock()
114 {
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530115 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
116 }
117
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600118 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530119 * This function implements the algorithm for checking the respective
120 * bytes of the resource id based on the lock management algorithm.
121 */
122
Ed Tanous104f09c2022-01-25 09:56:04 -0800123 static bool checkByte(uint64_t resourceId1, uint64_t resourceId2,
124 uint32_t position);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530125
126 /*
127 * This functions implements a counter that generates a unique 32 bit
128 * number for every successful transaction. This number will be used by
129 * the Management Console for debug.
130 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530131 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600132
manojkiraneda0b631ae2019-12-03 17:54:28 +0530133 public:
134 /*
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800135 * Explicitly deleted copy and move constructors
136 */
137 Lock(const Lock&) = delete;
138 Lock(Lock&&) = delete;
139 Lock& operator=(const Lock&) = delete;
140 Lock& operator=(Lock&&) = delete;
141
142 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530143 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530144 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530145 * conflicting requirements & without any conflicting requirement
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500146 * with the existing locks in the lock table.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530147 *
148 */
149
Ed Tanous104f09c2022-01-25 09:56:04 -0800150 RcAcquireLock acquireLock(const LockRequests& lockRequestStructure);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530151
manojkiraneda3b6dea62019-12-13 17:05:36 +0530152 /*
153 * This function implements the logic for releasing the lock that are
154 * owned by a management console session.
155 *
156 * The locks can be released by two ways
157 * - Using list of transaction ID's
158 * - Using a Session ID
159 *
160 * Client can choose either of the ways by using `Type` JSON key.
161 *
162 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800163 RcReleaseLockApi releaseLock(const ListOfTransactionIds& p,
164 const SessionFlags& ids);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530165
manojkiraneda402b5712019-12-13 17:07:09 +0530166 /*
167 * This function implements the logic for getting the list of locks obtained
168 * by a particular management console.
169 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800170 RcGetLockList getLockList(const ListOfSessionIds& listSessionId);
manojkiraneda402b5712019-12-13 17:07:09 +0530171
Ratan Gupta07386c62019-12-14 14:06:09 +0530172 /*
173 * This function is releases all the locks obtained by a particular
174 * session.
175 */
176
Ed Tanous104f09c2022-01-25 09:56:04 -0800177 void releaseLock(const std::string& sessionId);
Ratan Gupta07386c62019-12-14 14:06:09 +0530178
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500179 static Lock& getInstance()
Ratan Gupta07386c62019-12-14 14:06:09 +0530180 {
181 static Lock lockObject;
182 return lockObject;
183 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530184
Ed Tanous4e087512020-09-28 18:41:25 -0700185 virtual ~Lock() = default;
Ratan Gupta07386c62019-12-14 14:06:09 +0530186};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530187
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500188inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530189{
Ravi Teja9eef5782023-06-13 11:55:02 +0000190 std::vector<std::pair<uint32_t, LockRequests>> lockList{};
manojkiraneda402b5712019-12-13 17:07:09 +0530191
192 if (!lockTable.empty())
193 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500194 for (const auto& i : listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530195 {
196 auto it = lockTable.begin();
197 while (it != lockTable.end())
198 {
199 // Check if session id of this entry matches with session id
200 // given
201 if (std::get<0>(it->second[0]) == i)
202 {
Ed Tanous62598e32023-07-17 17:06:25 -0700203 BMCWEB_LOG_DEBUG("Session id is found in the locktable");
manojkiraneda402b5712019-12-13 17:07:09 +0530204
205 // Push the whole lock record into a vector for returning
206 // the json
Ed Tanous4e087512020-09-28 18:41:25 -0700207 lockList.emplace_back(it->first, it->second);
manojkiraneda402b5712019-12-13 17:07:09 +0530208 }
209 // Go to next entry in map
210 it++;
211 }
212 }
213 }
214 // we may have found at least one entry with the given session id
215 // return the json list of lock records pertaining to the given
216 // session id, or send an empty list if lock table is empty
Ed Tanous02379d32020-09-15 21:15:44 -0700217 return {lockList};
manojkiraneda402b5712019-12-13 17:07:09 +0530218}
219
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500220inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds& p,
221 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530222{
manojkiraneda3b6dea62019-12-13 17:05:36 +0530223 bool status = validateRids(p);
224
225 if (!status)
226 {
227 // Validation of rids failed
Ed Tanous62598e32023-07-17 17:06:25 -0700228 BMCWEB_LOG_ERROR("releaseLock: Contains invalid request id");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530229 return std::make_pair(false, status);
230 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700231 // Validation passed, check if all the locks are owned by the
232 // requesting HMC
233 auto status2 = isItMyLock(p, ids);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500234 if (!status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530235 {
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500236 return std::make_pair(false, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530237 }
Manojkiran Edaa1ffbb82020-10-28 17:42:21 +0530238 return std::make_pair(true, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530239}
240
Ed Tanousb5a76932020-09-29 16:16:58 -0700241inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530242{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530243 // validate the lock request
244
Ed Tanous9eb808c2022-01-25 10:19:23 -0800245 for (const auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530246 {
247 bool status = isValidLockRequest(lockRecord);
248 if (!status)
249 {
Ed Tanous62598e32023-07-17 17:06:25 -0700250 BMCWEB_LOG_DEBUG("Not a Valid record");
251 BMCWEB_LOG_DEBUG("Bad json in request");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530252 return std::make_pair(true, std::make_pair(status, 0));
253 }
254 }
255 // check for conflict record
256
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500257 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530258 bool status = isConflictRequest(multiRequest);
259
260 if (status)
261 {
Ed Tanous62598e32023-07-17 17:06:25 -0700262 BMCWEB_LOG_DEBUG("There is a conflict within itself");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530263 return std::make_pair(true, std::make_pair(status, 1));
264 }
Ed Tanous62598e32023-07-17 17:06:25 -0700265 BMCWEB_LOG_DEBUG("The request is not conflicting within itself");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530266
Ed Tanous3174e4d2020-10-07 11:41:22 -0700267 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530268
Ed Tanous3174e4d2020-10-07 11:41:22 -0700269 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530270
Ed Tanous62598e32023-07-17 17:06:25 -0700271 BMCWEB_LOG_DEBUG("Done with checking conflict with the locktable");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700272 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530273}
274
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500275inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530276{
Ratan Gupta07386c62019-12-14 14:06:09 +0530277 if (!lockTable.empty())
278 {
279 auto it = lockTable.begin();
280 while (it != lockTable.end())
281 {
Ed Tanous26f69762022-01-25 09:49:11 -0800282 if (!it->second.empty())
Ratan Gupta07386c62019-12-14 14:06:09 +0530283 {
284 // Check if session id of this entry matches with session id
285 // given
286 if (std::get<0>(it->second[0]) == sessionId)
287 {
Ed Tanous62598e32023-07-17 17:06:25 -0700288 BMCWEB_LOG_DEBUG("Remove the lock from the locktable "
289 "having sessionID={}",
290 sessionId);
291 BMCWEB_LOG_DEBUG("TransactionID ={}", it->first);
Ratan Gupta07386c62019-12-14 14:06:09 +0530292 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530293 }
294 else
295 {
296 it++;
297 }
298 }
299 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530300 }
301}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500302inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
303 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530304{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500305 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530306 {
307 // Just need to compare the client id of the first lock records in the
308 // complete lock row(in the map), because the rest of the lock records
309 // would have the same client id
310
311 std::string expectedClientId = std::get<1>(lockTable[id][0]);
312 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
313
314 if ((expectedClientId == ids.first) &&
315 (expectedSessionId == ids.second))
316 {
317 // It is owned by the currently request hmc
Ed Tanous62598e32023-07-17 17:06:25 -0700318 BMCWEB_LOG_DEBUG("Lock is owned by the current hmc");
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500319 // remove the lock
320 if (lockTable.erase(id) != 0U)
321 {
Ed Tanous62598e32023-07-17 17:06:25 -0700322 BMCWEB_LOG_DEBUG("Removing the locks with transaction ID : {}",
323 id);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500324 }
325 else
326 {
Ed Tanous62598e32023-07-17 17:06:25 -0700327 BMCWEB_LOG_ERROR("Removing the locks from the lock table "
328 "failed, transaction ID: {}",
329 id);
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500330 }
manojkiraneda3b6dea62019-12-13 17:05:36 +0530331 }
332 else
333 {
Ed Tanous62598e32023-07-17 17:06:25 -0700334 BMCWEB_LOG_DEBUG("Lock is not owned by the current hmc");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530335 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
336 }
337 }
338 return std::make_pair(true, std::make_pair(0, LockRequest()));
339}
340
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500341inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530342{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530344 {
345 auto search = lockTable.find(id);
346
347 if (search != lockTable.end())
348 {
Ed Tanous62598e32023-07-17 17:06:25 -0700349 BMCWEB_LOG_DEBUG("Valid Transaction id");
manojkiraneda3b6dea62019-12-13 17:05:36 +0530350 // continue for the next rid
351 }
352 else
353 {
Ed Tanous62598e32023-07-17 17:06:25 -0700354 BMCWEB_LOG_ERROR("validateRids: At least 1 inValid Request id: {}",
355 id);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530356 return false;
357 }
358 }
359 return true;
360}
361
Ed Tanousb5a76932020-09-29 16:16:58 -0700362inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530363{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530364 // validate the locktype
365
366 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
367 (boost::equals(std::get<2>(refLockRecord), "Write")))))
368 {
Ed Tanous62598e32023-07-17 17:06:25 -0700369 BMCWEB_LOG_DEBUG("Validation of LockType Failed");
370 BMCWEB_LOG_DEBUG("Locktype : {}", std::get<2>(refLockRecord));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530371 return false;
372 }
373
Ed Tanous62598e32023-07-17 17:06:25 -0700374 BMCWEB_LOG_DEBUG("{}", static_cast<int>(std::get<4>(refLockRecord).size()));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530375
376 // validate the number of segments
377 // Allowed No of segments are between 2 and 6
378 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
379 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
380 {
Ed Tanous62598e32023-07-17 17:06:25 -0700381 BMCWEB_LOG_DEBUG("Validation of Number of Segments Failed");
Ed Tanous8ece0e42024-01-02 13:16:50 -0800382 BMCWEB_LOG_DEBUG("Number of Segments provided : {}",
Ed Tanous62598e32023-07-17 17:06:25 -0700383 std::get<4>(refLockRecord).size());
manojkiraneda0b631ae2019-12-03 17:54:28 +0530384 return false;
385 }
386
387 int lockFlag = 0;
388 // validate the lockflags & segment length
389
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500390 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530391 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530392 // validate the lock flags
393 // Allowed lockflags are locksame,lockall & dontlock
394
395 if (!((boost::equals(p.first, "LockSame") ||
396 (boost::equals(p.first, "LockAll")) ||
397 (boost::equals(p.first, "DontLock")))))
398 {
Ed Tanous62598e32023-07-17 17:06:25 -0700399 BMCWEB_LOG_DEBUG("Validation of lock flags failed");
400 BMCWEB_LOG_DEBUG("{}", p.first);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530401 return false;
402 }
403
404 // validate the segment length
405 // Allowed values of segment length are between 1 and 4
406
407 if (p.second < 1 || p.second > 4)
408 {
Ed Tanous62598e32023-07-17 17:06:25 -0700409 BMCWEB_LOG_DEBUG("Validation of Segment Length Failed");
410 BMCWEB_LOG_DEBUG("{}", p.second);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530411 return false;
412 }
413
414 if ((boost::equals(p.first, "LockSame") ||
415 (boost::equals(p.first, "LockAll"))))
416 {
417 ++lockFlag;
418 if (lockFlag >= 2)
419 {
420 return false;
421 }
422 }
423 }
424
manojkiraneda0b631ae2019-12-03 17:54:28 +0530425 return true;
426}
427
Ed Tanousb5a76932020-09-29 16:16:58 -0700428inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530429{
manojkiraneda0b631ae2019-12-03 17:54:28 +0530430 if (lockTable.empty())
431 {
Ed Tanousf8fe53e2022-06-30 15:55:45 -0700432 uint32_t thisTransactionId = generateTransactionId();
Ed Tanous62598e32023-07-17 17:06:25 -0700433 BMCWEB_LOG_DEBUG("{}", thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530434 // Lock table is empty, so we are safe to add the lockrecords
435 // as there will be no conflict
Ed Tanous62598e32023-07-17 17:06:25 -0700436 BMCWEB_LOG_DEBUG("Lock table is empty, so adding the lockrecords");
Patrick Williamsad539542023-05-12 10:10:08 -0500437 lockTable.emplace(thisTransactionId, refLockRequestStructure);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530438
Ed Tanous8a592812022-06-04 09:06:59 -0700439 return std::make_pair(false, thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530440 }
Ed Tanous62598e32023-07-17 17:06:25 -0700441 BMCWEB_LOG_DEBUG(
442 "Lock table is not empty, check for conflict with lock table");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700443 // Lock table is not empty, compare the lockrequest entries with
444 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530445
Ed Tanous3174e4d2020-10-07 11:41:22 -0700446 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530447 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700448 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530449 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700450 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530451 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700452 bool status = isConflictRecord(lockRecord1, lockRecord2);
453 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530454 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700455 return std::make_pair(
456 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530457 }
458 }
459 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530460 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700461
462 // Reached here, so no conflict with the locktable, so we are safe to
463 // add the request records into the lock table
464
465 // Lock table is empty, so we are safe to add the lockrecords
466 // as there will be no conflict
Ed Tanous62598e32023-07-17 17:06:25 -0700467 BMCWEB_LOG_DEBUG(" Adding elements into lock table");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700468 transactionId = generateTransactionId();
469 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
470
manojkiraneda0b631ae2019-12-03 17:54:28 +0530471 return std::make_pair(false, transactionId);
472}
473
Ed Tanousb5a76932020-09-29 16:16:58 -0700474inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530475{
476 // check for all the locks coming in as a part of single request
477 // return conflict if any two lock requests are conflicting
478
479 if (refLockRequestStructure.size() == 1)
480 {
Ed Tanous62598e32023-07-17 17:06:25 -0700481 BMCWEB_LOG_DEBUG("Only single lock request, so there is no conflict");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530482 // This means , we have only one lock request in the current
483 // request , so no conflict within the request
484 return false;
485 }
486
Ed Tanous62598e32023-07-17 17:06:25 -0700487 BMCWEB_LOG_DEBUG(
488 "There are multiple lock requests coming in a single request");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700489
490 // There are multiple requests a part of one request
491
492 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530493 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700494 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530495 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700496 const LockRequest& p = refLockRequestStructure[i];
497 const LockRequest& q = refLockRequestStructure[j];
498 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530499
Ed Tanous3174e4d2020-10-07 11:41:22 -0700500 if (status)
501 {
502 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530503 }
504 }
505 }
506 return false;
507}
508
509// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500510// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530511// the content by bytes mentioned by a uint32_t number.
512
513// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500514// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530515// bytes in the resourceid based on the segment length.
Ravi Teja9eef5782023-06-13 11:55:02 +0000516inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
517 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530518{
Ravi Teja9eef5782023-06-13 11:55:02 +0000519 if (position >= sizeof(resourceId1))
520 {
521 return false;
522 }
Patrick Williams26b36302023-05-10 17:29:00 -0500523
Ravi Teja9eef5782023-06-13 11:55:02 +0000524 uint8_t pPosition = 0;
525 uint8_t qPosition = 0;
526 pPosition = 0xFF & (resourceId1 >> (8 * position));
527 qPosition = 0xFF & (resourceId2 >> (8 * position));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530528
Ed Tanousdcf2ebc2022-01-25 10:07:45 -0800529 return pPosition == qPosition;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530530}
531
Ed Tanousb5a76932020-09-29 16:16:58 -0700532inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
533 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530534{
535 // No conflict if both are read locks
536
537 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
538 boost::equals(std::get<2>(refLockRecord2), "Read"))
539 {
Ed Tanous62598e32023-07-17 17:06:25 -0700540 BMCWEB_LOG_DEBUG("Both are read locks, no conflict");
manojkiraneda0b631ae2019-12-03 17:54:28 +0530541 return false;
542 }
543
Ed Tanous3174e4d2020-10-07 11:41:22 -0700544 uint32_t i = 0;
545 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530546 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700547 // return conflict when any of them is try to lock all resources
548 // under the current resource level.
549 if (boost::equals(p.first, "LockAll") ||
550 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530551 {
Ed Tanous62598e32023-07-17 17:06:25 -0700552 BMCWEB_LOG_DEBUG(
553 "Either of the Comparing locks are trying to lock all "
554 "resources under the current resource level");
Ed Tanous3174e4d2020-10-07 11:41:22 -0700555 return true;
556 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530557
Ed Tanous3174e4d2020-10-07 11:41:22 -0700558 // determine if there is a lock-all-with-same-segment-size.
559 // If the current segment sizes are the same,then we should fail.
560
561 if ((boost::equals(p.first, "LockSame") ||
562 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
563 (p.second == std::get<4>(refLockRecord2)[i].second))
564 {
565 return true;
566 }
567
568 // if segment lengths are not the same, it means two different locks
569 // So no conflict
570 if (p.second != std::get<4>(refLockRecord2)[i].second)
571 {
Ed Tanous62598e32023-07-17 17:06:25 -0700572 BMCWEB_LOG_DEBUG("Segment lengths are not same");
573 BMCWEB_LOG_DEBUG("Segment 1 length : {}", p.second);
574 BMCWEB_LOG_DEBUG("Segment 2 length : {}",
575 std::get<4>(refLockRecord2)[i].second);
Ed Tanous3174e4d2020-10-07 11:41:22 -0700576 return false;
577 }
578
579 // compare segment data
580
Ed Tanous8a592812022-06-04 09:06:59 -0700581 for (uint32_t j = 0; j < p.second; j++)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700582 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500583 // if the segment data is different, then the locks is on a
584 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700585 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500586 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700587 // the Management Console in such a way that, the first byte
588 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500589 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700590 // resourceID into Big Endian before processing further.
591 if (!(checkByte(
592 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
593 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
Ed Tanous8a592812022-06-04 09:06:59 -0700594 j)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530595 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530596 return false;
597 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530598 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700599
600 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530601 }
602
Sunitha Harish41bb02b2022-08-08 03:12:15 -0500603 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530604}
605
Ratan Gupta07386c62019-12-14 14:06:09 +0530606inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530607{
608 ++transactionId;
609 return transactionId;
610}
611
612} // namespace ibm_mc_lock
613} // namespace crow