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

io.atomix.raft.storage.system.Configuration Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2015-present Open Networking Foundation
 * Copyright © 2020 camunda services GmbH ([email protected])
 *
 * 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 io.atomix.raft.storage.system;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.collect.ImmutableList;
import io.atomix.cluster.MemberId;
import io.atomix.raft.cluster.RaftMember;
import io.atomix.raft.cluster.impl.DefaultRaftMember;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Represents a persisted server configuration.
 *
 * @param index The index is the index of the {@link
 *     io.atomix.raft.storage.log.entry.ConfigurationEntry ConfigurationEntry} which resulted in
 *     this configuration.
 * @param term The term is the term of the leader at the time the configuration change was
 *     committed.
 * @param time The time at which the configuration was committed.
 * @param newMembers The cluster membership for this configuration.
 * @param oldMembers The cluster membership for the previous configuration.
 * @param force True indicates, we are skipping joint consensus and force the configuration change
 *     without a quorum.
 */
public record Configuration(
    long index,
    long term,
    long time,
    Collection newMembers,
    Collection oldMembers,
    boolean force) {

  public Configuration(
      final long index,
      final long term,
      final long time,
      final Collection newMembers,
      final Collection oldMembers,
      final boolean force) {
    checkArgument(time > 0, "time must be positive");
    checkNotNull(newMembers, "newMembers cannot be null");
    checkNotNull(oldMembers, "oldMembers cannot be null");

    this.index = index;
    this.term = term;
    this.time = time;
    this.newMembers = copyMembers(newMembers);
    this.oldMembers = copyMembers(oldMembers);
    this.force = force;

    if (force) {
      checkArgument(oldMembers.isEmpty(), "oldMembers must be empty when force is true");
      checkArgument(!newMembers.isEmpty(), "newMembers must not be empty when force is true");
    }
  }

  public Configuration(
      final long index,
      final long term,
      final long time,
      final Collection newMembers,
      final Collection oldMembers) {
    this(index, term, time, newMembers, oldMembers, false);
  }

  public Configuration(
      final long index, final long term, final long time, final Collection members) {
    this(index, term, time, members, Collections.emptyList());
  }

  public boolean requiresJointConsensus() {
    return !oldMembers.isEmpty();
  }

  /**
   * @return a set of all members in the configuration. During joint consensus where a member can be
   *     in both the old and new configuration, the member with the higher {@link RaftMember.Type
   *     type} is used.
   */
  public Set allMembers() {
    return new HashSet<>(
        Stream.concat(newMembers.stream(), oldMembers.stream())
            .collect(
                Collectors.toMap(
                    RaftMember::memberId,
                    Function.identity(),
                    BinaryOperator.maxBy(Comparator.comparing(RaftMember::getType))))
            .values());
  }

  private static Collection copyMembers(final Collection members) {
    final var copied = ImmutableList.builderWithExpectedSize(members.size());
    for (final var member : members) {
      copied.add(
          new DefaultRaftMember(member.memberId(), member.getType(), member.getLastUpdated()));
    }
    return copied.build();
  }

  public boolean hasMember(final MemberId member) {
    return allMembers().stream().anyMatch(m -> m.memberId().equals(member));
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy