All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.datastax.driver.core.ReplicationStategy Maven / Gradle / Ivy

Go to download

A driver for Apache Cassandra 1.2+ that works exclusively with the Cassandra Query Language version 3 (CQL3) and Cassandra's binary protocol.

The newest version!
/*
 *      Copyright (C) 2012 DataStax Inc.
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */
package com.datastax.driver.core;

import java.util.*;

import com.google.common.collect.ImmutableSet;

/*
 * Computes the token->list association, given the token ring and token->primary token map.
 *
 * Note: it's not an interface mainly because we don't want to expose it.
 */
abstract class ReplicationStrategy {

    static ReplicationStrategy create(Map replicationOptions) {

        String strategyClass = replicationOptions.get("class");
        if (strategyClass == null)
            return null;

        try {
            if (strategyClass.contains("SimpleStrategy")) {
                String repFactorString = replicationOptions.get("replication_factor");
                return repFactorString == null ? null : new SimpleStrategy(Integer.parseInt(repFactorString));
            } else if (strategyClass.contains("NetworkTopologyStrategy")) {
                Map dcRfs = new HashMap();
                for (Map.Entry entry : replicationOptions.entrySet())
                {
                    if (entry.getKey().equals("class"))
                        continue;

                    dcRfs.put(entry.getKey(), Integer.parseInt(entry.getValue()));
                }
                return new NetworkTopologyStrategy(dcRfs);
            } else {
                // We might want to support oldNetworkTopologyStrategy, though not sure anyone still using that
                return null;
            }
        } catch (NumberFormatException e) {
            // Cassandra wouldn't let that pass in the first place so this really should never happen
            return null;
        }
    }

    abstract Map> computeTokenToReplicaMap(Map tokenToPrimary, List ring);

    private static Token getTokenWrapping(int i, List ring) {
        return ring.get(i % ring.size());
    }

    static class SimpleStrategy extends ReplicationStrategy {

        private final int replicationFactor;

        private SimpleStrategy(int replicationFactor) {
            this.replicationFactor = replicationFactor;
        }

        Map> computeTokenToReplicaMap(Map tokenToPrimary, List ring) {

            int rf = Math.min(replicationFactor, ring.size());

            Map> replicaMap = new HashMap>(tokenToPrimary.size());
            for (int i = 0; i < ring.size(); i++) {
                // Consecutive sections of the ring can assigned to the same host
                Set replicas = new LinkedHashSet();
                for (int j = 0; j < ring.size() && replicas.size() < rf; j++)
                    replicas.add(tokenToPrimary.get(getTokenWrapping(i+j, ring)));
                replicaMap.put(ring.get(i), ImmutableSet.copyOf(replicas));
            }
            return replicaMap;
        }
    }

    static class NetworkTopologyStrategy extends ReplicationStrategy {

        private final Map replicationFactors;

        private NetworkTopologyStrategy(Map replicationFactors) {
            this.replicationFactors = replicationFactors;
        }

        Map> computeTokenToReplicaMap(Map tokenToPrimary, List ring) {

             // This is essentially a copy of org.apache.cassandra.locator.NetworkTopologyStrategy
            Map> racks = getRacksInDcs(tokenToPrimary.values());
            Map> replicaMap = new HashMap>(tokenToPrimary.size());
            for (int i = 0; i < ring.size(); i++) {
                Map> allDcReplicas = new HashMap>();
                Map> seenRacks = new HashMap>();
                Map> skippedDcEndpoints = new HashMap>();
                for (String dc : replicationFactors.keySet()) {
                    allDcReplicas.put(dc, new HashSet());
                    seenRacks.put(dc, new HashSet());
                    skippedDcEndpoints.put(dc, new LinkedHashSet()); // preserve order
                }

                // Preserve order - primary replica will be first
                Set replicas = new LinkedHashSet();
                for (int j = 0; j < ring.size() && !allDone(allDcReplicas); j++) {
                    Host h = tokenToPrimary.get(getTokenWrapping(i + j, ring));
                    String dc = h.getDatacenter();
                    if (dc == null || !allDcReplicas.containsKey(dc))
                        continue;

                    Integer rf = replicationFactors.get(dc);
                    Set dcReplicas = allDcReplicas.get(dc);
                    if (rf == null || dcReplicas.size() >= rf)
                        continue;

                    String rack = h.getRack();
                    // Check if we already visited all racks in dc
                    if (rack == null || seenRacks.get(dc).size() == racks.get(dc).size()) {
                        replicas.add(h);
                        dcReplicas.add(h);
                    } else {
                        // Is this a new rack?
                        if (seenRacks.get(dc).contains(rack)) {
                            skippedDcEndpoints.get(dc).add(h);
                        } else {
                            replicas.add(h);
                            dcReplicas.add(h);
                            seenRacks.get(dc).add(rack);
                            // If we've run out of distinct racks, add the nodes skipped so far
                            if (seenRacks.get(dc).size() == racks.get(dc).size()) {
                                Iterator skippedIt = skippedDcEndpoints.get(dc).iterator();
                                while (skippedIt.hasNext() && dcReplicas.size() < rf) {
                                    Host nextSkipped = skippedIt.next();
                                    replicas.add(nextSkipped);
                                    dcReplicas.add(nextSkipped);
                                }
                            }
                        }
                    }
                }
                replicaMap.put(ring.get(i), ImmutableSet.copyOf(replicas));
            }
            return replicaMap;
        }

        private boolean allDone(Map> map) {
            for (Map.Entry> entry : map.entrySet())
                if (entry.getValue().size() < replicationFactors.get(entry.getKey()))
                    return false;
            return true;
        }

        private Map> getRacksInDcs(Iterable hosts) {
            Map> result = new HashMap>();
            for (Host host : hosts) {
                Set racks = result.get(host.getDatacenter());
                if (racks == null) {
                    racks = new HashSet();
                    result.put(host.getDatacenter(), racks);
                }
                racks.add(host.getRack());
            }
            return result;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy