/*
* Copyright (c) 2015 by Johannes Dillmann, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.osd.operations;
import java.util.HashMap;
import java.util.Map;
import org.xtreemfs.common.Capability;
import org.xtreemfs.common.xloc.InvalidXLocationsException;
import org.xtreemfs.common.xloc.XLocations;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.ErrorType;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.POSIXErrno;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.RPCHeader.ErrorResponse;
import org.xtreemfs.foundation.pbrpc.utils.ErrorUtils;
import org.xtreemfs.osd.OSDRequest;
import org.xtreemfs.osd.OSDRequestDispatcher;
import org.xtreemfs.osd.rwre.RWReplicationStage.GetReplicatedFileStateCallback;
import org.xtreemfs.osd.rwre.ReplicatedFileState.ReplicaState;
import org.xtreemfs.osd.rwre.ReplicatedFileStateSimple;
import org.xtreemfs.osd.stages.StorageStage.InternalGetReplicaStateCallback;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.AuthoritativeReplicaState;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.ObjectVersion;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.ObjectVersionMapping;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.ReplicaStatus;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_rwr_reset_statusRequest;
import org.xtreemfs.pbrpc.generatedinterfaces.OSD.xtreemfs_rwr_reset_statusResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.OSDServiceConstants;
/**
* This operation returns information on the RWR reset status. It returns if there is an ongoing RESET and if the OSDs
* data is complete in regard to the submitted AuthState.
*/
public class InternalRWRResetStatusOperation extends OSDOperation {
public InternalRWRResetStatusOperation(OSDRequestDispatcher master) {
super(master);
}
@Override
public int getProcedureId() {
return OSDServiceConstants.PROC_ID_XTREEMFS_RWR_RESET_STATUS;
}
@Override
public void startRequest(final OSDRequest rq) {
master.getRWReplicationStage().getReplicatedFileState(rq.getFileId(), new GetReplicatedFileStateCallback() {
@Override
public void getReplicatedFileStateComplete(ReplicatedFileStateSimple state) {
if (state.getState() == ReplicaState.RESET) {
respond(rq, true, false);
} else {
postGetStatus(rq);
}
}
@Override
public void failed(ErrorResponse error) {
rq.sendError(error);
}
}, rq);
}
private void postGetStatus(final OSDRequest rq) {
master.getStorageStage().internalGetReplicaState(rq.getFileId(),
rq.getLocationList().getLocalReplica().getStripingPolicy(), 0, new InternalGetReplicaStateCallback() {
@Override
public void getReplicaStateComplete(ReplicaStatus localState, ErrorResponse error) {
if (error == null) {
xtreemfs_rwr_reset_statusRequest rpcrq = (xtreemfs_rwr_reset_statusRequest) rq
.getRequestArgs();
boolean complete = checkReplicaStateComplete(rpcrq.getState(), localState);
respond(rq, false, complete);
} else {
respond(rq, false, false);
}
}
});
}
static boolean checkReplicaStateComplete(AuthoritativeReplicaState authState, ReplicaStatus localState) {
// Return incomplete if the local replica did miss a truncate
if (localState.getTruncateEpoch() < authState.getTruncateEpoch()) {
return false;
}
// Check if the local replica has every object from the auth state stored.
Map<Long, ObjectVersionMapping> missingObjects = new HashMap<Long, ObjectVersionMapping>();
for (ObjectVersionMapping authObject : authState.getObjectVersionsList()) {
missingObjects.put(authObject.getObjectNumber(), authObject);
}
for (ObjectVersion localObject : localState.getObjectVersionsList()) {
ObjectVersionMapping object = missingObjects.get(localObject.getObjectNumber());
if ((object != null) && (localObject.getObjectVersion() >= object.getObjectVersion())) {
missingObjects.remove(localObject.getObjectNumber());
}
}
return missingObjects.isEmpty();
}
private void respond(final OSDRequest rq, boolean running, boolean complete) {
xtreemfs_rwr_reset_statusResponse response = xtreemfs_rwr_reset_statusResponse.newBuilder().setRunning(running)
.setComplete(complete).build();
rq.sendSuccess(response, null);
}
@Override
public ErrorResponse parseRPCMessage(OSDRequest rq) {
try {
xtreemfs_rwr_reset_statusRequest rpcrq = (xtreemfs_rwr_reset_statusRequest) rq.getRequestArgs();
rq.setFileId(rpcrq.getFileId());
rq.setCapability(
new Capability(rpcrq.getFileCredentials().getXcap(), master.getConfig().getCapabilitySecret()));
rq.setLocationList(
new XLocations(rpcrq.getFileCredentials().getXlocs(), master.getConfig().getUUID()));
return null;
} catch (InvalidXLocationsException ex) {
return ErrorUtils.getErrorResponse(ErrorType.ERRNO, POSIXErrno.POSIX_ERROR_EINVAL, ex.toString());
} catch (Throwable ex) {
return ErrorUtils.getInternalServerError(ex);
}
}
@Override
public boolean requiresCapability() {
return true;
}
@Override
public boolean bypassViewValidation() {
return true;
}
@Override
public void startInternalEvent(Object[] args) {
throw new UnsupportedOperationException("Not supported yet.");
}
}