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

io.atomix.copycat.server.state.ClusterState Maven / Gradle / Ivy

There is a newer version: 1.2.8
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * 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.copycat.server.state;

import io.atomix.catalyst.transport.Address;
import io.atomix.catalyst.util.Assert;

import java.util.*;

/**
 * Cluster state.
 *
 * @author Jordan Halterman
 */
class ClusterState {
  private final ServerState context;
  private final Address address;
  private Type type = Type.PASSIVE;
  private long version = -1;
  private final Map membersMap = new HashMap<>();
  private final Map types = new HashMap<>();
  private final List members = new ArrayList<>();
  private final List activeMembers = new ArrayList<>();
  private final List passiveMembers = new ArrayList<>();

  /**
   * Member state type.
   */
  private enum Type {
    ACTIVE,
    PASSIVE
  }

  ClusterState(ServerState context, Address address) {
    this.context = Assert.notNull(context, "context");
    this.address = Assert.notNull(address, "address");
  }

  /**
   * Returns the local cluster member address.
   *
   * @return The local cluster member address.
   */
  Address getAddress() {
    return address;
  }

  /**
   * Returns a boolean value indicating whether the local member is active.
   *
   * @return Indicates whether the local member is active.
   */
  boolean isActive() {
    return type == Type.ACTIVE;
  }

  /**
   * Sets whether the local member is active.
   *
   * @param active Whether the local member is active.
   * @return The cluster state.
   */
  ClusterState setActive(boolean active) {
    type = active ? Type.ACTIVE : Type.PASSIVE;
    return this;
  }

  /**
   * Returns a boolean value indicating whether the local member is passive.
   *
   * @return Indicates whether the local member is passive.
   */
  boolean isPassive() {
    return type == Type.PASSIVE;
  }

  /**
   * Sets whether the local member is passive.
   *
   * @param passive Whether the local member is passive.
   * @return The cluster state.
   */
  ClusterState setPassive(boolean passive) {
    type = passive ? Type.PASSIVE : Type.ACTIVE;
    return this;
  }

  /**
   * Returns the remote quorum count.
   *
   * @return The remote quorum count.
   */
  int getQuorum() {
    return (int) Math.floor((activeMembers.size() + 1) / 2.0) + 1;
  }

  /**
   * Returns the cluster state version.
   *
   * @return The cluster state version.
   */
  long getVersion() {
    return version;
  }

  /**
   * Clears all members from the cluster state.
   *
   * @return The cluster state.
   */
  private ClusterState clearMembers() {
    members.clear();
    activeMembers.clear();
    passiveMembers.clear();
    membersMap.clear();
    types.clear();
    return this;
  }

  /**
   * Returns a member by ID.
   *
   * @param id The member ID.
   * @return The member state.
   */
  MemberState getMember(int id) {
    return membersMap.get(id);
  }

  /**
   * Returns a boolean value indicating whether the given member is active.
   *
   * @param member The member state.
   * @return Indicates whether the member is active.
   */
  boolean isActiveMember(MemberState member) {
    return types.get(member.getAddress().hashCode()) == Type.ACTIVE;
  }

  /**
   * Returns a boolean value indicating whether the given member is passive.
   *
   * @param member The member state.
   * @return Indicates whether the member is passive.
   */
  boolean isPassiveMember(MemberState member) {
    return types.get(member.getAddress().hashCode()) == Type.PASSIVE;
  }

  /**
   * Returns a list of passive members.
   *
   * @return A list of passive members.
   */
  List getPassiveMembers() {
    return passiveMembers;
  }

  /**
   * Returns a list of passive members.
   *
   * @param comparator A comparator with which to sort the members list.
   * @return The sorted members list.
   */
  List getPassiveMembers(Comparator comparator) {
    Collections.sort(passiveMembers, comparator);
    return passiveMembers;
  }

  /**
   * Returns a list of active members.
   *
   * @return A list of active members.
   */
  List getActiveMembers() {
    return activeMembers;
  }

  /**
   * Returns a list of active members.
   *
   * @param comparator A comparator with which to sort the members list.
   * @return The sorted members list.
   */
  List getActiveMembers(Comparator comparator) {
    Collections.sort(activeMembers, comparator);
    return activeMembers;
  }

  /**
   * Returns a list of all members.
   *
   * @return A list of all members.
   */
  List getMembers() {
    return members;
  }

  /**
   * Configures the cluster state.
   *
   * @param version The cluster state version.
   * @param activeMembers The active members.
   * @param passiveMembers The passive members.
   * @return The cluster state.
   */
  ClusterState configure(long version, Collection
activeMembers, Collection
passiveMembers) { if (version <= this.version) return this; List newActiveMembers = buildMembers(activeMembers); List newPassiveMembers = buildMembers(passiveMembers); clearMembers(); for (MemberState member : newActiveMembers) { membersMap.put(member.getAddress().hashCode(), member); members.add(member); this.activeMembers.add(member); types.put(member.getAddress().hashCode(), Type.ACTIVE); } for (MemberState member : newPassiveMembers) { membersMap.put(member.getAddress().hashCode(), member); members.add(member); this.passiveMembers.add(member); types.put(member.getAddress().hashCode(), Type.PASSIVE); } if (activeMembers.contains(address)) { type = Type.ACTIVE; } else if (passiveMembers.contains(address)) { type = Type.PASSIVE; } else { type = null; } this.version = version; return this; } /** * Builds a list of all members. */ Collection
buildMembers() { List
members = new ArrayList<>(); for (MemberState member : activeMembers) { members.add(member.getAddress()); } for (MemberState member : passiveMembers) { members.add(member.getAddress()); } if (type != null) { members.add(address); } return members; } /** * Builds a list of active members. */ Collection
buildActiveMembers() { List
members = new ArrayList<>(); for (MemberState state : activeMembers) { members.add(state.getAddress()); } if (type == Type.ACTIVE) { members.add(address); } return members; } /** * Builds a list of passive members. */ Collection
buildPassiveMembers() { List
members = new ArrayList<>(); for (MemberState state : passiveMembers) { members.add(state.getAddress()); } if (type == Type.PASSIVE) { members.add(address); } return members; } /** * Builds a members list. */ private List buildMembers(Collection
members) { List states = new ArrayList<>(members.size()); for (Address address : members) { if (!address.equals(this.address)) { MemberState state = membersMap.get(address.hashCode()); if (state == null) { state = new MemberState(address); state.setNextIndex(Math.max(state.getMatchIndex(), Math.max(context.getLog().lastIndex(), 1))); } states.add(state); } } return states; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy