Search in sources :

Example 1 with EndpointsByReplica

use of org.apache.cassandra.locator.EndpointsByReplica in project cassandra by apache.

the class RangeStreamer method getOptimizedWorkMap.

/**
 * Optimized version that also outputs the final work map
 */
private static Multimap<InetAddressAndPort, FetchReplica> getOptimizedWorkMap(EndpointsByReplica rangesWithSources, Collection<SourceFilter> sourceFilters, String keyspace) {
    // For now we just aren't going to use the optimized range fetch map with transient replication to shrink
    // the surface area to test and introduce bugs.
    // In the future it's possible we could run it twice once for full ranges with only full replicas
    // and once with transient ranges and all replicas. Then merge the result.
    EndpointsByRange.Builder unwrapped = new EndpointsByRange.Builder();
    for (Map.Entry<Replica, Replica> entry : rangesWithSources.flattenEntries()) {
        Replicas.temporaryAssertFull(entry.getValue());
        unwrapped.put(entry.getKey().range(), entry.getValue());
    }
    EndpointsByRange unwrappedView = unwrapped.build();
    RangeFetchMapCalculator calculator = new RangeFetchMapCalculator(unwrappedView, sourceFilters, keyspace);
    Multimap<InetAddressAndPort, Range<Token>> rangeFetchMapMap = calculator.getRangeFetchMap();
    logger.info("Output from RangeFetchMapCalculator for keyspace {}", keyspace);
    validateRangeFetchMap(unwrappedView, rangeFetchMapMap, keyspace);
    // Need to rewrap as Replicas
    Multimap<InetAddressAndPort, FetchReplica> wrapped = HashMultimap.create();
    for (Map.Entry<InetAddressAndPort, Range<Token>> entry : rangeFetchMapMap.entries()) {
        Replica toFetch = null;
        for (Replica r : rangesWithSources.keySet()) {
            if (r.range().equals(entry.getValue())) {
                if (toFetch != null)
                    throw new AssertionError(String.format("There shouldn't be multiple replicas for range %s, replica %s and %s here", r.range(), r, toFetch));
                toFetch = r;
            }
        }
        if (toFetch == null)
            throw new AssertionError("Shouldn't be possible for the Replica we fetch to be null here");
        // Committing the cardinal sin of synthesizing a Replica, but it's ok because we assert earlier all of them
        // are full and optimized range fetch map doesn't support transient replication yet.
        wrapped.put(entry.getKey(), new FetchReplica(toFetch, fullReplica(entry.getKey(), entry.getValue())));
    }
    return wrapped;
}
Also used : InetAddressAndPort(org.apache.cassandra.locator.InetAddressAndPort) EndpointsByRange(org.apache.cassandra.locator.EndpointsByRange) EndpointsByRange(org.apache.cassandra.locator.EndpointsByRange) EndpointsForRange(org.apache.cassandra.locator.EndpointsForRange) Replica.fullReplica(org.apache.cassandra.locator.Replica.fullReplica) Replica(org.apache.cassandra.locator.Replica) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with EndpointsByReplica

use of org.apache.cassandra.locator.EndpointsByReplica in project cassandra by apache.

the class RangeStreamer method convertPreferredEndpointsToWorkMap.

/**
 * The preferred endpoint list is the wrong format because it is keyed by Replica (this node) rather than the source
 * endpoint we will fetch from which streaming wants.
 */
public static Multimap<InetAddressAndPort, FetchReplica> convertPreferredEndpointsToWorkMap(EndpointsByReplica preferredEndpoints) {
    Multimap<InetAddressAndPort, FetchReplica> workMap = HashMultimap.create();
    for (Map.Entry<Replica, EndpointsForRange> e : preferredEndpoints.entrySet()) {
        for (Replica source : e.getValue()) {
            assert (e.getKey()).isSelf();
            assert !source.isSelf();
            workMap.put(source.endpoint(), new FetchReplica(e.getKey(), source));
        }
    }
    logger.debug("Work map {}", workMap);
    return workMap;
}
Also used : InetAddressAndPort(org.apache.cassandra.locator.InetAddressAndPort) EndpointsForRange(org.apache.cassandra.locator.EndpointsForRange) Map(java.util.Map) HashMap(java.util.HashMap) Replica.fullReplica(org.apache.cassandra.locator.Replica.fullReplica) Replica(org.apache.cassandra.locator.Replica) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica)

Example 3 with EndpointsByReplica

use of org.apache.cassandra.locator.EndpointsByReplica in project cassandra by apache.

the class RangeStreamer method calculateRangesToFetchWithPreferredEndpoints.

/**
 * Get a map of all ranges and the source that will be cleaned up once this bootstrapped node is added for the given ranges.
 * For each range, the list should only contain a single source. This allows us to consistently migrate data without violating
 * consistency.
 */
public static EndpointsByReplica calculateRangesToFetchWithPreferredEndpoints(BiFunction<InetAddressAndPort, EndpointsForRange, EndpointsForRange> snitchGetSortedListByProximity, AbstractReplicationStrategy strat, ReplicaCollection<?> fetchRanges, boolean useStrictConsistency, TokenMetadata tmdBefore, TokenMetadata tmdAfter, String keyspace, Collection<SourceFilter> sourceFilters) {
    EndpointsByRange rangeAddresses = strat.getRangeAddresses(tmdBefore);
    InetAddressAndPort localAddress = FBUtilities.getBroadcastAddressAndPort();
    logger.debug("Keyspace: {}", keyspace);
    logger.debug("To fetch RN: {}", fetchRanges);
    logger.debug("Fetch ranges: {}", rangeAddresses);
    Predicate<Replica> testSourceFilters = and(sourceFilters);
    Function<EndpointsForRange, EndpointsForRange> sorted = endpoints -> snitchGetSortedListByProximity.apply(localAddress, endpoints);
    // This list of replicas is just candidates. With strict consistency it's going to be a narrow list.
    EndpointsByReplica.Builder rangesToFetchWithPreferredEndpoints = new EndpointsByReplica.Builder();
    for (Replica toFetch : fetchRanges) {
        // Replica that is sufficient to provide the data we need
        // With strict consistency and transient replication we may end up with multiple types
        // so this isn't used with strict consistency
        Predicate<Replica> isSufficient = r -> toFetch.isTransient() || r.isFull();
        logger.debug("To fetch {}", toFetch);
        for (Range<Token> range : rangeAddresses.keySet()) {
            if (!range.contains(toFetch.range()))
                continue;
            final EndpointsForRange oldEndpoints = sorted.apply(rangeAddresses.get(range));
            // Ultimately we populate this with whatever is going to be fetched from to satisfy toFetch
            // It could be multiple endpoints and we must fetch from all of them if they are there
            // With transient replication and strict consistency this is to get the full data from a full replica and
            // transient data from the transient replica losing data
            EndpointsForRange sources;
            // Due to CASSANDRA-5953 we can have a higher RF than we have endpoints.
            // So we need to be careful to only be strict when endpoints == RF
            boolean isStrictConsistencyApplicable = useStrictConsistency && (oldEndpoints.size() == strat.getReplicationFactor().allReplicas);
            if (isStrictConsistencyApplicable) {
                EndpointsForRange strictEndpoints;
                // Start with two sets of who replicates the range before and who replicates it after
                EndpointsForRange newEndpoints = strat.calculateNaturalReplicas(toFetch.range().right, tmdAfter);
                logger.debug("Old endpoints {}", oldEndpoints);
                logger.debug("New endpoints {}", newEndpoints);
                // Remove new endpoints from old endpoints based on address
                strictEndpoints = oldEndpoints.without(newEndpoints.endpoints());
                if (strictEndpoints.size() > 1)
                    throw new AssertionError("Expected <= 1 endpoint but found " + strictEndpoints);
                // required for strict consistency
                if (!all(strictEndpoints, testSourceFilters))
                    throw new IllegalStateException("Necessary replicas for strict consistency were removed by source filters: " + buildErrorMessage(sourceFilters, strictEndpoints));
                // So it's an error if we don't find what we need.
                if (strictEndpoints.isEmpty() && toFetch.isTransient())
                    throw new AssertionError("If there are no endpoints to fetch from then we must be transitioning from transient to full for range " + toFetch);
                if (!any(strictEndpoints, isSufficient)) {
                    // need an additional replica; include all our filters, to ensure we include a matching node
                    Optional<Replica> fullReplica = Iterables.<Replica>tryFind(oldEndpoints, and(isSufficient, testSourceFilters)).toJavaUtil();
                    if (fullReplica.isPresent())
                        strictEndpoints = Endpoints.concat(strictEndpoints, EndpointsForRange.of(fullReplica.get()));
                    else
                        throw new IllegalStateException("Couldn't find any matching sufficient replica out of " + buildErrorMessage(sourceFilters, oldEndpoints));
                }
                sources = strictEndpoints;
            } else {
                // Without strict consistency we have given up on correctness so no point in fetching from
                // a random full + transient replica since it's also likely to lose data
                // Also apply testSourceFilters that were given to us so we can safely select a single source
                sources = sorted.apply(oldEndpoints.filter(and(isSufficient, testSourceFilters)));
                // Limit it to just the first possible source, we don't need more than one and downstream
                // will fetch from every source we supply
                sources = sources.size() > 0 ? sources.subList(0, 1) : sources;
            }
            // storing range and preferred endpoint set
            rangesToFetchWithPreferredEndpoints.putAll(toFetch, sources, Conflict.NONE);
            logger.debug("Endpoints to fetch for {} are {}", toFetch, sources);
        }
        EndpointsForRange addressList = rangesToFetchWithPreferredEndpoints.getIfPresent(toFetch);
        if (addressList == null)
            throw new IllegalStateException("Failed to find endpoints to fetch " + toFetch);
        /*
              * When we move forwards (shrink our bucket) we are the one losing a range and no one else loses
              * from that action (we also don't gain). When we move backwards there are two people losing a range. One is a full replica
              * and the other is a transient replica. So we must need fetch from two places in that case for the full range we gain.
              * For a transient range we only need to fetch from one.
              */
        if (useStrictConsistency && addressList.size() > 1 && (addressList.filter(Replica::isFull).size() > 1 || addressList.filter(Replica::isTransient).size() > 1))
            throw new IllegalStateException(String.format("Multiple strict sources found for %s, sources: %s", toFetch, addressList));
        // We must have enough stuff to fetch from
        if (!any(addressList, isSufficient)) {
            if (strat.getReplicationFactor().allReplicas == 1) {
                if (useStrictConsistency) {
                    logger.warn("A node required to move the data consistently is down");
                    throw new IllegalStateException("Unable to find sufficient sources for streaming range " + toFetch + " in keyspace " + keyspace + " with RF=1. " + "Ensure this keyspace contains replicas in the source datacenter.");
                } else
                    logger.warn("Unable to find sufficient sources for streaming range {} in keyspace {} with RF=1. " + "Keyspace might be missing data.", toFetch, keyspace);
            } else {
                if (useStrictConsistency)
                    logger.warn("A node required to move the data consistently is down");
                throw new IllegalStateException("Unable to find sufficient sources for streaming range " + toFetch + " in keyspace " + keyspace);
            }
        }
    }
    return rangesToFetchWithPreferredEndpoints.build();
}
Also used : BiFunction(java.util.function.BiFunction) LoggerFactory(org.slf4j.LoggerFactory) Iterables.all(com.google.common.collect.Iterables.all) StringUtils(org.apache.commons.lang3.StringUtils) Gossiper(org.apache.cassandra.gms.Gossiper) NetworkTopologyStrategy(org.apache.cassandra.locator.NetworkTopologyStrategy) Predicates.and(com.google.common.base.Predicates.and) StreamResultFuture(org.apache.cassandra.streaming.StreamResultFuture) Replica.fullReplica(org.apache.cassandra.locator.Replica.fullReplica) HashMultimap(com.google.common.collect.HashMultimap) Replicas(org.apache.cassandra.locator.Replicas) Endpoints(org.apache.cassandra.locator.Endpoints) Predicates.not(com.google.common.base.Predicates.not) ReplicaCollection(org.apache.cassandra.locator.ReplicaCollection) Map(java.util.Map) EndpointsByRange(org.apache.cassandra.locator.EndpointsByRange) Keyspace(org.apache.cassandra.db.Keyspace) EndpointsForRange(org.apache.cassandra.locator.EndpointsForRange) FBUtilities(org.apache.cassandra.utils.FBUtilities) Collection(java.util.Collection) Set(java.util.Set) Collectors(java.util.stream.Collectors) RangesAtEndpoint(org.apache.cassandra.locator.RangesAtEndpoint) List(java.util.List) Predicate(com.google.common.base.Predicate) Conflict(org.apache.cassandra.locator.ReplicaCollection.Builder.Conflict) Optional(java.util.Optional) FailureDetector(org.apache.cassandra.gms.FailureDetector) Iterables.any(com.google.common.collect.Iterables.any) InetAddressAndPort(org.apache.cassandra.locator.InetAddressAndPort) Iterables(com.google.common.collect.Iterables) HashMap(java.util.HashMap) Multimap(com.google.common.collect.Multimap) Function(java.util.function.Function) SystemKeyspace(org.apache.cassandra.db.SystemKeyspace) ArrayList(java.util.ArrayList) IEndpointSnitch(org.apache.cassandra.locator.IEndpointSnitch) TokenMetadata(org.apache.cassandra.locator.TokenMetadata) ImmutableMultimap(com.google.common.collect.ImmutableMultimap) StreamOperation(org.apache.cassandra.streaming.StreamOperation) Logger(org.slf4j.Logger) Replica(org.apache.cassandra.locator.Replica) IFailureDetector(org.apache.cassandra.gms.IFailureDetector) PreviewKind(org.apache.cassandra.streaming.PreviewKind) AbstractReplicationStrategy(org.apache.cassandra.locator.AbstractReplicationStrategy) StreamPlan(org.apache.cassandra.streaming.StreamPlan) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica) Preconditions(com.google.common.base.Preconditions) VisibleForTesting(com.google.common.annotations.VisibleForTesting) LocalStrategy(org.apache.cassandra.locator.LocalStrategy) InetAddressAndPort(org.apache.cassandra.locator.InetAddressAndPort) EndpointsByRange(org.apache.cassandra.locator.EndpointsByRange) Replica.fullReplica(org.apache.cassandra.locator.Replica.fullReplica) Replica(org.apache.cassandra.locator.Replica) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica) EndpointsForRange(org.apache.cassandra.locator.EndpointsForRange)

Example 4 with EndpointsByReplica

use of org.apache.cassandra.locator.EndpointsByReplica in project cassandra by apache.

the class MoveTransientTest method invokeCalculateRangesToFetchWithPreferredEndpoints.

private void invokeCalculateRangesToFetchWithPreferredEndpoints(RangesAtEndpoint toFetch, Pair<TokenMetadata, TokenMetadata> tmds, EndpointsByReplica expectedResult) {
    DatabaseDescriptor.setTransientReplicationEnabledUnsafe(true);
    EndpointsByReplica result = RangeStreamer.calculateRangesToFetchWithPreferredEndpoints((address, replicas) -> replicas.sorted((a, b) -> b.endpoint().compareTo(a.endpoint())), simpleStrategy(tmds.left), toFetch, true, tmds.left, tmds.right, "TestKeyspace", sourceFilters);
    logger.info("Ranges to fetch with preferred endpoints");
    logger.info(result.toString());
    assertMultimapEqualsIgnoreOrder(expectedResult, result);
}
Also used : StorageServiceTest.assertMultimapEqualsIgnoreOrder(org.apache.cassandra.service.StorageServiceTest.assertMultimapEqualsIgnoreOrder) InetAddressAndPort(org.apache.cassandra.locator.InetAddressAndPort) Arrays(java.util.Arrays) Iterables(com.google.common.collect.Iterables) BeforeClass(org.junit.BeforeClass) LoggerFactory(org.slf4j.LoggerFactory) Range(org.apache.cassandra.dht.Range) ArrayList(java.util.ArrayList) RandomPartitioner(org.apache.cassandra.dht.RandomPartitioner) IEndpointSnitch(org.apache.cassandra.locator.IEndpointSnitch) Token(org.apache.cassandra.dht.Token) AbstractEndpointSnitch(org.apache.cassandra.locator.AbstractEndpointSnitch) Replica.fullReplica(org.apache.cassandra.locator.Replica.fullReplica) TokenMetadata(org.apache.cassandra.locator.TokenMetadata) Pair(org.apache.cassandra.utils.Pair) After(org.junit.After) SimpleStrategy(org.apache.cassandra.locator.SimpleStrategy) RangeStreamer(org.apache.cassandra.dht.RangeStreamer) DatabaseDescriptor(org.apache.cassandra.config.DatabaseDescriptor) Logger(org.slf4j.Logger) Collection(java.util.Collection) Assert.assertTrue(org.junit.Assert.assertTrue) Test(org.junit.Test) RangesByEndpoint(org.apache.cassandra.locator.RangesByEndpoint) RangesAtEndpoint(org.apache.cassandra.locator.RangesAtEndpoint) Replica(org.apache.cassandra.locator.Replica) Replica.transientReplica(org.apache.cassandra.locator.Replica.transientReplica) List(java.util.List) AbstractReplicationStrategy(org.apache.cassandra.locator.AbstractReplicationStrategy) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica) Assert.assertEquals(org.junit.Assert.assertEquals) EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica)

Example 5 with EndpointsByReplica

use of org.apache.cassandra.locator.EndpointsByReplica in project cassandra by apache.

the class BootstrapTransientTest method invokeCalculateRangesToFetchWithPreferredEndpoints.

private void invokeCalculateRangesToFetchWithPreferredEndpoints(ReplicaCollection<?> toFetch, Pair<TokenMetadata, TokenMetadata> tmds, EndpointsByReplica expectedResult) {
    DatabaseDescriptor.setTransientReplicationEnabledUnsafe(true);
    EndpointsByReplica result = RangeStreamer.calculateRangesToFetchWithPreferredEndpoints((address, replicas) -> replicas, simpleStrategy(tmds.left), toFetch, true, tmds.left, tmds.right, "TestKeyspace", sourceFilters);
    result.asMap().forEach((replica, list) -> System.out.printf("Replica %s, sources %s%n", replica, list));
    assertMultimapEqualsIgnoreOrder(expectedResult, result);
}
Also used : EndpointsByReplica(org.apache.cassandra.locator.EndpointsByReplica)

Aggregations

EndpointsByReplica (org.apache.cassandra.locator.EndpointsByReplica)8 Replica (org.apache.cassandra.locator.Replica)6 InetAddressAndPort (org.apache.cassandra.locator.InetAddressAndPort)5 Replica.fullReplica (org.apache.cassandra.locator.Replica.fullReplica)5 HashMap (java.util.HashMap)4 Map (java.util.Map)4 AbstractReplicationStrategy (org.apache.cassandra.locator.AbstractReplicationStrategy)4 Collection (java.util.Collection)3 EndpointsForRange (org.apache.cassandra.locator.EndpointsForRange)3 TokenMetadata (org.apache.cassandra.locator.TokenMetadata)3 Test (org.junit.Test)3 Iterables (com.google.common.collect.Iterables)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Keyspace (org.apache.cassandra.db.Keyspace)2 SystemKeyspace (org.apache.cassandra.db.SystemKeyspace)2 Range (org.apache.cassandra.dht.Range)2 EndpointsByRange (org.apache.cassandra.locator.EndpointsByRange)2 IEndpointSnitch (org.apache.cassandra.locator.IEndpointSnitch)2 RangesAtEndpoint (org.apache.cassandra.locator.RangesAtEndpoint)2