/* * Copyright (c) 2009-2011 by Bjoern Kolbeck, * Zuse Institute Berlin * * Licensed under the BSD License, see LICENSE file for details. * */ package org.xtreemfs.osd.operations; import java.io.IOException; import java.util.List; import org.xtreemfs.common.Capability; import org.xtreemfs.common.ReplicaUpdatePolicies; import org.xtreemfs.common.uuids.ServiceUUID; import org.xtreemfs.common.xloc.InvalidXLocationsException; import org.xtreemfs.common.xloc.Replica; import org.xtreemfs.common.xloc.XLocations; import org.xtreemfs.foundation.pbrpc.client.RPCAuthentication; import org.xtreemfs.foundation.pbrpc.client.RPCResponse; 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.OpenFileTable.OpenFileTableEntry; import org.xtreemfs.osd.operations.EventCloseFile.EventCloseCallback; import org.xtreemfs.osd.stages.DeletionStage.DeleteObjectsCallback; import org.xtreemfs.osd.stages.PreprocStage.CloseCallback; import org.xtreemfs.osd.stages.PreprocStage.DeleteOnCloseCallback; import org.xtreemfs.pbrpc.generatedinterfaces.OSD.unlink_osd_Request; import org.xtreemfs.pbrpc.generatedinterfaces.OSDServiceConstants; public final class DeleteOperation extends OSDOperation { final String sharedSecret; final ServiceUUID localUUID; public DeleteOperation(OSDRequestDispatcher master) { super(master); sharedSecret = master.getConfig().getCapabilitySecret(); localUUID = master.getConfig().getUUID(); } @Override public int getProcedureId() { return OSDServiceConstants.PROC_ID_UNLINK; } @Override public void startRequest(final OSDRequest rq) { final unlink_osd_Request args = (unlink_osd_Request) rq.getRequestArgs(); // If the file is open, the deleteOnClose flag will be set. master.getPreprocStage().checkDeleteOnClose(args.getFileId(), new DeleteOnCloseCallback() { @Override public void deleteOnCloseResult(boolean isDeleteOnClose, ErrorResponse error) { closeFileIfNecessary(rq, isDeleteOnClose, args, error); } }); } public void closeFileIfNecessary(final OSDRequest rq, final boolean isDeleteOnClose, final unlink_osd_Request args, final ErrorResponse error) { if (error != null) { rq.sendError(error); return; } if (!isDeleteOnClose) { // File is not open and can be deleted immediately. // Cancel replication of file if (ReplicaUpdatePolicies.isRO(rq.getLocationList().getReplicaUpdatePolicy())) master.getReplicationStage().cancelReplicationForFile(args.getFileId()); master.getDeletionStage().deleteObjects(args.getFileId(), null, rq.getCowPolicy().cowEnabled(), rq, false, new DeleteObjectsCallback() { @Override public void deleteComplete(ErrorResponse error) { disseminateDeletesIfNecessary(rq, args, error); } }); } else { // Close the file explicitly. master.getPreprocStage().close(args.getFileId(), new CloseCallback() { @Override public void closeResult(OpenFileTableEntry entry, ErrorResponse error) { // Send close event. // This will create new versions if necessary and delete objects (because deleteOnClose is set). OSDOperation closeEvent = master.getInternalEvent(EventCloseFile.class); closeEvent.startInternalEvent(new Object[] { entry.getFileId(), true, entry.getCowPolicy().cowEnabled(), entry.isWrite(), new EventCloseCallback() { @Override public void closeEventResult(ErrorResponse error) { disseminateDeletesIfNecessary(rq, args, error); } } }); } }); } } public void disseminateDeletesIfNecessary(final OSDRequest rq, final unlink_osd_Request args, final ErrorResponse error) { if (error != null) { rq.sendError(error); return; } final Replica localReplica = rq.getLocationList().getLocalReplica(); if (localReplica.isStriped() && localReplica.getHeadOsd().equals(localUUID)) { // striped replica, dissmeninate unlink requests try { final List<ServiceUUID> osds = rq.getLocationList().getLocalReplica().getOSDs(); final RPCResponse[] gmaxRPCs = new RPCResponse[osds.size() - 1]; int cnt = 0; for (ServiceUUID osd : osds) { if (!osd.equals(localUUID)) { gmaxRPCs[cnt++] = master.getOSDClient().unlink(osd.getAddress(), RPCAuthentication.authNone, RPCAuthentication.userService, args.getFileCredentials(), args.getFileId()); } } this.waitForResponses(gmaxRPCs, new ResponsesListener() { @Override public void responsesAvailable() { analyzeUnlinkReponses(rq, gmaxRPCs); } }); } catch (IOException ex) { rq.sendInternalServerError(ex); return; } } else { // non striped replica, fini sendResponse(rq); } } public void analyzeUnlinkReponses(final OSDRequest rq, RPCResponse[] gmaxRPCs) { // analyze results try { for (int i = 0; i < gmaxRPCs.length; i++) { gmaxRPCs[i].get(); } sendResponse(rq); } catch (Exception ex) { rq.sendInternalServerError(ex); } finally { for (RPCResponse r : gmaxRPCs) r.freeBuffers(); } } public void sendResponse(OSDRequest rq) { rq.sendSuccess(null, null); } @Override public ErrorResponse parseRPCMessage(OSDRequest rq) { try { unlink_osd_Request rpcrq = (unlink_osd_Request) rq.getRequestArgs(); rq.setFileId(rpcrq.getFileId()); rq.setCapability(new Capability(rpcrq.getFileCredentials().getXcap(), sharedSecret)); rq.setLocationList(new XLocations(rpcrq.getFileCredentials().getXlocs(), localUUID)); 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() { // Object deletion occurs for one thing if a file is unlinked, which does also delete its metadata like the // xLocSet. Therefore it is possible to bypass validation: No more Operation will be possible after a file has // been unlinked. // And it occurs for another thing if a replica is removed. In that case only the objects on the removed replica // will be deleted. It is necessary to bypass validation in that case, because the replica is invalidated and no // longer part of the new view. return true; } @Override public void startInternalEvent(Object[] args) { throw new UnsupportedOperationException("Not supported yet."); } }