blob: 03f9e3fb52dce1226e12f842b62c8c814edc51a0 [file] [log] [blame]
alshabib10580802015-02-18 18:30:33 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
alshabib10580802015-02-18 18:30:33 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.group.impl;
17
Jonathan Hart6ec029a2015-03-24 17:12:35 -070018import com.google.common.collect.FluentIterable;
Charles Chanf4838a72015-12-07 18:13:45 -080019import com.google.common.collect.ImmutableSet;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070020import com.google.common.collect.Iterables;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070021import com.google.common.collect.Sets;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070022import org.onlab.util.KryoNamespace;
alshabibb0285992016-03-28 23:30:37 -070023import org.onosproject.cfg.ComponentConfigService;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070024import org.onosproject.cluster.ClusterService;
Charles Chanf4838a72015-12-07 18:13:45 -080025import org.onosproject.cluster.NodeId;
alshabib10580802015-02-18 18:30:33 -080026import org.onosproject.core.GroupId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070027import org.onosproject.mastership.MastershipService;
alshabib10580802015-02-18 18:30:33 -080028import org.onosproject.net.DeviceId;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070029import org.onosproject.net.MastershipRole;
jaegonkim9477a9d2018-04-01 16:36:36 +090030import org.onosproject.net.driver.DriverService;
alshabib10580802015-02-18 18:30:33 -080031import org.onosproject.net.group.DefaultGroup;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070032import org.onosproject.net.group.DefaultGroupBucket;
alshabib10580802015-02-18 18:30:33 -080033import org.onosproject.net.group.DefaultGroupDescription;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070034import org.onosproject.net.group.DefaultGroupKey;
alshabib10580802015-02-18 18:30:33 -080035import org.onosproject.net.group.Group;
36import org.onosproject.net.group.Group.GroupState;
37import org.onosproject.net.group.GroupBucket;
38import org.onosproject.net.group.GroupBuckets;
39import org.onosproject.net.group.GroupDescription;
40import org.onosproject.net.group.GroupEvent;
41import org.onosproject.net.group.GroupEvent.Type;
42import org.onosproject.net.group.GroupKey;
43import org.onosproject.net.group.GroupOperation;
44import org.onosproject.net.group.GroupStore;
45import org.onosproject.net.group.GroupStoreDelegate;
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -070046import org.onosproject.net.group.StoredGroupBucketEntry;
alshabib10580802015-02-18 18:30:33 -080047import org.onosproject.net.group.StoredGroupEntry;
48import org.onosproject.store.AbstractStore;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070049import org.onosproject.store.cluster.messaging.ClusterCommunicationService;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -070050import org.onosproject.store.serializers.KryoNamespaces;
Madan Jampani0b847532016-03-03 13:44:15 -080051import org.onosproject.store.service.ConsistentMap;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070052import org.onosproject.store.service.DistributedPrimitive.Status;
Madan Jampani0b847532016-03-03 13:44:15 -080053import org.onosproject.store.service.MapEvent;
54import org.onosproject.store.service.MapEventListener;
alshabibb0285992016-03-28 23:30:37 -070055import org.onosproject.store.service.MultiValuedTimestamp;
Madan Jampani0b847532016-03-03 13:44:15 -080056import org.onosproject.store.service.Serializer;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070057import org.onosproject.store.service.StorageService;
helenyrwua1c41152016-08-18 16:16:14 -070058import org.onosproject.store.service.Topic;
Madan Jampani0b847532016-03-03 13:44:15 -080059import org.onosproject.store.service.Versioned;
alshabibb0285992016-03-28 23:30:37 -070060import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070061import org.osgi.service.component.annotations.Activate;
62import org.osgi.service.component.annotations.Component;
63import org.osgi.service.component.annotations.Deactivate;
64import org.osgi.service.component.annotations.Modified;
65import org.osgi.service.component.annotations.Reference;
66import org.osgi.service.component.annotations.ReferenceCardinality;
alshabib10580802015-02-18 18:30:33 -080067import org.slf4j.Logger;
68
Jonathan Hart6ec029a2015-03-24 17:12:35 -070069import java.util.ArrayList;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070070import java.util.Collection;
Charles Chanf4838a72015-12-07 18:13:45 -080071import java.util.Collections;
alshabibb0285992016-03-28 23:30:37 -070072import java.util.Dictionary;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070073import java.util.HashMap;
Charles Chan0c7c43b2016-01-14 17:39:20 -080074import java.util.HashSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070075import java.util.Iterator;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070076import java.util.List;
Madan Jampani0b847532016-03-03 13:44:15 -080077import java.util.Map;
Charles Chan0c7c43b2016-01-14 17:39:20 -080078import java.util.Map.Entry;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070079import java.util.Objects;
Sho SHIMIZU30d639b2015-05-05 09:30:35 -070080import java.util.Optional;
alshabibb0285992016-03-28 23:30:37 -070081import java.util.Properties;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070082import java.util.Set;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070083import java.util.concurrent.ConcurrentHashMap;
84import java.util.concurrent.ConcurrentMap;
85import java.util.concurrent.ExecutorService;
86import java.util.concurrent.Executors;
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +053087import java.util.concurrent.ScheduledExecutorService;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070088import java.util.concurrent.atomic.AtomicInteger;
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +053089import java.util.function.Consumer;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070090import java.util.stream.Collectors;
91
alshabibb0285992016-03-28 23:30:37 -070092import static com.google.common.base.Strings.isNullOrEmpty;
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +053093import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
alshabibb0285992016-03-28 23:30:37 -070094import static org.onlab.util.Tools.get;
Jonathan Hart6ec029a2015-03-24 17:12:35 -070095import static org.onlab.util.Tools.groupedThreads;
Ray Milkeyb5646e62018-10-16 11:42:18 -070096import static org.onosproject.store.OsgiPropertyConstants.ALLOW_EXTRANEOUS_GROUPS;
97import static org.onosproject.store.OsgiPropertyConstants.ALLOW_EXTRANEOUS_GROUPS_DEFAULT;
98import static org.onosproject.store.OsgiPropertyConstants.GARBAGE_COLLECT;
99import static org.onosproject.store.OsgiPropertyConstants.GARBAGE_COLLECT_DEFAULT;
100import static org.onosproject.store.OsgiPropertyConstants.GARBAGE_COLLECT_THRESH;
101import static org.onosproject.store.OsgiPropertyConstants.GARBAGE_COLLECT_THRESH_DEFAULT;
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700102import static org.slf4j.LoggerFactory.getLogger;
alshabib10580802015-02-18 18:30:33 -0800103
104/**
Saurav Das0fd79d92016-03-07 10:58:36 -0800105 * Manages inventory of group entries using distributed group stores from the
106 * storage service.
alshabib10580802015-02-18 18:30:33 -0800107 */
Ray Milkeyb5646e62018-10-16 11:42:18 -0700108@Component(
109 immediate = true,
110 service = GroupStore.class,
111 property = {
Ray Milkey2d7bca12018-10-17 14:51:52 -0700112 GARBAGE_COLLECT + ":Boolean=" + GARBAGE_COLLECT_DEFAULT,
113 GARBAGE_COLLECT_THRESH + ":Integer=" + GARBAGE_COLLECT_THRESH_DEFAULT,
114 ALLOW_EXTRANEOUS_GROUPS + ":Boolean=" + ALLOW_EXTRANEOUS_GROUPS_DEFAULT
Ray Milkeyb5646e62018-10-16 11:42:18 -0700115 }
116)
alshabib10580802015-02-18 18:30:33 -0800117public class DistributedGroupStore
118 extends AbstractStore<GroupEvent, GroupStoreDelegate>
119 implements GroupStore {
120
121 private final Logger log = getLogger(getClass());
122
Saurav Das137f27f2018-06-11 17:02:31 -0700123 private static final int MAX_FAILED_ATTEMPTS = 3;
alshabibb0285992016-03-28 23:30:37 -0700124
alshabib10580802015-02-18 18:30:33 -0800125 private final int dummyId = 0xffffffff;
Yi Tsengfa394de2017-02-01 11:26:40 -0800126 private final GroupId dummyGroupId = new GroupId(dummyId);
alshabib10580802015-02-18 18:30:33 -0800127
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700128 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700129 protected ClusterCommunicationService clusterCommunicator;
130
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700131 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700132 protected ClusterService clusterService;
133
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700134 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700135 protected StorageService storageService;
136
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700137 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700138 protected MastershipService mastershipService;
139
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700140 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabibb0285992016-03-28 23:30:37 -0700141 protected ComponentConfigService cfgService;
142
jaegonkim9477a9d2018-04-01 16:36:36 +0900143 // Guarantees enabling DriverService before enabling GroupStore
144 // (DriverService is used in serializing/de-serializing DefaultGroup)
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
jaegonkim9477a9d2018-04-01 16:36:36 +0900146 protected DriverService driverService;
147
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +0530148 private ScheduledExecutorService executor;
149 private Consumer<Status> statusChangeListener;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700150 // Per device group table with (device id + app cookie) as key
Madan Jampani0b847532016-03-03 13:44:15 -0800151 private ConsistentMap<GroupStoreKeyMapKey,
alshabibb0285992016-03-28 23:30:37 -0700152 StoredGroupEntry> groupStoreEntriesByKey = null;
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700153 // Per device group table with (device id + group id) as key
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700154 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>>
alshabibb0285992016-03-28 23:30:37 -0700155 groupEntriesById = new ConcurrentHashMap<>();
Madan Jampani0b847532016-03-03 13:44:15 -0800156 private ConsistentMap<GroupStoreKeyMapKey,
alshabibb0285992016-03-28 23:30:37 -0700157 StoredGroupEntry> auditPendingReqQueue = null;
Frank Wange0eb5ce2016-07-01 18:21:25 +0800158 private MapEventListener<GroupStoreKeyMapKey, StoredGroupEntry>
159 mapListener = new GroupStoreKeyMapListener();
alshabib10580802015-02-18 18:30:33 -0800160 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>>
161 extraneousGroupEntriesById = new ConcurrentHashMap<>();
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700162 private ExecutorService messageHandlingExecutor;
163 private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 1;
Saurav Das137f27f2018-06-11 17:02:31 -0700164
Sho SHIMIZU7a4087b2015-09-10 09:23:16 -0700165 private final HashMap<DeviceId, Boolean> deviceAuditStatus = new HashMap<>();
alshabib10580802015-02-18 18:30:33 -0800166
167 private final AtomicInteger groupIdGen = new AtomicInteger();
168
HIGUCHI Yuta180d70f2015-10-01 16:13:56 -0700169 private KryoNamespace clusterMsgSerializer;
170
helenyrwua1c41152016-08-18 16:16:14 -0700171 private static Topic<GroupStoreMessage> groupTopic;
172
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700173 //@Property(name = "garbageCollect", boolValue = GARBAGE_COLLECT,
174 // label = "Enable group garbage collection")
Ray Milkeyb5646e62018-10-16 11:42:18 -0700175 private boolean garbageCollect = GARBAGE_COLLECT_DEFAULT;
alshabibb0285992016-03-28 23:30:37 -0700176
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700177 //@Property(name = "gcThresh", intValue = GC_THRESH,
178 // label = "Number of rounds for group garbage collection")
Ray Milkeyb5646e62018-10-16 11:42:18 -0700179 private int gcThresh = GARBAGE_COLLECT_THRESH_DEFAULT;
alshabibb0285992016-03-28 23:30:37 -0700180
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700181 //@Property(name = "allowExtraneousGroups", boolValue = ALLOW_EXTRANEOUS_GROUPS,
182 // label = "Allow groups in switches not installed by ONOS")
Ray Milkeyb5646e62018-10-16 11:42:18 -0700183 private boolean allowExtraneousGroups = ALLOW_EXTRANEOUS_GROUPS_DEFAULT;
alshabibb0285992016-03-28 23:30:37 -0700184
alshabib10580802015-02-18 18:30:33 -0800185 @Activate
sisubram4beea652017-08-09 10:38:14 +0000186 public void activate(ComponentContext context) {
alshabibb0285992016-03-28 23:30:37 -0700187 cfgService.registerProperties(getClass());
sisubram4beea652017-08-09 10:38:14 +0000188 modified(context);
HIGUCHI Yuta3a84b322016-05-18 13:38:07 -0700189 KryoNamespace.Builder kryoBuilder = new KryoNamespace.Builder()
alshabibb0285992016-03-28 23:30:37 -0700190 .register(KryoNamespaces.API)
HIGUCHI Yuta3a84b322016-05-18 13:38:07 -0700191 .nextId(KryoNamespaces.BEGIN_USER_CUSTOM_ID)
alshabibb0285992016-03-28 23:30:37 -0700192 .register(DefaultGroup.class,
193 DefaultGroupBucket.class,
194 DefaultGroupDescription.class,
195 DefaultGroupKey.class,
196 GroupDescription.Type.class,
197 Group.GroupState.class,
198 GroupBuckets.class,
alshabibb0285992016-03-28 23:30:37 -0700199 GroupStoreMessage.class,
200 GroupStoreMessage.Type.class,
201 UpdateType.class,
202 GroupStoreMessageSubjects.class,
203 MultiValuedTimestamp.class,
204 GroupStoreKeyMapKey.class,
205 GroupStoreIdMapKey.class,
206 GroupStoreMapKey.class
207 );
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700208
HIGUCHI Yuta3a84b322016-05-18 13:38:07 -0700209 clusterMsgSerializer = kryoBuilder.build("GroupStore");
210 Serializer serializer = Serializer.using(clusterMsgSerializer);
HIGUCHI Yuta180d70f2015-10-01 16:13:56 -0700211
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700212 messageHandlingExecutor = Executors.
213 newFixedThreadPool(MESSAGE_HANDLER_THREAD_POOL_SIZE,
214 groupedThreads("onos/store/group",
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700215 "message-handlers",
216 log));
Madan Jampani01e05fb2015-08-13 13:29:36 -0700217
218 clusterCommunicator.addSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
alshabibb0285992016-03-28 23:30:37 -0700219 clusterMsgSerializer::deserialize,
220 this::process,
221 messageHandlingExecutor);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700222
Madan Jampani0b847532016-03-03 13:44:15 -0800223 log.debug("Creating Consistent map onos-group-store-keymap");
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700224
Madan Jampani0b847532016-03-03 13:44:15 -0800225 groupStoreEntriesByKey = storageService.<GroupStoreKeyMapKey, StoredGroupEntry>consistentMapBuilder()
226 .withName("onos-group-store-keymap")
HIGUCHI Yuta3a84b322016-05-18 13:38:07 -0700227 .withSerializer(serializer)
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700228 .build();
Frank Wange0eb5ce2016-07-01 18:21:25 +0800229 groupStoreEntriesByKey.addListener(mapListener);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700230 log.debug("Current size of groupstorekeymap:{}",
231 groupStoreEntriesByKey.size());
Thiago Santosfb73c502016-08-18 18:15:13 -0300232 synchronizeGroupStoreEntries();
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700233
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +0530234 log.debug("Creating GroupStoreId Map From GroupStoreKey Map");
235 matchGroupEntries();
236 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/group", "store", log));
237 statusChangeListener = status -> {
238 if (status == Status.ACTIVE) {
239 executor.execute(this::matchGroupEntries);
240 }
241 };
242 groupStoreEntriesByKey.addStatusChangeListener(statusChangeListener);
243
Madan Jampani0b847532016-03-03 13:44:15 -0800244 log.debug("Creating Consistent map pendinggroupkeymap");
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700245
Madan Jampani0b847532016-03-03 13:44:15 -0800246 auditPendingReqQueue = storageService.<GroupStoreKeyMapKey, StoredGroupEntry>consistentMapBuilder()
247 .withName("onos-pending-group-keymap")
HIGUCHI Yuta3a84b322016-05-18 13:38:07 -0700248 .withSerializer(serializer)
Jonathan Hart6ec029a2015-03-24 17:12:35 -0700249 .build();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700250 log.debug("Current size of pendinggroupkeymap:{}",
251 auditPendingReqQueue.size());
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700252
helenyrwua1c41152016-08-18 16:16:14 -0700253 groupTopic = getOrCreateGroupTopic(serializer);
254 groupTopic.subscribe(this::processGroupMessage);
255
alshabib10580802015-02-18 18:30:33 -0800256 log.info("Started");
257 }
258
259 @Deactivate
260 public void deactivate() {
Frank Wange0eb5ce2016-07-01 18:21:25 +0800261 groupStoreEntriesByKey.removeListener(mapListener);
alshabibb0285992016-03-28 23:30:37 -0700262 cfgService.unregisterProperties(getClass(), false);
HIGUCHI Yuta180d70f2015-10-01 16:13:56 -0700263 clusterCommunicator.removeSubscriber(GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST);
alshabib10580802015-02-18 18:30:33 -0800264 log.info("Stopped");
265 }
266
alshabibb0285992016-03-28 23:30:37 -0700267 @Modified
268 public void modified(ComponentContext context) {
269 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
270
271 try {
272 String s = get(properties, "garbageCollect");
Ray Milkeyb5646e62018-10-16 11:42:18 -0700273 garbageCollect = isNullOrEmpty(s) ? GARBAGE_COLLECT_DEFAULT : Boolean.parseBoolean(s.trim());
alshabibb0285992016-03-28 23:30:37 -0700274
275 s = get(properties, "gcThresh");
Ray Milkeyb5646e62018-10-16 11:42:18 -0700276 gcThresh = isNullOrEmpty(s) ? GARBAGE_COLLECT_THRESH_DEFAULT : Integer.parseInt(s.trim());
Kavitha Alagesanc56cded2017-01-13 10:48:18 +0530277
278 s = get(properties, "allowExtraneousGroups");
Ray Milkeyb5646e62018-10-16 11:42:18 -0700279 allowExtraneousGroups = isNullOrEmpty(s) ? ALLOW_EXTRANEOUS_GROUPS_DEFAULT : Boolean.parseBoolean(s.trim());
alshabibb0285992016-03-28 23:30:37 -0700280 } catch (Exception e) {
Ray Milkeyb5646e62018-10-16 11:42:18 -0700281 gcThresh = GARBAGE_COLLECT_THRESH_DEFAULT;
282 garbageCollect = GARBAGE_COLLECT_DEFAULT;
283 allowExtraneousGroups = ALLOW_EXTRANEOUS_GROUPS_DEFAULT;
alshabibb0285992016-03-28 23:30:37 -0700284 }
285 }
286
helenyrwua1c41152016-08-18 16:16:14 -0700287 private Topic<GroupStoreMessage> getOrCreateGroupTopic(Serializer serializer) {
288 if (groupTopic == null) {
289 return storageService.getTopic("group-failover-notif", serializer);
290 } else {
291 return groupTopic;
292 }
Sho SHIMIZUa6285542017-01-12 15:08:24 -0800293 }
helenyrwua1c41152016-08-18 16:16:14 -0700294
alshabib10580802015-02-18 18:30:33 -0800295 /**
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +0530296 * Updating values of groupEntriesById.
297 */
298 private void matchGroupEntries() {
299 for (Entry<GroupStoreKeyMapKey, StoredGroupEntry> entry : groupStoreEntriesByKey.asJavaMap().entrySet()) {
300 StoredGroupEntry group = entry.getValue();
301 getGroupIdTable(entry.getKey().deviceId()).put(group.id(), group);
302 }
303 }
304
Thiago Santosfb73c502016-08-18 18:15:13 -0300305
306 private void synchronizeGroupStoreEntries() {
307 Map<GroupStoreKeyMapKey, StoredGroupEntry> groupEntryMap = groupStoreEntriesByKey.asJavaMap();
308 for (Entry<GroupStoreKeyMapKey, StoredGroupEntry> entry : groupEntryMap.entrySet()) {
Thiago Santosfb73c502016-08-18 18:15:13 -0300309 StoredGroupEntry value = entry.getValue();
Thiago Santosfb73c502016-08-18 18:15:13 -0300310 ConcurrentMap<GroupId, StoredGroupEntry> groupIdTable = getGroupIdTable(value.deviceId());
311 groupIdTable.put(value.id(), value);
312 }
313 }
314
Kavitha Alagesanc884c3ef2017-01-19 12:32:26 +0530315 /**
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700316 * Returns the group store eventual consistent key map.
alshabib10580802015-02-18 18:30:33 -0800317 *
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700318 * @return Map representing group key table.
alshabib10580802015-02-18 18:30:33 -0800319 */
Madan Jampani0b847532016-03-03 13:44:15 -0800320 private Map<GroupStoreKeyMapKey, StoredGroupEntry>
alshabibb0285992016-03-28 23:30:37 -0700321 getGroupStoreKeyMap() {
Madan Jampani0b847532016-03-03 13:44:15 -0800322 return groupStoreEntriesByKey.asJavaMap();
alshabib10580802015-02-18 18:30:33 -0800323 }
324
325 /**
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700326 * Returns the group id table for specified device.
alshabib10580802015-02-18 18:30:33 -0800327 *
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700328 * @param deviceId identifier of the device
329 * @return Map representing group key table of given device.
alshabib10580802015-02-18 18:30:33 -0800330 */
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700331 private ConcurrentMap<GroupId, StoredGroupEntry> getGroupIdTable(DeviceId deviceId) {
Yuta HIGUCHIc2e68152016-08-16 13:47:36 -0700332 return groupEntriesById.computeIfAbsent(deviceId, k -> new ConcurrentHashMap<>());
alshabib10580802015-02-18 18:30:33 -0800333 }
334
335 /**
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700336 * Returns the pending group request table.
alshabib10580802015-02-18 18:30:33 -0800337 *
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700338 * @return Map representing group key table.
alshabib10580802015-02-18 18:30:33 -0800339 */
Madan Jampani0b847532016-03-03 13:44:15 -0800340 private Map<GroupStoreKeyMapKey, StoredGroupEntry>
alshabibb0285992016-03-28 23:30:37 -0700341 getPendingGroupKeyTable() {
Madan Jampani0b847532016-03-03 13:44:15 -0800342 return auditPendingReqQueue.asJavaMap();
alshabib10580802015-02-18 18:30:33 -0800343 }
344
345 /**
346 * Returns the extraneous group id table for specified device.
347 *
348 * @param deviceId identifier of the device
349 * @return Map representing group key table of given device.
350 */
351 private ConcurrentMap<GroupId, Group>
352 getExtraneousGroupIdTable(DeviceId deviceId) {
Yuta HIGUCHIc2e68152016-08-16 13:47:36 -0700353 return extraneousGroupEntriesById.computeIfAbsent(deviceId, k -> new ConcurrentHashMap<>());
alshabib10580802015-02-18 18:30:33 -0800354 }
355
356 /**
357 * Returns the number of groups for the specified device in the store.
358 *
359 * @return number of groups for the specified device
360 */
361 @Override
362 public int getGroupCount(DeviceId deviceId) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700363 return (getGroups(deviceId) != null) ?
alshabibb0285992016-03-28 23:30:37 -0700364 Iterables.size(getGroups(deviceId)) : 0;
alshabib10580802015-02-18 18:30:33 -0800365 }
366
367 /**
368 * Returns the groups associated with a device.
369 *
370 * @param deviceId the device ID
alshabib10580802015-02-18 18:30:33 -0800371 * @return the group entries
372 */
373 @Override
374 public Iterable<Group> getGroups(DeviceId deviceId) {
Charles Chanf4838a72015-12-07 18:13:45 -0800375 // Let ImmutableSet.copyOf do the type conversion
376 return ImmutableSet.copyOf(getStoredGroups(deviceId));
alshabib10580802015-02-18 18:30:33 -0800377 }
378
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700379 private Iterable<StoredGroupEntry> getStoredGroups(DeviceId deviceId) {
Charles Chanf4838a72015-12-07 18:13:45 -0800380 NodeId master = mastershipService.getMasterFor(deviceId);
381 if (master == null) {
382 log.debug("Failed to getGroups: No master for {}", deviceId);
383 return Collections.emptySet();
384 }
385
386 Set<StoredGroupEntry> storedGroups = getGroupStoreKeyMap().values()
387 .stream()
388 .filter(input -> input.deviceId().equals(deviceId))
389 .collect(Collectors.toSet());
390 return ImmutableSet.copyOf(storedGroups);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700391 }
392
alshabib10580802015-02-18 18:30:33 -0800393 /**
394 * Returns the stored group entry.
395 *
alshabibb0285992016-03-28 23:30:37 -0700396 * @param deviceId the device ID
alshabib10580802015-02-18 18:30:33 -0800397 * @param appCookie the group key
alshabib10580802015-02-18 18:30:33 -0800398 * @return a group associated with the key
399 */
400 @Override
401 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700402 return getStoredGroupEntry(deviceId, appCookie);
403 }
404
405 private StoredGroupEntry getStoredGroupEntry(DeviceId deviceId,
406 GroupKey appCookie) {
407 return getGroupStoreKeyMap().get(new GroupStoreKeyMapKey(deviceId,
408 appCookie));
409 }
410
411 @Override
412 public Group getGroup(DeviceId deviceId, GroupId groupId) {
413 return getStoredGroupEntry(deviceId, groupId);
414 }
415
416 private StoredGroupEntry getStoredGroupEntry(DeviceId deviceId,
417 GroupId groupId) {
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700418 return getGroupIdTable(deviceId).get(groupId);
alshabib10580802015-02-18 18:30:33 -0800419 }
420
421 private int getFreeGroupIdValue(DeviceId deviceId) {
422 int freeId = groupIdGen.incrementAndGet();
423
424 while (true) {
Yi Tsengfa394de2017-02-01 11:26:40 -0800425 Group existing = getGroup(deviceId, new GroupId(freeId));
alshabib10580802015-02-18 18:30:33 -0800426 if (existing == null) {
427 existing = (
428 extraneousGroupEntriesById.get(deviceId) != null) ?
429 extraneousGroupEntriesById.get(deviceId).
Yi Tsengfa394de2017-02-01 11:26:40 -0800430 get(new GroupId(freeId)) :
alshabib10580802015-02-18 18:30:33 -0800431 null;
432 }
433 if (existing != null) {
434 freeId = groupIdGen.incrementAndGet();
435 } else {
436 break;
437 }
438 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700439 log.debug("getFreeGroupIdValue: Next Free ID is {}", freeId);
alshabib10580802015-02-18 18:30:33 -0800440 return freeId;
441 }
442
443 /**
444 * Stores a new group entry using the information from group description.
445 *
446 * @param groupDesc group description to be used to create group entry
447 */
448 @Override
449 public void storeGroupDescription(GroupDescription groupDesc) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700450 log.debug("In storeGroupDescription");
alshabib10580802015-02-18 18:30:33 -0800451 // Check if a group is existing with the same key
Saurav Das8a0732e2015-11-20 15:27:53 -0800452 Group existingGroup = getGroup(groupDesc.deviceId(), groupDesc.appCookie());
453 if (existingGroup != null) {
Saurav Dasc568c342018-01-25 09:49:01 -0800454 log.debug("Group already exists with the same key {} in dev:{} with id:0x{}",
Saurav Das8a0732e2015-11-20 15:27:53 -0800455 groupDesc.appCookie(), groupDesc.deviceId(),
456 Integer.toHexString(existingGroup.id().id()));
alshabib10580802015-02-18 18:30:33 -0800457 return;
458 }
459
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700460 // Check if group to be created by a remote instance
Madan Jampani175e8fd2015-05-20 14:10:45 -0700461 if (mastershipService.getLocalRole(groupDesc.deviceId()) != MastershipRole.MASTER) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700462 log.debug("storeGroupDescription: Device {} local role is not MASTER",
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700463 groupDesc.deviceId());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700464 if (mastershipService.getMasterFor(groupDesc.deviceId()) == null) {
Sivachidambaram Subramanian9f816de2017-06-13 07:16:54 +0530465 log.debug("No Master for device {}..."
466 + "Queuing Group ADD request",
alshabibb0285992016-03-28 23:30:37 -0700467 groupDesc.deviceId());
Sivachidambaram Subramanian9f816de2017-06-13 07:16:54 +0530468 addToPendingAudit(groupDesc);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700469 return;
470 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700471 GroupStoreMessage groupOp = GroupStoreMessage.
472 createGroupAddRequestMsg(groupDesc.deviceId(),
473 groupDesc);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700474
Madan Jampani175e8fd2015-05-20 14:10:45 -0700475 clusterCommunicator.unicast(groupOp,
alshabibb0285992016-03-28 23:30:37 -0700476 GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
477 clusterMsgSerializer::serialize,
478 mastershipService.getMasterFor(groupDesc.deviceId()))
479 .whenComplete((result, error) -> {
Madan Jampani175e8fd2015-05-20 14:10:45 -0700480 if (error != null) {
481 log.warn("Failed to send request to master: {} to {}",
alshabibb0285992016-03-28 23:30:37 -0700482 groupOp,
483 mastershipService.getMasterFor(groupDesc.deviceId()));
Madan Jampani175e8fd2015-05-20 14:10:45 -0700484 //TODO: Send Group operation failure event
485 } else {
486 log.debug("Sent Group operation request for device {} "
alshabibb0285992016-03-28 23:30:37 -0700487 + "to remote MASTER {}",
488 groupDesc.deviceId(),
489 mastershipService.getMasterFor(groupDesc.deviceId()));
Madan Jampani175e8fd2015-05-20 14:10:45 -0700490 }
491 });
alshabib10580802015-02-18 18:30:33 -0800492 return;
493 }
494
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700495 log.debug("Store group for device {} is getting handled locally",
496 groupDesc.deviceId());
alshabib10580802015-02-18 18:30:33 -0800497 storeGroupDescriptionInternal(groupDesc);
498 }
499
Sivachidambaram Subramanian9f816de2017-06-13 07:16:54 +0530500 private void addToPendingAudit(GroupDescription groupDesc) {
501 Integer groupIdVal = groupDesc.givenGroupId();
502 GroupId groupId = (groupIdVal != null) ? new GroupId(groupIdVal) : dummyGroupId;
503 addToPendingKeyTable(new DefaultGroup(groupId, groupDesc));
504 }
505
506 private void addToPendingKeyTable(StoredGroupEntry group) {
507 group.setState(GroupState.WAITING_AUDIT_COMPLETE);
508 Map<GroupStoreKeyMapKey, StoredGroupEntry> pendingKeyTable =
509 getPendingGroupKeyTable();
510 pendingKeyTable.put(new GroupStoreKeyMapKey(group.deviceId(),
511 group.appCookie()),
512 group);
513 }
514
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700515 private Group getMatchingExtraneousGroupbyId(DeviceId deviceId, Integer groupId) {
516 ConcurrentMap<GroupId, Group> extraneousMap =
517 extraneousGroupEntriesById.get(deviceId);
518 if (extraneousMap == null) {
519 return null;
520 }
Yi Tsengfa394de2017-02-01 11:26:40 -0800521 return extraneousMap.get(new GroupId(groupId));
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700522 }
523
524 private Group getMatchingExtraneousGroupbyBuckets(DeviceId deviceId,
525 GroupBuckets buckets) {
526 ConcurrentMap<GroupId, Group> extraneousMap =
527 extraneousGroupEntriesById.get(deviceId);
528 if (extraneousMap == null) {
529 return null;
530 }
531
alshabibb0285992016-03-28 23:30:37 -0700532 for (Group extraneousGroup : extraneousMap.values()) {
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700533 if (extraneousGroup.buckets().equals(buckets)) {
534 return extraneousGroup;
535 }
536 }
537 return null;
538 }
539
alshabib10580802015-02-18 18:30:33 -0800540 private void storeGroupDescriptionInternal(GroupDescription groupDesc) {
541 // Check if a group is existing with the same key
542 if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
543 return;
544 }
545
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700546 if (deviceAuditStatus.get(groupDesc.deviceId()) == null) {
547 // Device group audit has not completed yet
548 // Add this group description to pending group key table
549 // Create a group entry object with Dummy Group ID
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700550 log.debug("storeGroupDescriptionInternal: Device {} AUDIT pending...Queuing Group ADD request",
alshabibb0285992016-03-28 23:30:37 -0700551 groupDesc.deviceId());
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700552 StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc);
553 group.setState(GroupState.WAITING_AUDIT_COMPLETE);
Madan Jampani0b847532016-03-03 13:44:15 -0800554 Map<GroupStoreKeyMapKey, StoredGroupEntry> pendingKeyTable =
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700555 getPendingGroupKeyTable();
556 pendingKeyTable.put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
557 groupDesc.appCookie()),
558 group);
559 return;
560 }
561
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700562 Group matchingExtraneousGroup = null;
563 if (groupDesc.givenGroupId() != null) {
564 //Check if there is a extraneous group existing with the same Id
565 matchingExtraneousGroup = getMatchingExtraneousGroupbyId(
alshabibb0285992016-03-28 23:30:37 -0700566 groupDesc.deviceId(), groupDesc.givenGroupId());
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700567 if (matchingExtraneousGroup != null) {
Saurav Das0fd79d92016-03-07 10:58:36 -0800568 log.debug("storeGroupDescriptionInternal: Matching extraneous group "
alshabibb0285992016-03-28 23:30:37 -0700569 + "found in Device {} for group id 0x{}",
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700570 groupDesc.deviceId(),
Saurav Das0fd79d92016-03-07 10:58:36 -0800571 Integer.toHexString(groupDesc.givenGroupId()));
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700572 //Check if the group buckets matches with user provided buckets
573 if (matchingExtraneousGroup.buckets().equals(groupDesc.buckets())) {
574 //Group is already existing with the same buckets and Id
575 // Create a group entry object
Saurav Das0fd79d92016-03-07 10:58:36 -0800576 log.debug("storeGroupDescriptionInternal: Buckets also matching "
alshabibb0285992016-03-28 23:30:37 -0700577 + "in Device {} for group id 0x{}",
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700578 groupDesc.deviceId(),
Saurav Das0fd79d92016-03-07 10:58:36 -0800579 Integer.toHexString(groupDesc.givenGroupId()));
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700580 StoredGroupEntry group = new DefaultGroup(
alshabibb0285992016-03-28 23:30:37 -0700581 matchingExtraneousGroup.id(), groupDesc);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700582 // Insert the newly created group entry into key and id maps
583 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700584 put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
585 groupDesc.appCookie()), group);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700586 // Ensure it also inserted into group id based table to
587 // avoid any chances of duplication in group id generation
588 getGroupIdTable(groupDesc.deviceId()).
alshabibb0285992016-03-28 23:30:37 -0700589 put(matchingExtraneousGroup.id(), group);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700590 addOrUpdateGroupEntry(matchingExtraneousGroup);
591 removeExtraneousGroupEntry(matchingExtraneousGroup);
592 return;
593 } else {
594 //Group buckets are not matching. Update group
595 //with user provided buckets.
Saurav Das0fd79d92016-03-07 10:58:36 -0800596 log.debug("storeGroupDescriptionInternal: Buckets are not "
alshabibb0285992016-03-28 23:30:37 -0700597 + "matching in Device {} for group id 0x{}",
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700598 groupDesc.deviceId(),
Saurav Das0fd79d92016-03-07 10:58:36 -0800599 Integer.toHexString(groupDesc.givenGroupId()));
600 StoredGroupEntry modifiedGroup = new DefaultGroup(
alshabibb0285992016-03-28 23:30:37 -0700601 matchingExtraneousGroup.id(), groupDesc);
Saurav Das0fd79d92016-03-07 10:58:36 -0800602 modifiedGroup.setState(GroupState.PENDING_UPDATE);
603 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700604 put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
605 groupDesc.appCookie()), modifiedGroup);
Saurav Das0fd79d92016-03-07 10:58:36 -0800606 // Ensure it also inserted into group id based table to
607 // avoid any chances of duplication in group id generation
608 getGroupIdTable(groupDesc.deviceId()).
alshabibb0285992016-03-28 23:30:37 -0700609 put(matchingExtraneousGroup.id(), modifiedGroup);
Saurav Das0fd79d92016-03-07 10:58:36 -0800610 removeExtraneousGroupEntry(matchingExtraneousGroup);
611 log.debug("storeGroupDescriptionInternal: Triggering Group "
alshabibb0285992016-03-28 23:30:37 -0700612 + "UPDATE request for {} in device {}",
Saurav Das0fd79d92016-03-07 10:58:36 -0800613 matchingExtraneousGroup.id(),
614 groupDesc.deviceId());
615 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, modifiedGroup));
616 return;
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700617 }
618 }
619 } else {
620 //Check if there is an extraneous group with user provided buckets
621 matchingExtraneousGroup = getMatchingExtraneousGroupbyBuckets(
alshabibb0285992016-03-28 23:30:37 -0700622 groupDesc.deviceId(), groupDesc.buckets());
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700623 if (matchingExtraneousGroup != null) {
624 //Group is already existing with the same buckets.
625 //So reuse this group.
626 log.debug("storeGroupDescriptionInternal: Matching extraneous group found in Device {}",
627 groupDesc.deviceId());
628 //Create a group entry object
629 StoredGroupEntry group = new DefaultGroup(
alshabibb0285992016-03-28 23:30:37 -0700630 matchingExtraneousGroup.id(), groupDesc);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700631 // Insert the newly created group entry into key and id maps
632 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700633 put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
634 groupDesc.appCookie()), group);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700635 // Ensure it also inserted into group id based table to
636 // avoid any chances of duplication in group id generation
637 getGroupIdTable(groupDesc.deviceId()).
alshabibb0285992016-03-28 23:30:37 -0700638 put(matchingExtraneousGroup.id(), group);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -0700639 addOrUpdateGroupEntry(matchingExtraneousGroup);
640 removeExtraneousGroupEntry(matchingExtraneousGroup);
641 return;
642 } else {
643 //TODO: Check if there are any empty groups that can be used here
644 log.debug("storeGroupDescriptionInternal: No matching extraneous groups found in Device {}",
645 groupDesc.deviceId());
646 }
647 }
648
Saurav Das100e3b82015-04-30 11:12:10 -0700649 GroupId id = null;
650 if (groupDesc.givenGroupId() == null) {
651 // Get a new group identifier
Yi Tsengfa394de2017-02-01 11:26:40 -0800652 id = new GroupId(getFreeGroupIdValue(groupDesc.deviceId()));
Saurav Das100e3b82015-04-30 11:12:10 -0700653 } else {
Saurav Das8be4e3a2016-03-11 17:19:07 -0800654 // we need to use the identifier passed in by caller, but check if
655 // already used
656 Group existing = getGroup(groupDesc.deviceId(),
Yi Tsengfa394de2017-02-01 11:26:40 -0800657 new GroupId(groupDesc.givenGroupId()));
Saurav Das8be4e3a2016-03-11 17:19:07 -0800658 if (existing != null) {
659 log.warn("Group already exists with the same id: 0x{} in dev:{} "
alshabibb0285992016-03-28 23:30:37 -0700660 + "but with different key: {} (request gkey: {})",
661 Integer.toHexString(groupDesc.givenGroupId()),
662 groupDesc.deviceId(),
663 existing.appCookie(),
664 groupDesc.appCookie());
Saurav Das8be4e3a2016-03-11 17:19:07 -0800665 return;
666 }
Yi Tsengfa394de2017-02-01 11:26:40 -0800667 id = new GroupId(groupDesc.givenGroupId());
Saurav Das100e3b82015-04-30 11:12:10 -0700668 }
alshabib10580802015-02-18 18:30:33 -0800669 // Create a group entry object
670 StoredGroupEntry group = new DefaultGroup(id, groupDesc);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700671 // Insert the newly created group entry into key and id maps
672 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700673 put(new GroupStoreKeyMapKey(groupDesc.deviceId(),
674 groupDesc.appCookie()), group);
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700675 // Ensure it also inserted into group id based table to
676 // avoid any chances of duplication in group id generation
677 getGroupIdTable(groupDesc.deviceId()).
alshabibb0285992016-03-28 23:30:37 -0700678 put(id, group);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700679 log.debug("storeGroupDescriptionInternal: Processing Group ADD request for Id {} in device {}",
alshabibb0285992016-03-28 23:30:37 -0700680 id,
681 groupDesc.deviceId());
alshabib10580802015-02-18 18:30:33 -0800682 notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
683 group));
684 }
685
686 /**
687 * Updates the existing group entry with the information
688 * from group description.
689 *
alshabibb0285992016-03-28 23:30:37 -0700690 * @param deviceId the device ID
alshabib10580802015-02-18 18:30:33 -0800691 * @param oldAppCookie the current group key
alshabibb0285992016-03-28 23:30:37 -0700692 * @param type update type
693 * @param newBuckets group buckets for updates
alshabib10580802015-02-18 18:30:33 -0800694 * @param newAppCookie optional new group key
695 */
696 @Override
697 public void updateGroupDescription(DeviceId deviceId,
698 GroupKey oldAppCookie,
699 UpdateType type,
700 GroupBuckets newBuckets,
701 GroupKey newAppCookie) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700702 // Check if group update to be done by a remote instance
sangho52abe3a2015-05-05 14:13:34 -0700703 if (mastershipService.getMasterFor(deviceId) != null &&
704 mastershipService.getLocalRole(deviceId) != MastershipRole.MASTER) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700705 log.debug("updateGroupDescription: Device {} local role is not MASTER",
706 deviceId);
707 if (mastershipService.getMasterFor(deviceId) == null) {
708 log.error("No Master for device {}..."
alshabibb0285992016-03-28 23:30:37 -0700709 + "Can not perform update group operation",
710 deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700711 //TODO: Send Group operation failure event
712 return;
713 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700714 GroupStoreMessage groupOp = GroupStoreMessage.
715 createGroupUpdateRequestMsg(deviceId,
716 oldAppCookie,
717 type,
718 newBuckets,
719 newAppCookie);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700720
Madan Jampani175e8fd2015-05-20 14:10:45 -0700721 clusterCommunicator.unicast(groupOp,
alshabibb0285992016-03-28 23:30:37 -0700722 GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
723 clusterMsgSerializer::serialize,
724 mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> {
725 if (error != null) {
726 log.warn("Failed to send request to master: {} to {}",
727 groupOp,
728 mastershipService.getMasterFor(deviceId), error);
729 }
730 //TODO: Send Group operation failure event
731 });
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700732 return;
733 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700734 log.debug("updateGroupDescription for device {} is getting handled locally",
735 deviceId);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700736 updateGroupDescriptionInternal(deviceId,
737 oldAppCookie,
738 type,
739 newBuckets,
740 newAppCookie);
741 }
742
743 private void updateGroupDescriptionInternal(DeviceId deviceId,
alshabibb0285992016-03-28 23:30:37 -0700744 GroupKey oldAppCookie,
745 UpdateType type,
746 GroupBuckets newBuckets,
747 GroupKey newAppCookie) {
alshabib10580802015-02-18 18:30:33 -0800748 // Check if a group is existing with the provided key
749 Group oldGroup = getGroup(deviceId, oldAppCookie);
750 if (oldGroup == null) {
Saurav Das8be4e3a2016-03-11 17:19:07 -0800751 log.warn("updateGroupDescriptionInternal: Group not found...strange. "
alshabibb0285992016-03-28 23:30:37 -0700752 + "GroupKey:{} DeviceId:{}", oldAppCookie, deviceId);
alshabib10580802015-02-18 18:30:33 -0800753 return;
754 }
755
756 List<GroupBucket> newBucketList = getUpdatedBucketList(oldGroup,
757 type,
758 newBuckets);
759 if (newBucketList != null) {
760 // Create a new group object from the old group
761 GroupBuckets updatedBuckets = new GroupBuckets(newBucketList);
762 GroupKey newCookie = (newAppCookie != null) ? newAppCookie : oldAppCookie;
763 GroupDescription updatedGroupDesc = new DefaultGroupDescription(
764 oldGroup.deviceId(),
765 oldGroup.type(),
766 updatedBuckets,
767 newCookie,
Saurav Das100e3b82015-04-30 11:12:10 -0700768 oldGroup.givenGroupId(),
alshabib10580802015-02-18 18:30:33 -0800769 oldGroup.appId());
770 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
771 updatedGroupDesc);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700772 log.debug("updateGroupDescriptionInternal: group entry {} in device {} moving from {} to PENDING_UPDATE",
alshabibb0285992016-03-28 23:30:37 -0700773 oldGroup.id(),
774 oldGroup.deviceId(),
775 oldGroup.state());
alshabib10580802015-02-18 18:30:33 -0800776 newGroup.setState(GroupState.PENDING_UPDATE);
777 newGroup.setLife(oldGroup.life());
778 newGroup.setPackets(oldGroup.packets());
779 newGroup.setBytes(oldGroup.bytes());
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700780 //Update the group entry in groupkey based map.
781 //Update to groupid based map will happen in the
782 //groupkey based map update listener
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700783 log.debug("updateGroupDescriptionInternal with type {}: Group updated with buckets",
784 type);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700785 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700786 put(new GroupStoreKeyMapKey(newGroup.deviceId(),
787 newGroup.appCookie()), newGroup);
alshabib10580802015-02-18 18:30:33 -0800788 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700789 } else {
790 log.warn("updateGroupDescriptionInternal with type {}: No "
alshabibb0285992016-03-28 23:30:37 -0700791 + "change in the buckets in update", type);
alshabib10580802015-02-18 18:30:33 -0800792 }
793 }
794
795 private List<GroupBucket> getUpdatedBucketList(Group oldGroup,
796 UpdateType type,
797 GroupBuckets buckets) {
Victor Silva0282ab82016-11-15 16:30:27 -0300798 if (type == UpdateType.SET) {
799 return buckets.buckets();
800 }
801
Victor Silvadf1eeae2016-08-12 15:28:57 -0300802 List<GroupBucket> oldBuckets = oldGroup.buckets().buckets();
803 List<GroupBucket> updatedBucketList = new ArrayList<>();
alshabib10580802015-02-18 18:30:33 -0800804 boolean groupDescUpdated = false;
805
806 if (type == UpdateType.ADD) {
Victor Silvadf1eeae2016-08-12 15:28:57 -0300807 List<GroupBucket> newBuckets = buckets.buckets();
808
809 // Add old buckets that will not be updated and check if any will be updated.
810 for (GroupBucket oldBucket : oldBuckets) {
811 int newBucketIndex = newBuckets.indexOf(oldBucket);
812
813 if (newBucketIndex != -1) {
814 GroupBucket newBucket = newBuckets.get(newBucketIndex);
815 if (!newBucket.hasSameParameters(oldBucket)) {
816 // Bucket will be updated
817 groupDescUpdated = true;
818 }
819 } else {
820 // Old bucket will remain the same - add it.
821 updatedBucketList.add(oldBucket);
alshabib10580802015-02-18 18:30:33 -0800822 }
823 }
Victor Silvadf1eeae2016-08-12 15:28:57 -0300824
825 // Add all new buckets
826 updatedBucketList.addAll(newBuckets);
827 if (!oldBuckets.containsAll(newBuckets)) {
828 groupDescUpdated = true;
829 }
830
alshabib10580802015-02-18 18:30:33 -0800831 } else if (type == UpdateType.REMOVE) {
Victor Silvadf1eeae2016-08-12 15:28:57 -0300832 List<GroupBucket> bucketsToRemove = buckets.buckets();
833
834 // Check which old buckets should remain
835 for (GroupBucket oldBucket : oldBuckets) {
836 if (!bucketsToRemove.contains(oldBucket)) {
837 updatedBucketList.add(oldBucket);
838 } else {
alshabib10580802015-02-18 18:30:33 -0800839 groupDescUpdated = true;
840 }
841 }
842 }
843
844 if (groupDescUpdated) {
Victor Silvadf1eeae2016-08-12 15:28:57 -0300845 return updatedBucketList;
alshabib10580802015-02-18 18:30:33 -0800846 } else {
847 return null;
848 }
849 }
850
851 /**
852 * Triggers deleting the existing group entry.
853 *
alshabibb0285992016-03-28 23:30:37 -0700854 * @param deviceId the device ID
alshabib10580802015-02-18 18:30:33 -0800855 * @param appCookie the group key
856 */
857 @Override
858 public void deleteGroupDescription(DeviceId deviceId,
859 GroupKey appCookie) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700860 // Check if group to be deleted by a remote instance
861 if (mastershipService.
862 getLocalRole(deviceId) != MastershipRole.MASTER) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700863 log.debug("deleteGroupDescription: Device {} local role is not MASTER",
864 deviceId);
865 if (mastershipService.getMasterFor(deviceId) == null) {
866 log.error("No Master for device {}..."
alshabibb0285992016-03-28 23:30:37 -0700867 + "Can not perform delete group operation",
868 deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700869 //TODO: Send Group operation failure event
870 return;
871 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700872 GroupStoreMessage groupOp = GroupStoreMessage.
873 createGroupDeleteRequestMsg(deviceId,
874 appCookie);
Madan Jampani2bfa94c2015-04-11 05:03:49 -0700875
Madan Jampani175e8fd2015-05-20 14:10:45 -0700876 clusterCommunicator.unicast(groupOp,
alshabibb0285992016-03-28 23:30:37 -0700877 GroupStoreMessageSubjects.REMOTE_GROUP_OP_REQUEST,
878 clusterMsgSerializer::serialize,
879 mastershipService.getMasterFor(deviceId)).whenComplete((result, error) -> {
880 if (error != null) {
881 log.warn("Failed to send request to master: {} to {}",
882 groupOp,
883 mastershipService.getMasterFor(deviceId), error);
884 }
885 //TODO: Send Group operation failure event
886 });
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700887 return;
888 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700889 log.debug("deleteGroupDescription in device {} is getting handled locally",
890 deviceId);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700891 deleteGroupDescriptionInternal(deviceId, appCookie);
892 }
893
894 private void deleteGroupDescriptionInternal(DeviceId deviceId,
895 GroupKey appCookie) {
alshabib10580802015-02-18 18:30:33 -0800896 // Check if a group is existing with the provided key
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700897 StoredGroupEntry existing = getStoredGroupEntry(deviceId, appCookie);
alshabib10580802015-02-18 18:30:33 -0800898 if (existing == null) {
899 return;
900 }
901
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700902 log.debug("deleteGroupDescriptionInternal: group entry {} in device {} moving from {} to PENDING_DELETE",
alshabibb0285992016-03-28 23:30:37 -0700903 existing.id(),
904 existing.deviceId(),
905 existing.state());
alshabib10580802015-02-18 18:30:33 -0800906 synchronized (existing) {
907 existing.setState(GroupState.PENDING_DELETE);
Saurav Das80980c72016-03-23 11:22:49 -0700908 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700909 put(new GroupStoreKeyMapKey(existing.deviceId(), existing.appCookie()),
910 existing);
alshabib10580802015-02-18 18:30:33 -0800911 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700912 log.debug("deleteGroupDescriptionInternal: in device {} issuing GROUP_REMOVE_REQUESTED",
913 deviceId);
alshabib10580802015-02-18 18:30:33 -0800914 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, existing));
915 }
916
917 /**
918 * Stores a new group entry, or updates an existing entry.
919 *
920 * @param group group entry
921 */
922 @Override
923 public void addOrUpdateGroupEntry(Group group) {
924 // check if this new entry is an update to an existing entry
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700925 StoredGroupEntry existing = getStoredGroupEntry(group.deviceId(),
926 group.id());
alshabib10580802015-02-18 18:30:33 -0800927 GroupEvent event = null;
928
929 if (existing != null) {
Saurav Das0fd79d92016-03-07 10:58:36 -0800930 log.trace("addOrUpdateGroupEntry: updating group entry {} in device {}",
alshabibb0285992016-03-28 23:30:37 -0700931 group.id(),
932 group.deviceId());
alshabib10580802015-02-18 18:30:33 -0800933 synchronized (existing) {
alshabibb0285992016-03-28 23:30:37 -0700934 for (GroupBucket bucket : group.buckets().buckets()) {
Sho SHIMIZU30d639b2015-05-05 09:30:35 -0700935 Optional<GroupBucket> matchingBucket =
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700936 existing.buckets().buckets()
alshabibb0285992016-03-28 23:30:37 -0700937 .stream()
938 .filter((existingBucket) -> (existingBucket.equals(bucket)))
939 .findFirst();
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700940 if (matchingBucket.isPresent()) {
941 ((StoredGroupBucketEntry) matchingBucket.
942 get()).setPackets(bucket.packets());
943 ((StoredGroupBucketEntry) matchingBucket.
944 get()).setBytes(bucket.bytes());
945 } else {
946 log.warn("addOrUpdateGroupEntry: No matching "
alshabibb0285992016-03-28 23:30:37 -0700947 + "buckets to update stats");
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700948 }
949 }
alshabib10580802015-02-18 18:30:33 -0800950 existing.setLife(group.life());
951 existing.setPackets(group.packets());
952 existing.setBytes(group.bytes());
alshabibb0285992016-03-28 23:30:37 -0700953 existing.setReferenceCount(group.referenceCount());
Saurav Das137f27f2018-06-11 17:02:31 -0700954 existing.setFailedRetryCount(0);
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700955 if ((existing.state() == GroupState.PENDING_ADD) ||
alshabibb0285992016-03-28 23:30:37 -0700956 (existing.state() == GroupState.PENDING_ADD_RETRY)) {
Saurav Das0fd79d92016-03-07 10:58:36 -0800957 log.trace("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED",
alshabibb0285992016-03-28 23:30:37 -0700958 existing.id(),
959 existing.deviceId(),
960 existing.state());
alshabib10580802015-02-18 18:30:33 -0800961 existing.setState(GroupState.ADDED);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700962 existing.setIsGroupStateAddedFirstTime(true);
alshabib10580802015-02-18 18:30:33 -0800963 event = new GroupEvent(Type.GROUP_ADDED, existing);
964 } else {
Saurav Das0fd79d92016-03-07 10:58:36 -0800965 log.trace("addOrUpdateGroupEntry: group entry {} in device {} moving from {} to ADDED",
alshabibb0285992016-03-28 23:30:37 -0700966 existing.id(),
967 existing.deviceId(),
968 GroupState.PENDING_UPDATE);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700969 existing.setState(GroupState.ADDED);
970 existing.setIsGroupStateAddedFirstTime(false);
alshabib10580802015-02-18 18:30:33 -0800971 event = new GroupEvent(Type.GROUP_UPDATED, existing);
972 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700973 //Re-PUT map entries to trigger map update events
974 getGroupStoreKeyMap().
alshabibb0285992016-03-28 23:30:37 -0700975 put(new GroupStoreKeyMapKey(existing.deviceId(),
976 existing.appCookie()), existing);
alshabib10580802015-02-18 18:30:33 -0800977 }
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -0700978 } else {
979 log.warn("addOrUpdateGroupEntry: Group update "
alshabibb0285992016-03-28 23:30:37 -0700980 + "happening for a non-existing entry in the map");
alshabib10580802015-02-18 18:30:33 -0800981 }
982
Saurav Das137f27f2018-06-11 17:02:31 -0700983 // XXX if map is going to trigger event, is this one needed?
alshabib10580802015-02-18 18:30:33 -0800984 if (event != null) {
985 notifyDelegate(event);
986 }
987 }
988
989 /**
990 * Removes the group entry from store.
991 *
992 * @param group group entry
993 */
994 @Override
995 public void removeGroupEntry(Group group) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700996 StoredGroupEntry existing = getStoredGroupEntry(group.deviceId(),
997 group.id());
alshabib10580802015-02-18 18:30:33 -0800998
999 if (existing != null) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001000 log.debug("removeGroupEntry: removing group entry {} in device {}",
alshabibb0285992016-03-28 23:30:37 -07001001 group.id(),
1002 group.deviceId());
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -07001003 //Removal from groupid based map will happen in the
1004 //map update listener
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001005 getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
1006 existing.appCookie()));
alshabib10580802015-02-18 18:30:33 -08001007 notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing));
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001008 } else {
1009 log.warn("removeGroupEntry for {} in device{} is "
alshabibb0285992016-03-28 23:30:37 -07001010 + "not existing in our maps",
1011 group.id(),
1012 group.deviceId());
alshabib10580802015-02-18 18:30:33 -08001013 }
1014 }
1015
Victor Silva4e8b7832016-08-17 17:11:19 -03001016 private void purgeGroupEntries(Set<Entry<GroupStoreKeyMapKey, StoredGroupEntry>> entries) {
1017 entries.forEach(entry -> {
1018 groupStoreEntriesByKey.remove(entry.getKey());
1019 });
1020 }
1021
alshabib10580802015-02-18 18:30:33 -08001022 @Override
Charles Chan0c7c43b2016-01-14 17:39:20 -08001023 public void purgeGroupEntry(DeviceId deviceId) {
Victor Silva4e8b7832016-08-17 17:11:19 -03001024 Set<Entry<GroupStoreKeyMapKey, StoredGroupEntry>> entriesPendingRemove =
Charles Chan0c7c43b2016-01-14 17:39:20 -08001025 new HashSet<>();
1026
Madan Jampani0b847532016-03-03 13:44:15 -08001027 getGroupStoreKeyMap().entrySet().stream()
Charles Chan0c7c43b2016-01-14 17:39:20 -08001028 .filter(entry -> entry.getKey().deviceId().equals(deviceId))
Victor Silva4e8b7832016-08-17 17:11:19 -03001029 .forEach(entriesPendingRemove::add);
Charles Chan0c7c43b2016-01-14 17:39:20 -08001030
Victor Silva4e8b7832016-08-17 17:11:19 -03001031 purgeGroupEntries(entriesPendingRemove);
1032 }
1033
1034 @Override
1035 public void purgeGroupEntries() {
1036 purgeGroupEntries(getGroupStoreKeyMap().entrySet());
Charles Chan0c7c43b2016-01-14 17:39:20 -08001037 }
1038
1039 @Override
alshabib10580802015-02-18 18:30:33 -08001040 public void deviceInitialAuditCompleted(DeviceId deviceId,
1041 boolean completed) {
1042 synchronized (deviceAuditStatus) {
1043 if (completed) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001044 log.debug("AUDIT completed for device {}",
1045 deviceId);
alshabib10580802015-02-18 18:30:33 -08001046 deviceAuditStatus.put(deviceId, true);
1047 // Execute all pending group requests
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001048 List<StoredGroupEntry> pendingGroupRequests =
1049 getPendingGroupKeyTable().values()
alshabibb0285992016-03-28 23:30:37 -07001050 .stream()
1051 .filter(g -> g.deviceId().equals(deviceId))
1052 .collect(Collectors.toList());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001053 log.debug("processing pending group add requests for device {} and number of pending requests {}",
alshabibb0285992016-03-28 23:30:37 -07001054 deviceId,
1055 pendingGroupRequests.size());
1056 for (Group group : pendingGroupRequests) {
alshabib10580802015-02-18 18:30:33 -08001057 GroupDescription tmp = new DefaultGroupDescription(
1058 group.deviceId(),
1059 group.type(),
1060 group.buckets(),
1061 group.appCookie(),
Saurav Das100e3b82015-04-30 11:12:10 -07001062 group.givenGroupId(),
alshabib10580802015-02-18 18:30:33 -08001063 group.appId());
1064 storeGroupDescriptionInternal(tmp);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001065 getPendingGroupKeyTable().
alshabibb0285992016-03-28 23:30:37 -07001066 remove(new GroupStoreKeyMapKey(deviceId, group.appCookie()));
alshabib10580802015-02-18 18:30:33 -08001067 }
alshabib10580802015-02-18 18:30:33 -08001068 } else {
Thomas Vachuskac40d4632015-04-09 16:55:03 -07001069 Boolean audited = deviceAuditStatus.get(deviceId);
1070 if (audited != null && audited) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001071 log.debug("Clearing AUDIT status for device {}", deviceId);
alshabib10580802015-02-18 18:30:33 -08001072 deviceAuditStatus.put(deviceId, false);
1073 }
1074 }
1075 }
1076 }
1077
1078 @Override
1079 public boolean deviceInitialAuditStatus(DeviceId deviceId) {
1080 synchronized (deviceAuditStatus) {
Thomas Vachuskac40d4632015-04-09 16:55:03 -07001081 Boolean audited = deviceAuditStatus.get(deviceId);
1082 return audited != null && audited;
alshabib10580802015-02-18 18:30:33 -08001083 }
1084 }
1085
1086 @Override
1087 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
1088
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001089 StoredGroupEntry existing = getStoredGroupEntry(deviceId,
1090 operation.groupId());
alshabib10580802015-02-18 18:30:33 -08001091
1092 if (existing == null) {
1093 log.warn("No group entry with ID {} found ", operation.groupId());
1094 return;
1095 }
1096
Saurav Das137f27f2018-06-11 17:02:31 -07001097 log.warn("groupOperationFailed: group operation {} failed in state {} "
alshabibb0285992016-03-28 23:30:37 -07001098 + "for group {} in device {} with code {}",
1099 operation.opType(),
Saurav Das137f27f2018-06-11 17:02:31 -07001100 existing.state(),
alshabibb0285992016-03-28 23:30:37 -07001101 existing.id(),
1102 existing.deviceId(),
1103 operation.failureCode());
Saurav Das0fd79d92016-03-07 10:58:36 -08001104 if (operation.failureCode() == GroupOperation.GroupMsgErrorCode.GROUP_EXISTS) {
Saurav Das8be4e3a2016-03-11 17:19:07 -08001105 if (operation.buckets().equals(existing.buckets())) {
Saurav Dasc88d4662017-05-15 15:34:25 -07001106 if (existing.state() == GroupState.PENDING_ADD ||
1107 existing.state() == GroupState.PENDING_ADD_RETRY) {
Saurav Das8be4e3a2016-03-11 17:19:07 -08001108 log.info("GROUP_EXISTS: GroupID and Buckets match for group in pending "
alshabibb0285992016-03-28 23:30:37 -07001109 + "add state - moving to ADDED for group {} in device {}",
1110 existing.id(), deviceId);
Saurav Das8be4e3a2016-03-11 17:19:07 -08001111 addOrUpdateGroupEntry(existing);
1112 return;
1113 } else {
Saurav Dasc88d4662017-05-15 15:34:25 -07001114 log.warn("GROUP_EXISTS: GroupId and Buckets match but existing"
1115 + "group in state: {}", existing.state());
Saurav Das8be4e3a2016-03-11 17:19:07 -08001116 }
Saurav Dasc88d4662017-05-15 15:34:25 -07001117 } else {
1118 log.warn("GROUP EXISTS: Group ID matched but buckets did not. "
1119 + "Operation: {} Existing: {}", operation.buckets(),
1120 existing.buckets());
Saurav Das8be4e3a2016-03-11 17:19:07 -08001121 }
Saurav Das0fd79d92016-03-07 10:58:36 -08001122 }
Saurav Das137f27f2018-06-11 17:02:31 -07001123 if (operation.failureCode() == GroupOperation.GroupMsgErrorCode.INVALID_GROUP) {
1124 existing.incrFailedRetryCount();
1125 if (existing.failedRetryCount() < MAX_FAILED_ATTEMPTS) {
1126 log.warn("Group {} programming failed {} of {} times in dev {}, "
1127 + "retrying ..", existing.id(),
1128 existing.failedRetryCount(), MAX_FAILED_ATTEMPTS,
1129 deviceId);
1130 return;
1131 }
1132 log.warn("Group {} programming failed {} of {} times in dev {}, "
1133 + "removing group from store", existing.id(),
1134 existing.failedRetryCount(), MAX_FAILED_ATTEMPTS,
1135 deviceId);
1136 // fall through to case
1137 }
1138
alshabib10580802015-02-18 18:30:33 -08001139 switch (operation.opType()) {
1140 case ADD:
Saurav Das137f27f2018-06-11 17:02:31 -07001141 if (existing.state() == GroupState.PENDING_ADD
1142 || existing.state() == GroupState.PENDING_ADD_RETRY) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -07001143 notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
1144 log.warn("groupOperationFailed: cleaningup "
alshabibb0285992016-03-28 23:30:37 -07001145 + "group {} from store in device {}....",
1146 existing.id(),
1147 existing.deviceId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -07001148 //Removal from groupid based map will happen in the
1149 //map update listener
1150 getGroupStoreKeyMap().remove(new GroupStoreKeyMapKey(existing.deviceId(),
1151 existing.appCookie()));
1152 }
alshabib10580802015-02-18 18:30:33 -08001153 break;
1154 case MODIFY:
1155 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
1156 break;
1157 case DELETE:
1158 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing));
1159 break;
1160 default:
1161 log.warn("Unknown group operation type {}", operation.opType());
1162 }
alshabib10580802015-02-18 18:30:33 -08001163 }
1164
1165 @Override
1166 public void addOrUpdateExtraneousGroupEntry(Group group) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001167 log.debug("add/update extraneous group entry {} in device {}",
alshabibb0285992016-03-28 23:30:37 -07001168 group.id(),
1169 group.deviceId());
alshabib10580802015-02-18 18:30:33 -08001170 ConcurrentMap<GroupId, Group> extraneousIdTable =
1171 getExtraneousGroupIdTable(group.deviceId());
1172 extraneousIdTable.put(group.id(), group);
Srikanth Vavilapallie48b3cf2015-07-06 11:43:07 -07001173 // Don't remove the extraneous groups, instead re-use it when
1174 // a group request comes with the same set of buckets
alshabib10580802015-02-18 18:30:33 -08001175 }
1176
1177 @Override
1178 public void removeExtraneousGroupEntry(Group group) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001179 log.debug("remove extraneous group entry {} of device {} from store",
alshabibb0285992016-03-28 23:30:37 -07001180 group.id(),
1181 group.deviceId());
alshabib10580802015-02-18 18:30:33 -08001182 ConcurrentMap<GroupId, Group> extraneousIdTable =
1183 getExtraneousGroupIdTable(group.deviceId());
1184 extraneousIdTable.remove(group.id());
1185 }
1186
1187 @Override
1188 public Iterable<Group> getExtraneousGroups(DeviceId deviceId) {
1189 // flatten and make iterator unmodifiable
1190 return FluentIterable.from(
1191 getExtraneousGroupIdTable(deviceId).values());
1192 }
1193
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001194 /**
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -07001195 * Map handler to receive any events when the group key map is updated.
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001196 */
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -07001197 private class GroupStoreKeyMapListener implements
Madan Jampani0b847532016-03-03 13:44:15 -08001198 MapEventListener<GroupStoreKeyMapKey, StoredGroupEntry> {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001199
1200 @Override
Madan Jampani0b847532016-03-03 13:44:15 -08001201 public void event(MapEvent<GroupStoreKeyMapKey, StoredGroupEntry> mapEvent) {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001202 GroupEvent groupEvent = null;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001203 GroupStoreKeyMapKey key = mapEvent.key();
Madan Jampani0b847532016-03-03 13:44:15 -08001204 StoredGroupEntry group = Versioned.valueOrNull(mapEvent.newValue());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001205 if ((key == null) && (group == null)) {
1206 log.error("GroupStoreKeyMapListener: Received "
alshabibb0285992016-03-28 23:30:37 -07001207 + "event {} with null entry", mapEvent.type());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001208 return;
1209 } else if (group == null) {
1210 group = getGroupIdTable(key.deviceId()).values()
1211 .stream()
1212 .filter((storedGroup) -> (storedGroup.appCookie().equals(key.appCookie)))
Yuta HIGUCHI6e5f4702016-11-21 11:42:11 -08001213 .findFirst().orElse(null);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001214 if (group == null) {
1215 log.error("GroupStoreKeyMapListener: Received "
alshabibb0285992016-03-28 23:30:37 -07001216 + "event {} with null entry... can not process", mapEvent.type());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001217 return;
1218 }
1219 }
1220 log.trace("received groupid map event {} for id {} in device {}",
1221 mapEvent.type(),
1222 group.id(),
jaegonkim68e080c2016-12-01 22:31:01 +09001223 (key != null ? key.deviceId() : null));
Madan Jampani0b847532016-03-03 13:44:15 -08001224 if (mapEvent.type() == MapEvent.Type.INSERT || mapEvent.type() == MapEvent.Type.UPDATE) {
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -07001225 // Update the group ID table
1226 getGroupIdTable(group.deviceId()).put(group.id(), group);
Madan Jampani0b847532016-03-03 13:44:15 -08001227 StoredGroupEntry value = Versioned.valueOrNull(mapEvent.newValue());
1228 if (value.state() == Group.GroupState.ADDED) {
1229 if (value.isGroupStateAddedFirstTime()) {
1230 groupEvent = new GroupEvent(Type.GROUP_ADDED, value);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001231 log.trace("Received first time GROUP_ADDED state update for id {} in device {}",
alshabibb0285992016-03-28 23:30:37 -07001232 group.id(),
1233 group.deviceId());
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001234 } else {
Madan Jampani0b847532016-03-03 13:44:15 -08001235 groupEvent = new GroupEvent(Type.GROUP_UPDATED, value);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001236 log.trace("Received following GROUP_ADDED state update for id {} in device {}",
alshabibb0285992016-03-28 23:30:37 -07001237 group.id(),
1238 group.deviceId());
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001239 }
1240 }
Madan Jampani0b847532016-03-03 13:44:15 -08001241 } else if (mapEvent.type() == MapEvent.Type.REMOVE) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001242 groupEvent = new GroupEvent(Type.GROUP_REMOVED, group);
Srikanth Vavilapalli6a9d4e42015-03-30 19:41:56 -07001243 // Remove the entry from the group ID table
1244 getGroupIdTable(group.deviceId()).remove(group.id(), group);
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001245 }
1246
1247 if (groupEvent != null) {
1248 notifyDelegate(groupEvent);
1249 }
1250 }
1251 }
Madan Jampani01e05fb2015-08-13 13:29:36 -07001252
helenyrwua1c41152016-08-18 16:16:14 -07001253 private void processGroupMessage(GroupStoreMessage message) {
1254 if (message.type() == GroupStoreMessage.Type.FAILOVER) {
1255 // FIXME: groupStoreEntriesByKey inaccessible here
1256 getGroupIdTable(message.deviceId()).values()
1257 .stream()
1258 .filter((storedGroup) -> (storedGroup.appCookie().equals(message.appCookie())))
1259 .findFirst().ifPresent(group -> notifyDelegate(new GroupEvent(Type.GROUP_BUCKET_FAILOVER, group)));
1260 }
1261 }
1262
Madan Jampani01e05fb2015-08-13 13:29:36 -07001263 private void process(GroupStoreMessage groupOp) {
1264 log.debug("Received remote group operation {} request for device {}",
alshabibb0285992016-03-28 23:30:37 -07001265 groupOp.type(),
1266 groupOp.deviceId());
1267 if (!mastershipService.isLocalMaster(groupOp.deviceId())) {
1268 log.warn("This node is not MASTER for device {}", groupOp.deviceId());
1269 return;
1270 }
1271 if (groupOp.type() == GroupStoreMessage.Type.ADD) {
1272 storeGroupDescriptionInternal(groupOp.groupDesc());
1273 } else if (groupOp.type() == GroupStoreMessage.Type.UPDATE) {
1274 updateGroupDescriptionInternal(groupOp.deviceId(),
1275 groupOp.appCookie(),
1276 groupOp.updateType(),
1277 groupOp.updateBuckets(),
1278 groupOp.newAppCookie());
1279 } else if (groupOp.type() == GroupStoreMessage.Type.DELETE) {
1280 deleteGroupDescriptionInternal(groupOp.deviceId(),
1281 groupOp.appCookie());
1282 }
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001283 }
1284
1285 /**
1286 * Flattened map key to be used to store group entries.
1287 */
Ray Milkeyb3c5ce22015-08-10 09:07:36 -07001288 protected static class GroupStoreMapKey {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001289 private final DeviceId deviceId;
1290
1291 public GroupStoreMapKey(DeviceId deviceId) {
1292 this.deviceId = deviceId;
1293 }
1294
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001295 public DeviceId deviceId() {
1296 return deviceId;
1297 }
1298
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001299 @Override
1300 public boolean equals(Object o) {
1301 if (this == o) {
1302 return true;
1303 }
1304 if (!(o instanceof GroupStoreMapKey)) {
1305 return false;
1306 }
1307 GroupStoreMapKey that = (GroupStoreMapKey) o;
1308 return this.deviceId.equals(that.deviceId);
1309 }
1310
1311 @Override
1312 public int hashCode() {
1313 int result = 17;
1314
1315 result = 31 * result + Objects.hash(this.deviceId);
1316
1317 return result;
1318 }
1319 }
1320
Ray Milkeyb3c5ce22015-08-10 09:07:36 -07001321 protected static class GroupStoreKeyMapKey extends GroupStoreMapKey {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001322 private final GroupKey appCookie;
alshabibb0285992016-03-28 23:30:37 -07001323
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001324 public GroupStoreKeyMapKey(DeviceId deviceId,
1325 GroupKey appCookie) {
1326 super(deviceId);
1327 this.appCookie = appCookie;
1328 }
1329
1330 @Override
1331 public boolean equals(Object o) {
1332 if (this == o) {
1333 return true;
1334 }
1335 if (!(o instanceof GroupStoreKeyMapKey)) {
1336 return false;
1337 }
1338 GroupStoreKeyMapKey that = (GroupStoreKeyMapKey) o;
1339 return (super.equals(that) &&
1340 this.appCookie.equals(that.appCookie));
1341 }
1342
1343 @Override
1344 public int hashCode() {
1345 int result = 17;
1346
1347 result = 31 * result + super.hashCode() + Objects.hash(this.appCookie);
1348
1349 return result;
1350 }
1351 }
1352
Ray Milkeyb3c5ce22015-08-10 09:07:36 -07001353 protected static class GroupStoreIdMapKey extends GroupStoreMapKey {
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001354 private final GroupId groupId;
alshabibb0285992016-03-28 23:30:37 -07001355
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -07001356 public GroupStoreIdMapKey(DeviceId deviceId,
1357 GroupId groupId) {
1358 super(deviceId);
1359 this.groupId = groupId;
1360 }
1361
1362 @Override
1363 public boolean equals(Object o) {
1364 if (this == o) {
1365 return true;
1366 }
1367 if (!(o instanceof GroupStoreIdMapKey)) {
1368 return false;
1369 }
1370 GroupStoreIdMapKey that = (GroupStoreIdMapKey) o;
1371 return (super.equals(that) &&
1372 this.groupId.equals(that.groupId));
1373 }
1374
1375 @Override
1376 public int hashCode() {
1377 int result = 17;
1378
1379 result = 31 * result + super.hashCode() + Objects.hash(this.groupId);
1380
1381 return result;
1382 }
1383 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001384
1385 @Override
1386 public void pushGroupMetrics(DeviceId deviceId,
1387 Collection<Group> groupEntries) {
1388 boolean deviceInitialAuditStatus =
1389 deviceInitialAuditStatus(deviceId);
1390 Set<Group> southboundGroupEntries =
1391 Sets.newHashSet(groupEntries);
1392 Set<StoredGroupEntry> storedGroupEntries =
1393 Sets.newHashSet(getStoredGroups(deviceId));
1394 Set<Group> extraneousStoredEntries =
1395 Sets.newHashSet(getExtraneousGroups(deviceId));
1396
Sho SHIMIZU695bac62016-08-15 12:41:59 -07001397 if (log.isTraceEnabled()) {
1398 log.trace("pushGroupMetrics: Displaying all ({}) southboundGroupEntries for device {}",
1399 southboundGroupEntries.size(),
1400 deviceId);
1401 for (Group group : southboundGroupEntries) {
1402 log.trace("Group {} in device {}", group, deviceId);
1403 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001404
Sho SHIMIZU695bac62016-08-15 12:41:59 -07001405 log.trace("Displaying all ({}) stored group entries for device {}",
1406 storedGroupEntries.size(),
1407 deviceId);
1408 for (StoredGroupEntry group : storedGroupEntries) {
1409 log.trace("Stored Group {} for device {}", group, deviceId);
1410 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001411 }
1412
alshabibb0285992016-03-28 23:30:37 -07001413 garbageCollect(deviceId, southboundGroupEntries, storedGroupEntries);
1414
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001415 for (Iterator<Group> it2 = southboundGroupEntries.iterator(); it2.hasNext();) {
1416 Group group = it2.next();
1417 if (storedGroupEntries.remove(group)) {
1418 // we both have the group, let's update some info then.
1419 log.trace("Group AUDIT: group {} exists in both planes for device {}",
alshabibb0285992016-03-28 23:30:37 -07001420 group.id(), deviceId);
1421
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001422 groupAdded(group);
1423 it2.remove();
1424 }
1425 }
1426 for (Group group : southboundGroupEntries) {
1427 if (getGroup(group.deviceId(), group.id()) != null) {
1428 // There is a group existing with the same id
1429 // It is possible that group update is
1430 // in progress while we got a stale info from switch
1431 if (!storedGroupEntries.remove(getGroup(
alshabibb0285992016-03-28 23:30:37 -07001432 group.deviceId(), group.id()))) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001433 log.warn("Group AUDIT: Inconsistent state:"
alshabibb0285992016-03-28 23:30:37 -07001434 + "Group exists in ID based table while "
1435 + "not present in key based table");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001436 }
1437 } else {
1438 // there are groups in the switch that aren't in the store
1439 log.debug("Group AUDIT: extraneous group {} exists in data plane for device {}",
alshabibb0285992016-03-28 23:30:37 -07001440 group.id(), deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001441 extraneousStoredEntries.remove(group);
Kavitha Alagesanc56cded2017-01-13 10:48:18 +05301442 if (allowExtraneousGroups) {
1443 extraneousGroup(group);
1444 } else {
1445 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
1446 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001447 }
1448 }
Charles Chan07f15f22018-05-08 21:35:50 -07001449 for (StoredGroupEntry group : storedGroupEntries) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001450 // there are groups in the store that aren't in the switch
1451 log.debug("Group AUDIT: group {} missing in data plane for device {}",
alshabibb0285992016-03-28 23:30:37 -07001452 group.id(), deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001453 groupMissing(group);
1454 }
1455 for (Group group : extraneousStoredEntries) {
1456 // there are groups in the extraneous store that
1457 // aren't in the switch
Saurav Das0fd79d92016-03-07 10:58:36 -08001458 log.debug("Group AUDIT: clearing extraneous group {} from store for device {}",
alshabibb0285992016-03-28 23:30:37 -07001459 group.id(), deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001460 removeExtraneousGroupEntry(group);
1461 }
1462
1463 if (!deviceInitialAuditStatus) {
Saurav Das0fd79d92016-03-07 10:58:36 -08001464 log.info("Group AUDIT: Setting device {} initial AUDIT completed",
alshabibb0285992016-03-28 23:30:37 -07001465 deviceId);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001466 deviceInitialAuditCompleted(deviceId, true);
1467 }
1468 }
1469
helenyrwu89470f12016-08-12 13:18:10 -07001470 @Override
1471 public void notifyOfFailovers(Collection<Group> failoverGroups) {
helenyrwu89470f12016-08-12 13:18:10 -07001472 failoverGroups.forEach(group -> {
1473 if (group.type() == Group.Type.FAILOVER) {
helenyrwua1c41152016-08-18 16:16:14 -07001474 groupTopic.publish(GroupStoreMessage.createGroupFailoverMsg(
1475 group.deviceId(), group));
helenyrwu89470f12016-08-12 13:18:10 -07001476 }
1477 });
helenyrwu89470f12016-08-12 13:18:10 -07001478 }
1479
alshabibb0285992016-03-28 23:30:37 -07001480 private void garbageCollect(DeviceId deviceId,
1481 Set<Group> southboundGroupEntries,
1482 Set<StoredGroupEntry> storedGroupEntries) {
1483 if (!garbageCollect) {
1484 return;
1485 }
1486
1487 Iterator<StoredGroupEntry> it = storedGroupEntries.iterator();
1488 while (it.hasNext()) {
1489 StoredGroupEntry group = it.next();
1490 if (group.state() != GroupState.PENDING_DELETE && checkGroupRefCount(group)) {
1491 log.debug("Garbage collecting group {} on {}", group, deviceId);
1492 deleteGroupDescription(deviceId, group.appCookie());
1493 southboundGroupEntries.remove(group);
1494 it.remove();
1495 }
1496 }
1497 }
1498
1499 private boolean checkGroupRefCount(Group group) {
1500 return (group.referenceCount() == 0 && group.age() >= gcThresh);
1501 }
1502
Charles Chan07f15f22018-05-08 21:35:50 -07001503 private void groupMissing(StoredGroupEntry group) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001504 switch (group.state()) {
1505 case PENDING_DELETE:
1506 log.debug("Group {} delete confirmation from device {}",
1507 group, group.deviceId());
1508 removeGroupEntry(group);
1509 break;
1510 case ADDED:
1511 case PENDING_ADD:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -07001512 case PENDING_ADD_RETRY:
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001513 case PENDING_UPDATE:
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -07001514 log.debug("groupMissing: group entry {} in device {} moving from {} to PENDING_ADD_RETRY",
Charles Chan07f15f22018-05-08 21:35:50 -07001515 group.id(),
1516 group.deviceId(),
1517 group.state());
1518 group.setState(Group.GroupState.PENDING_ADD_RETRY);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001519 //Re-PUT map entries to trigger map update events
Charles Chan07f15f22018-05-08 21:35:50 -07001520 getGroupStoreKeyMap().put(new GroupStoreKeyMapKey(group.deviceId(), group.appCookie()), group);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001521 notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
1522 group));
1523 break;
1524 default:
1525 log.debug("Group {} has not been installed.", group);
1526 break;
1527 }
1528 }
1529
1530 private void extraneousGroup(Group group) {
Saurav Das0fd79d92016-03-07 10:58:36 -08001531 log.trace("Group {} is on device {} but not in store.",
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001532 group, group.deviceId());
1533 addOrUpdateExtraneousGroupEntry(group);
1534 }
1535
1536 private void groupAdded(Group group) {
1537 log.trace("Group {} Added or Updated in device {}",
1538 group, group.deviceId());
1539 addOrUpdateGroupEntry(group);
1540 }
alshabib10580802015-02-18 18:30:33 -08001541}