protected void applyDelete(MessageInfo messageInfo, RemoteReplicaInfo remoteReplicaInfo) throws StoreException {
    DataNodeId remoteNode = remoteReplicaInfo.getReplicaId().getDataNodeId();
    try {
      messageInfo = new MessageInfo.Builder(messageInfo).isDeleted(true).isUndeleted(false).build();
      remoteReplicaInfo.getLocalStore().delete(Collections.singletonList(messageInfo));
      logger.trace("Remote node: {} Thread name: {} Remote replica: {} Key delete: {}", remoteNode, threadName,
          remoteReplicaInfo.getReplicaId(), messageInfo.getStoreKey());
    } catch (StoreException e) {
      // The blob may be deleted or updated which is alright
      if (e.getErrorCode() == StoreErrorCodes.IDDeleted || e.getErrorCode() == StoreErrorCodes.LifeVersionConflict) {
        logger.trace("Remote node: {} Thread name: {} Remote replica: {} Key {}: {}", remoteNode, threadName,
            remoteReplicaInfo.getReplicaId(), messageInfo.getStoreKey(), e.getErrorCode().name());
      } else {
        throw e;
      }
    }
    // A Repair event for Delete signifies that a Delete message was received from the remote and it is fired
    // as long as the Delete is guaranteed to have taken effect locally.
    if (notification != null) {
      notification.onBlobReplicaDeleted(dataNodeId.getHostname(), dataNodeId.getPort(),
          messageInfo.getStoreKey().getID(), BlobReplicaSourceType.REPAIRED);
    }
  }
Applies a delete to the blob described by {@code messageInfo}.
@param messageInfo the {@link MessageInfo} that will be transformed into a delete
@param remoteReplicaInfo The remote replica that is being replicated from
@throws StoreException
ambry-replication/src/main/java/com/github/ambry/replication/ReplicaThread.java