bool LockManager::acquireLock(const transaction_id tid, const ResourceId &rid, const AccessMode &access_mode) { std::stack<std::pair<ResourceId, AccessMode>> stack; ResourceId current_rid = rid; AccessMode current_access_mode = access_mode; stack.push(std::make_pair(current_rid, current_access_mode)); while (current_rid.hasParent()) { current_rid = current_rid.getParentResourceId(); current_access_mode = (current_access_mode.isShareLock() || current_access_mode.isIntentionShareLock()) ? AccessMode(AccessMode::IsLockMode()) : AccessMode(AccessMode::IxLockMode()); stack.push(std::make_pair(current_rid, current_access_mode)); } lock_table_->latchExclusive(); while (!stack.empty()) { const std::pair<ResourceId, AccessMode> pair_to_pick = stack.top(); const ResourceId rid_to_pick = pair_to_pick.first; const AccessMode access_mode_to_pick = pair_to_pick.second; if (!acquireLockInternal(tid, rid_to_pick, access_mode_to_pick)) { lock_table_->unlatchExclusive(); return false; } stack.pop(); } lock_table_->unlatchExclusive(); return true; }
TEST_F(LockTableTest, IncompatibleRequestsFromDifferentTransactions) { EXPECT_EQ(lock_table_.putLock(tid_1_, ResourceId(2), AccessMode(AccessModeType::kIsLock)), LockTableResult::kPLACED_IN_OWNED); // Acquire the same lock mode on same resource. EXPECT_EQ(lock_table_.putLock(tid_1_, ResourceId(2), AccessMode(AccessModeType::kIsLock)), LockTableResult::kALREADY_IN_OWNED); // Another transaction acquires incompatible lock on the same resource. EXPECT_EQ(lock_table_.putLock(tid_2_, ResourceId(2), AccessMode(AccessModeType::kXLock)), LockTableResult::kPLACED_IN_PENDING); }
TEST_F(LockTableTest, StarvationProtection) { EXPECT_EQ(lock_table_.putLock(tid_1_, ResourceId(2), AccessMode(AccessModeType::kIsLock)), LockTableResult::kPLACED_IN_OWNED); // Another transaction requests incompatible lock on the same resource. // It should wait for the previous transaction. EXPECT_EQ(lock_table_.putLock(tid_2_, ResourceId(2), AccessMode(AccessModeType::kXLock)), LockTableResult::kPLACED_IN_PENDING); // Another third transaction requests a compatible lock on the same resource. // Normally, it should acquire the lock, however, there is a pending // transaction waiting on the same resource. To prevent starvation, we should // put in the pending list. EXPECT_EQ(lock_table_.putLock(tid_3_, ResourceId(2), AccessMode(AccessModeType::kIsLock)), LockTableResult::kPLACED_IN_PENDING); }
/// \brief Read/Writes dataset's \p name attribute \p attrName to \p value template<class T> inline void attribute (const String name, const String attrName, T&& value) const noexcept { attribute_impl_(AccessMode(), name, attrName, std::forward<T>(value)); }
/** * @brief Factory method for SLockMode. * * @return SLockMode instance. **/ static AccessMode SLockMode() { return AccessMode(AccessModeType::kSLockMode); }
/** * @brief Factory method for IxLockMode. * * @return IxLockMode instance. **/ static AccessMode IxLockMode() { return AccessMode(AccessModeType::kIxLockMode); }
/** * @brief Factory method for NoLockMode. * * @return NoLockMode instance. **/ static AccessMode NoLockMode() { return AccessMode(AccessModeType::kNoLockMode); }