blob: 3c4f8ec46aed8cbc76bb64e8868072412234083c [file] [log] [blame]
manojkiraneda0b631ae2019-12-03 17:54:28 +05301#pragma once
2
manojkiraneda4eaf2ee2019-12-13 17:10:41 +05303#include <logging.h>
4
manojkiraneda0b631ae2019-12-03 17:54:28 +05305#include <boost/algorithm/string.hpp>
6#include <boost/container/flat_map.hpp>
Manojkiran Eda55fd1a92020-04-30 19:06:48 +05307#include <boost/endian/conversion.hpp>
manojkiraneda0b631ae2019-12-03 17:54:28 +05308#include <filesystem>
Sunitha Harish8a3bb712019-12-13 03:48:09 -06009#include <fstream>
manojkiraneda0b631ae2019-12-03 17:54:28 +053010#include <nlohmann/json.hpp>
11
12namespace crow
13{
14namespace ibm_mc_lock
15{
16
17namespace fs = std::filesystem;
18using 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>;
Sunitha Harish8a3bb712019-12-13 03:48:09 -060039static constexpr const char *fileName =
40 "/var/lib/obmc/bmc-console-mgmt/locks/ibm_mc_persistent_lock_data.json";
manojkiraneda0b631ae2019-12-03 17:54:28 +053041
42class Lock
43{
44 uint32_t transactionId;
45 boost::container::flat_map<uint32_t, LockRequests> lockTable;
46
47 /*
Sunitha Harish8a3bb712019-12-13 03:48:09 -060048 * This API implements the logic to persist the locks that are contained in
49 * the lock table into a json file.
50 */
51 void saveLocks();
52
53 /*
54 * This API implements the logic to load the locks that are present in the
55 * json file into the lock table.
56 */
57 void loadLocks();
58
manojkiraneda4eaf2ee2019-12-13 17:10:41 +053059 bool createPersistentLockFilePath();
60
61 protected:
62 /*
63 * This function implements the logic for validating an incoming
64 * lock request/requests.
65 *
66 * Returns : True (if Valid)
67 * Returns : False (if not a Valid lock request)
68 */
69
70 virtual bool isValidLockRequest(const LockRequest);
71
72 /*
73 * This function implements the logic of checking if the incoming
74 * multi-lock request is not having conflicting requirements.
75 *
76 * Returns : True (if conflicting)
77 * Returns : False (if not conflicting)
78 */
79
80 virtual bool isConflictRequest(const LockRequests);
81 /*
82 * Implements the core algorithm to find the conflicting
83 * lock requests.
84 *
85 * This functions takes two lock requests and check if both
86 * are conflicting to each other.
87 *
88 * Returns : True (if conflicting)
89 * Returns : False (if not conflicting)
90 */
91 virtual bool isConflictRecord(const LockRequest, const LockRequest);
92
93 /*
94 * This function implements the logic of checking the conflicting
95 * locks from a incoming single/multi lock requests with the already
96 * existing lock request in the lock table.
97 *
98 */
99
100 virtual Rc isConflictWithTable(const LockRequests);
101 /*
102 * This function implements the logic of checking the ownership of the
103 * lock from the releaselock request.
104 *
105 * Returns : True (if the requesting HMC & Session owns the lock(s))
106 * Returns : False (if the request HMC or Session does not own the lock(s))
107 */
108
109 virtual RcRelaseLock isItMyLock(const ListOfTransactionIds &,
110 const SessionFlags &);
111
112 /*
113 * This function validates the the list of transactionID's and returns false
114 * if the transaction ID is not valid & not present in the lock table
115 */
116
117 virtual bool validateRids(const ListOfTransactionIds &);
118
119 /*
120 * This function releases the locks that are already obtained by the
121 * requesting Management console.
122 */
123
124 void releaseLock(const ListOfTransactionIds &);
125
126 Lock()
127 {
128 loadLocks();
129 transactionId = lockTable.empty() ? 0 : prev(lockTable.end())->first;
130 }
131
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600132 /*
manojkiraneda0b631ae2019-12-03 17:54:28 +0530133 * This function implements the algorithm for checking the respective
134 * bytes of the resource id based on the lock management algorithm.
135 */
136
137 bool checkByte(uint64_t, uint64_t, uint32_t);
138
139 /*
140 * This functions implements a counter that generates a unique 32 bit
141 * number for every successful transaction. This number will be used by
142 * the Management Console for debug.
143 */
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530144 virtual uint32_t generateTransactionId();
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600145
manojkiraneda0b631ae2019-12-03 17:54:28 +0530146 public:
147 /*
148 * This function implements the logic for acquiring a lock on a
Manojkiran Eda5bb0ece2020-01-20 20:22:36 +0530149 * resource if the incoming request is legitimate without any
manojkiraneda0b631ae2019-12-03 17:54:28 +0530150 * conflicting requirements & without any conflicting requirement
151 * with the exsiting locks in the lock table.
152 *
153 */
154
155 RcAcquireLock acquireLock(const LockRequests);
156
manojkiraneda3b6dea62019-12-13 17:05:36 +0530157 /*
158 * This function implements the logic for releasing the lock that are
159 * owned by a management console session.
160 *
161 * The locks can be released by two ways
162 * - Using list of transaction ID's
163 * - Using a Session ID
164 *
165 * Client can choose either of the ways by using `Type` JSON key.
166 *
167 */
168 RcReleaseLockApi releaseLock(const ListOfTransactionIds &,
169 const SessionFlags &);
170
manojkiraneda402b5712019-12-13 17:07:09 +0530171 /*
172 * This function implements the logic for getting the list of locks obtained
173 * by a particular management console.
174 */
175 RcGetLockList getLockList(const ListOfSessionIds &);
176
Ratan Gupta07386c62019-12-14 14:06:09 +0530177 /*
178 * This function is releases all the locks obtained by a particular
179 * session.
180 */
181
182 void releaseLock(const std::string &);
183
Ratan Gupta07386c62019-12-14 14:06:09 +0530184 static Lock &getInstance()
185 {
186 static Lock lockObject;
187 return lockObject;
188 }
manojkiraneda4eaf2ee2019-12-13 17:10:41 +0530189
190 virtual ~Lock()
191 {
192 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530193};
manojkiraneda0b631ae2019-12-03 17:54:28 +0530194
Ratan Gupta07386c62019-12-14 14:06:09 +0530195inline bool Lock::createPersistentLockFilePath()
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600196{
197 // The path /var/lib/obmc will be created by initrdscripts
198 // Create the directories for the persistent lock file
199 std::error_code ec;
200 if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt", ec))
201 {
202 std::filesystem::create_directory("/var/lib/obmc/bmc-console-mgmt", ec);
203 }
204 if (ec)
205 {
206 BMCWEB_LOG_DEBUG
207 << "Failed to prepare bmc-console-mgmt directory. ec : " << ec;
208 return false;
209 }
210
211 if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt/locks",
212 ec))
213 {
214 std::filesystem::create_directory(
215 "/var/lib/obmc/bmc-console-mgmt/locks", ec);
216 }
217 if (ec)
218 {
219 BMCWEB_LOG_DEBUG
220 << "Failed to prepare persistent lock file directory. ec : " << ec;
221 return false;
222 }
223 return true;
224}
225
Ratan Gupta07386c62019-12-14 14:06:09 +0530226inline void Lock::loadLocks()
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600227{
228 std::ifstream persistentFile(fileName);
229 if (persistentFile.is_open())
230 {
231 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
232 if (data.is_discarded())
233 {
234 BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
235 return;
236 }
237 BMCWEB_LOG_DEBUG << "The persistent lock data is available";
238 for (const auto &item : data.items())
239 {
240 BMCWEB_LOG_DEBUG << item.key();
241 BMCWEB_LOG_DEBUG << item.value();
242 LockRequests locks = item.value();
Ratan Gupta07386c62019-12-14 14:06:09 +0530243 lockTable.emplace(std::pair<uint32_t, LockRequests>(
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600244 std::stoul(item.key()), locks));
245 BMCWEB_LOG_DEBUG << "The persistent lock data loaded";
246 }
247 }
248}
249
Ratan Gupta07386c62019-12-14 14:06:09 +0530250inline void Lock::saveLocks()
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600251{
252 std::error_code ec;
253 if (!std::filesystem::is_directory("/var/lib/obmc/bmc-console-mgmt/locks",
254 ec))
255 {
256 if (!createPersistentLockFilePath())
257 {
258 BMCWEB_LOG_DEBUG << "Failed to create lock persistent path";
259 return;
260 }
261 }
262 std::ofstream persistentFile(fileName);
263 // set the permission of the file to 640
264 fs::perms permission =
265 fs::perms::owner_read | fs::perms::owner_write | fs::perms::group_read;
266 fs::permissions(fileName, permission);
267 nlohmann::json data;
268 for (const auto &it : lockTable)
269 {
270 data[std::to_string(it.first)] = it.second;
271 }
272 BMCWEB_LOG_DEBUG << "data is " << data;
273 persistentFile << data;
274}
275
Ratan Gupta07386c62019-12-14 14:06:09 +0530276inline RcGetLockList Lock::getLockList(const ListOfSessionIds &listSessionId)
manojkiraneda402b5712019-12-13 17:07:09 +0530277{
278
279 std::vector<std::pair<uint32_t, LockRequests>> lockList;
280
281 if (!lockTable.empty())
282 {
283 for (const auto &i : listSessionId)
284 {
285 auto it = lockTable.begin();
286 while (it != lockTable.end())
287 {
288 // Check if session id of this entry matches with session id
289 // given
290 if (std::get<0>(it->second[0]) == i)
291 {
292 BMCWEB_LOG_DEBUG << "Session id is found in the locktable";
293
294 // Push the whole lock record into a vector for returning
295 // the json
296 lockList.push_back(std::make_pair(it->first, it->second));
297 }
298 // Go to next entry in map
299 it++;
300 }
301 }
302 }
303 // we may have found at least one entry with the given session id
304 // return the json list of lock records pertaining to the given
305 // session id, or send an empty list if lock table is empty
306 return lockList;
307}
308
Ratan Gupta07386c62019-12-14 14:06:09 +0530309inline RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds &p,
310 const SessionFlags &ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530311{
312
313 bool status = validateRids(p);
314
315 if (!status)
316 {
317 // Validation of rids failed
318 BMCWEB_LOG_DEBUG << "Not a Valid request id";
319 return std::make_pair(false, status);
320 }
321 else
322 {
323 // Validation passed, check if all the locks are owned by the
324 // requesting HMC
325 auto status = isItMyLock(p, ids);
326 if (status.first)
327 {
328 // The current hmc owns all the locks, so we can release
329 // them
330 releaseLock(p);
331 }
332 return std::make_pair(true, status);
333 }
334 return std::make_pair(false, status);
335}
336
Ratan Gupta07386c62019-12-14 14:06:09 +0530337inline RcAcquireLock Lock::acquireLock(const LockRequests lockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530338{
339
340 // validate the lock request
341
342 for (auto &lockRecord : lockRequestStructure)
343 {
344 bool status = isValidLockRequest(lockRecord);
345 if (!status)
346 {
347 BMCWEB_LOG_DEBUG << "Not a Valid record";
348 BMCWEB_LOG_DEBUG << "Bad json in request";
349 return std::make_pair(true, std::make_pair(status, 0));
350 }
351 }
352 // check for conflict record
353
354 const LockRequests &multiRequest = lockRequestStructure;
355 bool status = isConflictRequest(multiRequest);
356
357 if (status)
358 {
359 BMCWEB_LOG_DEBUG << "There is a conflict within itself";
360 return std::make_pair(true, std::make_pair(status, 1));
361 }
362 else
363 {
364 BMCWEB_LOG_DEBUG << "The request is not conflicting within itself";
365
366 // Need to check for conflict with the locktable entries.
367
368 auto conflict = isConflictWithTable(multiRequest);
369
370 BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable";
371 return std::make_pair(false, conflict);
372 }
373
374 return std::make_pair(true, std::make_pair(true, 1));
375}
376
Ratan Gupta07386c62019-12-14 14:06:09 +0530377inline void Lock::releaseLock(const ListOfTransactionIds &refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530378{
379 for (const auto &id : refRids)
380 {
381 if (lockTable.erase(id))
382 {
383 BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : "
384 << id;
385 }
386
387 else
388 {
389 BMCWEB_LOG_DEBUG << "Removing the locks from the lock table "
390 "failed, tranasction ID: "
391 << id;
392 }
393 }
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600394
395 saveLocks();
manojkiraneda3b6dea62019-12-13 17:05:36 +0530396}
397
Ratan Gupta07386c62019-12-14 14:06:09 +0530398inline void Lock::releaseLock(const std::string &sessionId)
399{
400 bool isErased = false;
401 if (!lockTable.empty())
402 {
403 auto it = lockTable.begin();
404 while (it != lockTable.end())
405 {
406 if (it->second.size() != 0)
407 {
408 // Check if session id of this entry matches with session id
409 // given
410 if (std::get<0>(it->second[0]) == sessionId)
411 {
412 BMCWEB_LOG_DEBUG << "Remove the lock from the locktable "
413 "having sessionID="
414 << sessionId;
415 BMCWEB_LOG_DEBUG << "TransactionID =" << it->first;
416 it = lockTable.erase(it);
417 isErased = true;
418 }
419 else
420 {
421 it++;
422 }
423 }
424 }
425 if (isErased)
426 {
427 // save the lock in the persistent file
428 saveLocks();
429 }
430 }
431}
432inline RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds &refRids,
433 const SessionFlags &ids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530434{
435 for (const auto &id : refRids)
436 {
437 // Just need to compare the client id of the first lock records in the
438 // complete lock row(in the map), because the rest of the lock records
439 // would have the same client id
440
441 std::string expectedClientId = std::get<1>(lockTable[id][0]);
442 std::string expectedSessionId = std::get<0>(lockTable[id][0]);
443
444 if ((expectedClientId == ids.first) &&
445 (expectedSessionId == ids.second))
446 {
447 // It is owned by the currently request hmc
448 BMCWEB_LOG_DEBUG << "Lock is owned by the current hmc";
449 }
450 else
451 {
452 BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc";
453 return std::make_pair(false, std::make_pair(id, lockTable[id][0]));
454 }
455 }
456 return std::make_pair(true, std::make_pair(0, LockRequest()));
457}
458
Ratan Gupta07386c62019-12-14 14:06:09 +0530459inline bool Lock::validateRids(const ListOfTransactionIds &refRids)
manojkiraneda3b6dea62019-12-13 17:05:36 +0530460{
461 for (const auto &id : refRids)
462 {
463 auto search = lockTable.find(id);
464
465 if (search != lockTable.end())
466 {
467 BMCWEB_LOG_DEBUG << "Valid Transaction id";
468 // continue for the next rid
469 }
470 else
471 {
472 BMCWEB_LOG_DEBUG << "Atleast 1 inValid Request id";
473 return false;
474 }
475 }
476 return true;
477}
478
Ratan Gupta07386c62019-12-14 14:06:09 +0530479inline bool Lock::isValidLockRequest(const LockRequest refLockRecord)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530480{
481
482 // validate the locktype
483
484 if (!((boost::equals(std::get<2>(refLockRecord), "Read") ||
485 (boost::equals(std::get<2>(refLockRecord), "Write")))))
486 {
487 BMCWEB_LOG_DEBUG << "Validation of LockType Failed";
488 BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord);
489 return false;
490 }
491
492 BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size());
493
494 // validate the number of segments
495 // Allowed No of segments are between 2 and 6
496 if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) ||
497 (static_cast<int>(std::get<4>(refLockRecord).size()) < 2))
498 {
499 BMCWEB_LOG_DEBUG << "Validation of Number of Segements Failed";
500 BMCWEB_LOG_DEBUG << "Number of Segments provied : "
501 << sizeof(std::get<4>(refLockRecord));
502 return false;
503 }
504
505 int lockFlag = 0;
506 // validate the lockflags & segment length
507
508 for (const auto &p : std::get<4>(refLockRecord))
509 {
510
511 // validate the lock flags
512 // Allowed lockflags are locksame,lockall & dontlock
513
514 if (!((boost::equals(p.first, "LockSame") ||
515 (boost::equals(p.first, "LockAll")) ||
516 (boost::equals(p.first, "DontLock")))))
517 {
518 BMCWEB_LOG_DEBUG << "Validation of lock flags failed";
519 BMCWEB_LOG_DEBUG << p.first;
520 return false;
521 }
522
523 // validate the segment length
524 // Allowed values of segment length are between 1 and 4
525
526 if (p.second < 1 || p.second > 4)
527 {
528 BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed";
529 BMCWEB_LOG_DEBUG << p.second;
530 return false;
531 }
532
533 if ((boost::equals(p.first, "LockSame") ||
534 (boost::equals(p.first, "LockAll"))))
535 {
536 ++lockFlag;
537 if (lockFlag >= 2)
538 {
539 return false;
540 }
541 }
542 }
543
manojkiraneda0b631ae2019-12-03 17:54:28 +0530544 return true;
545}
546
Ratan Gupta07386c62019-12-14 14:06:09 +0530547inline Rc Lock::isConflictWithTable(const LockRequests refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530548{
549
550 uint32_t transactionId;
551
552 if (lockTable.empty())
553 {
554 transactionId = generateTransactionId();
555 BMCWEB_LOG_DEBUG << transactionId;
556 // Lock table is empty, so we are safe to add the lockrecords
557 // as there will be no conflict
558 BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords";
559 lockTable.emplace(std::pair<uint32_t, LockRequests>(
560 transactionId, refLockRequestStructure));
561
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600562 // save the lock in the persistent file
563 saveLocks();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530564 return std::make_pair(false, transactionId);
565 }
566
567 else
568 {
569 BMCWEB_LOG_DEBUG
570 << "Lock table is not empty, check for conflict with lock table";
571 // Lock table is not empty, compare the lockrequest entries with
572 // the entries in the lock table
573
574 for (const auto &lockRecord1 : refLockRequestStructure)
575 {
576 for (const auto &map : lockTable)
577 {
578 for (const auto &lockRecord2 : map.second)
579 {
580 bool status = isConflictRecord(lockRecord1, lockRecord2);
581 if (status)
582 {
583 return std::make_pair(
584 true, std::make_pair(map.first, lockRecord2));
585 }
586 }
587 }
588 }
589
590 // Reached here, so no conflict with the locktable, so we are safe to
591 // add the request records into the lock table
592
593 // Lock table is empty, so we are safe to add the lockrecords
594 // as there will be no conflict
595 BMCWEB_LOG_DEBUG << " Adding elements into lock table";
596 transactionId = generateTransactionId();
597 lockTable.emplace(
598 std::make_pair(transactionId, refLockRequestStructure));
Sunitha Harish8a3bb712019-12-13 03:48:09 -0600599
600 // save the lock in the persistent file
601 saveLocks();
manojkiraneda0b631ae2019-12-03 17:54:28 +0530602 }
603 return std::make_pair(false, transactionId);
604}
605
Ratan Gupta07386c62019-12-14 14:06:09 +0530606inline bool Lock::isConflictRequest(const LockRequests refLockRequestStructure)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530607{
608 // check for all the locks coming in as a part of single request
609 // return conflict if any two lock requests are conflicting
610
611 if (refLockRequestStructure.size() == 1)
612 {
613 BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict";
614 // This means , we have only one lock request in the current
615 // request , so no conflict within the request
616 return false;
617 }
618
619 else
620 {
621 BMCWEB_LOG_DEBUG
622 << "There are multiple lock requests coming in a single request";
623
624 // There are multiple requests a part of one request
625
626 for (uint32_t i = 0; i < refLockRequestStructure.size(); i++)
627 {
628 for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++)
629 {
630 const LockRequest &p = refLockRequestStructure[i];
631 const LockRequest &q = refLockRequestStructure[j];
632 bool status = isConflictRecord(p, q);
633
634 if (status)
635 {
636 return true;
637 }
638 }
639 }
640 }
641 return false;
642}
643
644// This function converts the provided uint64_t resource id's from the two
645// lock requests subjected for comparision, and this function also compares
646// the content by bytes mentioned by a uint32_t number.
647
648// If all the elements in the lock requests which are subjected for comparison
649// are same, then the last comparision would be to check for the respective
650// bytes in the resourceid based on the segment length.
651
Ratan Gupta07386c62019-12-14 14:06:09 +0530652inline bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2,
653 uint32_t position)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530654{
655 uint8_t *p = reinterpret_cast<uint8_t *>(&resourceId1);
656 uint8_t *q = reinterpret_cast<uint8_t *>(&resourceId2);
657
658 BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(p[position]) << ","
659 << std::to_string(q[position]);
660 if (p[position] != q[position])
661 {
662 return false;
663 }
664
665 else
666 {
667 return true;
668 }
Ratan Gupta07386c62019-12-14 14:06:09 +0530669
manojkiraneda0b631ae2019-12-03 17:54:28 +0530670 return true;
671}
672
Ratan Gupta07386c62019-12-14 14:06:09 +0530673inline bool Lock::isConflictRecord(const LockRequest refLockRecord1,
674 const LockRequest refLockRecord2)
manojkiraneda0b631ae2019-12-03 17:54:28 +0530675{
676 // No conflict if both are read locks
677
678 if (boost::equals(std::get<2>(refLockRecord1), "Read") &&
679 boost::equals(std::get<2>(refLockRecord2), "Read"))
680 {
681 BMCWEB_LOG_DEBUG << "Both are read locks, no conflict";
682 return false;
683 }
684
685 else
686 {
687 uint32_t i = 0;
688 for (const auto &p : std::get<4>(refLockRecord1))
689 {
690
691 // return conflict when any of them is try to lock all resources
692 // under the current resource level.
693 if (boost::equals(p.first, "LockAll") ||
694 boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll"))
695 {
696 BMCWEB_LOG_DEBUG
697 << "Either of the Comparing locks are trying to lock all "
698 "resources under the current resource level";
699 return true;
700 }
701
702 // determine if there is a lock-all-with-same-segment-size.
703 // If the current segment sizes are the same,then we should fail.
704
705 if ((boost::equals(p.first, "LockSame") ||
706 boost::equals(std::get<4>(refLockRecord2)[i].first,
707 "LockSame")) &&
708 (p.second == std::get<4>(refLockRecord2)[i].second))
709 {
710 return true;
711 }
712
713 // if segment lengths are not the same, it means two different locks
714 // So no conflict
715 if (p.second != std::get<4>(refLockRecord2)[i].second)
716 {
717 BMCWEB_LOG_DEBUG << "Segment lengths are not same";
718 BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second;
719 BMCWEB_LOG_DEBUG << "Segment 2 length : "
720 << std::get<4>(refLockRecord2)[i].second;
721 return false;
722 }
723
724 // compare segment data
725
726 for (uint32_t i = 0; i < p.second; i++)
727 {
728 // if the segment data is different , then the locks is on a
Manojkiran Eda55fd1a92020-04-30 19:06:48 +0530729 // different resource So no conflict between the lock
730 // records.
731 // BMC is little endian , but the resourceID is formed by
732 // the Managament Console in such a way that, the first byte
733 // from the MSB Position corresponds to the First Segment
734 // data. Therefore we need to convert the in-comming
735 // resourceID into Big Endian before processing further.
736 if (!(checkByte(boost::endian::endian_reverse(
737 std::get<3>(refLockRecord1)),
738 boost::endian::endian_reverse(
739 std::get<3>(refLockRecord2)),
740 i)))
manojkiraneda0b631ae2019-12-03 17:54:28 +0530741 {
742 return false;
743 }
744 }
745
746 ++i;
747 }
748 }
749
750 return false;
751}
752
Ratan Gupta07386c62019-12-14 14:06:09 +0530753inline uint32_t Lock::generateTransactionId()
manojkiraneda0b631ae2019-12-03 17:54:28 +0530754{
755 ++transactionId;
756 return transactionId;
757}
758
759} // namespace ibm_mc_lock
760} // namespace crow