diff options
15 files changed, 139 insertions, 32 deletions
diff --git a/build.gradle b/build.gradle index 13be045..d7909f7 100644 --- a/build.gradle +++ b/build.gradle @@ -116,12 +116,14 @@ task runClient(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath main = 'pl.edu.mimuw.cloudatlas.client.Client' systemProperty 'agent_hostname', hostname() + systemProperty 'zone_path', zonePath() } task runFetcher(type: JavaExec) { classpath = sourceSets.main.runtimeClasspath main = 'pl.edu.mimuw.cloudatlas.fetcher.Fetcher' args(hostname() , 1099) + systemProperty 'zone_path', zonePath() } task runInterpreter(type: JavaExec) { diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java index 0cbda2d..06e067b 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/Agent.java @@ -42,14 +42,16 @@ public class Agent { // TODO: make query period confiurable with config file and from tests - // TODO config setup String zonePath = System.getProperty("zone_path"); String selectionStrategy = System.getProperty("Gossip.zone_strategy"); Long queryPeriod = Long.getLong("query_period"); Long gossipPeriod = Long.getLong("gossip_period"); + Long freshnessPeriod = Long.getLong("freshness_period"); HierarchyConfig hierarchyConfig = new HierarchyConfig(eventBus, zonePath, selectionStrategy); hierarchyConfig.startQueries(queryPeriod); - hierarchyConfig.startGossip(gossipPeriod); + hierarchyConfig.startGossip(gossipPeriod, zonePath); + // TODO: should this be different than ZMI freshness period? + hierarchyConfig.startCleaningGossips(freshnessPeriod); } } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/HierarchyConfig.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/HierarchyConfig.java index dc5241d..92b7f66 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/HierarchyConfig.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/HierarchyConfig.java @@ -37,7 +37,7 @@ public class HierarchyConfig { } } - public void startGossip(long gossipPeriod) { + public void startGossip(long gossipPeriod, String zonePath) { Supplier<TimerScheduledTask> taskSupplier = () -> new TimerScheduledTask() { public void run() { @@ -47,7 +47,7 @@ public class HierarchyConfig { ValueContact contact = selectContactFromLevel(gossipLevel); if (contact != null) { System.out.println("INFO: found a contact " + contact.toString()); - InitiateGossipMessage message = new InitiateGossipMessage("", 0, new PathName("/uw/violet07"), contact); + InitiateGossipMessage message = new InitiateGossipMessage("", 0, new PathName(zonePath), contact); sendMessage(message); } else { System.out.println("DEBUG: couldn't find contact for gossip"); @@ -153,4 +153,20 @@ public class HierarchyConfig { AgentUtils.startRecursiveTask(taskSupplier, queriesPeriod, eventBus); } + + public void startCleaningGossips(long gossipCleanPeriod) { + Supplier<TimerScheduledTask> taskSupplier = () -> + new TimerScheduledTask() { + public void run() { + try { + System.out.println("INFO: Scheduling old gossip cleanup"); + sendMessage(new CleanOldGossipsMessage("", 0, ValueUtils.addToTime(ValueUtils.currentTime(), -gossipCleanPeriod))); + } catch (InterruptedException e) { + System.out.println("Interrupted while triggering queries"); + } + } + }; + + AgentUtils.startRecursiveTask(taskSupplier, gossipCleanPeriod, eventBus); + } } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/CleanOldGossipsMessage.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/CleanOldGossipsMessage.java new file mode 100644 index 0000000..6c3cb7e --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/CleanOldGossipsMessage.java @@ -0,0 +1,16 @@ +package pl.edu.mimuw.cloudatlas.agent.messages; + +import pl.edu.mimuw.cloudatlas.model.ValueTime; + +public class CleanOldGossipsMessage extends GossipGirlMessage { + private ValueTime ageThreshold; + + public CleanOldGossipsMessage(String messageId, long timestamp, ValueTime ageThreshold) { + super(messageId, timestamp, Type.CLEAN); + this.ageThreshold = ageThreshold; + } + + public ValueTime getAgeThreshold() { + return ageThreshold; + } +} diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/GossipGirlMessage.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/GossipGirlMessage.java index 03525bb..6255e3b 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/GossipGirlMessage.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/messages/GossipGirlMessage.java @@ -9,7 +9,8 @@ public abstract class GossipGirlMessage extends AgentMessage { HEJKA, INITIATE, NO_CO_TAM, - QUERY + QUERY, + CLEAN } private Type type; diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java index 0ec9d6c..440df33 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirl.java @@ -2,10 +2,12 @@ package pl.edu.mimuw.cloudatlas.agent.modules; import java.util.AbstractMap.SimpleImmutableEntry; import java.util.HashMap; +import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import pl.edu.mimuw.cloudatlas.agent.messages.AttributesMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.CleanOldGossipsMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GetStateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GossipGirlMessage; import pl.edu.mimuw.cloudatlas.agent.messages.HejkaMessage; @@ -52,6 +54,9 @@ public class GossipGirl extends Module { case QUERY: handleQuery((QueryMessage) message); break; + case CLEAN: + cleanOldGossips((CleanOldGossipsMessage) message); + break; default: throw new InvalidMessageType("This type of message cannot be handled by GossipGirl"); } @@ -100,6 +105,7 @@ public class GossipGirl extends Module { GossipGirlState state = gossipStates.get(message.getRequestId()); if (state != null) { System.out.println("INFO: setting state in gossip " + Long.toString(message.getRequestId())); + state.setLastAction(); state.setState(message.getZMI(), message.getQueries()); if (state.state == GossipGirlState.State.SEND_HEJKA) { HejkaMessage hejka = new HejkaMessage( @@ -140,6 +146,7 @@ public class GossipGirl extends Module { GossipGirlState state = gossipStates.get(message.getReceiverGossipId()); if (state != null) { System.out.println("INFO: handling NoCoTamMessage in" + Long.toString(message.getReceiverGossipId())); + state.setLastAction(); state.handleNoCoTam(message); System.out.println("DEBUG: handled NoCoTam in GossipGirlState"); sendInfo(state); @@ -171,8 +178,9 @@ public class GossipGirl extends Module { GossipGirlState state = gossipStates.get(message.getReceiverGossipId()); if (state != null) { System.out.println("INFO: handling Attributes in " + Long.toString(message.getReceiverGossipId())); + state.setLastAction(); state.gotAttributes(message); - if (state.state == GossipGirlState.State.SEND_INFO) { + if (state.state == GossipGirlState.State.SEND_INFO || state.state == GossipGirlState.State.SEND_INFO_AND_FINISH) { sendInfo(state); } UpdateAttributesMessage updateMessage = new UpdateAttributesMessage("", 0, message.getPath().toString(), message.getAttributes()); @@ -190,6 +198,7 @@ public class GossipGirl extends Module { GossipGirlState state = gossipStates.get(message.getReceiverGossipId()); if (state != null) { System.out.println("INFO: handling Query in " + Long.toString(message.getReceiverGossipId())); + state.setLastAction(); state.gotQuery(message.getName()); Map<Attribute, Entry<ValueQuery, ValueTime>> queries = new HashMap(); queries.put( @@ -206,4 +215,15 @@ public class GossipGirl extends Module { System.out.println("ERROR: GossipGirl got query for a nonexistent gossip"); } } + + private void cleanOldGossips(CleanOldGossipsMessage message) { + Iterator<Entry<Long, GossipGirlState>> iterator = gossipStates.entrySet().iterator(); + while (iterator.hasNext()) { + GossipGirlState state = iterator.next().getValue(); + if (state.lastAction.isLowerThan(message.getAgeThreshold()).getValue()) { + System.out.println("INFO: GossipGirl removing old gossip " + Long.toString(state.gossipId)); + iterator.remove(); + } + } + } } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java index 6ee7474..e9bc02a 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlState.java @@ -36,6 +36,7 @@ public class GossipGirlState { FINISHED, ERROR } + public ValueTime lastAction; public PathName ourPath; public ValueContact theirContact; public long gossipId; @@ -65,6 +66,11 @@ public class GossipGirlState { } else { state = State.APPLY_HEJKA; } + this.lastAction = ValueUtils.currentTime(); + } + + public void setLastAction() { + lastAction = ValueUtils.currentTime(); } public void setState(ZMI hierarchy, Map<Attribute, Entry<ValueQuery, ValueTime>> queries) { diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java b/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java index 210505d..4019696 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/client/ClientController.java @@ -53,7 +53,7 @@ public class ClientController { return size() > MAX_ENTRIES; } }; - this.currentZoneName = "/uw/violet07"; + this.currentZoneName = System.getProperty("zone_path"); fetchAttributeData(); // fetch attribute data as early as possible } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/fetcher/Fetcher.java b/src/main/java/pl/edu/mimuw/cloudatlas/fetcher/Fetcher.java index 15f8a59..12d795a 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/fetcher/Fetcher.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/fetcher/Fetcher.java @@ -92,7 +92,7 @@ public class Fetcher { } // https://jj09.net/interprocess-communication-python-java/ - private static void fetchData() { + private static void fetchData(String zonePath) { BufferedReader bufferRead; ArrayList deserializedAttribs; String jsonAttribs; @@ -111,7 +111,7 @@ public class Fetcher { deserializedAttribs = deserializeAttribs(jsonAttribs); for (int i = 0; i < fetcherAttributeNames.size(); i++) { api.setAttributeValue( - "/uw/violet07", + zonePath, fetcherAttributeNames.get(i), packAttributeValue( deserializedAttribs.get(i), @@ -143,7 +143,8 @@ public class Fetcher { } public static void main(String[] args) { + String zonePath = System.getProperty("zone_path"); parseArgs(args); - fetchData(); + fetchData(zonePath); } } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueUtils.java b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueUtils.java index 3df8231..866349f 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueUtils.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/model/ValueUtils.java @@ -12,4 +12,8 @@ public class ValueUtils { public static ValueTime currentTime() { return new ValueTime(System.currentTimeMillis()); } + + public static ValueTime addToTime(ValueTime time, long millis) { + return time.addValue(new ValueDuration(millis)); + } } diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/AgentIntegrationTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/AgentIntegrationTest.java index e2c12d6..9028026 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/AgentIntegrationTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/AgentIntegrationTest.java @@ -48,9 +48,9 @@ public class AgentIntegrationTest { @BeforeClass public static void bindApi() throws Exception { registryProcess = Runtime.getRuntime().exec("./scripts/registry"); - Thread.sleep(10000); + Thread.sleep(5000); agentProcess = Runtime.getRuntime().exec("./gradlew runAgent -Dhostname=localhost -DfreshnessPeriod=10000000 -DqueryPeriod=100"); - Thread.sleep(10000); + Thread.sleep(5000); registry = LocateRegistry.getRegistry("localhost"); api = (Api) registry.lookup("Api"); diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/SchedulerTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/SchedulerTest.java index 4a9eb87..99051ff 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/SchedulerTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/SchedulerTest.java @@ -60,7 +60,7 @@ public class SchedulerTest { } })); - Thread.sleep(1000); + Thread.sleep(300); } @Test @@ -92,7 +92,7 @@ public class SchedulerTest { })); - Thread.sleep(1000); + Thread.sleep(300); } @Test @@ -129,6 +129,6 @@ public class SchedulerTest { } })); - Thread.sleep(1000); + Thread.sleep(300); } } diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/UDUPTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/UDUPTest.java index ac2c587..f731706 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/UDUPTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/UDUPTest.java @@ -30,7 +30,7 @@ public class UDUPTest { UDUPServer server2 = null; UDUPMessage msg1 = null; boolean testSuccess = true; - int timeout = 5000; + int timeout = 500; try { System.out.println("Starting udp1"); @@ -72,7 +72,7 @@ public class UDUPTest { udpThread2.start(); try { - Thread.sleep(500); + Thread.sleep(100); if (udp1 == null | udp2 == null) { testSuccess = false; } else { @@ -102,7 +102,7 @@ public class UDUPTest { UDUPServer server2 = null; UDUPMessage msg1 = null; boolean testSuccess = true; - int timeout = 3000; + int timeout = 1000; try { System.out.println("Starting udp1"); @@ -144,7 +144,7 @@ public class UDUPTest { udpThread2.start(); try { - Thread.sleep(500); + Thread.sleep(100); if (udp1 == null | udp2 == null) { testSuccess = false; } else { @@ -177,7 +177,7 @@ public class UDUPTest { UDUPMessage msg2 = null; UDUPMessage msg3 = null; boolean testSuccess = true; - int timeout = 3000; + int timeout = 1000; try { System.out.println("Starting udp1"); @@ -231,7 +231,7 @@ public class UDUPTest { udpThread2.start(); try { - Thread.sleep(500); + Thread.sleep(100); if (udp1 == null | udp2 == null) { testSuccess = false; } else { diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java index 5fac535..d443fad 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/agent/modules/GossipGirlTest.java @@ -16,6 +16,7 @@ import java.util.Set; import pl.edu.mimuw.cloudatlas.agent.MockExecutor; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; import pl.edu.mimuw.cloudatlas.agent.messages.AttributesMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.CleanOldGossipsMessage; import pl.edu.mimuw.cloudatlas.agent.messages.HejkaMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GetStateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GossipGirlMessage; @@ -83,7 +84,7 @@ public class GossipGirlTest { Map<PathName, ValueTime> otherZoneTimestamps = makeOtherZoneTimestamps(); Map<Attribute, ValueTime> otherQueryTimestamps = makeOtherQueryTimestamps(); - noCoTamMessage = new NoCoTamMessage("", 0, 42, 0, otherZoneTimestamps, otherQueryTimestamps, TestUtil.addToTime(testTime, 10), TestUtil.addToTime(testTime, 22)); + noCoTamMessage = new NoCoTamMessage("", 0, 42, 0, otherZoneTimestamps, otherQueryTimestamps, ValueUtils.addToTime(testTime, 10), ValueUtils.addToTime(testTime, 22)); attributesMessage1 = makeAttributesMessage("/son/bro", makeAttributes1()); attributesMessage2 = makeAttributesMessage("/son/whodis", makeAttributes2()); @@ -92,7 +93,7 @@ public class GossipGirlTest { hejkaMessage = new HejkaMessage("", 0, 123, new PathName("/son/bro"), new PathName("/son/grand"), otherZoneTimestamps, otherQueryTimestamps); hejkaMessage.setSentTimestamp(testTime); - hejkaMessage.setReceivedTimestamp(TestUtil.addToTime(testTime, 15)); + hejkaMessage.setReceivedTimestamp(ValueUtils.addToTime(testTime, 15)); hejkaMessage.setSenderAddress(theirContact.getAddress()); } @@ -113,7 +114,7 @@ public class GossipGirlTest { public AttributesMap makeAttributes2() { AttributesMap attributes = new AttributesMap(); attributes.add("name", new ValueString("whodis")); - attributes.add("timestamp", TestUtil.addToTime(testTime, -300)); + attributes.add("timestamp", ValueUtils.addToTime(testTime, -300)); attributes.add("foo", new ValueInt(61l)); attributes.add("bar", new ValueString("nice")); return attributes; @@ -141,11 +142,11 @@ public class GossipGirlTest { } public void addOtherQueryTimestamp(Map<Attribute, ValueTime> timestamps, String name, long offset) { - timestamps.put(new Attribute(name), TestUtil.addToTime(testTime, offset)); + timestamps.put(new Attribute(name), ValueUtils.addToTime(testTime, offset)); } public void addOtherZoneTimestamp(Map<PathName, ValueTime> timestamps, String path, long offset) { - timestamps.put(new PathName(path), TestUtil.addToTime(testTime, offset)); + timestamps.put(new PathName(path), ValueUtils.addToTime(testTime, offset)); } public void setupHierarchy() { @@ -289,7 +290,7 @@ public class GossipGirlTest { new SimpleImmutableEntry( new ValueQuery("SELECT 3 AS one"), // TODO: this should be modified by GTP - TestUtil.addToTime(testTime, 10) + ValueUtils.addToTime(testTime, 10) ) ); @@ -402,7 +403,7 @@ public class GossipGirlTest { new SimpleImmutableEntry( new ValueQuery("SELECT 3 AS one"), // TODO: this should be modified by GTP - TestUtil.addToTime(testTime, 10) + ValueUtils.addToTime(testTime, 10) ) ); @@ -410,6 +411,48 @@ public class GossipGirlTest { gossipGirl.handleTyped(queryMessage2); } + @Test + public void cleanupOldGossips() throws Exception { + gossipGirl.handleTyped(hejkaMessage); + executor.messagesToPass.take(); + gossipGirl.handleTyped(stateMessage); + executor.messagesToPass.take(); + + gossipGirl.handleTyped(attributesMessage1); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + + CleanOldGossipsMessage message = new CleanOldGossipsMessage("", 0, ValueUtils.addToTime(ValueUtils.currentTime(), 10)); + gossipGirl.handleTyped(message); + gossipGirl.handleTyped(attributesMessage2); + assertEquals(0, executor.messagesToPass.size()); + } + + @Test + public void dontCleanFreshGossips() throws Exception { + gossipGirl.handleTyped(hejkaMessage); + executor.messagesToPass.take(); + gossipGirl.handleTyped(stateMessage); + executor.messagesToPass.take(); + + gossipGirl.handleTyped(attributesMessage1); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + executor.messagesToPass.take(); + + CleanOldGossipsMessage message = new CleanOldGossipsMessage("", 0, ValueUtils.addToTime(testTime, -10)); + gossipGirl.handleTyped(message); + gossipGirl.handleTyped(attributesMessage2); + assertEquals(1, executor.messagesToPass.size()); + } + private void assertQueryMessage(AgentMessage message, String recipientPath, String name, String query) throws Exception { assertUDUPMessage( message, diff --git a/src/test/java/pl/edu/mimuw/cloudatlas/model/TestUtil.java b/src/test/java/pl/edu/mimuw/cloudatlas/model/TestUtil.java index 0fef6b4..ddc61a9 100644 --- a/src/test/java/pl/edu/mimuw/cloudatlas/model/TestUtil.java +++ b/src/test/java/pl/edu/mimuw/cloudatlas/model/TestUtil.java @@ -9,8 +9,4 @@ public class TestUtil { return count; } - - public static ValueTime addToTime(ValueTime time, long millis) { - return time.addValue(new ValueDuration(millis)); - } } |