blob: 5e6c084a18c2fd87077be8e818b43515c79bee68 [file] [log] [blame]
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -08001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
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.trivial.impl;
17
18import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.util.ArrayList;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080022import java.util.HashMap;
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080023import java.util.List;
Sho SHIMIZU30d639b2015-05-05 09:30:35 -070024import java.util.Optional;
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080025import java.util.concurrent.ConcurrentHashMap;
26import java.util.concurrent.ConcurrentMap;
27import java.util.concurrent.atomic.AtomicInteger;
28
29import org.apache.felix.scr.annotations.Activate;
30import org.apache.felix.scr.annotations.Component;
31import org.apache.felix.scr.annotations.Deactivate;
32import org.apache.felix.scr.annotations.Service;
33import org.onlab.util.NewConcurrentHashMap;
34import org.onosproject.core.DefaultGroupId;
35import org.onosproject.core.GroupId;
36import org.onosproject.net.DeviceId;
37import org.onosproject.net.group.DefaultGroup;
38import org.onosproject.net.group.DefaultGroupDescription;
39import org.onosproject.net.group.Group;
40import org.onosproject.net.group.Group.GroupState;
41import org.onosproject.net.group.GroupBucket;
42import org.onosproject.net.group.GroupBuckets;
43import org.onosproject.net.group.GroupDescription;
44import org.onosproject.net.group.GroupEvent;
45import org.onosproject.net.group.GroupEvent.Type;
46import org.onosproject.net.group.GroupKey;
sangho7ff01812015-02-09 16:21:53 -080047import org.onosproject.net.group.GroupOperation;
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080048import org.onosproject.net.group.GroupStore;
49import org.onosproject.net.group.GroupStoreDelegate;
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -070050import org.onosproject.net.group.StoredGroupBucketEntry;
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080051import org.onosproject.net.group.StoredGroupEntry;
52import org.onosproject.store.AbstractStore;
53import org.slf4j.Logger;
54
55import com.google.common.base.Function;
56import com.google.common.collect.FluentIterable;
57
58/**
59 * Manages inventory of group entries using trivial in-memory implementation.
60 */
61@Component(immediate = true)
62@Service
63public class SimpleGroupStore
64 extends AbstractStore<GroupEvent, GroupStoreDelegate>
65 implements GroupStore {
66
67 private final Logger log = getLogger(getClass());
68
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080069 private final int dummyId = 0xffffffff;
70 private final GroupId dummyGroupId = new DefaultGroupId(dummyId);
71
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080072 // inner Map is per device group table
73 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>>
74 groupEntriesByKey = new ConcurrentHashMap<>();
75 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>>
76 groupEntriesById = new ConcurrentHashMap<>();
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080077 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>>
78 pendingGroupEntriesByKey = new ConcurrentHashMap<>();
79 private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>>
80 extraneousGroupEntriesById = new ConcurrentHashMap<>();
81
82 private final HashMap<DeviceId, Boolean> deviceAuditStatus =
83 new HashMap<DeviceId, Boolean>();
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -080084
85 private final AtomicInteger groupIdGen = new AtomicInteger();
86
87 @Activate
88 public void activate() {
89 log.info("Started");
90 }
91
92 @Deactivate
93 public void deactivate() {
94 groupEntriesByKey.clear();
95 groupEntriesById.clear();
96 log.info("Stopped");
97 }
98
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -080099 private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
100 lazyEmptyGroupKeyTable() {
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800101 return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
102 }
103
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800104 private static NewConcurrentHashMap<GroupId, StoredGroupEntry>
105 lazyEmptyGroupIdTable() {
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800106 return NewConcurrentHashMap.<GroupId, StoredGroupEntry>ifNeeded();
107 }
108
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800109 private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
110 lazyEmptyPendingGroupKeyTable() {
111 return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
112 }
113
114 private static NewConcurrentHashMap<GroupId, Group>
115 lazyEmptyExtraneousGroupIdTable() {
116 return NewConcurrentHashMap.<GroupId, Group>ifNeeded();
117 }
118
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800119 /**
120 * Returns the group key table for specified device.
121 *
122 * @param deviceId identifier of the device
123 * @return Map representing group key table of given device.
124 */
125 private ConcurrentMap<GroupKey, StoredGroupEntry> getGroupKeyTable(DeviceId deviceId) {
126 return createIfAbsentUnchecked(groupEntriesByKey,
127 deviceId, lazyEmptyGroupKeyTable());
128 }
129
130 /**
131 * Returns the group id table for specified device.
132 *
133 * @param deviceId identifier of the device
134 * @return Map representing group key table of given device.
135 */
136 private ConcurrentMap<GroupId, StoredGroupEntry> getGroupIdTable(DeviceId deviceId) {
137 return createIfAbsentUnchecked(groupEntriesById,
138 deviceId, lazyEmptyGroupIdTable());
139 }
140
141 /**
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800142 * Returns the pending group key table for specified device.
143 *
144 * @param deviceId identifier of the device
145 * @return Map representing group key table of given device.
146 */
147 private ConcurrentMap<GroupKey, StoredGroupEntry>
148 getPendingGroupKeyTable(DeviceId deviceId) {
149 return createIfAbsentUnchecked(pendingGroupEntriesByKey,
150 deviceId, lazyEmptyPendingGroupKeyTable());
151 }
152
153 /**
154 * Returns the extraneous group id table for specified device.
155 *
156 * @param deviceId identifier of the device
157 * @return Map representing group key table of given device.
158 */
159 private ConcurrentMap<GroupId, Group>
160 getExtraneousGroupIdTable(DeviceId deviceId) {
161 return createIfAbsentUnchecked(extraneousGroupEntriesById,
162 deviceId,
163 lazyEmptyExtraneousGroupIdTable());
164 }
165
166 /**
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800167 * Returns the number of groups for the specified device in the store.
168 *
169 * @return number of groups for the specified device
170 */
171 @Override
172 public int getGroupCount(DeviceId deviceId) {
173 return (groupEntriesByKey.get(deviceId) != null) ?
174 groupEntriesByKey.get(deviceId).size() : 0;
175 }
176
177 /**
178 * Returns the groups associated with a device.
179 *
180 * @param deviceId the device ID
181 *
182 * @return the group entries
183 */
184 @Override
185 public Iterable<Group> getGroups(DeviceId deviceId) {
186 // flatten and make iterator unmodifiable
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800187 return FluentIterable.from(getGroupKeyTable(deviceId).values())
188 .transform(
189 new Function<StoredGroupEntry, Group>() {
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800190
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800191 @Override
192 public Group apply(
193 StoredGroupEntry input) {
194 return input;
195 }
196 });
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800197 }
198
199 /**
200 * Returns the stored group entry.
201 *
202 * @param deviceId the device ID
203 * @param appCookie the group key
204 *
205 * @return a group associated with the key
206 */
207 @Override
208 public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
209 return (groupEntriesByKey.get(deviceId) != null) ?
210 groupEntriesByKey.get(deviceId).get(appCookie) :
211 null;
212 }
213
Srikanth Vavilapalli717361f2015-03-16 12:06:04 -0700214 @Override
215 public Group getGroup(DeviceId deviceId, GroupId groupId) {
216 return (groupEntriesById.get(deviceId) != null) ?
217 groupEntriesById.get(deviceId).get(groupId) :
218 null;
219 }
220
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800221 private int getFreeGroupIdValue(DeviceId deviceId) {
222 int freeId = groupIdGen.incrementAndGet();
223
224 while (true) {
225 Group existing = (
226 groupEntriesById.get(deviceId) != null) ?
227 groupEntriesById.get(deviceId).get(new DefaultGroupId(freeId)) :
228 null;
229 if (existing == null) {
230 existing = (
231 extraneousGroupEntriesById.get(deviceId) != null) ?
232 extraneousGroupEntriesById.get(deviceId).
233 get(new DefaultGroupId(freeId)) :
234 null;
235 }
236 if (existing != null) {
237 freeId = groupIdGen.incrementAndGet();
238 } else {
239 break;
240 }
241 }
242 return freeId;
243 }
244
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800245 /**
246 * Stores a new group entry using the information from group description.
247 *
248 * @param groupDesc group description to be used to create group entry
249 */
250 @Override
251 public void storeGroupDescription(GroupDescription groupDesc) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800252 // Check if a group is existing with the same key
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800253 if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
254 return;
255 }
256
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800257 if (deviceAuditStatus.get(groupDesc.deviceId()) == null) {
258 // Device group audit has not completed yet
259 // Add this group description to pending group key table
260 // Create a group entry object with Dummy Group ID
261 StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc);
262 group.setState(GroupState.WAITING_AUDIT_COMPLETE);
263 ConcurrentMap<GroupKey, StoredGroupEntry> pendingKeyTable =
264 getPendingGroupKeyTable(groupDesc.deviceId());
265 pendingKeyTable.put(groupDesc.appCookie(), group);
266 return;
267 }
268
269 storeGroupDescriptionInternal(groupDesc);
270 }
271
272 private void storeGroupDescriptionInternal(GroupDescription groupDesc) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800273 // Check if a group is existing with the same key
274 if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
275 return;
276 }
277
Saurav Das100e3b82015-04-30 11:12:10 -0700278 GroupId id = null;
279 if (groupDesc.givenGroupId() == null) {
280 // Get a new group identifier
281 id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
282 } else {
283 id = new DefaultGroupId(groupDesc.givenGroupId());
284 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800285 // Create a group entry object
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800286 StoredGroupEntry group = new DefaultGroup(id, groupDesc);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800287 // Insert the newly created group entry into concurrent key and id maps
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800288 ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
289 getGroupKeyTable(groupDesc.deviceId());
290 keyTable.put(groupDesc.appCookie(), group);
291 ConcurrentMap<GroupId, StoredGroupEntry> idTable =
292 getGroupIdTable(groupDesc.deviceId());
293 idTable.put(id, group);
294 notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
295 group));
296 }
297
298 /**
299 * Updates the existing group entry with the information
300 * from group description.
301 *
302 * @param deviceId the device ID
303 * @param oldAppCookie the current group key
304 * @param type update type
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800305 * @param newBuckets group buckets for updates
306 * @param newAppCookie optional new group key
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800307 */
308 @Override
309 public void updateGroupDescription(DeviceId deviceId,
310 GroupKey oldAppCookie,
311 UpdateType type,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800312 GroupBuckets newBuckets,
313 GroupKey newAppCookie) {
314 // Check if a group is existing with the provided key
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800315 Group oldGroup = getGroup(deviceId, oldAppCookie);
316 if (oldGroup == null) {
317 return;
318 }
319
320 List<GroupBucket> newBucketList = getUpdatedBucketList(oldGroup,
321 type,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800322 newBuckets);
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800323 if (newBucketList != null) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800324 // Create a new group object from the old group
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800325 GroupBuckets updatedBuckets = new GroupBuckets(newBucketList);
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800326 GroupKey newCookie = (newAppCookie != null) ? newAppCookie : oldAppCookie;
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800327 GroupDescription updatedGroupDesc = new DefaultGroupDescription(
328 oldGroup.deviceId(),
329 oldGroup.type(),
330 updatedBuckets,
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800331 newCookie,
Saurav Das100e3b82015-04-30 11:12:10 -0700332 oldGroup.givenGroupId(),
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800333 oldGroup.appId());
334 StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
335 updatedGroupDesc);
336 newGroup.setState(GroupState.PENDING_UPDATE);
337 newGroup.setLife(oldGroup.life());
338 newGroup.setPackets(oldGroup.packets());
339 newGroup.setBytes(oldGroup.bytes());
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800340 // Remove the old entry from maps and add new entry using new key
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800341 ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
342 getGroupKeyTable(oldGroup.deviceId());
343 ConcurrentMap<GroupId, StoredGroupEntry> idTable =
344 getGroupIdTable(oldGroup.deviceId());
345 keyTable.remove(oldGroup.appCookie());
346 idTable.remove(oldGroup.id());
347 keyTable.put(newGroup.appCookie(), newGroup);
348 idTable.put(newGroup.id(), newGroup);
349 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup));
350 }
351 }
352
353 private List<GroupBucket> getUpdatedBucketList(Group oldGroup,
354 UpdateType type,
355 GroupBuckets buckets) {
356 GroupBuckets oldBuckets = oldGroup.buckets();
357 List<GroupBucket> newBucketList = new ArrayList<GroupBucket>(
358 oldBuckets.buckets());
359 boolean groupDescUpdated = false;
360
361 if (type == UpdateType.ADD) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800362 // Check if the any of the new buckets are part of
363 // the old bucket list
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800364 for (GroupBucket addBucket:buckets.buckets()) {
365 if (!newBucketList.contains(addBucket)) {
366 newBucketList.add(addBucket);
367 groupDescUpdated = true;
368 }
369 }
370 } else if (type == UpdateType.REMOVE) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800371 // Check if the to be removed buckets are part of the
372 // old bucket list
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800373 for (GroupBucket removeBucket:buckets.buckets()) {
374 if (newBucketList.contains(removeBucket)) {
375 newBucketList.remove(removeBucket);
376 groupDescUpdated = true;
377 }
378 }
379 }
380
381 if (groupDescUpdated) {
382 return newBucketList;
383 } else {
384 return null;
385 }
386 }
387
388 /**
389 * Triggers deleting the existing group entry.
390 *
391 * @param deviceId the device ID
392 * @param appCookie the group key
393 */
394 @Override
395 public void deleteGroupDescription(DeviceId deviceId,
396 GroupKey appCookie) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800397 // Check if a group is existing with the provided key
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800398 StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ?
399 groupEntriesByKey.get(deviceId).get(appCookie) :
400 null;
401 if (existing == null) {
402 return;
403 }
404
405 synchronized (existing) {
406 existing.setState(GroupState.PENDING_DELETE);
407 }
408 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, existing));
409 }
410
411 /**
412 * Stores a new group entry, or updates an existing entry.
413 *
414 * @param group group entry
415 */
416 @Override
417 public void addOrUpdateGroupEntry(Group group) {
418 // check if this new entry is an update to an existing entry
419 StoredGroupEntry existing = (groupEntriesById.get(
420 group.deviceId()) != null) ?
421 groupEntriesById.get(group.deviceId()).get(group.id()) :
422 null;
423 GroupEvent event = null;
424
425 if (existing != null) {
426 synchronized (existing) {
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700427 for (GroupBucket bucket:group.buckets().buckets()) {
Sho SHIMIZU30d639b2015-05-05 09:30:35 -0700428 Optional<GroupBucket> matchingBucket =
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700429 existing.buckets().buckets()
430 .stream()
431 .filter((existingBucket)->(existingBucket.equals(bucket)))
432 .findFirst();
433 if (matchingBucket.isPresent()) {
434 ((StoredGroupBucketEntry) matchingBucket.
435 get()).setPackets(bucket.packets());
436 ((StoredGroupBucketEntry) matchingBucket.
437 get()).setBytes(bucket.bytes());
438 } else {
439 log.warn("addOrUpdateGroupEntry: No matching "
440 + "buckets to update stats");
441 }
442 }
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800443 existing.setLife(group.life());
444 existing.setPackets(group.packets());
445 existing.setBytes(group.bytes());
446 if (existing.state() == GroupState.PENDING_ADD) {
447 existing.setState(GroupState.ADDED);
448 event = new GroupEvent(Type.GROUP_ADDED, existing);
449 } else {
450 if (existing.state() == GroupState.PENDING_UPDATE) {
Srikanth Vavilapalli10e75cd2015-04-13 16:21:24 -0700451 existing.setState(GroupState.ADDED);
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800452 }
453 event = new GroupEvent(Type.GROUP_UPDATED, existing);
454 }
455 }
456 }
457
458 if (event != null) {
459 notifyDelegate(event);
460 }
461 }
462
463 /**
464 * Removes the group entry from store.
465 *
466 * @param group group entry
467 */
468 @Override
469 public void removeGroupEntry(Group group) {
470 StoredGroupEntry existing = (groupEntriesById.get(
471 group.deviceId()) != null) ?
472 groupEntriesById.get(group.deviceId()).get(group.id()) :
473 null;
474
475 if (existing != null) {
476 ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
477 getGroupKeyTable(existing.deviceId());
478 ConcurrentMap<GroupId, StoredGroupEntry> idTable =
479 getGroupIdTable(existing.deviceId());
480 idTable.remove(existing.id());
481 keyTable.remove(existing.appCookie());
482 notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing));
483 }
484 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800485
486 @Override
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800487 public void deviceInitialAuditCompleted(DeviceId deviceId,
488 boolean completed) {
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800489 synchronized (deviceAuditStatus) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800490 if (completed) {
491 log.debug("deviceInitialAuditCompleted: AUDIT "
492 + "completed for device {}", deviceId);
493 deviceAuditStatus.put(deviceId, true);
494 // Execute all pending group requests
495 ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests =
496 getPendingGroupKeyTable(deviceId);
497 for (Group group:pendingGroupRequests.values()) {
498 GroupDescription tmp = new DefaultGroupDescription(
499 group.deviceId(),
500 group.type(),
501 group.buckets(),
502 group.appCookie(),
Saurav Das100e3b82015-04-30 11:12:10 -0700503 group.givenGroupId(),
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800504 group.appId());
505 storeGroupDescriptionInternal(tmp);
506 }
507 getPendingGroupKeyTable(deviceId).clear();
508 } else {
509 if (deviceAuditStatus.get(deviceId)) {
510 log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
511 + "status for device {}", deviceId);
512 deviceAuditStatus.put(deviceId, false);
513 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800514 }
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800515 }
516 }
517
518 @Override
519 public boolean deviceInitialAuditStatus(DeviceId deviceId) {
520 synchronized (deviceAuditStatus) {
Srikanth Vavilapallied12ae52015-02-09 14:43:19 -0800521 return (deviceAuditStatus.get(deviceId) != null)
522 ? deviceAuditStatus.get(deviceId) : false;
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800523 }
524 }
525
526 @Override
sangho7ff01812015-02-09 16:21:53 -0800527 public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
528
529 StoredGroupEntry existing = (groupEntriesById.get(
530 deviceId) != null) ?
531 groupEntriesById.get(deviceId).get(operation.groupId()) :
532 null;
533
534 if (existing == null) {
535 log.warn("No group entry with ID {} found ", operation.groupId());
536 return;
537 }
538
539 switch (operation.opType()) {
540 case ADD:
541 notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
542 break;
543 case MODIFY:
544 notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
545 break;
546 case DELETE:
547 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing));
548 break;
549 default:
550 log.warn("Unknown group operation type {}", operation.opType());
551 }
552
553 ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
554 getGroupKeyTable(existing.deviceId());
555 ConcurrentMap<GroupId, StoredGroupEntry> idTable =
556 getGroupIdTable(existing.deviceId());
557 idTable.remove(existing.id());
558 keyTable.remove(existing.appCookie());
559 }
560
561 @Override
Srikanth Vavilapalli45c27c82015-01-30 12:57:56 -0800562 public void addOrUpdateExtraneousGroupEntry(Group group) {
563 ConcurrentMap<GroupId, Group> extraneousIdTable =
564 getExtraneousGroupIdTable(group.deviceId());
565 extraneousIdTable.put(group.id(), group);
566 // Check the reference counter
567 if (group.referenceCount() == 0) {
568 notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
569 }
570 }
571
572 @Override
573 public void removeExtraneousGroupEntry(Group group) {
574 ConcurrentMap<GroupId, Group> extraneousIdTable =
575 getExtraneousGroupIdTable(group.deviceId());
576 extraneousIdTable.remove(group.id());
577 }
578
579 @Override
580 public Iterable<Group> getExtraneousGroups(DeviceId deviceId) {
581 // flatten and make iterator unmodifiable
582 return FluentIterable.from(
583 getExtraneousGroupIdTable(deviceId).values());
584 }
sangho7ff01812015-02-09 16:21:53 -0800585
Srikanth Vavilapalli0599d512015-01-30 12:57:56 -0800586}