blob: 5df3daa975cb3b74df73bc14e92f1f48598f338e [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{
223
224 bool status = validateRids(p);
225
226 if (!status)
227 {
228 // Validation of rids failed
229 BMCWEB_LOG_DEBUG << "Not a Valid request id";
230 return std::make_pair(false, status);
231 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700232 // Validation passed, check if all the locks are owned by the
233 // requesting HMC
234 auto status2 = isItMyLock(p, ids);
235 if (status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530236 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700237 // The current hmc owns all the locks, so we can release
238 // them
239 releaseLock(p);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530240 }
Manojkiran Edaa1ffbb82020-10-28 17:42:21 +0530241 return std::make_pair(true, status2);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530242}
243
Ed Tanousb5a76932020-09-29 16:16:58 -0700244inline RcAcquireLock Lock::acquireLock(const LockRequests& lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530245{
246
247 // validate the lock request
248
Ed Tanous9eb808c2022-01-25 10:19:23 -0800249 for (const auto& lockRecord : lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530250 {
251 bool status = isValidLockRequest(lockRecord);
252 if (!status)
253 {
254 BMCWEB_LOG_DEBUG << "Not a Valid record";
255 BMCWEB_LOG_DEBUG << "Bad json in request";
256 return std::make_pair(true, std::make_pair(status, 0));
257 }
258 }
259 // check for conflict record
260
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500261 const LockRequests& multiRequest = lockRequestStructure;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530262 bool status = isConflictRequest(multiRequest);
263
264 if (status)
265 {
266 BMCWEB_LOG_DEBUG << "There is a conflict within itself";
267 return std::make_pair(true, std::make_pair(status, 1));
268 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700269 BMCWEB_LOG_DEBUG << "The request is not conflicting within itself";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530270
Ed Tanous3174e4d2020-10-07 11:41:22 -0700271 // Need to check for conflict with the locktable entries.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530272
Ed Tanous3174e4d2020-10-07 11:41:22 -0700273 auto conflict = isConflictWithTable(multiRequest);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530274
Ed Tanous3174e4d2020-10-07 11:41:22 -0700275 BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable";
276 return std::make_pair(false, conflict);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530277}
278
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500279inline void Lock::releaseLock(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530280{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500281 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530282 {
Ed Tanouse662eae2022-01-25 10:39:19 -0800283 if (lockTable.erase(id) != 0U)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530284 {
285 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
286 << id;
287 }
288
289 else
290 {
291 BMCWEB_LOG_DEBUG << "Removing the locks from the lock table "
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500292 "failed, transaction ID: "
manojkiraneda3b6dea62019-12-13 17:05:36 +0530293 << id;
294 }
295 }
296}
297
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500298inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530299{
Ratan Gupta07386c62019-12-14 14:06:09 +0530300 if (!lockTable.empty())
301 {
302 auto it = lockTable.begin();
303 while (it != lockTable.end())
304 {
Ed Tanous26f69762022-01-25 09:49:11 -0800305 if (!it->second.empty())
Ratan Gupta07386c62019-12-14 14:06:09 +0530306 {
307 // Check if session id of this entry matches with session id
308 // given
309 if (std::get<0>(it->second[0]) == sessionId)
310 {
311 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
312 "having sessionID="
313 << sessionId;
314 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
315 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530316 }
317 else
318 {
319 it++;
320 }
321 }
322 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530323 }
324}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500325inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
326 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530327{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500328 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530329 {
330 // Just need to compare the client id of the first lock records in the
331 // complete lock row(in the map), because the rest of the lock records
332 // would have the same client id
333
334 std::string expectedClientId = std::get<1>(lockTable[id][0]);
335 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
336
337 if ((expectedClientId == ids.first) &&
338 (expectedSessionId == ids.second))
339 {
340 // It is owned by the currently request hmc
341 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
342 }
343 else
344 {
345 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
346 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
347 }
348 }
349 return std::make_pair(true, std::make_pair(0, LockRequest()));
350}
351
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500352inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530353{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530355 {
356 auto search = lockTable.find(id);
357
358 if (search != lockTable.end())
359 {
360 BMCWEB_LOG_DEBUG << "Valid Transaction id";
361 // continue for the next rid
362 }
363 else
364 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500365 BMCWEB_LOG_DEBUG << "At least 1 inValid Request id";
manojkiraneda3b6dea62019-12-13 17:05:36 +0530366 return false;
367 }
368 }
369 return true;
370}
371
Ed Tanousb5a76932020-09-29 16:16:58 -0700372inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530373{
374
375 // validate the locktype
376
377 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
378 (boost::equals(std::get<2>(refLockRecord), "Write")))))
379 {
380 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
381 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
382 return false;
383 }
384
385 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
386
387 // validate the number of segments
388 // Allowed No of segments are between 2 and 6
389 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
390 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
391 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500392 BMCWEB_LOG_DEBUG << "Validation of Number of Segments Failed";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530393 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
Ed Tanous7cd94e42020-09-29 16:03:02 -0700394 << std::get<4>(refLockRecord).size();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530395 return false;
396 }
397
398 int lockFlag = 0;
399 // validate the lockflags & segment length
400
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500401 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530402 {
403
404 // validate the lock flags
405 // Allowed lockflags are locksame,lockall & dontlock
406
407 if (!((boost::equals(p.first, "LockSame") ||
408 (boost::equals(p.first, "LockAll")) ||
409 (boost::equals(p.first, "DontLock")))))
410 {
411 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
412 BMCWEB_LOG_DEBUG << p.first;
413 return false;
414 }
415
416 // validate the segment length
417 // Allowed values of segment length are between 1 and 4
418
419 if (p.second < 1 || p.second > 4)
420 {
421 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
422 BMCWEB_LOG_DEBUG << p.second;
423 return false;
424 }
425
426 if ((boost::equals(p.first, "LockSame") ||
427 (boost::equals(p.first, "LockAll"))))
428 {
429 ++lockFlag;
430 if (lockFlag >= 2)
431 {
432 return false;
433 }
434 }
435 }
436
manojkiraneda0b631ae2019-12-03 17:54:28 +0530437 return true;
438}
439
Ed Tanousb5a76932020-09-29 16:16:58 -0700440inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530441{
442
Ed Tanous8a592812022-06-04 09:06:59 -0700443 uint32_t thisTransactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530444
445 if (lockTable.empty())
446 {
Ed Tanous8a592812022-06-04 09:06:59 -0700447 thisTransactionId = generateTransactionId();
448 BMCWEB_LOG_DEBUG << thisTransactionId;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530449 // Lock table is empty, so we are safe to add the lockrecords
450 // as there will be no conflict
451 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
452 lockTable.emplace(std::pair<uint32_t, LockRequests>(
Ed Tanous8a592812022-06-04 09:06:59 -0700453 thisTransactionId, refLockRequestStructure));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530454
Ed Tanous8a592812022-06-04 09:06:59 -0700455 return std::make_pair(false, thisTransactionId);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530456 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700457 BMCWEB_LOG_DEBUG
458 << "Lock table is not empty, check for conflict with lock table";
459 // Lock table is not empty, compare the lockrequest entries with
460 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530461
Ed Tanous3174e4d2020-10-07 11:41:22 -0700462 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530463 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700464 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530465 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700466 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530467 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700468 bool status = isConflictRecord(lockRecord1, lockRecord2);
469 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530470 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700471 return std::make_pair(
472 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530473 }
474 }
475 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530476 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700477
478 // Reached here, so no conflict with the locktable, so we are safe to
479 // add the request records into the lock table
480
481 // Lock table is empty, so we are safe to add the lockrecords
482 // as there will be no conflict
483 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
484 transactionId = generateTransactionId();
485 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
486
manojkiraneda0b631ae2019-12-03 17:54:28 +0530487 return std::make_pair(false, transactionId);
488}
489
Ed Tanousb5a76932020-09-29 16:16:58 -0700490inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530491{
492 // check for all the locks coming in as a part of single request
493 // return conflict if any two lock requests are conflicting
494
495 if (refLockRequestStructure.size() == 1)
496 {
497 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
498 // This means , we have only one lock request in the current
499 // request , so no conflict within the request
500 return false;
501 }
502
Ed Tanous3174e4d2020-10-07 11:41:22 -0700503 BMCWEB_LOG_DEBUG
504 << "There are multiple lock requests coming in a single request";
505
506 // There are multiple requests a part of one request
507
508 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530509 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700510 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530511 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700512 const LockRequest& p = refLockRequestStructure[i];
513 const LockRequest& q = refLockRequestStructure[j];
514 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530515
Ed Tanous3174e4d2020-10-07 11:41:22 -0700516 if (status)
517 {
518 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530519 }
520 }
521 }
522 return false;
523}
524
525// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500526// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530527// the content by bytes mentioned by a uint32_t number.
528
529// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500530// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530531// bytes in the resourceid based on the segment length.
532
Ratan Gupta07386c62019-12-14 14:06:09 +0530533inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
534 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530535{
Ed Tanous46ff87b2022-01-07 09:25:51 -0800536 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500537 uint8_t* p = reinterpret_cast<uint8_t*>(&resourceId1);
Ed Tanous46ff87b2022-01-07 09:25:51 -0800538 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500539 uint8_t* q = reinterpret_cast<uint8_t*>(&resourceId2);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530540
Ed Tanousca45aa32022-01-07 09:28:45 -0800541 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
542 uint8_t pPosition = p[position];
543 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
544 uint8_t qPosition = q[position];
545
546 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(pPosition) << ","
547 << std::to_string(qPosition);
Ed Tanousdcf2ebc2022-01-25 10:07:45 -0800548 return pPosition == qPosition;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530549}
550
Ed Tanousb5a76932020-09-29 16:16:58 -0700551inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
552 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530553{
554 // No conflict if both are read locks
555
556 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
557 boost::equals(std::get<2>(refLockRecord2), "Read"))
558 {
559 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
560 return false;
561 }
562
Ed Tanous3174e4d2020-10-07 11:41:22 -0700563 uint32_t i = 0;
564 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530565 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700566
567 // return conflict when any of them is try to lock all resources
568 // under the current resource level.
569 if (boost::equals(p.first, "LockAll") ||
570 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530571 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700572 BMCWEB_LOG_DEBUG
573 << "Either of the Comparing locks are trying to lock all "
574 "resources under the current resource level";
575 return true;
576 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530577
Ed Tanous3174e4d2020-10-07 11:41:22 -0700578 // determine if there is a lock-all-with-same-segment-size.
579 // If the current segment sizes are the same,then we should fail.
580
581 if ((boost::equals(p.first, "LockSame") ||
582 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
583 (p.second == std::get<4>(refLockRecord2)[i].second))
584 {
585 return true;
586 }
587
588 // if segment lengths are not the same, it means two different locks
589 // So no conflict
590 if (p.second != std::get<4>(refLockRecord2)[i].second)
591 {
592 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
593 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
594 BMCWEB_LOG_DEBUG << "Segment 2 length : "
595 << std::get<4>(refLockRecord2)[i].second;
596 return false;
597 }
598
599 // compare segment data
600
Ed Tanous8a592812022-06-04 09:06:59 -0700601 for (uint32_t j = 0; j < p.second; j++)
Ed Tanous3174e4d2020-10-07 11:41:22 -0700602 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500603 // if the segment data is different, then the locks is on a
604 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700605 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500606 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700607 // the Management Console in such a way that, the first byte
608 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500609 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700610 // resourceID into Big Endian before processing further.
611 if (!(checkByte(
612 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
613 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
Ed Tanous8a592812022-06-04 09:06:59 -0700614 j)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530615 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530616 return false;
617 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530618 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700619
620 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530621 }
622
623 return false;
624}
625
Ratan Gupta07386c62019-12-14 14:06:09 +0530626inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530627{
628 ++transactionId;
629 return transactionId;
630}
631
632} // namespace ibm_mc_lock
633} // namespace crow