Search in sources :

Example 1 with ReplicaType

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;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) ArrayList(java.util.ArrayList) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ReplicaType(com.github.ambry.clustermap.ReplicaType) Future(java.util.concurrent.Future) ArrayList(java.util.ArrayList) List(java.util.List) ExecutionException(java.util.concurrent.ExecutionException) EnumMap(java.util.EnumMap)

Example 2 with ReplicaType

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));
}
Also used : ServerNetworkResponseMetrics(com.github.ambry.network.ServerNetworkResponseMetrics) ArrayList(java.util.ArrayList) Store(com.github.ambry.store.Store) DataInputStream(java.io.DataInputStream) PartitionId(com.github.ambry.clustermap.PartitionId) ServerErrorCode(com.github.ambry.server.ServerErrorCode) IdUndeletedStoreException(com.github.ambry.store.IdUndeletedStoreException) StoreException(com.github.ambry.store.StoreException) IOException(java.io.IOException) MessageFormatException(com.github.ambry.messageformat.MessageFormatException) IdUndeletedStoreException(com.github.ambry.store.IdUndeletedStoreException) StoreException(com.github.ambry.store.StoreException) ReplicaType(com.github.ambry.clustermap.ReplicaType) FindToken(com.github.ambry.replication.FindToken) FindInfo(com.github.ambry.store.FindInfo)

Example 3 with ReplicaType

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);
}
Also used : ReplicaType(com.github.ambry.clustermap.ReplicaType) FindToken(com.github.ambry.replication.FindToken) PartitionId(com.github.ambry.clustermap.PartitionId) FindTokenFactory(com.github.ambry.replication.FindTokenFactory)

Example 4 with ReplicaType

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);
    }
}
Also used : ReplicaType(com.github.ambry.clustermap.ReplicaType) FindToken(com.github.ambry.replication.FindToken) PartitionId(com.github.ambry.clustermap.PartitionId) FindTokenFactory(com.github.ambry.replication.FindTokenFactory) ServerErrorCode(com.github.ambry.server.ServerErrorCode)

Example 5 with ReplicaType

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);
    }
}
Also used : StoreFindToken(com.github.ambry.store.StoreFindToken) IOException(java.io.IOException) NettyByteBufDataInputStream(com.github.ambry.utils.NettyByteBufDataInputStream) DataInputStream(java.io.DataInputStream) MockPartitionId(com.github.ambry.clustermap.MockPartitionId) PartitionId(com.github.ambry.clustermap.PartitionId) FindTokenFactory(com.github.ambry.replication.FindTokenFactory) ReplicaId(com.github.ambry.clustermap.ReplicaId) MockReplicaId(com.github.ambry.clustermap.MockReplicaId) FileInputStream(java.io.FileInputStream) Offset(com.github.ambry.store.Offset) StoreKeyFactory(com.github.ambry.store.StoreKeyFactory) CrcInputStream(com.github.ambry.utils.CrcInputStream) ReplicaType(com.github.ambry.clustermap.ReplicaType) MockDataNodeId(com.github.ambry.clustermap.MockDataNodeId) File(java.io.File) HashSet(java.util.HashSet)

Aggregations

ReplicaType (com.github.ambry.clustermap.ReplicaType)8 PartitionId (com.github.ambry.clustermap.PartitionId)4 FindToken (com.github.ambry.replication.FindToken)3 FindTokenFactory (com.github.ambry.replication.FindTokenFactory)3 EnumMap (java.util.EnumMap)3 CompositeNetworkClientFactory (com.github.ambry.network.CompositeNetworkClientFactory)2 LocalNetworkClientFactory (com.github.ambry.network.LocalNetworkClientFactory)2 NetworkClientFactory (com.github.ambry.network.NetworkClientFactory)2 ServerErrorCode (com.github.ambry.server.ServerErrorCode)2 DataInputStream (java.io.DataInputStream)2 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 HashSet (java.util.HashSet)2 AccountService (com.github.ambry.account.AccountService)1 InMemAccountService (com.github.ambry.account.InMemAccountService)1 CloudDestination (com.github.ambry.cloud.CloudDestination)1 CloudDestinationFactory (com.github.ambry.cloud.CloudDestinationFactory)1 LatchBasedInMemoryCloudDestinationFactory (com.github.ambry.cloud.LatchBasedInMemoryCloudDestinationFactory)1 MockDataNodeId (com.github.ambry.clustermap.MockDataNodeId)1 MockPartitionId (com.github.ambry.clustermap.MockPartitionId)1