blob: 5a86d09decc182552d063972d85b31ad3a9c826b [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 Tanousb5a76932020-09-29 16:16:58 -070054 virtual bool isValidLockRequest(const LockRequest&);
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 Tanousb5a76932020-09-29 16:16:58 -070064 virtual bool isConflictRequest(const LockRequests&);
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 Tanousb5a76932020-09-29 16:16:58 -070075 virtual bool isConflictRecord(const LockRequest&, const LockRequest&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053076
77 /*
78 * This function implements the logic of checking the conflicting
79 * locks from a incoming single/multi lock requests with the already
80 * existing lock request in the lock table.
81 *
82 */
83
Ed Tanousb5a76932020-09-29 16:16:58 -070084 virtual Rc isConflictWithTable(const LockRequests&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053085 /*
86 * This function implements the logic of checking the ownership of the
87 * lock from the releaselock request.
88 *
89 * Returns : True (if the requesting HMC & Session owns the lock(s))
90 * Returns : False (if the request HMC or Session does not own the lock(s))
91 */
92
Gunnar Mills1214b7e2020-06-04 10:11:30 -050093 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds&,
94 const SessionFlags&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053095
96 /*
97 * This function validates the the list of transactionID's and returns false
98 * if the transaction ID is not valid & not present in the lock table
99 */
100
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 virtual bool validateRids(const ListOfTransactionIds&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530102
103 /*
104 * This function releases the locks that are already obtained by the
105 * requesting Management console.
106 */
107
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500108 void releaseLock(const ListOfTransactionIds&);
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530109
110 Lock()
111 {
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530112 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
113 }
114
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600115 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530116 * This function implements the algorithm for checking the respective
117 * bytes of the resource id based on the lock management algorithm.
118 */
119
120 bool checkByte(uint64_t, uint64_t, uint32_t);
121
122 /*
123 * This functions implements a counter that generates a unique 32 bit
124 * number for every successful transaction. This number will be used by
125 * the Management Console for debug.
126 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530127 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600128
manojkiraneda0b631ae2019-12-03 17:54:28 +0530129 public:
130 /*
Ed Tanousecd6a3a2022-01-07 09:18:40 -0800131 * Explicitly deleted copy and move constructors
132 */
133 Lock(const Lock&) = delete;
134 Lock(Lock&&) = delete;
135 Lock& operator=(const Lock&) = delete;
136 Lock& operator=(Lock&&) = delete;
137
138 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530139 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530140 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530141 * conflicting requirements & without any conflicting requirement
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500142 * with the existing locks in the lock table.
manojkiraneda0b631ae2019-12-03 17:54:28 +0530143 *
144 */
145
Ed Tanousb5a76932020-09-29 16:16:58 -0700146 RcAcquireLock acquireLock(const LockRequests&);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530147
manojkiraneda3b6dea62019-12-13 17:05:36 +0530148 /*
149 * This function implements the logic for releasing the lock that are
150 * owned by a management console session.
151 *
152 * The locks can be released by two ways
153 * - Using list of transaction ID's
154 * - Using a Session ID
155 *
156 * Client can choose either of the ways by using `Type` JSON key.
157 *
158 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500159 RcReleaseLockApi releaseLock(const ListOfTransactionIds&,
160 const SessionFlags&);
manojkiraneda3b6dea62019-12-13 17:05:36 +0530161
manojkiraneda402b5712019-12-13 17:07:09 +0530162 /*
163 * This function implements the logic for getting the list of locks obtained
164 * by a particular management console.
165 */
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500166 RcGetLockList getLockList(const ListOfSessionIds&);
manojkiraneda402b5712019-12-13 17:07:09 +0530167
Ratan Gupta07386c62019-12-14 14:06:09 +0530168 /*
169 * This function is releases all the locks obtained by a particular
170 * session.
171 */
172
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500173 void releaseLock(const std::string&);
Ratan Gupta07386c62019-12-14 14:06:09 +0530174
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500175 static Lock& getInstance()
Ratan Gupta07386c62019-12-14 14:06:09 +0530176 {
177 static Lock lockObject;
178 return lockObject;
179 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530180
Ed Tanous4e087512020-09-28 18:41:25 -0700181 virtual ~Lock() = default;
Ratan Gupta07386c62019-12-14 14:06:09 +0530182};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530183
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500184inline RcGetLockList Lock::getLockList(const ListOfSessionIds& listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530185{
186
187 std::vector<std::pair<uint32_t, LockRequests>> lockList;
188
189 if (!lockTable.empty())
190 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500191 for (const auto& i : listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530192 {
193 auto it = lockTable.begin();
194 while (it != lockTable.end())
195 {
196 // Check if session id of this entry matches with session id
197 // given
198 if (std::get<0>(it->second[0]) == i)
199 {
200 BMCWEB_LOG_DEBUG << "Session id is found in the locktable";
201
202 // Push the whole lock record into a vector for returning
203 // the json
Ed Tanous4e087512020-09-28 18:41:25 -0700204 lockList.emplace_back(it->first, it->second);
manojkiraneda402b5712019-12-13 17:07:09 +0530205 }
206 // Go to next entry in map
207 it++;
208 }
209 }
210 }
211 // we may have found at least one entry with the given session id
212 // return the json list of lock records pertaining to the given
213 // session id, or send an empty list if lock table is empty
Ed Tanous02379d32020-09-15 21:15:44 -0700214 return {lockList};
manojkiraneda402b5712019-12-13 17:07:09 +0530215}
216
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500217inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds& p,
218 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530219{
220
221 bool status = validateRids(p);
222
223 if (!status)
224 {
225 // Validation of rids failed
226 BMCWEB_LOG_DEBUG << "Not a Valid request id";
227 return std::make_pair(false, status);
228 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700229 // Validation passed, check if all the locks are owned by the
230 // requesting HMC
231 auto status2 = isItMyLock(p, ids);
232 if (status2.first)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530233 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700234 // The current hmc owns all the locks, so we can release
235 // them
236 releaseLock(p);
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
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500246 for (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 ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530277{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530279 {
280 if (lockTable.erase(id))
281 {
282 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
283 << id;
284 }
285
286 else
287 {
288 BMCWEB_LOG_DEBUG << "Removing the locks from the lock table "
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500289 "failed, transaction ID: "
manojkiraneda3b6dea62019-12-13 17:05:36 +0530290 << id;
291 }
292 }
293}
294
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500295inline void Lock::releaseLock(const std::string& sessionId)
Ratan Gupta07386c62019-12-14 14:06:09 +0530296{
Ratan Gupta07386c62019-12-14 14:06:09 +0530297 if (!lockTable.empty())
298 {
299 auto it = lockTable.begin();
300 while (it != lockTable.end())
301 {
302 if (it->second.size() != 0)
303 {
304 // Check if session id of this entry matches with session id
305 // given
306 if (std::get<0>(it->second[0]) == sessionId)
307 {
308 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
309 "having sessionID="
310 << sessionId;
311 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
312 it = lockTable.erase(it);
Ratan Gupta07386c62019-12-14 14:06:09 +0530313 }
314 else
315 {
316 it++;
317 }
318 }
319 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530320 }
321}
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500322inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds& refRids,
323 const SessionFlags& ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530324{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500325 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530326 {
327 // Just need to compare the client id of the first lock records in the
328 // complete lock row(in the map), because the rest of the lock records
329 // would have the same client id
330
331 std::string expectedClientId = std::get<1>(lockTable[id][0]);
332 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
333
334 if ((expectedClientId == ids.first) &&
335 (expectedSessionId == ids.second))
336 {
337 // It is owned by the currently request hmc
338 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
339 }
340 else
341 {
342 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
343 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
344 }
345 }
346 return std::make_pair(true, std::make_pair(0, LockRequest()));
347}
348
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500349inline bool Lock::validateRids(const ListOfTransactionIds& refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530350{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500351 for (const auto& id : refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530352 {
353 auto search = lockTable.find(id);
354
355 if (search != lockTable.end())
356 {
357 BMCWEB_LOG_DEBUG << "Valid Transaction id";
358 // continue for the next rid
359 }
360 else
361 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500362 BMCWEB_LOG_DEBUG << "At least 1 inValid Request id";
manojkiraneda3b6dea62019-12-13 17:05:36 +0530363 return false;
364 }
365 }
366 return true;
367}
368
Ed Tanousb5a76932020-09-29 16:16:58 -0700369inline bool Lock::isValidLockRequest(const LockRequest& refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530370{
371
372 // validate the locktype
373
374 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
375 (boost::equals(std::get<2>(refLockRecord), "Write")))))
376 {
377 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
378 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
379 return false;
380 }
381
382 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
383
384 // validate the number of segments
385 // Allowed No of segments are between 2 and 6
386 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
387 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
388 {
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500389 BMCWEB_LOG_DEBUG << "Validation of Number of Segments Failed";
manojkiraneda0b631ae2019-12-03 17:54:28 +0530390 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
Ed Tanous7cd94e42020-09-29 16:03:02 -0700391 << std::get<4>(refLockRecord).size();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530392 return false;
393 }
394
395 int lockFlag = 0;
396 // validate the lockflags & segment length
397
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500398 for (const auto& p : std::get<4>(refLockRecord))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530399 {
400
401 // validate the lock flags
402 // Allowed lockflags are locksame,lockall & dontlock
403
404 if (!((boost::equals(p.first, "LockSame") ||
405 (boost::equals(p.first, "LockAll")) ||
406 (boost::equals(p.first, "DontLock")))))
407 {
408 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
409 BMCWEB_LOG_DEBUG << p.first;
410 return false;
411 }
412
413 // validate the segment length
414 // Allowed values of segment length are between 1 and 4
415
416 if (p.second < 1 || p.second > 4)
417 {
418 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
419 BMCWEB_LOG_DEBUG << p.second;
420 return false;
421 }
422
423 if ((boost::equals(p.first, "LockSame") ||
424 (boost::equals(p.first, "LockAll"))))
425 {
426 ++lockFlag;
427 if (lockFlag >= 2)
428 {
429 return false;
430 }
431 }
432 }
433
manojkiraneda0b631ae2019-12-03 17:54:28 +0530434 return true;
435}
436
Ed Tanousb5a76932020-09-29 16:16:58 -0700437inline Rc Lock::isConflictWithTable(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530438{
439
Ed Tanous543f4402022-01-06 13:12:53 -0800440 uint32_t transactionId = 0;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530441
442 if (lockTable.empty())
443 {
444 transactionId = generateTransactionId();
445 BMCWEB_LOG_DEBUG << transactionId;
446 // Lock table is empty, so we are safe to add the lockrecords
447 // as there will be no conflict
448 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
449 lockTable.emplace(std::pair<uint32_t, LockRequests>(
450 transactionId, refLockRequestStructure));
451
452 return std::make_pair(false, transactionId);
453 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700454 BMCWEB_LOG_DEBUG
455 << "Lock table is not empty, check for conflict with lock table";
456 // Lock table is not empty, compare the lockrequest entries with
457 // the entries in the lock table
manojkiraneda0b631ae2019-12-03 17:54:28 +0530458
Ed Tanous3174e4d2020-10-07 11:41:22 -0700459 for (const auto& lockRecord1 : refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530460 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700461 for (const auto& map : lockTable)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530462 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700463 for (const auto& lockRecord2 : map.second)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530464 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700465 bool status = isConflictRecord(lockRecord1, lockRecord2);
466 if (status)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530467 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700468 return std::make_pair(
469 true, std::make_pair(map.first, lockRecord2));
manojkiraneda0b631ae2019-12-03 17:54:28 +0530470 }
471 }
472 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530473 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700474
475 // Reached here, so no conflict with the locktable, so we are safe to
476 // add the request records into the lock table
477
478 // Lock table is empty, so we are safe to add the lockrecords
479 // as there will be no conflict
480 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
481 transactionId = generateTransactionId();
482 lockTable.emplace(std::make_pair(transactionId, refLockRequestStructure));
483
manojkiraneda0b631ae2019-12-03 17:54:28 +0530484 return std::make_pair(false, transactionId);
485}
486
Ed Tanousb5a76932020-09-29 16:16:58 -0700487inline bool Lock::isConflictRequest(const LockRequests& refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530488{
489 // check for all the locks coming in as a part of single request
490 // return conflict if any two lock requests are conflicting
491
492 if (refLockRequestStructure.size() == 1)
493 {
494 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
495 // This means , we have only one lock request in the current
496 // request , so no conflict within the request
497 return false;
498 }
499
Ed Tanous3174e4d2020-10-07 11:41:22 -0700500 BMCWEB_LOG_DEBUG
501 << "There are multiple lock requests coming in a single request";
502
503 // There are multiple requests a part of one request
504
505 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530506 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700507 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530508 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700509 const LockRequest& p = refLockRequestStructure[i];
510 const LockRequest& q = refLockRequestStructure[j];
511 bool status = isConflictRecord(p, q);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530512
Ed Tanous3174e4d2020-10-07 11:41:22 -0700513 if (status)
514 {
515 return true;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530516 }
517 }
518 }
519 return false;
520}
521
522// This function converts the provided uint64_t resource id's from the two
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500523// lock requests subjected for comparison, and this function also compares
manojkiraneda0b631ae2019-12-03 17:54:28 +0530524// the content by bytes mentioned by a uint32_t number.
525
526// If all the elements in the lock requests which are subjected for comparison
Gunnar Millscaa3ce32020-07-08 14:46:53 -0500527// are same, then the last comparison would be to check for the respective
manojkiraneda0b631ae2019-12-03 17:54:28 +0530528// bytes in the resourceid based on the segment length.
529
Ratan Gupta07386c62019-12-14 14:06:09 +0530530inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
531 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530532{
Ed Tanous46ff87b2022-01-07 09:25:51 -0800533 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500534 uint8_t* p = reinterpret_cast<uint8_t*>(&resourceId1);
Ed Tanous46ff87b2022-01-07 09:25:51 -0800535 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500536 uint8_t* q = reinterpret_cast<uint8_t*>(&resourceId2);
manojkiraneda0b631ae2019-12-03 17:54:28 +0530537
Ed Tanousca45aa32022-01-07 09:28:45 -0800538 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
539 uint8_t pPosition = p[position];
540 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
541 uint8_t qPosition = q[position];
542
543 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(pPosition) << ","
544 << std::to_string(qPosition);
545 if (pPosition != qPosition)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530546 {
547 return false;
548 }
549
manojkiraneda0b631ae2019-12-03 17:54:28 +0530550 return true;
551}
552
Ed Tanousb5a76932020-09-29 16:16:58 -0700553inline bool Lock::isConflictRecord(const LockRequest& refLockRecord1,
554 const LockRequest& refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530555{
556 // No conflict if both are read locks
557
558 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
559 boost::equals(std::get<2>(refLockRecord2), "Read"))
560 {
561 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
562 return false;
563 }
564
Ed Tanous3174e4d2020-10-07 11:41:22 -0700565 uint32_t i = 0;
566 for (const auto& p : std::get<4>(refLockRecord1))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530567 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700568
569 // return conflict when any of them is try to lock all resources
570 // under the current resource level.
571 if (boost::equals(p.first, "LockAll") ||
572 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530573 {
Ed Tanous3174e4d2020-10-07 11:41:22 -0700574 BMCWEB_LOG_DEBUG
575 << "Either of the Comparing locks are trying to lock all "
576 "resources under the current resource level";
577 return true;
578 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530579
Ed Tanous3174e4d2020-10-07 11:41:22 -0700580 // determine if there is a lock-all-with-same-segment-size.
581 // If the current segment sizes are the same,then we should fail.
582
583 if ((boost::equals(p.first, "LockSame") ||
584 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockSame")) &&
585 (p.second == std::get<4>(refLockRecord2)[i].second))
586 {
587 return true;
588 }
589
590 // if segment lengths are not the same, it means two different locks
591 // So no conflict
592 if (p.second != std::get<4>(refLockRecord2)[i].second)
593 {
594 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
595 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
596 BMCWEB_LOG_DEBUG << "Segment 2 length : "
597 << std::get<4>(refLockRecord2)[i].second;
598 return false;
599 }
600
601 // compare segment data
602
603 for (uint32_t i = 0; i < p.second; i++)
604 {
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500605 // if the segment data is different, then the locks is on a
606 // different resource so no conflict between the lock
Ed Tanous3174e4d2020-10-07 11:41:22 -0700607 // records.
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500608 // BMC is little endian, but the resourceID is formed by
Ed Tanous3174e4d2020-10-07 11:41:22 -0700609 // the Management Console in such a way that, the first byte
610 // from the MSB Position corresponds to the First Segment
Ali Ahmedd3d26ba2021-04-30 09:13:53 -0500611 // data. Therefore we need to convert the incoming
Ed Tanous3174e4d2020-10-07 11:41:22 -0700612 // resourceID into Big Endian before processing further.
613 if (!(checkByte(
614 boost::endian::endian_reverse(std::get<3>(refLockRecord1)),
615 boost::endian::endian_reverse(std::get<3>(refLockRecord2)),
616 i)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530617 {
manojkiraneda0b631ae2019-12-03 17:54:28 +0530618 return false;
619 }
manojkiraneda0b631ae2019-12-03 17:54:28 +0530620 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700621
622 ++i;
manojkiraneda0b631ae2019-12-03 17:54:28 +0530623 }
624
625 return false;
626}
627
Ratan Gupta07386c62019-12-14 14:06:09 +0530628inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530629{
630 ++transactionId;
631 return transactionId;
632}
633
634} // namespace ibm_mc_lock
635} // namespace crow