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;
}
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();
}
}
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);
}
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();
}
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)));
}
}
Aggregations