@Override
  public void handleDeleteRequest(NetworkRequest request) throws IOException, InterruptedException {
    DeleteRequest deleteRequest;
    if (request instanceof LocalChannelRequest) {
      // This is a case where handleDeleteRequest is called when frontends are talking to Azure. In this case, this method
      // is called by request handler threads running within the frontend router itself. So, the request can be directly
      // referenced as java objects without any need for deserialization.
      deleteRequest = (DeleteRequest) ((LocalChannelRequest) request).getRequestInfo().getRequest();
    } else {
      deleteRequest = DeleteRequest.readFrom(new DataInputStream(request.getInputStream()), clusterMap);
    }
    long requestQueueTime = SystemTime.getInstance().milliseconds() - request.getStartTimeInMs();
    long totalTimeSpent = requestQueueTime;
    long startTime = SystemTime.getInstance().milliseconds();
    DeleteResponse response;
    MessageInfo info = null;
    StoreKey convertedStoreKey = null;
    Store storeToDelete = null;
    ServerErrorCode serverErrorCode = ServerErrorCode.NoError;
    try {
      convertedStoreKey = getConvertedStoreKeys(Collections.singletonList(deleteRequest.getBlobId())).get(0);
      serverErrorCode =
          validateRequest(deleteRequest.getBlobId().getPartition(), RequestOrResponseType.DeleteRequest, false);
      if (serverErrorCode != ServerErrorCode.NoError) {
        logger.error("Validating delete request failed with error {} for request {}", serverErrorCode, deleteRequest);
      } else {
        BlobId convertedBlobId = (BlobId) convertedStoreKey;
        info = new MessageInfo.Builder(convertedBlobId, -1, convertedBlobId.getAccountId(),
            convertedBlobId.getContainerId(), deleteRequest.getDeletionTimeInMs()).isDeleted(true)
            .lifeVersion(MessageInfo.LIFE_VERSION_FROM_FRONTEND)
            .build();
        storeToDelete = storeManager.getStore(deleteRequest.getBlobId().getPartition());
        storeToDelete.delete(Collections.singletonList(info));
      }
    } catch (StoreException e) {
      if (e.getErrorCode() == StoreErrorCodes.IDNotFound && deleteRequest.shouldForceDelete()) {
        // If frontend forces a delete operation, place a tombstone even though blob is not present
        serverErrorCode = maybeForceDelete(info, storeToDelete);
      } else {
        serverErrorCode = ErrorMapping.getStoreErrorMapping(e.getErrorCode());
      }
      if (serverErrorCode != ServerErrorCode.NoError) {
        boolean logInErrorLevel = false;
        if (serverErrorCode == ServerErrorCode.BlobNotFound) {
          metrics.idNotFoundError.inc();
        } else if (serverErrorCode == ServerErrorCode.BlobExpired) {
          metrics.ttlExpiredError.inc();
        } else if (serverErrorCode == ServerErrorCode.BlobDeleted) {
          metrics.idDeletedError.inc();
        } else if (serverErrorCode == ServerErrorCode.BlobAuthorizationFailure) {
          metrics.deleteAuthorizationFailure.inc();
        } else {
          logInErrorLevel = true;
          metrics.unExpectedStoreDeleteError.inc();
        }
        if (logInErrorLevel) {
          logger.error("Store exception on a delete with error code {} for request {}", e.getErrorCode(), deleteRequest,
              e);
        } else {
          logger.trace("Store exception on a delete with error code {} for request {}", e.getErrorCode(), deleteRequest,
              e);
        }
      }
    } catch (Exception e) {
      logger.error("Unknown exception for delete request {}", deleteRequest, e);
      serverErrorCode = ServerErrorCode.UnknownError;
      metrics.unExpectedStoreDeleteError.inc();
    } finally {
      response = new DeleteResponse(deleteRequest.getCorrelationId(), deleteRequest.getClientId(), serverErrorCode);
      long processingTime = SystemTime.getInstance().milliseconds() - startTime;
      totalTimeSpent += processingTime;
      publicAccessLogger.info("{} {} processingTime {}", deleteRequest, response, processingTime);
      // Update request metrics.
      RequestMetricsUpdater metricsUpdater = new RequestMetricsUpdater(requestQueueTime, processingTime, 0, 0, false);
      deleteRequest.accept(metricsUpdater);
      if (serverErrorCode == ServerErrorCode.NoError) {
        if (notification != null) {
          notification.onBlobReplicaDeleted(currentNode.getHostname(), currentNode.getPort(),
              Objects.requireNonNull(convertedStoreKey).getID(), BlobReplicaSourceType.PRIMARY);
        }
      }
    }
    requestResponseChannel.sendResponse(response, request,
        new ServerNetworkResponseMetrics(metrics.deleteBlobResponseQueueTimeInMs, metrics.deleteBlobSendTimeInMs,
            metrics.deleteBlobTotalTimeInMs, null, null, totalTimeSpent));
  }
The main request implementation class. All requests to the server are
handled by this class
ambry-server/src/main/java/com/github/ambry/server/AmbryRequests.java