From afa32431d242d60471e5431d654784ee64b63bbf Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Fri, 27 Dec 2019 11:28:46 +0100 Subject: Begin Stanik impelementation * Get cloned hierarchy * Test on empty hierarchy --- .../edu/mimuw/cloudatlas/agent/modules/Module.java | 10 +++++++ .../mimuw/cloudatlas/agent/modules/ModuleType.java | 4 ++- .../edu/mimuw/cloudatlas/agent/modules/Stanik.java | 31 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java (limited to 'src/main/java/pl/edu/mimuw/cloudatlas/agent/modules') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Module.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Module.java index a50a95f..d0bf083 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Module.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Module.java @@ -3,7 +3,9 @@ package pl.edu.mimuw.cloudatlas.agent.modules; import pl.edu.mimuw.cloudatlas.agent.Executor; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; import pl.edu.mimuw.cloudatlas.agent.messages.TimerSchedulerMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.ResponseMessage; import pl.edu.mimuw.cloudatlas.agent.messages.RMIMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; /* * A Module is a (potentially stateful) event handler. @@ -34,6 +36,14 @@ public abstract class Module { throw new InvalidMessageType("Got an RMIMessage in module " + moduleType.toString()); } + public void handleTyped(StanikMessage message) throws InterruptedException, InvalidMessageType { + throw new InvalidMessageType("Got a StanikMessage in module " + moduleType.toString()); + } + + public void handleTyped(ResponseMessage message) throws InterruptedException, InvalidMessageType { + throw new InvalidMessageType("Got a ResponseMessage in module " + moduleType.toString()); + } + public void setExecutor(Executor executor) { this.executor = executor; } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/ModuleType.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/ModuleType.java index ff4a92e..d221f06 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/ModuleType.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/ModuleType.java @@ -8,5 +8,7 @@ public enum ModuleType { GOSSIP_IN, GOSSIP_OUT, STATE, - QUERY + QUERY, + // for testing + TEST } diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java new file mode 100644 index 0000000..b8db08a --- /dev/null +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -0,0 +1,31 @@ +package pl.edu.mimuw.cloudatlas.agent.modules; + +import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.GetHierarchyMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.HierarchyMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; +import pl.edu.mimuw.cloudatlas.model.ZMI; + +public class Stanik extends Module { + private ZMI hierarchy; + + public Stanik() { + super(ModuleType.STATE); + hierarchy = new ZMI(); + } + + public void handleTyped(StanikMessage message) throws InterruptedException, InvalidMessageType { + switch(message.getType()) { + case GET_HIERARCHY: + handleGetHierarchy((GetHierarchyMessage) message); + break; + default: + throw new InvalidMessageType("This type of message cannot be handled by Stanik"); + } + } + + public void handleGetHierarchy(GetHierarchyMessage message) throws InterruptedException { + HierarchyMessage response = new HierarchyMessage("", message.getRequestingModule(), 0, message.getRequestId(), hierarchy.clone()); + sendMessage(response); + } +} -- cgit v1.2.3 From 5f7e37d7b26832b3b512f9dda310cb9bc92c93fb Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Fri, 27 Dec 2019 21:08:44 +0100 Subject: Create new zones with UpdateAttributes message --- .../edu/mimuw/cloudatlas/agent/modules/Stanik.java | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'src/main/java/pl/edu/mimuw/cloudatlas/agent/modules') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java index b8db08a..a457a94 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -1,9 +1,17 @@ package pl.edu.mimuw.cloudatlas.agent.modules; +import java.util.Map.Entry; + import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; import pl.edu.mimuw.cloudatlas.agent.messages.GetHierarchyMessage; import pl.edu.mimuw.cloudatlas.agent.messages.HierarchyMessage; import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.UpdateAttributesMessage; +import pl.edu.mimuw.cloudatlas.model.AttributesMap; +import pl.edu.mimuw.cloudatlas.model.Attribute; +import pl.edu.mimuw.cloudatlas.model.PathName; +import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueString; import pl.edu.mimuw.cloudatlas.model.ZMI; public class Stanik extends Module { @@ -19,6 +27,9 @@ public class Stanik extends Module { case GET_HIERARCHY: handleGetHierarchy((GetHierarchyMessage) message); break; + case UPDATE_ATTRIBUTES: + handleUpdateAttributes((UpdateAttributesMessage) message); + break; default: throw new InvalidMessageType("This type of message cannot be handled by Stanik"); } @@ -28,4 +39,41 @@ public class Stanik extends Module { HierarchyMessage response = new HierarchyMessage("", message.getRequestingModule(), 0, message.getRequestId(), hierarchy.clone()); sendMessage(response); } + + public void handleUpdateAttributes(UpdateAttributesMessage message) { + try { + addMissingZones(new PathName(message.getPathName())); + ZMI zone = hierarchy.findDescendant(message.getPathName()); + for (Entry entry : zone.getAttributes()) { + Attribute attribute = entry.getKey(); + Value newValue = message.getAttributes().getOrNull(attribute); + if (newValue == null) { + zone.getAttributes().remove(attribute); + } + } + for (Entry entry : message.getAttributes()) { + zone.getAttributes().addOrChange(entry.getKey(), entry.getValue()); + } + } catch (ZMI.NoSuchZoneException e) { + System.out.println("ERROR: zone should exist after being added"); + } + } + + private void addMissingZones(PathName path) { + try { + if (!hierarchy.descendantExists(path)) { + addMissingZones(path.levelUp()); + ZMI parent = hierarchy.findDescendant(path.levelUp()); + ZMI newSon = new ZMI(parent); + newSon.getAttributes().add("name", new ValueString(path.getSingletonName())); + parent.addSon(newSon); + } + } catch (ZMI.NoSuchZoneException e) { + System.out.println("ERROR: zone should exist after being added"); + } + } + + public ZMI getHierarchy() { + return hierarchy; + } } -- cgit v1.2.3 From 8e0aed0711a26fec5c0497cee9777744f1d48663 Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Sat, 28 Dec 2019 15:47:06 +0100 Subject: Apply only fresher attributes --- .../edu/mimuw/cloudatlas/agent/modules/Stanik.java | 83 +++++++++++++++++++--- 1 file changed, 74 insertions(+), 9 deletions(-) (limited to 'src/main/java/pl/edu/mimuw/cloudatlas/agent/modules') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java index a457a94..76ca0b6 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -1,5 +1,6 @@ package pl.edu.mimuw.cloudatlas.agent.modules; +import java.util.Iterator; import java.util.Map.Entry; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; @@ -10,16 +11,27 @@ import pl.edu.mimuw.cloudatlas.agent.messages.UpdateAttributesMessage; import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.Attribute; import pl.edu.mimuw.cloudatlas.model.PathName; +import pl.edu.mimuw.cloudatlas.model.Type; +import pl.edu.mimuw.cloudatlas.model.TypePrimitive; import pl.edu.mimuw.cloudatlas.model.Value; +import pl.edu.mimuw.cloudatlas.model.ValueBoolean; import pl.edu.mimuw.cloudatlas.model.ValueString; +import pl.edu.mimuw.cloudatlas.model.ValueTime; import pl.edu.mimuw.cloudatlas.model.ZMI; public class Stanik extends Module { + private class InvalidUpdateAttributesMessage extends Exception { + public InvalidUpdateAttributesMessage(String message) { + super(message); + } + } + private ZMI hierarchy; public Stanik() { super(ModuleType.STATE); hierarchy = new ZMI(); + hierarchy.getAttributes().add("timestamp", new ValueTime(0l)); } public void handleTyped(StanikMessage message) throws InterruptedException, InvalidMessageType { @@ -42,23 +54,75 @@ public class Stanik extends Module { public void handleUpdateAttributes(UpdateAttributesMessage message) { try { + validateUpdateAttributesMessage(message); addMissingZones(new PathName(message.getPathName())); ZMI zone = hierarchy.findDescendant(message.getPathName()); - for (Entry entry : zone.getAttributes()) { - Attribute attribute = entry.getKey(); - Value newValue = message.getAttributes().getOrNull(attribute); - if (newValue == null) { - zone.getAttributes().remove(attribute); - } - } - for (Entry entry : message.getAttributes()) { - zone.getAttributes().addOrChange(entry.getKey(), entry.getValue()); + AttributesMap attributes = zone.getAttributes(); + if (valueLower(attributes.get("timestamp"), message.getAttributes().get("timestamp"))) { + transferAttributes(message.getAttributes(), attributes); + } else { + System.out.println("DEBUG: not applying update with older attributes"); } + } catch (InvalidUpdateAttributesMessage e) { + System.out.println("ERROR: invalid UpdateAttributesMessage " + e.getMessage()); } catch (ZMI.NoSuchZoneException e) { System.out.println("ERROR: zone should exist after being added"); } } + private boolean valueLower(Value a, Value b) { + return ((ValueBoolean) a.isLowerThan(b)).getValue(); + } + + private void validateUpdateAttributesMessage(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + validateZoneName(message); + validateHasTimeStamp(message); + } + + private void validateZoneName(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + Value name = message.getAttributes().getOrNull("name"); + if (message.getPathName().equals("/")) { + if (name != null && !name.isNull()) { + throw new InvalidUpdateAttributesMessage("The root zone should have a null name"); + } + } else { + if (valueNonNullOfType(name, TypePrimitive.STRING)) { + ValueString nameString = (ValueString) name; + String expectedName = (new PathName(message.getPathName())).getSingletonName(); + if (!nameString.getValue().equals(expectedName)) { + throw new InvalidUpdateAttributesMessage("The zone's name attribute should match its path name"); + } + } else { + throw new InvalidUpdateAttributesMessage("Zone attributes should have a name attribute of type String"); + } + } + } + + private void validateHasTimeStamp(UpdateAttributesMessage message) throws InvalidUpdateAttributesMessage { + if (!valueNonNullOfType(message.getAttributes().getOrNull("timestamp"), TypePrimitive.TIME)) { + throw new InvalidUpdateAttributesMessage("Zone attriutes should have a timestamp attribute of type Time"); + } + } + + private boolean valueNonNullOfType(Value value, Type type) { + return value != null && !value.isNull() && value.getType().isCompatible(type); + } + + private void transferAttributes(AttributesMap fromAttributes, AttributesMap toAttributes) { + Iterator> iterator = toAttributes.iterator(); + while (iterator.hasNext()) { + Entry entry = iterator.next(); + Attribute attribute = entry.getKey(); + Value newValue = fromAttributes.getOrNull(attribute); + if (newValue == null) { + iterator.remove(); + } + } + for (Entry entry : fromAttributes) { + toAttributes.addOrChange(entry.getKey(), entry.getValue()); + } + } + private void addMissingZones(PathName path) { try { if (!hierarchy.descendantExists(path)) { @@ -66,6 +130,7 @@ public class Stanik extends Module { ZMI parent = hierarchy.findDescendant(path.levelUp()); ZMI newSon = new ZMI(parent); newSon.getAttributes().add("name", new ValueString(path.getSingletonName())); + newSon.getAttributes().add("timestamp", new ValueTime(0l)); parent.addSon(newSon); } } catch (ZMI.NoSuchZoneException e) { -- cgit v1.2.3 From af6f6f37403d0e23a09a6ba4476271c2a0eaf623 Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Sun, 29 Dec 2019 14:12:31 +0100 Subject: Include timestamped queries in state --- .../edu/mimuw/cloudatlas/agent/modules/Stanik.java | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'src/main/java/pl/edu/mimuw/cloudatlas/agent/modules') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java index 76ca0b6..a31f265 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -1,20 +1,22 @@ package pl.edu.mimuw.cloudatlas.agent.modules; import java.util.Iterator; +import java.util.HashMap; import java.util.Map.Entry; import pl.edu.mimuw.cloudatlas.agent.messages.AgentMessage; -import pl.edu.mimuw.cloudatlas.agent.messages.GetHierarchyMessage; -import pl.edu.mimuw.cloudatlas.agent.messages.HierarchyMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.GetStateMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.StateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; import pl.edu.mimuw.cloudatlas.agent.messages.UpdateAttributesMessage; -import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.Attribute; +import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.PathName; import pl.edu.mimuw.cloudatlas.model.Type; import pl.edu.mimuw.cloudatlas.model.TypePrimitive; import pl.edu.mimuw.cloudatlas.model.Value; import pl.edu.mimuw.cloudatlas.model.ValueBoolean; +import pl.edu.mimuw.cloudatlas.model.ValueQuery; import pl.edu.mimuw.cloudatlas.model.ValueString; import pl.edu.mimuw.cloudatlas.model.ValueTime; import pl.edu.mimuw.cloudatlas.model.ZMI; @@ -27,17 +29,19 @@ public class Stanik extends Module { } private ZMI hierarchy; + private HashMap> queries; public Stanik() { super(ModuleType.STATE); hierarchy = new ZMI(); + queries = new HashMap>(); hierarchy.getAttributes().add("timestamp", new ValueTime(0l)); } public void handleTyped(StanikMessage message) throws InterruptedException, InvalidMessageType { switch(message.getType()) { - case GET_HIERARCHY: - handleGetHierarchy((GetHierarchyMessage) message); + case GET_STATE: + handleGetState((GetStateMessage) message); break; case UPDATE_ATTRIBUTES: handleUpdateAttributes((UpdateAttributesMessage) message); @@ -47,8 +51,8 @@ public class Stanik extends Module { } } - public void handleGetHierarchy(GetHierarchyMessage message) throws InterruptedException { - HierarchyMessage response = new HierarchyMessage("", message.getRequestingModule(), 0, message.getRequestId(), hierarchy.clone()); + public void handleGetState(GetStateMessage message) throws InterruptedException { + StateMessage response = new StateMessage("", message.getRequestingModule(), 0, message.getRequestId(), hierarchy.clone(), (HashMap>) queries.clone()); sendMessage(response); } @@ -141,4 +145,8 @@ public class Stanik extends Module { public ZMI getHierarchy() { return hierarchy; } + + public HashMap> getQueries() { + return queries; + } } -- cgit v1.2.3 From c3121bfa6c00682173a7f1fba9d4c524b8ef517e Mon Sep 17 00:00:00 2001 From: Marcin Chrzanowski Date: Sun, 29 Dec 2019 16:49:43 +0100 Subject: Handle queries in state --- .../pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/main/java/pl/edu/mimuw/cloudatlas/agent/modules') diff --git a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java index a31f265..e8721b3 100644 --- a/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java +++ b/src/main/java/pl/edu/mimuw/cloudatlas/agent/modules/Stanik.java @@ -9,6 +9,7 @@ import pl.edu.mimuw.cloudatlas.agent.messages.GetStateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.StateMessage; import pl.edu.mimuw.cloudatlas.agent.messages.StanikMessage; import pl.edu.mimuw.cloudatlas.agent.messages.UpdateAttributesMessage; +import pl.edu.mimuw.cloudatlas.agent.messages.UpdateQueriesMessage; import pl.edu.mimuw.cloudatlas.model.Attribute; import pl.edu.mimuw.cloudatlas.model.AttributesMap; import pl.edu.mimuw.cloudatlas.model.PathName; @@ -46,6 +47,9 @@ public class Stanik extends Module { case UPDATE_ATTRIBUTES: handleUpdateAttributes((UpdateAttributesMessage) message); break; + case UPDATE_QUERIES: + handleUpdateQueries((UpdateQueriesMessage) message); + break; default: throw new InvalidMessageType("This type of message cannot be handled by Stanik"); } @@ -74,6 +78,17 @@ public class Stanik extends Module { } } + public void handleUpdateQueries(UpdateQueriesMessage message) { + for (Entry> entry : message.getQueries().entrySet()) { + Attribute attribute = entry.getKey(); + ValueTime timestamp = entry.getValue().getValue(); + Entry currentTimestampedQuery = queries.get(attribute); + if (currentTimestampedQuery == null || valueLower(currentTimestampedQuery.getValue(), timestamp)) { + queries.put(entry.getKey(), entry.getValue()); + } + } + } + private boolean valueLower(Value a, Value b) { return ((ValueBoolean) a.isLowerThan(b)).getValue(); } -- cgit v1.2.3