/* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ 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.