package diskCacheV111.services;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import jersey.repackaged.com.google.common.collect.ImmutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import java.io.IOException;
import java.io.Serializable;
import java.net.InetAddress;
import java.net.URI;
import java.util.EnumSet;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import diskCacheV111.doors.FTPTransactionLog;
import diskCacheV111.util.CacheException;
import diskCacheV111.util.PnfsId;
import diskCacheV111.vehicles.DoorRequestInfoMessage;
import diskCacheV111.vehicles.DoorTransferFinishedMessage;
import diskCacheV111.vehicles.IoJobInfo;
import diskCacheV111.vehicles.IpProtocolInfo;
import diskCacheV111.vehicles.Message;
import diskCacheV111.vehicles.PnfsCreateEntryMessage;
import diskCacheV111.vehicles.PnfsDeleteEntryMessage;
import diskCacheV111.vehicles.PnfsMapPathMessage;
import diskCacheV111.vehicles.PnfsMessage;
import diskCacheV111.vehicles.PoolAcceptFileMessage;
import diskCacheV111.vehicles.PoolDeliverFileMessage;
import diskCacheV111.vehicles.PoolIoFileMessage;
import diskCacheV111.vehicles.PoolMgrSelectPoolMsg;
import diskCacheV111.vehicles.PoolMgrSelectReadPoolMsg;
import diskCacheV111.vehicles.PoolMgrSelectWritePoolMsg;
import diskCacheV111.vehicles.PoolMoverKillMessage;
import diskCacheV111.vehicles.transferManager.TransferCompleteMessage;
import diskCacheV111.vehicles.transferManager.TransferFailedMessage;
import diskCacheV111.vehicles.transferManager.TransferManagerMessage;
import diskCacheV111.vehicles.transferManager.TransferStatusQueryMessage;
import dmg.cells.nucleus.CellAddressCore;
import dmg.cells.nucleus.CellMessage;
import dmg.cells.nucleus.CellPath;
import org.dcache.acl.enums.AccessMask;
import org.dcache.auth.Subjects;
import org.dcache.cells.AbstractMessageCallback;
import org.dcache.cells.CellStub;
import org.dcache.cells.MessageReply;
import org.dcache.namespace.ACLPermissionHandler;
import org.dcache.namespace.ChainedPermissionHandler;
import org.dcache.namespace.FileAttribute;
import org.dcache.namespace.FileType;
import org.dcache.namespace.PermissionHandler;
import org.dcache.namespace.PosixPermissionHandler;
import org.dcache.pool.assumption.Assumption;
import org.dcache.vehicles.FileAttributes;
import org.dcache.vehicles.PnfsGetFileAttributes;
import static org.dcache.namespace.FileAttribute.*;
public class TransferManagerHandler extends AbstractMessageCallback<Message>
{
private static final Logger log =
LoggerFactory.getLogger(TransferManagerHandler.class);
private final TransferManager manager;
private final TransferManagerMessage transferRequest;
private final CellPath requestor;
private String pnfsPath;
private transient String parentDir;
boolean store;
boolean created;
private PnfsId pnfsId;
private String pnfsIdString;
private String remoteUrl;
transient boolean locked;
private String pool;
private CellAddressCore poolAddress;
private Assumption assumption;
private FTPTransactionLog tlog;
private FileAttributes fileAttributes;
public static final int INITIAL_STATE = 0;
public static final int WAITING_FOR_PNFS_INFO_STATE = 1;
public static final int RECEIVED_PNFS_INFO_STATE = 2;
public static final int WAITING_FOR_PNFS_ENTRY_CREATION_INFO_STATE = 5;
public static final int RECEIVED_PNFS_ENTRY_CREATION_INFO_STATE = 6;
public static final int WAITING_FOR_POOL_INFO_STATE = 7;
public static final int RECEIVED_POOL_INFO_STATE = 8;
public static final int WAITING_FIRST_POOL_REPLY_STATE = 9;
public static final int RECEIVED_FIRST_POOL_REPLY_STATE = 10;
public static final int WAITING_FOR_SPACE_INFO_STATE = 11;
public static final int RECEIVED_SPACE_INFO_STATE = 12;
public static final int WAITING_FOR_PNFS_ENTRY_DELETE = 13;
public static final int RECEIVED_PNFS_ENTRY_DELETE = 14;
public static final int WAITING_FOR_PNFS_CHECK_BEFORE_DELETE_STATE = 15;
public static final int RECEIVED_PNFS_CHECK_BEFORE_DELETE_STATE = 16;
public static final int SENT_ERROR_REPLY_STATE = -1;
public static final int SENT_SUCCESS_REPLY_STATE = -2;
public static final int UNKNOWN_ID = -3;
public static final Map<Integer,String> STATE_DESCRIPTION =
ImmutableMap.<Integer,String>builder()
.put(INITIAL_STATE, "initialising")
.put(WAITING_FOR_PNFS_INFO_STATE, "querying file metadata")
.put(RECEIVED_PNFS_INFO_STATE, "recieved file metadata")
.put(WAITING_FOR_PNFS_ENTRY_CREATION_INFO_STATE, "creating namespace entry")
.put(RECEIVED_PNFS_ENTRY_CREATION_INFO_STATE, "namespace entry created")
.put(WAITING_FOR_POOL_INFO_STATE, "selecting pool")
.put(RECEIVED_POOL_INFO_STATE, "pool selected")
.put(WAITING_FIRST_POOL_REPLY_STATE, "waiting for transfer to start")
.put(RECEIVED_FIRST_POOL_REPLY_STATE, "transfer has started")
.put(WAITING_FOR_SPACE_INFO_STATE, "reserving space")
.put(RECEIVED_SPACE_INFO_STATE, "space reserved")
.put(WAITING_FOR_PNFS_ENTRY_DELETE, "requesting file deletion")
.put(RECEIVED_PNFS_ENTRY_DELETE, "notified of file deletion")
.put(WAITING_FOR_PNFS_CHECK_BEFORE_DELETE_STATE, "checking before file deletion")
.put(RECEIVED_PNFS_CHECK_BEFORE_DELETE_STATE, "confirmed file deletion OK")
.put(SENT_ERROR_REPLY_STATE, "transfer failed")
.put(SENT_SUCCESS_REPLY_STATE, "transfer succeeded")
.put(UNKNOWN_ID, "unknown transfer")
.build();
public int state = INITIAL_STATE;
private long id;
private Integer moverId;
private IpProtocolInfo protocol_info;
private long creationTime;
private long lifeTime;
private Long credentialId;
private transient int numberOfRetries;
private transient int _replyCode;
private transient Serializable _errorObject;
private transient boolean _cancelTimer;
private final transient DoorRequestInfoMessage info;
private final transient PermissionHandler permissionHandler;
private transient PoolMgrSelectReadPoolMsg.Context _readPoolSelectionContext;
private final transient Executor executor;
public TransferManagerHandler(TransferManager tManager,
TransferManagerMessage message,
CellPath requestor,
Executor executor)
{
this.executor = executor;
numberOfRetries = 0;
creationTime = System.currentTimeMillis();
manager = tManager;
id = manager.getNextMessageID();
message.setId(id);
transferRequest = message;
pnfsPath = transferRequest.getPnfsPath();
store = transferRequest.isStore();
remoteUrl = transferRequest.getRemoteURL();
credentialId = transferRequest.getCredentialId();
Subject subject = transferRequest.getSubject();
info = new DoorRequestInfoMessage(manager.getCellAddress());
info.setTransactionDuration(-creationTime);
info.setSubject(subject);
info.setBillingPath(pnfsPath);
info.setTransferPath(pnfsPath);
info.setTimeQueued(-System.currentTimeMillis());
this.requestor = requestor;
try {
info.setClient(new URI(transferRequest.getRemoteURL()).getHost());
} catch (Exception e) {
}
try {
if (manager.getLogRootName() != null) {
tlog = new FTPTransactionLog(manager.getLogRootName());
String user_info =
Subjects.getDn(transferRequest.getSubject())
+ "(" + info.getUid() + "." + info.getGid() + ")";
String rw = store ? "write" : "read";
InetAddress remoteaddr =
InetAddress.getByName(new URI(transferRequest.getRemoteURL()).getHost());
tlog.begin(user_info, "remotegsiftp", rw, transferRequest.getPnfsPath(), remoteaddr);
}
} catch (Exception e) {
log.error("starting tlog failed :", e);
}
manager.addActiveTransfer(id, this);
setState(INITIAL_STATE);
permissionHandler =
new ChainedPermissionHandler(
new ACLPermissionHandler(),
new PosixPermissionHandler());
}
public static String describeState(int state)
{
String description = STATE_DESCRIPTION.get(state);
return description != null ? description : ("Unknown state: " + state);
}
public void handle()
{
log.debug("handling: " + toString(true));
int last_slash_pos = pnfsPath.lastIndexOf('/');
if (last_slash_pos == -1) {
transferRequest.setFailed(2,
new IOException("pnfsFilePath is not absolute:" + pnfsPath));
return;
}
parentDir = pnfsPath.substring(0, last_slash_pos);
PnfsMessage message;
if (store) {
message = new PnfsCreateEntryMessage(pnfsPath, FileAttributes.ofFileType(FileType.REGULAR));
message.setSubject(transferRequest.getSubject());
message.setRestriction(transferRequest.getRestriction());
setState(WAITING_FOR_PNFS_ENTRY_CREATION_INFO_STATE);
} else {
EnumSet<FileAttribute> attributes = EnumSet.noneOf(FileAttribute.class);
attributes.addAll(permissionHandler.getRequiredAttributes());
attributes.addAll(PoolMgrSelectReadPoolMsg.getRequiredAttributes());
message = new PnfsGetFileAttributes(pnfsPath, attributes);
message.setSubject(transferRequest.getSubject());
message.setRestriction(transferRequest.getRestriction());
message.setAccessMask(EnumSet.of(AccessMask.READ_DATA));
setState(WAITING_FOR_PNFS_INFO_STATE);
}
manager.persist(this);
CellStub.addCallback(manager.getPnfsManagerStub().send(message), this, executor);
}
@Override
public void success(Message message)
{
if (message instanceof PnfsCreateEntryMessage) {
PnfsCreateEntryMessage create_msg =
(PnfsCreateEntryMessage) message;
if (state == WAITING_FOR_PNFS_ENTRY_CREATION_INFO_STATE) {
setState(RECEIVED_PNFS_ENTRY_CREATION_INFO_STATE);
createEntryResponseArrived(create_msg);
return;
}
log.error(this.toString() + " got unexpected PnfsCreateEntryMessage "
+ " : " + create_msg + " ; Ignoring");
} else if (message instanceof PnfsGetFileAttributes) {
PnfsGetFileAttributes attributesMessage =
(PnfsGetFileAttributes) message;
if (state == WAITING_FOR_PNFS_INFO_STATE) {
setState(RECEIVED_PNFS_INFO_STATE);
storageInfoArrived(attributesMessage);
return;
}
log.error(this.toString() + " got unexpected PnfsGetStorageInfoMessage "
+ " : " + attributesMessage + " ; Ignoring");
} else if (message instanceof PnfsMapPathMessage) {
PnfsMapPathMessage mapMessage = (PnfsMapPathMessage) message;
if (state == WAITING_FOR_PNFS_CHECK_BEFORE_DELETE_STATE) {
state = RECEIVED_PNFS_CHECK_BEFORE_DELETE_STATE;
deletePnfsEntry();
return;
} else {
log.error(this.toString() + " got unexpected PnfsMapPathMessage "
+ " : " + mapMessage + " ; Ignoring");
}
} else if (message instanceof PoolMgrSelectPoolMsg) {
PoolMgrSelectPoolMsg select_pool_msg =
(PoolMgrSelectPoolMsg) message;
if (state == WAITING_FOR_POOL_INFO_STATE) {
setState(RECEIVED_POOL_INFO_STATE);
poolInfoArrived(select_pool_msg);
return;
}
log.error(this.toString() + " got unexpected PoolMgrSelectPoolMsg "
+ " : " + select_pool_msg + " ; Ignoring");
} else if (message instanceof PoolIoFileMessage) {
PoolIoFileMessage first_pool_reply =
(PoolIoFileMessage) message;
if (state == WAITING_FIRST_POOL_REPLY_STATE) {
setState(RECEIVED_FIRST_POOL_REPLY_STATE);
poolFirstReplyArrived(first_pool_reply);
return;
}
log.error(this.toString() + " got unexpected PoolIoFileMessage "
+ " : " + first_pool_reply + " ; Ignoring");
} else if (message instanceof PnfsDeleteEntryMessage) {
PnfsDeleteEntryMessage deleteReply = (PnfsDeleteEntryMessage) message;
if (state == WAITING_FOR_PNFS_ENTRY_DELETE) {
setState(RECEIVED_PNFS_ENTRY_DELETE);
log.debug("Received PnfsDeleteEntryMessage, Deleted : {}",
deleteReply.getPnfsPath());
sendErrorReply();
}
}
manager.persist(this);
}
@Override
public void failure(int rc, Object error)
{
switch (state) {
case WAITING_FOR_PNFS_INFO_STATE:
sendErrorReply(rc, "Failed to lookup file: " + error);
break;
case WAITING_FOR_PNFS_ENTRY_CREATION_INFO_STATE:
sendErrorReply(rc, "Failed to create namespace entry: " + error);
break;
case WAITING_FIRST_POOL_REPLY_STATE:
// FIXME: in the case of an attempted read (pool pushing the file
// to some remote site), we can ask PoolManager for another
// pool. For an attempted write (pool pulling the file)
// we must fail the transfer as we don't know if a mover
// was started.
sendErrorReply(CacheException.SELECTED_POOL_FAILED,
"Failed while waiting for mover to start: " + error);
break;
case WAITING_FOR_PNFS_CHECK_BEFORE_DELETE_STATE:
sendErrorReply(rc, "Pre-delete check failed: " + error);
break;
case WAITING_FOR_POOL_INFO_STATE:
if (rc == CacheException.OUT_OF_DATE) {
handle();
} else {
sendErrorReply(rc, "Failed to select pool: " + error);
}
break;
case WAITING_FOR_PNFS_ENTRY_DELETE:
log.warn("Delete attempt ({} of {}) failed: {}", numberOfRetries + 1,
manager.getMaxNumberOfDeleteRetries(), error);
numberOfRetries++;
if (numberOfRetries < manager.getMaxNumberOfDeleteRetries()) {
deletePnfsEntry();
} else {
sendErrorReply(_replyCode, "Failed to delete file " +
"(" + error + "), triggered by: " + _errorObject);
}
break;
default:
/* The code should never get here, but we try to recover from bugs. */
sendErrorReply(rc, "Failed in state " + state + ": " + error +
" [" + rc + "]");
break;
}
}
public void createEntryResponseArrived(PnfsCreateEntryMessage create)
{
created = true;
manager.persist(this);
fileAttributes = create.getFileAttributes();
pnfsId = create.getPnfsId();
pnfsIdString = pnfsId.toString();
info.setPnfsId(pnfsId);
info.setStorageInfo(create.getFileAttributes().getStorageInfo());
if (create.getFileAttributes().isDefined(STORAGEINFO) && create.getFileAttributes().getStorageInfo().getKey("path") != null) {
info.setBillingPath(create.getFileAttributes().getStorageInfo().getKey("path"));
}
selectPool();
}
public void storageInfoArrived(PnfsGetFileAttributes msg)
{
if (!store && tlog != null) {
tlog.middle(msg.getFileAttributes().getSize());
}
//
// Added by litvinse@fnal.gov
//
pnfsId = msg.getPnfsId();
info.setPnfsId(pnfsId);
info.setStorageInfo(msg.getFileAttributes().getStorageInfo());
pnfsIdString = pnfsId.toString();
manager.persist(this);
if (store) {
synchronized (manager.justRequestedIDs) {
if (manager.justRequestedIDs.contains(msg.getPnfsId())) {
sendErrorReply(6, new CacheException("pnfs pnfsid: " + pnfsId.toString() + " file " + pnfsPath + " is already there"));
return;
}
for (PnfsId pnfsid : manager.justRequestedIDs) {
log.debug("found pnfsid: {}", pnfsid);
}
manager.justRequestedIDs.add(pnfsId);
}
}
if (fileAttributes == null) {
fileAttributes =
msg.getFileAttributes();
}
log.debug("storageInfoArrived(uid={} gid={} pnfsid={} fileAttributes={}", info.getUid(), info.getGid(),
pnfsId, fileAttributes);
selectPool();
}
public void selectPool()
{
protocol_info = manager.getProtocolInfo(transferRequest);
PoolMgrSelectPoolMsg request = store
? new PoolMgrSelectWritePoolMsg(fileAttributes, protocol_info)
: new PoolMgrSelectReadPoolMsg(fileAttributes, protocol_info, _readPoolSelectionContext);
request.setBillingPath(pnfsPath);
request.setSubject(transferRequest.getSubject());
log.debug("PoolMgrSelectPoolMsg: " + request);
setState(WAITING_FOR_POOL_INFO_STATE);
manager.persist(this);
CellStub.addCallback(manager.getPoolManagerStub().sendAsync(request), this, executor);
}
public void poolInfoArrived(PoolMgrSelectPoolMsg pool_info)
{
log.debug("poolManagerReply = " + pool_info);
if (pool_info instanceof PoolMgrSelectReadPoolMsg) {
_readPoolSelectionContext =
((PoolMgrSelectReadPoolMsg) pool_info).getContext();
}
setPool(pool_info.getPoolName());
setPoolAddress(pool_info.getPoolAddress());
setAssumption(pool_info.getAssumption());
fileAttributes = pool_info.getFileAttributes();
manager.persist(this);
log.debug("Positive reply from pool {}", pool);
startMoverOnThePool();
}
public void startMoverOnThePool()
{
PoolIoFileMessage poolMessage = store
? new PoolAcceptFileMessage(
pool,
protocol_info,
fileAttributes,
assumption)
: new PoolDeliverFileMessage(
pool,
protocol_info,
fileAttributes,
assumption);
poolMessage.setBillingPath(info.getBillingPath());
poolMessage.setTransferPath(info.getTransferPath());
poolMessage.setSubject(transferRequest.getSubject());
if (manager.getIoQueueName() != null) {
poolMessage.setIoQueueName(manager.getIoQueueName());
}
poolMessage.setInitiator(info.getTransaction());
poolMessage.setId(id);
setState(WAITING_FIRST_POOL_REPLY_STATE);
manager.persist(this);
CellStub.addCallback(manager.getPoolManagerStub().startAsync(poolAddress, poolMessage), this, executor);
}
public void poolFirstReplyArrived(PoolIoFileMessage poolMessage)
{
log.debug("poolReply = " + poolMessage);
info.setTimeQueued(info.getTimeQueued() + System.currentTimeMillis());
log.debug("Pool " + pool + " will deliver file " + pnfsId + " mover id is " + poolMessage.getMoverId());
log.debug("Starting moverTimeout timer");
manager.startTimer(id);
setMoverId(poolMessage.getMoverId());
manager.persist(this);
}
public void deletePnfsEntry()
{
if (state == RECEIVED_PNFS_CHECK_BEFORE_DELETE_STATE) {
PnfsDeleteEntryMessage pnfsMsg = new PnfsDeleteEntryMessage(pnfsPath);
setState(WAITING_FOR_PNFS_ENTRY_DELETE);
manager.persist(this);
pnfsMsg.setReplyRequired(true);
CellStub.addCallback(manager.getPnfsManagerStub().send(pnfsMsg), this, executor);
} else {
PnfsMapPathMessage message = new PnfsMapPathMessage(pnfsPath);
setState(WAITING_FOR_PNFS_CHECK_BEFORE_DELETE_STATE);
CellStub.addCallback(manager.getPnfsManagerStub().send(message), this, executor);
}
}
public void poolDoorMessageArrived(DoorTransferFinishedMessage doorMessage)
{
log.debug("poolDoorMessageArrived, doorMessage.getReturnCode()={}", doorMessage.getReturnCode());
if (doorMessage.getReturnCode() != 0) {
sendErrorReply(CacheException.THIRD_PARTY_TRANSFER_FAILED,
doorMessage.getErrorObject());
return;
}
if (store && tlog != null) {
tlog.middle(doorMessage.getFileAttributes().getSize());
}
sendSuccessReply();
}
public void sendErrorReply(int replyCode,
Serializable errorObject)
{
sendErrorReply(replyCode, errorObject, true);
}
public void sendErrorReply(int replyCode,
Serializable errorObject,
boolean cancelTimer)
{
_replyCode = replyCode;
_errorObject = errorObject;
_cancelTimer = cancelTimer;
if (log.isDebugEnabled()) {
log.debug("sending error reply {}:{} for {}", replyCode,
errorObject, toString(true));
}
if (store && created) {// Timur: I think this check is not needed, we might not ever get storage info and pnfs id: && pnfsId != null && aMetadata != null && aMetadata.getFileSize() == 0) {
if (state != WAITING_FOR_PNFS_ENTRY_DELETE && state != RECEIVED_PNFS_ENTRY_DELETE) {
log.debug("deleting pnfs entry we created: {}", pnfsPath);
deletePnfsEntry();
return;
}
}
if (tlog != null) {
tlog.error("getFromRemoteGsiftpUrl failed: state = " + state
+ " replyCode=" + replyCode + " errorObject="
+ errorObject);
}
if (info.getTimeQueued() < 0) {
info.setTimeQueued(info.getTimeQueued() + System
.currentTimeMillis());
}
if (info.getTransactionDuration() < 0) {
info.setTransactionDuration(info
.getTransactionDuration() + System
.currentTimeMillis());
}
sendDoorRequestInfo(replyCode, errorObject.toString());
setState(SENT_ERROR_REPLY_STATE, errorObject);
manager.persist(this);
if (cancelTimer) {
manager.stopTimer(id);
}
if (store) {
synchronized (manager.justRequestedIDs) {
manager.justRequestedIDs.remove(pnfsId);
}
}
manager.finishTransfer();
try {
TransferFailedMessage errorReply = new TransferFailedMessage(transferRequest, replyCode, errorObject);
manager.sendMessage(new CellMessage(requestor, errorReply));
} catch (RuntimeException e) {
log.error(e.toString());
//can not do much more here!!!
}
//this will allow the handler to be garbage collected
// once we sent a response
manager.removeActiveTransfer(id);
}
public void sendErrorReply()
{
int replyCode = _replyCode;
Serializable errorObject = _errorObject;
boolean cancelTimer = _cancelTimer;
if (log.isDebugEnabled()) {
log.debug("sending error reply {}:{} for {}", replyCode,
errorObject, toString(true));
}
if (tlog != null) {
tlog.error("getFromRemoteGsiftpUrl failed: state = " + state
+ " replyCode=" + replyCode + " errorObject="
+ errorObject);
}
if (info.getTimeQueued() < 0) {
info.setTimeQueued(info.getTimeQueued() + System
.currentTimeMillis());
}
if (info.getTransactionDuration() < 0) {
info.setTransactionDuration(info
.getTransactionDuration() + System
.currentTimeMillis());
}
sendDoorRequestInfo(replyCode, errorObject.toString());
setState(SENT_ERROR_REPLY_STATE, errorObject);
manager.persist(this);
if (cancelTimer) {
manager.stopTimer(id);
}
if (store) {
synchronized (manager.justRequestedIDs) {
manager.justRequestedIDs.remove(pnfsId);
}
}
manager.finishTransfer();
try {
TransferFailedMessage errorReply = new TransferFailedMessage(transferRequest, replyCode, errorObject);
manager.sendMessage(new CellMessage(requestor, errorReply));
} catch (RuntimeException e) {
log.error(e.toString());
//can not do much more here!!!
}
//this will allow the handler to be garbage collected
// once we sent a response
manager.removeActiveTransfer(id);
}
public void sendSuccessReply()
{
log.debug("sendSuccessReply for: " + toString(true));
if (info.getTimeQueued() < 0) {
info.setTimeQueued(info.getTimeQueued() + System
.currentTimeMillis());
}
if (info.getTransactionDuration() < 0) {
info.setTransactionDuration(info
.getTransactionDuration() + System
.currentTimeMillis());
}
sendDoorRequestInfo(0, "");
setState(SENT_SUCCESS_REPLY_STATE);
manager.persist(this);
manager.stopTimer(id);
if (store) {
synchronized (manager.justRequestedIDs) {
manager.justRequestedIDs.remove(pnfsId);
}
}
manager.finishTransfer();
if (tlog != null) {
tlog.success();
}
try {
TransferCompleteMessage errorReply = new TransferCompleteMessage(transferRequest);
manager.sendMessage(new CellMessage(requestor, errorReply));
} catch (RuntimeException e) {
log.error(e.toString());
//can not do much more here!!!
}
//this will allow the handler to be garbage collected
// once we sent a response
manager.removeActiveTransfer(id);
}
/**
* Sends status information to the biling cell.
*/
void sendDoorRequestInfo(int code, String msg)
{
info.setResult(code, msg);
log.debug("Sending info: " + info);
manager.getBillingStub().notify(info);
}
public void timeout()
{
log.error(" transfer timed out");
if (moverId != null) {
killMover(moverId, "timed out");
}
sendErrorReply(24, new IOException("timed out while waiting for mover reply"), false);
}
public void cancel(String explanation)
{
log.debug("transfer cancelled: {}", explanation);
if (moverId != null) {
killMover(moverId, explanation);
}
// FIXME: sending the reply here removes the TransferManagerHandler
// from the set of active transfers. This triggers an error
// when the pool's DoorTransferFinishedMessage is received since
// TransferManager now cannot find the corresponding
// TransferManagerHandler message.
sendErrorReply(24, new IOException("transfer cancelled: " + explanation));
}
public synchronized String toString(boolean isLongFormat)
{
String src = store ? transferRequest.getRemoteURL() : transferRequest.getPnfsPath();
String dest = store ? transferRequest.getPnfsPath() : transferRequest.getRemoteURL();
String siPath = fileAttributes == null ? null : fileAttributes.getStorageInfo().getKey("path");
StringBuilder sb = new StringBuilder("id: ").append(id);
if (isLongFormat) {
sb.append('\n');
sb.append(" Source: ").append(src).append('\n');
sb.append(" Destination: ").append(dest).append('\n');
if (store && siPath != null && !siPath.equals(dest)) {
sb.append(" Final destination: ").append(siPath).append('\n');
}
sb.append(" State: ").append(describeState(state)).append('\n');
sb.append(" User: ").append(Subjects.getDisplayName(transferRequest.getSubject())).append('\n');
sb.append(" Restriction: ").append(transferRequest.getRestriction()).append('\n');
if (pnfsId != null) {
sb.append(" PNFS-ID: ").append(pnfsId).append('\n');
}
if (fileAttributes != null) {
if (fileAttributes.isDefined(ACCESS_LATENCY)) {
sb.append(" Access latency: ").append(fileAttributes.getAccessLatency()).append('\n');
}
if (fileAttributes.isDefined(RETENTION_POLICY)) {
sb.append(" Retention policy: ").append(fileAttributes.getRetentionPolicy()).append('\n');
}
if (fileAttributes.isDefined(STORAGECLASS)) {
sb.append(" Storage class: ").append(fileAttributes.getStorageClass()).append('\n');
}
if (fileAttributes.isDefined(SIZE)) {
sb.append(" Size: ").append(fileAttributes.getSize()).append('\n');
}
}
sb.append(" Pool: ").append(pool == null ? "not yet selected" : pool);
if (moverId != null) {
sb.append('\n');
sb.append(" Mover: ").append(moverId);
}
} else {
sb.append(' ').append(src).append(" --> ").append(dest);
if (store && siPath != null && !siPath.equals(dest)) {
sb.append(" [").append(siPath).append("]");
}
}
return sb.toString();
}
public boolean isMoverActive()
{
return state == RECEIVED_FIRST_POOL_REPLY_STATE;
}
public Object appendInfo(final TransferStatusQueryMessage message)
{
message.setState(state);
if (!isMoverActive()) {
return message;
}
final MessageReply<TransferStatusQueryMessage> reply = new MessageReply<>();
final ListenableFuture<IoJobInfo> future = manager.getPoolStub().
send(new CellPath(poolAddress), "mover ls -binary " + moverId,
IoJobInfo.class, 30_000);
Futures.addCallback(future, new FutureCallback<IoJobInfo>()
{
@Override
public void onSuccess(IoJobInfo info)
{
message.setMoverInfo(info);
reply.reply(message);
}
@Override
public void onFailure(Throwable e)
{
reply.fail(message, CacheException.UNEXPECTED_SYSTEM_EXCEPTION,
"failed to query pool: " + e.getMessage());
}
}, MoreExecutors.directExecutor());
return reply;
}
@Override
public String toString()
{
return toString(false);
}
public String getPool()
{
return pool;
}
public void setPool(String pool)
{
this.pool = pool;
}
public void setPoolAddress(CellAddressCore poolAddress)
{
this.poolAddress = poolAddress;
}
public void setAssumption(Assumption assumption)
{
this.assumption = assumption;
}
public void killMover(int moverId, String explanation)
{
log.debug("sending mover kill to pool {} for moverId={}", pool, moverId);
PoolMoverKillMessage killMessage = new PoolMoverKillMessage(pool, moverId,
"killed by TransferManagerHandler: " + explanation);
killMessage.setReplyRequired(false);
manager.getPoolStub().notify(new CellPath(poolAddress), killMessage);
}
public void setState(int istate)
{
this.state = istate;
TransferManagerHandlerState ts = new TransferManagerHandlerState(this, null);
manager.persist(ts);
}
public void setState(int istate, Object errorObject)
{
this.state = istate;
TransferManagerHandlerState ts = new TransferManagerHandlerState(this, errorObject);
manager.persist(ts);
}
public void setMoverId(Integer moverid)
{
moverId = moverid;
}
public String getPnfsPath()
{
return pnfsPath;
}
public boolean getStore()
{
return store;
}
public boolean getCreated()
{
return created;
}
public boolean getLocked()
{
return locked;
}
public String getPnfsIdString()
{
return pnfsIdString;
}
public String getRemoteUrl()
{
return remoteUrl;
}
public int getState()
{
return state;
}
public long getId()
{
return id;
}
public Integer getMoverId()
{
return moverId;
}
public long getCreationTime()
{
return creationTime;
}
public long getLifeTime()
{
return lifeTime;
}
public Long getCredentialId()
{
return credentialId;
}
}