/* * 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 {@literal <=} .... ). 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 {@literal &} 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.