blob: 0010ecebc0b20cd2b4fe00998080db3a481898f3 [file] [log] [blame]
Kevin Clarkab4460d2009-03-20 02:28:41 +00001/**
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.
Todd Lipcon53ae9f32009-12-07 00:42:38 +000018 *
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
Kevin Clarkab4460d2009-03-20 02:28:41 +000022 */
23
David Reiss7f42bcf2008-01-11 20:59:12 +000024using System;
David Reiss7f42bcf2008-01-11 20:59:12 +000025using System.Threading;
26using Thrift.Protocol;
27using Thrift.Transport;
28
29namespace Thrift.Server
30{
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070031 /// <summary>
32 /// Server that uses C# built-in ThreadPool to spawn threads when handling requests
33 /// </summary>
34 public class TThreadPoolServer : TServer
35 {
36 private const int DEFAULT_MIN_THREADS = 10;
37 private const int DEFAULT_MAX_THREADS = 100;
38 private volatile bool stop = false;
David Reiss7f42bcf2008-01-11 20:59:12 +000039
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070040 public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport)
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000041 : this(new TSingletonProcessorFactory(processor), serverTransport,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070042 new TTransportFactory(), new TTransportFactory(),
43 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
44 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
45 {
46 }
David Reiss7f42bcf2008-01-11 20:59:12 +000047
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070048 public TThreadPoolServer(TProcessor processor, TServerTransport serverTransport, LogDelegate logDelegate)
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000049 : this(new TSingletonProcessorFactory(processor), serverTransport,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070050 new TTransportFactory(), new TTransportFactory(),
51 new TBinaryProtocol.Factory(), new TBinaryProtocol.Factory(),
52 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, logDelegate)
53 {
54 }
David Reiss63191332009-01-06 19:49:22 +000055
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070056 public TThreadPoolServer(TProcessor processor,
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000057 TServerTransport serverTransport,
58 TTransportFactory transportFactory,
59 TProtocolFactory protocolFactory)
60 : this(new TSingletonProcessorFactory(processor), serverTransport,
61 transportFactory, transportFactory,
62 protocolFactory, protocolFactory,
63 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
64 {
65 }
66
67 public TThreadPoolServer(TProcessorFactory processorFactory,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070068 TServerTransport serverTransport,
69 TTransportFactory transportFactory,
70 TProtocolFactory protocolFactory)
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000071 : this(processorFactory, serverTransport,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070072 transportFactory, transportFactory,
73 protocolFactory, protocolFactory,
74 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
75 {
76 }
David Reiss7f42bcf2008-01-11 20:59:12 +000077
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000078 public TThreadPoolServer(TProcessorFactory processorFactory,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070079 TServerTransport serverTransport,
80 TTransportFactory inputTransportFactory,
81 TTransportFactory outputTransportFactory,
82 TProtocolFactory inputProtocolFactory,
83 TProtocolFactory outputProtocolFactory,
84 int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
Jonathan Heard2bfd7df2015-10-28 17:34:27 +000085 : base(processorFactory, serverTransport, inputTransportFactory, outputTransportFactory,
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070086 inputProtocolFactory, outputProtocolFactory, logDel)
87 {
88 lock (typeof(TThreadPoolServer))
89 {
Jens Geyer224c3342017-05-06 22:38:43 +020090 if(maxThreadPoolThreads > 0)
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070091 {
Jens Geyer224c3342017-05-06 22:38:43 +020092 if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
93 {
94 throw new Exception("Error: could not SetMaxThreads in ThreadPool");
95 }
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070096 }
Jens Geyer224c3342017-05-06 22:38:43 +020097 if (minThreadPoolThreads > 0)
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070098 {
Jens Geyer224c3342017-05-06 22:38:43 +020099 if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
100 {
101 throw new Exception("Error: could not SetMinThreads in ThreadPool");
102 }
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700103 }
104 }
105 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000106
Roger Meierb1ec4cc2012-04-11 21:21:41 +0000107
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700108 /// <summary>
109 /// Use new ThreadPool thread for each new client connection
110 /// </summary>
111 public override void Serve()
112 {
113 try
114 {
115 serverTransport.Listen();
116 }
117 catch (TTransportException ttx)
118 {
119 logDelegate("Error, could not listen on ServerTransport: " + ttx);
120 return;
121 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000122
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700123 //Fire the preServe server event when server is up but before any client connections
124 if (serverEventHandler != null)
125 serverEventHandler.preServe();
David Reiss63191332009-01-06 19:49:22 +0000126
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700127 while (!stop)
128 {
129 int failureCount = 0;
130 try
131 {
132 TTransport client = serverTransport.Accept();
133 ThreadPool.QueueUserWorkItem(this.Execute, client);
134 }
135 catch (TTransportException ttx)
136 {
Jens Geyer7d882082015-01-27 22:08:44 +0100137 if (!stop || ttx.Type != TTransportException.ExceptionType.Interrupted)
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700138 {
139 ++failureCount;
140 logDelegate(ttx.ToString());
141 }
David Reissdc815f52008-03-02 00:58:04 +0000142
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700143 }
144 }
David Reissdc815f52008-03-02 00:58:04 +0000145
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700146 if (stop)
147 {
148 try
149 {
150 serverTransport.Close();
151 }
152 catch (TTransportException ttx)
153 {
154 logDelegate("TServerTransport failed on close: " + ttx.Message);
155 }
156 stop = false;
157 }
158 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000159
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700160 /// <summary>
161 /// Loops on processing a client forever
162 /// threadContext will be a TTransport instance
163 /// </summary>
164 /// <param name="threadContext"></param>
165 private void Execute(Object threadContext)
166 {
167 TTransport client = (TTransport)threadContext;
Jonathan Heard2bfd7df2015-10-28 17:34:27 +0000168 TProcessor processor = processorFactory.GetProcessor(client, this);
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700169 TTransport inputTransport = null;
170 TTransport outputTransport = null;
171 TProtocol inputProtocol = null;
172 TProtocol outputProtocol = null;
173 Object connectionContext = null;
174 try
175 {
176 inputTransport = inputTransportFactory.GetTransport(client);
177 outputTransport = outputTransportFactory.GetTransport(client);
178 inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
179 outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
David Reiss63191332009-01-06 19:49:22 +0000180
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700181 //Recover event handler (if any) and fire createContext server event when a client connects
182 if (serverEventHandler != null)
183 connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
184
185 //Process client requests until client disconnects
Jens Geyer7d882082015-01-27 22:08:44 +0100186 while (!stop)
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700187 {
Jens Geyerd5436f52014-10-03 19:50:38 +0200188 if (!inputTransport.Peek())
Jens Geyereb8e5ad2014-09-29 21:50:15 +0200189 break;
190
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700191 //Fire processContext server event
192 //N.B. This is the pattern implemented in C++ and the event fires provisionally.
193 //That is to say it may be many minutes between the event firing and the client request
194 //actually arriving or the client may hang up without ever makeing a request.
195 if (serverEventHandler != null)
196 serverEventHandler.processContext(connectionContext, inputTransport);
197 //Process client request (blocks until transport is readable)
198 if (!processor.Process(inputProtocol, outputProtocol))
199 break;
200 }
201 }
202 catch (TTransportException)
203 {
204 //Usually a client disconnect, expected
205 }
206 catch (Exception x)
207 {
208 //Unexpected
209 logDelegate("Error: " + x);
210 }
211
212 //Fire deleteContext server event after client disconnects
213 if (serverEventHandler != null)
214 serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
215
216 //Close transports
217 if (inputTransport != null)
218 inputTransport.Close();
219 if (outputTransport != null)
220 outputTransport.Close();
221 }
222
223 public override void Stop()
224 {
225 stop = true;
226 serverTransport.Close();
227 }
228 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000229}