alshabib
Committed by Gerrit Code Review

adding group garbage collection functionality

If a group has a reference count of zero for more than
a configurable timeout, it is garbage collected.

This feature can be deactivated by component config.

Change-Id: I254d62a90ef7ac8d2ce2f406b67957455a5bf4d0
...@@ -35,6 +35,7 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -35,6 +35,7 @@ public class DefaultGroup extends DefaultGroupDescription
35 private long bytes; 35 private long bytes;
36 private long referenceCount; 36 private long referenceCount;
37 private GroupId id; 37 private GroupId id;
38 + private int age;
38 39
39 /** 40 /**
40 * Initializes default values. 41 * Initializes default values.
...@@ -48,6 +49,7 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -48,6 +49,7 @@ public class DefaultGroup extends DefaultGroupDescription
48 packets = 0; 49 packets = 0;
49 bytes = 0; 50 bytes = 0;
50 referenceCount = 0; 51 referenceCount = 0;
52 + age = 0;
51 } 53 }
52 54
53 /** 55 /**
...@@ -128,6 +130,11 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -128,6 +130,11 @@ public class DefaultGroup extends DefaultGroupDescription
128 return this.bytes; 130 return this.bytes;
129 } 131 }
130 132
133 + @Override
134 + public int age() {
135 + return age;
136 + }
137 +
131 /** 138 /**
132 * Sets the new state for this entry. 139 * Sets the new state for this entry.
133 * 140 *
...@@ -171,6 +178,11 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -171,6 +178,11 @@ public class DefaultGroup extends DefaultGroupDescription
171 @Override 178 @Override
172 public void setReferenceCount(long referenceCount) { 179 public void setReferenceCount(long referenceCount) {
173 this.referenceCount = referenceCount; 180 this.referenceCount = referenceCount;
181 + if (referenceCount == 0) {
182 + age++;
183 + } else {
184 + age = 0;
185 + }
174 } 186 }
175 187
176 @Override 188 @Override
...@@ -214,6 +226,7 @@ public class DefaultGroup extends DefaultGroupDescription ...@@ -214,6 +226,7 @@ public class DefaultGroup extends DefaultGroupDescription
214 .add("description", super.toString()) 226 .add("description", super.toString())
215 .add("groupid", id) 227 .add("groupid", id)
216 .add("state", state) 228 .add("state", state)
229 + .add("age", age)
217 .toString(); 230 .toString();
218 } 231 }
219 232
......
...@@ -96,4 +96,12 @@ public interface Group extends GroupDescription { ...@@ -96,4 +96,12 @@ public interface Group extends GroupDescription {
96 * @return number of flow rules or other groups pointing to this group 96 * @return number of flow rules or other groups pointing to this group
97 */ 97 */
98 long referenceCount(); 98 long referenceCount();
99 +
100 + /**
101 + * Obtains the age of a group. The age reflects the number of polling rounds
102 + * the group has had a reference count of zero.
103 + *
104 + * @return the age of the group as an integer
105 + */
106 + int age();
99 } 107 }
......
...@@ -19,15 +19,17 @@ import com.google.common.collect.FluentIterable; ...@@ -19,15 +19,17 @@ import com.google.common.collect.FluentIterable;
19 import com.google.common.collect.ImmutableSet; 19 import com.google.common.collect.ImmutableSet;
20 import com.google.common.collect.Iterables; 20 import com.google.common.collect.Iterables;
21 import com.google.common.collect.Sets; 21 import com.google.common.collect.Sets;
22 -
23 import org.apache.felix.scr.annotations.Activate; 22 import org.apache.felix.scr.annotations.Activate;
24 import org.apache.felix.scr.annotations.Component; 23 import org.apache.felix.scr.annotations.Component;
25 import org.apache.felix.scr.annotations.Deactivate; 24 import org.apache.felix.scr.annotations.Deactivate;
25 +import org.apache.felix.scr.annotations.Modified;
26 +import org.apache.felix.scr.annotations.Property;
26 import org.apache.felix.scr.annotations.Reference; 27 import org.apache.felix.scr.annotations.Reference;
27 import org.apache.felix.scr.annotations.ReferenceCardinality; 28 import org.apache.felix.scr.annotations.ReferenceCardinality;
28 import org.apache.felix.scr.annotations.Service; 29 import org.apache.felix.scr.annotations.Service;
29 import org.onlab.util.KryoNamespace; 30 import org.onlab.util.KryoNamespace;
30 import org.onlab.util.NewConcurrentHashMap; 31 import org.onlab.util.NewConcurrentHashMap;
32 +import org.onosproject.cfg.ComponentConfigService;
31 import org.onosproject.cluster.ClusterService; 33 import org.onosproject.cluster.ClusterService;
32 import org.onosproject.cluster.NodeId; 34 import org.onosproject.cluster.NodeId;
33 import org.onosproject.core.DefaultGroupId; 35 import org.onosproject.core.DefaultGroupId;
...@@ -54,19 +56,21 @@ import org.onosproject.net.group.StoredGroupBucketEntry; ...@@ -54,19 +56,21 @@ import org.onosproject.net.group.StoredGroupBucketEntry;
54 import org.onosproject.net.group.StoredGroupEntry; 56 import org.onosproject.net.group.StoredGroupEntry;
55 import org.onosproject.store.AbstractStore; 57 import org.onosproject.store.AbstractStore;
56 import org.onosproject.store.cluster.messaging.ClusterCommunicationService; 58 import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
57 -import org.onosproject.store.service.MultiValuedTimestamp;
58 import org.onosproject.store.serializers.KryoNamespaces; 59 import org.onosproject.store.serializers.KryoNamespaces;
59 import org.onosproject.store.service.ConsistentMap; 60 import org.onosproject.store.service.ConsistentMap;
60 import org.onosproject.store.service.MapEvent; 61 import org.onosproject.store.service.MapEvent;
61 import org.onosproject.store.service.MapEventListener; 62 import org.onosproject.store.service.MapEventListener;
63 +import org.onosproject.store.service.MultiValuedTimestamp;
62 import org.onosproject.store.service.Serializer; 64 import org.onosproject.store.service.Serializer;
63 import org.onosproject.store.service.StorageService; 65 import org.onosproject.store.service.StorageService;
64 import org.onosproject.store.service.Versioned; 66 import org.onosproject.store.service.Versioned;
67 +import org.osgi.service.component.ComponentContext;
65 import org.slf4j.Logger; 68 import org.slf4j.Logger;
66 69
67 import java.util.ArrayList; 70 import java.util.ArrayList;
68 import java.util.Collection; 71 import java.util.Collection;
69 import java.util.Collections; 72 import java.util.Collections;
73 +import java.util.Dictionary;
70 import java.util.HashMap; 74 import java.util.HashMap;
71 import java.util.HashSet; 75 import java.util.HashSet;
72 import java.util.Iterator; 76 import java.util.Iterator;
...@@ -75,6 +79,7 @@ import java.util.Map; ...@@ -75,6 +79,7 @@ import java.util.Map;
75 import java.util.Map.Entry; 79 import java.util.Map.Entry;
76 import java.util.Objects; 80 import java.util.Objects;
77 import java.util.Optional; 81 import java.util.Optional;
82 +import java.util.Properties;
78 import java.util.Set; 83 import java.util.Set;
79 import java.util.concurrent.ConcurrentHashMap; 84 import java.util.concurrent.ConcurrentHashMap;
80 import java.util.concurrent.ConcurrentMap; 85 import java.util.concurrent.ConcurrentMap;
...@@ -83,7 +88,9 @@ import java.util.concurrent.Executors; ...@@ -83,7 +88,9 @@ import java.util.concurrent.Executors;
83 import java.util.concurrent.atomic.AtomicInteger; 88 import java.util.concurrent.atomic.AtomicInteger;
84 import java.util.stream.Collectors; 89 import java.util.stream.Collectors;
85 90
91 +import static com.google.common.base.Strings.isNullOrEmpty;
86 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; 92 import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
93 +import static org.onlab.util.Tools.get;
87 import static org.onlab.util.Tools.groupedThreads; 94 import static org.onlab.util.Tools.groupedThreads;
88 import static org.slf4j.LoggerFactory.getLogger; 95 import static org.slf4j.LoggerFactory.getLogger;
89 96
...@@ -99,6 +106,9 @@ public class DistributedGroupStore ...@@ -99,6 +106,9 @@ public class DistributedGroupStore
99 106
100 private final Logger log = getLogger(getClass()); 107 private final Logger log = getLogger(getClass());
101 108
109 + private static final boolean GARBAGE_COLLECT = false;
110 + private static final int GC_THRESH = 6;
111 +
102 private final int dummyId = 0xffffffff; 112 private final int dummyId = 0xffffffff;
103 private final GroupId dummyGroupId = new DefaultGroupId(dummyId); 113 private final GroupId dummyGroupId = new DefaultGroupId(dummyId);
104 114
...@@ -114,6 +124,9 @@ public class DistributedGroupStore ...@@ -114,6 +124,9 @@ public class DistributedGroupStore
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected MastershipService mastershipService; 125 protected MastershipService mastershipService;
116 126
127 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 + protected ComponentConfigService cfgService;
129 +
117 // Per device group table with (device id + app cookie) as key 130 // Per device group table with (device id + app cookie) as key
118 private ConsistentMap<GroupStoreKeyMapKey, 131 private ConsistentMap<GroupStoreKeyMapKey,
119 StoredGroupEntry> groupStoreEntriesByKey = null; 132 StoredGroupEntry> groupStoreEntriesByKey = null;
...@@ -135,8 +148,18 @@ public class DistributedGroupStore ...@@ -135,8 +148,18 @@ public class DistributedGroupStore
135 148
136 private KryoNamespace clusterMsgSerializer; 149 private KryoNamespace clusterMsgSerializer;
137 150
151 + @Property(name = "garbageCollect", boolValue = GARBAGE_COLLECT,
152 + label = "Enable group garbage collection")
153 + private boolean garbageCollect = GARBAGE_COLLECT;
154 +
155 + @Property(name = "gcThresh", intValue = GC_THRESH,
156 + label = "Number of rounds for group garbage collection")
157 + private int gcThresh = GC_THRESH;
158 +
159 +
138 @Activate 160 @Activate
139 public void activate() { 161 public void activate() {
162 + cfgService.registerProperties(getClass());
140 kryoBuilder = new KryoNamespace.Builder() 163 kryoBuilder = new KryoNamespace.Builder()
141 .register(KryoNamespaces.API) 164 .register(KryoNamespaces.API)
142 .register(DefaultGroup.class, 165 .register(DefaultGroup.class,
...@@ -193,12 +216,29 @@ public class DistributedGroupStore ...@@ -193,12 +216,29 @@ public class DistributedGroupStore
193 216
194 @Deactivate 217 @Deactivate
195 public void deactivate() { 218 public void deactivate() {
219 + cfgService.unregisterProperties(getClass(), false);
196 clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST); 220 clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST);
197 groupStoreEntriesByKey.destroy(); 221 groupStoreEntriesByKey.destroy();
198 auditPendingReqQueue.destroy(); 222 auditPendingReqQueue.destroy();
199 log.info("Stopped"); 223 log.info("Stopped");
200 } 224 }
201 225
226 + @Modified
227 + public void modified(ComponentContext context) {
228 + Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
229 +
230 + try {
231 + String s = get(properties, "garbageCollect");
232 + garbageCollect = isNullOrEmpty(s) ? GARBAGE_COLLECT : Boolean.parseBoolean(s.trim());
233 +
234 + s = get(properties, "gcThresh");
235 + gcThresh = isNullOrEmpty(s) ? GC_THRESH : Integer.parseInt(s.trim());
236 + } catch (Exception e) {
237 + gcThresh = GC_THRESH;
238 + garbageCollect = GARBAGE_COLLECT;
239 + }
240 + }
241 +
202 private static NewConcurrentHashMap<GroupId, Group> 242 private static NewConcurrentHashMap<GroupId, Group>
203 lazyEmptyExtraneousGroupIdTable() { 243 lazyEmptyExtraneousGroupIdTable() {
204 return NewConcurrentHashMap.<GroupId, Group>ifNeeded(); 244 return NewConcurrentHashMap.<GroupId, Group>ifNeeded();
...@@ -268,7 +308,6 @@ public class DistributedGroupStore ...@@ -268,7 +308,6 @@ public class DistributedGroupStore
268 * Returns the groups associated with a device. 308 * Returns the groups associated with a device.
269 * 309 *
270 * @param deviceId the device ID 310 * @param deviceId the device ID
271 - *
272 * @return the group entries 311 * @return the group entries
273 */ 312 */
274 @Override 313 @Override
...@@ -296,7 +335,6 @@ public class DistributedGroupStore ...@@ -296,7 +335,6 @@ public class DistributedGroupStore
296 * 335 *
297 * @param deviceId the device ID 336 * @param deviceId the device ID
298 * @param appCookie the group key 337 * @param appCookie the group key
299 - *
300 * @return a group associated with the key 338 * @return a group associated with the key
301 */ 339 */
302 @Override 340 @Override
...@@ -377,7 +415,8 @@ public class DistributedGroupStore ...@@ -377,7 +415,8 @@ public class DistributedGroupStore
377 clusterCommunicator.unicast(groupOp, 415 clusterCommunicator.unicast(groupOp,
378 GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST, 416 GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
379 clusterMsgSerializer::serialize, 417 clusterMsgSerializer::serialize,
380 - mastershipService.getMasterFor(groupDesc.deviceId())).whenComplete((result, error) -> { 418 + mastershipService.getMasterFor(groupDesc.deviceId()))
419 + .whenComplete((result, error) -> {
381 if (error != null) { 420 if (error != null) {
382 log.warn("Failed to send request to master: {} to {}", 421 log.warn("Failed to send request to master: {} to {}",
383 groupOp, 422 groupOp,
...@@ -415,7 +454,7 @@ public class DistributedGroupStore ...@@ -415,7 +454,7 @@ public class DistributedGroupStore
415 return null; 454 return null;
416 } 455 }
417 456
418 - for (Group extraneousGroup:extraneousMap.values()) { 457 + for (Group extraneousGroup : extraneousMap.values()) {
419 if (extraneousGroup.buckets().equals(buckets)) { 458 if (extraneousGroup.buckets().equals(buckets)) {
420 return extraneousGroup; 459 return extraneousGroup;
421 } 460 }
...@@ -688,7 +727,7 @@ public class DistributedGroupStore ...@@ -688,7 +727,7 @@ public class DistributedGroupStore
688 if (type == UpdateType.ADD) { 727 if (type == UpdateType.ADD) {
689 // Check if the any of the new buckets are part of 728 // Check if the any of the new buckets are part of
690 // the old bucket list 729 // the old bucket list
691 - for (GroupBucket addBucket:buckets.buckets()) { 730 + for (GroupBucket addBucket : buckets.buckets()) {
692 if (!newBucketList.contains(addBucket)) { 731 if (!newBucketList.contains(addBucket)) {
693 newBucketList.add(addBucket); 732 newBucketList.add(addBucket);
694 groupDescUpdated = true; 733 groupDescUpdated = true;
...@@ -697,7 +736,7 @@ public class DistributedGroupStore ...@@ -697,7 +736,7 @@ public class DistributedGroupStore
697 } else if (type == UpdateType.REMOVE) { 736 } else if (type == UpdateType.REMOVE) {
698 // Check if the to be removed buckets are part of the 737 // Check if the to be removed buckets are part of the
699 // old bucket list 738 // old bucket list
700 - for (GroupBucket removeBucket:buckets.buckets()) { 739 + for (GroupBucket removeBucket : buckets.buckets()) {
701 if (newBucketList.contains(removeBucket)) { 740 if (newBucketList.contains(removeBucket)) {
702 newBucketList.remove(removeBucket); 741 newBucketList.remove(removeBucket);
703 groupDescUpdated = true; 742 groupDescUpdated = true;
...@@ -795,11 +834,11 @@ public class DistributedGroupStore ...@@ -795,11 +834,11 @@ public class DistributedGroupStore
795 group.id(), 834 group.id(),
796 group.deviceId()); 835 group.deviceId());
797 synchronized (existing) { 836 synchronized (existing) {
798 - for (GroupBucket bucket:group.buckets().buckets()) { 837 + for (GroupBucket bucket : group.buckets().buckets()) {
799 Optional<GroupBucket> matchingBucket = 838 Optional<GroupBucket> matchingBucket =
800 existing.buckets().buckets() 839 existing.buckets().buckets()
801 .stream() 840 .stream()
802 - .filter((existingBucket)->(existingBucket.equals(bucket))) 841 + .filter((existingBucket) -> (existingBucket.equals(bucket)))
803 .findFirst(); 842 .findFirst();
804 if (matchingBucket.isPresent()) { 843 if (matchingBucket.isPresent()) {
805 ((StoredGroupBucketEntry) matchingBucket. 844 ((StoredGroupBucketEntry) matchingBucket.
...@@ -814,6 +853,7 @@ public class DistributedGroupStore ...@@ -814,6 +853,7 @@ public class DistributedGroupStore
814 existing.setLife(group.life()); 853 existing.setLife(group.life());
815 existing.setPackets(group.packets()); 854 existing.setPackets(group.packets());
816 existing.setBytes(group.bytes()); 855 existing.setBytes(group.bytes());
856 + existing.setReferenceCount(group.referenceCount());
817 if ((existing.state() == GroupState.PENDING_ADD) || 857 if ((existing.state() == GroupState.PENDING_ADD) ||
818 (existing.state() == GroupState.PENDING_ADD_RETRY)) { 858 (existing.state() == GroupState.PENDING_ADD_RETRY)) {
819 log.trace("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED", 859 log.trace("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED",
...@@ -901,12 +941,12 @@ public class DistributedGroupStore ...@@ -901,12 +941,12 @@ public class DistributedGroupStore
901 List<StoredGroupEntry> pendingGroupRequests = 941 List<StoredGroupEntry> pendingGroupRequests =
902 getPendingGroupKeyTable().values() 942 getPendingGroupKeyTable().values()
903 .stream() 943 .stream()
904 - .filter(g-> g.deviceId().equals(deviceId)) 944 + .filter(g -> g.deviceId().equals(deviceId))
905 .collect(Collectors.toList()); 945 .collect(Collectors.toList());
906 log.debug("processing pending group add requests for device {} and number of pending requests {}", 946 log.debug("processing pending group add requests for device {} and number of pending requests {}",
907 deviceId, 947 deviceId,
908 pendingGroupRequests.size()); 948 pendingGroupRequests.size());
909 - for (Group group:pendingGroupRequests) { 949 + for (Group group : pendingGroupRequests) {
910 GroupDescription tmp = new DefaultGroupDescription( 950 GroupDescription tmp = new DefaultGroupDescription(
911 group.deviceId(), 951 group.deviceId(),
912 group.type(), 952 group.type(),
...@@ -1144,6 +1184,7 @@ public class DistributedGroupStore ...@@ -1144,6 +1184,7 @@ public class DistributedGroupStore
1144 1184
1145 protected static class GroupStoreKeyMapKey extends GroupStoreMapKey { 1185 protected static class GroupStoreKeyMapKey extends GroupStoreMapKey {
1146 private final GroupKey appCookie; 1186 private final GroupKey appCookie;
1187 +
1147 public GroupStoreKeyMapKey(DeviceId deviceId, 1188 public GroupStoreKeyMapKey(DeviceId deviceId,
1148 GroupKey appCookie) { 1189 GroupKey appCookie) {
1149 super(deviceId); 1190 super(deviceId);
...@@ -1175,6 +1216,7 @@ public class DistributedGroupStore ...@@ -1175,6 +1216,7 @@ public class DistributedGroupStore
1175 1216
1176 protected static class GroupStoreIdMapKey extends GroupStoreMapKey { 1217 protected static class GroupStoreIdMapKey extends GroupStoreMapKey {
1177 private final GroupId groupId; 1218 private final GroupId groupId;
1219 +
1178 public GroupStoreIdMapKey(DeviceId deviceId, 1220 public GroupStoreIdMapKey(DeviceId deviceId,
1179 GroupId groupId) { 1221 GroupId groupId) {
1180 super(deviceId); 1222 super(deviceId);
...@@ -1233,12 +1275,15 @@ public class DistributedGroupStore ...@@ -1233,12 +1275,15 @@ public class DistributedGroupStore
1233 log.trace("Stored Group {} for device {}", group, deviceId); 1275 log.trace("Stored Group {} for device {}", group, deviceId);
1234 } 1276 }
1235 1277
1278 + garbageCollect(deviceId, southboundGroupEntries, storedGroupEntries);
1279 +
1236 for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) { 1280 for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
1237 Group group = it2.next(); 1281 Group group = it2.next();
1238 if (storedGroupEntries.remove(group)) { 1282 if (storedGroupEntries.remove(group)) {
1239 // we both have the group, let's update some info then. 1283 // we both have the group, let's update some info then.
1240 log.trace("Group AUDIT: group {} exists in both planes for device {}", 1284 log.trace("Group AUDIT: group {} exists in both planes for device {}",
1241 group.id(), deviceId); 1285 group.id(), deviceId);
1286 +
1242 groupAdded(group); 1287 groupAdded(group);
1243 it2.remove(); 1288 it2.remove();
1244 } 1289 }
...@@ -1283,6 +1328,29 @@ public class DistributedGroupStore ...@@ -1283,6 +1328,29 @@ public class DistributedGroupStore
1283 } 1328 }
1284 } 1329 }
1285 1330
1331 + private void garbageCollect(DeviceId deviceId,
1332 + Set<Group> southboundGroupEntries,
1333 + Set<StoredGroupEntry> storedGroupEntries) {
1334 + if (!garbageCollect) {
1335 + return;
1336 + }
1337 +
1338 + Iterator<StoredGroupEntry> it = storedGroupEntries.iterator();
1339 + while (it.hasNext()) {
1340 + StoredGroupEntry group = it.next();
1341 + if (group.state() != GroupState.PENDING_DELETE && checkGroupRefCount(group)) {
1342 + log.debug("Garbage collecting group {} on {}", group, deviceId);
1343 + deleteGroupDescription(deviceId, group.appCookie());
1344 + southboundGroupEntries.remove(group);
1345 + it.remove();
1346 + }
1347 + }
1348 + }
1349 +
1350 + private boolean checkGroupRefCount(Group group) {
1351 + return (group.referenceCount() == 0 && group.age() >= gcThresh);
1352 + }
1353 +
1286 private void groupMissing(Group group) { 1354 private void groupMissing(Group group) {
1287 switch (group.state()) { 1355 switch (group.state()) {
1288 case PENDING_DELETE: 1356 case PENDING_DELETE:
......
...@@ -23,6 +23,7 @@ import org.junit.After; ...@@ -23,6 +23,7 @@ import org.junit.After;
23 import org.junit.Before; 23 import org.junit.Before;
24 import org.junit.Test; 24 import org.junit.Test;
25 import org.onlab.junit.TestUtils; 25 import org.onlab.junit.TestUtils;
26 +import org.onosproject.cfg.ComponentConfigAdapter;
26 import org.onosproject.cluster.NodeId; 27 import org.onosproject.cluster.NodeId;
27 import org.onosproject.core.DefaultGroupId; 28 import org.onosproject.core.DefaultGroupId;
28 import org.onosproject.core.GroupId; 29 import org.onosproject.core.GroupId;
...@@ -129,6 +130,7 @@ public class DistributedGroupStoreTest { ...@@ -129,6 +130,7 @@ public class DistributedGroupStoreTest {
129 groupStoreImpl.storageService = new TestStorageService(); 130 groupStoreImpl.storageService = new TestStorageService();
130 groupStoreImpl.clusterCommunicator = new ClusterCommunicationServiceAdapter(); 131 groupStoreImpl.clusterCommunicator = new ClusterCommunicationServiceAdapter();
131 groupStoreImpl.mastershipService = new MasterOfAll(); 132 groupStoreImpl.mastershipService = new MasterOfAll();
133 + groupStoreImpl.cfgService = new ComponentConfigAdapter();
132 groupStoreImpl.activate(); 134 groupStoreImpl.activate();
133 groupStore = groupStoreImpl; 135 groupStore = groupStoreImpl;
134 auditPendingReqQueue = 136 auditPendingReqQueue =
......
...@@ -156,6 +156,11 @@ public class GroupsResourceTest extends ResourceTest { ...@@ -156,6 +156,11 @@ public class GroupsResourceTest extends ResourceTest {
156 } 156 }
157 157
158 @Override 158 @Override
159 + public int age() {
160 + return 0;
161 + }
162 +
163 + @Override
159 public Type type() { 164 public Type type() {
160 return GroupDescription.Type.ALL; 165 return GroupDescription.Type.ALL;
161 } 166 }
......