CorbaConnectionCacheBase.java revision 608:7e06bf1dcb09
168651Skris/*
268651Skris * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
368651Skris * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
468651Skris *
568651Skris * This code is free software; you can redistribute it and/or modify it
668651Skris * under the terms of the GNU General Public License version 2 only, as
768651Skris * published by the Free Software Foundation.  Oracle designates this
8280297Sjkim * particular file as subject to the "Classpath" exception as provided
968651Skris * by Oracle in the LICENSE file that accompanied this code.
1068651Skris *
1168651Skris * This code is distributed in the hope that it will be useful, but WITHOUT
1268651Skris * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1368651Skris * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1468651Skris * version 2 for more details (a copy is included in the LICENSE file that
15280297Sjkim * accompanied this code).
1668651Skris *
1768651Skris * You should have received a copy of the GNU General Public License version
1868651Skris * 2 along with this work; if not, write to the Free Software Foundation,
1968651Skris * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2068651Skris *
2168651Skris * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22280297Sjkim * or visit www.oracle.com if you need additional information or have any
2368651Skris * questions.
2468651Skris */
2568651Skris
2668651Skrispackage com.sun.corba.se.impl.transport;
2768651Skris
2868651Skrisimport java.util.Collection;
2968651Skrisimport java.util.Iterator;
3068651Skris
3168651Skrisimport com.sun.corba.se.pept.broker.Broker;
3268651Skrisimport com.sun.corba.se.pept.transport.Connection;
3368651Skrisimport com.sun.corba.se.pept.transport.ConnectionCache;
3468651Skris
3568651Skrisimport com.sun.corba.se.spi.logging.CORBALogDomains;
3668651Skrisimport com.sun.corba.se.spi.orb.ORB;
37280297Sjkimimport com.sun.corba.se.spi.transport.CorbaConnection;
3868651Skrisimport com.sun.corba.se.spi.transport.CorbaConnectionCache;
3968651Skris
40280297Sjkimimport com.sun.corba.se.impl.logging.ORBUtilSystemException;
4168651Skrisimport com.sun.corba.se.impl.orbutil.ORBUtility;
4268651Skris
4368651Skris/**
4468651Skris * @author Harold Carr
4568651Skris */
4668651Skrispublic abstract class CorbaConnectionCacheBase
4768651Skris    implements
4868651Skris        ConnectionCache,
4968651Skris        CorbaConnectionCache
5068651Skris{
5168651Skris    protected ORB orb;
52280297Sjkim    protected long timestamp = 0;
5368651Skris    protected String cacheType;
5468651Skris    protected String monitoringName;
5568651Skris    protected ORBUtilSystemException wrapper;
5668651Skris
5768651Skris    protected CorbaConnectionCacheBase(ORB orb, String cacheType,
5868651Skris                                       String monitoringName)
5968651Skris    {
6068651Skris        this.orb = orb;
6168651Skris        this.cacheType = cacheType;
62109998Smarkm        this.monitoringName = monitoringName;
6368651Skris        wrapper =ORBUtilSystemException.get(orb,CORBALogDomains.RPC_TRANSPORT);
6468651Skris        registerWithMonitoring();
65280297Sjkim        dprintCreation();
6668651Skris    }
6768651Skris
68160814Ssimon    ////////////////////////////////////////////////////
69280297Sjkim    //
70280297Sjkim    // pept.transport.ConnectionCache
71280297Sjkim    //
7268651Skris
73280297Sjkim    public String getCacheType()
74280297Sjkim    {
75280297Sjkim        return cacheType;
76280297Sjkim    }
7768651Skris
78280297Sjkim    public synchronized void stampTime(Connection c)
7968651Skris    {
80280297Sjkim        // _REVISIT_ Need to worry about wrap around some day
81280297Sjkim        c.setTimeStamp(timestamp++);
82280297Sjkim    }
8368651Skris
84280297Sjkim    public long numberOfConnections()
85280297Sjkim    {
86280297Sjkim        synchronized (backingStore()) {
87280297Sjkim            return values().size();
88280297Sjkim        }
89280297Sjkim    }
90280297Sjkim
91280297Sjkim    public void close() {
9268651Skris        synchronized (backingStore()) {
93280297Sjkim            for (Object obj : values()) {
94280297Sjkim                ((CorbaConnection)obj).closeConnectionResources() ;
95280297Sjkim            }
96280297Sjkim        }
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 <= .... ). 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 & 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