Database System 0.1.0
Advanced C++20 Database System with Multi-Backend Support
Loading...
Searching...
No Matches
mock_connection_pool.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
5#pragma once
6
7#include "mock_database.h"
8#include <vector>
9#include <memory>
10#include <mutex>
11#include <condition_variable>
12#include <queue>
13#include <atomic>
14#include <chrono>
15
16namespace database::testing {
17
29public:
30 struct config {
31 size_t min_size = 2;
32 size_t max_size = 10;
33 std::chrono::milliseconds acquire_timeout{5000};
35 std::chrono::milliseconds slow_acquire_delay{100};
36 };
37
38 explicit mock_connection_pool(const config& cfg = {});
40
46
52 mock_database* acquire(std::chrono::milliseconds timeout);
53
58 void release(mock_database* conn);
59
72 stats get_stats() const;
73
78
82 void reset();
83
87 void configure_all(std::function<void(mock_database&)> configurator);
88
89private:
91 std::vector<std::unique_ptr<mock_database>> connections_;
92 std::queue<mock_database*> available_;
93 std::set<mock_database*> in_use_;
94 mutable std::mutex mutex_;
95 std::condition_variable cv_;
96 std::atomic<bool> exhausted_{false};
97
98 // Statistics
99 std::atomic<size_t> total_acquisitions_{0};
100 std::atomic<size_t> total_releases_{0};
101 std::atomic<size_t> acquisition_timeouts_{0};
102
103 void create_connection();
104};
105
111public:
113 : pool_(pool), conn_(pool.acquire())
114 {}
115
116 scoped_connection(mock_connection_pool& pool, std::chrono::milliseconds timeout)
117 : pool_(pool), conn_(pool.acquire(timeout))
118 {}
119
121 if (conn_) {
123 }
124 }
125
126 // Non-copyable
129
130 // Movable
132 : pool_(other.pool_), conn_(other.conn_)
133 {
134 other.conn_ = nullptr;
135 }
136
137 mock_database* get() { return conn_; }
140 explicit operator bool() const { return conn_ != nullptr; }
141
142private:
145};
146
147// Implementation
149 : config_(cfg)
150{
151 for (size_t i = 0; i < config_.min_size; ++i) {
153 }
154}
155
157
159 auto conn = std::make_unique<mock_database>();
160 available_.push(conn.get());
161 connections_.push_back(std::move(conn));
162}
163
167
168inline mock_database* mock_connection_pool::acquire(std::chrono::milliseconds timeout) {
169 std::unique_lock<std::mutex> lock(mutex_);
170
171 if (exhausted_) {
173 return nullptr;
174 }
175
176 // Wait for available connection or create new one
177 auto deadline = std::chrono::steady_clock::now() + timeout;
178 while (available_.empty()) {
179 if (connections_.size() < config_.max_size) {
181 break;
182 }
183
184 if (cv_.wait_until(lock, deadline) == std::cv_status::timeout) {
186 return nullptr;
187 }
188
189 if (exhausted_) {
191 return nullptr;
192 }
193 }
194
195 if (available_.empty()) {
197 return nullptr;
198 }
199
200 auto* conn = available_.front();
201 available_.pop();
202 in_use_.insert(conn);
204
205 // Simulate slow acquisition if configured
207 lock.unlock();
208 std::this_thread::sleep_for(config_.slow_acquire_delay);
209 }
210
211 return conn;
212}
213
215 std::lock_guard<std::mutex> lock(mutex_);
216 if (in_use_.erase(conn)) {
217 available_.push(conn);
219 cv_.notify_one();
220 }
221}
222
224 std::lock_guard<std::mutex> lock(mutex_);
225 return {
226 connections_.size(),
227 available_.size(),
228 in_use_.size(),
229 total_acquisitions_.load(),
230 total_releases_.load(),
233 };
234}
235
239
241 std::lock_guard<std::mutex> lock(mutex_);
242 exhausted_ = false;
243 // Return all in-use to available
244 for (auto* conn : in_use_) {
245 available_.push(conn);
246 }
247 in_use_.clear();
248}
249
250inline void mock_connection_pool::configure_all(std::function<void(mock_database&)> configurator) {
251 std::lock_guard<std::mutex> lock(mutex_);
252 for (auto& conn : connections_) {
253 configurator(*conn);
254 }
255}
256
257} // namespace database::testing
Mock connection pool for testing pool-related functionality.
mock_database * acquire()
Acquire a connection from the pool.
std::queue< mock_database * > available_
void release(mock_database *conn)
Release a connection back to the pool.
void simulate_exhaustion()
Simulate pool exhaustion.
std::vector< std::unique_ptr< mock_database > > connections_
void configure_all(std::function< void(mock_database &)> configurator)
Configure all connections with same expectation.
void reset()
Reset pool to normal operation.
Configurable mock for database_backend interface.
RAII wrapper for pool connections.
scoped_connection(mock_connection_pool &pool, std::chrono::milliseconds timeout)
scoped_connection(mock_connection_pool &pool)
scoped_connection & operator=(const scoped_connection &)=delete
scoped_connection(const scoped_connection &)=delete
scoped_connection(scoped_connection &&other) noexcept