diff --git a/include/sqlpp11/connection_pool.h b/include/sqlpp11/connection_pool.h new file mode 100644 index 00000000..72323d7b --- /dev/null +++ b/include/sqlpp11/connection_pool.h @@ -0,0 +1,137 @@ +#pragma once +#include +#include + +namespace sqlpp +{ + namespace mysql + { + template + class connection_pool + { + private: + std::mutex connection_pool_mutex; + const std::shared_ptr config; + + struct async_connection : Connection + { + async_connection(std::shared_ptr config) + : Connection(config) + {} + bool is_free = true; + }; + + std::vector connections; + + unsigned int default_pool_size = 0; + unsigned int current_pool_size = 0; + unsigned int max_pool_size = 0; + + void resize(unsigned int target_pool_size) + { + int lock = try_lock(connection_pool_mutex); + if (lock == -1) + { + throw sqlpp::exception("Connection_pool resize should not be called before locking."); + connection_pool_mutex.unlock(); + } + else + { + int diff = current_pool_size - target_pool_size; + if (!diff) + { + return; + } + + // does not guarantee to resize to target_pool_size + if (diff > 0) + { + for (auto it = connections.begin(); it != connections.end();) + { + if (diff && (*it).is_free) + { + it = connections.erase(it); + diff--; + } + else + { + ++it; + } + } + } + + if (diff < 0) + { + connections.reserve(target_pool_size); + for (int i = 0, count = -diff; i < count; i++) + { + try + { + connections.push_back(async_connection(config)); + diff++; + } + catch (const sqlpp::exception& e) + { + std::cerr << "Failed to spawn new connection." << std::endl; + std::cerr << e.what() << std::endl; + } + } + } + current_pool_size = target_pool_size + diff; + } + } + + public: + connection_pool(const std::shared_ptr& config, unsigned int pool_size) + : config(config), default_pool_size(pool_size) + { + std::lock_guard lock(connection_pool_mutex); + try + { + resize(pool_size); + } + catch (const sqlpp::exception& e) + { + std::cerr << "Failed to resize connection pool." << std::endl; + std::cerr << e.what() << std::endl; + } + } + ~connection_pool() = default; + connection_pool(const connection_pool&) = delete; + connection_pool(connection_pool&&) = delete; + connection_pool& operator=(const connection_pool&) = delete; + connection_pool& operator=(connection_pool&&) = delete; + + std::shared_ptr get_connection() + { + std::lock_guard lock(connection_pool_mutex); + for (auto& connection : connections) + { + if (connection.is_free) + { + connection.is_free = false; + return std::shared_ptr(static_cast(&connection)); + } + } + + try + { + resize(current_pool_size + 1); + } + catch (const sqlpp::exception& e) + { + std::cerr << "Failed to resize connection pool." << std::endl; + std::cerr << e.what() << std::endl; + } + + return std::shared_ptr(static_cast(&connections.back())); + } + + void free_connection(const std::shared_ptr& connection) + { + std::lock_guard lock(connection_pool_mutex); + static_cast(connection.get())->is_free = true; + } + }; + } +}