| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 1 | #pragma once | 
|  | 2 |  | 
|  | 3 | #include <app.h> | 
|  | 4 |  | 
|  | 5 | #include <boost/algorithm/string.hpp> | 
|  | 6 | #include <boost/container/flat_map.hpp> | 
|  | 7 | #include <filesystem> | 
|  | 8 | #include <nlohmann/json.hpp> | 
|  | 9 |  | 
|  | 10 | namespace crow | 
|  | 11 | { | 
|  | 12 | namespace ibm_mc_lock | 
|  | 13 | { | 
|  | 14 |  | 
|  | 15 | namespace fs = std::filesystem; | 
|  | 16 | using SType = std::string; | 
|  | 17 |  | 
|  | 18 | /*---------------------------------------- | 
|  | 19 | |Segment flags : LockFlag | SegmentLength| | 
|  | 20 | ------------------------------------------*/ | 
|  | 21 |  | 
|  | 22 | using SegmentFlags = std::vector<std::pair<SType, uint32_t>>; | 
|  | 23 |  | 
|  | 24 | // Lockrequest = session-id | hmc-id | locktype | resourceid | segmentinfo | 
|  | 25 | using LockRequest = std::tuple<SType, SType, SType, uint64_t, SegmentFlags>; | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 26 | using LockRequests = std::vector<LockRequest>; | 
|  | 27 | using Rc = | 
|  | 28 | std::pair<bool, std::variant<uint32_t, std::pair<uint32_t, LockRequest>>>; | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 29 | using RcRelaseLock = std::pair<bool, std::pair<uint32_t, LockRequest>>; | 
| manojkiraneda | 402b571 | 2019-12-13 17:07:09 +0530 | [diff] [blame^] | 30 | using RcGetLockList = | 
|  | 31 | std::variant<std::string, std::vector<std::pair<uint32_t, LockRequests>>>; | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 32 | using ListOfTransactionIds = std::vector<uint32_t>; | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 33 | using RcAcquireLock = std::pair<bool, std::variant<Rc, std::pair<bool, int>>>; | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 34 | using RcReleaseLockApi = std::pair<bool, std::variant<bool, RcRelaseLock>>; | 
|  | 35 | using SessionFlags = std::pair<SType, SType>; | 
| manojkiraneda | 402b571 | 2019-12-13 17:07:09 +0530 | [diff] [blame^] | 36 | using ListOfSessionIds = std::vector<std::string>; | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 37 |  | 
|  | 38 | class Lock | 
|  | 39 | { | 
|  | 40 | uint32_t transactionId; | 
|  | 41 | boost::container::flat_map<uint32_t, LockRequests> lockTable; | 
|  | 42 |  | 
|  | 43 | /* | 
|  | 44 | * This function implements the logic for validating an incomming | 
|  | 45 | * lock request/requests. | 
|  | 46 | * | 
|  | 47 | * Returns : True (if Valid) | 
|  | 48 | * Returns : False (if not a Valid lock request) | 
|  | 49 | */ | 
|  | 50 |  | 
|  | 51 | bool isValidLockRequest(const LockRequest); | 
|  | 52 |  | 
|  | 53 | /* | 
|  | 54 | * This function implements the logic of checking if the incomming | 
|  | 55 | * multi-lock request is not having conflicting requirements. | 
|  | 56 | * | 
|  | 57 | * Returns : True (if conflicting) | 
|  | 58 | * Returns : False (if not conflicting) | 
|  | 59 | */ | 
|  | 60 |  | 
|  | 61 | bool isConflictRequest(const LockRequests); | 
|  | 62 | /* | 
|  | 63 | * Implements the core algorithm to find the conflicting | 
|  | 64 | * lock requests. | 
|  | 65 | * | 
|  | 66 | * This functions takes two lock requests and check if both | 
|  | 67 | * are conflicting to each other. | 
|  | 68 | * | 
|  | 69 | * Returns : True (if conflicting) | 
|  | 70 | * Returns : False (if not conflicting) | 
|  | 71 | */ | 
|  | 72 | bool isConflictRecord(const LockRequest, const LockRequest); | 
|  | 73 |  | 
|  | 74 | /* | 
|  | 75 | * This function implements the logic of checking the conflicting | 
|  | 76 | * locks from a incomming single/multi lock requests with the already | 
|  | 77 | * existing lock request in the lock table. | 
|  | 78 | * | 
|  | 79 | */ | 
|  | 80 |  | 
|  | 81 | Rc isConflictWithTable(const LockRequests); | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 82 | /* | 
|  | 83 | * This function implements the logic of checking the ownership of the | 
|  | 84 | * lock from the releaselock request. | 
|  | 85 | * | 
|  | 86 | * Returns : True (if the requesting HMC & Session owns the lock(s)) | 
|  | 87 | * Returns : False (if the request HMC or Session does not own the lock(s)) | 
|  | 88 | */ | 
|  | 89 |  | 
|  | 90 | RcRelaseLock isItMyLock(const ListOfTransactionIds &, const SessionFlags &); | 
|  | 91 |  | 
|  | 92 | /* | 
|  | 93 | * This function validates the the list of transactionID's and returns false | 
|  | 94 | * if the transaction ID is not valid & not present in the lock table | 
|  | 95 | */ | 
|  | 96 |  | 
|  | 97 | bool validateRids(const ListOfTransactionIds &); | 
|  | 98 |  | 
|  | 99 | /* | 
|  | 100 | * This function releases the locks that are already obtained by the | 
|  | 101 | * requesting Management console. | 
|  | 102 | */ | 
|  | 103 |  | 
|  | 104 | void releaseLock(const ListOfTransactionIds &); | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 105 |  | 
|  | 106 | /* | 
|  | 107 | * This function implements the algorithm for checking the respective | 
|  | 108 | * bytes of the resource id based on the lock management algorithm. | 
|  | 109 | */ | 
|  | 110 |  | 
|  | 111 | bool checkByte(uint64_t, uint64_t, uint32_t); | 
|  | 112 |  | 
|  | 113 | /* | 
|  | 114 | * This functions implements a counter that generates a unique 32 bit | 
|  | 115 | * number for every successful transaction. This number will be used by | 
|  | 116 | * the Management Console for debug. | 
|  | 117 | */ | 
|  | 118 | uint32_t generateTransactionId(); | 
|  | 119 |  | 
|  | 120 | public: | 
|  | 121 | /* | 
|  | 122 | * This function implements the logic for acquiring a lock on a | 
|  | 123 | * resource if the incomming request is legitimate without any | 
|  | 124 | * conflicting requirements & without any conflicting requirement | 
|  | 125 | * with the exsiting locks in the lock table. | 
|  | 126 | * | 
|  | 127 | */ | 
|  | 128 |  | 
|  | 129 | RcAcquireLock acquireLock(const LockRequests); | 
|  | 130 |  | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 131 | /* | 
|  | 132 | * This function implements the logic for releasing the lock that are | 
|  | 133 | * owned by a management console session. | 
|  | 134 | * | 
|  | 135 | * The locks can be released by two ways | 
|  | 136 | *  - Using list of transaction ID's | 
|  | 137 | *  - Using a Session ID | 
|  | 138 | * | 
|  | 139 | * Client can choose either of the ways by using `Type` JSON key. | 
|  | 140 | * | 
|  | 141 | */ | 
|  | 142 | RcReleaseLockApi releaseLock(const ListOfTransactionIds &, | 
|  | 143 | const SessionFlags &); | 
|  | 144 |  | 
| manojkiraneda | 402b571 | 2019-12-13 17:07:09 +0530 | [diff] [blame^] | 145 | /* | 
|  | 146 | * This function implements the logic for getting the list of locks obtained | 
|  | 147 | * by a particular management console. | 
|  | 148 | */ | 
|  | 149 | RcGetLockList getLockList(const ListOfSessionIds &); | 
|  | 150 |  | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 151 | Lock() | 
|  | 152 | { | 
|  | 153 | transactionId = 0; | 
|  | 154 | } | 
|  | 155 |  | 
|  | 156 | } lockObject; | 
|  | 157 |  | 
| manojkiraneda | 402b571 | 2019-12-13 17:07:09 +0530 | [diff] [blame^] | 158 | RcGetLockList Lock::getLockList(const ListOfSessionIds &listSessionId) | 
|  | 159 | { | 
|  | 160 |  | 
|  | 161 | std::vector<std::pair<uint32_t, LockRequests>> lockList; | 
|  | 162 |  | 
|  | 163 | if (!lockTable.empty()) | 
|  | 164 | { | 
|  | 165 | for (const auto &i : listSessionId) | 
|  | 166 | { | 
|  | 167 | auto it = lockTable.begin(); | 
|  | 168 | while (it != lockTable.end()) | 
|  | 169 | { | 
|  | 170 | // Check if session id of this entry matches with session id | 
|  | 171 | // given | 
|  | 172 | if (std::get<0>(it->second[0]) == i) | 
|  | 173 | { | 
|  | 174 | BMCWEB_LOG_DEBUG << "Session id is found in the locktable"; | 
|  | 175 |  | 
|  | 176 | // Push the whole lock record into a vector for returning | 
|  | 177 | // the json | 
|  | 178 | lockList.push_back(std::make_pair(it->first, it->second)); | 
|  | 179 | } | 
|  | 180 | // Go to next entry in map | 
|  | 181 | it++; | 
|  | 182 | } | 
|  | 183 | } | 
|  | 184 | } | 
|  | 185 | // we may have found at least one entry with the given session id | 
|  | 186 | // return the json list of lock records pertaining to the given | 
|  | 187 | // session id, or send an empty list if lock table is empty | 
|  | 188 | return lockList; | 
|  | 189 | } | 
|  | 190 |  | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 191 | RcReleaseLockApi Lock::releaseLock(const ListOfTransactionIds &p, | 
|  | 192 | const SessionFlags &ids) | 
|  | 193 | { | 
|  | 194 |  | 
|  | 195 | bool status = validateRids(p); | 
|  | 196 |  | 
|  | 197 | if (!status) | 
|  | 198 | { | 
|  | 199 | // Validation of rids failed | 
|  | 200 | BMCWEB_LOG_DEBUG << "Not a Valid request id"; | 
|  | 201 | return std::make_pair(false, status); | 
|  | 202 | } | 
|  | 203 | else | 
|  | 204 | { | 
|  | 205 | // Validation passed, check if all the locks are owned by the | 
|  | 206 | // requesting HMC | 
|  | 207 | auto status = isItMyLock(p, ids); | 
|  | 208 | if (status.first) | 
|  | 209 | { | 
|  | 210 | // The current hmc owns all the locks, so we can release | 
|  | 211 | // them | 
|  | 212 | releaseLock(p); | 
|  | 213 | } | 
|  | 214 | return std::make_pair(true, status); | 
|  | 215 | } | 
|  | 216 | return std::make_pair(false, status); | 
|  | 217 | } | 
|  | 218 |  | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 219 | RcAcquireLock Lock::acquireLock(const LockRequests lockRequestStructure) | 
|  | 220 | { | 
|  | 221 |  | 
|  | 222 | // validate the lock request | 
|  | 223 |  | 
|  | 224 | for (auto &lockRecord : lockRequestStructure) | 
|  | 225 | { | 
|  | 226 | bool status = isValidLockRequest(lockRecord); | 
|  | 227 | if (!status) | 
|  | 228 | { | 
|  | 229 | BMCWEB_LOG_DEBUG << "Not a Valid record"; | 
|  | 230 | BMCWEB_LOG_DEBUG << "Bad json in request"; | 
|  | 231 | return std::make_pair(true, std::make_pair(status, 0)); | 
|  | 232 | } | 
|  | 233 | } | 
|  | 234 | // check for conflict record | 
|  | 235 |  | 
|  | 236 | const LockRequests &multiRequest = lockRequestStructure; | 
|  | 237 | bool status = isConflictRequest(multiRequest); | 
|  | 238 |  | 
|  | 239 | if (status) | 
|  | 240 | { | 
|  | 241 | BMCWEB_LOG_DEBUG << "There is a conflict within itself"; | 
|  | 242 | return std::make_pair(true, std::make_pair(status, 1)); | 
|  | 243 | } | 
|  | 244 | else | 
|  | 245 | { | 
|  | 246 | BMCWEB_LOG_DEBUG << "The request is not conflicting within itself"; | 
|  | 247 |  | 
|  | 248 | // Need to check for conflict with the locktable entries. | 
|  | 249 |  | 
|  | 250 | auto conflict = isConflictWithTable(multiRequest); | 
|  | 251 |  | 
|  | 252 | BMCWEB_LOG_DEBUG << "Done with checking conflict with the locktable"; | 
|  | 253 | return std::make_pair(false, conflict); | 
|  | 254 | } | 
|  | 255 |  | 
|  | 256 | return std::make_pair(true, std::make_pair(true, 1)); | 
|  | 257 | } | 
|  | 258 |  | 
| manojkiraneda | 3b6dea6 | 2019-12-13 17:05:36 +0530 | [diff] [blame] | 259 | void Lock::releaseLock(const ListOfTransactionIds &refRids) | 
|  | 260 | { | 
|  | 261 | for (const auto &id : refRids) | 
|  | 262 | { | 
|  | 263 | if (lockTable.erase(id)) | 
|  | 264 | { | 
|  | 265 | BMCWEB_LOG_DEBUG << "Removing the locks with transaction ID : " | 
|  | 266 | << id; | 
|  | 267 | } | 
|  | 268 |  | 
|  | 269 | else | 
|  | 270 | { | 
|  | 271 | BMCWEB_LOG_DEBUG << "Removing the locks from the lock table " | 
|  | 272 | "failed, tranasction ID: " | 
|  | 273 | << id; | 
|  | 274 | } | 
|  | 275 | } | 
|  | 276 | } | 
|  | 277 |  | 
|  | 278 | RcRelaseLock Lock::isItMyLock(const ListOfTransactionIds &refRids, | 
|  | 279 | const SessionFlags &ids) | 
|  | 280 | { | 
|  | 281 | for (const auto &id : refRids) | 
|  | 282 | { | 
|  | 283 | // Just need to compare the client id of the first lock records in the | 
|  | 284 | // complete lock row(in the map), because the rest of the lock records | 
|  | 285 | // would have the same client id | 
|  | 286 |  | 
|  | 287 | std::string expectedClientId = std::get<1>(lockTable[id][0]); | 
|  | 288 | std::string expectedSessionId = std::get<0>(lockTable[id][0]); | 
|  | 289 |  | 
|  | 290 | if ((expectedClientId == ids.first) && | 
|  | 291 | (expectedSessionId == ids.second)) | 
|  | 292 | { | 
|  | 293 | // It is owned by the currently request hmc | 
|  | 294 | BMCWEB_LOG_DEBUG << "Lock is owned  by the current hmc"; | 
|  | 295 | } | 
|  | 296 | else | 
|  | 297 | { | 
|  | 298 | BMCWEB_LOG_DEBUG << "Lock is not owned by the current hmc"; | 
|  | 299 | return std::make_pair(false, std::make_pair(id, lockTable[id][0])); | 
|  | 300 | } | 
|  | 301 | } | 
|  | 302 | return std::make_pair(true, std::make_pair(0, LockRequest())); | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | bool Lock::validateRids(const ListOfTransactionIds &refRids) | 
|  | 306 | { | 
|  | 307 | for (const auto &id : refRids) | 
|  | 308 | { | 
|  | 309 | auto search = lockTable.find(id); | 
|  | 310 |  | 
|  | 311 | if (search != lockTable.end()) | 
|  | 312 | { | 
|  | 313 | BMCWEB_LOG_DEBUG << "Valid Transaction id"; | 
|  | 314 | //  continue for the next rid | 
|  | 315 | } | 
|  | 316 | else | 
|  | 317 | { | 
|  | 318 | BMCWEB_LOG_DEBUG << "Atleast 1 inValid Request id"; | 
|  | 319 | return false; | 
|  | 320 | } | 
|  | 321 | } | 
|  | 322 | return true; | 
|  | 323 | } | 
|  | 324 |  | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 325 | bool Lock::isValidLockRequest(const LockRequest refLockRecord) | 
|  | 326 | { | 
|  | 327 |  | 
|  | 328 | // validate the locktype | 
|  | 329 |  | 
|  | 330 | if (!((boost::equals(std::get<2>(refLockRecord), "Read") || | 
|  | 331 | (boost::equals(std::get<2>(refLockRecord), "Write"))))) | 
|  | 332 | { | 
|  | 333 | BMCWEB_LOG_DEBUG << "Validation of LockType Failed"; | 
|  | 334 | BMCWEB_LOG_DEBUG << "Locktype : " << std::get<2>(refLockRecord); | 
|  | 335 | return false; | 
|  | 336 | } | 
|  | 337 |  | 
|  | 338 | BMCWEB_LOG_DEBUG << static_cast<int>(std::get<4>(refLockRecord).size()); | 
|  | 339 |  | 
|  | 340 | // validate the number of segments | 
|  | 341 | // Allowed No of segments are between 2 and 6 | 
|  | 342 | if ((static_cast<int>(std::get<4>(refLockRecord).size()) > 6) || | 
|  | 343 | (static_cast<int>(std::get<4>(refLockRecord).size()) < 2)) | 
|  | 344 | { | 
|  | 345 | BMCWEB_LOG_DEBUG << "Validation of Number of Segements Failed"; | 
|  | 346 | BMCWEB_LOG_DEBUG << "Number of Segments provied : " | 
|  | 347 | << sizeof(std::get<4>(refLockRecord)); | 
|  | 348 | return false; | 
|  | 349 | } | 
|  | 350 |  | 
|  | 351 | int lockFlag = 0; | 
|  | 352 | // validate the lockflags & segment length | 
|  | 353 |  | 
|  | 354 | for (const auto &p : std::get<4>(refLockRecord)) | 
|  | 355 | { | 
|  | 356 |  | 
|  | 357 | // validate the lock flags | 
|  | 358 | // Allowed lockflags are locksame,lockall & dontlock | 
|  | 359 |  | 
|  | 360 | if (!((boost::equals(p.first, "LockSame") || | 
|  | 361 | (boost::equals(p.first, "LockAll")) || | 
|  | 362 | (boost::equals(p.first, "DontLock"))))) | 
|  | 363 | { | 
|  | 364 | BMCWEB_LOG_DEBUG << "Validation of lock flags failed"; | 
|  | 365 | BMCWEB_LOG_DEBUG << p.first; | 
|  | 366 | return false; | 
|  | 367 | } | 
|  | 368 |  | 
|  | 369 | // validate the segment length | 
|  | 370 | // Allowed values of segment length are between 1 and 4 | 
|  | 371 |  | 
|  | 372 | if (p.second < 1 || p.second > 4) | 
|  | 373 | { | 
|  | 374 | BMCWEB_LOG_DEBUG << "Validation of Segment Length Failed"; | 
|  | 375 | BMCWEB_LOG_DEBUG << p.second; | 
|  | 376 | return false; | 
|  | 377 | } | 
|  | 378 |  | 
|  | 379 | if ((boost::equals(p.first, "LockSame") || | 
|  | 380 | (boost::equals(p.first, "LockAll")))) | 
|  | 381 | { | 
|  | 382 | ++lockFlag; | 
|  | 383 | if (lockFlag >= 2) | 
|  | 384 | { | 
|  | 385 | return false; | 
|  | 386 | } | 
|  | 387 | } | 
|  | 388 | } | 
|  | 389 |  | 
| manojkiraneda | 0b631ae | 2019-12-03 17:54:28 +0530 | [diff] [blame] | 390 | return true; | 
|  | 391 | } | 
|  | 392 |  | 
|  | 393 | Rc Lock::isConflictWithTable(const LockRequests refLockRequestStructure) | 
|  | 394 | { | 
|  | 395 |  | 
|  | 396 | uint32_t transactionId; | 
|  | 397 |  | 
|  | 398 | if (lockTable.empty()) | 
|  | 399 | { | 
|  | 400 | transactionId = generateTransactionId(); | 
|  | 401 | BMCWEB_LOG_DEBUG << transactionId; | 
|  | 402 | // Lock table is empty, so we are safe to add the lockrecords | 
|  | 403 | // as there will be no conflict | 
|  | 404 | BMCWEB_LOG_DEBUG << "Lock table is empty, so adding the lockrecords"; | 
|  | 405 | lockTable.emplace(std::pair<uint32_t, LockRequests>( | 
|  | 406 | transactionId, refLockRequestStructure)); | 
|  | 407 |  | 
|  | 408 | return std::make_pair(false, transactionId); | 
|  | 409 | } | 
|  | 410 |  | 
|  | 411 | else | 
|  | 412 | { | 
|  | 413 | BMCWEB_LOG_DEBUG | 
|  | 414 | << "Lock table is not empty, check for conflict with lock table"; | 
|  | 415 | // Lock table is not empty, compare the lockrequest entries with | 
|  | 416 | // the entries in the lock table | 
|  | 417 |  | 
|  | 418 | for (const auto &lockRecord1 : refLockRequestStructure) | 
|  | 419 | { | 
|  | 420 | for (const auto &map : lockTable) | 
|  | 421 | { | 
|  | 422 | for (const auto &lockRecord2 : map.second) | 
|  | 423 | { | 
|  | 424 | bool status = isConflictRecord(lockRecord1, lockRecord2); | 
|  | 425 | if (status) | 
|  | 426 | { | 
|  | 427 | return std::make_pair( | 
|  | 428 | true, std::make_pair(map.first, lockRecord2)); | 
|  | 429 | } | 
|  | 430 | } | 
|  | 431 | } | 
|  | 432 | } | 
|  | 433 |  | 
|  | 434 | // Reached here, so no conflict with the locktable, so we are safe to | 
|  | 435 | // add the request records into the lock table | 
|  | 436 |  | 
|  | 437 | // Lock table is empty, so we are safe to add the lockrecords | 
|  | 438 | // as there will be no conflict | 
|  | 439 | BMCWEB_LOG_DEBUG << " Adding elements into lock table"; | 
|  | 440 | transactionId = generateTransactionId(); | 
|  | 441 | lockTable.emplace( | 
|  | 442 | std::make_pair(transactionId, refLockRequestStructure)); | 
|  | 443 | } | 
|  | 444 | return std::make_pair(false, transactionId); | 
|  | 445 | } | 
|  | 446 |  | 
|  | 447 | bool Lock::isConflictRequest(const LockRequests refLockRequestStructure) | 
|  | 448 | { | 
|  | 449 | // check for all the locks coming in as a part of single request | 
|  | 450 | // return conflict if any two lock requests are conflicting | 
|  | 451 |  | 
|  | 452 | if (refLockRequestStructure.size() == 1) | 
|  | 453 | { | 
|  | 454 | BMCWEB_LOG_DEBUG << "Only single lock request, so there is no conflict"; | 
|  | 455 | // This means , we have only one lock request in the current | 
|  | 456 | // request , so no conflict within the request | 
|  | 457 | return false; | 
|  | 458 | } | 
|  | 459 |  | 
|  | 460 | else | 
|  | 461 | { | 
|  | 462 | BMCWEB_LOG_DEBUG | 
|  | 463 | << "There are multiple lock requests coming in a single request"; | 
|  | 464 |  | 
|  | 465 | // There are multiple requests a part of one request | 
|  | 466 |  | 
|  | 467 | for (uint32_t i = 0; i < refLockRequestStructure.size(); i++) | 
|  | 468 | { | 
|  | 469 | for (uint32_t j = i + 1; j < refLockRequestStructure.size(); j++) | 
|  | 470 | { | 
|  | 471 | const LockRequest &p = refLockRequestStructure[i]; | 
|  | 472 | const LockRequest &q = refLockRequestStructure[j]; | 
|  | 473 | bool status = isConflictRecord(p, q); | 
|  | 474 |  | 
|  | 475 | if (status) | 
|  | 476 | { | 
|  | 477 | return true; | 
|  | 478 | } | 
|  | 479 | } | 
|  | 480 | } | 
|  | 481 | } | 
|  | 482 | return false; | 
|  | 483 | } | 
|  | 484 |  | 
|  | 485 | // This function converts the provided uint64_t resource id's from the two | 
|  | 486 | // lock requests subjected for comparision, and this function also compares | 
|  | 487 | // the content by bytes mentioned by a uint32_t number. | 
|  | 488 |  | 
|  | 489 | // If all the elements in the lock requests which are subjected for comparison | 
|  | 490 | // are same, then the last comparision would be to check for the respective | 
|  | 491 | // bytes in the resourceid based on the segment length. | 
|  | 492 |  | 
|  | 493 | bool Lock::checkByte(uint64_t resourceId1, uint64_t resourceId2, | 
|  | 494 | uint32_t position) | 
|  | 495 | { | 
|  | 496 | uint8_t *p = reinterpret_cast<uint8_t *>(&resourceId1); | 
|  | 497 | uint8_t *q = reinterpret_cast<uint8_t *>(&resourceId2); | 
|  | 498 |  | 
|  | 499 | BMCWEB_LOG_DEBUG << "Comparing bytes " << std::to_string(p[position]) << "," | 
|  | 500 | << std::to_string(q[position]); | 
|  | 501 | if (p[position] != q[position]) | 
|  | 502 | { | 
|  | 503 | return false; | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | else | 
|  | 507 | { | 
|  | 508 | return true; | 
|  | 509 | } | 
|  | 510 | return true; | 
|  | 511 | } | 
|  | 512 |  | 
|  | 513 | bool Lock::isConflictRecord(const LockRequest refLockRecord1, | 
|  | 514 | const LockRequest refLockRecord2) | 
|  | 515 | { | 
|  | 516 | // No conflict if both are read locks | 
|  | 517 |  | 
|  | 518 | if (boost::equals(std::get<2>(refLockRecord1), "Read") && | 
|  | 519 | boost::equals(std::get<2>(refLockRecord2), "Read")) | 
|  | 520 | { | 
|  | 521 | BMCWEB_LOG_DEBUG << "Both are read locks, no conflict"; | 
|  | 522 | return false; | 
|  | 523 | } | 
|  | 524 |  | 
|  | 525 | else | 
|  | 526 | { | 
|  | 527 | uint32_t i = 0; | 
|  | 528 | for (const auto &p : std::get<4>(refLockRecord1)) | 
|  | 529 | { | 
|  | 530 |  | 
|  | 531 | // return conflict when any of them is try to lock all resources | 
|  | 532 | // under the current resource level. | 
|  | 533 | if (boost::equals(p.first, "LockAll") || | 
|  | 534 | boost::equals(std::get<4>(refLockRecord2)[i].first, "LockAll")) | 
|  | 535 | { | 
|  | 536 | BMCWEB_LOG_DEBUG | 
|  | 537 | << "Either of the Comparing locks are trying to lock all " | 
|  | 538 | "resources under the current resource level"; | 
|  | 539 | return true; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | // determine if there is a lock-all-with-same-segment-size. | 
|  | 543 | // If the current segment sizes are the same,then we should fail. | 
|  | 544 |  | 
|  | 545 | if ((boost::equals(p.first, "LockSame") || | 
|  | 546 | boost::equals(std::get<4>(refLockRecord2)[i].first, | 
|  | 547 | "LockSame")) && | 
|  | 548 | (p.second == std::get<4>(refLockRecord2)[i].second)) | 
|  | 549 | { | 
|  | 550 | return true; | 
|  | 551 | } | 
|  | 552 |  | 
|  | 553 | // if segment lengths are not the same, it means two different locks | 
|  | 554 | // So no conflict | 
|  | 555 | if (p.second != std::get<4>(refLockRecord2)[i].second) | 
|  | 556 | { | 
|  | 557 | BMCWEB_LOG_DEBUG << "Segment lengths are not same"; | 
|  | 558 | BMCWEB_LOG_DEBUG << "Segment 1 length : " << p.second; | 
|  | 559 | BMCWEB_LOG_DEBUG << "Segment 2 length : " | 
|  | 560 | << std::get<4>(refLockRecord2)[i].second; | 
|  | 561 | return false; | 
|  | 562 | } | 
|  | 563 |  | 
|  | 564 | // compare segment data | 
|  | 565 |  | 
|  | 566 | for (uint32_t i = 0; i < p.second; i++) | 
|  | 567 | { | 
|  | 568 | // if the segment data is different , then the locks is on a | 
|  | 569 | // different resource So no conflict between the lock records | 
|  | 570 | if (!(checkByte(std::get<3>(refLockRecord1), | 
|  | 571 | std::get<3>(refLockRecord2), i))) | 
|  | 572 | { | 
|  | 573 | return false; | 
|  | 574 | } | 
|  | 575 | } | 
|  | 576 |  | 
|  | 577 | ++i; | 
|  | 578 | } | 
|  | 579 | } | 
|  | 580 |  | 
|  | 581 | return false; | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | uint32_t Lock::generateTransactionId() | 
|  | 585 | { | 
|  | 586 | ++transactionId; | 
|  | 587 | return transactionId; | 
|  | 588 | } | 
|  | 589 |  | 
|  | 590 | } // namespace ibm_mc_lock | 
|  | 591 | } // namespace crow |