blob: 7cd803763ec9950fcd85049f47241944ef17887c [file] [log] [blame]
manojkiraneda0b631ae2019-12-03 17:54:28 +05301#pragma once
2
Ed Tanous11ba3972022-07-11 09:50:41 -07003#include <boost/algorithm/string/predicate.hpp>
manojkiraneda0b631ae2019-12-03 17:54:28 +05304#include <boost/container/flat_map.hpp>
Manojkiran Eda55fd1a92020-04-30 19:06:48 +05305#include <boost/endian/conversion.hpp>
Sunitha Harish3e919b52020-10-13 01:21:48 -05006#include <include/ibm/utils.hpp>
Ed Tanous04e438c2020-10-03 08:06:26 -07007#include <logging.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{
189
190 std::vector<std::pair<uint32_t, LockRequests>> lockList;
191
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 {
203 BMCWEB_LOG_DEBUG << "Session id is found in the locktable";
204
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
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500228 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{
243
244 // validate the lock request
245
Ed Tanous9eb808c2022-01-25 10:19:23 -0800246 for (const auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530247 {
248 bool status = isValidLockRequest(lockRecord);
249 if (!status)
250 {
251 BMCWEB_LOG_DEBUG << "Not a Valid record";
252 BMCWEB_LOG_DEBUG << "Bad json in request";
253 return std::make_pair(true, std::make_pair(status, 0));
254 }
255 }
256 // check for conflict record
257
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500258 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530259 bool status = isConflictRequest(multiRequest);
260
261 if (status)
262 {
263 BMCWEB_LOG_DEBUG << "There is a conflict within itself";
264 return std::make_pair(true, std::make_pair(status, 1));
265 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700266 BMCWEB_LOG_DEBUG << "The request is not conflicting within itself";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530267
Ed Tanous3174e4d2020-10-07 11:41:22 -0700268 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530269
Ed Tanous3174e4d2020-10-07 11:41:22 -0700270 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530271
Ed Tanous3174e4d2020-10-07 11:41:22 -0700272 BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable";
273 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530274}
275
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500276inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530277{
Ratan Gupta07386c62019-12-14 14:06:09 +0530278 if (!lockTable.empty())
279 {
280 auto it = lockTable.begin();
281 while (it != lockTable.end())
282 {
Ed Tanous26f69762022-01-25 09:49:11 -0800283 if (!it->second.empty())
Ratan Gupta07386c62019-12-14 14:06:09 +0530284 {
285 // Check if session id of this entry matches with session id
286 // given
287 if (std::get<0>(it->second[0]) == sessionId)
288 {
289 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
290 "having sessionID="
291 << sessionId;
292 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
293 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530294 }
295 else
296 {
297 it++;
298 }
299 }
300 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530301 }
302}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500303inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
304 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530305{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500306 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530307 {
308 // Just need to compare the client id of the first lock records in the
309 // complete lock row(in the map), because the rest of the lock records
310 // would have the same client id
311
312 std::string expectedClientId = std::get<1>(lockTable[id][0]);
313 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
314
315 if ((expectedClientId == ids.first) &&
316 (expectedSessionId == ids.second))
317 {
318 // It is owned by the currently request hmc
319 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500320 // remove the lock
321 if (lockTable.erase(id) != 0U)
322 {
323 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
324 << id;
325 }
326 else
327 {
328 BMCWEB_LOG_ERROR << "Removing the locks from the lock table "
329 "failed, transaction ID: "
330 << id;
331 }
manojkiraneda3b6dea62019-12-13 17:05:36 +0530332 }
333 else
334 {
335 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
336 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
337 }
338 }
339 return std::make_pair(true, std::make_pair(0, LockRequest()));
340}
341
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500342inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530343{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500344 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530345 {
346 auto search = lockTable.find(id);
347
348 if (search != lockTable.end())
349 {
350 BMCWEB_LOG_DEBUG << "Valid Transaction id";
351 // continue for the next rid
352 }
353 else
354 {
Sunitha Harish3e7ab702022-08-08 02:08:39 -0500355 BMCWEB_LOG_ERROR << "validateRids: At least 1 inValid Request id: "
356 << id;
manojkiraneda3b6dea62019-12-13 17:05:36 +0530357 return false;
358 }
359 }
360 return true;
361}
362
Ed Tanousb5a76932020-09-29 16:16:58 -0700363inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530364{
365
366 // validate the locktype
367
368 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
369 (boost::equals(std::get<2>(refLockRecord), "Write")))))
370 {
371 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
372 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
373 return false;
374 }
375
376 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
377
378 // validate the number of segments
379 // Allowed No of segments are between 2 and 6
380 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
381 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
382 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500383 BMCWEB_LOG_DEBUG << "Validation of Number of Segments Failed";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530384 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
Ed Tanous7cd94e42020-09-29 16:03:02 -0700385 << std::get<4>(refLockRecord).size();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530386 return false;
387 }
388
389 int lockFlag = 0;
390 // validate the lockflags & segment length
391
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500392 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530393 {
394
395 // validate the lock flags
396 // Allowed lockflags are locksame,lockall & dontlock
397
398 if (!((boost::equals(p.first, "LockSame") ||
399 (boost::equals(p.first, "LockAll")) ||
400 (boost::equals(p.first, "DontLock")))))
401 {
402 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
403 BMCWEB_LOG_DEBUG << p.first;
404 return false;
405 }
406
407 // validate the segment length
408 // Allowed values of segment length are between 1 and 4
409
410 if (p.second < 1 || p.second > 4)
411 {
412 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
413 BMCWEB_LOG_DEBUG << p.second;
414 return false;
415 }
416
417 if ((boost::equals(p.first, "LockSame") ||
418 (boost::equals(p.first, "LockAll"))))
419 {
420 ++lockFlag;
421 if (lockFlag >= 2)
422 {
423 return false;
424 }
425 }
426 }
427
manojkiraneda0b631ae2019-12-03 17:54:28 +0530428 return true;
429}
430
Ed Tanousb5a76932020-09-29 16:16:58 -0700431inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530432{
433
Ed Tanous8a592812022-06-04 09:06:59 -0700434 uint32_t thisTransactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530435
436 if (lockTable.empty())
437 {
Ed Tanous8a592812022-06-04 09:06:59 -0700438 thisTransactionId = generateTransactionId();
439 BMCWEB_LOG_DEBUG << thisTransactionId;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530440 // Lock table is empty, so we are safe to add the lockrecords
441 // as there will be no conflict
442 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
443 lockTable.emplace(std::pair<uint32_t, LockRequests>(
Ed Tanous8a592812022-06-04 09:06:59 -0700444 thisTransactionId, refLockRequestStructure));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530445
Ed Tanous8a592812022-06-04 09:06:59 -0700446 return std::make_pair(false, thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530447 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700448 BMCWEB_LOG_DEBUG
449 << "Lock table is not empty, check for conflict with lock table";
450 // Lock table is not empty, compare the lockrequest entries with
451 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530452
Ed Tanous3174e4d2020-10-07 11:41:22 -0700453 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530454 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700455 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530456 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700457 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530458 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700459 bool status = isConflictRecord(lockRecord1, lockRecord2);
460 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530461 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700462 return std::make_pair(
463 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530464 }
465 }
466 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530467 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700468
469 // Reached here, so no conflict with the locktable, so we are safe to
470 // add the request records into the lock table
471
472 // Lock table is empty, so we are safe to add the lockrecords
473 // as there will be no conflict
474 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
475 transactionId = generateTransactionId();
476 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
477
manojkiraneda0b631ae2019-12-03 17:54:28 +0530478 return std::make_pair(false, transactionId);
479}
480
Ed Tanousb5a76932020-09-29 16:16:58 -0700481inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530482{
483 // check for all the locks coming in as a part of single request
484 // return conflict if any two lock requests are conflicting
485
486 if (refLockRequestStructure.size() == 1)
487 {
488 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
489 // This means , we have only one lock request in the current
490 // request , so no conflict within the request
491 return false;
492 }
493
Ed Tanous3174e4d2020-10-07 11:41:22 -0700494 BMCWEB_LOG_DEBUG
495 << "There are multiple lock requests coming in a single request";
496
497 // There are multiple requests a part of one request
498
499 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530500 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700501 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530502 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700503 const LockRequest& p = refLockRequestStructure[i];
504 const LockRequest& q = refLockRequestStructure[j];
505 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530506
Ed Tanous3174e4d2020-10-07 11:41:22 -0700507 if (status)
508 {
509 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530510 }
511 }
512 }
513 return false;
514}
515
516// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500517// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530518// the content by bytes mentioned by a uint32_t number.
519
520// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500521// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530522// bytes in the resourceid based on the segment length.
523
Ratan Gupta07386c62019-12-14 14:06:09 +0530524inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
525 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530526{
Ed Tanous46ff87b2022-01-07 09:25:51 -0800527 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500528 uint8_t* p = reinterpret_cast<uint8_t*>(&resourceId1);
Ed Tanous46ff87b2022-01-07 09:25:51 -0800529 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500530 uint8_t* q = reinterpret_cast<uint8_t*>(&resourceId2);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530531
Ed Tanousca45aa32022-01-07 09:28:45 -0800532 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
533 uint8_t pPosition = p[position];
534 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
535 uint8_t qPosition = q[position];
536
537 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(pPosition) << ","
538 << std::to_string(qPosition);
Ed Tanousdcf2ebc2022-01-25 10:07:45 -0800539 return pPosition == qPosition;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530540}
541
Ed Tanousb5a76932020-09-29 16:16:58 -0700542inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
543 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530544{
545 // No conflict if both are read locks
546
547 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
548 boost::equals(std::get<2>(refLockRecord2), "Read"))
549 {
550 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
551 return false;
552 }
553
Ed Tanous3174e4d2020-10-07 11:41:22 -0700554 uint32_t i = 0;
555 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530556 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700557
558 // return conflict when any of them is try to lock all resources
559 // under the current resource level.
560 if (boost::equals(p.first, "LockAll") ||
561 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530562 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700563 BMCWEB_LOG_DEBUG
564 << "Either of the Comparing locks are trying to lock all "
565 "resources under the current resource level";
566 return true;
567 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530568
Ed Tanous3174e4d2020-10-07 11:41:22 -0700569 // determine if there is a lock-all-with-same-segment-size.
570 // If the current segment sizes are the same,then we should fail.
571
572 if ((boost::equals(p.first, "LockSame") ||
573 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
574 (p.second == std::get<4>(refLockRecord2)[i].second))
575 {
576 return true;
577 }
578
579 // if segment lengths are not the same, it means two different locks
580 // So no conflict
581 if (p.second != std::get<4>(refLockRecord2)[i].second)
582 {
583 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
584 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
585 BMCWEB_LOG_DEBUG << "Segment 2 length : "
586 << std::get<4>(refLockRecord2)[i].second;
587 return false;
588 }
589
590 // compare segment data
591
Ed Tanous8a592812022-06-04 09:06:59 -0700592 for (uint32_t j = 0; j < p.second; j++)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700593 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500594 // if the segment data is different, then the locks is on a
595 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700596 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500597 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700598 // the Management Console in such a way that, the first byte
599 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500600 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700601 // resourceID into Big Endian before processing further.
602 if (!(checkByte(
603 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
604 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
Ed Tanous8a592812022-06-04 09:06:59 -0700605 j)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530606 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530607 return false;
608 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530609 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700610
611 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530612 }
613
Sunitha Harish41bb02b2022-08-08 03:12:15 -0500614 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530615}
616
Ratan Gupta07386c62019-12-14 14:06:09 +0530617inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530618{
619 ++transactionId;
620 return transactionId;
621}
622
623} // namespace ibm_mc_lock
624} // namespace crow