| /* |
| * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.corba.se.impl.transport; |
| |
| import java.util.Collection; |
| import java.util.Iterator; |
| |
| import com.sun.corba.se.pept.broker.Broker; |
| import com.sun.corba.se.pept.transport.Connection; |
| import com.sun.corba.se.pept.transport.ConnectionCache; |
| |
| import com.sun.corba.se.spi.logging.CORBALogDomains; |
| import com.sun.corba.se.spi.orb.ORB; |
| import com.sun.corba.se.spi.transport.CorbaConnection; |
| import com.sun.corba.se.spi.transport.CorbaConnectionCache; |
| |
| import com.sun.corba.se.impl.logging.ORBUtilSystemException; |
| import com.sun.corba.se.impl.orbutil.ORBUtility; |
| |
| /** |
| * @author Harold Carr |
| */ |
| public abstract class CorbaConnectionCacheBase |
| implements |
| ConnectionCache, |
| CorbaConnectionCache |
| { |
| protected ORB orb; |
| protected long timestamp = 0; |
| protected String cacheType; |
| protected String monitoringName; |
| protected ORBUtilSystemException wrapper; |
| |
| protected CorbaConnectionCacheBase(ORB orb, String cacheType, |
| String monitoringName) |
| { |
| this.orb = orb; |
| this.cacheType = cacheType; |
| this.monitoringName = monitoringName; |
| wrapper =ORBUtilSystemException.get(orb,CORBALogDomains.RPC_TRANSPORT); |
| registerWithMonitoring(); |
| dprintCreation(); |
| } |
| |
| //////////////////////////////////////////////////// |
| // |
| // pept.transport.ConnectionCache |
| // |
| |
| public String getCacheType() |
| { |
| return cacheType; |
| } |
| |
| public synchronized void stampTime(Connection c) |
| { |
| // _REVISIT_ Need to worry about wrap around some day |
| c.setTimeStamp(timestamp++); |
| } |
| |
| public long numberOfConnections() |
| { |
| synchronized (backingStore()) { |
| return values().size(); |
| } |
| } |
| |
| public void close() { |
| synchronized (backingStore()) { |
| for (Object obj : values()) { |
| ((CorbaConnection)obj).closeConnectionResources() ; |
| } |
| } |
| } |
| |
| public long numberOfIdleConnections() |
| { |
| long count = 0; |
| synchronized (backingStore()) { |
| Iterator connections = values().iterator(); |
| while (connections.hasNext()) { |
| if (! ((Connection)connections.next()).isBusy()) { |
| count++; |
| } |
| } |
| } |
| return count; |
| } |
| |
| public long numberOfBusyConnections() |
| { |
| long count = 0; |
| synchronized (backingStore()) { |
| Iterator connections = values().iterator(); |
| while (connections.hasNext()) { |
| if (((Connection)connections.next()).isBusy()) { |
| count++; |
| } |
| } |
| } |
| return count; |
| } |
| |
| /** |
| * Discarding least recently used Connections that are not busy |
| * |
| * This method must be synchronized since one WorkerThread could |
| * be reclaming connections inside the synchronized backingStore |
| * block and a second WorkerThread (or a SelectorThread) could have |
| * already executed the if (numberOfConnections <= .... ). As a |
| * result the second thread would also attempt to reclaim connections. |
| * |
| * If connection reclamation becomes a performance issue, the connection |
| * reclamation could make its own task and consequently executed in |
| * a separate thread. |
| * Currently, the accept & reclaim are done in the same thread, WorkerThread |
| * by default. It could be changed such that the SelectorThread would do |
| * it for SocketChannels and WorkerThreads for Sockets by updating the |
| * ParserTable. |
| */ |
| synchronized public boolean reclaim() |
| { |
| try { |
| long numberOfConnections = numberOfConnections(); |
| |
| if (orb.transportDebugFlag) { |
| dprint(".reclaim->: " + numberOfConnections |
| + " (" |
| + orb.getORBData().getHighWaterMark() |
| + "/" |
| + orb.getORBData().getLowWaterMark() |
| + "/" |
| + orb.getORBData().getNumberToReclaim() |
| + ")"); |
| } |
| |
| if (numberOfConnections <= orb.getORBData().getHighWaterMark() || |
| numberOfConnections < orb.getORBData().getLowWaterMark()) { |
| return false; |
| } |
| |
| Object backingStore = backingStore(); |
| synchronized (backingStore) { |
| |
| // REVISIT - A less expensive alternative connection reclaiming |
| // algorithm could be investigated. |
| |
| for (int i=0; i < orb.getORBData().getNumberToReclaim(); i++) { |
| Connection toClose = null; |
| long lru = java.lang.Long.MAX_VALUE; |
| Iterator iterator = values().iterator(); |
| |
| // Find least recently used and not busy connection in cache |
| while ( iterator.hasNext() ) { |
| Connection c = (Connection) iterator.next(); |
| if ( !c.isBusy() && c.getTimeStamp() < lru ) { |
| toClose = c; |
| lru = c.getTimeStamp(); |
| } |
| } |
| |
| if ( toClose == null ) { |
| return false; |
| } |
| |
| try { |
| if (orb.transportDebugFlag) { |
| dprint(".reclaim: closing: " + toClose); |
| } |
| toClose.close(); |
| } catch (Exception ex) { |
| // REVISIT - log |
| } |
| } |
| |
| if (orb.transportDebugFlag) { |
| dprint(".reclaim: connections reclaimed (" |
| + (numberOfConnections - numberOfConnections()) + ")"); |
| } |
| } |
| |
| // XXX is necessary to do a GC to reclaim |
| // closed network connections ?? |
| // java.lang.System.gc(); |
| |
| return true; |
| } finally { |
| if (orb.transportDebugFlag) { |
| dprint(".reclaim<-: " + numberOfConnections()); |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////// |
| // |
| // spi.transport.ConnectionCache |
| // |
| |
| public String getMonitoringName() |
| { |
| return monitoringName; |
| } |
| |
| //////////////////////////////////////////////////// |
| // |
| // Implementation |
| // |
| |
| // This is public so folb.Server test can access it. |
| public abstract Collection values(); |
| |
| protected abstract Object backingStore(); |
| |
| protected abstract void registerWithMonitoring(); |
| |
| protected void dprintCreation() |
| { |
| if (orb.transportDebugFlag) { |
| dprint(".constructor: cacheType: " + getCacheType() |
| + " monitoringName: " + getMonitoringName()); |
| } |
| } |
| |
| protected void dprintStatistics() |
| { |
| if (orb.transportDebugFlag) { |
| dprint(".stats: " |
| + numberOfConnections() + "/total " |
| + numberOfBusyConnections() + "/busy " |
| + numberOfIdleConnections() + "/idle" |
| + " (" |
| + orb.getORBData().getHighWaterMark() + "/" |
| + orb.getORBData().getLowWaterMark() + "/" |
| + orb.getORBData().getNumberToReclaim() |
| + ")"); |
| } |
| } |
| |
| protected void dprint(String msg) |
| { |
| ORBUtility.dprint("CorbaConnectionCacheBase", msg); |
| } |
| } |
| |
| // End of file. |