You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2014/07/25 19:57:00 UTC
[04/11] git commit: ServerPools refuse to remove manually-added
machines until they are stopped
ServerPools refuse to remove manually-added machines until they are stopped
Project: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/commit/f1a465c0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/tree/f1a465c0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/diff/f1a465c0
Branch: refs/heads/master
Commit: f1a465c01e75ba143dd4a1137ef13501ce058be6
Parents: e7f1291
Author: Sam Corbett <sa...@cloudsoftcorp.com>
Authored: Tue Jul 22 19:47:14 2014 +0100
Committer: Sam Corbett <sa...@cloudsoftcorp.com>
Committed: Tue Jul 22 19:47:14 2014 +0100
----------------------------------------------------------------------
.../brooklyn/entity/pool/ServerPoolImpl.java | 95 +++++++++++++-------
.../brooklyn/entity/pool/ServerPoolTest.java | 40 +++++++--
2 files changed, 99 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f1a465c0/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
index 1ef26e3..c0b88cd 100644
--- a/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
+++ b/software/base/src/main/java/brooklyn/entity/pool/ServerPoolImpl.java
@@ -30,7 +30,6 @@ import brooklyn.entity.Entity;
import brooklyn.entity.basic.Attributes;
import brooklyn.entity.basic.ConfigKeys;
import brooklyn.entity.basic.EntityInternal;
-import brooklyn.entity.basic.EntityPredicates;
import brooklyn.entity.basic.Lifecycle;
import brooklyn.entity.effector.Effectors;
import brooklyn.entity.group.AbstractMembershipTrackingPolicy;
@@ -55,6 +54,7 @@ import brooklyn.util.task.DynamicTasks;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -68,8 +68,14 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
private static final Logger LOG = LoggerFactory.getLogger(ServerPoolImpl.class);
private static enum MachinePoolMemberStatus {
+ /** The server is available for use */
AVAILABLE,
+ /** The server has been leased to another application */
CLAIMED,
+ /**
+ * The server will not be leased to other applications. It will be the first
+ * candidate to release when the pool is shrunk.
+ */
UNUSABLE
}
@@ -129,6 +135,10 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
public void stop() {
super.stop();
deleteLocation();
+ setAttribute(AVAILABLE_COUNT, 0);
+ setAttribute(CLAIMED_COUNT, 0);
+ getAttribute(ENTITY_MACHINE).clear();
+ getAttribute(MACHINE_ENTITY).clear();
}
private void addMembershipTrackerPolicy() {
@@ -180,10 +190,12 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
LOG.debug("{} deleting and unmanaging location {}", this, location);
mgr.unmanage(location);
}
+ // definition will only be null if deleteLocation has already been called, e.g. by two calls to stop().
LocationDefinition definition = getAttribute(DYNAMIC_LOCATION_DEFINITION);
- LOG.debug("{} unregistering dynamic location {}", this, definition);
- getManagementContext().getLocationRegistry().removeDefinedLocation(definition.getId());
-
+ if (definition != null) {
+ LOG.debug("{} unregistering dynamic location {}", this, definition);
+ getManagementContext().getLocationRegistry().removeDefinedLocation(definition.getId());
+ }
setAttribute(LOCATION_SPEC, null);
setAttribute(DYNAMIC_LOCATION, null);
setAttribute(LOCATION_NAME, null);
@@ -247,10 +259,10 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
Iterable<MachineLocation> machines = FluentIterable.from(location.getChildren())
.filter(MachineLocation.class);
LOG.info("{} adding additional machines: {}", this, machines);
- synchronized (mutex) {
- for (MachineLocation machine : machines) {
- additions.add(addExistingMachine(machine));
- }
+ // Doesn't need to be synchronised on mutex: it will be claimed per-machine
+ // as the new members are handled by the membership tracking policy.
+ for (MachineLocation machine : machines) {
+ additions.add(addExistingMachine(machine));
}
LOG.debug("{} added additional machines", this);
}
@@ -268,14 +280,26 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
*/
@Override
protected Collection<Entity> shrink(int delta) {
+ if (Lifecycle.STOPPING.equals(getAttribute(Attributes.SERVICE_STATE))) {
+ return super.shrink(delta);
+ }
+
synchronized (mutex) {
- int unusable = Iterables.size(getMembersWithStatus(MachinePoolMemberStatus.UNUSABLE));
- int removeable = getAttribute(AVAILABLE_COUNT) + unusable;
- if (-delta > removeable && !Lifecycle.STOPPING.equals(getAttribute(Attributes.SERVICE_STATE))) {
- LOG.info("Too few unclaimed machines in {} to shrink by delta {}. Altered delta to {}",
- new Object[]{this, delta, -removeable});
- delta = -removeable;
+ int removable = 0;
+ for (Entity entity : getMembers()) {
+ // Skip machine marked not for removal and machines that are claimed
+ if (!Boolean.FALSE.equals(entity.getConfig(REMOVABLE)) &&
+ !MachinePoolMemberStatus.CLAIMED.equals(entity.getAttribute(SERVER_STATUS))) {
+ removable -= 1;
+ }
+ }
+
+ if (delta < removable) {
+ LOG.info("Too few removable machines in {} to shrink by delta {}. Altered delta to {}",
+ new Object[]{this, delta, removable});
+ delta = removable;
}
+
Collection<Entity> removed = super.shrink(delta);
updateCountSensors();
return removed;
@@ -291,11 +315,6 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
}
@Override
- public Integer getCurrentSize() {
- return super.getCurrentSize();
- }
-
- @Override
public Function<Collection<Entity>, Entity> getRemovalStrategy() {
return UNCLAIMED_REMOVAL_STRATEGY;
}
@@ -303,12 +322,15 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
private final Function<Collection<Entity>, Entity> UNCLAIMED_REMOVAL_STRATEGY = new Function<Collection<Entity>, Entity>() {
// Semantics of superclass mean that mutex should already be held when apply is called
@Override
- public Entity apply(Collection<Entity> input) {
+ public Entity apply(Collection<Entity> members) {
synchronized (mutex) {
- Optional<Entity> choice = getMemberWithStatus(MachinePoolMemberStatus.UNUSABLE)
- .or(getMemberWithStatus(MachinePoolMemberStatus.AVAILABLE));
- if (!choice.isPresent() && Lifecycle.STOPPING.equals(getAttribute(Attributes.SERVICE_STATE))) {
- choice = getMemberWithStatus(MachinePoolMemberStatus.CLAIMED);
+ Optional<Entity> choice;
+ if (Lifecycle.STOPPING.equals(getAttribute(Attributes.SERVICE_STATE))) {
+ choice = Optional.of(members.iterator().next());
+ } else {
+ // Otherwise should only choose between removable + unusable or available
+ choice = getMemberWithStatusExcludingUnremovable(members, MachinePoolMemberStatus.UNUSABLE)
+ .or(getMemberWithStatusExcludingUnremovable(members, MachinePoolMemberStatus.AVAILABLE));
}
if (!choice.isPresent()) {
LOG.warn("{} has no machines available to remove!", this);
@@ -352,13 +374,27 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
}
private Optional<Entity> getMemberWithStatus(MachinePoolMemberStatus status) {
- return Iterables.tryFind(getMembers(),
- EntityPredicates.attributeEqualTo(SERVER_STATUS, status));
+ return getMemberWithStatus0(getMembers(), status, true);
}
- private Iterable<Entity> getMembersWithStatus(MachinePoolMemberStatus status) {
- return Iterables.filter(getMembers(),
- EntityPredicates.attributeEqualTo(SERVER_STATUS, status));
+ private Optional<Entity> getMemberWithStatusExcludingUnremovable(Collection<Entity> entities, MachinePoolMemberStatus status) {
+ return getMemberWithStatus0(entities, status, false);
+ }
+
+ private Optional<Entity> getMemberWithStatus0(Collection<Entity> entities, final MachinePoolMemberStatus status, final boolean includeUnremovableMachines) {
+ return Iterables.tryFind(entities,
+ new Predicate<Entity>() {
+ @Override
+ public boolean apply(Entity input) {
+ return (includeUnremovableMachines || isRemovable(input)) &&
+ status.equals(input.getAttribute(SERVER_STATUS));
+ }
+ });
+ }
+
+ /** @return true if the entity has {@link #REMOVABLE} set to null or true. */
+ private boolean isRemovable(Entity entity) {
+ return !Boolean.FALSE.equals(entity.getConfig(REMOVABLE));
}
private void updateCountSensors() {
@@ -377,7 +413,6 @@ public class ServerPoolImpl extends DynamicClusterImpl implements ServerPool {
}
}
-
public static class MemberTrackingPolicy extends AbstractMembershipTrackingPolicy {
@Override
protected void onEntityEvent(EventType type, Entity member) {
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/f1a465c0/software/base/src/test/java/brooklyn/entity/pool/ServerPoolTest.java
----------------------------------------------------------------------
diff --git a/software/base/src/test/java/brooklyn/entity/pool/ServerPoolTest.java b/software/base/src/test/java/brooklyn/entity/pool/ServerPoolTest.java
index 88317ea..f565c54 100644
--- a/software/base/src/test/java/brooklyn/entity/pool/ServerPoolTest.java
+++ b/software/base/src/test/java/brooklyn/entity/pool/ServerPoolTest.java
@@ -22,10 +22,14 @@ import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
+import java.util.Collection;
+import java.util.Iterator;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.Test;
+import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
@@ -34,6 +38,7 @@ import brooklyn.entity.basic.Attributes;
import brooklyn.location.LocationSpec;
import brooklyn.location.basic.LocalhostMachineProvisioningLocation.LocalhostMachine;
import brooklyn.test.Asserts;
+import brooklyn.test.EntityTestUtils;
import brooklyn.test.entity.TestApplication;
public class ServerPoolTest extends AbstractServerPoolTest {
@@ -134,16 +139,39 @@ public class ServerPoolTest extends AbstractServerPoolTest {
LocalhostMachine loc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachine.class));
Entity added = pool.addExistingMachine(loc);
assertFalse(added.getConfig(ServerPoolImpl.REMOVABLE));
- Asserts.succeedsEventually(new Runnable() {
- @Override
- public void run() {
- assertAvailableCountEquals(1);
- }
- });
+ assertAvailableCountEventuallyEquals(1);
TestApplication app2 = createAppWithChildren(1);
app2.start(ImmutableList.of(pool.getDynamicLocation()));
assertAvailableCountEquals(0);
}
+ @Test
+ public void testExistingMachinesAreNotRemovedFromThePoolOnShrinkButAreOnStop() {
+ LocalhostMachine loc = mgmt.getLocationManager().createLocation(LocationSpec.create(LocalhostMachine.class));
+ pool.addExistingMachine(loc);
+ assertAvailableCountEventuallyEquals(getInitialPoolSize() + 1);
+ pool.resize(0);
+ assertAvailableCountEventuallyEquals(1);
+ pool.stop();
+ assertAvailableCountEventuallyEquals(0);
+ }
+
+ @Test
+ public void testAddExistingMachineFromSpec() {
+ TestApplication app = createAppWithChildren(getInitialPoolSize());
+ app.start(ImmutableList.of(pool.getDynamicLocation()));
+ assertAvailableCountEquals(0);
+
+ Collection<Entity> added = pool.addExistingMachinesFromSpec("byon:(hosts=\"localhost,localhost\")");
+ assertEquals(added.size(), 2, "Added: " + Joiner.on(", ").join(added));
+ Iterator<Entity> it = added.iterator();
+ assertFalse(it.next().getConfig(ServerPoolImpl.REMOVABLE));
+ assertFalse(it.next().getConfig(ServerPoolImpl.REMOVABLE));
+ assertAvailableCountEventuallyEquals(2);
+
+ TestApplication app2 = createAppWithChildren(2);
+ app2.start(ImmutableList.of(pool.getDynamicLocation()));
+ assertAvailableCountEquals(0);
+ }
}