blob: a6592144b7f7a5f45fe2ae589eb69730fa0da25d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#include "transaction/DeadLockDetector.hpp"
#include <atomic>
#include <memory>
#include <vector>
#include "transaction/AccessMode.hpp"
#include "transaction/DirectedGraph.hpp"
#include "transaction/LockTable.hpp"
#include "transaction/ResourceId.hpp"
#include "transaction/Transaction.hpp"
#include "gtest/gtest.h"
namespace quickstep {
namespace transaction {
class DeadLockDetectorTest : public ::testing::Test {
protected:
DeadLockDetectorTest()
: lock_table_(std::make_unique<LockTable>()),
status_(DeadLockDetectorStatus::kDone) {
}
std::unique_ptr<LockTable> lock_table_;
std::atomic<DeadLockDetectorStatus> status_;
std::vector<DirectedGraph::node_id> victims_;
};
TEST_F(DeadLockDetectorTest, SimpleCycle) {
const transaction_id transaction_one(1), transaction_two(2);
const ResourceId resource_one(1, 2), resource_two(4, 5);
const AccessMode x_lock_mode(AccessMode::XLockMode());
// Produce a conflicting schedule.
// Transaction 1 will acquire X lock on resource 1.
lock_table_->putLock(transaction_one,
resource_one,
x_lock_mode);
// Transaction 2 will acquire X lock on resource 2.
lock_table_->putLock(transaction_two,
resource_two,
x_lock_mode);
// Transaction 1 will try to acquire X lock on resource 2,
// but it will fail since Transaction 2 has already acquired
// X lock on resource 2.
lock_table_->putLock(transaction_one,
resource_two,
x_lock_mode);
// Transaction 2 will try to acquire X lock on resource 1,
// but it will fail since Transaction 1 has already acquired
// X lock on resource 2.
lock_table_->putLock(transaction_two,
resource_one,
x_lock_mode);
// Run deadlock detector.
DeadLockDetector deadlock_detector(lock_table_.get(), &status_, &victims_);
status_.store(DeadLockDetectorStatus::kNotReady);
deadlock_detector.start();
// Signal deadlock detector.
while (status_.load() == DeadLockDetectorStatus::kNotReady) {
}
status_.store(DeadLockDetectorStatus::kQuit);
deadlock_detector.join();
// Victim size must be 1.
ASSERT_EQ(1u, victims_.size());
}
} // namespace transaction
} // namespace quickstep