/*
* Copyright (c) 2015 by Robert Bärhold, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
package org.xtreemfs.mrc.operations;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.xtreemfs.common.Capability;
import org.xtreemfs.common.quota.FinalizeVoucherResponseHelper;
import org.xtreemfs.foundation.logging.Logging;
import org.xtreemfs.foundation.pbrpc.generatedinterfaces.RPC.POSIXErrno;
import org.xtreemfs.mrc.MRCRequest;
import org.xtreemfs.mrc.MRCRequestDispatcher;
import org.xtreemfs.mrc.UserException;
import org.xtreemfs.mrc.database.AtomicDBUpdate;
import org.xtreemfs.mrc.database.DatabaseException;
import org.xtreemfs.mrc.database.DatabaseException.ExceptionType;
import org.xtreemfs.mrc.database.StorageManager;
import org.xtreemfs.mrc.metadata.FileMetadata;
import org.xtreemfs.mrc.quota.QuotaFileInformation;
import org.xtreemfs.mrc.utils.MRCHelper.GlobalFileIdResolver;
import org.xtreemfs.pbrpc.generatedinterfaces.Common.emptyResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.OSDFinalizeVouchersResponse;
import org.xtreemfs.pbrpc.generatedinterfaces.GlobalTypes.StripingPolicy;
import org.xtreemfs.pbrpc.generatedinterfaces.MRC.xtreemfs_clear_vouchersRequest;
/**
* Operation to handle a clear voucher request to free voucher with the finalize responses of the osds.
*/
public class ClearVouchersOperation extends MRCOperation {
public ClearVouchersOperation(MRCRequestDispatcher master) {
super(master);
}
@Override
public void startRequest(MRCRequest rq) throws Throwable {
// perform master redirect if necessary
if (master.getReplMasterUUID() != null
&& !master.getReplMasterUUID().equals(master.getConfig().getUUID().toString()))
throw new DatabaseException(ExceptionType.REDIRECT);
final xtreemfs_clear_vouchersRequest cvRequest = (xtreemfs_clear_vouchersRequest) rq.getRequestArgs();
Capability cap = new Capability(cvRequest.getCreds().getXcap(), master.getConfig().getCapabilitySecret());
Set<Long> expireTimeSet = new HashSet<Long>(cvRequest.getExpireTimeMsList());
List<OSDFinalizeVouchersResponse> osdFinalizeVouchersResponseList = cvRequest
.getOsdFinalizeVouchersResponseList();
// check whether the capability has a valid signature
if (!cap.hasValidSignature())
throw new UserException(POSIXErrno.POSIX_ERROR_EPERM, cap + " does not have a valid signature");
// check whether the capability has expired
if (cap.hasExpired())
throw new UserException(POSIXErrno.POSIX_ERROR_EPERM, cap + " has expired");
// Striping with active replication isn't supported, so the policy should be the same on all replicas
StripingPolicy sp = cvRequest.getCreds().getXlocs().getReplicasList().get(0).getStripingPolicy();
if (osdFinalizeVouchersResponseList.size() != sp.getWidth()) {
throw new UserException(POSIXErrno.POSIX_ERROR_EINVAL, cvRequest
+ " has a mismach for the width of the striping policy and the OSDFinalizeVouchersRespone count");
}
// add expire time of xcap
expireTimeSet.add(cap.getExpireMs());
FinalizeVoucherResponseHelper responseHelper = new FinalizeVoucherResponseHelper(master.getConfig()
.getCapabilitySecret());
long newFileSizeMax = -1;
long truncateEpoch = -1;
for (OSDFinalizeVouchersResponse osdFinalizeVouchersResponse : osdFinalizeVouchersResponseList) {
boolean valid = responseHelper.validateSignature(osdFinalizeVouchersResponse, expireTimeSet);
if (!valid) {
throw new UserException(POSIXErrno.POSIX_ERROR_EINVAL, osdFinalizeVouchersResponse
+ " does not have a valid signature");
}
if (truncateEpoch == -1) {
osdFinalizeVouchersResponse.getTruncateEpoch();
} else if (truncateEpoch != osdFinalizeVouchersResponse.getTruncateEpoch()) {
throw new UserException(POSIXErrno.POSIX_ERROR_EINVAL, osdFinalizeVouchersResponse
+ " does not match the truncateEpoch of other responses:" + truncateEpoch);
}
if (osdFinalizeVouchersResponse.getSizeInBytes() > newFileSizeMax) {
newFileSizeMax = osdFinalizeVouchersResponse.getSizeInBytes();
}
}
if (newFileSizeMax == -1) {
throw new UserException(POSIXErrno.POSIX_ERROR_EINVAL,
"The OSDFinalizeVouchersResponse(s) did not contain a valid filesize or valid truncate epoch.");
}
GlobalFileIdResolver globalFileIdResolver = new GlobalFileIdResolver(cap.getFileId());
StorageManager sMan = master.getVolumeManager().getStorageManager(globalFileIdResolver.getVolumeId());
AtomicDBUpdate update = sMan.createAtomicDBUpdate(master, rq);
FileMetadata metadata = sMan.getMetadata(globalFileIdResolver.getLocalFileId());
// check for deleted file
if (metadata != null) {
QuotaFileInformation quotaFileInformation = new QuotaFileInformation(globalFileIdResolver.getVolumeId(),
metadata);
master.getMrcVoucherManager().clearVouchers(quotaFileInformation, cap.getClientIdentity(), expireTimeSet,
newFileSizeMax, update);
}
// TODO(baerhold): update file size for storage
rq.setResponse(emptyResponse.getDefaultInstance());
update.execute();
}
}