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

com.fasterxml.clustermate.client.cluster.HashRouter Maven / Gradle / Ivy

There is a newer version: 0.10.5
Show newest version
package com.fasterxml.clustermate.client.cluster;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;

import com.fasterxml.clustermate.api.*;
import com.fasterxml.clustermate.client.ClusterServerNode;
import com.fasterxml.clustermate.client.NodesForKey;

/**
 * Helper class we use to encapsulate details of finding ordered sequence
 * of servers to contact, to locate entry with given key.
 */
public final class HashRouter
{
    private final KeySpace _keyspace;
    
    private final EntryKeyConverter _keyConverter;

    /**
     * Monotonically increasing counter we use for lazily constructing
     * and invalidating routing information, mapping from key hashes
     * to {@link NodesForKey} objects.
     */
    private final AtomicInteger _version = new AtomicInteger(1);

    private final AtomicReferenceArray _routing;

    /**
     * Since we will need to iterate over server nodes, let's use pre-calculated
     * array. Parent will update it, we just need to access it in thread-safe
     * manner.
     */
    private AtomicReference _states = new AtomicReference(
            new ClusterServerNode[0]);
    
    public HashRouter(KeySpace keyspace, EntryKeyConverter keyConverter,
            AtomicReference states)
    {
        _keyspace = keyspace;
        _keyConverter = keyConverter;
        _routing = new AtomicReferenceArray(keyspace.getLength());
        _states = states;
    }

    public void invalidateRouting() {
        _version.addAndGet(1);
    }
    
    public NodesForKey getNodesFor(K key)
    {
        int fullHash = _keyConverter.routingHashFor(key);
        KeyHash hash = new KeyHash(fullHash, _keyspace.getLength());
        int currVersion = _version.get();
        int modulo = hash.getModuloHash();
        NodesForKey nodes = _routing.get(modulo);
        // fast (and common) case: pre-calculated, valid info exists:
        if (nodes != null && nodes.version() == currVersion) {
            return nodes;
        }
        NodesForKey newNodes = _calculateNodes(currVersion, hash);
        _routing.compareAndSet(modulo, nodes, newNodes);
        return newNodes;
    }

    protected NodesForKey _calculateNodes(int version, KeyHash keyHash) {
        return _calculateNodes(version, keyHash, _states.get());
    }

    // separate method for testing
    protected NodesForKey _calculateNodes(int version, KeyHash keyHash,
            ClusterServerNode[] allNodes)
    {
        final int allCount = allNodes.length;
        // First: simply collect all applicable nodes:
        ArrayList appl = new ArrayList();
        for (int i = 0; i < allCount; ++i) {
            ClusterServerNode state = allNodes[i];
            if (state.getTotalRange().contains(keyHash)) {
                appl.add(state);
            }
        }
        return _sortNodes(version, keyHash, appl);
    }

    protected NodesForKey _sortNodes(int version, KeyHash keyHash,
            Collection appl)
    {
        // edge case: no matching
        if (appl.isEmpty()) {
            return NodesForKey.empty(version);
        }
        // otherwise need to sort
        ClusterServerNodeImpl[] matching = appl.toArray(new ClusterServerNodeImpl[appl.size()]);
        Arrays.sort(matching, 0, appl.size(), new NodePriorityComparator(keyHash));
        return new NodesForKey(version, matching);
    }

    /*
    /**********************************************************************
    /* Helper classes
    /**********************************************************************
     */
    
    /**
     * Comparator that orders server in decreasing priority, that is, starts with
     * the closest enabled match, ending with disabled entries.
     */
    private final static class NodePriorityComparator implements Comparator
    {
        private final KeyHash _keyHash;
    
        public NodePriorityComparator(KeyHash keyHash) {
            _keyHash = keyHash;
        }
        
        @Override
        public int compare(ClusterServerNodeImpl node1, ClusterServerNodeImpl node2)
        {
            return node1.calculateSortingDistance(_keyHash) - node2.calculateSortingDistance(_keyHash);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy