Fixed build

This commit is contained in:
Jaime Freire
2023-11-25 09:11:39 +01:00
parent 789a5f6abc
commit c0d8cc348c
71 changed files with 1426 additions and 1197 deletions

View File

@ -21,10 +21,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.gossip.lock.LockManagerSettings; import org.apache.gossip.lock.LockManagerSettings;
/** /** In this object the settings used by the GossipService are held. */
* In this object the settings used by the GossipService are held.
*
*/
public class GossipSettings { public class GossipSettings {
/** Time between gossip'ing in ms. Default is 1 second. */ /** Time between gossip'ing in ms. Default is 1 second. */
@ -35,58 +32,59 @@ public class GossipSettings {
/** the minimum samples needed before reporting a result */ /** the minimum samples needed before reporting a result */
private int minimumSamples = 5; private int minimumSamples = 5;
/** the number of samples to keep per host */ /** the number of samples to keep per host */
private int windowSize = 5000; private int windowSize = 5000;
/** the threshold for the detector */ /** the threshold for the detector */
private double convictThreshold = 10; private double convictThreshold = 10;
private String distribution = "normal"; private String distribution = "normal";
private String activeGossipClass = "org.apache.gossip.manager.SimpleActiveGossiper"; private String activeGossipClass = "org.apache.gossip.manager.SimpleActiveGossiper";
private String transportManagerClass = "org.apache.gossip.transport.udp.UdpTransportManager"; private String transportManagerClass = "org.apache.gossip.transport.udp.UdpTransportManager";
private String protocolManagerClass = "org.apache.gossip.protocol.json.JacksonProtocolManager"; private String protocolManagerClass = "org.apache.gossip.protocol.json.JacksonProtocolManager";
private Map<String,String> activeGossipProperties = new HashMap<>(); private Map<String, String> activeGossipProperties = new HashMap<>();
private String pathToRingState = "./"; private String pathToRingState = "./";
private boolean persistRingState = true; private boolean persistRingState = true;
private String pathToDataState = "./"; private String pathToDataState = "./";
private boolean persistDataState = true; private boolean persistDataState = true;
private String pathToKeyStore = "./keys"; private String pathToKeyStore = "./keys";
private boolean signMessages = false; private boolean signMessages = false;
// Settings related to lock manager // Settings related to lock manager
private LockManagerSettings lockManagerSettings = LockManagerSettings private LockManagerSettings lockManagerSettings =
.getLockManagerDefaultSettings(); LockManagerSettings.getLockManagerDefaultSettings();
private boolean bulkTransfer = false; private boolean bulkTransfer = false;
private int bulkTransferSize = StartupSettings.DEFAULT_BULK_TRANSFER_SIZE; private int bulkTransferSize = StartupSettings.DEFAULT_BULK_TRANSFER_SIZE;
/** /** Construct GossipSettings with default settings. */
* Construct GossipSettings with default settings. public GossipSettings() {}
*/
public GossipSettings() {
}
/** /**
* Construct GossipSettings with given settings. * Construct GossipSettings with given settings.
* *
* @param gossipInterval * @param gossipInterval The gossip interval in ms.
* The gossip interval in ms. * @param cleanupInterval The cleanup interval in ms.
* @param cleanupInterval
* The cleanup interval in ms.
*/ */
public GossipSettings(int gossipInterval, int cleanupInterval, int windowSize, int minimumSamples, public GossipSettings(
double convictThreshold, String distribution, boolean bulkTransfer) { int gossipInterval,
int cleanupInterval,
int windowSize,
int minimumSamples,
double convictThreshold,
String distribution,
boolean bulkTransfer) {
this.gossipInterval = gossipInterval; this.gossipInterval = gossipInterval;
this.cleanupInterval = cleanupInterval; this.cleanupInterval = cleanupInterval;
this.windowSize = windowSize; this.windowSize = windowSize;
@ -98,9 +96,8 @@ public class GossipSettings {
/** /**
* Set the gossip interval. This is the time between a gossip message is send. * Set the gossip interval. This is the time between a gossip message is send.
* *
* @param gossipInterval * @param gossipInterval The gossip interval in ms.
* The gossip interval in ms.
*/ */
public void setGossipTimeout(int gossipInterval) { public void setGossipTimeout(int gossipInterval) {
this.gossipInterval = gossipInterval; this.gossipInterval = gossipInterval;
@ -121,7 +118,7 @@ public class GossipSettings {
/** /**
* Get the clean interval. * Get the clean interval.
* *
* @return The cleanup interval. * @return The cleanup interval.
*/ */
public int getCleanupInterval() { public int getCleanupInterval() {
@ -132,8 +129,7 @@ public class GossipSettings {
* Set the cleanup interval. This is the time between the last heartbeat received from a member * Set the cleanup interval. This is the time between the last heartbeat received from a member
* and when it will be marked as dead. * and when it will be marked as dead.
* *
* @param cleanupInterval * @param cleanupInterval The cleanup interval in ms.
* The cleanup interval in ms.
*/ */
public void setCleanupInterval(int cleanupInterval) { public void setCleanupInterval(int cleanupInterval) {
this.cleanupInterval = cleanupInterval; this.cleanupInterval = cleanupInterval;
@ -257,6 +253,7 @@ public class GossipSettings {
/** /**
* Set the lock settings use by the lock manager * Set the lock settings use by the lock manager
*
* @param lockManagerSettings lock settings. This object cannot be null. * @param lockManagerSettings lock settings. This object cannot be null.
*/ */
public void setLockManagerSettings(LockManagerSettings lockManagerSettings) { public void setLockManagerSettings(LockManagerSettings lockManagerSettings) {

View File

@ -19,7 +19,6 @@ package org.apache.gossip;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import org.apache.gossip.accrual.FailureDetector; import org.apache.gossip.accrual.FailureDetector;
/** /**

View File

@ -32,34 +32,33 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
/** /** This object represents the settings used when starting the gossip service. */
* This object represents the settings used when starting the gossip service.
*
*/
@Slf4j @Slf4j
public class StartupSettings { public class StartupSettings {
public static final int DEFAULT_BULK_TRANSFER_SIZE = 100; public static final int DEFAULT_BULK_TRANSFER_SIZE = 100;
/** Default setting values */ /** Default setting values */
private static final boolean DEFAULT_BULK_TRANSFER = false; private static final boolean DEFAULT_BULK_TRANSFER = false;
/** The gossip settings used at startup. */ /** The gossip settings used at startup. */
private final GossipSettings gossipSettings; private final GossipSettings gossipSettings;
/** The list with gossip members to start with. */ /** The list with gossip members to start with. */
private final List<Member> gossipMembers; private final List<Member> gossipMembers;
/** The id to use fo the service */ /** The id to use fo the service */
private String id; private String id;
private URI uri; private URI uri;
private String cluster; private String cluster;
/** /**
* Constructor. * Constructor.
* *
* @param id * @param id The id to be used for this service
* The id to be used for this service * @param uri A URI object containing IP/hostname and port
* @param uri * @param logLevel unused
* A URI object containing IP/hostname and port
* @param logLevel
* unused
*/ */
public StartupSettings(String id, URI uri, int logLevel, String cluster) { public StartupSettings(String id, URI uri, int logLevel, String cluster) {
this(id, uri, new GossipSettings(), cluster); this(id, uri, new GossipSettings(), cluster);
@ -68,10 +67,8 @@ public class StartupSettings {
/** /**
* Constructor. * Constructor.
* *
* @param id * @param id The id to be used for this service
* The id to be used for this service * @param uri A URI object containing IP/hostname and port
* @param uri
* A URI object containing IP/hostname and port
*/ */
public StartupSettings(String id, URI uri, GossipSettings gossipSettings, String cluster) { public StartupSettings(String id, URI uri, GossipSettings gossipSettings, String cluster) {
this.id = id; this.id = id;
@ -84,30 +81,27 @@ public class StartupSettings {
/** /**
* Parse the settings for the gossip service from a JSON file. * Parse the settings for the gossip service from a JSON file.
* *
* @param jsonFile * @param jsonFile The file object which refers to the JSON config file.
* The file object which refers to the JSON config file.
* @return The StartupSettings object with the settings from the config file. * @return The StartupSettings object with the settings from the config file.
* @throws FileNotFoundException * @throws FileNotFoundException Thrown when the file cannot be found.
* Thrown when the file cannot be found. * @throws IOException Thrown when reading the file gives problems.
* @throws IOException
* Thrown when reading the file gives problems.
* @throws URISyntaxException * @throws URISyntaxException
*/ */
public static StartupSettings fromJSONFile(File jsonFile) throws public static StartupSettings fromJSONFile(File jsonFile)
FileNotFoundException, IOException, URISyntaxException { throws FileNotFoundException, IOException, URISyntaxException {
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
JsonNode root = om.readTree(jsonFile); JsonNode root = om.readTree(jsonFile);
JsonNode jsonObject = root.get(0); JsonNode jsonObject = root.get(0);
String uri = jsonObject.get("uri").textValue(); String uri = jsonObject.get("uri").textValue();
String id = jsonObject.get("id").textValue(); String id = jsonObject.get("id").textValue();
Map<String,String> properties = new HashMap<String,String>(); Map<String, String> properties = new HashMap<String, String>();
JsonNode n = jsonObject.get("properties"); JsonNode n = jsonObject.get("properties");
Iterator<Entry<String, JsonNode>> l = n.fields(); Iterator<Entry<String, JsonNode>> l = n.fields();
while (l.hasNext()){ while (l.hasNext()) {
Entry<String, JsonNode> i = l.next(); Entry<String, JsonNode> i = l.next();
properties.put(i.getKey(), i.getValue().asText()); properties.put(i.getKey(), i.getValue().asText());
} }
//TODO constants as defaults? // TODO constants as defaults?
// TODO setting keys as constants? // TODO setting keys as constants?
int gossipInterval = jsonObject.get("gossip_interval").intValue(); int gossipInterval = jsonObject.get("gossip_interval").intValue();
int cleanupInterval = jsonObject.get("cleanup_interval").intValue(); int cleanupInterval = jsonObject.get("cleanup_interval").intValue();
@ -116,24 +110,35 @@ public class StartupSettings {
double convictThreshold = jsonObject.get("convict_threshold").asDouble(); double convictThreshold = jsonObject.get("convict_threshold").asDouble();
String cluster = jsonObject.get("cluster").textValue(); String cluster = jsonObject.get("cluster").textValue();
String distribution = jsonObject.get("distribution").textValue(); String distribution = jsonObject.get("distribution").textValue();
boolean bulkTransfer = jsonObject.has("bulk_transfer") ? boolean bulkTransfer =
jsonObject.get("bulk_transfer").booleanValue() : jsonObject.has("bulk_transfer")
DEFAULT_BULK_TRANSFER; ? jsonObject.get("bulk_transfer").booleanValue()
int bulkTransferSize = jsonObject.has("bulk_transfer_size") ? : DEFAULT_BULK_TRANSFER;
jsonObject.get("bulk_transfer_size").intValue() : int bulkTransferSize =
DEFAULT_BULK_TRANSFER_SIZE; jsonObject.has("bulk_transfer_size")
if (cluster == null){ ? jsonObject.get("bulk_transfer_size").intValue()
: DEFAULT_BULK_TRANSFER_SIZE;
if (cluster == null) {
throw new IllegalArgumentException("cluster was null. It is required"); throw new IllegalArgumentException("cluster was null. It is required");
} }
String transportClass = jsonObject.has("transport_manager_class") ? String transportClass =
jsonObject.get("transport_manager_class").textValue() : jsonObject.has("transport_manager_class")
null; ? jsonObject.get("transport_manager_class").textValue()
String protocolClass = jsonObject.has("protocol_manager_class") ? : null;
jsonObject.get("protocol_manager_class").textValue() : String protocolClass =
null; jsonObject.has("protocol_manager_class")
? jsonObject.get("protocol_manager_class").textValue()
: null;
URI uri2 = new URI(uri); URI uri2 = new URI(uri);
GossipSettings gossipSettings = new GossipSettings(gossipInterval, cleanupInterval, windowSize, GossipSettings gossipSettings =
minSamples, convictThreshold, distribution, bulkTransfer); new GossipSettings(
gossipInterval,
cleanupInterval,
windowSize,
minSamples,
convictThreshold,
distribution,
bulkTransfer);
gossipSettings.setBulkTransferSize(bulkTransferSize); gossipSettings.setBulkTransferSize(bulkTransferSize);
if (transportClass != null) { if (transportClass != null) {
gossipSettings.setTransportManagerClass(transportClass); gossipSettings.setTransportManagerClass(transportClass);
@ -144,15 +149,15 @@ public class StartupSettings {
StartupSettings settings = new StartupSettings(id, uri2, gossipSettings, cluster); StartupSettings settings = new StartupSettings(id, uri2, gossipSettings, cluster);
String configMembersDetails = "Config-members ["; String configMembersDetails = "Config-members [";
JsonNode membersJSON = jsonObject.get("members"); JsonNode membersJSON = jsonObject.get("members");
for (JsonNode child : membersJSON) { for (JsonNode child : membersJSON) {
URI uri3 = new URI(child.get("uri").textValue()); URI uri3 = new URI(child.get("uri").textValue());
RemoteMember member = new RemoteMember(child.get("cluster").asText(), RemoteMember member =
uri3, "", 0, new HashMap<String, String>() new RemoteMember(
); child.get("cluster").asText(), uri3, "", 0, new HashMap<String, String>());
settings.addGossipMember(member); settings.addGossipMember(member);
configMembersDetails += member.computeAddress(); configMembersDetails += member.computeAddress();
configMembersDetails += ", "; configMembersDetails += ", ";
} }
log.info(configMembersDetails + "]"); log.info(configMembersDetails + "]");
return settings; return settings;
} }
@ -175,7 +180,7 @@ public class StartupSettings {
/** /**
* Get the id for this service. * Get the id for this service.
* *
* @return the service's id. * @return the service's id.
*/ */
public String getId() { public String getId() {
@ -185,8 +190,7 @@ public class StartupSettings {
/** /**
* Set the id to be used for this service. * Set the id to be used for this service.
* *
* @param id * @param id The id for this service.
* The id for this service.
*/ */
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
@ -204,8 +208,7 @@ public class StartupSettings {
/** /**
* Add a gossip member to the list of members to start with. * Add a gossip member to the list of members to start with.
* *
* @param member * @param member The member to add.
* The member to add.
*/ */
public void addGossipMember(Member member) { public void addGossipMember(Member member) {
gossipMembers.add(member); gossipMembers.add(member);

View File

@ -38,8 +38,7 @@ public class FailureDetector {
} }
/** /**
* Updates the statistics based on the delta between the last * Updates the statistics based on the delta between the last heartbeat and supplied time
* heartbeat and supplied time
* *
* @param now the time of the heartbeat in milliseconds * @param now the time of the heartbeat in milliseconds
*/ */
@ -63,9 +62,13 @@ public class FailureDetector {
if (distribution.equals("normal")) { if (distribution.equals("normal")) {
double standardDeviation = descriptiveStatistics.getStandardDeviation(); double standardDeviation = descriptiveStatistics.getStandardDeviation();
standardDeviation = Math.max(standardDeviation, 0.1); standardDeviation = Math.max(standardDeviation, 0.1);
probability = new NormalDistribution(descriptiveStatistics.getMean(), standardDeviation).cumulativeProbability(delta); probability =
new NormalDistribution(descriptiveStatistics.getMean(), standardDeviation)
.cumulativeProbability(delta);
} else { } else {
probability = new ExponentialDistribution(descriptiveStatistics.getMean()).cumulativeProbability(delta); probability =
new ExponentialDistribution(descriptiveStatistics.getMean())
.cumulativeProbability(delta);
} }
final double eps = 1e-12; final double eps = 1e-12;
if (1 - probability < eps) { if (1 - probability < eps) {

View File

@ -37,105 +37,135 @@ import org.apache.gossip.replication.WhiteListReplicable;
abstract class OrSetMixin<E> { abstract class OrSetMixin<E> {
@JsonCreator @JsonCreator
OrSetMixin(@JsonProperty("elements") Map<E, Set<UUID>> w, @JsonProperty("tombstones") Map<E, Set<UUID>> h) { } OrSetMixin(
@JsonProperty("elements") abstract Map<E, Set<UUID>> getElements(); @JsonProperty("elements") Map<E, Set<UUID>> w,
@JsonProperty("tombstones") abstract Map<E, Set<UUID>> getTombstones(); @JsonProperty("tombstones") Map<E, Set<UUID>> h) {}
@JsonIgnore abstract boolean isEmpty();
@JsonProperty("elements")
abstract Map<E, Set<UUID>> getElements();
@JsonProperty("tombstones")
abstract Map<E, Set<UUID>> getTombstones();
@JsonIgnore
abstract boolean isEmpty();
} }
abstract class LWWSetMixin<ElementType> { abstract class LWWSetMixin<ElementType> {
@JsonCreator @JsonCreator
LWWSetMixin(@JsonProperty("data") Map<ElementType, LwwSet.Timestamps> struct) { } LWWSetMixin(@JsonProperty("data") Map<ElementType, LwwSet.Timestamps> struct) {}
@JsonProperty("data") abstract Map<ElementType, LwwSet.Timestamps> getStruct();
@JsonProperty("data")
abstract Map<ElementType, LwwSet.Timestamps> getStruct();
} }
abstract class LWWSetTimestampsMixin { abstract class LWWSetTimestampsMixin {
@JsonCreator @JsonCreator
LWWSetTimestampsMixin(@JsonProperty("add") long latestAdd, @JsonProperty("remove") long latestRemove) { } LWWSetTimestampsMixin(
@JsonProperty("add") abstract long getLatestAdd(); @JsonProperty("add") long latestAdd, @JsonProperty("remove") long latestRemove) {}
@JsonProperty("remove") abstract long getLatestRemove();
@JsonProperty("add")
abstract long getLatestAdd();
@JsonProperty("remove")
abstract long getLatestRemove();
} }
abstract class MaxChangeSetMixin<E> { abstract class MaxChangeSetMixin<E> {
@JsonCreator @JsonCreator
MaxChangeSetMixin(@JsonProperty("data") Map<E, Integer> struct) { } MaxChangeSetMixin(@JsonProperty("data") Map<E, Integer> struct) {}
@JsonProperty("data") abstract Map<E, Integer> getStruct();
@JsonProperty("data")
abstract Map<E, Integer> getStruct();
} }
abstract class TwoPhaseSetMixin<E> { abstract class TwoPhaseSetMixin<E> {
@JsonCreator @JsonCreator
TwoPhaseSetMixin(@JsonProperty("added") Set<E> added, @JsonProperty("removed") Set<E> removed) { } TwoPhaseSetMixin(@JsonProperty("added") Set<E> added, @JsonProperty("removed") Set<E> removed) {}
@JsonProperty("added") abstract Set<E> getAdded();
@JsonProperty("removed") abstract Set<E> getRemoved(); @JsonProperty("added")
abstract Set<E> getAdded();
@JsonProperty("removed")
abstract Set<E> getRemoved();
} }
abstract class GrowOnlySetMixin<E>{ abstract class GrowOnlySetMixin<E> {
@JsonCreator @JsonCreator
GrowOnlySetMixin(@JsonProperty("elements") Set<E> elements){ } GrowOnlySetMixin(@JsonProperty("elements") Set<E> elements) {}
@JsonProperty("elements") abstract Set<E> getElements();
@JsonIgnore abstract boolean isEmpty(); @JsonProperty("elements")
abstract Set<E> getElements();
@JsonIgnore
abstract boolean isEmpty();
} }
abstract class GrowOnlyCounterMixin { abstract class GrowOnlyCounterMixin {
@JsonCreator @JsonCreator
GrowOnlyCounterMixin(@JsonProperty("counters") Map<String, Long> counters) { } GrowOnlyCounterMixin(@JsonProperty("counters") Map<String, Long> counters) {}
@JsonProperty("counters") abstract Map<String, Long> getCounters();
@JsonProperty("counters")
abstract Map<String, Long> getCounters();
} }
abstract class PNCounterMixin { abstract class PNCounterMixin {
@JsonCreator @JsonCreator
PNCounterMixin(@JsonProperty("p-counters") Map<String, Long> up, @JsonProperty("n-counters") Map<String,Long> down) { } PNCounterMixin(
@JsonProperty("p-counters") abstract Map<String, Long> getPCounters(); @JsonProperty("p-counters") Map<String, Long> up,
@JsonProperty("n-counters") abstract Map<String, Long> getNCounters(); @JsonProperty("n-counters") Map<String, Long> down) {}
@JsonProperty("p-counters")
abstract Map<String, Long> getPCounters();
@JsonProperty("n-counters")
abstract Map<String, Long> getNCounters();
} }
@JsonTypeInfo( @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
use = JsonTypeInfo.Id.CLASS, abstract class ReplicableMixin {}
include = JsonTypeInfo.As.PROPERTY,
property = "type")
abstract class ReplicableMixin {
}
abstract class WhiteListReplicableMixin { abstract class WhiteListReplicableMixin {
@JsonCreator @JsonCreator
WhiteListReplicableMixin(@JsonProperty("whiteListMembers") List<LocalMember> whiteListMembers) { } WhiteListReplicableMixin(@JsonProperty("whiteListMembers") List<LocalMember> whiteListMembers) {}
@JsonProperty("whiteListMembers") abstract List<LocalMember> getWhiteListMembers();
@JsonProperty("whiteListMembers")
abstract List<LocalMember> getWhiteListMembers();
} }
abstract class BlackListReplicableMixin { abstract class BlackListReplicableMixin {
@JsonCreator @JsonCreator
BlackListReplicableMixin(@JsonProperty("blackListMembers") List<LocalMember> blackListMembers) { } BlackListReplicableMixin(@JsonProperty("blackListMembers") List<LocalMember> blackListMembers) {}
@JsonProperty("blackListMembers") abstract List<LocalMember> getBlackListMembers();
@JsonProperty("blackListMembers")
abstract List<LocalMember> getBlackListMembers();
} }
abstract class VoteCandidateMixin { abstract class VoteCandidateMixin {
@JsonCreator @JsonCreator
VoteCandidateMixin( VoteCandidateMixin(
@JsonProperty("candidateNodeId") String candidateNodeId, @JsonProperty("candidateNodeId") String candidateNodeId,
@JsonProperty("votingKey") String votingKey, @JsonProperty("votingKey") String votingKey,
@JsonProperty("votes") Map<String, Vote> votes @JsonProperty("votes") Map<String, Vote> votes) {}
) { }
} }
abstract class VoteMixin { abstract class VoteMixin {
@JsonCreator @JsonCreator
VoteMixin( VoteMixin(
@JsonProperty("votingNode") String votingNode, @JsonProperty("votingNode") String votingNode,
@JsonProperty("voteValue") Boolean voteValue, @JsonProperty("voteValue") Boolean voteValue,
@JsonProperty("voteExchange") Boolean voteExchange, @JsonProperty("voteExchange") Boolean voteExchange,
@JsonProperty("liveMembers") List<String> liveMembers, @JsonProperty("liveMembers") List<String> liveMembers,
@JsonProperty("deadMembers") List<String> deadMembers @JsonProperty("deadMembers") List<String> deadMembers) {}
) { }
} }
abstract class MajorityVoteMixin<E>{ abstract class MajorityVoteMixin<E> {
@JsonCreator @JsonCreator
MajorityVoteMixin(@JsonProperty("voteCandidates") Map<String, VoteCandidate> voteCandidateMap){ } MajorityVoteMixin(@JsonProperty("voteCandidates") Map<String, VoteCandidate> voteCandidateMap) {}
} }
//If anyone wants to take a stab at this. please have at it // If anyone wants to take a stab at this. please have at it
//https://github.com/FasterXML/jackson-datatype-guava/blob/master/src/main/java/com/fasterxml/jackson/datatype/guava/ser/MultimapSerializer.java // https://github.com/FasterXML/jackson-datatype-guava/blob/master/src/main/java/com/fasterxml/jackson/datatype/guava/ser/MultimapSerializer.java
public class CrdtModule extends SimpleModule { public class CrdtModule extends SimpleModule {
private static final long serialVersionUID = 6134836523275023418L; private static final long serialVersionUID = 6134836523275023418L;
@ -161,6 +191,4 @@ public class CrdtModule extends SimpleModule {
context.setMixInAnnotations(VoteCandidate.class, VoteCandidateMixin.class); context.setMixInAnnotations(VoteCandidate.class, VoteCandidateMixin.class);
context.setMixInAnnotations(Vote.class, VoteMixin.class); context.setMixInAnnotations(Vote.class, VoteMixin.class);
} }
} }

View File

@ -23,13 +23,13 @@ import java.util.Map;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
public class GrowOnlyCounter implements CrdtCounter<Long, GrowOnlyCounter> { public class GrowOnlyCounter implements CrdtCounter<Long, GrowOnlyCounter> {
private final Map<String, Long> counters = new HashMap<>(); private final Map<String, Long> counters = new HashMap<>();
GrowOnlyCounter(Map<String, Long> counters) { GrowOnlyCounter(Map<String, Long> counters) {
this.counters.putAll(counters); this.counters.putAll(counters);
} }
public GrowOnlyCounter(GrowOnlyCounter growOnlyCounter, Builder builder) { public GrowOnlyCounter(GrowOnlyCounter growOnlyCounter, Builder builder) {
counters.putAll(growOnlyCounter.counters); counters.putAll(growOnlyCounter.counters);
if (counters.containsKey(builder.myId)) { if (counters.containsKey(builder.myId)) {
@ -39,21 +39,21 @@ public class GrowOnlyCounter implements CrdtCounter<Long, GrowOnlyCounter> {
counters.put(builder.myId, builder.counter); counters.put(builder.myId, builder.counter);
} }
} }
public GrowOnlyCounter(Builder builder) { public GrowOnlyCounter(Builder builder) {
counters.put(builder.myId, builder.counter); counters.put(builder.myId, builder.counter);
} }
public GrowOnlyCounter(GossipManager manager) { public GrowOnlyCounter(GossipManager manager) {
counters.put(manager.getMyself().getId(), 0L); counters.put(manager.getMyself().getId(), 0L);
} }
public GrowOnlyCounter(GrowOnlyCounter growOnlyCounter, GrowOnlyCounter other) { public GrowOnlyCounter(GrowOnlyCounter growOnlyCounter, GrowOnlyCounter other) {
counters.putAll(growOnlyCounter.counters); counters.putAll(growOnlyCounter.counters);
for (Map.Entry<String, Long> entry : other.counters.entrySet()) { for (Map.Entry<String, Long> entry : other.counters.entrySet()) {
String otherKey = entry.getKey(); String otherKey = entry.getKey();
Long otherValue = entry.getValue(); Long otherValue = entry.getValue();
if (counters.containsKey(otherKey)) { if (counters.containsKey(otherKey)) {
Long newValue = Math.max(counters.get(otherKey), otherValue); Long newValue = Math.max(counters.get(otherKey), otherValue);
counters.replace(otherKey, newValue); counters.replace(otherKey, newValue);
@ -62,12 +62,12 @@ public class GrowOnlyCounter implements CrdtCounter<Long, GrowOnlyCounter> {
} }
} }
} }
@Override @Override
public GrowOnlyCounter merge(GrowOnlyCounter other) { public GrowOnlyCounter merge(GrowOnlyCounter other) {
return new GrowOnlyCounter(this, other); return new GrowOnlyCounter(this, other);
} }
@Override @Override
public Long value() { public Long value() {
Long globalCount = 0L; Long globalCount = 0L;
@ -76,40 +76,39 @@ public class GrowOnlyCounter implements CrdtCounter<Long, GrowOnlyCounter> {
} }
return globalCount; return globalCount;
} }
@Override @Override
public GrowOnlyCounter optimize() { public GrowOnlyCounter optimize() {
return new GrowOnlyCounter(counters); return new GrowOnlyCounter(counters);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass()) return false;
return false;
GrowOnlyCounter other = (GrowOnlyCounter) obj; GrowOnlyCounter other = (GrowOnlyCounter) obj;
return value().longValue() == other.value().longValue(); return value().longValue() == other.value().longValue();
} }
@Override @Override
public String toString() { public String toString() {
return "GrowOnlyCounter [counters= " + counters + ", Value=" + value() + "]"; return "GrowOnlyCounter [counters= " + counters + ", Value=" + value() + "]";
} }
Map<String, Long> getCounters() { Map<String, Long> getCounters() {
return counters; return counters;
} }
public static class Builder { public static class Builder {
private final String myId; private final String myId;
private Long counter; private Long counter;
public Builder(GossipManager gossipManager) { public Builder(GossipManager gossipManager) {
myId = gossipManager.getMyself().getId(); myId = gossipManager.getMyself().getId();
counter = 0L; counter = 0L;
} }
public GrowOnlyCounter.Builder increment(Long count) { public GrowOnlyCounter.Builder increment(Long count) {
counter += count; counter += count;
return this; return this;

View File

@ -43,57 +43,60 @@ import org.apache.gossip.manager.SystemClock;
DataTest - integration test with 2 nodes, LWWSet was serialized/deserialized, sent between nodes, merged DataTest - integration test with 2 nodes, LWWSet was serialized/deserialized, sent between nodes, merged
*/ */
public class LwwSet<ElementType> implements CrdtAddRemoveSet<ElementType, Set<ElementType>, LwwSet<ElementType>> { public class LwwSet<ElementType>
static private Clock clock = new SystemClock(); implements CrdtAddRemoveSet<ElementType, Set<ElementType>, LwwSet<ElementType>> {
private static Clock clock = new SystemClock();
private final Map<ElementType, Timestamps> struct; private final Map<ElementType, Timestamps> struct;
public LwwSet(){ public LwwSet() {
struct = new HashMap<>(); struct = new HashMap<>();
} }
@SafeVarargs @SafeVarargs
public LwwSet(ElementType... elements){ public LwwSet(ElementType... elements) {
this(new HashSet<>(Arrays.asList(elements))); this(new HashSet<>(Arrays.asList(elements)));
} }
public LwwSet(Set<ElementType> set){ public LwwSet(Set<ElementType> set) {
struct = new HashMap<>(); struct = new HashMap<>();
for (ElementType e : set){ for (ElementType e : set) {
struct.put(e, new Timestamps().updateAdd()); struct.put(e, new Timestamps().updateAdd());
} }
} }
public LwwSet(LwwSet<ElementType> first, LwwSet<ElementType> second){ public LwwSet(LwwSet<ElementType> first, LwwSet<ElementType> second) {
Function<ElementType, Timestamps> timestampsFor = p -> { Function<ElementType, Timestamps> timestampsFor =
Timestamps firstTs = first.struct.get(p); p -> {
Timestamps secondTs = second.struct.get(p); Timestamps firstTs = first.struct.get(p);
if (firstTs == null){ Timestamps secondTs = second.struct.get(p);
return secondTs; if (firstTs == null) {
} return secondTs;
return firstTs.merge(secondTs); }
}; return firstTs.merge(secondTs);
struct = Stream.concat(first.struct.keySet().stream(), second.struct.keySet().stream()) };
.distinct().collect(Collectors.toMap(p -> p, timestampsFor)); struct =
Stream.concat(first.struct.keySet().stream(), second.struct.keySet().stream())
.distinct()
.collect(Collectors.toMap(p -> p, timestampsFor));
} }
// for serialization // for serialization
LwwSet(Map<ElementType, Timestamps> struct){ LwwSet(Map<ElementType, Timestamps> struct) {
this.struct = struct; this.struct = struct;
} }
public LwwSet<ElementType> add(ElementType e){ public LwwSet<ElementType> add(ElementType e) {
return this.merge(new LwwSet<>(e)); return this.merge(new LwwSet<>(e));
} }
Map<ElementType, Timestamps> getStruct(){ Map<ElementType, Timestamps> getStruct() {
return struct; return struct;
} }
public LwwSet<ElementType> remove(ElementType e){ public LwwSet<ElementType> remove(ElementType e) {
Timestamps eTimestamps = struct.get(e); Timestamps eTimestamps = struct.get(e);
if (eTimestamps == null || !eTimestamps.isPresent()){ if (eTimestamps == null || !eTimestamps.isPresent()) {
return this; return this;
} }
Map<ElementType, Timestamps> changeMap = new HashMap<>(); Map<ElementType, Timestamps> changeMap = new HashMap<>();
@ -102,12 +105,12 @@ public class LwwSet<ElementType> implements CrdtAddRemoveSet<ElementType, Set<El
} }
@Override @Override
public LwwSet<ElementType> merge(LwwSet<ElementType> other){ public LwwSet<ElementType> merge(LwwSet<ElementType> other) {
return new LwwSet<>(this, other); return new LwwSet<>(this, other);
} }
@Override @Override
public Set<ElementType> value(){ public Set<ElementType> value() {
return struct.entrySet().stream() return struct.entrySet().stream()
.filter(entry -> entry.getValue().isPresent()) .filter(entry -> entry.getValue().isPresent())
.map(Map.Entry::getKey) .map(Map.Entry::getKey)
@ -115,55 +118,57 @@ public class LwwSet<ElementType> implements CrdtAddRemoveSet<ElementType, Set<El
} }
@Override @Override
public LwwSet<ElementType> optimize(){ public LwwSet<ElementType> optimize() {
return this; return this;
} }
@Override @Override
public boolean equals(Object obj){ public boolean equals(Object obj) {
return this == obj || (obj != null && getClass() == obj.getClass() && value().equals(((LwwSet) obj).value())); return this == obj
|| (obj != null && getClass() == obj.getClass() && value().equals(((LwwSet) obj).value()));
} }
static class Timestamps { static class Timestamps {
private final long latestAdd; private final long latestAdd;
private final long latestRemove; private final long latestRemove;
Timestamps(){ Timestamps() {
latestAdd = 0; latestAdd = 0;
latestRemove = 0; latestRemove = 0;
} }
Timestamps(long add, long remove){ Timestamps(long add, long remove) {
latestAdd = add; latestAdd = add;
latestRemove = remove; latestRemove = remove;
} }
long getLatestAdd(){ long getLatestAdd() {
return latestAdd; return latestAdd;
} }
long getLatestRemove(){ long getLatestRemove() {
return latestRemove; return latestRemove;
} }
// consider element present when addTime >= removeTime, so we prefer add to remove // consider element present when addTime >= removeTime, so we prefer add to remove
boolean isPresent(){ boolean isPresent() {
return latestAdd >= latestRemove; return latestAdd >= latestRemove;
} }
Timestamps updateAdd(){ Timestamps updateAdd() {
return new Timestamps(clock.nanoTime(), latestRemove); return new Timestamps(clock.nanoTime(), latestRemove);
} }
Timestamps updateRemove(){ Timestamps updateRemove() {
return new Timestamps(latestAdd, clock.nanoTime()); return new Timestamps(latestAdd, clock.nanoTime());
} }
Timestamps merge(Timestamps other){ Timestamps merge(Timestamps other) {
if (other == null){ if (other == null) {
return this; return this;
} }
return new Timestamps(Math.max(latestAdd, other.latestAdd), Math.max(latestRemove, other.latestRemove)); return new Timestamps(
Math.max(latestAdd, other.latestAdd), Math.max(latestRemove, other.latestRemove));
} }
} }
} }

View File

@ -23,57 +23,39 @@ import java.util.function.BiConsumer;
import org.apache.gossip.crdt.OrSet.Builder.Operation; import org.apache.gossip.crdt.OrSet.Builder.Operation;
/* /*
* A immutable set * A immutable set
*/ */
public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> { public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
private final Map<E, Set<UUID>> elements = new HashMap<>(); private final Map<E, Set<UUID>> elements = new HashMap<>();
private final Map<E, Set<UUID>> tombstones = new HashMap<>(); private final Map<E, Set<UUID>> tombstones = new HashMap<>();
private final transient Set<E> val; private final transient Set<E> val;
public OrSet(){ public OrSet() {
val = computeValue(); val = computeValue();
} }
OrSet(Map<E, Set<UUID>> elements, Map<E, Set<UUID>> tombstones){ OrSet(Map<E, Set<UUID>> elements, Map<E, Set<UUID>> tombstones) {
this.elements.putAll(elements); this.elements.putAll(elements);
this.tombstones.putAll(tombstones); this.tombstones.putAll(tombstones);
val = computeValue(); val = computeValue();
} }
@SafeVarargs @SafeVarargs
public OrSet(E ... elements){ public OrSet(E... elements) {
this(new HashSet<>(Arrays.asList(elements))); this(new HashSet<>(Arrays.asList(elements)));
} }
public OrSet(Set<E> elements) { public OrSet(Set<E> elements) {
for (E e: elements){ for (E e : elements) {
internalAdd(e); internalAdd(e);
} }
val = computeValue(); val = computeValue();
} }
public OrSet(Builder<E>builder){ public OrSet(Builder<E> builder) {
for (Builder<E>.OrSetElement<E> e: builder.elements){ for (Builder<E>.OrSetElement<E> e : builder.elements) {
if (e.operation == Operation.ADD){ if (e.operation == Operation.ADD) {
internalAdd(e.element);
} else {
internalRemove(e.element);
}
}
val = computeValue();
}
/**
* This constructor is the way to remove elements from an existing set
* @param set
* @param builder
*/
public OrSet(OrSet<E> set, Builder<E> builder){
elements.putAll(set.elements);
tombstones.putAll(set.tombstones);
for (Builder<E>.OrSetElement<E> e: builder.elements){
if (e.operation == Operation.ADD){
internalAdd(e.element); internalAdd(e.element);
} else { } else {
internalRemove(e.element); internalRemove(e.element);
@ -82,12 +64,32 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
val = computeValue(); val = computeValue();
} }
public OrSet(OrSet<E> left, OrSet<E> right){ /**
BiConsumer<Map<E, Set<UUID>>, Map<E, Set<UUID>>> internalMerge = (items, other) -> { * This constructor is the way to remove elements from an existing set
for (Entry<E, Set<UUID>> l : other.entrySet()){ *
internalSetMerge(items, l.getKey(), l.getValue()); * @param set
* @param builder
*/
public OrSet(OrSet<E> set, Builder<E> builder) {
elements.putAll(set.elements);
tombstones.putAll(set.tombstones);
for (Builder<E>.OrSetElement<E> e : builder.elements) {
if (e.operation == Operation.ADD) {
internalAdd(e.element);
} else {
internalRemove(e.element);
} }
}; }
val = computeValue();
}
public OrSet(OrSet<E> left, OrSet<E> right) {
BiConsumer<Map<E, Set<UUID>>, Map<E, Set<UUID>>> internalMerge =
(items, other) -> {
for (Entry<E, Set<UUID>> l : other.entrySet()) {
internalSetMerge(items, l.getKey(), l.getValue());
}
};
internalMerge.accept(elements, left.elements); internalMerge.accept(elements, left.elements);
internalMerge.accept(elements, right.elements); internalMerge.accept(elements, right.elements);
@ -121,31 +123,31 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
return new OrSet<>(this, new Builder<E>().remove(e)); return new OrSet<>(this, new Builder<E>().remove(e));
} }
public OrSet.Builder<E> builder(){ public OrSet.Builder<E> builder() {
return new OrSet.Builder<>(); return new OrSet.Builder<>();
} }
@Override @Override
public OrSet<E> merge(OrSet<E> other) { public OrSet<E> merge(OrSet<E> other) {
return new OrSet<E>(this, other); return new OrSet<E>(this, other);
} }
private void internalAdd(E element) { private void internalAdd(E element) {
Set<UUID> toMerge = new HashSet<>(); Set<UUID> toMerge = new HashSet<>();
toMerge.add(UUID.randomUUID()); toMerge.add(UUID.randomUUID());
internalSetMerge(elements, element, toMerge); internalSetMerge(elements, element, toMerge);
} }
private void internalRemove(E element){ private void internalRemove(E element) {
internalSetMerge(tombstones, element, elements.get(element)); internalSetMerge(tombstones, element, elements.get(element));
} }
/* /*
* Computes the live values by analyzing the elements and tombstones * Computes the live values by analyzing the elements and tombstones
*/ */
private Set<E> computeValue(){ private Set<E> computeValue() {
Set<E> values = new HashSet<>(); Set<E> values = new HashSet<>();
for (Entry<E, Set<UUID>> entry: elements.entrySet()){ for (Entry<E, Set<UUID>> entry : elements.entrySet()) {
Set<UUID> deleteIds = tombstones.get(entry.getKey()); Set<UUID> deleteIds = tombstones.get(entry.getKey());
// if not all tokens for current element are in tombstones // if not all tokens for current element are in tombstones
if (deleteIds == null || !deleteIds.containsAll(entry.getValue())) { if (deleteIds == null || !deleteIds.containsAll(entry.getValue())) {
@ -154,7 +156,7 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
} }
return values; return values;
} }
@Override @Override
public Set<E> value() { public Set<E> value() {
return val; return val;
@ -164,7 +166,7 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
public OrSet<E> optimize() { public OrSet<E> optimize() {
return this; return this;
} }
public int size() { public int size() {
return value().size(); return value().size();
} }
@ -195,7 +197,6 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
public E next() { public E next() {
return managed.next(); return managed.next();
} }
}; };
} }
@ -229,7 +230,7 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
@Override @Override
public String toString() { public String toString() {
return "OrSet [elements=" + elements + ", tombstones=" + tombstones + "]" ; return "OrSet [elements=" + elements + ", tombstones=" + tombstones + "]";
} }
@Override @Override
@ -242,19 +243,14 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) if (this == obj) return true;
return true; if (obj == null) return false;
if (obj == null) if (getClass() != obj.getClass()) return false;
return false;
if (getClass() != obj.getClass())
return false;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
OrSet other = (OrSet) obj; OrSet other = (OrSet) obj;
if (elements == null) { if (elements == null) {
if (other.elements != null) if (other.elements != null) return false;
return false; } else if (!value().equals(other.value())) return false;
} else if (!value().equals(other.value()))
return false;
return true; return true;
} }
@ -267,7 +263,8 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
} }
public static class Builder<E> { public static class Builder<E> {
private List<OrSetElement<E>> elements = new ArrayList<>();; private List<OrSetElement<E>> elements = new ArrayList<>();
;
public Builder<E> add(E element) { public Builder<E> add(E element) {
elements.add(new OrSetElement<E>(element, Operation.ADD)); elements.add(new OrSetElement<E>(element, Operation.ADD));
@ -284,8 +281,9 @@ public class OrSet<E> implements CrdtAddRemoveSet<E, Set<E>, OrSet<E>> {
return this; return this;
} }
public static enum Operation { public static enum Operation {
ADD, REMOVE ADD,
REMOVE
} }
private class OrSetElement<EL> { private class OrSetElement<EL> {
@ -298,5 +296,4 @@ public static enum Operation {
} }
} }
} }
} }

View File

@ -74,8 +74,7 @@ public class PNCounter implements CrdtCounter<Long, PNCounter> {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (getClass() != obj.getClass()) if (getClass() != obj.getClass()) return false;
return false;
PNCounter other = (PNCounter) obj; PNCounter other = (PNCounter) obj;
return value().longValue() == other.value().longValue(); return value().longValue() == other.value().longValue();
} }
@ -118,8 +117,8 @@ public class PNCounter implements CrdtCounter<Long, PNCounter> {
} }
public org.apache.gossip.crdt.GrowOnlyCounter.Builder makeGrowOnlyCounterBuilder(long value) { public org.apache.gossip.crdt.GrowOnlyCounter.Builder makeGrowOnlyCounterBuilder(long value) {
org.apache.gossip.crdt.GrowOnlyCounter.Builder ret = new org.apache.gossip.crdt.GrowOnlyCounter.Builder( org.apache.gossip.crdt.GrowOnlyCounter.Builder ret =
myManager); new org.apache.gossip.crdt.GrowOnlyCounter.Builder(myManager);
ret.increment(value); ret.increment(value);
return ret; return ret;
} }
@ -134,5 +133,4 @@ public class PNCounter implements CrdtCounter<Long, PNCounter> {
return this; return this;
} }
} }
} }

View File

@ -19,7 +19,6 @@ package org.apache.gossip.event.data;
import com.codahale.metrics.Gauge; import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import java.util.List; import java.util.List;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;

View File

@ -46,7 +46,6 @@ import org.apache.gossip.model.SharedDataMessage;
@Slf4j @Slf4j
public class LockManager { public class LockManager {
// For MetricRegistry // For MetricRegistry
public static final String LOCK_KEY_SET_SIZE = "gossip.lock.key_set_size"; public static final String LOCK_KEY_SET_SIZE = "gossip.lock.key_set_size";
public static final String LOCK_TIME = "gossip.lock.time"; public static final String LOCK_TIME = "gossip.lock.time";
@ -57,8 +56,10 @@ public class LockManager {
private final Set<String> lockKeys; private final Set<String> lockKeys;
private final Timer lockTimeMetric; private final Timer lockTimeMetric;
public LockManager(GossipManager gossipManager, final LockManagerSettings lockManagerSettings, public LockManager(
MetricRegistry metrics) { GossipManager gossipManager,
final LockManagerSettings lockManagerSettings,
MetricRegistry metrics) {
this.gossipManager = gossipManager; this.gossipManager = gossipManager;
this.lockSettings = lockManagerSettings; this.lockSettings = lockManagerSettings;
this.numberOfNodes = new AtomicInteger(lockSettings.getNumberOfNodes()); this.numberOfNodes = new AtomicInteger(lockSettings.getNumberOfNodes());
@ -66,14 +67,15 @@ public class LockManager {
metrics.register(LOCK_KEY_SET_SIZE, (Gauge<Integer>) lockKeys::size); metrics.register(LOCK_KEY_SET_SIZE, (Gauge<Integer>) lockKeys::size);
lockTimeMetric = metrics.timer(LOCK_TIME); lockTimeMetric = metrics.timer(LOCK_TIME);
// Register listener for lock keys // Register listener for lock keys
gossipManager.registerSharedDataSubscriber((key, oldValue, newValue) -> { gossipManager.registerSharedDataSubscriber(
if (key.contains("lock/")) { (key, oldValue, newValue) -> {
lockKeys.add(key); if (key.contains("lock/")) {
} lockKeys.add(key);
}); }
});
voteService = Executors.newScheduledThreadPool(2); voteService = Executors.newScheduledThreadPool(2);
voteService.scheduleAtFixedRate(this::updateVotes, 0, lockSettings.getVoteUpdateInterval(), voteService.scheduleAtFixedRate(
TimeUnit.MILLISECONDS); this::updateVotes, 0, lockSettings.getVoteUpdateInterval(), TimeUnit.MILLISECONDS);
} }
public void acquireSharedDataLock(String key) throws VoteFailedException { public void acquireSharedDataLock(String key) throws VoteFailedException {
@ -89,21 +91,30 @@ public class LockManager {
final Map<String, VoteCandidate> voteCandidatesMap = majorityVoteResult.value(); final Map<String, VoteCandidate> voteCandidatesMap = majorityVoteResult.value();
final Map<String, Boolean> voteResultMap = new HashMap<>(); final Map<String, Boolean> voteResultMap = new HashMap<>();
// Store the vote result for each vote candidate nodes // Store the vote result for each vote candidate nodes
voteCandidatesMap.forEach((candidateId, voteCandidate) -> voteResultMap voteCandidatesMap.forEach(
.put(candidateId, isVoteSuccess(voteCandidate))); (candidateId, voteCandidate) ->
voteResultMap.put(candidateId, isVoteSuccess(voteCandidate)));
long passedCandidates = voteResultMap.values().stream().filter(aBoolean -> aBoolean).count(); long passedCandidates = voteResultMap.values().stream().filter(aBoolean -> aBoolean).count();
String myNodeId = gossipManager.getMyself().getId(); String myNodeId = gossipManager.getMyself().getId();
log.debug("NodeId=" + myNodeId + ", VoteMap=" + voteResultMap + ", WinnerCount=" log.debug(
+ passedCandidates); "NodeId="
+ myNodeId
+ ", VoteMap="
+ voteResultMap
+ ", WinnerCount="
+ passedCandidates);
// Check for possible dead lock when no candidates were won // Check for possible dead lock when no candidates were won
if (passedCandidates == 0) { if (passedCandidates == 0) {
if (isDeadLock(voteCandidatesMap)) { if (isDeadLock(voteCandidatesMap)) {
deadlockDetectCount++; deadlockDetectCount++;
// Testing for deadlock is not always correct, therefore test for continues deadlocks // Testing for deadlock is not always correct, therefore test for continues deadlocks
if (deadlockDetectCount >= lockSettings.getDeadlockDetectionThreshold()) { if (deadlockDetectCount >= lockSettings.getDeadlockDetectionThreshold()) {
log.debug("Deadlock detected from node " + myNodeId + ". VoteCandidatesMap=" log.debug(
+ voteCandidatesMap); "Deadlock detected from node "
+ myNodeId
+ ". VoteCandidatesMap="
+ voteCandidatesMap);
preventDeadLock(voteCandidatesMap); preventDeadLock(voteCandidatesMap);
} }
} else { } else {
@ -133,12 +144,17 @@ public class LockManager {
// Generate Crdt lock message for voting // Generate Crdt lock message for voting
private SharedDataMessage generateLockMessage(String key) { private SharedDataMessage generateLockMessage(String key) {
VoteCandidate voteCandidate = new VoteCandidate(gossipManager.getMyself().getId(), key, VoteCandidate voteCandidate =
new ConcurrentHashMap<>()); new VoteCandidate(gossipManager.getMyself().getId(), key, new ConcurrentHashMap<>());
voteCandidate.addVote(new Vote(gossipManager.getMyself().getId(), true, false, voteCandidate.addVote(
new Vote(
gossipManager.getMyself().getId(),
true,
false,
gossipManager.getLiveMembers().stream().map(Member::getId).collect(Collectors.toList()), gossipManager.getLiveMembers().stream().map(Member::getId).collect(Collectors.toList()),
gossipManager.getDeadMembers().stream().map(Member::getId) gossipManager.getDeadMembers().stream()
.collect(Collectors.toList()))); .map(Member::getId)
.collect(Collectors.toList())));
Map<String, VoteCandidate> voteCandidateMap = new ConcurrentHashMap<>(); Map<String, VoteCandidate> voteCandidateMap = new ConcurrentHashMap<>();
voteCandidateMap.put(voteCandidate.getCandidateNodeId(), voteCandidate); voteCandidateMap.put(voteCandidate.getCandidateNodeId(), voteCandidate);
MajorityVote majorityVote = new MajorityVote(voteCandidateMap); MajorityVote majorityVote = new MajorityVote(voteCandidateMap);
@ -167,7 +183,8 @@ public class LockManager {
String myVoteCandidate = getVotedCandidateNodeId(myNodeId, voteCandidateMap); String myVoteCandidate = getVotedCandidateNodeId(myNodeId, voteCandidateMap);
if (myVoteCandidate == null) { if (myVoteCandidate == null) {
myVoteCandidate = lockSettings.getVoteSelector().getVoteCandidateId(voteCandidateMap.keySet()); myVoteCandidate =
lockSettings.getVoteSelector().getVoteCandidateId(voteCandidateMap.keySet());
} }
for (VoteCandidate voteCandidate : voteCandidateMap.values()) { for (VoteCandidate voteCandidate : voteCandidateMap.values()) {
if (voteCandidate.getCandidateNodeId().equals(myNodeId)) { if (voteCandidate.getCandidateNodeId().equals(myNodeId)) {
@ -175,11 +192,17 @@ public class LockManager {
} }
// Vote for selected candidate // Vote for selected candidate
boolean voteResult = voteCandidate.getCandidateNodeId().equals(myVoteCandidate); boolean voteResult = voteCandidate.getCandidateNodeId().equals(myVoteCandidate);
voteCandidate.addVote(new Vote(gossipManager.getMyself().getId(), voteResult, false, voteCandidate.addVote(
gossipManager.getLiveMembers().stream().map(Member::getId) new Vote(
.collect(Collectors.toList()), gossipManager.getMyself().getId(),
gossipManager.getDeadMembers().stream().map(Member::getId) voteResult,
.collect(Collectors.toList()))); false,
gossipManager.getLiveMembers().stream()
.map(Member::getId)
.collect(Collectors.toList()),
gossipManager.getDeadMembers().stream()
.map(Member::getId)
.collect(Collectors.toList())));
} }
} }
} }
@ -203,9 +226,13 @@ public class LockManager {
numberOfLiveNodes = numberOfNodes.get(); numberOfLiveNodes = numberOfNodes.get();
} else { } else {
// numberOfNodes is not set by the user, therefore calculate it. // numberOfNodes is not set by the user, therefore calculate it.
Set<String> liveNodes = voteCandidates.values().stream() Set<String> liveNodes =
.map(voteCandidate -> voteCandidate.getVotes().values()).flatMap(Collection::stream) voteCandidates.values().stream()
.map(Vote::getLiveMembers).flatMap(List::stream).collect(Collectors.toSet()); .map(voteCandidate -> voteCandidate.getVotes().values())
.flatMap(Collection::stream)
.map(Vote::getLiveMembers)
.flatMap(List::stream)
.collect(Collectors.toSet());
numberOfLiveNodes = liveNodes.size(); numberOfLiveNodes = liveNodes.size();
} }
for (VoteCandidate voteCandidate : voteCandidates.values()) { for (VoteCandidate voteCandidate : voteCandidates.values()) {
@ -222,15 +249,17 @@ public class LockManager {
return; return;
} }
// Set of nodes that is going to receive this nodes votes // Set of nodes that is going to receive this nodes votes
List<String> donateCandidateIds = voteCandidates.keySet().stream() List<String> donateCandidateIds =
.filter(s -> s.compareTo(myNodeId) < 0).collect(Collectors.toList()); voteCandidates.keySet().stream()
.filter(s -> s.compareTo(myNodeId) < 0)
.collect(Collectors.toList());
if (donateCandidateIds.size() == 0) { if (donateCandidateIds.size() == 0) {
return; return;
} }
// Select a random node to donate // Select a random node to donate
Random randomizer = new Random(); Random randomizer = new Random();
String selectedCandidateId = donateCandidateIds String selectedCandidateId =
.get(randomizer.nextInt(donateCandidateIds.size())); donateCandidateIds.get(randomizer.nextInt(donateCandidateIds.size()));
VoteCandidate selectedCandidate = voteCandidates.get(selectedCandidateId); VoteCandidate selectedCandidate = voteCandidates.get(selectedCandidateId);
Set<Vote> myVotes = new HashSet<>(myResults.getVotes().values()); Set<Vote> myVotes = new HashSet<>(myResults.getVotes().values());
@ -246,11 +275,11 @@ public class LockManager {
} }
} }
} }
log.debug("Node " + myNodeId + " give up votes to node " + selectedCandidateId); log.debug("Node " + myNodeId + " give up votes to node " + selectedCandidateId);
} }
private String getVotedCandidateNodeId(String nodeId, private String getVotedCandidateNodeId(
final Map<String, VoteCandidate> voteCandidates) { String nodeId, final Map<String, VoteCandidate> voteCandidates) {
for (VoteCandidate voteCandidate : voteCandidates.values()) { for (VoteCandidate voteCandidate : voteCandidates.values()) {
Vote vote = voteCandidate.getVotes().get(nodeId); Vote vote = voteCandidate.getVotes().get(nodeId);
if (vote != null && vote.getVoteValue()) { if (vote != null && vote.getVoteValue()) {
@ -279,15 +308,17 @@ public class LockManager {
return numberOfLiveNodes > 0 && voteCount >= (numberOfLiveNodes / 2 + 1); return numberOfLiveNodes > 0 && voteCount >= (numberOfLiveNodes / 2 + 1);
} }
private String generateLockKey(String key){ private String generateLockKey(String key) {
return "lock/" + key; return "lock/" + key;
} }
public void shutdown(){ public void shutdown() {
voteService.shutdown(); voteService.shutdown();
} }
/** /**
* Get the voted node id from this node for a given key * Get the voted node id from this node for a given key
*
* @param key key of the data object * @param key key of the data object
* @return Voted node id * @return Voted node id
*/ */
@ -302,10 +333,10 @@ public class LockManager {
/** /**
* Set the number of live nodes. If this value is negative, live nodes will be calculated * Set the number of live nodes. If this value is negative, live nodes will be calculated
*
* @param numberOfNodes live node count or negative to calculate. * @param numberOfNodes live node count or negative to calculate.
*/ */
public void setNumberOfNodes(int numberOfNodes) { public void setNumberOfNodes(int numberOfNodes) {
this.numberOfNodes.set(numberOfNodes); this.numberOfNodes.set(numberOfNodes);
} }
} }

View File

@ -25,9 +25,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.gossip.crdt.Crdt; import org.apache.gossip.crdt.Crdt;
/** /** CRDT which used for distribute a votes for a given key. */
* CRDT which used for distribute a votes for a given key.
*/
public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVote> { public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVote> {
private final Map<String, VoteCandidate> voteCandidates = new ConcurrentHashMap<>(); private final Map<String, VoteCandidate> voteCandidates = new ConcurrentHashMap<>();
@ -53,11 +51,13 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
} }
// Merge votes for the same candidate // Merge votes for the same candidate
for (String sameCandidateId : sameCandidatesSet) { for (String sameCandidateId : sameCandidatesSet) {
if (this.voteCandidates.containsKey(sameCandidateId) && other.voteCandidates if (this.voteCandidates.containsKey(sameCandidateId)
.containsKey(sameCandidateId)) { && other.voteCandidates.containsKey(sameCandidateId)) {
mergedCandidates.put(sameCandidateId, mergedCandidates.put(
mergeCandidate(this.voteCandidates.get(sameCandidateId), sameCandidateId,
other.voteCandidates.get(sameCandidateId))); mergeCandidate(
this.voteCandidates.get(sameCandidateId),
other.voteCandidates.get(sameCandidateId)));
} }
} }
@ -65,10 +65,13 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
} }
// Merge different votes for same candidate // Merge different votes for same candidate
private VoteCandidate mergeCandidate(VoteCandidate firstCandidate, private VoteCandidate mergeCandidate(
VoteCandidate secondCandidate) { VoteCandidate firstCandidate, VoteCandidate secondCandidate) {
VoteCandidate mergeResult = new VoteCandidate(firstCandidate.getCandidateNodeId(), VoteCandidate mergeResult =
firstCandidate.getVotingKey(), new ConcurrentHashMap<>()); new VoteCandidate(
firstCandidate.getCandidateNodeId(),
firstCandidate.getVotingKey(),
new ConcurrentHashMap<>());
Set<String> firstKeySet = firstCandidate.getVotes().keySet(); Set<String> firstKeySet = firstCandidate.getVotes().keySet();
Set<String> secondKeySet = secondCandidate.getVotes().keySet(); Set<String> secondKeySet = secondCandidate.getVotes().keySet();
Set<String> sameVoteNodeSet = getIntersection(firstKeySet, secondKeySet); Set<String> sameVoteNodeSet = getIntersection(firstKeySet, secondKeySet);
@ -76,20 +79,26 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
// Merge different voters by combining their votes // Merge different voters by combining their votes
for (String differentCandidateId : differentVoteNodeSet) { for (String differentCandidateId : differentVoteNodeSet) {
if (firstCandidate.getVotes().containsKey(differentCandidateId)) { if (firstCandidate.getVotes().containsKey(differentCandidateId)) {
mergeResult.getVotes() mergeResult
.put(differentCandidateId, firstCandidate.getVotes().get(differentCandidateId)); .getVotes()
.put(differentCandidateId, firstCandidate.getVotes().get(differentCandidateId));
} else if (secondCandidate.getVotes().containsKey(differentCandidateId)) { } else if (secondCandidate.getVotes().containsKey(differentCandidateId)) {
mergeResult.getVotes() mergeResult
.put(differentCandidateId, secondCandidate.getVotes().get(differentCandidateId)); .getVotes()
.put(differentCandidateId, secondCandidate.getVotes().get(differentCandidateId));
} }
} }
// Merge vote for same voter // Merge vote for same voter
for (String sameVoteNodeId : sameVoteNodeSet) { for (String sameVoteNodeId : sameVoteNodeSet) {
if (firstCandidate.getVotes().containsKey(sameVoteNodeId) && secondCandidate.getVotes() if (firstCandidate.getVotes().containsKey(sameVoteNodeId)
.containsKey(sameVoteNodeId)) { && secondCandidate.getVotes().containsKey(sameVoteNodeId)) {
mergeResult.getVotes().put(sameVoteNodeId, mergeResult
mergeVote(firstCandidate.getVotes().get(sameVoteNodeId), .getVotes()
secondCandidate.getVotes().get(sameVoteNodeId))); .put(
sameVoteNodeId,
mergeVote(
firstCandidate.getVotes().get(sameVoteNodeId),
secondCandidate.getVotes().get(sameVoteNodeId)));
} }
} }
@ -131,7 +140,6 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
Map<String, VoteCandidate> copy = new ConcurrentHashMap<>(); Map<String, VoteCandidate> copy = new ConcurrentHashMap<>();
copy.putAll(voteCandidates); copy.putAll(voteCandidates);
return Collections.unmodifiableMap(copy); return Collections.unmodifiableMap(copy);
} }
@Override @Override
@ -141,12 +149,9 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj == null) if (obj == null) return false;
return false; if (obj == this) return true;
if (obj == this) if (!(obj instanceof MajorityVote)) return false;
return true;
if (!(obj instanceof MajorityVote))
return false;
MajorityVote other = (MajorityVote) obj; MajorityVote other = (MajorityVote) obj;
return Objects.equals(voteCandidates, other.voteCandidates); return Objects.equals(voteCandidates, other.voteCandidates);
} }
@ -164,5 +169,4 @@ public class MajorityVote implements Crdt<Map<String, VoteCandidate>, MajorityVo
public Map<String, VoteCandidate> getVoteCandidates() { public Map<String, VoteCandidate> getVoteCandidates() {
return new ConcurrentHashMap<>(voteCandidates); return new ConcurrentHashMap<>(voteCandidates);
} }
} }

View File

@ -19,9 +19,7 @@ package org.apache.gossip.lock.vote;
import java.util.List; import java.util.List;
/** /** Store a voter details. */
* Store a voter details.
*/
public class Vote { public class Vote {
private final String votingNode; private final String votingNode;
private final Boolean voteValue; // TODO: 7/16/17 weight? private final Boolean voteValue; // TODO: 7/16/17 weight?
@ -29,8 +27,12 @@ public class Vote {
private final List<String> deadMembers; private final List<String> deadMembers;
private Boolean voteExchange; private Boolean voteExchange;
public Vote(String votingNode, Boolean voteValue, Boolean voteExchange, List<String> liveMembers, public Vote(
List<String> deadMembers) { String votingNode,
Boolean voteValue,
Boolean voteExchange,
List<String> liveMembers,
List<String> deadMembers) {
this.votingNode = votingNode; this.votingNode = votingNode;
this.voteValue = voteValue; this.voteValue = voteValue;
this.voteExchange = voteExchange; this.voteExchange = voteExchange;
@ -64,7 +66,13 @@ public class Vote {
@Override @Override
public String toString() { public String toString() {
return "votingNode=" + votingNode + ", voteValue=" + voteValue + ", liveMembers=" + liveMembers return "votingNode="
+ ", deadMembers= " + deadMembers; + votingNode
+ ", voteValue="
+ voteValue
+ ", liveMembers="
+ liveMembers
+ ", deadMembers= "
+ deadMembers;
} }
} }

View File

@ -38,7 +38,8 @@ import org.apache.gossip.model.ShutdownMessage;
import org.apache.gossip.udp.*; import org.apache.gossip.udp.*;
/** /**
* The ActiveGossipThread sends information. Pick a random partner and send the membership list to that partner * The ActiveGossipThread sends information. Pick a random partner and send the membership list to
* that partner
*/ */
@Slf4j @Slf4j
public abstract class AbstractActiveGossiper { public abstract class AbstractActiveGossiper {
@ -51,26 +52,26 @@ public abstract class AbstractActiveGossiper {
private final Random random; private final Random random;
private final GossipSettings gossipSettings; private final GossipSettings gossipSettings;
public AbstractActiveGossiper(GossipManager gossipManager, GossipCore gossipCore, MetricRegistry registry) { public AbstractActiveGossiper(
GossipManager gossipManager, GossipCore gossipCore, MetricRegistry registry) {
this.gossipManager = gossipManager; this.gossipManager = gossipManager;
this.gossipCore = gossipCore; this.gossipCore = gossipCore;
sharedDataHistogram = registry.histogram(name(AbstractActiveGossiper.class, "sharedDataHistogram-time")); sharedDataHistogram =
sendPerNodeDataHistogram = registry.histogram(name(AbstractActiveGossiper.class, "sendPerNodeDataHistogram-time")); registry.histogram(name(AbstractActiveGossiper.class, "sharedDataHistogram-time"));
sendMembershipHistogram = registry.histogram(name(AbstractActiveGossiper.class, "sendMembershipHistogram-time")); sendPerNodeDataHistogram =
registry.histogram(name(AbstractActiveGossiper.class, "sendPerNodeDataHistogram-time"));
sendMembershipHistogram =
registry.histogram(name(AbstractActiveGossiper.class, "sendMembershipHistogram-time"));
random = new Random(); random = new Random();
gossipSettings = gossipManager.getSettings(); gossipSettings = gossipManager.getSettings();
} }
public void init() { public void init() {}
} public void shutdown() {}
public void shutdown() { public final void sendShutdownMessage(LocalMember me, LocalMember target) {
if (target == null) {
}
public final void sendShutdownMessage(LocalMember me, LocalMember target){
if (target == null){
return; return;
} }
ShutdownMessage m = new ShutdownMessage(); ShutdownMessage m = new ShutdownMessage();
@ -94,8 +95,11 @@ public abstract class AbstractActiveGossiper {
/** Send shared data one entry at a time. */ /** Send shared data one entry at a time. */
private void sendSharedDataInternal(LocalMember me, LocalMember member) { private void sendSharedDataInternal(LocalMember me, LocalMember member) {
for (Entry<String, SharedDataMessage> innerEntry : gossipCore.getSharedData().entrySet()){ for (Entry<String, SharedDataMessage> innerEntry : gossipCore.getSharedData().entrySet()) {
if (innerEntry.getValue().getReplicable() != null && !innerEntry.getValue().getReplicable() if (innerEntry.getValue().getReplicable() != null
&& !innerEntry
.getValue()
.getReplicable()
.shouldReplicate(me, member, innerEntry.getValue())) { .shouldReplicate(me, member, innerEntry.getValue())) {
continue; continue;
} }
@ -113,7 +117,10 @@ public abstract class AbstractActiveGossiper {
udpMessage.setUuid(UUID.randomUUID().toString()); udpMessage.setUuid(UUID.randomUUID().toString());
udpMessage.setUriFrom(me.getId()); udpMessage.setUriFrom(me.getId());
for (Entry<String, SharedDataMessage> innerEntry : gossipCore.getSharedData().entrySet()) { for (Entry<String, SharedDataMessage> innerEntry : gossipCore.getSharedData().entrySet()) {
if (innerEntry.getValue().getReplicable() != null && !innerEntry.getValue().getReplicable() if (innerEntry.getValue().getReplicable() != null
&& !innerEntry
.getValue()
.getReplicable()
.shouldReplicate(me, member, innerEntry.getValue())) { .shouldReplicate(me, member, innerEntry.getValue())) {
continue; continue;
} }
@ -141,8 +148,8 @@ public abstract class AbstractActiveGossiper {
copy.setReplicable(original.getReplicable()); copy.setReplicable(original.getReplicable());
} }
public final void sendPerNodeData(LocalMember me, LocalMember member){ public final void sendPerNodeData(LocalMember me, LocalMember member) {
if (member == null){ if (member == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
@ -156,9 +163,13 @@ public abstract class AbstractActiveGossiper {
/** Send per node data one entry at a time. */ /** Send per node data one entry at a time. */
private void sendPerNodeDataInternal(LocalMember me, LocalMember member) { private void sendPerNodeDataInternal(LocalMember me, LocalMember member) {
for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> entry : gossipCore.getPerNodeData().entrySet()){ for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> entry :
for (Entry<String, PerNodeDataMessage> innerEntry : entry.getValue().entrySet()){ gossipCore.getPerNodeData().entrySet()) {
if (innerEntry.getValue().getReplicable() != null && !innerEntry.getValue().getReplicable() for (Entry<String, PerNodeDataMessage> innerEntry : entry.getValue().entrySet()) {
if (innerEntry.getValue().getReplicable() != null
&& !innerEntry
.getValue()
.getReplicable()
.shouldReplicate(me, member, innerEntry.getValue())) { .shouldReplicate(me, member, innerEntry.getValue())) {
continue; continue;
} }
@ -169,17 +180,20 @@ public abstract class AbstractActiveGossiper {
gossipCore.sendOneWay(message, member.getUri()); gossipCore.sendOneWay(message, member.getUri());
} }
} }
} }
/** Send per node data by batching together several entries. */ /** Send per node data by batching together several entries. */
private void sendPerNodeDataInBulkInternal(LocalMember me, LocalMember member) { private void sendPerNodeDataInBulkInternal(LocalMember me, LocalMember member) {
for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> entry : gossipCore.getPerNodeData().entrySet()){ for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> entry :
gossipCore.getPerNodeData().entrySet()) {
UdpPerNodeDataBulkMessage udpMessage = new UdpPerNodeDataBulkMessage(); UdpPerNodeDataBulkMessage udpMessage = new UdpPerNodeDataBulkMessage();
udpMessage.setUuid(UUID.randomUUID().toString()); udpMessage.setUuid(UUID.randomUUID().toString());
udpMessage.setUriFrom(me.getId()); udpMessage.setUriFrom(me.getId());
for (Entry<String, PerNodeDataMessage> innerEntry : entry.getValue().entrySet()){ for (Entry<String, PerNodeDataMessage> innerEntry : entry.getValue().entrySet()) {
if (innerEntry.getValue().getReplicable() != null && !innerEntry.getValue().getReplicable() if (innerEntry.getValue().getReplicable() != null
&& !innerEntry
.getValue()
.getReplicable()
.shouldReplicate(me, member, innerEntry.getValue())) { .shouldReplicate(me, member, innerEntry.getValue())) {
continue; continue;
} }
@ -208,11 +222,9 @@ public abstract class AbstractActiveGossiper {
copy.setReplicable(original.getReplicable()); copy.setReplicable(original.getReplicable());
} }
/** /** Performs the sending of the membership list, after we have incremented our own heartbeat. */
* Performs the sending of the membership list, after we have incremented our own heartbeat.
*/
protected void sendMembershipList(LocalMember me, LocalMember member) { protected void sendMembershipList(LocalMember me, LocalMember member) {
if (member == null){ if (member == null) {
return; return;
} }
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
@ -225,15 +237,15 @@ public abstract class AbstractActiveGossiper {
message.getMembers().add(convert(other)); message.getMembers().add(convert(other));
} }
Response r = gossipCore.send(message, member.getUri()); Response r = gossipCore.send(message, member.getUri());
if (r instanceof ActiveGossipOk){ if (r instanceof ActiveGossipOk) {
//maybe count metrics here // maybe count metrics here
} else { } else {
log.debug("Message " + message + " generated response " + r); log.debug("Message " + message + " generated response " + r);
} }
sendMembershipHistogram.update(System.currentTimeMillis() - startTime); sendMembershipHistogram.update(System.currentTimeMillis() - startTime);
} }
protected final Member convert(LocalMember member){ protected final Member convert(LocalMember member) {
Member gm = new Member(); Member gm = new Member();
gm.setCluster(member.getClusterName()); gm.setCluster(member.getClusterName());
gm.setHeartbeat(member.getHeartbeat()); gm.setHeartbeat(member.getHeartbeat());
@ -244,9 +256,7 @@ public abstract class AbstractActiveGossiper {
} }
/** /**
* * @param memberList An immutable list
* @param memberList
* An immutable list
* @return The chosen LocalGossipMember to gossip with. * @return The chosen LocalGossipMember to gossip with.
*/ */
protected LocalMember selectPartner(List<LocalMember> memberList) { protected LocalMember selectPartner(List<LocalMember> memberList) {

View File

@ -37,48 +37,50 @@ public class DataReaper {
private final GossipCore gossipCore; private final GossipCore gossipCore;
private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1); private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(1);
private final Clock clock; private final Clock clock;
public DataReaper(GossipCore gossipCore, Clock clock){ public DataReaper(GossipCore gossipCore, Clock clock) {
this.gossipCore = gossipCore; this.gossipCore = gossipCore;
this.clock = clock; this.clock = clock;
} }
public void init(){ public void init() {
Runnable reapPerNodeData = () -> { Runnable reapPerNodeData =
runPerNodeOnce(); () -> {
runSharedOnce(); runPerNodeOnce();
}; runSharedOnce();
};
scheduledExecutor.scheduleAtFixedRate(reapPerNodeData, 0, 5, TimeUnit.SECONDS); scheduledExecutor.scheduleAtFixedRate(reapPerNodeData, 0, 5, TimeUnit.SECONDS);
} }
void runSharedOnce(){ void runSharedOnce() {
for (Entry<String, SharedDataMessage> entry : gossipCore.getSharedData().entrySet()){ for (Entry<String, SharedDataMessage> entry : gossipCore.getSharedData().entrySet()) {
if (entry.getValue().getExpireAt() < clock.currentTimeMillis()){ if (entry.getValue().getExpireAt() < clock.currentTimeMillis()) {
gossipCore.getSharedData().remove(entry.getKey(), entry.getValue()); gossipCore.getSharedData().remove(entry.getKey(), entry.getValue());
} }
} }
} }
void runPerNodeOnce(){ void runPerNodeOnce() {
for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> node : gossipCore.getPerNodeData().entrySet()){ for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> node :
gossipCore.getPerNodeData().entrySet()) {
reapData(node.getValue()); reapData(node.getValue());
} }
} }
void reapData(ConcurrentHashMap<String, PerNodeDataMessage> concurrentHashMap){ void reapData(ConcurrentHashMap<String, PerNodeDataMessage> concurrentHashMap) {
for (Entry<String, PerNodeDataMessage> entry : concurrentHashMap.entrySet()){ for (Entry<String, PerNodeDataMessage> entry : concurrentHashMap.entrySet()) {
if (entry.getValue().getExpireAt() < clock.currentTimeMillis()){ if (entry.getValue().getExpireAt() < clock.currentTimeMillis()) {
concurrentHashMap.remove(entry.getKey(), entry.getValue()); concurrentHashMap.remove(entry.getKey(), entry.getValue());
} }
} }
} }
public void close(){ public void close() {
scheduledExecutor.shutdown(); scheduledExecutor.shutdown();
try { try {
scheduledExecutor.awaitTermination(1, TimeUnit.SECONDS); scheduledExecutor.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) { } catch (InterruptedException e) {
} }
} }
} }

View File

@ -31,11 +31,10 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.LocalMember; import org.apache.gossip.LocalMember;
/** /**
* Sends gossip traffic at different rates to other racks and data-centers. * Sends gossip traffic at different rates to other racks and data-centers. This implementation
* This implementation controls the rate at which gossip traffic is shared. * controls the rate at which gossip traffic is shared. There are two constructs Datacenter and
* There are two constructs Datacenter and Rack. It is assumed that bandwidth and latency is higher * Rack. It is assumed that bandwidth and latency is higher in the rack than in the the datacenter.
* in the rack than in the the datacenter. We can adjust the rate at which we send messages to each group. * We can adjust the rate at which we send messages to each group.
*
*/ */
@Slf4j @Slf4j
public class DatacenterRackAwareActiveGossiper extends AbstractActiveGossiper { public class DatacenterRackAwareActiveGossiper extends AbstractActiveGossiper {
@ -49,125 +48,166 @@ public class DatacenterRackAwareActiveGossiper extends AbstractActiveGossiper {
private int randomDeadMemberSendIntervalMs = 250; private int randomDeadMemberSendIntervalMs = 250;
private ScheduledExecutorService scheduledExecutorService; private ScheduledExecutorService scheduledExecutorService;
private ThreadPoolExecutor threadService; private ThreadPoolExecutor threadService;
public DatacenterRackAwareActiveGossiper(GossipManager gossipManager, GossipCore gossipCore, public DatacenterRackAwareActiveGossiper(
MetricRegistry registry) { GossipManager gossipManager, GossipCore gossipCore, MetricRegistry registry) {
super(gossipManager, gossipCore, registry); super(gossipManager, gossipCore, registry);
scheduledExecutorService = Executors.newScheduledThreadPool(2); scheduledExecutorService = Executors.newScheduledThreadPool(2);
workQueue = new ArrayBlockingQueue<Runnable>(1024); workQueue = new ArrayBlockingQueue<Runnable>(1024);
threadService = new ThreadPoolExecutor(1, 30, 1, TimeUnit.SECONDS, workQueue, threadService =
new ThreadPoolExecutor.DiscardOldestPolicy()); new ThreadPoolExecutor(
1, 30, 1, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
try { try {
sameRackGossipIntervalMs = Integer.parseInt(gossipManager.getSettings() sameRackGossipIntervalMs =
.getActiveGossipProperties().get("sameRackGossipIntervalMs")); Integer.parseInt(
} catch (RuntimeException ex) { } gossipManager
.getSettings()
.getActiveGossipProperties()
.get("sameRackGossipIntervalMs"));
} catch (RuntimeException ex) {
}
try { try {
sameDcGossipIntervalMs = Integer.parseInt(gossipManager.getSettings() sameDcGossipIntervalMs =
.getActiveGossipProperties().get("sameDcGossipIntervalMs")); Integer.parseInt(
} catch (RuntimeException ex) { } gossipManager
.getSettings()
.getActiveGossipProperties()
.get("sameDcGossipIntervalMs"));
} catch (RuntimeException ex) {
}
try { try {
differentDatacenterGossipIntervalMs = Integer.parseInt(gossipManager.getSettings() differentDatacenterGossipIntervalMs =
.getActiveGossipProperties().get("differentDatacenterGossipIntervalMs")); Integer.parseInt(
} catch (RuntimeException ex) { } gossipManager
.getSettings()
.getActiveGossipProperties()
.get("differentDatacenterGossipIntervalMs"));
} catch (RuntimeException ex) {
}
try { try {
randomDeadMemberSendIntervalMs = Integer.parseInt(gossipManager.getSettings() randomDeadMemberSendIntervalMs =
.getActiveGossipProperties().get("randomDeadMemberSendIntervalMs")); Integer.parseInt(
} catch (RuntimeException ex) { } gossipManager
.getSettings()
.getActiveGossipProperties()
.get("randomDeadMemberSendIntervalMs"));
} catch (RuntimeException ex) {
}
} }
@Override @Override
public void init() { public void init() {
super.init(); super.init();
//same rack // same rack
scheduledExecutorService.scheduleAtFixedRate(() -> scheduledExecutorService.scheduleAtFixedRate(
threadService.execute(() -> sendToSameRackMember()), () -> threadService.execute(() -> sendToSameRackMember()),
0, sameRackGossipIntervalMs, TimeUnit.MILLISECONDS); 0,
sameRackGossipIntervalMs,
scheduledExecutorService.scheduleAtFixedRate(() -> TimeUnit.MILLISECONDS);
threadService.execute(() -> sendToSameRackMemberPerNode()),
0, sameRackGossipIntervalMs, TimeUnit.MILLISECONDS); scheduledExecutorService.scheduleAtFixedRate(
() -> threadService.execute(() -> sendToSameRackMemberPerNode()),
scheduledExecutorService.scheduleAtFixedRate(() -> 0,
threadService.execute(() -> sendToSameRackShared()), sameRackGossipIntervalMs,
0, sameRackGossipIntervalMs, TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
//same dc different rack scheduledExecutorService.scheduleAtFixedRate(
scheduledExecutorService.scheduleAtFixedRate(() -> () -> threadService.execute(() -> sendToSameRackShared()),
threadService.execute(() -> sameDcDiffernetRackMember()), 0,
0, sameDcGossipIntervalMs, TimeUnit.MILLISECONDS); sameRackGossipIntervalMs,
TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(() ->
threadService.execute(() -> sameDcDiffernetRackPerNode()), // same dc different rack
0, sameDcGossipIntervalMs, TimeUnit.MILLISECONDS); scheduledExecutorService.scheduleAtFixedRate(
() -> threadService.execute(() -> sameDcDiffernetRackMember()),
scheduledExecutorService.scheduleAtFixedRate(() -> 0,
threadService.execute(() -> sameDcDiffernetRackShared()), sameDcGossipIntervalMs,
0, sameDcGossipIntervalMs, TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
//different dc scheduledExecutorService.scheduleAtFixedRate(
scheduledExecutorService.scheduleAtFixedRate(() -> () -> threadService.execute(() -> sameDcDiffernetRackPerNode()),
threadService.execute(() -> differentDcMember()), 0,
0, differentDatacenterGossipIntervalMs, TimeUnit.MILLISECONDS); sameDcGossipIntervalMs,
TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(() ->
threadService.execute(() -> differentDcPerNode()), scheduledExecutorService.scheduleAtFixedRate(
0, differentDatacenterGossipIntervalMs, TimeUnit.MILLISECONDS); () -> threadService.execute(() -> sameDcDiffernetRackShared()),
0,
scheduledExecutorService.scheduleAtFixedRate(() -> sameDcGossipIntervalMs,
threadService.execute(() -> differentDcShared()), TimeUnit.MILLISECONDS);
0, differentDatacenterGossipIntervalMs, TimeUnit.MILLISECONDS);
// different dc
//the dead scheduledExecutorService.scheduleAtFixedRate(
scheduledExecutorService.scheduleAtFixedRate(() -> () -> threadService.execute(() -> differentDcMember()),
threadService.execute(() -> sendToDeadMember()), 0,
0, randomDeadMemberSendIntervalMs, TimeUnit.MILLISECONDS); differentDatacenterGossipIntervalMs,
TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(
() -> threadService.execute(() -> differentDcPerNode()),
0,
differentDatacenterGossipIntervalMs,
TimeUnit.MILLISECONDS);
scheduledExecutorService.scheduleAtFixedRate(
() -> threadService.execute(() -> differentDcShared()),
0,
differentDatacenterGossipIntervalMs,
TimeUnit.MILLISECONDS);
// the dead
scheduledExecutorService.scheduleAtFixedRate(
() -> threadService.execute(() -> sendToDeadMember()),
0,
randomDeadMemberSendIntervalMs,
TimeUnit.MILLISECONDS);
} }
private void sendToDeadMember() { private void sendToDeadMember() {
sendMembershipList(gossipManager.getMyself(), selectPartner(gossipManager.getDeadMembers())); sendMembershipList(gossipManager.getMyself(), selectPartner(gossipManager.getDeadMembers()));
} }
private List<LocalMember> differentDataCenter(){ private List<LocalMember> differentDataCenter() {
String myDc = gossipManager.getMyself().getProperties().get(DATACENTER); String myDc = gossipManager.getMyself().getProperties().get(DATACENTER);
String rack = gossipManager.getMyself().getProperties().get(RACK); String rack = gossipManager.getMyself().getProperties().get(RACK);
if (myDc == null|| rack == null){ if (myDc == null || rack == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<LocalMember> notMyDc = new ArrayList<LocalMember>(10); List<LocalMember> notMyDc = new ArrayList<LocalMember>(10);
for (LocalMember i : gossipManager.getLiveMembers()){ for (LocalMember i : gossipManager.getLiveMembers()) {
if (!myDc.equals(i.getProperties().get(DATACENTER))){ if (!myDc.equals(i.getProperties().get(DATACENTER))) {
notMyDc.add(i); notMyDc.add(i);
} }
} }
return notMyDc; return notMyDc;
} }
private List<LocalMember> sameDatacenterDifferentRack(){ private List<LocalMember> sameDatacenterDifferentRack() {
String myDc = gossipManager.getMyself().getProperties().get(DATACENTER); String myDc = gossipManager.getMyself().getProperties().get(DATACENTER);
String rack = gossipManager.getMyself().getProperties().get(RACK); String rack = gossipManager.getMyself().getProperties().get(RACK);
if (myDc == null|| rack == null){ if (myDc == null || rack == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<LocalMember> notMyDc = new ArrayList<LocalMember>(10); List<LocalMember> notMyDc = new ArrayList<LocalMember>(10);
for (LocalMember i : gossipManager.getLiveMembers()){ for (LocalMember i : gossipManager.getLiveMembers()) {
if (myDc.equals(i.getProperties().get(DATACENTER)) && !rack.equals(i.getProperties().get(RACK))){ if (myDc.equals(i.getProperties().get(DATACENTER))
&& !rack.equals(i.getProperties().get(RACK))) {
notMyDc.add(i); notMyDc.add(i);
} }
} }
return notMyDc; return notMyDc;
} }
private List<LocalMember> sameRackNodes(){ private List<LocalMember> sameRackNodes() {
String myDc = gossipManager.getMyself().getProperties().get(DATACENTER); String myDc = gossipManager.getMyself().getProperties().get(DATACENTER);
String rack = gossipManager.getMyself().getProperties().get(RACK); String rack = gossipManager.getMyself().getProperties().get(RACK);
if (myDc == null|| rack == null){ if (myDc == null || rack == null) {
return Collections.emptyList(); return Collections.emptyList();
} }
List<LocalMember> sameDcAndRack = new ArrayList<LocalMember>(10); List<LocalMember> sameDcAndRack = new ArrayList<LocalMember>(10);
for (LocalMember i : gossipManager.getLiveMembers()){ for (LocalMember i : gossipManager.getLiveMembers()) {
if (myDc.equals(i.getProperties().get(DATACENTER)) if (myDc.equals(i.getProperties().get(DATACENTER))
&& rack.equals(i.getProperties().get(RACK))){ && rack.equals(i.getProperties().get(RACK))) {
sameDcAndRack.add(i); sameDcAndRack.add(i);
} }
} }
@ -178,39 +218,39 @@ public class DatacenterRackAwareActiveGossiper extends AbstractActiveGossiper {
LocalMember i = selectPartner(sameRackNodes()); LocalMember i = selectPartner(sameRackNodes());
sendMembershipList(gossipManager.getMyself(), i); sendMembershipList(gossipManager.getMyself(), i);
} }
private void sendToSameRackMemberPerNode() { private void sendToSameRackMemberPerNode() {
sendPerNodeData(gossipManager.getMyself(), selectPartner(sameRackNodes())); sendPerNodeData(gossipManager.getMyself(), selectPartner(sameRackNodes()));
} }
private void sendToSameRackShared() { private void sendToSameRackShared() {
sendSharedData(gossipManager.getMyself(), selectPartner(sameRackNodes())); sendSharedData(gossipManager.getMyself(), selectPartner(sameRackNodes()));
} }
private void differentDcMember() { private void differentDcMember() {
sendMembershipList(gossipManager.getMyself(), selectPartner(differentDataCenter())); sendMembershipList(gossipManager.getMyself(), selectPartner(differentDataCenter()));
} }
private void differentDcPerNode() { private void differentDcPerNode() {
sendPerNodeData(gossipManager.getMyself(), selectPartner(differentDataCenter())); sendPerNodeData(gossipManager.getMyself(), selectPartner(differentDataCenter()));
} }
private void differentDcShared() { private void differentDcShared() {
sendSharedData(gossipManager.getMyself(), selectPartner(differentDataCenter())); sendSharedData(gossipManager.getMyself(), selectPartner(differentDataCenter()));
} }
private void sameDcDiffernetRackMember() { private void sameDcDiffernetRackMember() {
sendMembershipList(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack())); sendMembershipList(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack()));
} }
private void sameDcDiffernetRackPerNode() { private void sameDcDiffernetRackPerNode() {
sendPerNodeData(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack())); sendPerNodeData(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack()));
} }
private void sameDcDiffernetRackShared() { private void sameDcDiffernetRackShared() {
sendSharedData(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack())); sendSharedData(gossipManager.getMyself(), selectPartner(sameDatacenterDifferentRack()));
} }
@Override @Override
public void shutdown() { public void shutdown() {
super.shutdown(); super.shutdown();
@ -228,11 +268,9 @@ public class DatacenterRackAwareActiveGossiper extends AbstractActiveGossiper {
log.debug("Issue during shutdown", e); log.debug("Issue during shutdown", e);
} }
} }
/** /** sends an optimistic shutdown message to several clusters nodes */
* sends an optimistic shutdown message to several clusters nodes protected void sendShutdownMessage() {
*/
protected void sendShutdownMessage(){
List<LocalMember> l = gossipManager.getLiveMembers(); List<LocalMember> l = gossipManager.getLiveMembers();
int sendTo = l.size() < 3 ? 1 : l.size() / 3; int sendTo = l.size() < 3 ? 1 : l.size() / 3;
for (int i = 0; i < sendTo; i++) { for (int i = 0; i < sendTo; i++) {

View File

@ -45,38 +45,41 @@ import org.apache.gossip.udp.Trackable;
public class GossipCore implements GossipCoreConstants { public class GossipCore implements GossipCoreConstants {
private final GossipManager gossipManager; private final GossipManager gossipManager;
@Getter @Getter
private final ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>> perNodeData; private final ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>>
@Getter perNodeData;
private final ConcurrentHashMap<String, SharedDataMessage> sharedData;
@Getter private final ConcurrentHashMap<String, SharedDataMessage> sharedData;
private final Meter messageSerdeException; private final Meter messageSerdeException;
private final Meter transmissionException; private final Meter transmissionException;
private final Meter transmissionSuccess; private final Meter transmissionSuccess;
private final DataEventManager eventManager; private final DataEventManager eventManager;
private ConcurrentHashMap<String, LatchAndBase> requests; private final ConcurrentHashMap<String, LatchAndBase> requests;
public GossipCore(GossipManager manager, MetricRegistry metrics){
public GossipCore(GossipManager manager, MetricRegistry metrics) {
this.gossipManager = manager; this.gossipManager = manager;
requests = new ConcurrentHashMap<>(); requests = new ConcurrentHashMap<>();
perNodeData = new ConcurrentHashMap<>(); perNodeData = new ConcurrentHashMap<>();
sharedData = new ConcurrentHashMap<>(); sharedData = new ConcurrentHashMap<>();
eventManager = new DataEventManager(metrics); eventManager = new DataEventManager(metrics);
metrics.register(PER_NODE_DATA_SIZE, (Gauge<Integer>)() -> perNodeData.size()); metrics.register(PER_NODE_DATA_SIZE, (Gauge<Integer>) perNodeData::size);
metrics.register(SHARED_DATA_SIZE, (Gauge<Integer>)() -> sharedData.size()); metrics.register(SHARED_DATA_SIZE, (Gauge<Integer>) sharedData::size);
metrics.register(REQUEST_SIZE, (Gauge<Integer>)() -> requests.size()); metrics.register(REQUEST_SIZE, (Gauge<Integer>) requests::size);
messageSerdeException = metrics.meter(MESSAGE_SERDE_EXCEPTION); messageSerdeException = metrics.meter(MESSAGE_SERDE_EXCEPTION);
transmissionException = metrics.meter(MESSAGE_TRANSMISSION_EXCEPTION); transmissionException = metrics.meter(MESSAGE_TRANSMISSION_EXCEPTION);
transmissionSuccess = metrics.meter(MESSAGE_TRANSMISSION_SUCCESS); transmissionSuccess = metrics.meter(MESSAGE_TRANSMISSION_SUCCESS);
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({"unchecked", "rawtypes"})
public void addSharedData(SharedDataMessage message) { public void addSharedData(SharedDataMessage message) {
while (true){ while (true) {
SharedDataMessage previous = sharedData.putIfAbsent(message.getKey(), message); SharedDataMessage previous = sharedData.putIfAbsent(message.getKey(), message);
if (previous == null){ if (previous == null) {
eventManager.notifySharedData(message.getKey(), message.getPayload(), null); eventManager.notifySharedData(message.getKey(), message.getPayload(), null);
return; return;
} }
if (message.getPayload() instanceof Crdt){ if (message.getPayload() instanceof Crdt) {
SharedDataMessage merged = new SharedDataMessage(); SharedDataMessage merged = new SharedDataMessage();
merged.setExpireAt(message.getExpireAt()); merged.setExpireAt(message.getExpireAt());
merged.setKey(message.getKey()); merged.setKey(message.getKey());
@ -85,18 +88,19 @@ public class GossipCore implements GossipCoreConstants {
Crdt mergedCrdt = ((Crdt) previous.getPayload()).merge((Crdt) message.getPayload()); Crdt mergedCrdt = ((Crdt) previous.getPayload()).merge((Crdt) message.getPayload());
merged.setPayload(mergedCrdt); merged.setPayload(mergedCrdt);
boolean replaced = sharedData.replace(message.getKey(), previous, merged); boolean replaced = sharedData.replace(message.getKey(), previous, merged);
if (replaced){ if (replaced) {
if(!merged.getPayload().equals(previous.getPayload())) { if (!merged.getPayload().equals(previous.getPayload())) {
eventManager eventManager.notifySharedData(
.notifySharedData(message.getKey(), merged.getPayload(), previous.getPayload()); message.getKey(), merged.getPayload(), previous.getPayload());
} }
return; return;
} }
} else { } else {
if (previous.getTimestamp() < message.getTimestamp()){ if (previous.getTimestamp() < message.getTimestamp()) {
boolean result = sharedData.replace(message.getKey(), previous, message); boolean result = sharedData.replace(message.getKey(), previous, message);
if (result){ if (result) {
eventManager.notifySharedData(message.getKey(), message.getPayload(), previous.getPayload()); eventManager.notifySharedData(
message.getKey(), message.getPayload(), previous.getPayload());
return; return;
} }
} else { } else {
@ -106,29 +110,30 @@ public class GossipCore implements GossipCoreConstants {
} }
} }
public void addPerNodeData(PerNodeDataMessage message){ public void addPerNodeData(PerNodeDataMessage message) {
ConcurrentHashMap<String,PerNodeDataMessage> nodeMap = new ConcurrentHashMap<>(); ConcurrentHashMap<String, PerNodeDataMessage> nodeMap = new ConcurrentHashMap<>();
nodeMap.put(message.getKey(), message); nodeMap.put(message.getKey(), message);
nodeMap = perNodeData.putIfAbsent(message.getNodeId(), nodeMap); nodeMap = perNodeData.putIfAbsent(message.getNodeId(), nodeMap);
if (nodeMap != null){ if (nodeMap != null) {
PerNodeDataMessage current = nodeMap.get(message.getKey()); PerNodeDataMessage current = nodeMap.get(message.getKey());
if (current == null){ if (current == null) {
nodeMap.putIfAbsent(message.getKey(), message); nodeMap.putIfAbsent(message.getKey(), message);
eventManager.notifyPerNodeData(message.getNodeId(), message.getKey(), message.getPayload(), null); eventManager.notifyPerNodeData(
message.getNodeId(), message.getKey(), message.getPayload(), null);
} else { } else {
if (current.getTimestamp() < message.getTimestamp()){ if (current.getTimestamp() < message.getTimestamp()) {
nodeMap.replace(message.getKey(), current, message); nodeMap.replace(message.getKey(), current, message);
eventManager.notifyPerNodeData(message.getNodeId(), message.getKey(), message.getPayload(), eventManager.notifyPerNodeData(
current.getPayload()); message.getNodeId(), message.getKey(), message.getPayload(), current.getPayload());
} }
} }
} else { } else {
eventManager.notifyPerNodeData(message.getNodeId(), message.getKey(), message.getPayload(), null); eventManager.notifyPerNodeData(
message.getNodeId(), message.getKey(), message.getPayload(), null);
} }
} }
public void shutdown(){ public void shutdown() {}
}
public void receive(Base base) { public void receive(Base base) {
if (!gossipManager.getMessageHandler().invoke(this, gossipManager, base)) { if (!gossipManager.getMessageHandler().invoke(this, gossipManager, base)) {
@ -137,8 +142,8 @@ public class GossipCore implements GossipCoreConstants {
} }
/** /**
* Sends a blocking message. * Sends a blocking message. todo: move functionality to TransportManager layer.
* todo: move functionality to TransportManager layer. *
* @param message * @param message
* @param uri * @param uri
* @throws RuntimeException if data can not be serialized or in transmission error * @throws RuntimeException if data can not be serialized or in transmission error
@ -160,13 +165,13 @@ public class GossipCore implements GossipCoreConstants {
} }
} }
public Response send(Base message, URI uri){ public Response send(Base message, URI uri) {
log.debug("Sending " + message); log.debug("Sending " + message);
log.debug("Current request queue " + requests); log.debug("Current request queue " + requests);
final Trackable t; final Trackable t;
LatchAndBase latchAndBase = null; LatchAndBase latchAndBase = null;
if (message instanceof Trackable){ if (message instanceof Trackable) {
t = (Trackable) message; t = (Trackable) message;
latchAndBase = new LatchAndBase(); latchAndBase = new LatchAndBase();
requests.put(t.getUuid() + "/" + t.getUriFrom(), latchAndBase); requests.put(t.getUuid() + "/" + t.getUriFrom(), latchAndBase);
@ -174,27 +179,28 @@ public class GossipCore implements GossipCoreConstants {
t = null; t = null;
} }
sendInternal(message, uri); sendInternal(message, uri);
if (latchAndBase == null){ if (latchAndBase == null) {
return null; return null;
} }
try { try {
boolean complete = latchAndBase.latch.await(1, TimeUnit.SECONDS); boolean complete = latchAndBase.latch.await(1, TimeUnit.SECONDS);
if (complete){ if (complete) {
return (Response) latchAndBase.base; return (Response) latchAndBase.base;
} else{ } else {
return null; return null;
} }
} catch (InterruptedException e) { } catch (InterruptedException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { } finally {
requests.remove(t.getUuid() + "/" + t.getUriFrom()); requests.remove(t.getUuid() + "/" + t.getUriFrom());
} }
} }
/** /**
* Sends a message across the network while blocking. Catches and ignores IOException in transmission. Used * Sends a message across the network while blocking. Catches and ignores IOException in
* when the protocol for the message is not to wait for a response * transmission. Used when the protocol for the message is not to wait for a response
*
* @param message the message to send * @param message the message to send
* @param u the uri to send it to * @param u the uri to send it to
*/ */
@ -217,10 +223,9 @@ public class GossipCore implements GossipCoreConstants {
* *
* @param senderMember * @param senderMember
* @param remoteList * @param remoteList
*
*/ */
public void mergeLists(RemoteMember senderMember, List<Member> remoteList) { public void mergeLists(RemoteMember senderMember, List<Member> remoteList) {
if (log.isDebugEnabled()){ if (log.isDebugEnabled()) {
debugState(senderMember, remoteList); debugState(senderMember, remoteList);
} }
for (LocalMember i : gossipManager.getDeadMembers()) { for (LocalMember i : gossipManager.getDeadMembers()) {
@ -228,26 +233,28 @@ public class GossipCore implements GossipCoreConstants {
log.debug(gossipManager.getMyself() + " contacted by dead member " + senderMember.getUri()); log.debug(gossipManager.getMyself() + " contacted by dead member " + senderMember.getUri());
i.recordHeartbeat(senderMember.getHeartbeat()); i.recordHeartbeat(senderMember.getHeartbeat());
i.setHeartbeat(senderMember.getHeartbeat()); i.setHeartbeat(senderMember.getHeartbeat());
//TODO consider forcing an UP here // TODO consider forcing an UP here
} }
} }
for (Member remoteMember : remoteList) { for (Member remoteMember : remoteList) {
if (remoteMember.getId().equals(gossipManager.getMyself().getId())) { if (remoteMember.getId().equals(gossipManager.getMyself().getId())) {
continue; continue;
} }
LocalMember aNewMember = new LocalMember(remoteMember.getClusterName(), LocalMember aNewMember =
remoteMember.getUri(), new LocalMember(
remoteMember.getId(), remoteMember.getClusterName(),
remoteMember.getHeartbeat(), remoteMember.getUri(),
remoteMember.getProperties(), remoteMember.getId(),
gossipManager.getSettings().getWindowSize(), remoteMember.getHeartbeat(),
gossipManager.getSettings().getMinimumSamples(), remoteMember.getProperties(),
gossipManager.getSettings().getDistribution()); gossipManager.getSettings().getWindowSize(),
gossipManager.getSettings().getMinimumSamples(),
gossipManager.getSettings().getDistribution());
aNewMember.recordHeartbeat(remoteMember.getHeartbeat()); aNewMember.recordHeartbeat(remoteMember.getHeartbeat());
Object result = gossipManager.getMembers().putIfAbsent(aNewMember, GossipState.UP); Object result = gossipManager.getMembers().putIfAbsent(aNewMember, GossipState.UP);
if (result != null){ if (result != null) {
for (Entry<LocalMember, GossipState> localMember : gossipManager.getMembers().entrySet()){ for (Entry<LocalMember, GossipState> localMember : gossipManager.getMembers().entrySet()) {
if (localMember.getKey().getId().equals(remoteMember.getId())){ if (localMember.getKey().getId().equals(remoteMember.getId())) {
localMember.getKey().recordHeartbeat(remoteMember.getHeartbeat()); localMember.getKey().recordHeartbeat(remoteMember.getHeartbeat());
localMember.getKey().setHeartbeat(remoteMember.getHeartbeat()); localMember.getKey().setHeartbeat(remoteMember.getHeartbeat());
localMember.getKey().setProperties(remoteMember.getProperties()); localMember.getKey().setProperties(remoteMember.getProperties());
@ -255,28 +262,37 @@ public class GossipCore implements GossipCoreConstants {
} }
} }
} }
if (log.isDebugEnabled()){ if (log.isDebugEnabled()) {
debugState(senderMember, remoteList); debugState(senderMember, remoteList);
} }
} }
private void debugState(RemoteMember senderMember, private void debugState(RemoteMember senderMember, List<Member> remoteList) {
List<Member> remoteList){
log.warn( log.warn(
"-----------------------\n" + "-----------------------\n"
"Me " + gossipManager.getMyself() + "\n" + + "Me "
"Sender " + senderMember + "\n" + + gossipManager.getMyself()
"RemoteList " + remoteList + "\n" + + "\n"
"Live " + gossipManager.getLiveMembers()+ "\n" + + "Sender "
"Dead " + gossipManager.getDeadMembers()+ "\n" + + senderMember
"======================="); + "\n"
+ "RemoteList "
+ remoteList
+ "\n"
+ "Live "
+ gossipManager.getLiveMembers()
+ "\n"
+ "Dead "
+ gossipManager.getDeadMembers()
+ "\n"
+ "=======================");
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public Crdt merge(SharedDataMessage message) { public Crdt merge(SharedDataMessage message) {
for (;;){ for (; ; ) {
SharedDataMessage previous = sharedData.putIfAbsent(message.getKey(), message); SharedDataMessage previous = sharedData.putIfAbsent(message.getKey(), message);
if (previous == null){ if (previous == null) {
return (Crdt) message.getPayload(); return (Crdt) message.getPayload();
} }
SharedDataMessage copy = new SharedDataMessage(); SharedDataMessage copy = new SharedDataMessage();
@ -288,35 +304,34 @@ public class GossipCore implements GossipCoreConstants {
Crdt merged = ((Crdt) previous.getPayload()).merge((Crdt) message.getPayload()); Crdt merged = ((Crdt) previous.getPayload()).merge((Crdt) message.getPayload());
copy.setPayload(merged); copy.setPayload(merged);
boolean replaced = sharedData.replace(message.getKey(), previous, copy); boolean replaced = sharedData.replace(message.getKey(), previous, copy);
if (replaced){ if (replaced) {
return merged; return merged;
} }
} }
} }
void registerPerNodeDataSubscriber(UpdateNodeDataEventHandler handler){ void registerPerNodeDataSubscriber(UpdateNodeDataEventHandler handler) {
eventManager.registerPerNodeDataSubscriber(handler); eventManager.registerPerNodeDataSubscriber(handler);
} }
void registerSharedDataSubscriber(UpdateSharedDataEventHandler handler){ void registerSharedDataSubscriber(UpdateSharedDataEventHandler handler) {
eventManager.registerSharedDataSubscriber(handler); eventManager.registerSharedDataSubscriber(handler);
} }
void unregisterPerNodeDataSubscriber(UpdateNodeDataEventHandler handler){ void unregisterPerNodeDataSubscriber(UpdateNodeDataEventHandler handler) {
eventManager.unregisterPerNodeDataSubscriber(handler); eventManager.unregisterPerNodeDataSubscriber(handler);
} }
void unregisterSharedDataSubscriber(UpdateSharedDataEventHandler handler){ void unregisterSharedDataSubscriber(UpdateSharedDataEventHandler handler) {
eventManager.unregisterSharedDataSubscriber(handler); eventManager.unregisterSharedDataSubscriber(handler);
} }
class LatchAndBase { static class LatchAndBase {
private final CountDownLatch latch; private final CountDownLatch latch;
private volatile Base base; private volatile Base base;
LatchAndBase(){ LatchAndBase() {
latch = new CountDownLatch(1); latch = new CountDownLatch(1);
} }
} }
} }

View File

@ -56,15 +56,16 @@ import org.apache.gossip.utils.ReflectionUtils;
@Slf4j @Slf4j
public class GossipManager { public class GossipManager {
// this mapper is used for ring and user-data persistence only. NOT messages. // this mapper is used for ring and user-data persistence only. NOT messages.
public static final ObjectMapper metdataObjectMapper = new ObjectMapper() { public static final ObjectMapper metdataObjectMapper =
@Serial new ObjectMapper() {
private static final long serialVersionUID = 1L; @Serial private static final long serialVersionUID = 1L;
{
enableDefaultTyping(); {
configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false); enableDefaultTyping();
}}; configure(JsonGenerator.Feature.WRITE_NUMBERS_AS_STRINGS, false);
}
};
private final ConcurrentSkipListMap<LocalMember, GossipState> members; private final ConcurrentSkipListMap<LocalMember, GossipState> members;
private final LocalMember me; private final LocalMember me;
@ -83,27 +84,47 @@ public class GossipManager {
private TransportManager transportManager; private TransportManager transportManager;
private ProtocolManager protocolManager; private ProtocolManager protocolManager;
public GossipManager(String cluster, public GossipManager(
URI uri, String id, Map<String, String> properties, GossipSettings settings, String cluster,
List<Member> gossipMembers, GossipListener listener, MetricRegistry registry, URI uri,
MessageHandler messageHandler) { String id,
Map<String, String> properties,
GossipSettings settings,
List<Member> gossipMembers,
GossipListener listener,
MetricRegistry registry,
MessageHandler messageHandler) {
this.settings = settings; this.settings = settings;
this.messageHandler = messageHandler; this.messageHandler = messageHandler;
clock = new SystemClock(); clock = new SystemClock();
me = new LocalMember(cluster, uri, id, clock.nanoTime(), properties, me =
settings.getWindowSize(), settings.getMinimumSamples(), settings.getDistribution()); new LocalMember(
cluster,
uri,
id,
clock.nanoTime(),
properties,
settings.getWindowSize(),
settings.getMinimumSamples(),
settings.getDistribution());
gossipCore = new GossipCore(this, registry); gossipCore = new GossipCore(this, registry);
this.lockManager = new LockManager(this, settings.getLockManagerSettings(), registry); this.lockManager = new LockManager(this, settings.getLockManagerSettings(), registry);
dataReaper = new DataReaper(gossipCore, clock); dataReaper = new DataReaper(gossipCore, clock);
members = new ConcurrentSkipListMap<>(); members = new ConcurrentSkipListMap<>();
for (Member startupMember : gossipMembers) { for (Member startupMember : gossipMembers) {
if (!startupMember.equals(me)) { if (!startupMember.equals(me)) {
LocalMember member = new LocalMember(startupMember.getClusterName(), LocalMember member =
startupMember.getUri(), startupMember.getId(), new LocalMember(
clock.nanoTime(), startupMember.getProperties(), settings.getWindowSize(), startupMember.getClusterName(),
settings.getMinimumSamples(), settings.getDistribution()); startupMember.getUri(),
//TODO should members start in down state? startupMember.getId(),
clock.nanoTime(),
startupMember.getProperties(),
settings.getWindowSize(),
settings.getMinimumSamples(),
settings.getDistribution());
// TODO should members start in down state?
members.put(member, GossipState.DOWN); members.put(member, GossipState.DOWN);
} }
} }
@ -111,28 +132,45 @@ public class GossipManager {
this.scheduledServiced = Executors.newScheduledThreadPool(1); this.scheduledServiced = Executors.newScheduledThreadPool(1);
this.registry = registry; this.registry = registry;
this.ringState = new RingStatePersister(GossipManager.buildRingStatePath(this), this); this.ringState = new RingStatePersister(GossipManager.buildRingStatePath(this), this);
this.userDataState = new UserDataPersister( this.userDataState =
gossipCore, new UserDataPersister(
GossipManager.buildPerNodeDataPath(this), gossipCore,
GossipManager.buildSharedDataPath(this)); GossipManager.buildPerNodeDataPath(this),
this.memberStateRefresher = new GossipMemberStateRefresher(members, settings, listener, this::findPerNodeGossipData); GossipManager.buildSharedDataPath(this));
this.memberStateRefresher =
new GossipMemberStateRefresher(members, settings, listener, this::findPerNodeGossipData);
readSavedRingState(); readSavedRingState();
readSavedDataState(); readSavedDataState();
} }
public static File buildRingStatePath(GossipManager manager) { public static File buildRingStatePath(GossipManager manager) {
return new File(manager.getSettings().getPathToRingState(), "ringstate." + manager.getMyself().getClusterName() + "." return new File(
+ manager.getMyself().getId() + ".json"); manager.getSettings().getPathToRingState(),
"ringstate."
+ manager.getMyself().getClusterName()
+ "."
+ manager.getMyself().getId()
+ ".json");
} }
public static File buildSharedDataPath(GossipManager manager){ public static File buildSharedDataPath(GossipManager manager) {
return new File(manager.getSettings().getPathToDataState(), "shareddata." return new File(
+ manager.getMyself().getClusterName() + "." + manager.getMyself().getId() + ".json"); manager.getSettings().getPathToDataState(),
"shareddata."
+ manager.getMyself().getClusterName()
+ "."
+ manager.getMyself().getId()
+ ".json");
} }
public static File buildPerNodeDataPath(GossipManager manager) { public static File buildPerNodeDataPath(GossipManager manager) {
return new File(manager.getSettings().getPathToDataState(), "pernodedata." return new File(
+ manager.getMyself().getClusterName() + "." + manager.getMyself().getId() + ".json"); manager.getSettings().getPathToDataState(),
"pernodedata."
+ manager.getMyself().getClusterName()
+ "."
+ manager.getMyself().getId()
+ ".json");
} }
public MessageHandler getMessageHandler() { public MessageHandler getMessageHandler() {
@ -152,22 +190,21 @@ public class GossipManager {
*/ */
public List<LocalMember> getDeadMembers() { public List<LocalMember> getDeadMembers() {
return Collections.unmodifiableList( return Collections.unmodifiableList(
members.entrySet() members.entrySet().stream()
.stream() .filter(entry -> GossipState.DOWN.equals(entry.getValue()))
.filter(entry -> GossipState.DOWN.equals(entry.getValue())) .map(Entry::getKey)
.map(Entry::getKey).collect(Collectors.toList())); .collect(Collectors.toList()));
} }
/** /**
*
* @return a read only list of members found in the UP state * @return a read only list of members found in the UP state
*/ */
public List<LocalMember> getLiveMembers() { public List<LocalMember> getLiveMembers() {
return Collections.unmodifiableList( return Collections.unmodifiableList(
members.entrySet() members.entrySet().stream()
.stream() .filter(entry -> GossipState.UP.equals(entry.getValue()))
.filter(entry -> GossipState.UP.equals(entry.getValue())) .map(Entry::getKey)
.map(Entry::getKey).collect(Collectors.toList())); .collect(Collectors.toList()));
} }
public LocalMember getMyself() { public LocalMember getMyself() {
@ -183,17 +220,17 @@ public class GossipManager {
// protocol manager and transport managers are specified in settings. // protocol manager and transport managers are specified in settings.
// construct them here via reflection. // construct them here via reflection.
protocolManager = ReflectionUtils.constructWithReflection( protocolManager =
settings.getProtocolManagerClass(), ReflectionUtils.constructWithReflection(
new Class<?>[] { GossipSettings.class, String.class, MetricRegistry.class }, settings.getProtocolManagerClass(),
new Object[] { settings, me.getId(), this.getRegistry() } new Class<?>[] {GossipSettings.class, String.class, MetricRegistry.class},
); new Object[] {settings, me.getId(), this.getRegistry()});
transportManager = ReflectionUtils.constructWithReflection( transportManager =
settings.getTransportManagerClass(), ReflectionUtils.constructWithReflection(
new Class<?>[] { GossipManager.class, GossipCore.class}, settings.getTransportManagerClass(),
new Object[] { this, gossipCore } new Class<?>[] {GossipManager.class, GossipCore.class},
); new Object[] {this, gossipCore});
// start processing gossip messages. // start processing gossip messages.
transportManager.startEndpoint(); transportManager.startEndpoint();
@ -213,10 +250,16 @@ public class GossipManager {
private void readSavedRingState() { private void readSavedRingState() {
if (settings.isPersistRingState()) { if (settings.isPersistRingState()) {
for (LocalMember l : ringState.readFromDisk()) { for (LocalMember l : ringState.readFromDisk()) {
LocalMember member = new LocalMember(l.getClusterName(), LocalMember member =
l.getUri(), l.getId(), new LocalMember(
clock.nanoTime(), l.getProperties(), settings.getWindowSize(), l.getClusterName(),
settings.getMinimumSamples(), settings.getDistribution()); l.getUri(),
l.getId(),
clock.nanoTime(),
l.getProperties(),
settings.getWindowSize(),
settings.getMinimumSamples(),
settings.getDistribution());
members.putIfAbsent(member, GossipState.DOWN); members.putIfAbsent(member, GossipState.DOWN);
} }
} }
@ -224,7 +267,8 @@ public class GossipManager {
private void readSavedDataState() { private void readSavedDataState() {
if (settings.isPersistDataState()) { if (settings.isPersistDataState()) {
for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> l : userDataState.readPerNodeFromDisk().entrySet()) { for (Entry<String, ConcurrentHashMap<String, PerNodeDataMessage>> l :
userDataState.readPerNodeFromDisk().entrySet()) {
for (Entry<String, PerNodeDataMessage> j : l.getValue().entrySet()) { for (Entry<String, PerNodeDataMessage> j : l.getValue().entrySet()) {
gossipCore.addPerNodeData(j.getValue()); gossipCore.addPerNodeData(j.getValue());
} }
@ -237,9 +281,7 @@ public class GossipManager {
} }
} }
/** /** Shutdown the gossip service. */
* Shutdown the gossip service.
*/
public void shutdown() { public void shutdown() {
gossipServiceRunning.set(false); gossipServiceRunning.set(false);
lockManager.shutdown(); lockManager.shutdown();
@ -256,7 +298,7 @@ public class GossipManager {
scheduledServiced.shutdownNow(); scheduledServiced.shutdownNow();
} }
public void gossipPerNodeData(PerNodeDataMessage message){ public void gossipPerNodeData(PerNodeDataMessage message) {
Objects.nonNull(message.getKey()); Objects.nonNull(message.getKey());
Objects.nonNull(message.getTimestamp()); Objects.nonNull(message.getTimestamp());
Objects.nonNull(message.getPayload()); Objects.nonNull(message.getPayload());
@ -264,7 +306,7 @@ public class GossipManager {
gossipCore.addPerNodeData(message); gossipCore.addPerNodeData(message);
} }
public void gossipSharedData(SharedDataMessage message){ public void gossipSharedData(SharedDataMessage message) {
Objects.nonNull(message.getKey()); Objects.nonNull(message.getKey());
Objects.nonNull(message.getTimestamp()); Objects.nonNull(message.getTimestamp());
Objects.nonNull(message.getPayload()); Objects.nonNull(message.getPayload());
@ -273,12 +315,12 @@ public class GossipManager {
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public Crdt findCrdt(String key){ public Crdt findCrdt(String key) {
SharedDataMessage l = gossipCore.getSharedData().get(key); SharedDataMessage l = gossipCore.getSharedData().get(key);
if (l == null){ if (l == null) {
return null; return null;
} }
if (l.getExpireAt() < clock.currentTimeMillis()){ if (l.getExpireAt() < clock.currentTimeMillis()) {
return null; return null;
} else { } else {
return (Crdt) l.getPayload(); return (Crdt) l.getPayload();
@ -286,24 +328,24 @@ public class GossipManager {
} }
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public Crdt merge(SharedDataMessage message){ public Crdt merge(SharedDataMessage message) {
Objects.nonNull(message.getKey()); Objects.nonNull(message.getKey());
Objects.nonNull(message.getTimestamp()); Objects.nonNull(message.getTimestamp());
Objects.nonNull(message.getPayload()); Objects.nonNull(message.getPayload());
message.setNodeId(me.getId()); message.setNodeId(me.getId());
if (! (message.getPayload() instanceof Crdt)){ if (!(message.getPayload() instanceof Crdt)) {
throw new IllegalArgumentException("Not a subclass of CRDT " + message.getPayload()); throw new IllegalArgumentException("Not a subclass of CRDT " + message.getPayload());
} }
return gossipCore.merge(message); return gossipCore.merge(message);
} }
public PerNodeDataMessage findPerNodeGossipData(String nodeId, String key){ public PerNodeDataMessage findPerNodeGossipData(String nodeId, String key) {
ConcurrentHashMap<String, PerNodeDataMessage> j = gossipCore.getPerNodeData().get(nodeId); ConcurrentHashMap<String, PerNodeDataMessage> j = gossipCore.getPerNodeData().get(nodeId);
if (j == null){ if (j == null) {
return null; return null;
} else { } else {
PerNodeDataMessage l = j.get(key); PerNodeDataMessage l = j.get(key);
if (l == null){ if (l == null) {
return null; return null;
} }
if (l.getExpireAt() != null && l.getExpireAt() < clock.currentTimeMillis()) { if (l.getExpireAt() != null && l.getExpireAt() < clock.currentTimeMillis()) {
@ -313,12 +355,12 @@ public class GossipManager {
} }
} }
public SharedDataMessage findSharedGossipData(String key){ public SharedDataMessage findSharedGossipData(String key) {
SharedDataMessage l = gossipCore.getSharedData().get(key); SharedDataMessage l = gossipCore.getSharedData().get(key);
if (l == null){ if (l == null) {
return null; return null;
} }
if (l.getExpireAt() < clock.currentTimeMillis()){ if (l.getExpireAt() < clock.currentTimeMillis()) {
return null; return null;
} else { } else {
return l; return l;
@ -344,34 +386,34 @@ public class GossipManager {
public Clock getClock() { public Clock getClock() {
return clock; return clock;
} }
// todo: consider making these path methods part of GossipSettings // todo: consider making these path methods part of GossipSettings
public MetricRegistry getRegistry() { public MetricRegistry getRegistry() {
return registry; return registry;
} }
public ProtocolManager getProtocolManager() { public ProtocolManager getProtocolManager() {
return protocolManager; return protocolManager;
} }
public TransportManager getTransportManager() { public TransportManager getTransportManager() {
return transportManager; return transportManager;
} }
public void registerPerNodeDataSubscriber(UpdateNodeDataEventHandler handler){ public void registerPerNodeDataSubscriber(UpdateNodeDataEventHandler handler) {
gossipCore.registerPerNodeDataSubscriber(handler); gossipCore.registerPerNodeDataSubscriber(handler);
} }
public void registerSharedDataSubscriber(UpdateSharedDataEventHandler handler){ public void registerSharedDataSubscriber(UpdateSharedDataEventHandler handler) {
gossipCore.registerSharedDataSubscriber(handler); gossipCore.registerSharedDataSubscriber(handler);
} }
public void unregisterPerNodeDataSubscriber(UpdateNodeDataEventHandler handler){ public void unregisterPerNodeDataSubscriber(UpdateNodeDataEventHandler handler) {
gossipCore.unregisterPerNodeDataSubscriber(handler); gossipCore.unregisterPerNodeDataSubscriber(handler);
} }
public void unregisterSharedDataSubscriber(UpdateSharedDataEventHandler handler){ public void unregisterSharedDataSubscriber(UpdateSharedDataEventHandler handler) {
gossipCore.unregisterSharedDataSubscriber(handler); gossipCore.unregisterSharedDataSubscriber(handler);
} }
@ -381,6 +423,7 @@ public class GossipManager {
/** /**
* Get the lock manager specified with this GossipManager. * Get the lock manager specified with this GossipManager.
*
* @return lock manager object. * @return lock manager object.
*/ */
public LockManager getLockManager() { public LockManager getLockManager() {
@ -389,10 +432,11 @@ public class GossipManager {
/** /**
* Try to acquire a lock on given shared data key. * Try to acquire a lock on given shared data key.
*
* @param key key of tha share data object. * @param key key of tha share data object.
* @throws VoteFailedException if the locking is failed. * @throws VoteFailedException if the locking is failed.
*/ */
public void acquireSharedDataLock(String key) throws VoteFailedException{ public void acquireSharedDataLock(String key) throws VoteFailedException {
lockManager.acquireSharedDataLock(key); lockManager.acquireSharedDataLock(key);
} }
} }

View File

@ -18,19 +18,17 @@
package org.apache.gossip.manager; package org.apache.gossip.manager;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import org.apache.gossip.GossipSettings;
import org.apache.gossip.Member;
import org.apache.gossip.StartupSettings;
import org.apache.gossip.event.GossipListener;
import org.apache.gossip.event.GossipState;
import org.apache.gossip.manager.handlers.MessageHandler;
import org.apache.gossip.manager.handlers.MessageHandlerFactory;
import java.net.URI; import java.net.URI;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.gossip.GossipSettings;
import org.apache.gossip.Member;
import org.apache.gossip.StartupSettings;
import org.apache.gossip.event.GossipListener;
import org.apache.gossip.manager.handlers.MessageHandler;
import org.apache.gossip.manager.handlers.MessageHandlerFactory;
public class GossipManagerBuilder { public class GossipManagerBuilder {

View File

@ -43,17 +43,20 @@ public class GossipMemberStateRefresher {
private final ScheduledExecutorService scheduledExecutor; private final ScheduledExecutorService scheduledExecutor;
private final BlockingQueue<Runnable> workQueue; private final BlockingQueue<Runnable> workQueue;
public GossipMemberStateRefresher(Map<LocalMember, GossipState> members, GossipSettings settings, public GossipMemberStateRefresher(
GossipListener listener, Map<LocalMember, GossipState> members,
BiFunction<String, String, PerNodeDataMessage> findPerNodeGossipData) { GossipSettings settings,
GossipListener listener,
BiFunction<String, String, PerNodeDataMessage> findPerNodeGossipData) {
this.members = members; this.members = members;
this.settings = settings; this.settings = settings;
listeners.add(listener); listeners.add(listener);
this.findPerNodeGossipData = findPerNodeGossipData; this.findPerNodeGossipData = findPerNodeGossipData;
clock = new SystemClock(); clock = new SystemClock();
workQueue = new ArrayBlockingQueue<>(1024); workQueue = new ArrayBlockingQueue<>(1024);
listenerExecutor = new ThreadPoolExecutor(1, 20, 1, TimeUnit.SECONDS, workQueue, listenerExecutor =
new ThreadPoolExecutor.DiscardOldestPolicy()); new ThreadPoolExecutor(
1, 20, 1, TimeUnit.SECONDS, workQueue, new ThreadPoolExecutor.DiscardOldestPolicy());
scheduledExecutor = Executors.newScheduledThreadPool(1); scheduledExecutor = Executors.newScheduledThreadPool(1);
} }
@ -72,8 +75,7 @@ public class GossipMemberStateRefresher {
public void runOnce() { public void runOnce() {
for (Entry<LocalMember, GossipState> entry : members.entrySet()) { for (Entry<LocalMember, GossipState> entry : members.entrySet()) {
boolean userDown = processOptimisticShutdown(entry); boolean userDown = processOptimisticShutdown(entry);
if (userDown) if (userDown) continue;
continue;
Double phiMeasure = entry.getKey().detect(clock.nanoTime()); Double phiMeasure = entry.getKey().detect(clock.nanoTime());
GossipState requiredState; GossipState requiredState;
@ -87,17 +89,15 @@ public class GossipMemberStateRefresher {
if (entry.getValue() != requiredState) { if (entry.getValue() != requiredState) {
members.put(entry.getKey(), requiredState); members.put(entry.getKey(), requiredState);
/* Call listeners asynchronously */ /* Call listeners asynchronously */
for (GossipListener listener: listeners) for (GossipListener listener : listeners)
listenerExecutor.execute(() -> listener.gossipEvent(entry.getKey(), requiredState)); listenerExecutor.execute(() -> listener.gossipEvent(entry.getKey(), requiredState));
} }
} }
} }
public GossipState calcRequiredState(Double phiMeasure) { public GossipState calcRequiredState(Double phiMeasure) {
if (phiMeasure > settings.getConvictThreshold()) if (phiMeasure > settings.getConvictThreshold()) return GossipState.DOWN;
return GossipState.DOWN; else return GossipState.UP;
else
return GossipState.UP;
} }
public GossipState calcRequiredStateCleanupInterval(LocalMember member, GossipState state) { public GossipState calcRequiredStateCleanupInterval(LocalMember member, GossipState state) {
@ -111,14 +111,15 @@ public class GossipMemberStateRefresher {
} }
/** /**
* If we have a special key the per-node data that means that the node has sent us * If we have a special key the per-node data that means that the node has sent us a pre-emptive
* a pre-emptive shutdown message. We process this so node is seen down sooner * shutdown message. We process this so node is seen down sooner
* *
* @param l member to consider * @param l member to consider
* @return true if node forced down * @return true if node forced down
*/ */
public boolean processOptimisticShutdown(Entry<LocalMember, GossipState> l) { public boolean processOptimisticShutdown(Entry<LocalMember, GossipState> l) {
PerNodeDataMessage m = findPerNodeGossipData.apply(l.getKey().getId(), ShutdownMessage.PER_NODE_KEY); PerNodeDataMessage m =
findPerNodeGossipData.apply(l.getKey().getId(), ShutdownMessage.PER_NODE_KEY);
if (m == null) { if (m == null) {
return false; return false;
} }
@ -126,7 +127,7 @@ public class GossipMemberStateRefresher {
if (s.getShutdownAtNanos() > l.getKey().getHeartbeat()) { if (s.getShutdownAtNanos() > l.getKey().getHeartbeat()) {
members.put(l.getKey(), GossipState.DOWN); members.put(l.getKey(), GossipState.DOWN);
if (l.getValue() == GossipState.UP) { if (l.getValue() == GossipState.UP) {
for (GossipListener listener: listeners) for (GossipListener listener : listeners)
listenerExecutor.execute(() -> listener.gossipEvent(l.getKey(), GossipState.DOWN)); listenerExecutor.execute(() -> listener.gossipEvent(l.getKey(), GossipState.DOWN));
} }
return true; return true;
@ -153,4 +154,4 @@ public class GossipMemberStateRefresher {
} }
listenerExecutor.shutdownNow(); listenerExecutor.shutdownNow();
} }
} }

View File

@ -14,7 +14,7 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.gossip.manager; package org.apache.gossip.manager;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@ -35,21 +35,21 @@ public class RingStatePersister implements Runnable {
// NOTE: this is a different instance than what gets used for message marshalling. // NOTE: this is a different instance than what gets used for message marshalling.
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final GossipManager manager; private final GossipManager manager;
public RingStatePersister(File path, GossipManager manager){ public RingStatePersister(File path, GossipManager manager) {
this.path = path; this.path = path;
this.objectMapper = GossipManager.metdataObjectMapper; this.objectMapper = GossipManager.metdataObjectMapper;
this.manager = manager; this.manager = manager;
} }
@Override @Override
public void run() { public void run() {
writeToDisk(); writeToDisk();
} }
void writeToDisk() { void writeToDisk() {
NavigableSet<LocalMember> i = manager.getMembers().keySet(); NavigableSet<LocalMember> i = manager.getMembers().keySet();
try (FileOutputStream fos = new FileOutputStream(path)){ try (FileOutputStream fos = new FileOutputStream(path)) {
objectMapper.writeValue(fos, i); objectMapper.writeValue(fos, i);
} catch (IOException e) { } catch (IOException e) {
log.error("Error!", e); log.error("Error!", e);
@ -61,7 +61,7 @@ public class RingStatePersister implements Runnable {
if (!path.exists()) { if (!path.exists()) {
return new ArrayList<>(); return new ArrayList<>();
} }
try (FileInputStream fos = new FileInputStream(path)){ try (FileInputStream fos = new FileInputStream(path)) {
return objectMapper.readValue(fos, ArrayList.class); return objectMapper.readValue(fos, ArrayList.class);
} catch (IOException e) { } catch (IOException e) {
log.error("Error", e); log.error("Error", e);

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.gossip.manager; package org.apache.gossip.manager;
import com.codahale.metrics.MetricRegistry;
import java.util.List; import java.util.List;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
@ -24,12 +25,9 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.LocalMember; import org.apache.gossip.LocalMember;
import com.codahale.metrics.MetricRegistry;
/** Base implementation gossips randomly to live nodes periodically gossips to dead ones */ /** Base implementation gossips randomly to live nodes periodically gossips to dead ones */
@Slf4j @Slf4j
public class SimpleActiveGossiper extends AbstractActiveGossiper { public class SimpleActiveGossiper extends AbstractActiveGossiper {

View File

@ -17,14 +17,12 @@
*/ */
package org.apache.gossip.manager; package org.apache.gossip.manager;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.model.PerNodeDataMessage; import org.apache.gossip.model.PerNodeDataMessage;
import org.apache.gossip.model.SharedDataMessage; import org.apache.gossip.model.SharedDataMessage;
@ -48,14 +46,14 @@ public class UserDataPersister implements Runnable {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>> readPerNodeFromDisk() { ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>> readPerNodeFromDisk() {
if (!perNodePath.exists()) { if (!perNodePath.exists()) {
return new ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>>(); return new ConcurrentHashMap<>();
} }
try (FileInputStream fos = new FileInputStream(perNodePath)) { try (FileInputStream fos = new FileInputStream(perNodePath)) {
return objectMapper.readValue(fos, ConcurrentHashMap.class); return objectMapper.readValue(fos, ConcurrentHashMap.class);
} catch (IOException e) { } catch (IOException e) {
log.error("Error!", e); log.error("Error!", e);
} }
return new ConcurrentHashMap<String, ConcurrentHashMap<String, PerNodeDataMessage>>(); return new ConcurrentHashMap<>();
} }
void writePerNodeToDisk() { void writePerNodeToDisk() {

View File

@ -33,7 +33,7 @@ import org.apache.gossip.udp.UdpNotAMemberFault;
@Slf4j @Slf4j
public class ActiveGossipMessageHandler implements MessageHandler { public class ActiveGossipMessageHandler implements MessageHandler {
/** /**
* @param gossipCore context. * @param gossipCore context.
* @param gossipManager context. * @param gossipManager context.
@ -53,7 +53,8 @@ public class ActiveGossipMessageHandler implements MessageHandler {
log.debug("Gossip message with faulty URI", e); log.debug("Gossip message with faulty URI", e);
continue; continue;
} }
RemoteMember member = new RemoteMember( RemoteMember member =
new RemoteMember(
activeGossipMessage.getMembers().get(i).getCluster(), activeGossipMessage.getMembers().get(i).getCluster(),
u, u,
activeGossipMessage.getMembers().get(i).getId(), activeGossipMessage.getMembers().get(i).getId(),

View File

@ -26,22 +26,17 @@ import org.apache.gossip.udp.UdpNotAMemberFault;
import org.apache.gossip.udp.UdpPerNodeDataBulkMessage; import org.apache.gossip.udp.UdpPerNodeDataBulkMessage;
import org.apache.gossip.udp.UdpSharedDataBulkMessage; import org.apache.gossip.udp.UdpSharedDataBulkMessage;
@JsonTypeInfo( @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
use = JsonTypeInfo.Id.CLASS,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({ @JsonSubTypes({
@Type(value = ActiveGossipMessage.class, name = "ActiveGossipMessage"), @Type(value = ActiveGossipMessage.class, name = "ActiveGossipMessage"),
@Type(value = Fault.class, name = "Fault"), @Type(value = Fault.class, name = "Fault"),
@Type(value = ActiveGossipOk.class, name = "ActiveGossipOk"), @Type(value = ActiveGossipOk.class, name = "ActiveGossipOk"),
@Type(value = UdpActiveGossipOk.class, name = "UdpActiveGossipOk"), @Type(value = UdpActiveGossipOk.class, name = "UdpActiveGossipOk"),
@Type(value = UdpActiveGossipMessage.class, name = "UdpActiveGossipMessage"), @Type(value = UdpActiveGossipMessage.class, name = "UdpActiveGossipMessage"),
@Type(value = UdpNotAMemberFault.class, name = "UdpNotAMemberFault"), @Type(value = UdpNotAMemberFault.class, name = "UdpNotAMemberFault"),
@Type(value = PerNodeDataMessage.class, name = "PerNodeDataMessage"), @Type(value = PerNodeDataMessage.class, name = "PerNodeDataMessage"),
@Type(value = UdpPerNodeDataBulkMessage.class, name = "UdpPerNodeDataMessage"), @Type(value = UdpPerNodeDataBulkMessage.class, name = "UdpPerNodeDataMessage"),
@Type(value = SharedDataMessage.class, name = "SharedDataMessage"), @Type(value = SharedDataMessage.class, name = "SharedDataMessage"),
@Type(value = UdpSharedDataBulkMessage.class, name = "UdpSharedDataMessage") @Type(value = UdpSharedDataBulkMessage.class, name = "UdpSharedDataMessage")
}) })
public class Base { public class Base {}
}

View File

@ -31,47 +31,65 @@ public class SharedDataMessage extends Base {
public String getNodeId() { public String getNodeId() {
return nodeId; return nodeId;
} }
public void setNodeId(String nodeId) { public void setNodeId(String nodeId) {
this.nodeId = nodeId; this.nodeId = nodeId;
} }
public String getKey() { public String getKey() {
return key; return key;
} }
public void setKey(String key) { public void setKey(String key) {
this.key = key; this.key = key;
} }
public Object getPayload() { public Object getPayload() {
return payload; return payload;
} }
public void setPayload(Object payload) { public void setPayload(Object payload) {
this.payload = payload; this.payload = payload;
} }
public Long getTimestamp() { public Long getTimestamp() {
return timestamp; return timestamp;
} }
public void setTimestamp(Long timestamp) { public void setTimestamp(Long timestamp) {
this.timestamp = timestamp; this.timestamp = timestamp;
} }
public Long getExpireAt() { public Long getExpireAt() {
return expireAt; return expireAt;
} }
public void setExpireAt(Long expireAt) { public void setExpireAt(Long expireAt) {
this.expireAt = expireAt; this.expireAt = expireAt;
} }
public Replicable<SharedDataMessage> getReplicable() { public Replicable<SharedDataMessage> getReplicable() {
return replicable; return replicable;
} }
public void setReplicable(Replicable<SharedDataMessage> replicable) { public void setReplicable(Replicable<SharedDataMessage> replicable) {
this.replicable = replicable; this.replicable = replicable;
} }
@Override @Override
public String toString() { public String toString() {
return "SharedGossipDataMessage [nodeId=" + nodeId + ", key=" + key + ", payload=" + payload return "SharedGossipDataMessage [nodeId="
+ ", timestamp=" + timestamp + ", expireAt=" + expireAt + nodeId
+ ", replicable=" + replicable + "]"; + ", key="
+ key
+ ", payload="
+ payload
+ ", timestamp="
+ timestamp
+ ", expireAt="
+ expireAt
+ ", replicable="
+ replicable
+ "]";
} }
} }

View File

@ -23,7 +23,9 @@ import org.apache.gossip.model.Base;
/** interface for managing message marshaling. */ /** interface for managing message marshaling. */
public interface ProtocolManager { public interface ProtocolManager {
/** serialize a message /**
* serialize a message
*
* @param message * @param message
* @return serialized message. * @return serialized message.
* @throws IOException * @throws IOException
@ -32,6 +34,7 @@ public interface ProtocolManager {
/** /**
* Reads the next message from a byte source. * Reads the next message from a byte source.
*
* @param buf * @param buf
* @return a gossip message. * @return a gossip message.
* @throws IOException * @throws IOException

View File

@ -17,11 +17,10 @@
*/ */
package org.apache.gossip.replication; package org.apache.gossip.replication;
import org.apache.gossip.LocalMember;
import org.apache.gossip.model.Base;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.gossip.LocalMember;
import org.apache.gossip.model.Base;
/** /**
* Replicable implementation which does not replicate data to given set of nodes. * Replicable implementation which does not replicate data to given set of nodes.

View File

@ -29,9 +29,9 @@ import org.apache.gossip.model.Base;
* @see Replicable * @see Replicable
*/ */
public class WhiteListReplicable<T extends Base> implements Replicable<T> { public class WhiteListReplicable<T extends Base> implements Replicable<T> {
private final List<LocalMember> whiteListMembers; private final List<LocalMember> whiteListMembers;
public WhiteListReplicable(List<LocalMember> whiteListMembers) { public WhiteListReplicable(List<LocalMember> whiteListMembers) {
if (whiteListMembers == null) { if (whiteListMembers == null) {
this.whiteListMembers = new ArrayList<>(); this.whiteListMembers = new ArrayList<>();

View File

@ -27,9 +27,7 @@ import org.apache.gossip.manager.GossipCore;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.utils.ReflectionUtils; import org.apache.gossip.utils.ReflectionUtils;
/** /** Manage the protcol threads (active and passive gossipers). */
* Manage the protcol threads (active and passive gossipers).
*/
@Slf4j @Slf4j
public abstract class AbstractTransportManager implements TransportManager { public abstract class AbstractTransportManager implements TransportManager {
@ -37,19 +35,16 @@ public abstract class AbstractTransportManager implements TransportManager {
protected final GossipCore gossipCore; protected final GossipCore gossipCore;
private final ExecutorService gossipThreadExecutor; private final ExecutorService gossipThreadExecutor;
private final AbstractActiveGossiper activeGossipThread; private final AbstractActiveGossiper activeGossipThread;
public AbstractTransportManager(GossipManager gossipManager, GossipCore gossipCore) { public AbstractTransportManager(GossipManager gossipManager, GossipCore gossipCore) {
this.gossipManager = gossipManager; this.gossipManager = gossipManager;
this.gossipCore = gossipCore; this.gossipCore = gossipCore;
gossipThreadExecutor = Executors.newCachedThreadPool(); gossipThreadExecutor = Executors.newCachedThreadPool();
activeGossipThread = ReflectionUtils.constructWithReflection( activeGossipThread =
gossipManager.getSettings().getActiveGossipClass(), ReflectionUtils.constructWithReflection(
new Class<?>[]{ gossipManager.getSettings().getActiveGossipClass(),
GossipManager.class, GossipCore.class, MetricRegistry.class new Class<?>[] {GossipManager.class, GossipCore.class, MetricRegistry.class},
}, new Object[] {gossipManager, gossipCore, gossipManager.getRegistry()});
new Object[]{
gossipManager, gossipCore, gossipManager.getRegistry()
});
} }
// shut down threads etc. // shut down threads etc.

View File

@ -23,6 +23,7 @@ public class UdpNotAMemberFault extends NotAMemberFault implements Trackable {
private String uriFrom; private String uriFrom;
private String uuid; private String uuid;
public UdpNotAMemberFault() {} public UdpNotAMemberFault() {}
public String getUriFrom() { public String getUriFrom() {

View File

@ -23,7 +23,6 @@ import java.net.URISyntaxException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.manager.GossipManagerBuilder;
import org.junit.After; import org.junit.After;

View File

@ -27,16 +27,18 @@ public class MemberTest {
@Test @Test
public void testHashCodeFromGossip40() throws URISyntaxException { public void testHashCodeFromGossip40() throws URISyntaxException {
Assertions.assertNotEquals(new LocalMember( Assertions.assertNotEquals(
"mycluster", new LocalMember(
new URI("udp://4.4.4.4:1000"), "mycluster",
"myid", new URI("udp://4.4.4.4:1000"),
1, "myid",
new HashMap<>(), 1,
10, new HashMap<>(),
5, 10,
"exponential") 5,
.hashCode(), new LocalMember( "exponential")
.hashCode(),
new LocalMember(
"mycluster", "mycluster",
new URI("udp://4.4.4.5:1005"), new URI("udp://4.4.4.5:1005"),
"yourid", "yourid",

View File

@ -54,20 +54,24 @@ public class FailureDetectorTest {
} }
Integer lastRecorded = values.get(values.size() - 2); Integer lastRecorded = values.get(values.size() - 2);
//after "step" delay we need to be considered UP // after "step" delay we need to be considered UP
Assertions.assertTrue(fd.computePhiMeasure(values.get(values.size() - 1)) < failureThreshold); Assertions.assertTrue(fd.computePhiMeasure(values.get(values.size() - 1)) < failureThreshold);
//if we check phi-measure after mean delay we get value for 0.5 probability(normal distribution) // if we check phi-measure after mean delay we get value for 0.5 probability(normal
Assertions.assertEquals(fd.computePhiMeasure(lastRecorded + Math.round(deltaSum / deltaCount)), // distribution)
-Math.log10(0.5), Assertions.assertEquals(
0.1); fd.computePhiMeasure(lastRecorded + Math.round(deltaSum / deltaCount)),
-Math.log10(0.5),
0.1);
} }
@Test @Test
public void checkMinimumSamples() { public void checkMinimumSamples() {
int minimumSamples = 5; int minimumSamples = 5;
FailureDetector fd = new FailureDetector(minimumSamples, 1000, "normal"); FailureDetector fd = new FailureDetector(minimumSamples, 1000, "normal");
for (int i = 0; i < minimumSamples + 1; i++) { // +1 because we don't place first heartbeat into structure for (int i = 0;
i < minimumSamples + 1;
i++) { // +1 because we don't place first heartbeat into structure
Assertions.assertNull(fd.computePhiMeasure(100)); Assertions.assertNull(fd.computePhiMeasure(100));
fd.recordHeartbeat(i); fd.recordHeartbeat(i);
} }
@ -77,28 +81,30 @@ public class FailureDetectorTest {
@Test @Test
public void checkMonotonicDead() { public void checkMonotonicDead() {
final FailureDetector fd = new FailureDetector(5, 1000, "normal"); final FailureDetector fd = new FailureDetector(5, 1000, "normal");
TriConsumer<Integer, Integer, Integer> checkAlive = (begin, end, step) -> { TriConsumer<Integer, Integer, Integer> checkAlive =
List<Integer> times = generateTimeList(begin, end, step); (begin, end, step) -> {
for (Integer time : times) { List<Integer> times = generateTimeList(begin, end, step);
for (Integer time : times) {
Double current = fd.computePhiMeasure(time); Double current = fd.computePhiMeasure(time);
if (current != null) { if (current != null) {
Assertions.assertTrue(current < failureThreshold); Assertions.assertTrue(current < failureThreshold);
} }
fd.recordHeartbeat(time); fd.recordHeartbeat(time);
} }
}; };
TriConsumer<Integer, Integer, Integer> checkDeadMonotonic = (begin, end, step) -> { TriConsumer<Integer, Integer, Integer> checkDeadMonotonic =
List<Integer> times = generateTimeList(begin, end, step); (begin, end, step) -> {
Double prev = null; List<Integer> times = generateTimeList(begin, end, step);
for (Integer time : times) { Double prev = null;
for (Integer time : times) {
Double current = fd.computePhiMeasure(time); Double current = fd.computePhiMeasure(time);
if (current != null && prev != null) { if (current != null && prev != null) {
Assertions.assertTrue(current >= prev); Assertions.assertTrue(current >= prev);
} }
prev = current; prev = current;
} }
}; };
checkAlive.accept(0, 20000, 100); checkAlive.accept(0, 20000, 100);
checkDeadMonotonic.accept(20000, 20500, 5); checkDeadMonotonic.accept(20000, 20500, 5);

View File

@ -17,15 +17,14 @@
*/ */
package org.apache.gossip.crdt; package org.apache.gossip.crdt;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/* /*
Abstract test suit to test CrdtSets with Add and Remove operations. Abstract test suit to test CrdtSets with Add and Remove operations.

View File

@ -23,29 +23,29 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class GrowOnlyCounterTest { public class GrowOnlyCounterTest {
@Test @Test
public void mergeTest() { public void mergeTest() {
Map<String, Long> node1Counter = new HashMap<>(); Map<String, Long> node1Counter = new HashMap<>();
node1Counter.put("1", 3L); node1Counter.put("1", 3L);
Map<String, Long> node2Counter = new HashMap<>(); Map<String, Long> node2Counter = new HashMap<>();
node2Counter.put("2", 1L); node2Counter.put("2", 1L);
Map<String, Long> node3Counter = new HashMap<>(); Map<String, Long> node3Counter = new HashMap<>();
node3Counter.put("3", 2L); node3Counter.put("3", 2L);
GrowOnlyCounter gCounter1 = new GrowOnlyCounter(node1Counter); GrowOnlyCounter gCounter1 = new GrowOnlyCounter(node1Counter);
GrowOnlyCounter gCounter2 = new GrowOnlyCounter(node2Counter); GrowOnlyCounter gCounter2 = new GrowOnlyCounter(node2Counter);
GrowOnlyCounter gCounter3 = new GrowOnlyCounter(node3Counter); GrowOnlyCounter gCounter3 = new GrowOnlyCounter(node3Counter);
// After node 2 receive from node 1 // After node 2 receive from node 1
gCounter2 = gCounter2.merge(gCounter1); gCounter2 = gCounter2.merge(gCounter1);
Assert.assertEquals(4, (long) gCounter2.value()); Assert.assertEquals(4, (long) gCounter2.value());
// After node 3 receive from node 1 // After node 3 receive from node 1
gCounter3 = gCounter3.merge(gCounter1); gCounter3 = gCounter3.merge(gCounter1);
Assert.assertEquals(5, (long) gCounter3.value()); Assert.assertEquals(5, (long) gCounter3.value());
// After node 3 receive from node 2 // After node 3 receive from node 2
gCounter3 = gCounter3.merge(gCounter2); gCounter3 = gCounter3.merge(gCounter2);
Assert.assertEquals(6, (long) gCounter3.value()); Assert.assertEquals(6, (long) gCounter3.value());

View File

@ -19,7 +19,6 @@ package org.apache.gossip.crdt;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;

View File

@ -17,15 +17,14 @@
*/ */
package org.apache.gossip.crdt; package org.apache.gossip.crdt;
import org.apache.gossip.manager.Clock;
import org.apache.gossip.manager.SystemClock;
import org.junit.Assert;
import org.junit.Test;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.gossip.manager.Clock;
import org.apache.gossip.manager.SystemClock;
import org.junit.Assert;
import org.junit.Test;
public class LwwSetTest extends AddRemoveStringSetTest<LwwSet<String>> { public class LwwSetTest extends AddRemoveStringSetTest<LwwSet<String>> {
private static Clock clock = new SystemClock(); private static Clock clock = new SystemClock();

View File

@ -25,16 +25,16 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class MaxChangeSetTest extends AddRemoveStringSetTest<MaxChangeSet<String>> { public class MaxChangeSetTest extends AddRemoveStringSetTest<MaxChangeSet<String>> {
MaxChangeSet<String> construct(Set<String> set){ MaxChangeSet<String> construct(Set<String> set) {
return new MaxChangeSet<>(set); return new MaxChangeSet<>(set);
} }
MaxChangeSet<String> construct(){ MaxChangeSet<String> construct() {
return new MaxChangeSet<>(); return new MaxChangeSet<>();
} }
@Test @Test
public void valueTest(){ public void valueTest() {
Map<Character, Integer> struct = new HashMap<>(); Map<Character, Integer> struct = new HashMap<>();
struct.put('a', 0); struct.put('a', 0);
struct.put('b', 1); struct.put('b', 1);
@ -47,7 +47,7 @@ public class MaxChangeSetTest extends AddRemoveStringSetTest<MaxChangeSet<String
} }
@Test @Test
public void mergeTest(){ public void mergeTest() {
MaxChangeSet<Integer> set1 = new MaxChangeSet<Integer>().add(1); // Set with one operation on 1 MaxChangeSet<Integer> set1 = new MaxChangeSet<Integer>().add(1); // Set with one operation on 1
MaxChangeSet<Integer> set2 = new MaxChangeSet<Integer>().add(1).remove(1); // two operations MaxChangeSet<Integer> set2 = new MaxChangeSet<Integer>().add(1).remove(1); // two operations
Assert.assertEquals(set1.merge(set2), new MaxChangeSet<Integer>()); // empty set wins Assert.assertEquals(set1.merge(set2), new MaxChangeSet<Integer>()); // empty set wins

View File

@ -25,22 +25,22 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> { public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> {
OrSet<String> construct(){ OrSet<String> construct() {
return new OrSet<>(); return new OrSet<>();
} }
OrSet<String> construct(Set<String> set){ OrSet<String> construct(Set<String> set) {
return new OrSet<>(set); return new OrSet<>(set);
} }
@Test @Test
public void atest(){ public void atest() {
OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(4).add(5).add(6).remove(5)); OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(4).add(5).add(6).remove(5));
Assert.assertArrayEquals(Arrays.asList(4, 6).toArray(), i.value().toArray()); Assert.assertArrayEquals(Arrays.asList(4, 6).toArray(), i.value().toArray());
} }
@Test @Test
public void mergeTest(){ public void mergeTest() {
OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(4).add(5).add(6).remove(5)); OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(4).add(5).add(6).remove(5));
Assert.assertArrayEquals(Arrays.asList(4, 6).toArray(), i.value().toArray()); Assert.assertArrayEquals(Arrays.asList(4, 6).toArray(), i.value().toArray());
OrSet<Integer> j = new OrSet<>(new OrSet.Builder<Integer>().add(9).add(4).add(5).remove(6)); OrSet<Integer> j = new OrSet<>(new OrSet.Builder<Integer>().add(9).add(4).add(5).remove(6));
@ -49,11 +49,11 @@ public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> {
} }
@Test @Test
public void mergeTest2(){ public void mergeTest2() {
OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(5).add(4).remove(4).add(6)); OrSet<Integer> i = new OrSet<>(new OrSet.Builder<Integer>().add(5).add(4).remove(4).add(6));
Assert.assertEquals(new OrSet<>(5, 6), i); Assert.assertEquals(new OrSet<>(5, 6), i);
SortedSet<Integer> tree = new TreeSet<>(); SortedSet<Integer> tree = new TreeSet<>();
for (Integer in : i.value()){ for (Integer in : i.value()) {
tree.add(in); tree.add(in);
} }
TreeSet<Integer> compare = new TreeSet<>(); TreeSet<Integer> compare = new TreeSet<>();
@ -63,32 +63,32 @@ public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> {
} }
@Test @Test
public void mergeTest4(){ public void mergeTest4() {
Assert.assertArrayEquals(new Integer[]{}, Assert.assertArrayEquals(
new OrSet<>(new OrSet.Builder<Integer>().add(1).remove(1)).toArray()); new Integer[] {}, new OrSet<>(new OrSet.Builder<Integer>().add(1).remove(1)).toArray());
} }
@Test @Test
public void mergeTest3(){ public void mergeTest3() {
OrSet<Integer> i = new OrSet<>(1); OrSet<Integer> i = new OrSet<>(1);
OrSet<Integer> j = new OrSet<>(2); OrSet<Integer> j = new OrSet<>(2);
OrSet<Integer> k = new OrSet<>(i.merge(j), new OrSet.Builder<Integer>().remove(1)); OrSet<Integer> k = new OrSet<>(i.merge(j), new OrSet.Builder<Integer>().remove(1));
Assert.assertArrayEquals(new Integer[]{2}, i.merge(j).merge(k).toArray()); Assert.assertArrayEquals(new Integer[] {2}, i.merge(j).merge(k).toArray());
Assert.assertArrayEquals(new Integer[]{2}, j.merge(i).merge(k).toArray()); Assert.assertArrayEquals(new Integer[] {2}, j.merge(i).merge(k).toArray());
Assert.assertArrayEquals(new Integer[]{2}, k.merge(i).merge(j).toArray()); Assert.assertArrayEquals(new Integer[] {2}, k.merge(i).merge(j).toArray());
Assert.assertArrayEquals(new Integer[]{2}, k.merge(j).merge(i).toArray()); Assert.assertArrayEquals(new Integer[] {2}, k.merge(j).merge(i).toArray());
Assert.assertEquals(j, i.merge(j.merge(k))); Assert.assertEquals(j, i.merge(j.merge(k)));
} }
@Test @Test
public void mergeTest9(){ public void mergeTest9() {
OrSet<Integer> i = new OrSet<>(19); OrSet<Integer> i = new OrSet<>(19);
OrSet<Integer> j = i.merge(i); OrSet<Integer> j = i.merge(i);
Assert.assertEquals(i.value(), j.value()); Assert.assertEquals(i.value(), j.value());
} }
@Test @Test
public void mergeTestSame(){ public void mergeTestSame() {
OrSet<Integer> i = new OrSet<>(19); OrSet<Integer> i = new OrSet<>(19);
OrSet<Integer> j = new OrSet<>(19); OrSet<Integer> j = new OrSet<>(19);
OrSet<Integer> k = i.merge(j); OrSet<Integer> k = i.merge(j);
@ -98,4 +98,4 @@ public class OrSetTest extends AddRemoveStringSetTest<OrSet<String>> {
Assert.assertEquals(2, y.getElements().get(19).size()); Assert.assertEquals(2, y.getElements().get(19).size());
Assert.assertEquals(new OrSet<Integer>().value(), y.value()); Assert.assertEquals(new OrSet<Integer>().value(), y.value());
} }
} }

View File

@ -22,7 +22,6 @@ import static org.mockito.Mockito.when;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.gossip.LocalMember; import org.apache.gossip.LocalMember;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.junit.Assert; import org.junit.Assert;

View File

@ -17,13 +17,12 @@
*/ */
package org.apache.gossip.crdt; package org.apache.gossip.crdt;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TwoPhaseSetTest { public class TwoPhaseSetTest {

View File

@ -18,13 +18,12 @@
package org.apache.gossip.event.data; package org.apache.gossip.event.data;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
public class DataEventManagerTest { public class DataEventManagerTest {
private static Semaphore semaphore; private static Semaphore semaphore;

View File

@ -17,12 +17,11 @@
*/ */
package org.apache.gossip.lock.vote; package org.apache.gossip.lock.vote;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
public class MajorityVoteTest { public class MajorityVoteTest {

View File

@ -18,16 +18,14 @@
package org.apache.gossip.manager; package org.apache.gossip.manager;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import io.teknek.tunit.TUnit;
import java.net.URI; import java.net.URI;
import org.apache.gossip.GossipSettings; import org.apache.gossip.GossipSettings;
import org.apache.gossip.model.PerNodeDataMessage; import org.apache.gossip.model.PerNodeDataMessage;
import org.apache.gossip.model.SharedDataMessage; import org.apache.gossip.model.SharedDataMessage;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import io.teknek.tunit.TUnit;
public class DataReaperTest { public class DataReaperTest {
private final MetricRegistry registry = new MetricRegistry(); private final MetricRegistry registry = new MetricRegistry();

View File

@ -22,7 +22,6 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.gossip.GossipSettings; import org.apache.gossip.GossipSettings;
import org.apache.gossip.model.PerNodeDataMessage; import org.apache.gossip.model.PerNodeDataMessage;
import org.apache.gossip.model.SharedDataMessage; import org.apache.gossip.model.SharedDataMessage;

View File

@ -28,7 +28,8 @@ import org.junit.Test;
public class MessageHandlerTest { public class MessageHandlerTest {
@Test @Test
public void testSimpleHandler() { public void testSimpleHandler() {
MessageHandler mi = new TypedMessageHandlerWrapper(FakeMessage.class, new DummyMessageHandler()); MessageHandler mi =
new TypedMessageHandlerWrapper(FakeMessage.class, new DummyMessageHandler());
Assert.assertTrue(mi.invoke(null, null, new FakeMessage())); Assert.assertTrue(mi.invoke(null, null, new FakeMessage()));
Assert.assertFalse(mi.invoke(null, null, new ActiveGossipMessage())); Assert.assertFalse(mi.invoke(null, null, new ActiveGossipMessage()));
} }
@ -72,7 +73,8 @@ public class MessageHandlerTest {
@Test @Test
public void testMessageHandlerCombiner() { public void testMessageHandlerCombiner() {
// Empty combiner - false result // Empty combiner - false result
MessageHandler mi = MessageHandlerFactory.concurrentHandler((gossipCore, gossipManager, base) -> false); MessageHandler mi =
MessageHandlerFactory.concurrentHandler((gossipCore, gossipManager, base) -> false);
Assert.assertFalse(mi.invoke(null, null, new Base())); Assert.assertFalse(mi.invoke(null, null, new Base()));
DummyMessageHandler h = new DummyMessageHandler(); DummyMessageHandler h = new DummyMessageHandler();
@ -86,7 +88,9 @@ public class MessageHandlerTest {
Assert.assertEquals(2, h.counter); Assert.assertEquals(2, h.counter);
// Increase size in runtime. Should be 3 calls: 2+3 = 5 // Increase size in runtime. Should be 3 calls: 2+3 = 5
mi = MessageHandlerFactory.concurrentHandler(mi, new TypedMessageHandlerWrapper(FakeMessage.class, h)); mi =
MessageHandlerFactory.concurrentHandler(
mi, new TypedMessageHandlerWrapper(FakeMessage.class, h));
Assert.assertTrue(mi.invoke(null, null, new FakeMessage())); Assert.assertTrue(mi.invoke(null, null, new FakeMessage()));
Assert.assertEquals(5, h.counter); Assert.assertEquals(5, h.counter);
} }

View File

@ -29,21 +29,23 @@ import org.apache.gossip.model.Base;
// doesn't serialize anything besides longs. Uses a static lookup table to read and write objects. // doesn't serialize anything besides longs. Uses a static lookup table to read and write objects.
public class UnitTestProtocolManager implements ProtocolManager { public class UnitTestProtocolManager implements ProtocolManager {
// so it can be shared across gossipers. this works as long as each object has a different memory address. // so it can be shared across gossipers. this works as long as each object has a different memory
// address.
private static final Map<Long, Base> lookup = new ConcurrentHashMap<>(); private static final Map<Long, Base> lookup = new ConcurrentHashMap<>();
private final Meter meter; private final Meter meter;
public UnitTestProtocolManager(GossipSettings settings, String id, MetricRegistry registry) { public UnitTestProtocolManager(GossipSettings settings, String id, MetricRegistry registry) {
meter = settings.isSignMessages() ? meter =
registry.meter(PassiveGossipConstants.SIGNED_MESSAGE) : settings.isSignMessages()
registry.meter(PassiveGossipConstants.UNSIGNED_MESSAGE); ? registry.meter(PassiveGossipConstants.SIGNED_MESSAGE)
: registry.meter(PassiveGossipConstants.UNSIGNED_MESSAGE);
} }
private static byte[] longToBytes(long val) { private static byte[] longToBytes(long val) {
byte[] b = new byte[8]; byte[] b = new byte[8];
b[7] = (byte) (val); b[7] = (byte) (val);
b[6] = (byte) (val >>> 8); b[6] = (byte) (val >>> 8);
b[5] = (byte) (val >>> 16); b[5] = (byte) (val >>> 16);
b[4] = (byte) (val >>> 24); b[4] = (byte) (val >>> 24);
b[3] = (byte) (val >>> 32); b[3] = (byte) (val >>> 32);
@ -54,16 +56,16 @@ public class UnitTestProtocolManager implements ProtocolManager {
} }
static long bytesToLong(byte[] b) { static long bytesToLong(byte[] b) {
return ((b[7] & 0xFFL)) + return ((b[7] & 0xFFL))
((b[6] & 0xFFL) << 8) + + ((b[6] & 0xFFL) << 8)
((b[5] & 0xFFL) << 16) + + ((b[5] & 0xFFL) << 16)
((b[4] & 0xFFL) << 24) + + ((b[4] & 0xFFL) << 24)
((b[3] & 0xFFL) << 32) + + ((b[3] & 0xFFL) << 32)
((b[2] & 0xFFL) << 40) + + ((b[2] & 0xFFL) << 40)
((b[1] & 0xFFL) << 48) + + ((b[1] & 0xFFL) << 48)
(((long) b[0]) << 56); + (((long) b[0]) << 56);
} }
@Override @Override
public byte[] write(Base message) throws IOException { public byte[] write(Base message) throws IOException {
long hashCode = System.identityHashCode(message); long hashCode = System.identityHashCode(message);

View File

@ -30,9 +30,9 @@ import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class DataReplicationTest { public class DataReplicationTest {
private static SharedDataMessage getSharedNodeData(String key, String value, private static SharedDataMessage getSharedNodeData(
Replicable<SharedDataMessage> replicable) { String key, String value, Replicable<SharedDataMessage> replicable) {
SharedDataMessage g = new SharedDataMessage(); SharedDataMessage g = new SharedDataMessage();
g.setExpireAt(Long.MAX_VALUE); g.setExpireAt(Long.MAX_VALUE);
g.setKey(key); g.setKey(key);
@ -41,114 +41,118 @@ public class DataReplicationTest {
g.setReplicable(replicable); g.setReplicable(replicable);
return g; return g;
} }
private static LocalMember getLocalMember(URI uri, String id){ private static LocalMember getLocalMember(URI uri, String id) {
return new LocalMember("cluster1", uri, id, 0, null, 1, 0, ""); return new LocalMember("cluster1", uri, id, 0, null, 1, 0, "");
} }
private static LocalMember getLocalMemberDc(URI uri, String id, String dataCenter, String rack){ private static LocalMember getLocalMemberDc(URI uri, String id, String dataCenter, String rack) {
Map<String, String> props = new HashMap<>(); Map<String, String> props = new HashMap<>();
props.put(DatacenterRackAwareActiveGossiper.DATACENTER, dataCenter); props.put(DatacenterRackAwareActiveGossiper.DATACENTER, dataCenter);
props.put(DatacenterRackAwareActiveGossiper.RACK, rack); props.put(DatacenterRackAwareActiveGossiper.RACK, rack);
return new LocalMember("cluster1", uri, id, 0, props, 1, 0, ""); return new LocalMember("cluster1", uri, id, 0, props, 1, 0, "");
} }
@Test @Test
public void dataReplicateAllTest() throws URISyntaxException { public void dataReplicateAllTest() throws URISyntaxException {
SharedDataMessage message = getSharedNodeData("public","public", new AllReplicable<>()); SharedDataMessage message = getSharedNodeData("public", "public", new AllReplicable<>());
LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8001"),"1"); LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8001"), "1");
LocalMember member = getLocalMember(new URI("udp://127.0.0.1:8002"),"2"); LocalMember member = getLocalMember(new URI("udp://127.0.0.1:8002"), "2");
Assert.assertEquals(true, message.getReplicable().shouldReplicate(me, member, message)); Assert.assertEquals(true, message.getReplicable().shouldReplicate(me, member, message));
} }
@Test @Test
public void dataReplicateNoneTest() throws URISyntaxException { public void dataReplicateNoneTest() throws URISyntaxException {
SharedDataMessage message = getSharedNodeData("private","private", new NotReplicable<>()); SharedDataMessage message = getSharedNodeData("private", "private", new NotReplicable<>());
LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8001"),"1"); LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8001"), "1");
LocalMember member = getLocalMember(new URI("udp://127.0.0.1:8002"),"2"); LocalMember member = getLocalMember(new URI("udp://127.0.0.1:8002"), "2");
Assert.assertEquals(false, message.getReplicable().shouldReplicate(me, member, message)); Assert.assertEquals(false, message.getReplicable().shouldReplicate(me, member, message));
} }
@Test @Test
public void dataReplicateWhiteListTest() throws URISyntaxException { public void dataReplicateWhiteListTest() throws URISyntaxException {
List<LocalMember> memberList = new ArrayList<>(); List<LocalMember> memberList = new ArrayList<>();
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"),"1")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"), "1"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"),"2")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"), "2"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8003"),"3")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8003"), "3"));
// add node 1 and 2 to the white list // add node 1 and 2 to the white list
List<LocalMember> whiteList = new ArrayList<>(); List<LocalMember> whiteList = new ArrayList<>();
whiteList.add(memberList.get(0)); whiteList.add(memberList.get(0));
whiteList.add(memberList.get(1)); whiteList.add(memberList.get(1));
SharedDataMessage message = getSharedNodeData("whiteList", "Only allow some nodes", SharedDataMessage message =
new WhiteListReplicable<>(whiteList)); getSharedNodeData(
LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8004"),"4"); "whiteList", "Only allow some nodes", new WhiteListReplicable<>(whiteList));
LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8004"), "4");
// data should replicate to node 1 and 2 but not 3 // data should replicate to node 1 and 2 but not 3
Assert.assertEquals(true, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(0), message)); true, message.getReplicable().shouldReplicate(me, memberList.get(0), message));
Assert.assertEquals(true, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(1), message)); true, message.getReplicable().shouldReplicate(me, memberList.get(1), message));
Assert.assertEquals(false, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(2), message)); false, message.getReplicable().shouldReplicate(me, memberList.get(2), message));
} }
@Test @Test
public void dataReplicateWhiteListNullTest() throws URISyntaxException { public void dataReplicateWhiteListNullTest() throws URISyntaxException {
List<LocalMember> memberList = new ArrayList<>(); List<LocalMember> memberList = new ArrayList<>();
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"),"1")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"), "1"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"),"2")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"), "2"));
SharedDataMessage message = getSharedNodeData("whiteList", "Only allow some nodes", SharedDataMessage message =
new WhiteListReplicable<>(null)); getSharedNodeData("whiteList", "Only allow some nodes", new WhiteListReplicable<>(null));
// data should not replicate if no whitelist specified // data should not replicate if no whitelist specified
Assert.assertEquals(false, Assert.assertEquals(
message.getReplicable().shouldReplicate(memberList.get(0), memberList.get(1), message)); false,
Assert.assertEquals(false, message.getReplicable().shouldReplicate(memberList.get(0), memberList.get(1), message));
message.getReplicable().shouldReplicate(memberList.get(1), memberList.get(0), message)); Assert.assertEquals(
false,
message.getReplicable().shouldReplicate(memberList.get(1), memberList.get(0), message));
} }
@Test @Test
public void dataReplicateBlackListTest() throws URISyntaxException { public void dataReplicateBlackListTest() throws URISyntaxException {
List<LocalMember> memberList = new ArrayList<>(); List<LocalMember> memberList = new ArrayList<>();
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"),"1")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"), "1"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"),"2")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"), "2"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8003"),"3")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8003"), "3"));
// add node 1 and 2 to the black list // add node 1 and 2 to the black list
List<LocalMember> blackList = new ArrayList<>(); List<LocalMember> blackList = new ArrayList<>();
blackList.add(memberList.get(0)); blackList.add(memberList.get(0));
blackList.add(memberList.get(1)); blackList.add(memberList.get(1));
SharedDataMessage message = getSharedNodeData("blackList", "Disallow some nodes", SharedDataMessage message =
new BlackListReplicable<>(blackList)); getSharedNodeData("blackList", "Disallow some nodes", new BlackListReplicable<>(blackList));
LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8004"),"4"); LocalMember me = getLocalMember(new URI("udp://127.0.0.1:8004"), "4");
// data should not replicate to node 1 and 2 // data should not replicate to node 1 and 2
Assert.assertEquals(false, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(0), message)); false, message.getReplicable().shouldReplicate(me, memberList.get(0), message));
Assert.assertEquals(false, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(1), message)); false, message.getReplicable().shouldReplicate(me, memberList.get(1), message));
Assert.assertEquals(true, Assert.assertEquals(
message.getReplicable().shouldReplicate(me, memberList.get(2), message)); true, message.getReplicable().shouldReplicate(me, memberList.get(2), message));
} }
@Test @Test
public void dataReplicateBlackListNullTest() throws URISyntaxException { public void dataReplicateBlackListNullTest() throws URISyntaxException {
List<LocalMember> memberList = new ArrayList<>(); List<LocalMember> memberList = new ArrayList<>();
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"),"1")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8001"), "1"));
memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"),"2")); memberList.add(getLocalMember(new URI("udp://127.0.0.1:8002"), "2"));
SharedDataMessage message = getSharedNodeData("blackList", "Disallow some nodes", SharedDataMessage message =
new BlackListReplicable<>(null)); getSharedNodeData("blackList", "Disallow some nodes", new BlackListReplicable<>(null));
// data should replicate if no blacklist specified // data should replicate if no blacklist specified
Assert.assertEquals(true, Assert.assertEquals(
message.getReplicable().shouldReplicate(memberList.get(0), memberList.get(1), message)); true,
Assert.assertEquals(true, message.getReplicable().shouldReplicate(memberList.get(0), memberList.get(1), message));
message.getReplicable().shouldReplicate(memberList.get(1), memberList.get(0), message)); Assert.assertEquals(
true,
message.getReplicable().shouldReplicate(memberList.get(1), memberList.get(0), message));
} }
@Test @Test
@ -157,28 +161,41 @@ public class DataReplicationTest {
List<LocalMember> memberListDc1 = new ArrayList<>(); List<LocalMember> memberListDc1 = new ArrayList<>();
List<LocalMember> memberListDc2 = new ArrayList<>(); List<LocalMember> memberListDc2 = new ArrayList<>();
memberListDc1 memberListDc1.add(
.add(getLocalMemberDc(new URI("udp://10.0.0.1:8000"), "1", "DataCenter1", "Rack1")); getLocalMemberDc(new URI("udp://10.0.0.1:8000"), "1", "DataCenter1", "Rack1"));
memberListDc1 memberListDc1.add(
.add(getLocalMemberDc(new URI("udp://10.0.0.2:8000"), "2", "DataCenter1", "Rack2")); getLocalMemberDc(new URI("udp://10.0.0.2:8000"), "2", "DataCenter1", "Rack2"));
memberListDc2 memberListDc2.add(
.add(getLocalMemberDc(new URI("udp://10.0.1.1:8000"), "11", "DataCenter2", "Rack1")); getLocalMemberDc(new URI("udp://10.0.1.1:8000"), "11", "DataCenter2", "Rack1"));
memberListDc2 memberListDc2.add(
.add(getLocalMemberDc(new URI("udp://10.0.1.2:8000"), "12", "DataCenter2", "Rack2")); getLocalMemberDc(new URI("udp://10.0.1.2:8000"), "12", "DataCenter2", "Rack2"));
SharedDataMessage message = getSharedNodeData("datacenter1", "I am in data center 1 rack 1", SharedDataMessage message =
new DataCenterReplicable<>()); getSharedNodeData(
"datacenter1", "I am in data center 1 rack 1", new DataCenterReplicable<>());
// data should replicate in data center 1 // data should replicate in data center 1
Assert.assertEquals(true, message.getReplicable() Assert.assertEquals(
true,
message
.getReplicable()
.shouldReplicate(memberListDc1.get(0), memberListDc1.get(1), message)); .shouldReplicate(memberListDc1.get(0), memberListDc1.get(1), message));
Assert.assertEquals(true, message.getReplicable() Assert.assertEquals(
true,
message
.getReplicable()
.shouldReplicate(memberListDc2.get(0), memberListDc2.get(1), message)); .shouldReplicate(memberListDc2.get(0), memberListDc2.get(1), message));
// data should not replicate to data center 2 // data should not replicate to data center 2
Assert.assertEquals(false, message.getReplicable() Assert.assertEquals(
false,
message
.getReplicable()
.shouldReplicate(memberListDc1.get(0), memberListDc2.get(0), message)); .shouldReplicate(memberListDc1.get(0), memberListDc2.get(0), message));
Assert.assertEquals(false, message.getReplicable() Assert.assertEquals(
false,
message
.getReplicable()
.shouldReplicate(memberListDc1.get(1), memberListDc2.get(1), message)); .shouldReplicate(memberListDc1.get(1), memberListDc2.get(1), message));
} }
@ -186,21 +203,22 @@ public class DataReplicationTest {
public void dataReplicateDataCenterUnknownDataCenterTest() throws URISyntaxException { public void dataReplicateDataCenterUnknownDataCenterTest() throws URISyntaxException {
List<LocalMember> memberListDc1 = new ArrayList<>(); List<LocalMember> memberListDc1 = new ArrayList<>();
memberListDc1 memberListDc1.add(
.add(getLocalMemberDc(new URI("udp://10.0.0.1:8000"), "1", "DataCenter1", "Rack1")); getLocalMemberDc(new URI("udp://10.0.0.1:8000"), "1", "DataCenter1", "Rack1"));
Map<String, String> properties = new HashMap<>(); Map<String, String> properties = new HashMap<>();
LocalMember unknownDc = new LocalMember("cluster1", new URI("udp://10.0.1.2:8000"), "12", 0, LocalMember unknownDc =
properties, 1, 0, ""); new LocalMember("cluster1", new URI("udp://10.0.1.2:8000"), "12", 0, properties, 1, 0, "");
SharedDataMessage message = getSharedNodeData("datacenter1","I am in data center 1 rack 1", new DataCenterReplicable<>()); SharedDataMessage message =
getSharedNodeData(
"datacenter1", "I am in data center 1 rack 1", new DataCenterReplicable<>());
// data should not replicate from dc1 to unknown node // data should not replicate from dc1 to unknown node
Assert.assertEquals(false, message.getReplicable() Assert.assertEquals(
.shouldReplicate(memberListDc1.get(0), unknownDc, message)); false, message.getReplicable().shouldReplicate(memberListDc1.get(0), unknownDc, message));
// data can replicate from unknown node to dc // data can replicate from unknown node to dc
Assert.assertEquals(true, message.getReplicable() Assert.assertEquals(
.shouldReplicate(unknownDc, memberListDc1.get(0), message)); true, message.getReplicable().shouldReplicate(unknownDc, memberListDc1.get(0), message));
} }
} }

View File

@ -18,15 +18,14 @@
package org.apache.gossip.transport; package org.apache.gossip.transport;
import org.apache.gossip.manager.GossipCore;
import org.apache.gossip.manager.GossipManager;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.gossip.manager.GossipCore;
import org.apache.gossip.manager.GossipManager;
/** Only use in unit tests! */ /** Only use in unit tests! */
public class UnitTestTransportManager extends AbstractTransportManager { public class UnitTestTransportManager extends AbstractTransportManager {

View File

@ -21,10 +21,6 @@ import java.io.IOException;
public class RunStandardExamples { public class RunStandardExamples {
private static boolean WILL_READ = true;
private static boolean WILL_NOT_READ = false;
public static void main(String[] args) { public static void main(String[] args) {
if ((args.length < 1) || args[0].equals("-h") || args[0].equals("--help") || args.length < 2) { if ((args.length < 1) || args[0].equals("-h") || args[0].equals("--help") || args.length < 2) {
System.out.print(usage()); System.out.print(usage());
@ -37,16 +33,18 @@ public class RunStandardExamples {
System.out.print(usage()); System.out.print(usage());
return; return;
} }
runExaple(example, channel); runExample(example, channel);
} catch (Exception e) { } catch (Exception e) {
System.out.print(usage()); System.out.print(usage());
} }
} }
private static void runExaple(int exampleNumber, int channel) throws IOException { private static void runExample(int exampleNumber, int channel) throws IOException {
String[] args = stanardArgs(channel, new String[4]); String[] args = standardArgs(channel, new String[4]);
boolean WILL_READ = true;
if (exampleNumber == 1) { if (exampleNumber == 1) {
StandAloneNode example = new StandAloneNode(args); StandAloneNode example = new StandAloneNode(args);
boolean WILL_NOT_READ = false;
example.exec(WILL_NOT_READ); example.exec(WILL_NOT_READ);
} else if (exampleNumber == 2) { } else if (exampleNumber == 2) {
StandAloneNodeCrdtOrSet example = new StandAloneNodeCrdtOrSet(args); StandAloneNodeCrdtOrSet example = new StandAloneNodeCrdtOrSet(args);
@ -61,7 +59,7 @@ public class RunStandardExamples {
} }
} }
private static String[] stanardArgs(int channel, String[] args) { private static String[] standardArgs(int channel, String[] args) {
// see README.md for examples // see README.md for examples
args[0] = "udp://localhost:1000" + channel; args[0] = "udp://localhost:1000" + channel;
args[1] = "" + channel; args[1] = "" + channel;
@ -71,7 +69,7 @@ public class RunStandardExamples {
} }
private static String[] extendedArgs(int channel, String[] args) { private static String[] extendedArgs(int channel, String[] args) {
args = stanardArgs(channel, args); standardArgs(channel, args);
// see README.md for examples // see README.md for examples
if (channel == 0) { if (channel == 0) {
args[4] = "1"; args[4] = "1";

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.gossip.GossipSettings; import org.apache.gossip.GossipSettings;
@ -37,7 +38,7 @@ public class StandAloneDatacenterAndRack extends StandAloneExampleBase {
initGossipManager(args); initGossipManager(args);
} }
public static void main(String[] args) throws InterruptedException, IOException { public static void main(String[] args) throws IOException {
StandAloneDatacenterAndRack example = new StandAloneDatacenterAndRack(args); StandAloneDatacenterAndRack example = new StandAloneDatacenterAndRack(args);
boolean willRead = true; boolean willRead = true;
example.exec(willRead); example.exec(willRead);
@ -61,8 +62,7 @@ public class StandAloneDatacenterAndRack extends StandAloneExampleBase {
.uri(URI.create(args[0])) .uri(URI.create(args[0]))
.id(args[1]) .id(args[1])
.gossipSettings(s) .gossipSettings(s)
.gossipMembers( .gossipMembers(List.of(new RemoteMember("mycluster", URI.create(args[2]), args[3])))
Arrays.asList(new RemoteMember("mycluster", URI.create(args[2]), args[3])))
.properties(props) .properties(props)
.build(); .build();
manager.init(); manager.init();

View File

@ -23,7 +23,6 @@ import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.apache.gossip.GossipSettings; import org.apache.gossip.GossipSettings;
import org.apache.gossip.LocalMember; import org.apache.gossip.LocalMember;
import org.apache.gossip.RemoteMember; import org.apache.gossip.RemoteMember;

View File

@ -22,20 +22,17 @@ import org.apache.gossip.manager.GossipManager;
public class StandAloneNode extends StandAloneExampleBase { public class StandAloneNode extends StandAloneExampleBase {
private static boolean WILL_READ = false;
StandAloneNode(String[] args) { StandAloneNode(String[] args) {
args = super.checkArgsForClearFlag(args); args = super.checkArgsForClearFlag(args);
super.initGossipManager(args); super.initGossipManager(args);
} }
public static void main(String[] args) throws InterruptedException, IOException { public static void main(String[] args) throws IOException {
StandAloneNode example = new StandAloneNode(args); StandAloneNode example = new StandAloneNode(args);
boolean WILL_READ = false;
example.exec(WILL_READ); example.exec(WILL_READ);
} }
@Override @Override
void printValues(GossipManager gossipService) { void printValues(GossipManager gossipService) {}
}
} }

View File

@ -18,7 +18,6 @@
package org.apache.gossip.examples; package org.apache.gossip.examples;
import java.io.IOException; import java.io.IOException;
import org.apache.gossip.crdt.GrowOnlyCounter; import org.apache.gossip.crdt.GrowOnlyCounter;
import org.apache.gossip.crdt.OrSet; import org.apache.gossip.crdt.OrSet;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
@ -35,7 +34,7 @@ public class StandAloneNodeCrdtOrSet extends StandAloneExampleBase {
super.initGossipManager(args); super.initGossipManager(args);
} }
public static void main(String[] args) throws InterruptedException, IOException { public static void main(String[] args) throws IOException {
StandAloneNodeCrdtOrSet example = new StandAloneNodeCrdtOrSet(args); StandAloneNodeCrdtOrSet example = new StandAloneNodeCrdtOrSet(args);
boolean willRead = true; boolean willRead = true;
example.exec(willRead); example.exec(willRead);
@ -53,7 +52,7 @@ public class StandAloneNodeCrdtOrSet extends StandAloneExampleBase {
private static void gcount(String val, GossipManager gossipManager) { private static void gcount(String val, GossipManager gossipManager) {
GrowOnlyCounter c = (GrowOnlyCounter) gossipManager.findCrdt(INDEX_KEY_FOR_COUNTER); GrowOnlyCounter c = (GrowOnlyCounter) gossipManager.findCrdt(INDEX_KEY_FOR_COUNTER);
Long l = Long.valueOf(val); long l = Long.parseLong(val);
if (c == null) { if (c == null) {
c = new GrowOnlyCounter(new GrowOnlyCounter.Builder(gossipManager).increment((l))); c = new GrowOnlyCounter(new GrowOnlyCounter.Builder(gossipManager).increment((l)));
} else { } else {
@ -73,7 +72,7 @@ public class StandAloneNodeCrdtOrSet extends StandAloneExampleBase {
SharedDataMessage m = new SharedDataMessage(); SharedDataMessage m = new SharedDataMessage();
m.setExpireAt(Long.MAX_VALUE); m.setExpireAt(Long.MAX_VALUE);
m.setKey(INDEX_KEY_FOR_SET); m.setKey(INDEX_KEY_FOR_SET);
m.setPayload(new OrSet<String>(s, new OrSet.Builder<String>().remove(val))); m.setPayload(new OrSet<>(s, new OrSet.Builder<String>().remove(val)));
m.setTimestamp(System.currentTimeMillis()); m.setTimestamp(System.currentTimeMillis());
gossipService.merge(m); gossipService.merge(m);
} }
@ -82,7 +81,7 @@ public class StandAloneNodeCrdtOrSet extends StandAloneExampleBase {
SharedDataMessage m = new SharedDataMessage(); SharedDataMessage m = new SharedDataMessage();
m.setExpireAt(Long.MAX_VALUE); m.setExpireAt(Long.MAX_VALUE);
m.setKey(INDEX_KEY_FOR_SET); m.setKey(INDEX_KEY_FOR_SET);
m.setPayload(new OrSet<String>(val)); m.setPayload(new OrSet<>(val));
m.setTimestamp(System.currentTimeMillis()); m.setTimestamp(System.currentTimeMillis());
gossipService.merge(m); gossipService.merge(m);
} }
@ -118,7 +117,7 @@ public class StandAloneNodeCrdtOrSet extends StandAloneExampleBase {
valid = false; valid = false;
} }
} else if (op == 'l') { } else if (op == 'l') {
if ((val == INDEX_KEY_FOR_SET) || (val == INDEX_KEY_FOR_COUNTER)) { if ((val.equals(INDEX_KEY_FOR_SET)) || (val.equals(INDEX_KEY_FOR_COUNTER))) {
listen(val, getGossipManager()); listen(val, getGossipManager());
} else { } else {
valid = false; valid = false;

View File

@ -18,7 +18,6 @@
package org.apache.gossip.examples; package org.apache.gossip.examples;
import java.io.IOException; import java.io.IOException;
import org.apache.gossip.crdt.PNCounter; import org.apache.gossip.crdt.PNCounter;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.model.SharedDataMessage; import org.apache.gossip.model.SharedDataMessage;
@ -30,7 +29,7 @@ public class StandAlonePNCounter extends StandAloneExampleBase {
super.initGossipManager(args); super.initGossipManager(args);
} }
public static void main(String[] args) throws InterruptedException, IOException { public static void main(String[] args) throws IOException {
StandAlonePNCounter example = new StandAlonePNCounter(args); StandAlonePNCounter example = new StandAlonePNCounter(args);
boolean willRead = true; boolean willRead = true;
example.exec(willRead); example.exec(willRead);
@ -61,7 +60,7 @@ public class StandAlonePNCounter extends StandAloneExampleBase {
if (valid) { if (valid) {
if (op == 'i') { if (op == 'i') {
increment(l, getGossipManager()); increment(l, getGossipManager());
} else if (op == 'd') { } else {
decrement(l, getGossipManager()); decrement(l, getGossipManager());
} }
} }

View File

@ -52,7 +52,8 @@ public class DataTest {
private final String pnCounterKey = "crdtpn"; private final String pnCounterKey = "crdtpn";
@BeforeClass @BeforeClass
public static void initializeMembers() throws InterruptedException, UnknownHostException, URISyntaxException{ public static void initializeMembers()
throws InterruptedException, UnknownHostException, URISyntaxException {
final int clusterMembers = 2; final int clusterMembers = 2;
GossipSettings settings = new GossipSettings(); GossipSettings settings = new GossipSettings();
@ -60,107 +61,122 @@ public class DataTest {
settings.setPersistDataState(false); settings.setPersistDataState(false);
String cluster = UUID.randomUUID().toString(); String cluster = UUID.randomUUID().toString();
List<Member> startupMembers = new ArrayList<>(); List<Member> startupMembers = new ArrayList<>();
for (int i = 0; i < clusterMembers; ++i){ for (int i = 0; i < clusterMembers; ++i) {
int id = i + 1; int id = i + 1;
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + id)); URI uri = new URI("udp://" + "127.0.0.1" + ":" + (50000 + id));
startupMembers.add(new RemoteMember(cluster, uri, id + "")); startupMembers.add(new RemoteMember(cluster, uri, id + ""));
} }
for (Member member : startupMembers){ for (Member member : startupMembers) {
GossipManager gossipService = GossipManagerBuilder.newBuilder().cluster(cluster).uri(member.getUri()) GossipManager gossipService =
.id(member.getId()).gossipMembers(startupMembers).gossipSettings(settings).build(); GossipManagerBuilder.newBuilder()
.cluster(cluster)
.uri(member.getUri())
.id(member.getId())
.gossipMembers(startupMembers)
.gossipSettings(settings)
.build();
clients.add(gossipService); clients.add(gossipService);
gossipService.init(); gossipService.init();
} }
} }
@AfterClass @AfterClass
public static void shutdownMembers(){ public static void shutdownMembers() {
for (final GossipManager client : clients){ for (final GossipManager client : clients) {
client.shutdown(); client.shutdown();
} }
} }
@Test @Test
public void simpleDataTest(){ public void simpleDataTest() {
TUnit.assertThat(() -> { TUnit.assertThat(
int total = 0; () -> {
for (GossipManager client : clients){ int total = 0;
total += client.getLiveMembers().size(); for (GossipManager client : clients) {
} total += client.getLiveMembers().size();
return total; }
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(2); return total;
})
.afterWaitingAtMost(10, TimeUnit.SECONDS)
.isEqualTo(2);
clients.get(0).gossipPerNodeData(generatePerNodeMsg("a", "b")); clients.get(0).gossipPerNodeData(generatePerNodeMsg("a", "b"));
clients.get(0).gossipSharedData(generateSharedMsg("a", "c")); clients.get(0).gossipSharedData(generateSharedMsg("a", "c"));
TUnit.assertThat(() -> { TUnit.assertThat(
PerNodeDataMessage x = clients.get(1).findPerNodeGossipData(1 + "", "a"); () -> {
if (x == null) PerNodeDataMessage x = clients.get(1).findPerNodeGossipData(1 + "", "a");
return ""; if (x == null) return "";
else else return x.getPayload();
return x.getPayload(); })
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo("b"); .afterWaitingAtMost(10, TimeUnit.SECONDS)
.isEqualTo("b");
TUnit.assertThat(() -> { TUnit.assertThat(
SharedDataMessage x = clients.get(1).findSharedGossipData("a"); () -> {
if (x == null) SharedDataMessage x = clients.get(1).findSharedGossipData("a");
return ""; if (x == null) return "";
else else return x.getPayload();
return x.getPayload(); })
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo("c"); .afterWaitingAtMost(10, TimeUnit.SECONDS)
.isEqualTo("c");
} }
Set<String> setFromList(String... elements){ Set<String> setFromList(String... elements) {
return new HashSet<>(Arrays.asList(elements)); return new HashSet<>(Arrays.asList(elements));
} }
void crdtSetTest(String key, Function<Set<String>, CrdtAddRemoveSet<String, Set<String>, ?>> construct){ void crdtSetTest(
//populate String key, Function<Set<String>, CrdtAddRemoveSet<String, Set<String>, ?>> construct) {
// populate
clients.get(0).merge(generateSharedMsg(key, construct.apply(setFromList("1", "2")))); clients.get(0).merge(generateSharedMsg(key, construct.apply(setFromList("1", "2"))));
clients.get(1).merge(generateSharedMsg(key, construct.apply(setFromList("3", "4")))); clients.get(1).merge(generateSharedMsg(key, construct.apply(setFromList("3", "4"))));
assertMergedCrdt(key, construct.apply(setFromList("1", "2", "3", "4")).value()); assertMergedCrdt(key, construct.apply(setFromList("1", "2", "3", "4")).value());
//drop element // drop element
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
CrdtAddRemoveSet<String, ?, ?> set = (CrdtAddRemoveSet<String, ?, ?>) clients.get(0).findCrdt(key); CrdtAddRemoveSet<String, ?, ?> set =
(CrdtAddRemoveSet<String, ?, ?>) clients.get(0).findCrdt(key);
clients.get(0).merge(generateSharedMsg(key, set.remove("3"))); clients.get(0).merge(generateSharedMsg(key, set.remove("3")));
//assert deletion // assert deletion
assertMergedCrdt(key, construct.apply(setFromList("1", "2", "4")).value()); assertMergedCrdt(key, construct.apply(setFromList("1", "2", "4")).value());
} }
@Test @Test
public void OrSetTest(){ public void OrSetTest() {
crdtSetTest("cror", OrSet::new); crdtSetTest("cror", OrSet::new);
} }
@Test @Test
public void LWWSetTest(){ public void LWWSetTest() {
crdtSetTest("crlww", LwwSet::new); crdtSetTest("crlww", LwwSet::new);
} }
@Test @Test
public void MaxChangeSetTest(){ public void MaxChangeSetTest() {
crdtSetTest("crmcs", MaxChangeSet::new); crdtSetTest("crmcs", MaxChangeSet::new);
} }
@Test @Test
public void TwoPhaseSetTest(){ public void TwoPhaseSetTest() {
crdtSetTest("crtps", TwoPhaseSet::new); crdtSetTest("crtps", TwoPhaseSet::new);
} }
@Test @Test
public void GrowOnlyCounterTest(){ public void GrowOnlyCounterTest() {
Consumer<Long> assertCountUpdated = count -> { Consumer<Long> assertCountUpdated =
for (GossipManager client : clients){ count -> {
TUnit.assertThat(() -> client.findCrdt(gCounterKey)) for (GossipManager client : clients) {
.afterWaitingAtMost(10, TimeUnit.SECONDS) TUnit.assertThat(() -> client.findCrdt(gCounterKey))
.isEqualTo(new GrowOnlyCounter(new GrowOnlyCounter.Builder(client).increment(count))); .afterWaitingAtMost(10, TimeUnit.SECONDS)
} .isEqualTo(
}; new GrowOnlyCounter(new GrowOnlyCounter.Builder(client).increment(count)));
//generate different increment }
};
// generate different increment
Object payload = new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L)); Object payload = new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L));
clients.get(0).merge(generateSharedMsg(gCounterKey, payload)); clients.get(0).merge(generateSharedMsg(gCounterKey, payload));
payload = new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(1)).increment(2L)); payload = new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(1)).increment(2L));
@ -168,30 +184,39 @@ public class DataTest {
assertCountUpdated.accept((long) 3); assertCountUpdated.accept((long) 3);
//update one // update one
GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(1).findCrdt(gCounterKey); GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(1).findCrdt(gCounterKey);
GrowOnlyCounter gc2 = new GrowOnlyCounter(gc, GrowOnlyCounter gc2 =
new GrowOnlyCounter.Builder(clients.get(1)).increment(4L)); new GrowOnlyCounter(gc, new GrowOnlyCounter.Builder(clients.get(1)).increment(4L));
clients.get(1).merge(generateSharedMsg(gCounterKey, gc2)); clients.get(1).merge(generateSharedMsg(gCounterKey, gc2));
assertCountUpdated.accept((long) 7); assertCountUpdated.accept((long) 7);
} }
@Test @Test
public void PNCounterTest(){ public void PNCounterTest() {
Consumer<List<Integer>> counterUpdate = list -> { Consumer<List<Integer>> counterUpdate =
int clientIndex = 0; list -> {
for (int delta : list){ int clientIndex = 0;
PNCounter c = (PNCounter) clients.get(clientIndex).findCrdt(pnCounterKey); for (int delta : list) {
c = new PNCounter(c, new PNCounter.Builder(clients.get(clientIndex)).increment(((long) delta))); PNCounter c = (PNCounter) clients.get(clientIndex).findCrdt(pnCounterKey);
clients.get(clientIndex).merge(generateSharedMsg(pnCounterKey, c)); c =
clientIndex = (clientIndex + 1) % clients.size(); new PNCounter(
} c, new PNCounter.Builder(clients.get(clientIndex)).increment(((long) delta)));
}; clients.get(clientIndex).merge(generateSharedMsg(pnCounterKey, c));
clientIndex = (clientIndex + 1) % clients.size();
}
};
// given PNCounter // given PNCounter
clients.get(0).merge(generateSharedMsg(pnCounterKey, new PNCounter(new PNCounter.Builder(clients.get(0))))); clients
clients.get(1).merge(generateSharedMsg(pnCounterKey, new PNCounter(new PNCounter.Builder(clients.get(1))))); .get(0)
.merge(
generateSharedMsg(pnCounterKey, new PNCounter(new PNCounter.Builder(clients.get(0)))));
clients
.get(1)
.merge(
generateSharedMsg(pnCounterKey, new PNCounter(new PNCounter.Builder(clients.get(1)))));
assertMergedCrdt(pnCounterKey, (long) 0); assertMergedCrdt(pnCounterKey, (long) 0);
@ -203,28 +228,29 @@ public class DataTest {
Long[] expectedResults = {5L, 7L, 9L, 3L}; Long[] expectedResults = {5L, 7L, 9L, 3L};
for (int i = 0; i < updateLists.size(); i++){ for (int i = 0; i < updateLists.size(); i++) {
counterUpdate.accept(updateLists.get(i)); counterUpdate.accept(updateLists.get(i));
assertMergedCrdt(pnCounterKey, expectedResults[i]); assertMergedCrdt(pnCounterKey, expectedResults[i]);
} }
} }
@Test @Test
public void GrowOnlySetTest(){ public void GrowOnlySetTest() {
clients.get(0).merge(generateSharedMsg("cr", new GrowOnlySet<>(Arrays.asList("1")))); clients.get(0).merge(generateSharedMsg("cr", new GrowOnlySet<>(Arrays.asList("1"))));
clients.get(1).merge(generateSharedMsg("cr", new GrowOnlySet<>(Arrays.asList("2")))); clients.get(1).merge(generateSharedMsg("cr", new GrowOnlySet<>(Arrays.asList("2"))));
assertMergedCrdt("cr", new GrowOnlySet<>(Arrays.asList("1", "2")).value()); assertMergedCrdt("cr", new GrowOnlySet<>(Arrays.asList("1", "2")).value());
} }
private void assertMergedCrdt(String key, Object expected){ private void assertMergedCrdt(String key, Object expected) {
for (GossipManager client : clients){ for (GossipManager client : clients) {
TUnit.assertThat(() -> client.findCrdt(key).value()) TUnit.assertThat(() -> client.findCrdt(key).value())
.afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo(expected); .afterWaitingAtMost(10, TimeUnit.SECONDS)
.isEqualTo(expected);
} }
} }
private PerNodeDataMessage generatePerNodeMsg(String key, Object payload){ private PerNodeDataMessage generatePerNodeMsg(String key, Object payload) {
PerNodeDataMessage g = new PerNodeDataMessage(); PerNodeDataMessage g = new PerNodeDataMessage();
g.setExpireAt(Long.MAX_VALUE); g.setExpireAt(Long.MAX_VALUE);
g.setKey(key); g.setKey(key);
@ -233,7 +259,7 @@ public class DataTest {
return g; return g;
} }
private SharedDataMessage generateSharedMsg(String key, Object payload){ private SharedDataMessage generateSharedMsg(String key, Object payload) {
SharedDataMessage d = new SharedDataMessage(); SharedDataMessage d = new SharedDataMessage();
d.setKey(key); d.setKey(key);
d.setPayload(payload); d.setPayload(payload);
@ -241,4 +267,4 @@ public class DataTest {
d.setTimestamp(System.currentTimeMillis()); d.setTimestamp(System.currentTimeMillis());
return d; return d;
} }
} }

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.gossip; package org.apache.gossip;
import io.teknek.tunit.TUnit;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@ -26,14 +27,11 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.gossip.manager.DatacenterRackAwareActiveGossiper; import org.apache.gossip.manager.DatacenterRackAwareActiveGossiper;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.manager.GossipManagerBuilder;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import io.teknek.tunit.TUnit;
public class IdAndPropertyTest extends AbstractIntegrationBase { public class IdAndPropertyTest extends AbstractIntegrationBase {
@Test @Test

View File

@ -18,6 +18,12 @@
package org.apache.gossip; package org.apache.gossip;
import io.teknek.tunit.TUnit; import io.teknek.tunit.TUnit;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.model.PerNodeDataMessage; import org.apache.gossip.model.PerNodeDataMessage;
@ -26,13 +32,6 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class PerNodeDataEventTest extends AbstractIntegrationBase { public class PerNodeDataEventTest extends AbstractIntegrationBase {

View File

@ -18,6 +18,11 @@
package org.apache.gossip; package org.apache.gossip;
import io.teknek.tunit.TUnit; import io.teknek.tunit.TUnit;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import org.apache.gossip.manager.DatacenterRackAwareActiveGossiper; import org.apache.gossip.manager.DatacenterRackAwareActiveGossiper;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.manager.GossipManagerBuilder;
@ -25,12 +30,6 @@ import org.apache.gossip.model.PerNodeDataMessage;
import org.apache.gossip.replication.*; import org.apache.gossip.replication.*;
import org.junit.Test; import org.junit.Test;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class PerNodeDataReplicationControlTest extends AbstractIntegrationBase { public class PerNodeDataReplicationControlTest extends AbstractIntegrationBase {
@Test @Test

View File

@ -35,7 +35,7 @@ import org.junit.runners.Parameterized;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class SharedDataEventTest extends AbstractIntegrationBase { public class SharedDataEventTest extends AbstractIntegrationBase {
private String receivedKey = ""; private String receivedKey = "";
private Object receivingNodeDataNewValue = ""; private Object receivingNodeDataNewValue = "";
private Object receivingNodeDataOldValue = ""; private Object receivingNodeDataOldValue = "";
@ -51,14 +51,12 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
@Parameterized.Parameters(name = "{index} bulkTransfer={1}") @Parameterized.Parameters(name = "{index} bulkTransfer={1}")
public static Collection<Object[]> data() { public static Collection<Object[]> data() {
return Arrays.asList(new Object[][]{ return Arrays.asList(new Object[][] {{50000, false}, {55000, true}});
{50000, false}, {55000, true}
});
} }
@Test @Test
public void sharedDataEventTest() public void sharedDataEventTest()
throws InterruptedException, UnknownHostException, URISyntaxException { throws InterruptedException, UnknownHostException, URISyntaxException {
GossipSettings settings = new GossipSettings(); GossipSettings settings = new GossipSettings();
settings.setPersistRingState(false); settings.setPersistRingState(false);
settings.setPersistDataState(false); settings.setPersistDataState(false);
@ -74,41 +72,52 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
final int clusterMembers = 2; final int clusterMembers = 2;
for (int i = 1; i < clusterMembers + 1; ++i) { for (int i = 1; i < clusterMembers + 1; ++i) {
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i)); URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
GossipManager gossipService = GossipManagerBuilder.newBuilder().cluster(cluster).uri(uri) GossipManager gossipService =
.id(i + "").gossipMembers(startupMembers).gossipSettings(settings).build(); GossipManagerBuilder.newBuilder()
.cluster(cluster)
.uri(uri)
.id(i + "")
.gossipMembers(startupMembers)
.gossipSettings(settings)
.build();
clients.add(gossipService); clients.add(gossipService);
gossipService.init(); gossipService.init();
register(gossipService); register(gossipService);
} }
// check whether the members are discovered // check whether the members are discovered
TUnit.assertThat(() -> { TUnit.assertThat(
int total = 0; () -> {
for (int i = 0; i < clusterMembers; ++i) { int total = 0;
total += clients.get(i).getLiveMembers().size(); for (int i = 0; i < clusterMembers; ++i) {
} total += clients.get(i).getLiveMembers().size();
return total; }
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(2); return total;
})
.afterWaitingAtMost(20, TimeUnit.SECONDS)
.isEqualTo(2);
// Adding new data to Node 1 // Adding new data to Node 1
clients.get(0).gossipSharedData(sharedNodeData("category", "distributed")); clients.get(0).gossipSharedData(sharedNodeData("category", "distributed"));
// Node 2 is interested in data changes for the key "organization" and "category" // Node 2 is interested in data changes for the key "organization" and "category"
clients.get(1).registerSharedDataSubscriber((key, oldValue, newValue) -> { clients
if (!key.equals("organization") && !key.equals("category")) .get(1)
return; .registerSharedDataSubscriber(
receivedKey = key; (key, oldValue, newValue) -> {
receivingNodeDataOldValue = oldValue; if (!key.equals("organization") && !key.equals("category")) return;
receivingNodeDataNewValue = newValue; receivedKey = key;
lock.release(); receivingNodeDataOldValue = oldValue;
}); receivingNodeDataNewValue = newValue;
lock.release();
});
// Node 2 first time gets shared data // Node 2 first time gets shared data
lock.tryAcquire(10, TimeUnit.SECONDS); lock.tryAcquire(10, TimeUnit.SECONDS);
Assert.assertEquals("category", receivedKey); Assert.assertEquals("category", receivedKey);
Assert.assertEquals(null, receivingNodeDataOldValue); Assert.assertEquals(null, receivingNodeDataOldValue);
Assert.assertEquals("distributed", receivingNodeDataNewValue); Assert.assertEquals("distributed", receivingNodeDataNewValue);
// Node 1 adds new per node data // Node 1 adds new per node data
clients.get(0).gossipSharedData(sharedNodeData("organization", "apache")); clients.get(0).gossipSharedData(sharedNodeData("organization", "apache"));
// Node 2 adds new shared data // Node 2 adds new shared data
@ -116,21 +125,20 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
Assert.assertEquals("organization", receivedKey); Assert.assertEquals("organization", receivedKey);
Assert.assertEquals(null, receivingNodeDataOldValue); Assert.assertEquals(null, receivingNodeDataOldValue);
Assert.assertEquals("apache", receivingNodeDataNewValue); Assert.assertEquals("apache", receivingNodeDataNewValue);
// Node 1 updates its value // Node 1 updates its value
clients.get(0).gossipSharedData(sharedNodeData("organization", "apache-gossip")); clients.get(0).gossipSharedData(sharedNodeData("organization", "apache-gossip"));
// Node 2 updates existing value // Node 2 updates existing value
lock.tryAcquire(10, TimeUnit.SECONDS); lock.tryAcquire(10, TimeUnit.SECONDS);
Assert.assertEquals("organization", receivedKey); Assert.assertEquals("organization", receivedKey);
Assert.assertEquals("apache", receivingNodeDataOldValue); Assert.assertEquals("apache", receivingNodeDataOldValue);
Assert.assertEquals("apache-gossip", receivingNodeDataNewValue); Assert.assertEquals("apache-gossip", receivingNodeDataNewValue);
} }
@Test @Test
public void CrdtDataChangeEventTest() public void CrdtDataChangeEventTest()
throws InterruptedException, UnknownHostException, URISyntaxException { throws InterruptedException, UnknownHostException, URISyntaxException {
GossipSettings settings = new GossipSettings(); GossipSettings settings = new GossipSettings();
settings.setPersistRingState(false); settings.setPersistRingState(false);
settings.setPersistDataState(false); settings.setPersistDataState(false);
@ -145,29 +153,41 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
final int clusterMembers = 3; final int clusterMembers = 3;
for (int i = 1; i < clusterMembers + 1; ++i) { for (int i = 1; i < clusterMembers + 1; ++i) {
URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i)); URI uri = new URI("udp://" + "127.0.0.1" + ":" + (base + i));
GossipManager gossipService = GossipManagerBuilder.newBuilder().cluster(cluster).uri(uri) GossipManager gossipService =
.id(i + "").gossipMembers(startupMembers).gossipSettings(settings).build(); GossipManagerBuilder.newBuilder()
.cluster(cluster)
.uri(uri)
.id(i + "")
.gossipMembers(startupMembers)
.gossipSettings(settings)
.build();
clients.add(gossipService); clients.add(gossipService);
gossipService.init(); gossipService.init();
register(gossipService); register(gossipService);
} }
// check whether the members are discovered // check whether the members are discovered
TUnit.assertThat(() -> { TUnit.assertThat(
int total = 0; () -> {
for (int i = 0; i < clusterMembers; ++i) { int total = 0;
total += clients.get(i).getLiveMembers().size(); for (int i = 0; i < clusterMembers; ++i) {
} total += clients.get(i).getLiveMembers().size();
return total; }
}).afterWaitingAtMost(20, TimeUnit.SECONDS).isEqualTo(2); return total;
})
clients.get(1).registerSharedDataSubscriber((key, oldValue, newValue) -> { .afterWaitingAtMost(20, TimeUnit.SECONDS)
receivedKey = key; .isEqualTo(2);
receivingNodeDataOldValue = oldValue;
receivingNodeDataNewValue = newValue; clients
lock.release(); .get(1)
}); .registerSharedDataSubscriber(
(key, oldValue, newValue) -> {
receivedKey = key;
receivingNodeDataOldValue = oldValue;
receivingNodeDataNewValue = newValue;
lock.release();
});
// Add initial gCounter to Node 1 // Add initial gCounter to Node 1
SharedDataMessage d = new SharedDataMessage(); SharedDataMessage d = new SharedDataMessage();
d.setKey(gCounterKey); d.setKey(gCounterKey);
@ -175,37 +195,39 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
d.setExpireAt(Long.MAX_VALUE); d.setExpireAt(Long.MAX_VALUE);
d.setTimestamp(System.currentTimeMillis()); d.setTimestamp(System.currentTimeMillis());
clients.get(0).merge(d); clients.get(0).merge(d);
// Check if initial Crdt received // Check if initial Crdt received
lock.tryAcquire(10, TimeUnit.SECONDS); lock.tryAcquire(10, TimeUnit.SECONDS);
Assert.assertEquals("gCounter", receivedKey); Assert.assertEquals("gCounter", receivedKey);
Assert.assertEquals(null, receivingNodeDataOldValue); Assert.assertEquals(null, receivingNodeDataOldValue);
Assert.assertTrue(receivingNodeDataNewValue instanceof GrowOnlyCounter); Assert.assertTrue(receivingNodeDataNewValue instanceof GrowOnlyCounter);
Assert.assertEquals(1, ((GrowOnlyCounter) receivingNodeDataNewValue).value().longValue()); Assert.assertEquals(1, ((GrowOnlyCounter) receivingNodeDataNewValue).value().longValue());
// check whether Node 3 received the gCounter // check whether Node 3 received the gCounter
TUnit.assertThat(() -> { TUnit.assertThat(
GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(2).findCrdt(gCounterKey); () -> {
if (gc == null) { GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(2).findCrdt(gCounterKey);
return ""; if (gc == null) {
} else { return "";
return gc; } else {
} return gc;
}).afterWaitingAtMost(10, TimeUnit.SECONDS).isEqualTo( }
new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L))); })
.afterWaitingAtMost(10, TimeUnit.SECONDS)
.isEqualTo(new GrowOnlyCounter(new GrowOnlyCounter.Builder(clients.get(0)).increment(1L)));
// Node 3 Updates the gCounter by 4 // Node 3 Updates the gCounter by 4
GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(2).findCrdt(gCounterKey); GrowOnlyCounter gc = (GrowOnlyCounter) clients.get(2).findCrdt(gCounterKey);
GrowOnlyCounter gcNew = new GrowOnlyCounter(gc, GrowOnlyCounter gcNew =
new GrowOnlyCounter.Builder(clients.get(2)).increment(4L)); new GrowOnlyCounter(gc, new GrowOnlyCounter.Builder(clients.get(2)).increment(4L));
d = new SharedDataMessage(); d = new SharedDataMessage();
d.setKey(gCounterKey); d.setKey(gCounterKey);
d.setPayload(gcNew); d.setPayload(gcNew);
d.setExpireAt(Long.MAX_VALUE); d.setExpireAt(Long.MAX_VALUE);
d.setTimestamp(System.currentTimeMillis()); d.setTimestamp(System.currentTimeMillis());
clients.get(2).merge(d); clients.get(2).merge(d);
// Check if Node 3's Crdt update is received in Node 2 event handler // Check if Node 3's Crdt update is received in Node 2 event handler
lock.tryAcquire(10, TimeUnit.SECONDS); lock.tryAcquire(10, TimeUnit.SECONDS);
Assert.assertEquals("gCounter", receivedKey); Assert.assertEquals("gCounter", receivedKey);
@ -213,9 +235,8 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
Assert.assertEquals(1, ((GrowOnlyCounter) receivingNodeDataOldValue).value().longValue()); Assert.assertEquals(1, ((GrowOnlyCounter) receivingNodeDataOldValue).value().longValue());
Assert.assertTrue(receivingNodeDataNewValue instanceof GrowOnlyCounter); Assert.assertTrue(receivingNodeDataNewValue instanceof GrowOnlyCounter);
Assert.assertEquals(5, ((GrowOnlyCounter) receivingNodeDataNewValue).value().longValue()); Assert.assertEquals(5, ((GrowOnlyCounter) receivingNodeDataNewValue).value().longValue());
} }
private SharedDataMessage sharedNodeData(String key, String value) { private SharedDataMessage sharedNodeData(String key, String value) {
SharedDataMessage g = new SharedDataMessage(); SharedDataMessage g = new SharedDataMessage();
g.setExpireAt(Long.MAX_VALUE); g.setExpireAt(Long.MAX_VALUE);
@ -224,5 +245,4 @@ public class SharedDataEventTest extends AbstractIntegrationBase {
g.setTimestamp(System.currentTimeMillis()); g.setTimestamp(System.currentTimeMillis());
return g; return g;
} }
} }

View File

@ -17,13 +17,6 @@
*/ */
package org.apache.gossip; package org.apache.gossip;
import org.apache.gossip.lock.exceptions.VoteFailedException;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.model.SharedDataMessage;
import org.junit.Assert;
import org.junit.Test;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@ -31,6 +24,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import org.apache.gossip.lock.exceptions.VoteFailedException;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.model.SharedDataMessage;
import org.junit.Assert;
import org.junit.Test;
public class SharedDataLockTest extends AbstractIntegrationBase { public class SharedDataLockTest extends AbstractIntegrationBase {

View File

@ -44,8 +44,7 @@ import java.util.concurrent.TimeUnit;
public class SharedDataReplicationControlTest extends AbstractIntegrationBase { public class SharedDataReplicationControlTest extends AbstractIntegrationBase {
@Test @Test
public void sharedDataReplicationTest() public void sharedDataReplicationTest() throws URISyntaxException {
throws URISyntaxException {
generateStandardNodes(3); generateStandardNodes(3);
// check whether the members are discovered // check whether the members are discovered

View File

@ -38,8 +38,7 @@ public class ShutdownDeadtimeTest {
// harm), and the // harm), and the
// sleep that happens after startup. // sleep that happens after startup.
@Test @Test
public void DeadNodesDoNotComeAliveAgain() public void DeadNodesDoNotComeAliveAgain() throws InterruptedException, URISyntaxException {
throws InterruptedException, URISyntaxException {
GossipSettings settings = new GossipSettings(100, 10000, 1000, 1, 10.0, "normal", false); GossipSettings settings = new GossipSettings(100, 10000, 1000, 1, 10.0, "normal", false);
settings.setPersistRingState(false); settings.setPersistRingState(false);
settings.setPersistDataState(false); settings.setPersistDataState(false);
@ -68,13 +67,13 @@ public class ShutdownDeadtimeTest {
Thread.sleep(1000); Thread.sleep(1000);
} }
TUnit.assertThat( TUnit.assertThat(
() -> { () -> {
int total = 0; int total = 0;
for (int i = 0; i < clusterMembers; ++i) { for (int i = 0; i < clusterMembers; ++i) {
total += clients.get(i).getLiveMembers().size(); total += clients.get(i).getLiveMembers().size();
} }
return total; return total;
}) })
.afterWaitingAtMost(40, TimeUnit.SECONDS) .afterWaitingAtMost(40, TimeUnit.SECONDS)
.isEqualTo(20); .isEqualTo(20);
@ -86,25 +85,25 @@ public class ShutdownDeadtimeTest {
final String shutdownId = clients.get(randomClientId).getMyself().getId(); final String shutdownId = clients.get(randomClientId).getMyself().getId();
clients.get(randomClientId).shutdown(); clients.get(randomClientId).shutdown();
TUnit.assertThat( TUnit.assertThat(
() -> { () -> {
int total = 0; int total = 0;
for (int i = 0; i < clusterMembers; ++i) { for (int i = 0; i < clusterMembers; ++i) {
total += clients.get(i).getLiveMembers().size(); total += clients.get(i).getLiveMembers().size();
} }
return total; return total;
}) })
.afterWaitingAtMost(40, TimeUnit.SECONDS) .afterWaitingAtMost(40, TimeUnit.SECONDS)
.isEqualTo(16); .isEqualTo(16);
clients.remove(randomClientId); clients.remove(randomClientId);
TUnit.assertThat( TUnit.assertThat(
() -> { () -> {
int total = 0; int total = 0;
for (int i = 0; i < clusterMembers - 1; ++i) { for (int i = 0; i < clusterMembers - 1; ++i) {
total += clients.get(i).getDeadMembers().size(); total += clients.get(i).getDeadMembers().size();
} }
return total; return total;
}) })
.afterWaitingAtMost(50, TimeUnit.SECONDS) .afterWaitingAtMost(50, TimeUnit.SECONDS)
.isEqualTo(4); .isEqualTo(4);
@ -123,13 +122,13 @@ public class ShutdownDeadtimeTest {
// verify that the client is alive again for every node // verify that the client is alive again for every node
TUnit.assertThat( TUnit.assertThat(
() -> { () -> {
int total = 0; int total = 0;
for (int i = 0; i < clusterMembers; ++i) { for (int i = 0; i < clusterMembers; ++i) {
total += clients.get(i).getLiveMembers().size(); total += clients.get(i).getLiveMembers().size();
} }
return total; return total;
}) })
.afterWaitingAtMost(60, TimeUnit.SECONDS) .afterWaitingAtMost(60, TimeUnit.SECONDS)
.isEqualTo(20); .isEqualTo(20);

View File

@ -17,6 +17,7 @@
*/ */
package org.apache.gossip; package org.apache.gossip;
import io.teknek.tunit.TUnit;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
@ -28,7 +29,6 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.apache.gossip.manager.GossipManager; import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder; import org.apache.gossip.manager.GossipManagerBuilder;
import org.apache.gossip.manager.PassiveGossipConstants; import org.apache.gossip.manager.PassiveGossipConstants;
@ -36,8 +36,6 @@ import org.apache.gossip.secure.KeyTool;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import io.teknek.tunit.TUnit;
public class SignedMessageTest extends AbstractIntegrationBase { public class SignedMessageTest extends AbstractIntegrationBase {
private GossipSettings gossiperThatSigns() { private GossipSettings gossiperThatSigns() {

View File

@ -17,18 +17,16 @@
*/ */
package org.apache.gossip; package org.apache.gossip;
import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.junit.jupiter.api.Test;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.util.UUID; import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.manager.GossipManagerBuilder;
import org.junit.jupiter.api.Test;
/** Tests support of using {@code StartupSettings} and thereby reading setup config from file. */ /** Tests support of using {@code StartupSettings} and thereby reading setup config from file. */
@Slf4j @Slf4j

View File

@ -18,7 +18,6 @@
package org.apache.gossip; package org.apache.gossip;
import io.teknek.tunit.TUnit; import io.teknek.tunit.TUnit;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.UnknownHostException; import java.net.UnknownHostException;

View File

@ -21,13 +21,6 @@ import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.gossip.GossipSettings;
import org.apache.gossip.crdt.CrdtModule;
import org.apache.gossip.manager.PassiveGossipConstants;
import org.apache.gossip.model.Base;
import org.apache.gossip.model.SignedPayload;
import org.apache.gossip.protocol.ProtocolManager;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
@ -40,6 +33,12 @@ import java.security.Signature;
import java.security.SignatureException; import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException; import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.PKCS8EncodedKeySpec;
import org.apache.gossip.GossipSettings;
import org.apache.gossip.crdt.CrdtModule;
import org.apache.gossip.manager.PassiveGossipConstants;
import org.apache.gossip.model.Base;
import org.apache.gossip.model.SignedPayload;
import org.apache.gossip.protocol.ProtocolManager;
// this class is constructed by reflection in GossipManager. // this class is constructed by reflection in GossipManager.
public class JacksonProtocolManager implements ProtocolManager { public class JacksonProtocolManager implements ProtocolManager {

View File

@ -18,6 +18,8 @@
package org.apache.gossip.protocol.json; package org.apache.gossip.protocol.json;
import static org.junit.jupiter.api.Assertions.*;
import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException; import java.io.IOException;
@ -38,8 +40,6 @@ import org.apache.gossip.protocol.ProtocolManager;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class JacksonTest { public class JacksonTest {
private static GossipSettings simpleSettings(GossipSettings settings) { private static GossipSettings simpleSettings(GossipSettings settings) {

View File

@ -17,15 +17,13 @@
*/ */
package org.apache.gossip.protocol.json; package org.apache.gossip.protocol.json;
import lombok.Data;
import lombok.Getter;
import org.apache.gossip.model.Base;
import org.apache.gossip.udp.Trackable;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import lombok.Data;
import org.apache.gossip.model.Base;
import org.apache.gossip.udp.Trackable;
/* /*
* Here is a test class for serialization. I've tried to include a lot of things in it including nested classes. * Here is a test class for serialization. I've tried to include a lot of things in it including nested classes.

View File

@ -17,12 +17,6 @@
*/ */
package org.apache.gossip.transport.udp; package org.apache.gossip.transport.udp;
import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.manager.GossipCore;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.model.Base;
import org.apache.gossip.transport.AbstractTransportManager;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
@ -32,6 +26,11 @@ import java.net.SocketAddress;
import java.net.SocketException; import java.net.SocketException;
import java.net.URI; import java.net.URI;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import lombok.extern.slf4j.Slf4j;
import org.apache.gossip.manager.GossipCore;
import org.apache.gossip.manager.GossipManager;
import org.apache.gossip.model.Base;
import org.apache.gossip.transport.AbstractTransportManager;
/** /**
* This class is constructed by reflection in GossipManager. It manages transport (byte read/write) * This class is constructed by reflection in GossipManager. It manages transport (byte read/write)