1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
21 #define _THRIFT_SERVER_TTHREADEDSERVER_H_ 1
22 
23 #include <map>
24 #include <thrift/concurrency/Monitor.h>
25 #include <thrift/concurrency/ThreadFactory.h>
26 #include <thrift/concurrency/Thread.h>
27 #include <thrift/server/TServerFramework.h>
28 
29 namespace apache {
30 namespace thrift {
31 namespace server {
32 
33 /**
34  * Manage clients using threads - threads are created one for each client and are
35  * released when the client disconnects.  This server is used to make a dynamically
36  * scalable server up to the concurrent connection limit.
37  */
38 class TThreadedServer : public TServerFramework {
39 public:
40   TThreadedServer(
41       const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
42       const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
43       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
44       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
45       const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
46       = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
47           new apache::thrift::concurrency::ThreadFactory(false)));
48 
49   TThreadedServer(
50       const std::shared_ptr<apache::thrift::TProcessor>& processor,
51       const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
52       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& transportFactory,
53       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& protocolFactory,
54       const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
55       = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
56           new apache::thrift::concurrency::ThreadFactory(false)));
57 
58   TThreadedServer(
59       const std::shared_ptr<apache::thrift::TProcessorFactory>& processorFactory,
60       const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
61       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
62       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
63       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
64       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
65       const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
66       = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
67           new apache::thrift::concurrency::ThreadFactory(false)));
68 
69   TThreadedServer(
70       const std::shared_ptr<apache::thrift::TProcessor>& processor,
71       const std::shared_ptr<apache::thrift::transport::TServerTransport>& serverTransport,
72       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& inputTransportFactory,
73       const std::shared_ptr<apache::thrift::transport::TTransportFactory>& outputTransportFactory,
74       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& inputProtocolFactory,
75       const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>& outputProtocolFactory,
76       const std::shared_ptr<apache::thrift::concurrency::ThreadFactory>& threadFactory
77       = std::shared_ptr<apache::thrift::concurrency::ThreadFactory>(
78           new apache::thrift::concurrency::ThreadFactory(false)));
79 
80   ~TThreadedServer() override;
81 
82   /**
83    * Post-conditions (return guarantees):
84    *   There will be no clients connected.
85    */
86   void serve() override;
87 
88 protected:
89   /**
90    * Drain recently connected clients by joining their threads - this is done lazily because
91    * we cannot do it inside the thread context that is disconnecting.
92    */
93   virtual void drainDeadClients();
94 
95   /**
96    * Implementation of TServerFramework::onClientConnected
97    */
98   void onClientConnected(const std::shared_ptr<TConnectedClient>& pClient) override /* override */;
99 
100   /**
101    * Implementation of TServerFramework::onClientDisconnected
102    */
103   void onClientDisconnected(TConnectedClient *pClient) override /* override */;
104 
105   std::shared_ptr<apache::thrift::concurrency::ThreadFactory> threadFactory_;
106 
107   /**
108    * A helper wrapper used to wrap the client in something we can use to maintain
109    * the lifetime of the connected client within a detached thread.  We cannot simply
110    * track the threads because a shared_ptr<Thread> hangs on to the Runnable it is
111    * passed, and TServerFramework requires the runnable (TConnectedClient) to be
112    * destroyed in order to work properly.
113    */
114   class TConnectedClientRunner : public apache::thrift::concurrency::Runnable
115   {
116   public:
117     TConnectedClientRunner(const std::shared_ptr<TConnectedClient>& pClient);
118     ~TConnectedClientRunner() override;
119     void run() override /* override */;
120   private:
121     std::shared_ptr<TConnectedClient> pClient_;
122   };
123 
124   apache::thrift::concurrency::Monitor clientMonitor_;
125 
126   typedef std::map<TConnectedClient *, std::shared_ptr<apache::thrift::concurrency::Thread> > ClientMap;
127 
128   /**
129    * A map of active clients
130    */
131   ClientMap activeClientMap_;
132 
133   /**
134    * A map of clients that have disconnected but their threads have not been joined
135    */
136   ClientMap deadClientMap_;
137 };
138 
139 }
140 }
141 } // apache::thrift::server
142 
143 #endif // #ifndef _THRIFT_SERVER_TTHREADEDSERVER_H_
144