1
#pragma once
2

            
3
#include <functional>
4
#include <vector>
5

            
6
#include "envoy/common/conn_pool.h"
7
#include "envoy/event/dispatcher.h"
8
#include "envoy/upstream/resource_manager.h"
9
#include "envoy/upstream/upstream.h"
10

            
11
#include "source/common/common/debug_recursion_checker.h"
12

            
13
#include "absl/container/flat_hash_map.h"
14
#include "absl/types/optional.h"
15

            
16
namespace Envoy {
17
namespace Upstream {
18
/**
19
 *  A class mapping keys to connection pools, with some recycling logic built in.
20
 */
21
template <typename KEY_TYPE, typename POOL_TYPE> class ConnPoolMap {
22
public:
23
  using PoolFactory = std::function<std::unique_ptr<POOL_TYPE>()>;
24
  using IdleCb = typename POOL_TYPE::IdleCb;
25
  using PoolOptRef = absl::optional<std::reference_wrapper<POOL_TYPE>>;
26

            
27
  ConnPoolMap(Event::Dispatcher& dispatcher, const HostConstSharedPtr& host,
28
              ResourcePriority priority);
29
  ~ConnPoolMap();
30
  /**
31
   * Returns an existing pool for `key`, or creates a new one using `factory`. Note that it is
32
   * possible for this to fail if a limit on the number of pools allowed is reached.
33
   * @return The pool corresponding to `key`, or `absl::nullopt`.
34
   */
35
  PoolOptRef getPool(const KEY_TYPE& key, const PoolFactory& factory);
36

            
37
  /**
38
   * Erases an existing pool mapped to `key`.
39
   *
40
   * @return true if the entry exists and was removed, false otherwise
41
   */
42
  bool erasePool(const KEY_TYPE& key);
43

            
44
  /**
45
   * @return the number of pools.
46
   */
47
  size_t size() const;
48

            
49
  /**
50
   * @return true if the pools are empty.
51
   */
52
  bool empty() const;
53

            
54
  /**
55
   * Destroys all mapped pools.
56
   */
57
  void clear();
58

            
59
  /**
60
   * Adds an idle callback to all mapped pools. Any future mapped pools with have the callback
61
   * automatically added. Be careful with the callback. If it itself calls into `this`, modifying
62
   * the state of `this`, there is a good chance it will cause corruption due to the callback firing
63
   * immediately.
64
   */
65
  void addIdleCallback(const IdleCb& cb);
66

            
67
  /**
68
   * See `Envoy::ConnectionPool::Instance::drainConnections()`.
69
   */
70
  void drainConnections(Envoy::ConnectionPool::DrainBehavior drain_behavior);
71

            
72
private:
73
  /**
74
   * Frees the first idle pool in `active_pools_`.
75
   * @return false if no pool was freed.
76
   */
77
  bool freeOnePool();
78

            
79
  /**
80
   * Cleans up the active_pools_ map and updates resource tracking
81
   **/
82
  void clearActivePools();
83

            
84
  absl::flat_hash_map<KEY_TYPE, std::unique_ptr<POOL_TYPE>> active_pools_;
85
  Event::Dispatcher& thread_local_dispatcher_;
86
  std::vector<IdleCb> cached_callbacks_;
87
  const HostConstSharedPtr host_;
88
  // Keep smaller fields near the end to reduce padding
89
  const ResourcePriority priority_;
90
  Common::DebugRecursionChecker recursion_checker_;
91
};
92

            
93
} // namespace Upstream
94
} // namespace Envoy