added multi threaded pool test
This commit is contained in:
parent
25bcc362f2
commit
b4765cac88
|
|
@ -12,7 +12,7 @@ list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(Catch)
|
include(Catch)
|
||||||
|
|
||||||
set(POSTGRES_CONNECTION_STRING "postgres://test:test123@127.0.0.1:5432/matador_test")
|
set(POSTGRES_CONNECTION_STRING "postgres://test:test123@127.0.0.1:15432/test")
|
||||||
|
|
||||||
configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE)
|
configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -86,19 +86,21 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_pointer acquire() {
|
connection_pointer acquire() {
|
||||||
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
|
while (idle_connections_.empty()) {
|
||||||
|
cv.wait(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_next_connection();
|
||||||
|
}
|
||||||
|
|
||||||
|
connection_pointer try_acquire() {
|
||||||
std::unique_lock<std::mutex> lock(mutex_);
|
std::unique_lock<std::mutex> lock(mutex_);
|
||||||
if (idle_connections_.empty()) {
|
if (idle_connections_.empty()) {
|
||||||
return {nullptr, this};
|
return {nullptr, this};
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer next_connection{nullptr};
|
return get_next_connection();
|
||||||
for (auto &item : idle_connections_) {
|
|
||||||
next_connection = item.second;
|
|
||||||
auto node = idle_connections_.extract(item.first);
|
|
||||||
inuse_connections_.insert(std::move(node));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return {next_connection, this};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connection_pointer acquire(size_t id) {
|
connection_pointer acquire(size_t id) {
|
||||||
|
|
@ -151,8 +153,21 @@ public:
|
||||||
const connection_info &info() const {
|
const connection_info &info() const {
|
||||||
return info_;
|
return info_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
connection_pointer get_next_connection() {
|
||||||
|
pointer next_connection{nullptr};
|
||||||
|
for (auto &item : idle_connections_) {
|
||||||
|
next_connection = item.second;
|
||||||
|
auto node = idle_connections_.extract(item.first);
|
||||||
|
inuse_connections_.insert(std::move(node));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return {next_connection, this};
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
mutable std::mutex mutex_;
|
mutable std::mutex mutex_;
|
||||||
|
std::condition_variable cv;
|
||||||
std::vector<IdConnection<Connection>> connection_repo_;
|
std::vector<IdConnection<Connection>> connection_repo_;
|
||||||
using pointer = IdConnection<Connection>*;
|
using pointer = IdConnection<Connection>*;
|
||||||
using connection_map = std::unordered_map<size_t, pointer>;
|
using connection_map = std::unordered_map<size_t, pointer>;
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,6 @@ add_executable(tests
|
||||||
models/location.hpp
|
models/location.hpp
|
||||||
models/optional.hpp
|
models/optional.hpp
|
||||||
ConvertTest.cpp
|
ConvertTest.cpp
|
||||||
DummyConnection.hpp
|
|
||||||
DummyConnection.cpp
|
|
||||||
EntityQueryBuilderTest.cpp
|
EntityQueryBuilderTest.cpp
|
||||||
models/author.hpp
|
models/author.hpp
|
||||||
models/book.hpp
|
models/book.hpp
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,42 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include <matador/sql/connection_pool.hpp>
|
#include <matador/sql/connection_pool.hpp>
|
||||||
|
#include <matador/sql/noop_connection.hpp>
|
||||||
|
|
||||||
#include "DummyConnection.hpp"
|
class AutoResetEvent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AutoResetEvent() : state(false) {}
|
||||||
|
AutoResetEvent(const AutoResetEvent& other) = delete;
|
||||||
|
|
||||||
|
void WaitOne() {
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
underlying.wait(lock, [this](){return state.load();});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set() {
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
state = true;
|
||||||
|
underlying.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reset() {
|
||||||
|
std::unique_lock<std::mutex> lock(sync);
|
||||||
|
state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::condition_variable underlying;
|
||||||
|
std::mutex sync;
|
||||||
|
std::atomic<bool> state;
|
||||||
|
};
|
||||||
|
|
||||||
using namespace matador::sql;
|
using namespace matador::sql;
|
||||||
|
|
||||||
TEST_CASE("Create connection pool", "[connection pool]") {
|
TEST_CASE("Create connection pool", "[connection pool]") {
|
||||||
using pool_t = connection_pool<matador::test::DummyConnection>;
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
pool_t pool("sqlite://sqlite.db", 4);
|
pool_t pool("noop://noop.db", 4);
|
||||||
|
|
||||||
REQUIRE(pool.size() == 4);
|
REQUIRE(pool.size() == 4);
|
||||||
REQUIRE(pool.idle() == 4);
|
REQUIRE(pool.idle() == 4);
|
||||||
|
|
@ -51,9 +78,9 @@ TEST_CASE("Create connection pool", "[connection pool]") {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Acquire connection by id", "[connection pool]") {
|
TEST_CASE("Acquire connection by id", "[connection pool]") {
|
||||||
using pool_t = connection_pool<matador::test::DummyConnection>;
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
pool_t pool("sqlite://sqlite.db", 4);
|
pool_t pool("noop://noop.db", 4);
|
||||||
|
|
||||||
REQUIRE(pool.size() == 4);
|
REQUIRE(pool.size() == 4);
|
||||||
REQUIRE(pool.idle() == 4);
|
REQUIRE(pool.idle() == 4);
|
||||||
|
|
@ -79,3 +106,74 @@ TEST_CASE("Acquire connection by id", "[connection pool]") {
|
||||||
REQUIRE(same_ptr.valid());
|
REQUIRE(same_ptr.valid());
|
||||||
REQUIRE(same_ptr.id() == connection_id);
|
REQUIRE(same_ptr.id() == connection_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Try acquire connection", "[connection pool][try acquire]") {
|
||||||
|
using pool_t = connection_pool<noop_connection>;
|
||||||
|
|
||||||
|
pool_t pool("noop://noop.db", 1);
|
||||||
|
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 1);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
auto ptr = pool.try_acquire();
|
||||||
|
REQUIRE(ptr.valid());
|
||||||
|
REQUIRE(ptr.id());
|
||||||
|
REQUIRE(ptr.id().value() > 0);
|
||||||
|
REQUIRE(ptr->is_open());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 0);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
|
||||||
|
auto ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(!ptr2.valid());
|
||||||
|
|
||||||
|
pool.release(ptr);
|
||||||
|
REQUIRE(!ptr.valid());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 1);
|
||||||
|
REQUIRE(pool.inuse() == 0);
|
||||||
|
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(ptr2.valid());
|
||||||
|
REQUIRE(ptr2.id());
|
||||||
|
REQUIRE(ptr2.id().value() > 0);
|
||||||
|
REQUIRE(ptr2->is_open());
|
||||||
|
REQUIRE(pool.size() == 1);
|
||||||
|
REQUIRE(pool.idle() == 0);
|
||||||
|
REQUIRE(pool.inuse() == 1);
|
||||||
|
|
||||||
|
pool.release(ptr2);
|
||||||
|
|
||||||
|
AutoResetEvent reset_event1;
|
||||||
|
AutoResetEvent reset_event2;
|
||||||
|
AutoResetEvent reset_event3;
|
||||||
|
|
||||||
|
std::thread t([&reset_event1, &reset_event2, &reset_event3, &pool]() {
|
||||||
|
auto c1 = pool.acquire();
|
||||||
|
REQUIRE(c1.valid());
|
||||||
|
REQUIRE(c1.id());
|
||||||
|
REQUIRE(c1.id().value() > 0);
|
||||||
|
|
||||||
|
reset_event1.Set();
|
||||||
|
|
||||||
|
reset_event2.WaitOne();
|
||||||
|
pool.release(c1);
|
||||||
|
REQUIRE(!c1.valid());
|
||||||
|
reset_event3.Set();
|
||||||
|
});
|
||||||
|
reset_event1.WaitOne();
|
||||||
|
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(!ptr2.valid());
|
||||||
|
|
||||||
|
reset_event2.Set();
|
||||||
|
|
||||||
|
reset_event3.WaitOne();
|
||||||
|
ptr2 = pool.try_acquire();
|
||||||
|
REQUIRE(ptr2.valid());
|
||||||
|
REQUIRE(ptr2.id());
|
||||||
|
REQUIRE(ptr2.id().value() > 0);
|
||||||
|
|
||||||
|
t.join();
|
||||||
|
}
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#include "DummyConnection.hpp"
|
|
||||||
|
|
||||||
namespace matador::test {
|
|
||||||
|
|
||||||
DummyConnection::DummyConnection(sql::connection_info info)
|
|
||||||
: connection_info_(std::move(info))
|
|
||||||
{}
|
|
||||||
|
|
||||||
DummyConnection::DummyConnection(const std::string &dns)
|
|
||||||
: DummyConnection(sql::connection_info::parse(dns))
|
|
||||||
{}
|
|
||||||
|
|
||||||
void DummyConnection::open()
|
|
||||||
{
|
|
||||||
is_open_ = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DummyConnection::close()
|
|
||||||
{
|
|
||||||
is_open_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DummyConnection::is_open() const
|
|
||||||
{
|
|
||||||
return is_open_;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
#ifndef QUERY_DUMMYCONNECTION_HPP
|
|
||||||
#define QUERY_DUMMYCONNECTION_HPP
|
|
||||||
|
|
||||||
#include "matador/sql/connection_info.hpp"
|
|
||||||
|
|
||||||
namespace matador::test {
|
|
||||||
|
|
||||||
class DummyConnection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DummyConnection(sql::connection_info info);
|
|
||||||
explicit DummyConnection(const std::string& dns);
|
|
||||||
DummyConnection(const DummyConnection &x) = default;
|
|
||||||
DummyConnection& operator=(const DummyConnection &x) = default;
|
|
||||||
DummyConnection(DummyConnection &&x) noexcept = default;
|
|
||||||
DummyConnection& operator=(DummyConnection &&x) noexcept = default;
|
|
||||||
~DummyConnection() = default;
|
|
||||||
|
|
||||||
void open();
|
|
||||||
void close();
|
|
||||||
[[nodiscard]] bool is_open() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
sql::connection_info connection_info_;
|
|
||||||
|
|
||||||
bool is_open_{};
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif //QUERY_DUMMYCONNECTION_HPP
|
|
||||||
Loading…
Reference in New Issue