relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
postgresql_connection_pool.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <atomic>
6#include <chrono>
7#include <condition_variable>
8#include <format>
9#include <memory>
10#include <mutex>
11#include <optional>
12#include <queue>
13#include <string>
14#include <string_view>
15#include <vector>
16
17namespace relx::connection {
18
23
25 size_t initial_size = 5;
26
28 size_t max_size = 10;
29
31 std::chrono::milliseconds connection_timeout{5000};
32
35
37 std::chrono::milliseconds max_idle_time{60000};
38};
39
42 std::string message;
43 int error_code = 0;
44};
45
49inline std::string format_error(const ConnectionPoolError& error) {
50 return std::format("Connection pool error: {} (Code: {})", error.message, error.error_code);
51}
52
54template <typename T>
55using ConnectionPoolResult = std::expected<T, ConnectionPoolError>;
56
57// Forward declaration
59
61class PostgreSQLConnectionPool : public std::enable_shared_from_this<PostgreSQLConnectionPool> {
62private:
64 struct PoolEntry {
65 std::shared_ptr<PostgreSQLConnection> connection;
66 std::chrono::steady_clock::time_point last_used;
67 };
68
72
73public:
74 // Forward declaration of the connection wrapper class
75 class PooledConnection;
76
80
83 static std::shared_ptr<PostgreSQLConnectionPool> create(PostgreSQLConnectionPoolConfig config) {
84 // Use new directly instead of make_shared to access the private constructor
85 return std::shared_ptr<PostgreSQLConnectionPool>(
86 new PostgreSQLConnectionPool(std::move(config)));
87 }
88
91
92 // Delete copy and move operations
97
101
105
108 size_t active_connections() const;
109
112 size_t idle_connections() const;
113
118 template <typename Func>
119 [[nodiscard]] auto with_connection(Func&& func)
121 using ResultType = std::invoke_result_t<Func, PooledConnection&>;
122
123 auto conn_result = get_connection();
124 if (!conn_result) {
125 // Convert connection pool error to function result error
126 return std::unexpected(conn_result.error());
127 }
128
129 try {
130 // Execute the function with the connection by reference
131 if constexpr (std::is_same_v<ResultType, void>) {
132 func(*conn_result);
133 return {};
134 } else {
135 return func(*conn_result);
136 }
137 } catch (...) {
138 // Connection will be returned automatically by PooledConnection's destructor
139 throw; // Re-throw the exception
140 }
141 }
142
145 private:
146 std::shared_ptr<PostgreSQLConnection> connection_;
147 std::weak_ptr<PostgreSQLConnectionPool> pool_;
148
149 public:
153 PooledConnection(std::shared_ptr<PostgreSQLConnection> connection,
154 const std::shared_ptr<PostgreSQLConnectionPool>& pool)
155 : connection_(std::move(connection)), pool_(pool) {}
156
159 if (connection_) {
160 // Check if pool still exists
161 if (auto pool = pool_.lock()) {
162 pool->return_connection(std::move(connection_));
163 }
164 // If pool no longer exists, connection will simply be destroyed
165 }
166 }
167
168 // Delete copy operations
171
172 // Allow move operations
175
177 PostgreSQLConnection* operator->() { return connection_.get(); }
178
180 const PostgreSQLConnection* operator->() const { return connection_.get(); }
181
183 explicit operator bool() const { return connection_ != nullptr; }
184 };
185
186private:
188 std::atomic<size_t> active_connections_{0};
189 std::atomic<size_t> total_connections_{0};
190
191 mutable std::mutex pool_mutex_;
192 std::condition_variable conn_available_;
193 std::queue<PoolEntry> idle_connections_;
194
197 [[nodiscard]] ConnectionPoolResult<std::shared_ptr<PostgreSQLConnection>> get_raw_connection();
198
201 void return_connection(std::shared_ptr<PostgreSQLConnection> connection);
202
205 ConnectionPoolResult<std::shared_ptr<PostgreSQLConnection>> create_connection();
206
210 static bool validate_connection(const std::shared_ptr<PostgreSQLConnection>& connection);
211
213 void cleanup_idle_connections();
214};
215
216} // namespace relx::connection
A wrapper for a connection that automatically returns it to the pool.
PostgreSQLConnection * operator->()
Forward -> operator to the underlying connection.
PooledConnection(std::shared_ptr< PostgreSQLConnection > connection, const std::shared_ptr< PostgreSQLConnectionPool > &pool)
Constructor takes a connection and its parent pool.
PooledConnection & operator=(PooledConnection &&)=default
const PostgreSQLConnection * operator->() const
Forward const -> operator to the underlying connection.
PooledConnection & operator=(const PooledConnection &)=delete
~PooledConnection()
Destructor automatically returns connection to pool if available.
PostgreSQL connection pool that manages a collection of PostgreSQL connections.
PostgreSQLConnectionPool & operator=(const PostgreSQLConnectionPool &)=delete
ConnectionPoolResult< PooledConnection > get_connection()
Get a connection from the pool with automatic return when out of scope.
ConnectionPoolResult< void > initialize()
Initialize the connection pool.
auto with_connection(Func &&func) -> ConnectionPoolResult< std::invoke_result_t< Func, PooledConnection & > >
Execute a function with a connection from the pool.
size_t active_connections() const
Get the current number of active connections.
size_t idle_connections() const
Get the current number of idle connections.
PostgreSQLConnectionPool(const PostgreSQLConnectionPool &)=delete
PostgreSQLConnectionPool(PostgreSQLConnectionPool &&)=delete
~PostgreSQLConnectionPool()
Destructor that cleans up all connections.
static std::shared_ptr< PostgreSQLConnectionPool > create(PostgreSQLConnectionPoolConfig config)
Create a new connection pool.
PostgreSQLConnectionPool & operator=(PostgreSQLConnectionPool &&)=delete
PostgreSQL implementation of the Connection interface.
std::expected< T, ConnectionPoolError > ConnectionPoolResult
Type alias for result of connection pool operations.
std::string format_error(const ConnectionPoolError &error)
Format a ConnectionPoolError for exception messages.
STL namespace.
Error type for connection pool operations.
Basic parameters for a PostgreSQL connection.
Configuration for PostgreSQL connection pool.
bool validate_connections
Whether to validate connections before returning them.
PostgreSQLConnectionParams connection_params
Connection parameters for PostgreSQL.
std::chrono::milliseconds connection_timeout
Maximum time to wait for a connection before timeout (ms)
std::chrono::milliseconds max_idle_time
Maximum idle time before a connection is closed (ms)
size_t max_size
Maximum number of connections allowed.
size_t initial_size
Initial number of connections to create.