copy wangle back into folly
[folly.git] / folly / wangle / acceptor / ConnectionManager.h
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #pragma once
18
19 #include <folly/wangle/acceptor/ManagedConnection.h>
20
21 #include <chrono>
22 #include <folly/Memory.h>
23 #include <folly/io/async/AsyncTimeout.h>
24 #include <folly/io/async/HHWheelTimer.h>
25 #include <folly/io/async/DelayedDestruction.h>
26 #include <folly/io/async/EventBase.h>
27
28 namespace folly { namespace wangle {
29
30 /**
31  * A ConnectionManager keeps track of ManagedConnections.
32  */
33 class ConnectionManager: public folly::DelayedDestruction,
34                          private ManagedConnection::Callback {
35  public:
36
37   /**
38    * Interface for an optional observer that's notified about
39    * various events in a ConnectionManager
40    */
41   class Callback {
42   public:
43     virtual ~Callback() {}
44
45     /**
46      * Invoked when the number of connections managed by the
47      * ConnectionManager changes from nonzero to zero.
48      */
49     virtual void onEmpty(const ConnectionManager& cm) = 0;
50
51     /**
52      * Invoked when a connection is added to the ConnectionManager.
53      */
54     virtual void onConnectionAdded(const ConnectionManager& cm) = 0;
55
56     /**
57      * Invoked when a connection is removed from the ConnectionManager.
58      */
59     virtual void onConnectionRemoved(const ConnectionManager& cm) = 0;
60   };
61
62   typedef std::unique_ptr<ConnectionManager, Destructor> UniquePtr;
63
64   /**
65    * Returns a new instance of ConnectionManager wrapped in a unique_ptr
66    */
67   template<typename... Args>
68   static UniquePtr makeUnique(Args&&... args) {
69     return folly::make_unique<ConnectionManager, Destructor>(
70       std::forward<Args>(args)...);
71   }
72
73   /**
74    * Constructor not to be used by itself.
75    */
76   ConnectionManager(folly::EventBase* eventBase,
77                     std::chrono::milliseconds timeout,
78                     Callback* callback = nullptr);
79
80   /**
81    * Add a connection to the set of connections managed by this
82    * ConnectionManager.
83    *
84    * @param connection     The connection to add.
85    * @param timeout        Whether to immediately register this connection
86    *                         for an idle timeout callback.
87    */
88   void addConnection(ManagedConnection* connection,
89       bool timeout = false);
90
91   /**
92    * Schedule a timeout callback for a connection.
93    */
94   void scheduleTimeout(ManagedConnection* const connection,
95                        std::chrono::milliseconds timeout);
96
97   /*
98    * Schedule a callback on the wheel timer
99    */
100   void scheduleTimeout(folly::HHWheelTimer::Callback* callback,
101                        std::chrono::milliseconds timeout);
102
103   /**
104    * Remove a connection from this ConnectionManager and, if
105    * applicable, cancel the pending timeout callback that the
106    * ConnectionManager has scheduled for the connection.
107    *
108    * @note This method does NOT destroy the connection.
109    */
110   void removeConnection(ManagedConnection* connection);
111
112   /* Begin gracefully shutting down connections in this ConnectionManager.
113    * Notify all connections of pending shutdown, and after idleGrace,
114    * begin closing idle connections.
115    */
116   void initiateGracefulShutdown(std::chrono::milliseconds idleGrace);
117
118   /**
119    * Destroy all connections Managed by this ConnectionManager, even
120    * the ones that are busy.
121    */
122   void dropAllConnections();
123
124   size_t getNumConnections() const { return conns_.size(); }
125
126   template <typename F>
127   void iterateConns(F func) {
128     auto it = conns_.begin();
129     while ( it != conns_.end()) {
130       func(&(*it));
131       it++;
132     }
133   }
134
135   std::chrono::milliseconds getDefaultTimeout() const {
136     return timeout_;
137   }
138
139   void setLoweredIdleTimeout(std::chrono::milliseconds timeout) {
140     CHECK(timeout >= std::chrono::milliseconds(0));
141     CHECK(timeout <= timeout_);
142     idleConnEarlyDropThreshold_ = timeout;
143   }
144
145   /**
146    * try to drop num idle connections to release system resources.  Return the
147    * actual number of dropped idle connections
148    */
149   size_t dropIdleConnections(size_t num);
150
151   /**
152    * ManagedConnection::Callbacks
153    */
154   void onActivated(ManagedConnection& conn);
155
156   void onDeactivated(ManagedConnection& conn);
157
158  private:
159   class CloseIdleConnsCallback :
160       public folly::EventBase::LoopCallback,
161       public folly::AsyncTimeout {
162    public:
163     explicit CloseIdleConnsCallback(ConnectionManager* manager)
164         : folly::AsyncTimeout(manager->eventBase_),
165           manager_(manager) {}
166
167     void runLoopCallback() noexcept override {
168       VLOG(3) << "Draining more conns from loop callback";
169       manager_->drainAllConnections();
170     }
171
172     void timeoutExpired() noexcept override {
173       VLOG(3) << "Idle grace expired";
174       manager_->drainAllConnections();
175     }
176
177    private:
178     ConnectionManager* manager_;
179   };
180
181   enum class ShutdownAction : uint8_t {
182     /**
183      * Drain part 1: inform remote that you will soon reject new requests.
184      */
185     DRAIN1 = 0,
186     /**
187      * Drain part 2: start rejecting new requests.
188      */
189     DRAIN2 = 1,
190   };
191
192   ~ConnectionManager() {}
193
194   ConnectionManager(const ConnectionManager&) = delete;
195   ConnectionManager& operator=(ConnectionManager&) = delete;
196
197   /**
198    * Destroy all connections managed by this ConnectionManager that
199    * are currently idle, as determined by a call to each ManagedConnection's
200    * isBusy() method.
201    */
202   void drainAllConnections();
203
204   /**
205    * All the managed connections. idleIterator_ seperates them into two parts:
206    * idle and busy ones.  [conns_.begin(), idleIterator_) are the busy ones,
207    * while [idleIterator_, conns_.end()) are the idle one. Moreover, the idle
208    * ones are organized in the decreasing idle time order. */
209   folly::CountedIntrusiveList<
210     ManagedConnection,&ManagedConnection::listHook_> conns_;
211
212   /** Connections that currently are registered for timeouts */
213   folly::HHWheelTimer::UniquePtr connTimeouts_;
214
215   /** Optional callback to notify of state changes */
216   Callback* callback_;
217
218   /** Event base in which we run */
219   folly::EventBase* eventBase_;
220
221   /** Iterator to the next connection to shed; used by drainAllConnections() */
222   folly::CountedIntrusiveList<
223     ManagedConnection,&ManagedConnection::listHook_>::iterator idleIterator_;
224   CloseIdleConnsCallback idleLoopCallback_;
225   ShutdownAction action_{ShutdownAction::DRAIN1};
226
227   /**
228    * the default idle timeout for downstream sessions when no system resource
229    * limit is reached
230    */
231   std::chrono::milliseconds timeout_;
232
233   /**
234    * The idle connections can be closed earlier that their idle timeout when any
235    * system resource limit is reached.  This feature can be considerred as a pre
236    * load shedding stage for the system, and can be easily disabled by setting
237    * idleConnEarlyDropThreshold_ to defaultIdleTimeout_. Also,
238    * idleConnEarlyDropThreshold_ can be used to bottom the idle timeout. That
239    * is, connection manager will not early drop the idle connections whose idle
240    * time is less than idleConnEarlyDropThreshold_.
241    */
242   std::chrono::milliseconds idleConnEarlyDropThreshold_;
243 };
244
245 }} // folly::wangle