author | prappo |
Fri, 01 Aug 2014 22:32:51 +0100 | |
changeset 25808 | e113d0a0fde0 |
parent 10324 | e28265130e4f |
permissions | -rw-r--r-- |
2 | 1 |
/* |
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
2 |
* Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
26 |
package com.sun.jndi.ldap.pool; |
|
27 |
||
28 |
import java.util.Map; |
|
29 |
import java.util.WeakHashMap; |
|
30 |
import java.util.Collection; |
|
31 |
import java.util.Collections; |
|
32 |
import java.util.Iterator; |
|
33 |
import java.util.LinkedList; |
|
34 |
||
35 |
import java.io.PrintStream; |
|
36 |
import java.lang.ref.Reference; |
|
37 |
import java.lang.ref.ReferenceQueue; |
|
38 |
import javax.naming.NamingException; |
|
39 |
||
40 |
/** |
|
41 |
* A map of pool ids to Connections. |
|
42 |
* Key is an object that uniquely identifies a PooledConnection request |
|
43 |
* (typically information needed to create the connection). |
|
44 |
* The definitions of the key's equals() and hashCode() methods are |
|
45 |
* vital to its unique identification in a Pool. |
|
46 |
* |
|
47 |
* Value is a ConnectionsRef, which is a reference to Connections, |
|
48 |
* a list of equivalent connections. |
|
49 |
* |
|
50 |
* Supports methods that |
|
51 |
* - retrieves (or creates as necessary) a connection from the pool |
|
52 |
* - removes expired connections from the pool |
|
53 |
* |
|
54 |
* Connections cleanup: |
|
55 |
* A WeakHashMap is used for mapping the pool ids and Connections. |
|
56 |
* A SoftReference from the value to the key is kept to hold the map |
|
57 |
* entry as long as possible. This allows the GC to remove Connections |
|
58 |
* from the Pool under situations of VM running out of resources. |
|
59 |
* To take an appropriate action of 'closing the connections' before the GC |
|
60 |
* reclaims the ConnectionsRef objects, the ConnectionsRef objects are made |
|
61 |
* weakly reachable through a list of weak references registered with |
|
62 |
* a reference queue. |
|
63 |
* Upon an entry gets removed from the WeakHashMap, the ConnectionsRef (value |
|
64 |
* in the map) object is weakly reachable. When another sweep of |
|
65 |
* clearing the weak references is made by the GC it puts the corresponding |
|
66 |
* ConnectionsWeakRef object into the reference queue. |
|
67 |
* The reference queue is monitored lazily for reclaimable Connections |
|
68 |
* whenever a pooled connection is requested or a call to remove the expired |
|
69 |
* connections is made. The monitoring is done regularly when idle connection |
|
70 |
* timeout is set as the PoolCleaner removes expired connections periodically. |
|
25808 | 71 |
* As determined by experimentation, cleanup of resources using the |
72 |
* ReferenceQueue mechanism is reliable and has more immediate effect than the |
|
2 | 73 |
* finalizer approach. |
74 |
* |
|
75 |
* @author Rosanna Lee |
|
76 |
*/ |
|
77 |
||
78 |
final public class Pool { |
|
79 |
||
80 |
static final boolean debug = com.sun.jndi.ldap.LdapPoolManager.debug; |
|
81 |
||
82 |
/* |
|
83 |
* Used for connections cleanup |
|
84 |
*/ |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
85 |
private static final ReferenceQueue<ConnectionsRef> queue = |
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
86 |
new ReferenceQueue<>(); |
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
87 |
private static final Collection<Reference<ConnectionsRef>> weakRefs = |
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
88 |
Collections.synchronizedList(new LinkedList<Reference<ConnectionsRef>>()); |
2 | 89 |
|
90 |
final private int maxSize; // max num of identical conn per pool |
|
91 |
final private int prefSize; // preferred num of identical conn per pool |
|
92 |
final private int initSize; // initial number of identical conn to create |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
93 |
final private Map<Object, ConnectionsRef> map; |
2 | 94 |
|
95 |
public Pool(int initSize, int prefSize, int maxSize) { |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
96 |
map = new WeakHashMap<>(); |
2 | 97 |
this.prefSize = prefSize; |
98 |
this.maxSize = maxSize; |
|
99 |
this.initSize = initSize; |
|
100 |
} |
|
101 |
||
102 |
/** |
|
103 |
* Gets a pooled connection for id. The pooled connection might be |
|
104 |
* newly created, as governed by the maxSize and prefSize settings. |
|
105 |
* If a pooled connection is unavailable and cannot be created due |
|
106 |
* to the maxSize constraint, this call blocks until the constraint |
|
107 |
* is removed or until 'timeout' ms has elapsed. |
|
108 |
* |
|
109 |
* @param id identity of the connection to get |
|
110 |
* @param timeout the number of milliseconds to wait before giving up |
|
111 |
* @param factory the factory to use for creating the connection if |
|
112 |
* creation is necessary |
|
113 |
* @return a pooled connection |
|
114 |
* @throws NamingException the connection could not be created due to |
|
115 |
* an error. |
|
116 |
*/ |
|
117 |
public PooledConnection getPooledConnection(Object id, long timeout, |
|
118 |
PooledConnectionFactory factory) throws NamingException { |
|
119 |
||
120 |
d("get(): ", id); |
|
121 |
d("size: ", map.size()); |
|
122 |
||
123 |
expungeStaleConnections(); |
|
124 |
||
125 |
Connections conns; |
|
126 |
synchronized (map) { |
|
127 |
conns = getConnections(id); |
|
128 |
if (conns == null) { |
|
129 |
d("get(): creating new connections list for ", id); |
|
130 |
||
131 |
// No connections for this id so create a new list |
|
132 |
conns = new Connections(id, initSize, prefSize, maxSize, |
|
133 |
factory); |
|
134 |
ConnectionsRef connsRef = new ConnectionsRef(conns); |
|
135 |
map.put(id, connsRef); |
|
136 |
||
137 |
// Create a weak reference to ConnectionsRef |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
138 |
Reference<ConnectionsRef> weakRef = |
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
139 |
new ConnectionsWeakRef(connsRef, queue); |
2 | 140 |
|
141 |
// Keep the weak reference through the element of a linked list |
|
142 |
weakRefs.add(weakRef); |
|
143 |
} |
|
144 |
} |
|
145 |
||
146 |
d("get(): size after: ", map.size()); |
|
147 |
||
148 |
return conns.get(timeout, factory); // get one connection from list |
|
149 |
} |
|
150 |
||
151 |
private Connections getConnections(Object id) { |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
152 |
ConnectionsRef ref = map.get(id); |
2 | 153 |
return (ref != null) ? ref.getConnections() : null; |
154 |
} |
|
155 |
||
156 |
/** |
|
157 |
* Goes through the connections in this Pool and expires ones that |
|
158 |
* have been idle before 'threshold'. An expired connection is closed |
|
159 |
* and then removed from the pool (removePooledConnection() will eventually |
|
160 |
* be called, and the list of pools itself removed if it becomes empty). |
|
161 |
* |
|
162 |
* @param threshold connections idle before 'threshold' should be closed |
|
163 |
* and removed. |
|
164 |
*/ |
|
165 |
public void expire(long threshold) { |
|
166 |
synchronized (map) { |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
167 |
Iterator<ConnectionsRef> iter = map.values().iterator(); |
2 | 168 |
Connections conns; |
169 |
while (iter.hasNext()) { |
|
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
170 |
conns = iter.next().getConnections(); |
2 | 171 |
if (conns.expire(threshold)) { |
172 |
d("expire(): removing ", conns); |
|
173 |
iter.remove(); |
|
174 |
} |
|
175 |
} |
|
176 |
} |
|
177 |
expungeStaleConnections(); |
|
178 |
} |
|
179 |
||
180 |
/* |
|
181 |
* Closes the connections contained in the ConnectionsRef object that |
|
182 |
* is going to be reclaimed by the GC. Called by getPooledConnection() |
|
183 |
* and expire() methods of this class. |
|
184 |
*/ |
|
185 |
private static void expungeStaleConnections() { |
|
186 |
ConnectionsWeakRef releaseRef = null; |
|
187 |
while ((releaseRef = (ConnectionsWeakRef) queue.poll()) |
|
188 |
!= null) { |
|
189 |
Connections conns = releaseRef.getConnections(); |
|
190 |
||
191 |
if (debug) { |
|
192 |
System.err.println( |
|
193 |
"weak reference cleanup: Closing Connections:" + conns); |
|
194 |
} |
|
195 |
||
196 |
// cleanup |
|
197 |
conns.close(); |
|
198 |
weakRefs.remove(releaseRef); |
|
199 |
releaseRef.clear(); |
|
200 |
} |
|
201 |
} |
|
202 |
||
203 |
||
204 |
public void showStats(PrintStream out) { |
|
205 |
Object id; |
|
206 |
Connections conns; |
|
207 |
||
208 |
out.println("===== Pool start ======================"); |
|
209 |
out.println("maximum pool size: " + maxSize); |
|
210 |
out.println("preferred pool size: " + prefSize); |
|
211 |
out.println("initial pool size: " + initSize); |
|
212 |
out.println("current pool size: " + map.size()); |
|
213 |
||
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
214 |
for (Map.Entry<Object, ConnectionsRef> entry : map.entrySet()) { |
2 | 215 |
id = entry.getKey(); |
10324
e28265130e4f
7072353: JNDI libraries do not build with javac -Xlint:all -Werror
jjg
parents:
5506
diff
changeset
|
216 |
conns = entry.getValue().getConnections(); |
2 | 217 |
out.println(" " + id + ":" + conns.getStats()); |
218 |
} |
|
219 |
||
220 |
out.println("====== Pool end ====================="); |
|
221 |
} |
|
222 |
||
223 |
public String toString() { |
|
224 |
return super.toString() + " " + map.toString(); |
|
225 |
} |
|
226 |
||
227 |
private void d(String msg, int i) { |
|
228 |
if (debug) { |
|
229 |
System.err.println(this + "." + msg + i); |
|
230 |
} |
|
231 |
} |
|
232 |
||
233 |
private void d(String msg, Object obj) { |
|
234 |
if (debug) { |
|
235 |
System.err.println(this + "." + msg + obj); |
|
236 |
} |
|
237 |
} |
|
238 |
} |