CorbaConnectionCacheBase.java revision 673:6b017d166ac2
1/*
2 * Copyright (c) 2001, 2010, 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 com.sun.corba.se.impl.transport;
27
28import java.util.Collection;
29import java.util.Iterator;
30
31import com.sun.corba.se.pept.broker.Broker;
32import com.sun.corba.se.pept.transport.Connection;
33import com.sun.corba.se.pept.transport.ConnectionCache;
34
35import com.sun.corba.se.spi.logging.CORBALogDomains;
36import com.sun.corba.se.spi.orb.ORB;
37import com.sun.corba.se.spi.transport.CorbaConnection;
38import com.sun.corba.se.spi.transport.CorbaConnectionCache;
39
40import com.sun.corba.se.impl.logging.ORBUtilSystemException;
41import com.sun.corba.se.impl.orbutil.ORBUtility;
42
43/**
44 * @author Harold Carr
45 */
46public abstract class CorbaConnectionCacheBase
47    implements
48        ConnectionCache,
49        CorbaConnectionCache
50{
51    protected ORB orb;
52    protected long timestamp = 0;
53    protected String cacheType;
54    protected String monitoringName;
55    protected ORBUtilSystemException wrapper;
56
57    protected CorbaConnectionCacheBase(ORB orb, String cacheType,
58                                       String monitoringName)
59    {
60        this.orb = orb;
61        this.cacheType = cacheType;
62        this.monitoringName = monitoringName;
63        wrapper =ORBUtilSystemException.get(orb,CORBALogDomains.RPC_TRANSPORT);
64        registerWithMonitoring();
65        dprintCreation();
66    }
67
68    ////////////////////////////////////////////////////
69    //
70    // pept.transport.ConnectionCache
71    //
72
73    public String getCacheType()
74    {
75        return cacheType;
76    }
77
78    public synchronized void stampTime(Connection c)
79    {
80        // _REVISIT_ Need to worry about wrap around some day
81        c.setTimeStamp(timestamp++);
82    }
83
84    public long numberOfConnections()
85    {
86        synchronized (backingStore()) {
87            return values().size();
88        }
89    }
90
91    public void close() {
92        synchronized (backingStore()) {
93            for (Object obj : values()) {
94                ((CorbaConnection)obj).closeConnectionResources() ;
95            }
96        }
97    }
98
99    public long numberOfIdleConnections()
100    {
101        long count = 0;
102        synchronized (backingStore()) {
103            Iterator connections = values().iterator();
104            while (connections.hasNext()) {
105                if (! ((Connection)connections.next()).isBusy()) {
106                    count++;
107                }
108            }
109        }
110        return count;
111    }
112
113    public long numberOfBusyConnections()
114    {
115        long count = 0;
116        synchronized (backingStore()) {
117            Iterator connections = values().iterator();
118            while (connections.hasNext()) {
119                if (((Connection)connections.next()).isBusy()) {
120                    count++;
121                }
122            }
123        }
124        return count;
125    }
126
127    /**
128     * Discarding least recently used Connections that are not busy
129     *
130     * This method must be synchronized since one WorkerThread could
131     * be reclaming connections inside the synchronized backingStore
132     * block and a second WorkerThread (or a SelectorThread) could have
133     * already executed the if (numberOfConnections {@literal <=} .... ). As a
134     * result the second thread would also attempt to reclaim connections.
135     *
136     * If connection reclamation becomes a performance issue, the connection
137     * reclamation could make its own task and consequently executed in
138     * a separate thread.
139     * Currently, the accept {@literal &} reclaim are done in the same thread, WorkerThread
140     * by default. It could be changed such that the SelectorThread would do
141     * it for SocketChannels and WorkerThreads for Sockets by updating the
142     * ParserTable.
143     */
144    synchronized public boolean reclaim()
145    {
146        try {
147            long numberOfConnections = numberOfConnections();
148
149            if (orb.transportDebugFlag) {
150                dprint(".reclaim->: " + numberOfConnections
151                        + " ("
152                        + orb.getORBData().getHighWaterMark()
153                        + "/"
154                        + orb.getORBData().getLowWaterMark()
155                        + "/"
156                        + orb.getORBData().getNumberToReclaim()
157                        + ")");
158            }
159
160            if (numberOfConnections <= orb.getORBData().getHighWaterMark() ||
161                numberOfConnections < orb.getORBData().getLowWaterMark()) {
162                return false;
163            }
164
165            Object backingStore = backingStore();
166            synchronized (backingStore) {
167
168                 // REVISIT - A less expensive alternative connection reclaiming
169                 //           algorithm could be investigated.
170
171                for (int i=0; i < orb.getORBData().getNumberToReclaim(); i++) {
172                    Connection toClose = null;
173                    long lru = java.lang.Long.MAX_VALUE;
174                    Iterator iterator = values().iterator();
175
176                    // Find least recently used and not busy connection in cache
177                    while ( iterator.hasNext() ) {
178                        Connection c = (Connection) iterator.next();
179                        if ( !c.isBusy() && c.getTimeStamp() < lru ) {
180                            toClose = c;
181                            lru = c.getTimeStamp();
182                        }
183                    }
184
185                    if ( toClose == null ) {
186                        return false;
187                    }
188
189                    try {
190                        if (orb.transportDebugFlag) {
191                            dprint(".reclaim: closing: " + toClose);
192                        }
193                        toClose.close();
194                    } catch (Exception ex) {
195                        // REVISIT - log
196                    }
197                }
198
199                if (orb.transportDebugFlag) {
200                    dprint(".reclaim: connections reclaimed ("
201                            + (numberOfConnections - numberOfConnections()) + ")");
202                }
203            }
204
205            // XXX is necessary to do a GC to reclaim
206            // closed network connections ??
207            // java.lang.System.gc();
208
209            return true;
210        } finally {
211            if (orb.transportDebugFlag) {
212                dprint(".reclaim<-: " + numberOfConnections());
213            }
214        }
215    }
216
217    ////////////////////////////////////////////////////
218    //
219    // spi.transport.ConnectionCache
220    //
221
222    public String getMonitoringName()
223    {
224        return monitoringName;
225    }
226
227    ////////////////////////////////////////////////////
228    //
229    // Implementation
230    //
231
232    // This is public so folb.Server test can access it.
233    public abstract Collection values();
234
235    protected abstract Object backingStore();
236
237    protected abstract void registerWithMonitoring();
238
239    protected void dprintCreation()
240    {
241        if (orb.transportDebugFlag) {
242            dprint(".constructor: cacheType: " + getCacheType()
243                   + " monitoringName: " + getMonitoringName());
244        }
245    }
246
247    protected void dprintStatistics()
248    {
249        if (orb.transportDebugFlag) {
250            dprint(".stats: "
251                   + numberOfConnections() + "/total "
252                   + numberOfBusyConnections() + "/busy "
253                   + numberOfIdleConnections() + "/idle"
254                   + " ("
255                   + orb.getORBData().getHighWaterMark() + "/"
256                   + orb.getORBData().getLowWaterMark() + "/"
257                   + orb.getORBData().getNumberToReclaim()
258                   + ")");
259        }
260    }
261
262    protected void dprint(String msg)
263    {
264        ORBUtility.dprint("CorbaConnectionCacheBase", msg);
265    }
266}
267
268// End of file.
269