Пример #1
0
  public List<InetAddress> calculateNaturalEndpoints(Token token, TokenMetadata metadata) {
    int replicas = getReplicationFactor();
    ArrayList<Token> tokens = metadata.sortedTokens();
    List<InetAddress> endpoints = new ArrayList<InetAddress>(replicas);

    if (tokens.isEmpty()) return endpoints;

    // Add the token at the index by default
    Iterator<Token> iter = TokenMetadata.ringIterator(tokens, token, false);
    while (endpoints.size() < replicas && iter.hasNext()) {
      endpoints.add(metadata.getEndpoint(iter.next()));
    }
    return endpoints;
  }
Пример #2
0
  public List<InetAddress> calculateNaturalEndpoints(Token token, TokenMetadata metadata) {
    int replicas = getReplicationFactor();
    ArrayList<Token> tokens = metadata.sortedTokens();
    List<InetAddress> endpoints = new ArrayList<InetAddress>(replicas);

    if (tokens.isEmpty()) return endpoints;

    // Add the token at the index by default
    Iterator<Token> iter = TokenMetadata.ringIterator(tokens, token, false);
    while (endpoints.size() < replicas && iter.hasNext()) {
      endpoints.add(metadata.getEndpoint(iter.next()));
    }

    if (endpoints.size() < replicas)
      throw new IllegalStateException(
          String.format(
              "replication factor (%s) exceeds number of endpoints (%s)",
              replicas, endpoints.size()));

    return endpoints;
  }
  @Test
  public void testStateJumpToLeaving() throws UnknownHostException {
    StorageService ss = StorageService.instance;
    TokenMetadata tmd = ss.getTokenMetadata();
    tmd.clearUnsafe();
    IPartitioner partitioner = RandomPartitioner.instance;
    VersionedValue.VersionedValueFactory valueFactory =
        new VersionedValue.VersionedValueFactory(partitioner);

    ArrayList<Token> endpointTokens = new ArrayList<Token>();
    ArrayList<Token> keyTokens = new ArrayList<Token>();
    List<InetAddress> hosts = new ArrayList<InetAddress>();
    List<UUID> hostIds = new ArrayList<UUID>();

    // create a ring or 5 nodes
    Util.createInitialRing(ss, partitioner, endpointTokens, keyTokens, hosts, hostIds, 6);

    // node 2 leaves with _different_ token
    Gossiper.instance.injectApplicationState(
        hosts.get(2),
        ApplicationState.TOKENS,
        valueFactory.tokens(Collections.singleton(keyTokens.get(0))));
    ss.onChange(
        hosts.get(2),
        ApplicationState.STATUS,
        valueFactory.leaving(Collections.singleton(keyTokens.get(0))));

    assertEquals(keyTokens.get(0), tmd.getToken(hosts.get(2)));
    assertTrue(tmd.isLeaving(hosts.get(2)));
    assertNull(tmd.getEndpoint(endpointTokens.get(2)));

    // go to boostrap
    Gossiper.instance.injectApplicationState(
        hosts.get(2),
        ApplicationState.TOKENS,
        valueFactory.tokens(Collections.singleton(keyTokens.get(1))));
    ss.onChange(
        hosts.get(2),
        ApplicationState.STATUS,
        valueFactory.bootstrapping(Collections.<Token>singleton(keyTokens.get(1))));

    assertFalse(tmd.isLeaving(hosts.get(2)));
    assertEquals(1, tmd.getBootstrapTokens().size());
    assertEquals(hosts.get(2), tmd.getBootstrapTokens().get(keyTokens.get(1)));

    // jump to leaving again
    ss.onChange(
        hosts.get(2),
        ApplicationState.STATUS,
        valueFactory.leaving(Collections.singleton(keyTokens.get(1))));

    assertEquals(hosts.get(2), tmd.getEndpoint(keyTokens.get(1)));
    assertTrue(tmd.isLeaving(hosts.get(2)));
    assertTrue(tmd.getBootstrapTokens().isEmpty());

    // go to state left
    ss.onChange(
        hosts.get(2),
        ApplicationState.STATUS,
        valueFactory.left(Collections.singleton(keyTokens.get(1)), Gossiper.computeExpireTime()));

    assertFalse(tmd.isMember(hosts.get(2)));
    assertFalse(tmd.isLeaving(hosts.get(2)));
  }
  /**
   * Test whether write endpoints is correct when the node is leaving. Uses StorageService.onChange
   * and does not manipulate token metadata directly.
   */
  @Test
  public void newTestWriteEndpointsDuringLeave() throws Exception {
    StorageService ss = StorageService.instance;
    final int RING_SIZE = 6;
    final int LEAVING_NODE = 3;

    TokenMetadata tmd = ss.getTokenMetadata();
    tmd.clearUnsafe();
    IPartitioner partitioner = RandomPartitioner.instance;
    VersionedValue.VersionedValueFactory valueFactory =
        new VersionedValue.VersionedValueFactory(partitioner);

    ArrayList<Token> endpointTokens = new ArrayList<Token>();
    ArrayList<Token> keyTokens = new ArrayList<Token>();
    List<InetAddress> hosts = new ArrayList<InetAddress>();
    List<UUID> hostIds = new ArrayList<UUID>();

    Util.createInitialRing(ss, partitioner, endpointTokens, keyTokens, hosts, hostIds, RING_SIZE);

    Map<Token, List<InetAddress>> expectedEndpoints = new HashMap<Token, List<InetAddress>>();
    for (String keyspaceName : Schema.instance.getNonLocalStrategyKeyspaces()) {
      for (Token token : keyTokens) {
        List<InetAddress> endpoints = new ArrayList<InetAddress>();
        Iterator<Token> tokenIter = TokenMetadata.ringIterator(tmd.sortedTokens(), token, false);
        while (tokenIter.hasNext()) {
          endpoints.add(tmd.getEndpoint(tokenIter.next()));
        }
        expectedEndpoints.put(token, endpoints);
      }
    }

    // Third node leaves
    ss.onChange(
        hosts.get(LEAVING_NODE),
        ApplicationState.STATUS,
        valueFactory.leaving(Collections.singleton(endpointTokens.get(LEAVING_NODE))));
    assertTrue(tmd.isLeaving(hosts.get(LEAVING_NODE)));

    Thread.sleep(100); // because there is a tight race between submit and blockUntilFinished
    PendingRangeCalculatorService.instance.blockUntilFinished();

    AbstractReplicationStrategy strategy;
    for (String keyspaceName : Schema.instance.getNonLocalStrategyKeyspaces()) {
      strategy = getStrategy(keyspaceName, tmd);
      for (Token token : keyTokens) {
        int replicationFactor = strategy.getReplicationFactor();

        HashSet<InetAddress> actual =
            new HashSet<InetAddress>(
                tmd.getWriteEndpoints(
                    token,
                    keyspaceName,
                    strategy.calculateNaturalEndpoints(token, tmd.cloneOnlyTokenMap())));
        HashSet<InetAddress> expected = new HashSet<InetAddress>();

        for (int i = 0; i < replicationFactor; i++) {
          expected.add(expectedEndpoints.get(token).get(i));
        }

        // if the leaving node is in the endpoint list,
        // then we should expect it plus one extra for when it's gone
        if (expected.contains(hosts.get(LEAVING_NODE)))
          expected.add(expectedEndpoints.get(token).get(replicationFactor));

        assertEquals("mismatched endpoint sets", expected, actual);
      }
    }
  }