brooklyn-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From henev...@apache.org
Subject [11/23] brooklyn-server git commit: Adds configurable removal strategies
Date Fri, 13 May 2016 09:05:21 GMT
Adds configurable removal strategies


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/0ebd0669
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/0ebd0669
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/0ebd0669

Branch: refs/heads/master
Commit: 0ebd0669ed9e80dc7968edff269ed2100d0e7e64
Parents: a5d65fd
Author: Martin Harris <github@nakomis.com>
Authored: Tue Apr 12 13:23:36 2016 +0100
Committer: Martin Harris <github@nakomis.com>
Committed: Mon May 9 10:57:15 2016 +0100

----------------------------------------------------------------------
 .../entity/group/DynamicClusterImpl.java        | 18 ++++---
 .../entity/group/FirstFromRemovalStrategy.java  | 53 ++++++++++++++++++++
 .../brooklyn/entity/group/RemovalStrategy.java  | 30 +++++++++++
 .../group/SensorMatchingRemovalStrategy.java    | 50 ++++++++++++++++++
 .../entity/group/DynamicClusterTest.java        | 51 +++++++++++++++++++
 5 files changed, 194 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0ebd0669/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
index db263d7..3577004 100644
--- a/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/DynamicClusterImpl.java
@@ -151,12 +151,14 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements
DynamicClus
      */
     protected final Object mutex = new Object[0];
 
-    private static final Function<Collection<Entity>, Entity> defaultRemovalStrategy
= new Function<Collection<Entity>, Entity>() {
-        @Override public Entity apply(Collection<Entity> contenders) {
+    public static class DefaultRemovalStrategy extends RemovalStrategy {
+        @Nullable
+        @Override
+        public Entity apply(@Nullable Collection<Entity> contenders) {
             /*
              * Choose the newest entity (largest cluster member ID or latest timestamp) that
is stoppable.
              * If none are stoppable, take the newest non-stoppable.
-             * 
+             *
              * Both cluster member ID and timestamp must be taken into consideration to account
for legacy
              * clusters that were created before the addition of the cluster member ID config
value.
              */
@@ -171,8 +173,8 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
                 boolean newer = (contenderClusterMemberId != null && contenderClusterMemberId
> largestClusterMemberId) ||
                         contenderCreationTime > newestTime;
 
-                if ((contender instanceof Startable && newer) || 
-                    (!(newest instanceof Startable) && ((contender instanceof Startable)
|| newer))) {
+                if ((contender instanceof Startable && newer) ||
+                        (!(newest instanceof Startable) && ((contender instanceof
Startable) || newer))) {
                     newest = contender;
 
                     if (contenderClusterMemberId != null) largestClusterMemberId = contenderClusterMemberId;
@@ -182,7 +184,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
 
             return newest;
         }
-    };
+    }
 
     private static class NextClusterMemberIdSupplier implements Supplier<Integer> {
         private AtomicInteger nextId = new AtomicInteger(0);
@@ -259,7 +261,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
         // override previous enricher so that only members are checked
         ServiceStateLogic.newEnricherFromChildrenUp().checkMembersOnly().requireUpChildren(getConfig(UP_QUORUM_CHECK)).addTo(this);
     }
-    
+
     @Override
     public void setRemovalStrategy(Function<Collection<Entity>, Entity> val)
{
         config().set(REMOVAL_STRATEGY, checkNotNull(val, "removalStrategy"));
@@ -267,7 +269,7 @@ public class DynamicClusterImpl extends AbstractGroupImpl implements DynamicClus
 
     protected Function<Collection<Entity>, Entity> getRemovalStrategy() {
         Function<Collection<Entity>, Entity> result = getConfig(REMOVAL_STRATEGY);
-        return (result != null) ? result : defaultRemovalStrategy;
+        return (result != null) ? result : new DefaultRemovalStrategy();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0ebd0669/core/src/main/java/org/apache/brooklyn/entity/group/FirstFromRemovalStrategy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/FirstFromRemovalStrategy.java
b/core/src/main/java/org/apache/brooklyn/entity/group/FirstFromRemovalStrategy.java
new file mode 100644
index 0000000..9af48f0
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/FirstFromRemovalStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
+
+public class FirstFromRemovalStrategy extends RemovalStrategy {
+
+    public static final ConfigKey<List<RemovalStrategy>> STRATEGIES = ConfigKeys.newConfigKey(new
TypeToken<List<RemovalStrategy>>() {}, "firstfrom.strategies",
+            "An ordered list of removal strategies to be used to determine which entity to
remove");
+
+    @Nullable
+    @Override
+    public Entity apply(@Nullable Collection<Entity> input) {
+        List<RemovalStrategy> strategies = config().get(STRATEGIES);
+        if (strategies == null || Iterables.isEmpty(strategies)) {
+            return null;
+        }
+        for (RemovalStrategy strategy : strategies) {
+            Entity entity = strategy.apply(input);
+            if (entity != null) {
+                return entity;
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0ebd0669/core/src/main/java/org/apache/brooklyn/entity/group/RemovalStrategy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/RemovalStrategy.java b/core/src/main/java/org/apache/brooklyn/entity/group/RemovalStrategy.java
new file mode 100644
index 0000000..61fc3fa
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/RemovalStrategy.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import java.util.Collection;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.core.objs.BasicConfigurableObject;
+
+import com.google.common.base.Function;
+
+public abstract class RemovalStrategy extends BasicConfigurableObject implements Function<Collection<Entity>,
Entity> {
+
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0ebd0669/core/src/main/java/org/apache/brooklyn/entity/group/SensorMatchingRemovalStrategy.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/brooklyn/entity/group/SensorMatchingRemovalStrategy.java
b/core/src/main/java/org/apache/brooklyn/entity/group/SensorMatchingRemovalStrategy.java
new file mode 100644
index 0000000..037da44
--- /dev/null
+++ b/core/src/main/java/org/apache/brooklyn/entity/group/SensorMatchingRemovalStrategy.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.brooklyn.entity.group;
+
+import java.util.Collection;
+import java.util.Objects;
+
+import javax.annotation.Nullable;
+
+import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.config.ConfigKey;
+import org.apache.brooklyn.core.config.ConfigKeys;
+
+import com.google.common.reflect.TypeToken;
+
+public class SensorMatchingRemovalStrategy<T> extends RemovalStrategy {
+    public static final ConfigKey<AttributeSensor> SENSOR = ConfigKeys.newConfigKey(new
TypeToken<AttributeSensor>() {}, "sensor.matching.sensor");
+    // Would be nice to use ConfigKey<T>, but TypeToken<T> cannot be instantiated
at runtime
+    public static final ConfigKey<Object> DESIRED_VALUE = ConfigKeys.newConfigKey(new
TypeToken<Object>() {}, "sensor.matching.value");
+
+    @Nullable
+    @Override
+    public Entity apply(@Nullable Collection<Entity> input) {
+        AttributeSensor<T> sensor = config().get(SENSOR);
+        Object desiredValue = config().get(DESIRED_VALUE);
+        for (Entity entity : input) {
+            if (Objects.equals(desiredValue, entity.sensors().get(sensor))) {
+                return entity;
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/0ebd0669/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java
index b58c630..fe9e09f 100644
--- a/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java
+++ b/core/src/test/java/org/apache/brooklyn/entity/group/DynamicClusterTest.java
@@ -49,6 +49,7 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.api.sensor.SensorEvent;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
+import org.apache.brooklyn.core.entity.EntityAsserts;
 import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.entity.factory.EntityFactory;
 import org.apache.brooklyn.core.entity.lifecycle.Lifecycle;
@@ -1161,6 +1162,56 @@ public class DynamicClusterTest extends BrooklynAppUnitTestSupport
{
         }
     }
 
+    @Test
+    public void testResizeStrategies() throws Exception {
+        int clusterSize = 5;
+
+        ImmutableList.Builder<RemovalStrategy> sensorMatchingStrategiesBuilder = ImmutableList.builder();
+        for (int i = 0; i < clusterSize; i++){
+            SensorMatchingRemovalStrategy sensorMatchingRemovalStrategy = new SensorMatchingRemovalStrategy();
+            sensorMatchingRemovalStrategy.config().set(SensorMatchingRemovalStrategy.SENSOR,
TestEntity.SEQUENCE);
+            sensorMatchingRemovalStrategy.config().set(SensorMatchingRemovalStrategy.DESIRED_VALUE,
i);
+            sensorMatchingStrategiesBuilder.add(sensorMatchingRemovalStrategy);
+        }
+
+        RemovalStrategy firstFrom = new FirstFromRemovalStrategy();
+        firstFrom.config().set(FirstFromRemovalStrategy.STRATEGIES, sensorMatchingStrategiesBuilder.build());
+
+        DynamicCluster cluster = app.createAndManageChild(EntitySpec.create(DynamicCluster.class)
+                .configure(DynamicCluster.MEMBER_SPEC, EntitySpec.create(TestEntity.class))
+                .configure(DynamicCluster.INITIAL_SIZE, clusterSize)
+                .configure(DynamicCluster.REMOVAL_STRATEGY, firstFrom));
+
+        cluster.start(ImmutableList.of(loc));
+
+        assertEquals(cluster.getMembers().size(), clusterSize);
+        EntityAsserts.assertAttributeEqualsEventually(cluster, Attributes.SERVICE_UP, true);
+
+        // Set the sensor values of the entities in a non-linear pattern (4, 0, 3, 1, 2),
then resize the cluster
+        // down by 1 and see if the correct entity has been removed, then resize down by
3
+        Iterator<Entity> childIterator = cluster.getMembers().iterator();
+        for (int i : new int[] {4, 0, 3, 1, 2}) {
+            childIterator.next().sensors().set(TestEntity.SEQUENCE, i);
+        }
+
+        assertEntityCollectionContainsSequence(cluster.getMembers(), ImmutableSet.of(0, 1,
2, 3, 4));
+
+        cluster.resizeByDelta(-1);
+        EntityAsserts.assertAttributeEqualsEventually(cluster, DynamicCluster.GROUP_SIZE,
4);
+        assertEntityCollectionContainsSequence(cluster.getMembers(), ImmutableSet.of(1, 2,
3, 4));
+
+        cluster.resizeByDelta(-3);
+        EntityAsserts.assertAttributeEqualsEventually(cluster, DynamicCluster.GROUP_SIZE,
1);
+        assertEntityCollectionContainsSequence(cluster.getMembers(), ImmutableSet.of(4));
+    }
+
+    private void assertEntityCollectionContainsSequence(Collection<Entity> entities,
Set<Integer> expected) {
+        assertEquals(entities.size(), expected.size());
+        for (Entity entity : entities) {
+            assertTrue(expected.contains(entity.sensors().get(TestEntity.SEQUENCE)));
+        }
+    }
+
     private void assertFirstAndNonFirstCounts(Collection<Entity> members, int expectedFirstCount,
int expectedNonFirstCount) {
         Set<Entity> found = MutableSet.of();
         for (Entity e: members) {


Mime
View raw message