| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 | 
							- /*
 
-  * Copyright (c)2021 ZeroTier, Inc.
 
-  *
 
-  * Use of this software is governed by the Business Source License included
 
-  * in the LICENSE.TXT file in the project's root directory.
 
-  *
 
-  * Change Date: 2025-01-01
 
-  *
 
-  * On the date above, in accordance with the Business Source License, use
 
-  * of this software will be governed by version 2.0 of the Apache License.
 
-  */
 
- /****/
 
- #ifndef ZT_CONNECTION_POOL_H_
 
- #define ZT_CONNECTION_POOL_H_
 
- #ifndef _DEBUG
 
- 	#define _DEBUG(x)
 
- #endif
 
- #include "../node/Metrics.hpp"
 
- #include <deque>
 
- #include <set>
 
- #include <memory>
 
- #include <mutex>
 
- #include <exception>
 
- #include <string>
 
- namespace ZeroTier {
 
- struct ConnectionUnavailable : std::exception { 
 
-     char const* what() const throw() {
 
-         return "Unable to allocate connection";
 
-     }; 
 
- };
 
- class Connection {
 
- public:
 
-     virtual ~Connection() {};
 
- };
 
- class ConnectionFactory {
 
- public:
 
-     virtual ~ConnectionFactory() {};
 
-     virtual std::shared_ptr<Connection> create()=0;
 
- };
 
- struct ConnectionPoolStats {
 
-     size_t pool_size;
 
-     size_t borrowed_size;
 
- };
 
- template<class T>
 
- class ConnectionPool {
 
- public:
 
-     ConnectionPool(size_t max_pool_size, size_t min_pool_size, std::shared_ptr<ConnectionFactory> factory)
 
-         : m_maxPoolSize(max_pool_size)
 
-         , m_minPoolSize(min_pool_size)
 
-         , m_factory(factory)
 
-     {
 
-         Metrics::max_pool_size += max_pool_size;
 
-         Metrics::min_pool_size += min_pool_size;
 
-         while(m_pool.size() < m_minPoolSize){
 
-             m_pool.push_back(m_factory->create());
 
-             Metrics::pool_avail++;
 
-         }
 
-     };
 
-     ConnectionPoolStats get_stats() {
 
-         std::unique_lock<std::mutex> lock(m_poolMutex);
 
-         ConnectionPoolStats stats;
 
-         stats.pool_size = m_pool.size();
 
-         stats.borrowed_size = m_borrowed.size();			
 
-         return stats;
 
-     };
 
-     ~ConnectionPool() {
 
-     };
 
-     /**
 
-      * Borrow
 
-      *
 
-      * Borrow a connection for temporary use
 
-      *
 
-      * When done, either (a) call unborrow() to return it, or (b) (if it's bad) just let it go out of scope.  This will cause it to automatically be replaced.
 
-      * @retval a shared_ptr to the connection object
 
-      */
 
-     std::shared_ptr<T> borrow() {
 
-         std::unique_lock<std::mutex> l(m_poolMutex);
 
-         
 
-         while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
 
-             std::shared_ptr<Connection> conn = m_factory->create();
 
-             m_pool.push_back(conn);
 
-             Metrics::pool_avail++;
 
-         }
 
-         if(m_pool.size()==0){
 
-             
 
-             if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
 
-                 try {
 
-                     std::shared_ptr<Connection> conn = m_factory->create();
 
-                     m_borrowed.insert(conn);
 
-                     Metrics::pool_in_use++;
 
-                     return std::static_pointer_cast<T>(conn);
 
-                 } catch (std::exception &e) {
 
-                     Metrics::pool_errors++;
 
-                     throw ConnectionUnavailable();
 
-                 }
 
-             } else {
 
-                 for(auto it = m_borrowed.begin(); it != m_borrowed.end(); ++it){
 
-                     if((*it).unique()) {
 
-                         // This connection has been abandoned! Destroy it and create a new connection
 
-                         try {
 
-                             // If we are able to create a new connection, return it
 
-                             _DEBUG("Creating new connection to replace discarded connection");
 
-                             std::shared_ptr<Connection> conn = m_factory->create();
 
-                             m_borrowed.erase(it);
 
-                             m_borrowed.insert(conn);
 
-                             return std::static_pointer_cast<T>(conn);
 
-                         } catch(std::exception& e) {
 
-                             // Error creating a replacement connection
 
-                             Metrics::pool_errors++;
 
-                             throw ConnectionUnavailable();
 
-                         }
 
-                     }
 
-                 }
 
-                 // Nothing available
 
-                 Metrics::pool_errors++;
 
-                 throw ConnectionUnavailable();
 
-             }
 
-         }
 
-         // Take one off the front
 
-         std::shared_ptr<Connection> conn = m_pool.front();
 
-         m_pool.pop_front();
 
-         Metrics::pool_avail--;
 
-         // Add it to the borrowed list
 
-         m_borrowed.insert(conn);
 
-         Metrics::pool_in_use++;
 
-         return std::static_pointer_cast<T>(conn);
 
-     };
 
-     /**
 
-      * Unborrow a connection
 
-      *
 
-      * Only call this if you are returning a working connection.  If the connection was bad, just let it go out of scope (so the connection manager can replace it).
 
-      * @param the connection
 
-      */
 
-     void unborrow(std::shared_ptr<T> conn) {
 
-         // Lock
 
-         std::unique_lock<std::mutex> lock(m_poolMutex);
 
-         m_borrowed.erase(conn);
 
-         Metrics::pool_in_use--;
 
-         if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
 
-             Metrics::pool_avail++;
 
-             m_pool.push_back(conn);
 
-         }
 
-     };
 
- protected:
 
-     size_t m_maxPoolSize;
 
-     size_t m_minPoolSize;
 
-     std::shared_ptr<ConnectionFactory> m_factory;
 
-     std::deque<std::shared_ptr<Connection> > m_pool;
 
-     std::set<std::shared_ptr<Connection> > m_borrowed;
 
-     std::mutex m_poolMutex;
 
- };
 
- }
 
- #endif
 
 
  |