Search in sources :

Example 6 with PartitionResponseInfo

use of com.github.ambry.protocol.PartitionResponseInfo in project ambry by linkedin.

the class AmbryServerRequestsTest method sendAndVerifyOperationRequest.

/**
 * Sends and verifies that an operation specific request works correctly.
 * @param request the {@link NetworkRequest} to send to {@link AmbryRequests}
 * @param expectedErrorCode the {@link ServerErrorCode} expected in the response. For some requests this is the
 *                          response in the constituents rather than the actual response ({@link GetResponse} and
 *                          {@link ReplicaMetadataResponse}).
 * @param forceCheckOpReceived if {@code true}, checks the operation received at the {@link Store} even if
 *                             there is an error expected. Always checks op received if {@code expectedErrorCode} is
 *                             {@link ServerErrorCode#No_Error}. Skips the check otherwise.
 * @throws InterruptedException
 * @throws IOException
 * @return the response associated with given request.
 */
private Response sendAndVerifyOperationRequest(RequestOrResponse request, ServerErrorCode expectedErrorCode, Boolean forceCheckOpReceived) throws InterruptedException, IOException {
    storageManager.resetStore();
    RequestOrResponseType requestType = request.getRequestType();
    Response response = sendRequestGetResponse(request, EnumSet.of(RequestOrResponseType.GetRequest, RequestOrResponseType.ReplicaMetadataRequest).contains(requestType) ? ServerErrorCode.No_Error : expectedErrorCode);
    if (expectedErrorCode.equals(ServerErrorCode.No_Error) || (forceCheckOpReceived && !expectedErrorCode.equals(ServerErrorCode.Temporarily_Disabled))) {
        assertEquals("Operation received at the store not as expected", requestType, MockStorageManager.operationReceived);
    }
    if (requestType == RequestOrResponseType.GetRequest) {
        GetResponse getResponse = (GetResponse) response;
        for (PartitionResponseInfo info : getResponse.getPartitionResponseInfoList()) {
            assertEquals("Error code does not match expected", expectedErrorCode, info.getErrorCode());
        }
    } else if (requestType == RequestOrResponseType.ReplicaMetadataRequest) {
        ReplicaMetadataResponse replicaMetadataResponse = (ReplicaMetadataResponse) response;
        for (ReplicaMetadataResponseInfo info : replicaMetadataResponse.getReplicaMetadataResponseInfoList()) {
            assertEquals("Error code does not match expected", expectedErrorCode, info.getError());
        }
    }
    return response;
}
Also used : CatchupStatusAdminResponse(com.github.ambry.protocol.CatchupStatusAdminResponse) Response(com.github.ambry.protocol.Response) GetResponse(com.github.ambry.protocol.GetResponse) ReplicaMetadataResponse(com.github.ambry.protocol.ReplicaMetadataResponse) AdminResponse(com.github.ambry.protocol.AdminResponse) RequestOrResponse(com.github.ambry.protocol.RequestOrResponse) ReplicaMetadataResponse(com.github.ambry.protocol.ReplicaMetadataResponse) AdminRequestOrResponseType(com.github.ambry.protocol.AdminRequestOrResponseType) RequestOrResponseType(com.github.ambry.protocol.RequestOrResponseType) ReplicaMetadataResponseInfo(com.github.ambry.protocol.ReplicaMetadataResponseInfo) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) GetResponse(com.github.ambry.protocol.GetResponse)

Example 7 with PartitionResponseInfo

use of com.github.ambry.protocol.PartitionResponseInfo in project ambry by linkedin.

the class AmbryServerRequestsTest method sendAndVerifyGetOriginalStoreKeys.

/**
 * Sends and verifies that GetRequest with a list of original blobIds works correctly.
 * @param blobIds List of blobIds for GetRequest.
 * @param expectedErrorCode the {@link ServerErrorCode} expected in the response.
 * @throws InterruptedException
 * @throws IOException
 */
private void sendAndVerifyGetOriginalStoreKeys(List<BlobId> blobIds, ServerErrorCode expectedErrorCode) throws InterruptedException, IOException {
    PartitionId partitionId = blobIds.get(0).getPartition();
    int correlationId = blobIds.get(0).getContainerId();
    String clientId = TestUtils.getRandomString(10);
    PartitionRequestInfo pRequestInfo = new PartitionRequestInfo(partitionId, blobIds);
    RequestOrResponse request = new GetRequest(correlationId, clientId, MessageFormatFlags.All, Collections.singletonList(pRequestInfo), GetOption.Include_All);
    storageManager.resetStore();
    if (!expectedErrorCode.equals(ServerErrorCode.Unknown_Error)) {
        // known error will be filled to each PartitionResponseInfo and set ServerErrorCode.No_Error in response.
        Response response = sendRequestGetResponse(request, ServerErrorCode.No_Error);
        assertEquals("Operation received at the store not as expected", RequestOrResponseType.GetRequest, MockStorageManager.operationReceived);
        for (PartitionResponseInfo info : ((GetResponse) response).getPartitionResponseInfoList()) {
            assertEquals("Error code does not match expected", expectedErrorCode, info.getErrorCode());
        }
        response.release();
    } else {
        sendRequestGetResponse(request, ServerErrorCode.Unknown_Error).release();
    }
}
Also used : CatchupStatusAdminResponse(com.github.ambry.protocol.CatchupStatusAdminResponse) Response(com.github.ambry.protocol.Response) GetResponse(com.github.ambry.protocol.GetResponse) ReplicaMetadataResponse(com.github.ambry.protocol.ReplicaMetadataResponse) AdminResponse(com.github.ambry.protocol.AdminResponse) RequestOrResponse(com.github.ambry.protocol.RequestOrResponse) RequestOrResponse(com.github.ambry.protocol.RequestOrResponse) GetRequest(com.github.ambry.protocol.GetRequest) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) MockPartitionId(com.github.ambry.clustermap.MockPartitionId) PartitionId(com.github.ambry.clustermap.PartitionId) PartitionRequestInfo(com.github.ambry.protocol.PartitionRequestInfo) GetResponse(com.github.ambry.protocol.GetResponse)

Example 8 with PartitionResponseInfo

use of com.github.ambry.protocol.PartitionResponseInfo in project ambry by linkedin.

the class ReplicaThread method writeMessagesToLocalStoreAndAdvanceTokens.

/**
 * Writes the messages (if any) to the local stores from the remote stores for the missing keys, and advances tokens.
 * @param exchangeMetadataResponseList The list of metadata response from the remote node
 * @param getResponse The {@link GetResponse} that contains the missing messages. This may be null if there are no
 *                    missing messages to write as per the exchange metadata response. In that case this method will
 *                    simply advance the tokens for every store.
 * @param replicasToReplicatePerNode The list of remote replicas for the remote node
 * @param remoteNode The remote node from which replication needs to happen
 */
private void writeMessagesToLocalStoreAndAdvanceTokens(List<ExchangeMetadataResponse> exchangeMetadataResponseList, GetResponse getResponse, List<RemoteReplicaInfo> replicasToReplicatePerNode, DataNodeId remoteNode) throws IOException {
    int partitionResponseInfoIndex = 0;
    long totalBytesFixed = 0;
    long totalBlobsFixed = 0;
    long startTime = SystemTime.getInstance().milliseconds();
    for (int i = 0; i < exchangeMetadataResponseList.size(); i++) {
        ExchangeMetadataResponse exchangeMetadataResponse = exchangeMetadataResponseList.get(i);
        RemoteReplicaInfo remoteReplicaInfo = replicasToReplicatePerNode.get(i);
        if (exchangeMetadataResponse.serverErrorCode == ServerErrorCode.No_Error) {
            if (exchangeMetadataResponse.missingStoreKeys.size() > 0) {
                PartitionResponseInfo partitionResponseInfo = getResponse.getPartitionResponseInfoList().get(partitionResponseInfoIndex);
                responseHandler.onEvent(remoteReplicaInfo.getReplicaId(), partitionResponseInfo.getErrorCode());
                partitionResponseInfoIndex++;
                if (partitionResponseInfo.getPartition().compareTo(remoteReplicaInfo.getReplicaId().getPartitionId()) != 0) {
                    throw new IllegalStateException("The partition id from partitionResponseInfo " + partitionResponseInfo.getPartition() + " and from remoteReplicaInfo " + remoteReplicaInfo.getReplicaId().getPartitionId() + " are not the same");
                }
                if (partitionResponseInfo.getErrorCode() == ServerErrorCode.No_Error) {
                    try {
                        List<MessageInfo> messageInfoList = partitionResponseInfo.getMessageInfoList();
                        logger.trace("Remote node: {} Thread name: {} Remote replica: {} Messages to fix: {} " + "Partition: {} Local mount path: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId(), exchangeMetadataResponse.missingStoreKeys, remoteReplicaInfo.getReplicaId().getPartitionId(), remoteReplicaInfo.getLocalReplicaId().getMountPath());
                        MessageFormatWriteSet writeset = null;
                        if (validateMessageStream) {
                            MessageSievingInputStream validMessageDetectionInputStream = new MessageSievingInputStream(getResponse.getInputStream(), messageInfoList, storeKeyFactory, metricRegistry);
                            if (validMessageDetectionInputStream.hasInvalidMessages()) {
                                replicationMetrics.incrementInvalidMessageError(partitionResponseInfo.getPartition());
                                logger.error("Out of " + (messageInfoList.size()) + " messages, " + (messageInfoList.size() - validMessageDetectionInputStream.getValidMessageInfoList().size()) + " invalid messages were found in message stream from " + remoteReplicaInfo.getReplicaId());
                            }
                            messageInfoList = validMessageDetectionInputStream.getValidMessageInfoList();
                            if (messageInfoList.size() == 0) {
                                logger.error("MessageInfoList is of size 0 as all messages are invalidated ");
                            } else {
                                writeset = new MessageFormatWriteSet(validMessageDetectionInputStream, messageInfoList, false);
                                remoteReplicaInfo.getLocalStore().put(writeset);
                            }
                        } else {
                            writeset = new MessageFormatWriteSet(getResponse.getInputStream(), messageInfoList, true);
                            remoteReplicaInfo.getLocalStore().put(writeset);
                        }
                        for (MessageInfo messageInfo : messageInfoList) {
                            totalBytesFixed += messageInfo.getSize();
                            logger.trace("Remote node: {} Thread name: {} Remote replica: {} Message replicated: {} Partition: {} " + "Local mount path: {} Message size: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId(), messageInfo.getStoreKey(), remoteReplicaInfo.getReplicaId().getPartitionId(), remoteReplicaInfo.getLocalReplicaId().getMountPath(), messageInfo.getSize());
                            if (notification != null) {
                                notification.onBlobReplicaCreated(dataNodeId.getHostname(), dataNodeId.getPort(), messageInfo.getStoreKey().getID(), BlobReplicaSourceType.REPAIRED);
                            }
                        }
                        totalBlobsFixed += messageInfoList.size();
                        remoteReplicaInfo.setToken(exchangeMetadataResponse.remoteToken);
                        remoteReplicaInfo.setLocalLagFromRemoteInBytes(exchangeMetadataResponse.localLagFromRemoteInBytes);
                        logger.trace("Remote node: {} Thread name: {} Remote replica: {} Token after speaking to remote node: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId(), exchangeMetadataResponse.remoteToken);
                    } catch (StoreException e) {
                        if (e.getErrorCode() != StoreErrorCodes.Already_Exist) {
                            replicationMetrics.updateLocalStoreError(remoteReplicaInfo.getReplicaId());
                            logger.error("Remote node: " + remoteNode + " Thread name: " + threadName + " Remote replica: " + remoteReplicaInfo.getReplicaId(), e);
                        }
                    }
                } else if (partitionResponseInfo.getErrorCode() == ServerErrorCode.Blob_Deleted) {
                    replicationMetrics.blobDeletedOnGetCount.inc();
                    logger.trace("One of the blobs to GET is deleted: Remote node: {} Thread name: {} Remote replica: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId());
                } else {
                    replicationMetrics.updateGetRequestError(remoteReplicaInfo.getReplicaId());
                    logger.error("Remote node: {} Thread name: {} Remote replica: {} Server error: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId(), partitionResponseInfo.getErrorCode());
                }
            } else {
                // There are no missing keys. We just advance the token
                remoteReplicaInfo.setToken(exchangeMetadataResponse.remoteToken);
                remoteReplicaInfo.setLocalLagFromRemoteInBytes(exchangeMetadataResponse.localLagFromRemoteInBytes);
                logger.trace("Remote node: {} Thread name: {} Remote replica: {} Token after speaking to remote node: {}", remoteNode, threadName, remoteReplicaInfo.getReplicaId(), exchangeMetadataResponse.remoteToken);
            }
        }
    }
    long batchStoreWriteTime = SystemTime.getInstance().milliseconds() - startTime;
    replicationMetrics.updateBatchStoreWriteTime(batchStoreWriteTime, totalBytesFixed, totalBlobsFixed, replicatingFromRemoteColo, replicatingOverSsl, datacenterName);
}
Also used : MessageSievingInputStream(com.github.ambry.messageformat.MessageSievingInputStream) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) MessageInfo(com.github.ambry.store.MessageInfo) MessageFormatWriteSet(com.github.ambry.messageformat.MessageFormatWriteSet) StoreException(com.github.ambry.store.StoreException)

Example 9 with PartitionResponseInfo

use of com.github.ambry.protocol.PartitionResponseInfo in project ambry by linkedin.

the class InMemoryCloudDestinationErrorSimulationTest method testGetBlobErrorSimulation.

/**
 * test error simulation for GetBlobRequest
 * @throws Exception
 */
@Test
public void testGetBlobErrorSimulation() throws Exception {
    BlobId blobId = doPut(partitionId);
    ArrayList<BlobId> blobIdList = new ArrayList<BlobId>();
    blobIdList.add(blobId);
    PartitionRequestInfo partitionRequestInfo = new PartitionRequestInfo(partitionId, blobIdList);
    ArrayList<PartitionRequestInfo> partitionRequestInfoList = new ArrayList<PartitionRequestInfo>();
    partitionRequestInfoList.add(partitionRequestInfo);
    GetRequest getRequest = new GetRequest(1234, "clientId", MessageFormatFlags.Blob, partitionRequestInfoList, GetOption.None);
    RequestInfo requestInfo = new RequestInfo(hostname, port, getRequest, replica, null);
    ResponseInfo responseInfo = sendAndWaitForResponses(requestInfo);
    GetResponse response = responseInfo.getError() == null ? (GetResponse) RouterUtils.mapToReceivedResponse((Response) responseInfo.getResponse()) : null;
    PartitionResponseInfo partitionResponseInfo = response.getPartitionResponseInfoList().get(0);
    Assert.assertEquals("GetRequest should succeed.", response.getError(), ServerErrorCode.No_Error);
    Assert.assertEquals("GetRequest partitionResponseInfo should succeed.", partitionResponseInfo.getErrorCode(), ServerErrorCode.No_Error);
    responseInfo.release();
    // inject error for cloud colo.
    cloudDestination.setServerErrorForAllRequests(StoreErrorCodes.ID_Not_Found);
    getRequest = new GetRequest(1234, "clientId", MessageFormatFlags.Blob, partitionRequestInfoList, GetOption.None);
    requestInfo = new RequestInfo(hostname, port, getRequest, replica, null);
    responseInfo = sendAndWaitForResponses(requestInfo);
    response = responseInfo.getError() == null ? (GetResponse) RouterUtils.mapToReceivedResponse((Response) responseInfo.getResponse()) : null;
    partitionResponseInfo = response.getPartitionResponseInfoList().get(0);
    Assert.assertEquals("GetRequest responseInfo should have no error.", response.getError(), ServerErrorCode.No_Error);
    Assert.assertEquals("GetRequest partitionResponseInfo should be Blob_Not_Found", partitionResponseInfo.getErrorCode(), ServerErrorCode.Blob_Not_Found);
    responseInfo.release();
}
Also used : ResponseInfo(com.github.ambry.network.ResponseInfo) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) GetResponse(com.github.ambry.protocol.GetResponse) TtlUpdateResponse(com.github.ambry.protocol.TtlUpdateResponse) UndeleteResponse(com.github.ambry.protocol.UndeleteResponse) DeleteResponse(com.github.ambry.protocol.DeleteResponse) PutResponse(com.github.ambry.protocol.PutResponse) Response(com.github.ambry.protocol.Response) GetRequest(com.github.ambry.protocol.GetRequest) ArrayList(java.util.ArrayList) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) PartitionRequestInfo(com.github.ambry.protocol.PartitionRequestInfo) PartitionRequestInfo(com.github.ambry.protocol.PartitionRequestInfo) RequestInfo(com.github.ambry.network.RequestInfo) BlobId(com.github.ambry.commons.BlobId) GetResponse(com.github.ambry.protocol.GetResponse) Test(org.junit.Test)

Example 10 with PartitionResponseInfo

use of com.github.ambry.protocol.PartitionResponseInfo in project ambry by linkedin.

the class GetBlobInfoOperation method processGetBlobInfoResponse.

/**
 * Process the {@link GetResponse} extracted from a {@link ResponseInfo}
 * @param getRequestInfo the associated {@link GetRequestInfo} for which this response was received.
 * @param getResponse the {@link GetResponse} extracted from the {@link ResponseInfo}
 * @throws IOException if there is an error during deserialization of the GetResponse.
 * @throws MessageFormatException if there is an error during deserialization of the GetResponse.
 */
private void processGetBlobInfoResponse(GetRequestInfo getRequestInfo, GetResponse getResponse) throws IOException, MessageFormatException {
    ServerErrorCode getError = getResponse.getError();
    if (getError == ServerErrorCode.No_Error) {
        int partitionsInResponse = getResponse.getPartitionResponseInfoList().size();
        // Each get request issued by the router is for a single blob.
        if (partitionsInResponse != 1) {
            onErrorResponse(getRequestInfo.replicaId, new RouterException("Unexpected number of partition responses, expected: 1, " + "received: " + partitionsInResponse, RouterErrorCode.UnexpectedInternalError));
        // Again, no need to notify the responseHandler.
        } else {
            getError = getResponse.getPartitionResponseInfoList().get(0).getErrorCode();
            if (getError == ServerErrorCode.No_Error) {
                PartitionResponseInfo partitionResponseInfo = getResponse.getPartitionResponseInfoList().get(0);
                int msgsInResponse = partitionResponseInfo.getMessageInfoList().size();
                if (msgsInResponse != 1) {
                    onErrorResponse(getRequestInfo.replicaId, new RouterException("Unexpected number of messages in a partition response, expected: 1, " + "received: " + msgsInResponse, RouterErrorCode.UnexpectedInternalError));
                } else {
                    MessageMetadata messageMetadata = partitionResponseInfo.getMessageMetadataList().get(0);
                    MessageInfo messageInfo = partitionResponseInfo.getMessageInfoList().get(0);
                    handleBody(getResponse.getInputStream(), messageMetadata, messageInfo);
                    operationTracker.onResponse(getRequestInfo.replicaId, TrackedRequestFinalState.SUCCESS);
                    if (RouterUtils.isRemoteReplica(routerConfig, getRequestInfo.replicaId)) {
                        logger.trace("Cross colo request successful for remote replica in {} ", getRequestInfo.replicaId.getDataNodeId().getDatacenterName());
                        routerMetrics.crossColoSuccessCount.inc();
                    }
                }
            } else {
                // process and set the most relevant exception.
                logger.trace("Replica  {} returned error {} with response correlationId {} ", getRequestInfo.replicaId.getDataNodeId(), getError, getResponse.getCorrelationId());
                RouterErrorCode routerErrorCode = processServerError(getError);
                if (getError == ServerErrorCode.Disk_Unavailable) {
                    operationTracker.onResponse(getRequestInfo.replicaId, TrackedRequestFinalState.DISK_DOWN);
                    setOperationException(new RouterException("Server returned: " + getError, routerErrorCode));
                    routerMetrics.routerRequestErrorCount.inc();
                    routerMetrics.getDataNodeBasedMetrics(getRequestInfo.replicaId.getDataNodeId()).getBlobInfoRequestErrorCount.inc();
                } else {
                    if (getError == ServerErrorCode.Blob_Deleted || getError == ServerErrorCode.Blob_Expired || getError == ServerErrorCode.Blob_Authorization_Failure) {
                        // this is a successful response and one that completes the operation regardless of whether the
                        // success target has been reached or not.
                        operationCompleted = true;
                    }
                    // any server error code that is not equal to ServerErrorCode.No_Error, the onErrorResponse should be invoked
                    // because the operation itself doesn't succeed although the response in some cases is successful (i.e. Blob_Deleted)
                    onErrorResponse(getRequestInfo.replicaId, new RouterException("Server returned: " + getError, routerErrorCode));
                }
            }
        }
    } else {
        logger.trace("Replica {} returned an error {} for a GetBlobInfoRequest with response correlationId : {} ", getRequestInfo.replicaId.getDataNodeId(), getError, getResponse.getCorrelationId());
        onErrorResponse(getRequestInfo.replicaId, new RouterException("Server returned", processServerError(getError)));
    }
}
Also used : MessageMetadata(com.github.ambry.messageformat.MessageMetadata) PartitionResponseInfo(com.github.ambry.protocol.PartitionResponseInfo) ServerErrorCode(com.github.ambry.server.ServerErrorCode) MessageInfo(com.github.ambry.store.MessageInfo)

Aggregations

PartitionResponseInfo (com.github.ambry.protocol.PartitionResponseInfo)12 GetResponse (com.github.ambry.protocol.GetResponse)9 PartitionRequestInfo (com.github.ambry.protocol.PartitionRequestInfo)8 GetRequest (com.github.ambry.protocol.GetRequest)7 MessageInfo (com.github.ambry.store.MessageInfo)6 Response (com.github.ambry.protocol.Response)5 BlobId (com.github.ambry.commons.BlobId)4 ArrayList (java.util.ArrayList)4 AdminResponse (com.github.ambry.protocol.AdminResponse)3 CatchupStatusAdminResponse (com.github.ambry.protocol.CatchupStatusAdminResponse)3 ReplicaMetadataResponse (com.github.ambry.protocol.ReplicaMetadataResponse)3 RequestOrResponse (com.github.ambry.protocol.RequestOrResponse)3 StoreException (com.github.ambry.store.StoreException)3 PartitionId (com.github.ambry.clustermap.PartitionId)2 ReplicationConfig (com.github.ambry.config.ReplicationConfig)2 VerifiableProperties (com.github.ambry.config.VerifiableProperties)2 BlobProperties (com.github.ambry.messageformat.BlobProperties)2 MessageFormatException (com.github.ambry.messageformat.MessageFormatException)2 MessageFormatWriteSet (com.github.ambry.messageformat.MessageFormatWriteSet)2 MessageMetadata (com.github.ambry.messageformat.MessageMetadata)2