query/include/matador/sql/connection_pool.hpp

108 lines
2.6 KiB
C++

#ifndef QUERY_CONNECTION_POOL_HPP
#define QUERY_CONNECTION_POOL_HPP
#include <utility>
#include <queue>
#include <mutex>
#include <string>
#include <unordered_set>
namespace matador::sql {
template < class Connection >
class connection_pool;
template < class Connection >
class connection_ptr
{
public:
connection_ptr(Connection *c, connection_pool<Connection> &pool)
: connection_(c), pool_(pool) {}
~connection_ptr();
connection_ptr(const connection_ptr &) = delete;
connection_ptr& operator=(const connection_ptr &) = delete;
connection_ptr(connection_ptr &&) noexcept = default;
connection_ptr& operator=(connection_ptr &&) noexcept = default;
Connection* operator->() { return connection_; }
Connection& operator*() { return *connection_; }
[[nodiscard]] bool valid() const { return connection_ != nullptr; }
private:
friend class connection_pool<Connection>;
Connection *connection_;
connection_pool<Connection> &pool_;
};
template < class Connection >
class connection_pool
{
public:
connection_pool(const std::string &db, unsigned int count) {
connection_repo_.reserve(count);
for (auto i = 0U; i < count; ++i) {
connection_repo_.emplace_back(db + std::to_string(i+1));
idle_connections_.push(&connection_repo_.back());
idle_connections_.back()->open();
}
}
connection_ptr<Connection> acquire() {
std::lock_guard<std::mutex> guard(mutex_);
if (idle_connections_.empty()) {
return {nullptr, *this};
}
auto ptr = idle_connections_.front();
idle_connections_.pop();
inuse_connections_.insert(ptr);
return { ptr, *this };
}
void release(Connection *c) {
if (c == nullptr) {
return;
}
std::lock_guard<std::mutex> guard(mutex_);
if (inuse_connections_.erase(c) > 0) {
idle_connections_.push(c);
}
}
void release(connection_ptr<Connection> &c) {
release(c.connection_);
c.connection_ = nullptr;
}
std::size_t size() const { return connection_repo_.size(); }
std::size_t idle() const {
std::lock_guard<std::mutex> guard(mutex_);
return idle_connections_.size();
}
std::size_t inuse() const {
std::lock_guard<std::mutex> guard(mutex_);
return inuse_connections_.size();
}
private:
mutable std::mutex mutex_;
std::vector<Connection> connection_repo_;
using pointer = Connection*;
using connections = std::queue<pointer>;
using connection_set = std::unordered_set<pointer>;
connections idle_connections_;
connection_set inuse_connections_;
};
template<class Connection>
connection_ptr<Connection>::~connection_ptr() {
pool_.release(connection_);
}
}
#endif //QUERY_CONNECTION_POOL_HPP