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+
26+package sun.net.www.http;
27+
28+import java.io.IOException;
29+import java.io.NotSerializableException;
30+import java.util.ArrayList;
31+import java.util.HashMap;
32+import 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+ */
40+public 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+
240+class 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+
295+class 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+
339+class KeepAliveEntry {
340+ HttpClient hc;
341+ long idleStartTime;
342+
343+ KeepAliveEntry(HttpClient hc, long idleStartTime) {
344+ this.hc = hc;
345+ this.idleStartTime = idleStartTime;
346+ }
347+}