package com.jivesoftware.os.amza.api.partition;
import com.google.common.collect.ImmutableSet;
import java.util.Set;
/**
* @author jonathan.colt
*/
public enum Consistency {
/**
* Writes are routed to an elected node. No synchronous replication is performed.
* Reads are routed to an elected node.
*/
leader((byte) 1, true,
numberOfNeighbors -> 0,
numberOfNeighbors -> {
throw new UnsupportedOperationException("Leader consistency has no repair quorum, please take from the demoted leader");
}),
/**
* Writes are routed to an elected node. Each write will be synchronously replicated to at least one other node.
* Reads are routed to an elected node. If elected node is offline then a read request will re-routed to all other nodes and merged at the client.
*/
leader_plus_one((byte) 2, true,
numberOfNeighbors -> {
if (numberOfNeighbors == 0) {
throw new IllegalArgumentException("Leader plus one consistency requires at least one neighbor");
}
return 1;
},
numberOfNeighbors -> numberOfNeighbors - 1),
/**
* Writes are routed to an elected node. Each write will be synchronously replicated to an additional quorum of nodes based on ring size at write time.
* Reads are routed to an elected node. If elected node is offline then a read request will re-routed to a quorum of other nodes and merged at the client.
*/
leader_quorum((byte) 3, true,
numberOfNeighbors -> (numberOfNeighbors + 1) / 2,
numberOfNeighbors -> numberOfNeighbors / 2),
/**
* Writes are routed to an elected node. Each write will be synchronously replicated to all nodes based on ring size at write time.
* Reads are routed to an elected node. If elected node is offline then a read request will re-routed to a random node.
*/
leader_all((byte) 4, true,
numberOfNeighbors -> numberOfNeighbors,
numberOfNeighbors -> 0),
/**
* Writes are synchronously replicated to a quorum of nodes based on ring size at write time.
* Reads are routed to a quorum of nodes and merged at the client.
*/
quorum((byte) 11, false,
numberOfNeighbors -> (numberOfNeighbors + 1) / 2,
numberOfNeighbors -> numberOfNeighbors / 2),
/**
* Writes are synchronously written to all nodes based on ring size at write time.
* Reads are routed to a random node.
*/
write_all_read_one((byte) 21, false,
numberOfNeighbors -> numberOfNeighbors,
numberOfNeighbors -> 0),
/**
* Writes are to a random node based on ring size at write time.
* Reads are routed to all nodes and merged at the client.
*/
write_one_read_all((byte) 22, false,
numberOfNeighbors -> 0,
numberOfNeighbors -> numberOfNeighbors),
/**
* Writes are to a random node based on ring size at write time.
* Reads are to a random node based on ring size at write time.
*/
none((byte) 127, false,
numberOfNeighbors -> 0,
numberOfNeighbors -> 0);
private static final Set<Consistency>[] WRITES_SUPPORT;
private static final Set<Consistency>[] READS_SUPPORT;
static {
@SuppressWarnings("unchecked")
Set<Consistency>[] writesSupport = new Set[Consistency.values().length];
writesSupport[leader.ordinal()] = ImmutableSet.of(leader, leader_plus_one, leader_quorum, leader_all, write_all_read_one);
writesSupport[leader_plus_one.ordinal()] = ImmutableSet.of(leader_plus_one, leader_quorum, leader_all, write_all_read_one);
writesSupport[leader_quorum.ordinal()] = ImmutableSet.of(leader_quorum, leader_all, write_all_read_one);
writesSupport[leader_all.ordinal()] = ImmutableSet.of(leader_all, write_all_read_one);
writesSupport[quorum.ordinal()] = ImmutableSet.of(leader_quorum, leader_all, quorum, write_all_read_one);
writesSupport[write_all_read_one.ordinal()] = ImmutableSet.of(leader_all, write_all_read_one);
writesSupport[write_one_read_all.ordinal()] = ImmutableSet.copyOf(Consistency.values());
writesSupport[none.ordinal()] = ImmutableSet.copyOf(Consistency.values());
WRITES_SUPPORT = writesSupport;
@SuppressWarnings("unchecked")
Set<Consistency>[] readsSupport = new Set[Consistency.values().length];
readsSupport[leader.ordinal()] = ImmutableSet.of(leader, write_one_read_all, none);
readsSupport[leader_plus_one.ordinal()] = ImmutableSet.of(leader, leader_plus_one, write_one_read_all, none);
readsSupport[leader_quorum.ordinal()] = ImmutableSet.of(leader, leader_quorum, quorum, write_one_read_all, none);
readsSupport[leader_all.ordinal()] = ImmutableSet.copyOf(Consistency.values());
readsSupport[quorum.ordinal()] = ImmutableSet.of(quorum, write_one_read_all, none);
readsSupport[write_all_read_one.ordinal()] = ImmutableSet.copyOf(Consistency.values());
readsSupport[write_one_read_all.ordinal()] = ImmutableSet.of(write_one_read_all, none);
readsSupport[none.ordinal()] = ImmutableSet.copyOf(Consistency.values());
READS_SUPPORT = readsSupport;
}
private final byte serializedByte;
private final boolean requiresLeader;
private final NumberOfNeighborsQuorum writeQuorum;
private final NumberOfNeighborsQuorum repairQuorum;
Consistency(byte serializedByte, boolean requiresLeader, NumberOfNeighborsQuorum writeQuorum, NumberOfNeighborsQuorum repairQuorum) {
this.serializedByte = serializedByte;
this.requiresLeader = requiresLeader;
this.writeQuorum = writeQuorum;
this.repairQuorum = repairQuorum;
}
public boolean requiresLeader() {
return requiresLeader;
}
public byte toBytes() {
return serializedByte;
}
static Consistency fromBytes(byte[] b) {
for (Consistency v : values()) {
if (v.serializedByte == b[0]) {
return v;
}
}
return null;
}
public boolean supportsWrites(Consistency consistency) {
return WRITES_SUPPORT[ordinal()].contains(consistency);
}
public boolean supportsReads(Consistency consistency) {
return READS_SUPPORT[ordinal()].contains(consistency);
}
interface NumberOfNeighborsQuorum {
int quorum(int numberOfNeighbors);
}
public int quorum(int numberOfNeighbors) {
return writeQuorum.quorum(numberOfNeighbors);
}
public int repairQuorum(int numberOfNeighbors) {
return repairQuorum.quorum(numberOfNeighbors);
}
}