blob: 4434e1f1178e98714c0f466e92d822441c59c01e [file] [log] [blame]
manojkiraneda0b631ae2019-12-03 17:54:28 +05301#pragma once
2
manojkiraneda0b631ae2019-12-03 17:54:28 +05303#include <boost/algorithm/string.hpp>
4#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>
manojkiraneda0b631ae2019-12-03 17:54:28 +053012
13namespace crow
14{
15namespace ibm_mc_lock
16{
17
manojkiraneda0b631ae2019-12-03 17:54:28 +053018using SType = std::string;
19
20/*----------------------------------------
21|Segment flags : LockFlag | SegmentLength|
22------------------------------------------*/
23
24using SegmentFlags = std::vector<std::pair<SType, uint32_t>>;
25
26// Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo
27using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053028using LockRequests = std::vector<LockRequest>;
29using Rc =
30 std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053031using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>;
manojkiraneda402b5712019-12-13 17:07:09 +053032using RcGetLockList =
33 std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053034using ListOfTransactionIds = std::vector<uint32_t>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053035using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>;
manojkiraneda3b6dea62019-12-13 17:05:36 +053036using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>;
37using SessionFlags = std::pair<SType, SType>;
manojkiraneda402b5712019-12-13 17:07:09 +053038using ListOfSessionIds = std::vector<std::string>;
manojkiraneda0b631ae2019-12-03 17:54:28 +053039
40class Lock
41{
Ed Tanous543f4402022-01-06 13:12:53 -080042 uint32_t transactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +053043 boost::container::flat_map<uint32_t, LockRequests> lockTable;
44
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053045 protected:
46 /*
47 * This function implements the logic for validating an incoming
48 * lock request/requests.
49 *
50 * Returns : True (if Valid)
51 * Returns : False (if not a Valid lock request)
52 */
53
Ed Tanous104f09c2022-01-25 09:56:04 -080054 virtual bool isValidLockRequest(const LockRequest& refLockRecord);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053055
56 /*
57 * This function implements the logic of checking if the incoming
58 * multi-lock request is not having conflicting requirements.
59 *
60 * Returns : True (if conflicting)
61 * Returns : False (if not conflicting)
62 */
63
Ed Tanous104f09c2022-01-25 09:56:04 -080064 virtual bool isConflictRequest(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053065 /*
66 * Implements the core algorithm to find the conflicting
67 * lock requests.
68 *
69 * This functions takes two lock requests and check if both
70 * are conflicting to each other.
71 *
72 * Returns : True (if conflicting)
73 * Returns : False (if not conflicting)
74 */
Ed Tanous104f09c2022-01-25 09:56:04 -080075 virtual bool isConflictRecord(const LockRequest& refLockRecord1,
76 const LockRequest& refLockRecord2);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053077
78 /*
79 * This function implements the logic of checking the conflicting
80 * locks from a incoming single/multi lock requests with the already
81 * existing lock request in the lock table.
82 *
83 */
84
Ed Tanous104f09c2022-01-25 09:56:04 -080085 virtual Rc isConflictWithTable(const LockRequests& refLockRequestStructure);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053086 /*
87 * This function implements the logic of checking the ownership of the
88 * lock from the releaselock request.
89 *
90 * Returns : True (if the requesting HMC & Session owns the lock(s))
91 * Returns : False (if the request HMC or Session does not own the lock(s))
92 */
93
Ed Tanous104f09c2022-01-25 09:56:04 -080094 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds& refRids,
95 const SessionFlags& ids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053096
97 /*
98 * This function validates the the list of transactionID's and returns false
99 * if the transaction ID is not valid & not present in the lock table
100 */
101
Ed Tanous104f09c2022-01-25 09:56:04 -0800102 virtual bool validateRids(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530103
104 /*
105 * This function releases the locks that are already obtained by the
106 * requesting Management console.
107 */
108
Ed Tanous104f09c2022-01-25 09:56:04 -0800109 void releaseLock(const ListOfTransactionIds& refRids);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530110
111 Lock()
112 {
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530113 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
114 }
115
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600116 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530117 * This function implements the algorithm for checking the respective
118 * bytes of the resource id based on the lock management algorithm.
119 */
120
Ed Tanous104f09c2022-01-25 09:56:04 -0800121 static bool checkByte(uint64_t resourceId1, uint64_t resourceId2,
122 uint32_t position);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530123
124 /*
125 * This functions implements a counter that generates a unique 32 bit
126 * number for every successful transaction. This number will be used by
127 * the Management Console for debug.
128 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530129 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600130
manojkiraneda0b631ae2019-12-03 17:54:28 +0530131 public:
132 /*
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800133 * Explicitly deleted copy and move constructors
134 */
135 Lock(const Lock&) = delete;
136 Lock(Lock&&) = delete;
137 Lock& operator=(const Lock&) = delete;
138 Lock& operator=(Lock&&) = delete;
139
140 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530141 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530142 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530143 * conflicting requirements & without any conflicting requirement
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500144 * with the existing locks in the lock table.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530145 *
146 */
147
Ed Tanous104f09c2022-01-25 09:56:04 -0800148 RcAcquireLock acquireLock(const LockRequests& lockRequestStructure);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530149
manojkiraneda3b6dea62019-12-13 17:05:36 +0530150 /*
151 * This function implements the logic for releasing the lock that are
152 * owned by a management console session.
153 *
154 * The locks can be released by two ways
155 * - Using list of transaction ID's
156 * - Using a Session ID
157 *
158 * Client can choose either of the ways by using `Type` JSON key.
159 *
160 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800161 RcReleaseLockApi releaseLock(const ListOfTransactionIds& p,
162 const SessionFlags& ids);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530163
manojkiraneda402b5712019-12-13 17:07:09 +0530164 /*
165 * This function implements the logic for getting the list of locks obtained
166 * by a particular management console.
167 */
Ed Tanous104f09c2022-01-25 09:56:04 -0800168 RcGetLockList getLockList(const ListOfSessionIds& listSessionId);
manojkiraneda402b5712019-12-13 17:07:09 +0530169
Ratan Gupta07386c62019-12-14 14:06:09 +0530170 /*
171 * This function is releases all the locks obtained by a particular
172 * session.
173 */
174
Ed Tanous104f09c2022-01-25 09:56:04 -0800175 void releaseLock(const std::string& sessionId);
Ratan Gupta07386c62019-12-14 14:06:09 +0530176
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500177 static Lock& getInstance()
Ratan Gupta07386c62019-12-14 14:06:09 +0530178 {
179 static Lock lockObject;
180 return lockObject;
181 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530182
Ed Tanous4e087512020-09-28 18:41:25 -0700183 virtual ~Lock() = default;
Ratan Gupta07386c62019-12-14 14:06:09 +0530184};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530185
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500186inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530187{
188
189 std::vector<std::pair<uint32_t, LockRequests>> lockList;
190
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 {
202 BMCWEB_LOG_DEBUG << "Session id is found in the locktable";
203
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{
222
223 bool status = validateRids(p);
224
225 if (!status)
226 {
227 // Validation of rids failed
228 BMCWEB_LOG_DEBUG << "Not a Valid request id";
229 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);
234 if (status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530235 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700236 // The current hmc owns all the locks, so we can release
237 // them
238 releaseLock(p);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530239 }
Manojkiran Edaa1ffbb82020-10-28 17:42:21 +0530240 return std::make_pair(true, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530241}
242
Ed Tanousb5a76932020-09-29 16:16:58 -0700243inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530244{
245
246 // validate the lock request
247
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500248 for (auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530249 {
250 bool status = isValidLockRequest(lockRecord);
251 if (!status)
252 {
253 BMCWEB_LOG_DEBUG << "Not a Valid record";
254 BMCWEB_LOG_DEBUG << "Bad json in request";
255 return std::make_pair(true, std::make_pair(status, 0));
256 }
257 }
258 // check for conflict record
259
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500260 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530261 bool status = isConflictRequest(multiRequest);
262
263 if (status)
264 {
265 BMCWEB_LOG_DEBUG << "There is a conflict within itself";
266 return std::make_pair(true, std::make_pair(status, 1));
267 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700268 BMCWEB_LOG_DEBUG << "The request is not conflicting within itself";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530269
Ed Tanous3174e4d2020-10-07 11:41:22 -0700270 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530271
Ed Tanous3174e4d2020-10-07 11:41:22 -0700272 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530273
Ed Tanous3174e4d2020-10-07 11:41:22 -0700274 BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable";
275 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530276}
277
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278inline void Lock::releaseLock(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530279{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500280 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530281 {
282 if (lockTable.erase(id))
283 {
284 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
285 << id;
286 }
287
288 else
289 {
290 BMCWEB_LOG_DEBUG << "Removing the locks from the lock table "
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500291 "failed, transaction ID: "
manojkiraneda3b6dea62019-12-13 17:05:36 +0530292 << id;
293 }
294 }
295}
296
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500297inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530298{
Ratan Gupta07386c62019-12-14 14:06:09 +0530299 if (!lockTable.empty())
300 {
301 auto it = lockTable.begin();
302 while (it != lockTable.end())
303 {
Ed Tanous26f69762022-01-25 09:49:11 -0800304 if (!it->second.empty())
Ratan Gupta07386c62019-12-14 14:06:09 +0530305 {
306 // Check if session id of this entry matches with session id
307 // given
308 if (std::get<0>(it->second[0]) == sessionId)
309 {
310 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
311 "having sessionID="
312 << sessionId;
313 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
314 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530315 }
316 else
317 {
318 it++;
319 }
320 }
321 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530322 }
323}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500324inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
325 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530326{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530328 {
329 // Just need to compare the client id of the first lock records in the
330 // complete lock row(in the map), because the rest of the lock records
331 // would have the same client id
332
333 std::string expectedClientId = std::get<1>(lockTable[id][0]);
334 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
335
336 if ((expectedClientId == ids.first) &&
337 (expectedSessionId == ids.second))
338 {
339 // It is owned by the currently request hmc
340 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
341 }
342 else
343 {
344 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
345 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
346 }
347 }
348 return std::make_pair(true, std::make_pair(0, LockRequest()));
349}
350
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500351inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530352{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500353 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530354 {
355 auto search = lockTable.find(id);
356
357 if (search != lockTable.end())
358 {
359 BMCWEB_LOG_DEBUG << "Valid Transaction id";
360 // continue for the next rid
361 }
362 else
363 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500364 BMCWEB_LOG_DEBUG << "At least 1 inValid Request id";
manojkiraneda3b6dea62019-12-13 17:05:36 +0530365 return false;
366 }
367 }
368 return true;
369}
370
Ed Tanousb5a76932020-09-29 16:16:58 -0700371inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530372{
373
374 // validate the locktype
375
376 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
377 (boost::equals(std::get<2>(refLockRecord), "Write")))))
378 {
379 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
380 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
381 return false;
382 }
383
384 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
385
386 // validate the number of segments
387 // Allowed No of segments are between 2 and 6
388 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
389 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
390 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500391 BMCWEB_LOG_DEBUG << "Validation of Number of Segments Failed";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530392 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
Ed Tanous7cd94e42020-09-29 16:03:02 -0700393 << std::get<4>(refLockRecord).size();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530394 return false;
395 }
396
397 int lockFlag = 0;
398 // validate the lockflags & segment length
399
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500400 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530401 {
402
403 // validate the lock flags
404 // Allowed lockflags are locksame,lockall & dontlock
405
406 if (!((boost::equals(p.first, "LockSame") ||
407 (boost::equals(p.first, "LockAll")) ||
408 (boost::equals(p.first, "DontLock")))))
409 {
410 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
411 BMCWEB_LOG_DEBUG << p.first;
412 return false;
413 }
414
415 // validate the segment length
416 // Allowed values of segment length are between 1 and 4
417
418 if (p.second < 1 || p.second > 4)
419 {
420 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
421 BMCWEB_LOG_DEBUG << p.second;
422 return false;
423 }
424
425 if ((boost::equals(p.first, "LockSame") ||
426 (boost::equals(p.first, "LockAll"))))
427 {
428 ++lockFlag;
429 if (lockFlag >= 2)
430 {
431 return false;
432 }
433 }
434 }
435
manojkiraneda0b631ae2019-12-03 17:54:28 +0530436 return true;
437}
438
Ed Tanousb5a76932020-09-29 16:16:58 -0700439inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530440{
441
Ed Tanous543f4402022-01-06 13:12:53 -0800442 uint32_t transactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530443
444 if (lockTable.empty())
445 {
446 transactionId = generateTransactionId();
447 BMCWEB_LOG_DEBUG << transactionId;
448 // Lock table is empty, so we are safe to add the lockrecords
449 // as there will be no conflict
450 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
451 lockTable.emplace(std::pair<uint32_t, LockRequests>(
452 transactionId, refLockRequestStructure));
453
454 return std::make_pair(false, transactionId);
455 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700456 BMCWEB_LOG_DEBUG
457 << "Lock table is not empty, check for conflict with lock table";
458 // Lock table is not empty, compare the lockrequest entries with
459 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530460
Ed Tanous3174e4d2020-10-07 11:41:22 -0700461 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530462 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700463 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530464 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700465 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530466 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700467 bool status = isConflictRecord(lockRecord1, lockRecord2);
468 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530469 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700470 return std::make_pair(
471 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530472 }
473 }
474 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530475 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700476
477 // Reached here, so no conflict with the locktable, so we are safe to
478 // add the request records into the lock table
479
480 // Lock table is empty, so we are safe to add the lockrecords
481 // as there will be no conflict
482 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
483 transactionId = generateTransactionId();
484 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
485
manojkiraneda0b631ae2019-12-03 17:54:28 +0530486 return std::make_pair(false, transactionId);
487}
488
Ed Tanousb5a76932020-09-29 16:16:58 -0700489inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530490{
491 // check for all the locks coming in as a part of single request
492 // return conflict if any two lock requests are conflicting
493
494 if (refLockRequestStructure.size() == 1)
495 {
496 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
497 // This means , we have only one lock request in the current
498 // request , so no conflict within the request
499 return false;
500 }
501
Ed Tanous3174e4d2020-10-07 11:41:22 -0700502 BMCWEB_LOG_DEBUG
503 << "There are multiple lock requests coming in a single request";
504
505 // There are multiple requests a part of one request
506
507 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530508 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700509 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530510 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700511 const LockRequest& p = refLockRequestStructure[i];
512 const LockRequest& q = refLockRequestStructure[j];
513 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530514
Ed Tanous3174e4d2020-10-07 11:41:22 -0700515 if (status)
516 {
517 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530518 }
519 }
520 }
521 return false;
522}
523
524// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500525// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530526// the content by bytes mentioned by a uint32_t number.
527
528// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500529// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530530// bytes in the resourceid based on the segment length.
531
Ratan Gupta07386c62019-12-14 14:06:09 +0530532inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
533 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530534{
Ed Tanous46ff87b2022-01-07 09:25:51 -0800535 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500536 uint8_t* p = reinterpret_cast<uint8_t*>(&resourceId1);
Ed Tanous46ff87b2022-01-07 09:25:51 -0800537 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500538 uint8_t* q = reinterpret_cast<uint8_t*>(&resourceId2);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530539
Ed Tanousca45aa32022-01-07 09:28:45 -0800540 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
541 uint8_t pPosition = p[position];
542 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
543 uint8_t qPosition = q[position];
544
545 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(pPosition) << ","
546 << std::to_string(qPosition);
547 if (pPosition != qPosition)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530548 {
549 return false;
550 }
551
manojkiraneda0b631ae2019-12-03 17:54:28 +0530552 return true;
553}
554
Ed Tanousb5a76932020-09-29 16:16:58 -0700555inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
556 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530557{
558 // No conflict if both are read locks
559
560 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
561 boost::equals(std::get<2>(refLockRecord2), "Read"))
562 {
563 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
564 return false;
565 }
566
Ed Tanous3174e4d2020-10-07 11:41:22 -0700567 uint32_t i = 0;
568 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530569 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700570
571 // return conflict when any of them is try to lock all resources
572 // under the current resource level.
573 if (boost::equals(p.first, "LockAll") ||
574 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530575 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700576 BMCWEB_LOG_DEBUG
577 << "Either of the Comparing locks are trying to lock all "
578 "resources under the current resource level";
579 return true;
580 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530581
Ed Tanous3174e4d2020-10-07 11:41:22 -0700582 // determine if there is a lock-all-with-same-segment-size.
583 // If the current segment sizes are the same,then we should fail.
584
585 if ((boost::equals(p.first, "LockSame") ||
586 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
587 (p.second == std::get<4>(refLockRecord2)[i].second))
588 {
589 return true;
590 }
591
592 // if segment lengths are not the same, it means two different locks
593 // So no conflict
594 if (p.second != std::get<4>(refLockRecord2)[i].second)
595 {
596 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
597 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
598 BMCWEB_LOG_DEBUG << "Segment 2 length : "
599 << std::get<4>(refLockRecord2)[i].second;
600 return false;
601 }
602
603 // compare segment data
604
605 for (uint32_t i = 0; i < p.second; i++)
606 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500607 // if the segment data is different, then the locks is on a
608 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700609 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500610 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700611 // the Management Console in such a way that, the first byte
612 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500613 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700614 // resourceID into Big Endian before processing further.
615 if (!(checkByte(
616 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
617 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
618 i)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530619 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530620 return false;
621 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530622 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700623
624 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530625 }
626
627 return false;
628}
629
Ratan Gupta07386c62019-12-14 14:06:09 +0530630inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530631{
632 ++transactionId;
633 return transactionId;
634}
635
636} // namespace ibm_mc_lock
637} // namespace crow