KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdbc > conn > PreparedStatementPool


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdbc.conn;
13
14 import java.sql.SQLException JavaDoc;
15 import java.util.Iterator JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Map JavaDoc;
18
19 import com.versant.core.common.Debug;
20 import com.versant.core.common.BindingSupportImpl;
21
22 /**
23  * Count limited LRU PreparedStatement pool for LoggingConnection.
24  */

25 public final class PreparedStatementPool {
26
27     private final LoggingConnection con;
28     private final HashMap JavaDoc keys = new HashMap JavaDoc(); // maps Key -> Key
29
private Key head; // most recently accessed Key
30
private Key tail; // least recently accessed Key
31
private int max;
32     private int numActive;
33     private int numIdle;
34
35     public PreparedStatementPool(LoggingConnection con, int max) {
36         this.con = con;
37         this.max = max;
38     }
39
40     public LoggingConnection getCon() {
41         return con;
42     }
43
44     public int getMax() {
45         return max;
46     }
47
48     /**
49      * Get the total number of PS currently idle in the pool.
50      */

51     public int getNumIdle() {
52         return numIdle;
53     }
54
55     /**
56      * Get the number of active PS outside of the pool.
57      */

58     public int getNumActive() {
59         return numActive;
60     }
61
62     /**
63      * Get the total number of PS (numActive + numIdle).
64      */

65     public int getSize() {
66         return numIdle + numActive;
67     }
68
69     /**
70      * Borrow a PS from the pool. This will create one if none are available.
71      * If this pushes the total number of PSes over max then idle PS'es are
72      * closed as needed.
73      */

74     public PooledPreparedStatement borrowPS(Key pkey) throws SQLException JavaDoc {
75         Key key = (Key)keys.get(pkey);
76         if (key == null) {
77             keys.put(key = pkey, pkey);
78         } else {
79             removeFromLRUList(key);
80         }
81         addToHeadOfLRUList(key);
82         PooledPreparedStatement ps = key.removePsFromList();
83         if (ps == null) {
84             ps = con.prepareStatementImp(key.getSql(), key.getResultSetType(),
85                     key.getResultSetConcurrency(), key);
86         } else {
87             --numIdle;
88         }
89         ++key.activeCount;
90         ++numActive;
91         if (max > 0) {
92             closeExcessStatements();
93         }
94         if (Debug.DEBUG) {
95             check();
96         }
97         return ps;
98     }
99
100     /**
101      * Return a PS to the pool.
102      */

103     public void returnPS(PooledPreparedStatement ps) {
104         Key key = ps.getKey();
105         key.addPsToList(ps);
106         --key.activeCount;
107         ++numIdle;
108         --numActive;
109         if (max > 0) {
110             closeExcessStatements();
111         }
112         if (Debug.DEBUG) {
113             check();
114         }
115     }
116
117     private void closeExcessStatements() {
118         int toClose = (numActive + numIdle) - max;
119         if (toClose > numIdle) {
120             toClose = numIdle;
121         }
122         for (Key key = tail; toClose > 0; ) {
123             for (;;) {
124                 PooledPreparedStatement ps = key.removePsFromList();
125                 if (ps == null) {
126                     break;
127                 }
128                 try {
129                     ps.closeRealStatement();
130                 } catch (SQLException JavaDoc e) {
131                     // ignore
132
}
133                 --numIdle;
134                 if (--toClose == 0) {
135                     break;
136                 }
137             }
138             if (key.psList == null) {
139                 if (key.activeCount == 0) {
140                     Key next = key.next;
141                     removeFromLRUList(key);
142                     keys.remove(key);
143                     key = next;
144                 } else {
145                     key = key.next;
146                 }
147             }
148         }
149         if (Debug.DEBUG) {
150             check();
151         }
152     }
153
154     private void check() {
155         try {
156             // count the number of idle PS'es
157
int c = 0;
158             for (Iterator JavaDoc i = keys.keySet().iterator(); i.hasNext(); ) {
159                 Key key = (Key)i.next();
160                 for (PooledPreparedStatement ps = key.psList; ps != null; ++c) {
161                     if (ps == ps.next) {
162                         throw BindingSupportImpl.getInstance().internal(
163                                 "ps == ps.next for key " + key);
164                     }
165                     ps = ps.next;
166                 }
167             }
168             if (numIdle != c) {
169                 throw BindingSupportImpl.getInstance().internal("numIdle is " +
170                         numIdle + " but there are " + c + " idle PS'es in map");
171             }
172             // walk the LRU list checking the links, detected dups and making
173
// sure all entries are in the map and that the map has no extra
174
// entries
175
c = 0;
176             int totActive = 0;
177             Map JavaDoc dupMap = new HashMap JavaDoc();
178             for (Key key = tail; key != null; key = key.next, ++c) {
179                 if (key.next != null) {
180                     if (key.next.prev != key) {
181                         throw BindingSupportImpl.getInstance().internal(
182                                 "key.next.prev != key");
183                     }
184                 }
185                 Key pkey = (Key)dupMap.get(key);
186                 if (pkey != null) {
187                     throw BindingSupportImpl.getInstance().internal(
188                             "Dup key in LRU list: " + pkey);
189                 }
190                 dupMap.put(key, key);
191                 if (!keys.containsKey(key)) {
192                     throw BindingSupportImpl.getInstance().internal(
193                             "Key in LRU list not in map: " + key);
194                 }
195                 totActive += key.activeCount;
196             }
197             if (c != keys.size()) {
198                 throw BindingSupportImpl.getInstance().internal(
199                         "There are " + c + " keys in the LRU list and " +
200                         keys.size() + " in the keys map");
201             }
202             if (numActive != totActive) {
203                 throw BindingSupportImpl.getInstance().internal("numActive is " +
204                         numIdle + " but there are " + c + " active PS'es in keys");
205             }
206         } catch (RuntimeException JavaDoc e) {
207             System.out.println("PreparedStatementPool check failed: " + e);
208             dump();
209             e.printStackTrace(System.out);
210             throw e;
211         }
212     }
213
214     /**
215      * Remove key from the double linked LRU list.
216      */

217     private void removeFromLRUList(Key key) {
218         if (key.prev != null) {
219             key.prev.next = key.next;
220         } else {
221             tail = key.next;
222         }
223         if (key.next != null) {
224             key.next.prev = key.prev;
225         } else {
226             head = key.prev;
227         }
228     }
229
230     /**
231      * Add key to the head of the double linked LRU list. This will make it
232      * the most recently accessed object.
233      */

234     private void addToHeadOfLRUList(Key key) {
235         key.next = null;
236         key.prev = head;
237         if (head != null) head.next = key;
238         head = key;
239         if (tail == null) tail = key;
240     }
241
242     /**
243      * Dump the contents of the pool.
244      */

245     public void dump() {
246         if (Debug.DEBUG) {
247             System.out.println("=== keys ===");
248             for (Iterator JavaDoc i = keys.keySet().iterator(); i.hasNext(); ) {
249                 Key key = (Key)i.next();
250                 System.out.println(key.toDumpString());
251             }
252             System.out.println("=== LRU list ===");
253             for (Key key = tail; key != null; key = key.next) {
254                 System.out.println(key);
255             }
256             System.out.println("---");
257         }
258     }
259
260     /**
261      * This is the key for this pool. These are linked together when in the
262      * pool to form a double linked list used for LRU evictions. Each
263      * maintains a single linked list of PooledPreparedStatement's.
264      */

265     public static final class Key {
266
267         private final String JavaDoc sql;
268         private final int resultSetType;
269         private final int resultSetConcurrency;
270
271         private PooledPreparedStatement psList;
272         private int activeCount;
273         private Key prev;
274         private Key next;
275
276         public Key(String JavaDoc sql, int resultSetType, int resultSetConcurrency) {
277             if (sql == null) {
278                 throw new NullPointerException JavaDoc("sql is null");
279             }
280             this.sql = sql;
281             this.resultSetType = resultSetType;
282             this.resultSetConcurrency = resultSetConcurrency;
283         }
284
285         public Key(String JavaDoc sql) {
286             if (sql == null) {
287                 throw new NullPointerException JavaDoc("sql is null");
288             }
289             this.sql = sql;
290             resultSetType = 0;
291             resultSetConcurrency = 0;
292         }
293
294         public String JavaDoc getSql() {
295             return sql;
296         }
297
298         public int getResultSetType() {
299             return resultSetType;
300         }
301
302         public int getResultSetConcurrency() {
303             return resultSetConcurrency;
304         }
305
306         public boolean equals(Object JavaDoc o) {
307             if (!(o instanceof Key)) return false;
308             final Key psKey = (Key)o;
309             return resultSetConcurrency == psKey.resultSetConcurrency
310                 && resultSetType == psKey.resultSetType
311                 && sql.equals(psKey.sql);
312         }
313
314         public int hashCode() {
315             return sql.hashCode() + resultSetType + resultSetConcurrency;
316         }
317
318         public String JavaDoc toString() {
319             StringBuffer JavaDoc s = new StringBuffer JavaDoc();
320             s.append(Integer.toHexString(sql.hashCode()));
321             for (int i = 9 - s.length(); i > 0; i--) {
322                 s.append(' ');
323             }
324             if (sql.length() > 40) {
325                 s.append(sql.substring(0, 37));
326                 s.append("...");
327             } else {
328                 s.append(sql);
329             }
330             return s.toString();
331         }
332
333         public String JavaDoc toDumpString() {
334             StringBuffer JavaDoc s = new StringBuffer JavaDoc();
335             s.append(toString());
336             for (PooledPreparedStatement ps = psList; ps != null; ) {
337                 s.append(" -> ");
338                 s.append(ps);
339                 if (ps == ps.next) {
340                     s.append("*** LOOP ps == ps.next ***");
341                     break;
342                 }
343                 ps = ps.next;
344             }
345             return s.toString();
346         }
347
348         /**
349          * Do we have no PS'es?
350          */

351         public boolean isPsListEmpty() {
352             return psList == null;
353         }
354
355         /**
356          * Remove the first PS from our list and return it or null if none
357          * are available.
358          */

359         public PooledPreparedStatement removePsFromList() {
360             if (psList == null) {
361                 return null;
362             }
363             PooledPreparedStatement ps = psList;
364             psList = ps.next;
365             ps.next = null;
366             return ps;
367         }
368
369         /**
370          * Add ps to our list.
371          */

372         public void addPsToList(PooledPreparedStatement ps) {
373             ps.next = psList;
374             psList = ps;
375         }
376     }
377
378  }
379
Popular Tags