io.atomix.protocols.raft.storage.system.Configuration Java Examples

The following examples show how to use io.atomix.protocols.raft.storage.system.Configuration. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 6 votes vote down vote up
@Override
public CompletableFuture<Void> bootstrap(Collection<MemberId> cluster) {
  if (joinFuture != null) {
    return joinFuture;
  }

  if (configuration == null) {
    member.setType(RaftMember.Type.ACTIVE);

    // Create a set of active members.
    Set<RaftMember> activeMembers = cluster.stream()
        .filter(m -> !m.equals(member.memberId()))
        .map(m -> new DefaultRaftMember(m, RaftMember.Type.ACTIVE, member.getLastUpdated()))
        .collect(Collectors.toSet());

    // Add the local member to the set of active members.
    activeMembers.add(member);

    // Create a new configuration and store it on disk to ensure the cluster can fall back to the configuration.
    configure(new Configuration(0, 0, member.getLastUpdated().toEpochMilli(), activeMembers));
  }
  return join();
}
 
Example #2
Source File: LeaderRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
/**
 * Commits the given configuration.
 */
protected CompletableFuture<Long> configure(Collection<RaftMember> members) {
  raft.checkThread();

  final long term = raft.getTerm();

  return appendAndCompact(new ConfigurationEntry(term, System.currentTimeMillis(), members))
      .thenComposeAsync(entry -> {
        // Store the index of the configuration entry in order to prevent other configurations from
        // being logged and committed concurrently. This is an important safety property of Raft.
        configuring = entry.index();
        raft.getCluster().configure(new Configuration(entry.index(), entry.entry().term(), entry.entry().timestamp(), entry.entry().members()));

        return appender.appendEntries(entry.index()).whenComplete((commitIndex, commitError) -> {
          raft.checkThread();
          if (isRunning() && commitError == null) {
            raft.getServiceManager().<OperationResult>apply(entry.index());
          }
          configuring = 0;
        });
      }, raft.getThreadContext());
}
 
Example #3
Source File: InactiveRole.java    From atomix with Apache License 2.0 6 votes vote down vote up
@Override
public CompletableFuture<ConfigureResponse> onConfigure(ConfigureRequest request) {
  raft.checkThread();
  logRequest(request);
  updateTermAndLeader(request.term(), request.leader());

  Configuration configuration = new Configuration(request.index(), request.term(), request.timestamp(), request.members());

  // Configure the cluster membership. This will cause this server to transition to the
  // appropriate state if its type has changed.
  raft.getCluster().configure(configuration);

  // If the configuration is already committed, commit it to disk.
  // Check against the actual cluster Configuration rather than the received configuration in
  // case the received configuration was an older configuration that was not applied.
  if (raft.getCommitIndex() >= raft.getCluster().getConfiguration().index()) {
    raft.getCluster().commit();
  }

  return CompletableFuture.completedFuture(logResponse(ConfigureResponse.builder()
      .withStatus(RaftResponse.Status.OK)
      .build()));
}
 
Example #4
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public synchronized CompletableFuture<Void> listen(Collection<MemberId> cluster) {
  if (joinFuture != null) {
    return joinFuture;
  }

  // If no configuration was loaded from disk, create a new configuration.
  if (configuration == null) {
    member.setType(RaftMember.Type.PASSIVE);

    // Create a set of cluster members, excluding the local member which is joining a cluster.
    Set<RaftMember> activeMembers = cluster.stream()
        .filter(m -> !m.equals(member.memberId()))
        .map(m -> new DefaultRaftMember(m, RaftMember.Type.ACTIVE, member.getLastUpdated()))
        .collect(Collectors.toSet());

    // If the set of members in the cluster is empty when the local member is excluded,
    // fail the join.
    if (activeMembers.isEmpty()) {
      return Futures.exceptionalFuture(new IllegalStateException("cannot join empty cluster"));
    }

    // Create a new configuration and configure the cluster. Once the cluster is configured, the configuration
    // will be stored on disk to ensure the cluster can fall back to the provided configuration if necessary.
    configure(new Configuration(0, 0, member.getLastUpdated().toEpochMilli(), activeMembers));
  }
  return join();
}
 
Example #5
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
@Override
public synchronized CompletableFuture<Void> join(Collection<MemberId> cluster) {
  if (joinFuture != null) {
    return joinFuture;
  }

  // If no configuration was loaded from disk, create a new configuration.
  if (configuration == null) {
    member.setType(RaftMember.Type.PROMOTABLE);

    // Create a set of cluster members, excluding the local member which is joining a cluster.
    Set<RaftMember> activeMembers = cluster.stream()
        .filter(m -> !m.equals(member.memberId()))
        .map(m -> new DefaultRaftMember(m, RaftMember.Type.ACTIVE, member.getLastUpdated()))
        .collect(Collectors.toSet());

    // If the set of members in the cluster is empty when the local member is excluded,
    // fail the join.
    if (activeMembers.isEmpty()) {
      return Futures.exceptionalFuture(new IllegalStateException("cannot join empty cluster"));
    }

    // Create a new configuration and configure the cluster. Once the cluster is configured, the configuration
    // will be stored on disk to ensure the cluster can fall back to the provided configuration if necessary.
    configure(new Configuration(0, 0, member.getLastUpdated().toEpochMilli(), activeMembers));
  }

  return join().thenCompose(v -> {
    if (member.getType() == RaftMember.Type.ACTIVE) {
      return CompletableFuture.completedFuture(null);
    } else {
      return member.promote(RaftMember.Type.ACTIVE);
    }
  });
}
 
Example #6
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Attempts to leave the cluster.
 */
private void leave(CompletableFuture<Void> future) {
  // Set a timer to retry the attempt to leave the cluster.
  leaveTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout(), () -> {
    leave(future);
  });

  // Attempt to leave the cluster by submitting a LeaveRequest directly to the server state.
  // Non-leader states should forward the request to the leader if there is one. Leader states
  // will log, replicate, and commit the reconfiguration.
  raft.getRaftRole().onLeave(LeaveRequest.builder()
      .withMember(getMember())
      .build()).whenComplete((response, error) -> {
        // Cancel the leave timer.
        cancelLeaveTimer();

        if (error == null && response.status() == RaftResponse.Status.OK) {
          Configuration configuration = new Configuration(response.index(), response.term(), response.timestamp(), response.members());

          // Configure the cluster and commit the configuration as we know the successful response
          // indicates commitment.
          configure(configuration).commit();
          future.complete(null);
        } else {
          // Reset the leave timer.
          leaveTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout(), () -> {
            leave(future);
          });
        }
      });
}
 
Example #7
Source File: DefaultRaftMember.java    From atomix with Apache License 2.0 5 votes vote down vote up
/**
 * Recursively reconfigures the cluster.
 */
private void configure(RaftMember.Type type, CompletableFuture<Void> future) {
  // Set a timer to retry the attempt to leave the cluster.
  configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout(), () -> {
    configure(type, future);
  });

  // Attempt to leave the cluster by submitting a LeaveRequest directly to the server state.
  // Non-leader states should forward the request to the leader if there is one. Leader states
  // will log, replicate, and commit the reconfiguration.
  cluster.getContext().getRaftRole().onReconfigure(ReconfigureRequest.builder()
      .withIndex(cluster.getConfiguration().index())
      .withTerm(cluster.getConfiguration().term())
      .withMember(new DefaultRaftMember(id, type, updated))
      .build()).whenComplete((response, error) -> {
        if (error == null) {
          if (response.status() == RaftResponse.Status.OK) {
            cancelConfigureTimer();
            cluster.configure(new Configuration(response.index(), response.term(), response.timestamp(), response.members()));
            future.complete(null);
          } else if (response.error() == null
              || response.error().type() == RaftError.Type.UNAVAILABLE
              || response.error().type() == RaftError.Type.PROTOCOL_ERROR
              || response.error().type() == RaftError.Type.NO_LEADER) {
            cancelConfigureTimer();
            configureTimeout = cluster.getContext().getThreadContext().schedule(cluster.getContext().getElectionTimeout().multipliedBy(2), () -> configure(type, future));
          } else {
            cancelConfigureTimer();
            future.completeExceptionally(response.error().createException());
          }
        } else {
          future.completeExceptionally(error);
        }
      });
}
 
Example #8
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 4 votes vote down vote up
/**
 * Recursively attempts to join the cluster.
 */
private void join(Iterator<RaftMemberContext> iterator) {
  if (iterator.hasNext()) {
    cancelJoinTimer();
    joinTimeout = raft.getThreadContext().schedule(raft.getElectionTimeout().multipliedBy(2), () -> {
      join(iterator);
    });

    RaftMemberContext member = iterator.next();

    log.debug("Attempting to join via {}", member.getMember().memberId());

    JoinRequest request = JoinRequest.builder()
        .withMember(new DefaultRaftMember(getMember().memberId(), getMember().getType(), getMember().getLastUpdated()))
        .build();
    raft.getProtocol().join(member.getMember().memberId(), request).whenCompleteAsync((response, error) -> {
      // Cancel the join timer.
      cancelJoinTimer();

      if (error == null) {
        if (response.status() == RaftResponse.Status.OK) {
          log.debug("Successfully joined via {}", member.getMember().memberId());

          Configuration configuration = new Configuration(response.index(), response.term(), response.timestamp(), response.members());

          // Configure the cluster with the join response.
          // Commit the configuration as we know it was committed via the successful join response.
          configure(configuration).commit();

          // If the local member is not present in the configuration, fail the future.
          if (!members.contains(this.member)) {
            joinFuture.completeExceptionally(new IllegalStateException("not a member of the cluster"));
          } else if (joinFuture != null) {
            joinFuture.complete(null);
          }
        } else if (response.error() == null || response.error().type() == RaftError.Type.CONFIGURATION_ERROR) {
          // If the response error is null, that indicates that no error occurred but the leader was
          // in a state that was incapable of handling the join request. Attempt to join the leader
          // again after an election timeout.
          log.debug("Failed to join {}", member.getMember().memberId());
          resetJoinTimer();
        } else {
          // If the response error was non-null, attempt to join via the next server in the members list.
          log.debug("Failed to join {}", member.getMember().memberId());
          join(iterator);
        }
      } else {
        log.debug("Failed to join {}", member.getMember().memberId());
        join(iterator);
      }
    }, raft.getThreadContext());
  }
  // If join attempts remain, schedule another attempt after two election timeouts. This allows enough time
  // for servers to potentially timeout and elect a leader.
  else {
    log.debug("Failed to join cluster, retrying...");
    resetJoinTimer();
  }
}
 
Example #9
Source File: RaftClusterContext.java    From atomix with Apache License 2.0 2 votes vote down vote up
/**
 * Returns the cluster configuration.
 *
 * @return The cluster configuration.
 */
public Configuration getConfiguration() {
  return configuration;
}