-
Notifications
You must be signed in to change notification settings - Fork 594
Conversation
@@ -229,6 +229,11 @@ public boolean equals(Object o) { | |||
} | |||
|
|||
@Override | |||
public int compareTo(ContainerPlan c) { | |||
return Integer.compare(this.getId(), c.getId()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we choose to implement Comparable
we must assure that if thisContainer.compareTo(thatContainer) == 0
then thisContainer.equals(thatContainer)
, which isn't currently the case. It implies implementing Comparable
for all child objects and including them in the comparison.
See http://docs.oracle.com/javase/8/docs/api/java/lang/Comparable.html#compareTo-T-
new InstanceId("bolt", 3, 0))); | ||
packing.put(3, Arrays.asList(new InstanceId("spout", 2, 1))); | ||
packing.put(2, Arrays.asList(new InstanceId("spout", 4, 1))); | ||
PackingPlan packingPlan = generatePacking(packing); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cleaner to use PackingTestUtils.testContainerPlan(..)
repeatedly to construct an Array<ContainerPlan>
.
packing.put(2, Arrays.asList(new InstanceId("spout", 4, 1))); | ||
PackingPlan packingPlan = generatePacking(packing); | ||
|
||
Object[] currentContainers = packingPlan.getContainers().toArray(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Best to work with ContainerPlan[]
here instead of Object[]
.
} | ||
} | ||
Assert.assertEquals("Components " + component + " found in the container plans: ", | ||
instancesFound, numInstances); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The output of the assertion classes on failure expect the param ordering to be [expectedValue, foundValue]
.
return instanceIds.get(i); | ||
} | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Optional instead of null. See #1311
* @param firstTaskIndex first taskId to use for the new instances | ||
*/ | ||
private void assignInstancesToContainers( | ||
ArrayList<Container> containers, Map<Integer, List<InstanceId>> allocation, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like we're stretching our use of Lists and Maps in the signature here, by passing a mutable list of containers and a map of containers to instance lists. Instead can we use an object that encapsulated all of that? Like a PackingPlan object or a variant of it? Some container object that is able to effectively mutate a plan? Maybe a Builder that takes a packing plan, allows update methods to be called to change internal state, and then produces a new plan with a build() method?
@@ -313,4 +457,22 @@ private int allocateNewContainer(ArrayList<Container> containers) { | |||
containers.add(new Container(maxContainerResources)); | |||
return containers.size(); | |||
} | |||
|
|||
private class IdPair { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return new IdPair(containerId, instanceId); | ||
} | ||
} | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use Optional instead of null. Or make this method return void if the caller doesn't care either way. See #1311
/** | ||
* Removes containers from tha allocation that do not contain any instances | ||
*/ | ||
private void cleanAllocation(Map<Integer, List<InstanceId>> allocation) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removeEmpyContainers(..)
?
* Removes containers from tha allocation that do not contain any instances | ||
*/ | ||
private void cleanAllocation(Map<Integer, List<InstanceId>> allocation) { | ||
Iterator<Map.Entry<Integer, List<InstanceId>>> entries = allocation.entrySet().iterator(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of iterating over entries it's more idiomatic (and reads easier IMO since it's always obvious what the key and value represents by their naming) to iterate over keys:
Iterator<Integer> containerIds = allocation.keySet().iterator();
while (containerIds.hasNext() {
Integer containerId = containerIds.next();
if (allocation.get(containerId) == null)
allocation.remove(containerId);
...
Or even better using for (Integer containerId : allocation.keySet())
if that doesn't cause issues during deletion.
@billonahill I addressed all the comments except for the packing builder object. I need to think more about it. |
@@ -59,14 +67,48 @@ private boolean hasSpace(long ram, double cpuCores, long disk) { | |||
* | |||
* @return true if the instance can be added to the container, false otherwise | |||
*/ | |||
public boolean add(Resource resource) { | |||
public boolean add(Resource resource, InstanceId instanceId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An instance id with resources is an InstancePlan. Could we instead take an InstancePlan here and keep a Set of those? That way we don't need to separately track the sum of all resources for each add/remove.
If we do that we also don't need to pass a different resource to the remove method than the one that we know is bound to the instance. Currently the two aren't bound to each other, but there seems to be an assumption that the one passed is the same as that of the instance found and removed.
public Optional<InstanceId> removeAnyInstanceOfComponent(Resource resource, String component) { | ||
Optional<InstanceId> instanceId = getAnyInstanceOfComponent(component); | ||
if (instanceId.isPresent()) { | ||
usedRam -= resource.getRam(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When accessing class member variables, best to use self.usedRam
here and elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to disregard this comment, as we don't follow this standard in many places.
|
||
@Override | ||
public String toString() { | ||
return componentName + " " + taskId + " " + componentIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of string concatenation, better to use String.format("%s %d %d", ...)
Assert.assertEquals(packingPlan.getContainers().size(), 2); | ||
Assert.assertEquals(totalInstances, packingPlan.getInstanceCount()); | ||
AssertPacking.assertNumInstances(packingPlan.getContainers(), BOLT_NAME, 3); | ||
AssertPacking.assertNumInstances(packingPlan.getContainers(), SPOUT_NAME, 4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The first 7 lines here are duplicated in 5 tests. Could you pull those out into an initScalingTests()
method or maybe something like this, followed by assertions on the returned plan:
PackingPlan doScalingTest(Map<String, Integer> componentChanges) {}
* @param containers | ||
* @return sorted array of container plans | ||
*/ | ||
public static PackingPlan.ContainerPlan[] sortOnContainerId( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add back the PackingPlanTest.testContainerSorting
from the earlier review as PackingUtilsTest.testContainerSorting
?
@billonahill I addressed all the comments. We have some ideas about the packing builder. Will submit that later. |
if (instancePlan.isPresent()) { | ||
PackingPlan.InstancePlan plan = instancePlan.get(); | ||
this.instances.remove(plan); | ||
return Optional.of(plan); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of creating a new Optional you could return the same one removed: instancePlan
.
private long usedRam; | ||
private double usedCpuCores; | ||
private long usedDisk; | ||
private HashSet<PackingPlan.InstancePlan> instances; | ||
|
||
//Maximum resources that can be assigned to the container. | ||
private long maxRam; | ||
private double maxCpuCores; | ||
private long maxDisk; | ||
|
||
public Container(Resource resource) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to make it clear what this resource is, can we call it something like capacity
and clarify it's use in the javadoc for the costructor?
private long usedRam; | ||
private double usedCpuCores; | ||
private long usedDisk; | ||
private HashSet<PackingPlan.InstancePlan> instances; | ||
|
||
//Maximum resources that can be assigned to the container. | ||
private long maxRam; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of storing each part of the resource passed, can we just store the resource itself?
@Test | ||
public void testContainerSortOnId() { | ||
|
||
PackingPlan packingPlan = getFirstFitDecreasingPackingPlan(topology); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an indirect way to test container sorting. Could we instead write this test without a dep on FirstFitDecreasingPacking and just pass a Set of containers to sortOnContainerId and assert the returned ordering? That way we can directly test the utility method without going through the FirstFitDecreasingPacking code, which should be tested in it's own test suite/class.
@@ -81,6 +81,35 @@ private static PackingPlan getFirstFitDecreasingPackingPlanRepack( | |||
return packing.repack(currentPackingPlan, componentChanges); | |||
} | |||
|
|||
PackingPlan doScalingTest(TopologyAPI.Topology t, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TopologyAPI.Topology topology
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@billonahill This gives me a checkstyle error that that the topology hides a field because the class contains a topology member. This is the reason I used t.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could make the method static and pass totalInstances
in as totalExpectedInstances
* Creates a container with a specific capacity | ||
* @param maxResource the capacity of the container in terms of cpu, ram and disk | ||
*/ | ||
public Container(Resource maxResource) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using both capacity and maxResource, how about just capacity?
One last naming nit and then lgtm! Thanks! |
@billonahill Thanks for the comments. I think we can merge now. |
* AssignInsatnces takes into account previous state * Scale down support * Address review comments * Address comments in second review * Addressed review comments
This is related to #1362