History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/net/www/http/KeepAliveCache.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/net/www/http/KeepAliveCache.java+347−0
@@ -0,0 +1,347 @@
1/*
2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.net.www.http;
27
28import java.io.IOException;
29import java.io.NotSerializableException;
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.net.URL;
33
34/**
35 * A class that implements a cache of idle Http connections for keep-alive
36 *
37 * @author Stephen R. Pietrowicz (NCSA)
38 * @author Dave Brown
39 */
40public class KeepAliveCache
41 extends HashMap<KeepAliveKey, ClientVector>
42 implements Runnable {
43 private static final long serialVersionUID = -2937172892064557949L;
44
45 /* maximum # keep-alive connections to maintain at once
46 * This should be 2 by the HTTP spec, but because we don't support pipe-lining
47 * a larger value is more appropriate. So we now set a default of 5, and the value
48 * refers to the number of idle connections per destination (in the cache) only.
49 * It can be reset by setting system property "http.maxConnections".
50 */
51 static final int MAX_CONNECTIONS = 5;
52 static int result = -1;
53 static int getMaxConnections() {
54 if (result == -1) {
55 result = java.security.AccessController.doPrivileged(
56 new sun.security.action.GetIntegerAction("http.maxConnections",
57 MAX_CONNECTIONS))
58 .intValue();
59 if (result <= 0)
60 result = MAX_CONNECTIONS;
61 }
62 return result;
63 }
64
65 static final int LIFETIME = 5000;
66
67 private Thread keepAliveTimer = null;
68
69 /**
70 * Constructor
71 */
72 public KeepAliveCache() {}
73
74 /**
75 * Register this URL and HttpClient (that supports keep-alive) with the cache
76 * @param url The URL contains info about the host and port
77 * @param http The HttpClient to be cached
78 */
79 public synchronized void put(final URL url, Object obj, HttpClient http) {
80 boolean startThread = (keepAliveTimer == null);
81 if (!startThread) {
82 if (!keepAliveTimer.isAlive()) {
83 startThread = true;
84 }
85 }
86 if (startThread) {
87 clear();
88 /* Unfortunately, we can't always believe the keep-alive timeout we got
89 * back from the server. If I'm connected through a Netscape proxy
90 * to a server that sent me a keep-alive
91 * time of 15 sec, the proxy unilaterally terminates my connection
92 * The robustness to get around this is in HttpClient.parseHTTP()
93 */
94 final KeepAliveCache cache = this;
95 java.security.AccessController.doPrivileged(
96 new java.security.PrivilegedAction<Void>() {
97 public Void run() {
98 // We want to create the Keep-Alive-Timer in the
99 // system threadgroup
100 ThreadGroup grp = Thread.currentThread().getThreadGroup();
101 ThreadGroup parent = null;
102 while ((parent = grp.getParent()) != null) {
103 grp = parent;
104 }
105
106 keepAliveTimer = new Thread(grp, cache, "Keep-Alive-Timer");
107 keepAliveTimer.setDaemon(true);
108 keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2);
109 // Set the context class loader to null in order to avoid
110 // keeping a strong reference to an application classloader.
111 keepAliveTimer.setContextClassLoader(null);
112 keepAliveTimer.start();
113 return null;
114 }
115 });
116 }
117
118 KeepAliveKey key = new KeepAliveKey(url, obj);
119 ClientVector v = super.get(key);
120
121 if (v == null) {
122 int keepAliveTimeout = http.getKeepAliveTimeout();
123 v = new ClientVector(keepAliveTimeout > 0?
124 keepAliveTimeout*1000 : LIFETIME);
125 v.put(http);
126 super.put(key, v);
127 } else {
128 v.put(http);
129 }
130 }
131
132 /* remove an obsolete HttpClient from its VectorCache */
133 public synchronized void remove (HttpClient h, Object obj) {
134 KeepAliveKey key = new KeepAliveKey(h.url, obj);
135 ClientVector v = super.get(key);
136 if (v != null) {
137 v.remove(h);
138 if (v.empty()) {
139 removeVector(key);
140 }
141 }
142 }
143
144 /* called by a clientVector thread when all its connections have timed out
145 * and that vector of connections should be removed.
146 */
147 synchronized void removeVector(KeepAliveKey k) {
148 super.remove(k);
149 }
150
151 /**
152 * Check to see if this URL has a cached HttpClient
153 */
154 public synchronized HttpClient get(URL url, Object obj) {
155
156 KeepAliveKey key = new KeepAliveKey(url, obj);
157 ClientVector v = super.get(key);
158 if (v == null) { // nothing in cache yet
159 return null;
160 }
161 return v.get();
162 }
163
164 /* Sleeps for an alloted timeout, then checks for timed out connections.
165 * Errs on the side of caution (leave connections idle for a relatively
166 * short time).
167 */
168 @Override
169 public void run() {
170 do {
171 try {
172 Thread.sleep(LIFETIME);
173 } catch (InterruptedException e) {}
174 synchronized (this) {
175 /* Remove all unused HttpClients. Starting from the
176 * bottom of the stack (the least-recently used first).
177 * REMIND: It'd be nice to not remove *all* connections
178 * that aren't presently in use. One could have been added
179 * a second ago that's still perfectly valid, and we're
180 * needlessly axing it. But it's not clear how to do this
181 * cleanly, and doing it right may be more trouble than it's
182 * worth.
183 */
184
185 long currentTime = System.currentTimeMillis();
186
187 ArrayList<KeepAliveKey> keysToRemove
188 = new ArrayList<KeepAliveKey>();
189
190 for (KeepAliveKey key : keySet()) {
191 ClientVector v = get(key);
192 synchronized (v) {
193 int i;
194
195 for (i = 0; i < v.size(); i++) {
196 KeepAliveEntry e = v.elementAt(i);
197 if ((currentTime - e.idleStartTime) > v.nap) {
198 HttpClient h = e.hc;
199 h.closeServer();
200 } else {
201 break;
202 }
203 }
204 v.subList(0, i).clear();
205
206 if (v.size() == 0) {
207 keysToRemove.add(key);
208 }
209 }
210 }
211
212 for (KeepAliveKey key : keysToRemove) {
213 removeVector(key);
214 }
215 }
216 } while (size() > 0);
217
218 return;
219 }
220
221 /*
222 * Do not serialize this class!
223 */
224 private void writeObject(java.io.ObjectOutputStream stream)
225 throws IOException {
226 throw new NotSerializableException();
227 }
228
229 private void readObject(java.io.ObjectInputStream stream)
230 throws IOException, ClassNotFoundException {
231 throw new NotSerializableException();
232 }
233}
234
235/* FILO order for recycling HttpClients, should run in a thread
236 * to time them out. If > maxConns are in use, block.
237 */
238
239
240class ClientVector extends java.util.Stack<KeepAliveEntry> {
241 private static final long serialVersionUID = -8680532108106489459L;
242
243 // sleep time in milliseconds, before cache clear
244 int nap;
245
246
247
248 ClientVector (int nap) {
249 this.nap = nap;
250 }
251
252 synchronized HttpClient get() {
253 if (empty()) {
254 return null;
255 } else {
256 // Loop until we find a connection that has not timed out
257 HttpClient hc = null;
258 long currentTime = System.currentTimeMillis();
259 do {
260 KeepAliveEntry e = pop();
261 if ((currentTime - e.idleStartTime) > nap) {
262 e.hc.closeServer();
263 } else {
264 hc = e.hc;
265 }
266 } while ((hc== null) && (!empty()));
267 return hc;
268 }
269 }
270
271 /* return a still valid, unused HttpClient */
272 synchronized void put(HttpClient h) {
273 if (size() >= KeepAliveCache.getMaxConnections()) {
274 h.closeServer(); // otherwise the connection remains in limbo
275 } else {
276 push(new KeepAliveEntry(h, System.currentTimeMillis()));
277 }
278 }
279
280 /*
281 * Do not serialize this class!
282 */
283 private void writeObject(java.io.ObjectOutputStream stream)
284 throws IOException {
285 throw new NotSerializableException();
286 }
287
288 private void readObject(java.io.ObjectInputStream stream)
289 throws IOException, ClassNotFoundException {
290 throw new NotSerializableException();
291 }
292}
293
294
295class KeepAliveKey {
296 private String protocol = null;
297 private String host = null;
298 private int port = 0;
299 private Object obj = null; // additional key, such as socketfactory
300
301 /**
302 * Constructor
303 *
304 * @param url the URL containing the protocol, host and port information
305 */
306 public KeepAliveKey(URL url, Object obj) {
307 this.protocol = url.getProtocol();
308 this.host = url.getHost();
309 this.port = url.getPort();
310 this.obj = obj;
311 }
312
313 /**
314 * Determine whether or not two objects of this type are equal
315 */
316 @Override
317 public boolean equals(Object obj) {
318 if ((obj instanceof KeepAliveKey) == false)
319 return false;
320 KeepAliveKey kae = (KeepAliveKey)obj;
321 return host.equals(kae.host)
322 && (port == kae.port)
323 && protocol.equals(kae.protocol)
324 && this.obj == kae.obj;
325 }
326
327 /**
328 * The hashCode() for this object is the string hashCode() of
329 * concatenation of the protocol, host name and port.
330 */
331 @Override
332 public int hashCode() {
333 String str = protocol+host+port;
334 return this.obj == null? str.hashCode() :
335 str.hashCode() + this.obj.hashCode();
336 }
337}
338
339class KeepAliveEntry {
340 HttpClient hc;
341 long idleStartTime;
342
343 KeepAliveEntry(HttpClient hc, long idleStartTime) {
344 this.hc = hc;
345 this.idleStartTime = idleStartTime;
346 }
347}