use of com.github.ambry.clustermap.ReplicaType in project ambry by linkedin.
the class CompositeNetworkClient method sendAndPoll.
@Override
public List<ResponseInfo> sendAndPoll(List<RequestInfo> allRequestsToSend, Set<Integer> allRequestsToDrop, int pollTimeoutMs) {
// prepare lists of requests to send and drop
EnumMap<ReplicaType, List<RequestInfo>> requestsToSendByType = new EnumMap<>(ReplicaType.class);
EnumMap<ReplicaType, Set<Integer>> requestsToDropByType = new EnumMap<>(ReplicaType.class);
for (ReplicaType replicaType : childNetworkClients.keySet()) {
requestsToSendByType.put(replicaType, new ArrayList<>());
requestsToDropByType.put(replicaType, new HashSet<>());
}
for (RequestInfo requestInfo : allRequestsToSend) {
ReplicaType replicaType = requestInfo.getReplicaId().getReplicaType();
List<RequestInfo> requestsToSend = requestsToSendByType.get(replicaType);
if (requestsToSend == null) {
throw new IllegalStateException("No NetworkClient configured for replica type: " + replicaType);
}
requestsToSend.add(requestInfo);
correlationIdToReplicaType.put(requestInfo.getRequest().getCorrelationId(), replicaType);
}
for (Integer correlationId : allRequestsToDrop) {
ReplicaType replicaType = correlationIdToReplicaType.get(correlationId);
if (replicaType != null) {
requestsToDropByType.get(replicaType).add(correlationId);
}
}
// send requests using child clients from background threads so that inactive clients do not block the other client
// from making progress.
AtomicBoolean wakeupCalled = new AtomicBoolean(false);
ArrayList<Future<List<ResponseInfo>>> sendAndPollFutures = new ArrayList<>(childNetworkClients.size());
childNetworkClients.forEach((replicaType, client) -> {
List<RequestInfo> requestsToSend = requestsToSendByType.get(replicaType);
Set<Integer> requestsToDrop = requestsToDropByType.get(replicaType);
if (!requestsToSend.isEmpty() || !requestsToDrop.isEmpty()) {
logger.trace("replicaType={}, requestsToSend={}, requestsToDrop={}", replicaType, requestsToSend, requestsToDrop);
}
sendAndPollFutures.add(executor.submit(() -> {
List<ResponseInfo> childClientResponses = client.sendAndPoll(requestsToSend, requestsToDrop, pollTimeoutMs);
if (wakeupCalled.compareAndSet(false, true)) {
// the client that gets a response first can wake up the other clients so that they do not waste time waiting
// for the poll timeout to expire. This helps when one child client is very active and the others have very
// little activity.
childNetworkClients.values().stream().filter(c -> c != client).forEach(NetworkClient::wakeup);
}
return childClientResponses;
}));
});
// process responses returned by each child client
List<ResponseInfo> responses = new ArrayList<>();
for (Future<List<ResponseInfo>> future : sendAndPollFutures) {
try {
List<ResponseInfo> responseInfoList = future.get();
for (ResponseInfo responseInfo : responseInfoList) {
// clean up correlation ids for completed requests
if (responseInfo.getRequestInfo() != null) {
correlationIdToReplicaType.remove(responseInfo.getRequestInfo().getRequest().getCorrelationId());
}
responses.add(responseInfo);
}
} catch (InterruptedException | ExecutionException e) {
logger.error("Hit unexpected exception on parallel sendAndPoll.", e);
}
}
return responses;
}
use of com.github.ambry.clustermap.ReplicaType in project ambry by linkedin.
the class AmbryRequests method handleReplicaMetadataRequest.
@Override
public void handleReplicaMetadataRequest(NetworkRequest request) throws IOException, InterruptedException {
if (replicationEngine == null) {
throw new UnsupportedOperationException("Replication not supported on this node.");
}
ReplicaMetadataRequest replicaMetadataRequest = ReplicaMetadataRequest.readFrom(new DataInputStream(request.getInputStream()), clusterMap, findTokenHelper);
long requestQueueTime = SystemTime.getInstance().milliseconds() - request.getStartTimeInMs();
long totalTimeSpent = requestQueueTime;
metrics.replicaMetadataRequestQueueTimeInMs.update(requestQueueTime);
metrics.replicaMetadataRequestRate.mark();
List<ReplicaMetadataRequestInfo> replicaMetadataRequestInfoList = replicaMetadataRequest.getReplicaMetadataRequestInfoList();
int partitionCnt = replicaMetadataRequestInfoList.size();
long startTimeInMs = SystemTime.getInstance().milliseconds();
ReplicaMetadataResponse response = null;
try {
List<ReplicaMetadataResponseInfo> replicaMetadataResponseList = new ArrayList<>(partitionCnt);
for (ReplicaMetadataRequestInfo replicaMetadataRequestInfo : replicaMetadataRequestInfoList) {
long partitionStartTimeInMs = SystemTime.getInstance().milliseconds();
PartitionId partitionId = replicaMetadataRequestInfo.getPartitionId();
ReplicaType replicaType = replicaMetadataRequestInfo.getReplicaType();
ServerErrorCode error = validateRequest(partitionId, RequestOrResponseType.ReplicaMetadataRequest, false);
logger.trace("{} Time used to validate metadata request: {}", partitionId, (SystemTime.getInstance().milliseconds() - partitionStartTimeInMs));
if (error != ServerErrorCode.No_Error) {
logger.error("Validating replica metadata request failed with error {} for partition {}", error, partitionId);
ReplicaMetadataResponseInfo replicaMetadataResponseInfo = new ReplicaMetadataResponseInfo(partitionId, replicaType, error, ReplicaMetadataResponse.getCompatibleResponseVersion(replicaMetadataRequest.getVersionId()));
replicaMetadataResponseList.add(replicaMetadataResponseInfo);
} else {
try {
FindToken findToken = replicaMetadataRequestInfo.getToken();
String hostName = replicaMetadataRequestInfo.getHostName();
String replicaPath = replicaMetadataRequestInfo.getReplicaPath();
Store store = storeManager.getStore(partitionId);
partitionStartTimeInMs = SystemTime.getInstance().milliseconds();
FindInfo findInfo = store.findEntriesSince(findToken, replicaMetadataRequest.getMaxTotalSizeOfEntriesInBytes(), hostName, replicaPath);
logger.trace("{} Time used to find entry since: {}", partitionId, (SystemTime.getInstance().milliseconds() - partitionStartTimeInMs));
partitionStartTimeInMs = SystemTime.getInstance().milliseconds();
long totalBytesRead = findInfo.getFindToken().getBytesRead();
replicationEngine.updateTotalBytesReadByRemoteReplica(partitionId, hostName, replicaPath, totalBytesRead);
logger.trace("{} Time used to update total bytes read: {}", partitionId, (SystemTime.getInstance().milliseconds() - partitionStartTimeInMs));
partitionStartTimeInMs = SystemTime.getInstance().milliseconds();
logger.trace("{} Time used to get remote replica lag in bytes: {}", partitionId, (SystemTime.getInstance().milliseconds() - partitionStartTimeInMs));
ReplicaMetadataResponseInfo replicaMetadataResponseInfo = new ReplicaMetadataResponseInfo(partitionId, replicaType, findInfo.getFindToken(), findInfo.getMessageEntries(), getRemoteReplicaLag(store, totalBytesRead), ReplicaMetadataResponse.getCompatibleResponseVersion(replicaMetadataRequest.getVersionId()));
if (replicaMetadataResponseInfo.getTotalSizeOfAllMessages() > 5 * replicaMetadataRequest.getMaxTotalSizeOfEntriesInBytes()) {
logger.debug("{} generated a metadata response {} where the cumulative size of messages is {}", replicaMetadataRequest, replicaMetadataResponseInfo, replicaMetadataResponseInfo.getTotalSizeOfAllMessages());
metrics.replicationResponseMessageSizeTooHigh.inc();
}
replicaMetadataResponseList.add(replicaMetadataResponseInfo);
metrics.replicaMetadataTotalSizeOfMessages.update(replicaMetadataResponseInfo.getTotalSizeOfAllMessages());
} catch (StoreException e) {
logger.error("Store exception on a replica metadata request with error code {} for partition {}", e.getErrorCode(), partitionId, e);
if (e.getErrorCode() == StoreErrorCodes.IOError) {
metrics.storeIOError.inc();
} else {
metrics.unExpectedStoreFindEntriesError.inc();
}
ReplicaMetadataResponseInfo replicaMetadataResponseInfo = new ReplicaMetadataResponseInfo(partitionId, replicaType, ErrorMapping.getStoreErrorMapping(e.getErrorCode()), ReplicaMetadataResponse.getCompatibleResponseVersion(replicaMetadataRequest.getVersionId()));
replicaMetadataResponseList.add(replicaMetadataResponseInfo);
}
}
}
response = new ReplicaMetadataResponse(replicaMetadataRequest.getCorrelationId(), replicaMetadataRequest.getClientId(), ServerErrorCode.No_Error, replicaMetadataResponseList, ReplicaMetadataResponse.getCompatibleResponseVersion(replicaMetadataRequest.getVersionId()));
} catch (Exception e) {
logger.error("Unknown exception for request {}", replicaMetadataRequest, e);
response = new ReplicaMetadataResponse(replicaMetadataRequest.getCorrelationId(), replicaMetadataRequest.getClientId(), ServerErrorCode.Unknown_Error, ReplicaMetadataResponse.getCompatibleResponseVersion(replicaMetadataRequest.getVersionId()));
} finally {
long processingTime = SystemTime.getInstance().milliseconds() - startTimeInMs;
totalTimeSpent += processingTime;
publicAccessLogger.info("{} {} processingTime {}", replicaMetadataRequest, response, processingTime);
logger.trace("{} {} processingTime {}", replicaMetadataRequest, response, processingTime);
metrics.replicaMetadataRequestProcessingTimeInMs.update(processingTime);
// client id now has dc name at the end, for example: ClientId=replication-metadata-abc.example.com[dc1]
String[] clientStrs = replicaMetadataRequest.getClientId().split("\\[");
if (clientStrs.length > 1) {
String clientDc = clientStrs[1].substring(0, clientStrs[1].length() - 1);
if (!currentNode.getDatacenterName().equals(clientDc)) {
metrics.updateCrossColoMetadataExchangeBytesRate(clientDc, response != null ? response.sizeInBytes() : 0L);
}
}
}
requestResponseChannel.sendResponse(response, request, new ServerNetworkResponseMetrics(metrics.replicaMetadataResponseQueueTimeInMs, metrics.replicaMetadataSendTimeInMs, metrics.replicaMetadataTotalTimeInMs, null, null, totalTimeSpent));
}
use of com.github.ambry.clustermap.ReplicaType in project ambry by linkedin.
the class ReplicaMetadataRequestInfo method readFrom.
public static ReplicaMetadataRequestInfo readFrom(DataInputStream stream, ClusterMap clusterMap, FindTokenHelper findTokenHelper, short requestVersion) throws IOException {
String hostName = Utils.readIntString(stream);
String replicaPath = Utils.readIntString(stream);
ReplicaType replicaType;
if (requestVersion == ReplicaMetadataRequest.Replica_Metadata_Request_Version_V2) {
replicaType = ReplicaType.values()[stream.readShort()];
} else {
// before version 2 we only have disk based replicas
replicaType = ReplicaType.DISK_BACKED;
}
PartitionId partitionId = clusterMap.getPartitionIdFromStream(stream);
FindTokenFactory findTokenFactory = findTokenHelper.getFindTokenFactoryFromReplicaType(replicaType);
FindToken token = findTokenFactory.getFindToken(stream);
return new ReplicaMetadataRequestInfo(partitionId, token, hostName, replicaPath, replicaType, requestVersion);
}
use of com.github.ambry.clustermap.ReplicaType in project ambry by linkedin.
the class ReplicaMetadataResponseInfo method readFrom.
public static ReplicaMetadataResponseInfo readFrom(DataInputStream stream, FindTokenHelper helper, ClusterMap clusterMap, short replicaMetadataResponseVersion) throws IOException {
PartitionId partitionId = clusterMap.getPartitionIdFromStream(stream);
ReplicaType replicaType;
if (replicaMetadataResponseVersion == ReplicaMetadataResponse.REPLICA_METADATA_RESPONSE_VERSION_V_6) {
replicaType = ReplicaType.values()[stream.readShort()];
} else {
// before REPLICA_METADATA_RESPONSE_VERSION_V_6 there were only disk based replicas
replicaType = ReplicaType.DISK_BACKED;
}
ServerErrorCode error = ServerErrorCode.values()[stream.readShort()];
if (error != ServerErrorCode.No_Error) {
return new ReplicaMetadataResponseInfo(partitionId, replicaType, error, replicaMetadataResponseVersion);
} else {
FindTokenFactory findTokenFactory = helper.getFindTokenFactoryFromReplicaType(replicaType);
FindToken token = findTokenFactory.getFindToken(stream);
MessageInfoAndMetadataListSerde messageInfoAndMetadataList = MessageInfoAndMetadataListSerde.deserializeMessageInfoAndMetadataList(stream, clusterMap, getMessageInfoAndMetadataListSerDeVersion(replicaMetadataResponseVersion));
long remoteReplicaLag = stream.readLong();
return new ReplicaMetadataResponseInfo(partitionId, replicaType, token, messageInfoAndMetadataList.getMessageInfoList(), remoteReplicaLag, replicaMetadataResponseVersion);
}
}
use of com.github.ambry.clustermap.ReplicaType in project ambry by linkedin.
the class ServerTestUtil method checkReplicaTokens.
/**
* Repeatedly check the replication token file until a certain offset value on all nodes on a certain
* partition is found. Fail if {@code numTries} is exceeded or a token offset larger than the target
* is found.
* @param clusterMap the cluster map that contains the data node to inspect
* @param dataNodeId the data node to inspect
* @param targetOffset the token offset to look for in the {@code targetPartition}
* @param targetPartition the name of the partition to look for the {@code targetOffset}
* @throws Exception
*/
private static void checkReplicaTokens(MockClusterMap clusterMap, DataNodeId dataNodeId, long targetOffset, String targetPartition) throws Exception {
List<String> mountPaths = ((MockDataNodeId) dataNodeId).getMountPaths();
// we should have an entry for each partition - remote replica pair
Set<String> completeSetToCheck = new HashSet<>();
List<ReplicaId> replicaIds = clusterMap.getReplicaIds(dataNodeId);
int numRemoteNodes = 0;
for (ReplicaId replicaId : replicaIds) {
List<? extends ReplicaId> peerReplicas = replicaId.getPeerReplicaIds();
if (replicaId.getPartitionId().isEqual(targetPartition)) {
numRemoteNodes = peerReplicas.size();
}
for (ReplicaId peerReplica : peerReplicas) {
completeSetToCheck.add(replicaId.getPartitionId().toString() + peerReplica.getDataNodeId().getHostname() + peerReplica.getDataNodeId().getPort());
}
}
StoreKeyFactory storeKeyFactory = Utils.getObj("com.github.ambry.commons.BlobIdFactory", clusterMap);
FindTokenFactory factory = Utils.getObj("com.github.ambry.store.StoreFindTokenFactory", storeKeyFactory);
int numTries = 4;
boolean foundTarget = false;
while (!foundTarget && numTries > 0) {
Thread.sleep(5000);
numTries--;
Set<String> setToCheck = new HashSet<String>(completeSetToCheck);
int numFound = 0;
for (String mountPath : mountPaths) {
File replicaTokenFile = new File(mountPath, "replicaTokens");
if (replicaTokenFile.exists()) {
CrcInputStream crcStream = new CrcInputStream(new FileInputStream(replicaTokenFile));
DataInputStream dataInputStream = new DataInputStream(crcStream);
try {
short version = dataInputStream.readShort();
assertEquals(1, version);
while (dataInputStream.available() > 8) {
// read partition id
PartitionId partitionId = clusterMap.getPartitionIdFromStream(dataInputStream);
// read remote node host name
String hostname = Utils.readIntString(dataInputStream);
// read remote replica path
Utils.readIntString(dataInputStream);
// read remote port
int port = dataInputStream.readInt();
assertTrue(setToCheck.contains(partitionId.toString() + hostname + port));
setToCheck.remove(partitionId.toString() + hostname + port);
// read total bytes read from local store
dataInputStream.readLong();
// read replica type
ReplicaType replicaType = ReplicaType.values()[dataInputStream.readShort()];
// read replica token
StoreFindToken token = (StoreFindToken) factory.getFindToken(dataInputStream);
System.out.println("partitionId " + partitionId + " hostname " + hostname + " port " + port + " token " + token);
Offset endTokenOffset = token.getOffset();
long parsedToken = endTokenOffset == null ? -1 : endTokenOffset.getOffset();
System.out.println("The parsed token is " + parsedToken);
if (partitionId.isEqual(targetPartition)) {
assertFalse("Parsed offset: " + parsedToken + " must not be larger than target value: " + targetOffset, parsedToken > targetOffset);
if (parsedToken == targetOffset) {
numFound++;
}
} else {
assertEquals("Tokens should remain at -1 offsets on unmodified partitions", -1, parsedToken);
}
}
long crc = crcStream.getValue();
assertEquals(crc, dataInputStream.readLong());
} catch (IOException e) {
fail();
} finally {
dataInputStream.close();
}
}
}
if (numFound == numRemoteNodes) {
foundTarget = true;
}
}
if (!foundTarget) {
fail("Could not find target token offset: " + targetOffset);
}
}
Aggregations