blob: 0cbce53ffc1645b5d73653db2dad2ee2c2a3a53c [file] [log] [blame]
/*
* 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.