blob: aff5733fcd948091bcd1d06ee8ea024b49b9dad4 [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)
41 : this(processor, serverTransport,
42 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)
49 : this(processor, serverTransport,
50 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
56
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070057 public TThreadPoolServer(TProcessor processor,
58 TServerTransport serverTransport,
59 TTransportFactory transportFactory,
60 TProtocolFactory protocolFactory)
61 : this(processor, serverTransport,
62 transportFactory, transportFactory,
63 protocolFactory, protocolFactory,
64 DEFAULT_MIN_THREADS, DEFAULT_MAX_THREADS, DefaultLogDelegate)
65 {
66 }
David Reiss7f42bcf2008-01-11 20:59:12 +000067
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070068 public TThreadPoolServer(TProcessor processor,
69 TServerTransport serverTransport,
70 TTransportFactory inputTransportFactory,
71 TTransportFactory outputTransportFactory,
72 TProtocolFactory inputProtocolFactory,
73 TProtocolFactory outputProtocolFactory,
74 int minThreadPoolThreads, int maxThreadPoolThreads, LogDelegate logDel)
75 : base(processor, serverTransport, inputTransportFactory, outputTransportFactory,
76 inputProtocolFactory, outputProtocolFactory, logDel)
77 {
78 lock (typeof(TThreadPoolServer))
79 {
80 if (!ThreadPool.SetMaxThreads(maxThreadPoolThreads, maxThreadPoolThreads))
81 {
82 throw new Exception("Error: could not SetMaxThreads in ThreadPool");
83 }
84 if (!ThreadPool.SetMinThreads(minThreadPoolThreads, minThreadPoolThreads))
85 {
86 throw new Exception("Error: could not SetMinThreads in ThreadPool");
87 }
88 }
89 }
David Reiss7f42bcf2008-01-11 20:59:12 +000090
Roger Meierb1ec4cc2012-04-11 21:21:41 +000091
Randy Abernethy0e86f1f2014-07-13 09:50:19 -070092 /// <summary>
93 /// Use new ThreadPool thread for each new client connection
94 /// </summary>
95 public override void Serve()
96 {
97 try
98 {
99 serverTransport.Listen();
100 }
101 catch (TTransportException ttx)
102 {
103 logDelegate("Error, could not listen on ServerTransport: " + ttx);
104 return;
105 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000106
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700107 //Fire the preServe server event when server is up but before any client connections
108 if (serverEventHandler != null)
109 serverEventHandler.preServe();
David Reiss63191332009-01-06 19:49:22 +0000110
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700111 while (!stop)
112 {
113 int failureCount = 0;
114 try
115 {
116 TTransport client = serverTransport.Accept();
117 ThreadPool.QueueUserWorkItem(this.Execute, client);
118 }
119 catch (TTransportException ttx)
120 {
121 if (stop)
122 {
123 logDelegate("TThreadPoolServer was shutting down, caught " + ttx.GetType().Name);
124 }
125 else
126 {
127 ++failureCount;
128 logDelegate(ttx.ToString());
129 }
David Reissdc815f52008-03-02 00:58:04 +0000130
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700131 }
132 }
David Reissdc815f52008-03-02 00:58:04 +0000133
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700134 if (stop)
135 {
136 try
137 {
138 serverTransport.Close();
139 }
140 catch (TTransportException ttx)
141 {
142 logDelegate("TServerTransport failed on close: " + ttx.Message);
143 }
144 stop = false;
145 }
146 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000147
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700148 /// <summary>
149 /// Loops on processing a client forever
150 /// threadContext will be a TTransport instance
151 /// </summary>
152 /// <param name="threadContext"></param>
153 private void Execute(Object threadContext)
154 {
155 TTransport client = (TTransport)threadContext;
156 TTransport inputTransport = null;
157 TTransport outputTransport = null;
158 TProtocol inputProtocol = null;
159 TProtocol outputProtocol = null;
160 Object connectionContext = null;
161 try
162 {
163 inputTransport = inputTransportFactory.GetTransport(client);
164 outputTransport = outputTransportFactory.GetTransport(client);
165 inputProtocol = inputProtocolFactory.GetProtocol(inputTransport);
166 outputProtocol = outputProtocolFactory.GetProtocol(outputTransport);
David Reiss63191332009-01-06 19:49:22 +0000167
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700168 //Recover event handler (if any) and fire createContext server event when a client connects
169 if (serverEventHandler != null)
170 connectionContext = serverEventHandler.createContext(inputProtocol, outputProtocol);
171
172 //Process client requests until client disconnects
173 while (true)
174 {
Jens Geyerd5436f52014-10-03 19:50:38 +0200175 if (!inputTransport.Peek())
Jens Geyereb8e5ad2014-09-29 21:50:15 +0200176 break;
177
Randy Abernethy0e86f1f2014-07-13 09:50:19 -0700178 //Fire processContext server event
179 //N.B. This is the pattern implemented in C++ and the event fires provisionally.
180 //That is to say it may be many minutes between the event firing and the client request
181 //actually arriving or the client may hang up without ever makeing a request.
182 if (serverEventHandler != null)
183 serverEventHandler.processContext(connectionContext, inputTransport);
184 //Process client request (blocks until transport is readable)
185 if (!processor.Process(inputProtocol, outputProtocol))
186 break;
187 }
188 }
189 catch (TTransportException)
190 {
191 //Usually a client disconnect, expected
192 }
193 catch (Exception x)
194 {
195 //Unexpected
196 logDelegate("Error: " + x);
197 }
198
199 //Fire deleteContext server event after client disconnects
200 if (serverEventHandler != null)
201 serverEventHandler.deleteContext(connectionContext, inputProtocol, outputProtocol);
202
203 //Close transports
204 if (inputTransport != null)
205 inputTransport.Close();
206 if (outputTransport != null)
207 outputTransport.Close();
208 }
209
210 public override void Stop()
211 {
212 stop = true;
213 serverTransport.Close();
214 }
215 }
David Reiss7f42bcf2008-01-11 20:59:12 +0000216}