/*
* dCache - http://www.dcache.org/
*
* Copyright (C) 2016 Deutsches Elektronen-Synchrotron
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.dcache.poolmanager;
import com.google.common.util.concurrent.MoreExecutors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.remoting.RemoteConnectFailureException;
import org.springframework.remoting.RemoteProxyFailureException;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
import diskCacheV111.poolManager.CostModule;
import diskCacheV111.poolManager.PoolSelectionUnit;
import diskCacheV111.pools.PoolCostInfo;
import diskCacheV111.util.CacheException;
import diskCacheV111.util.FileLocality;
import diskCacheV111.vehicles.PoolManagerGetPoolMonitor;
import diskCacheV111.vehicles.ProtocolInfo;
import dmg.cells.nucleus.CellEndpoint;
import dmg.cells.nucleus.CellLifeCycleAware;
import dmg.cells.nucleus.CellMessageReceiver;
import dmg.cells.nucleus.NoRouteToCellException;
import org.dcache.cells.AbstractMessageCallback;
import org.dcache.cells.CellStub;
import org.dcache.vehicles.FileAttributes;
import static org.dcache.util.MathUtils.addWithInfinity;
import static org.dcache.util.MathUtils.subWithInfinity;
/**
* PoolMonitor that delegates to a PoolMonitor obtained from pool manager.
*/
public class RemotePoolMonitor
implements PoolMonitor, CellLifeCycleAware, CellMessageReceiver
{
private static final Logger LOGGER = LoggerFactory.getLogger(RemotePoolMonitor.class);
private long lastRefreshTime;
private CellStub poolManagerStub;
private PoolMonitor poolMonitor;
private long refreshCount;
@Required
public void setPoolManagerStub(CellStub stub)
{
poolManagerStub = stub;
}
@Override
public synchronized void afterStart()
{
CellStub.addCallback(poolManagerStub.send(new PoolManagerGetPoolMonitor(), CellEndpoint.SendFlag.RETRY_ON_NO_ROUTE_TO_CELL),
new AbstractMessageCallback<PoolManagerGetPoolMonitor>()
{
@Override
public void success(PoolManagerGetPoolMonitor message)
{
messageArrived(message.getPoolMonitor());
}
@Override
public void timeout(String message)
{
afterStart();
}
@Override
public void failure(int rc, Object error)
{
}
},
MoreExecutors.directExecutor());
}
@Override
public PoolSelectionUnit getPoolSelectionUnit()
{
return getPoolMonitor().getPoolSelectionUnit();
}
@Override
public CostModule getCostModule()
{
return getPoolMonitor().getCostModule();
}
@Override
public PartitionManager getPartitionManager()
{
return getPoolMonitor().getPartitionManager();
}
@Override
public PoolSelector getPoolSelector(FileAttributes fileAttributes, ProtocolInfo protocolInfo, String linkGroup)
{
return getPoolMonitor().getPoolSelector(fileAttributes, protocolInfo, linkGroup);
}
@Override
public Collection<PoolCostInfo> queryPoolsByLinkName(String linkName)
{
return getPoolMonitor().queryPoolsByLinkName(linkName);
}
@Override
public FileLocality getFileLocality(FileAttributes attributes, String hostName)
{
return getPoolMonitor().getFileLocality(attributes, hostName);
}
public void refresh() throws CacheException, InterruptedException, NoRouteToCellException
{
messageArrived(poolManagerStub.sendAndWait(new PoolManagerGetPoolMonitor()).getPoolMonitor());
}
public synchronized long getRefreshCount()
{
return refreshCount;
}
public synchronized long getLastRefreshTime()
{
return lastRefreshTime;
}
public synchronized void messageArrived(SerializablePoolMonitor monitor)
{
poolMonitor = monitor;
lastRefreshTime = System.currentTimeMillis();
refreshCount++;
notifyAll();
}
private synchronized PoolMonitor getPoolMonitor()
{
try {
if (poolMonitor == null) {
long deadline = addWithInfinity(System.currentTimeMillis(), poolManagerStub.getTimeoutInMillis());
do {
wait(subWithInfinity(deadline, System.currentTimeMillis()));
} while (poolMonitor == null || deadline <= System.currentTimeMillis());
if (poolMonitor == null) {
throw new RemoteConnectFailureException("Cached pool information is not yet available.", null);
}
}
if (lastRefreshTime < System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(5)) {
LOGGER.warn("Cached pool information is older than 5 minutes. Please check pool manager.");
}
return poolMonitor;
} catch (InterruptedException e) {
throw new RemoteProxyFailureException("Failed to fetch pool monitor: " + e.getMessage(), e);
}
}
}