Committed by
Ali "The Bomb" Al-Shabibi
ONOS-895: Group manager implementation
Change-Id: Ie183f722fa39012f8de056961715c325e2388e63
Showing
16 changed files
with
1301 additions
and
91 deletions
... | @@ -17,7 +17,10 @@ package org.onosproject.net.group; | ... | @@ -17,7 +17,10 @@ package org.onosproject.net.group; |
17 | 17 | ||
18 | import static org.slf4j.LoggerFactory.getLogger; | 18 | import static org.slf4j.LoggerFactory.getLogger; |
19 | 19 | ||
20 | +import java.util.Objects; | ||
21 | + | ||
20 | import org.onosproject.core.GroupId; | 22 | import org.onosproject.core.GroupId; |
23 | +import org.onosproject.net.DeviceId; | ||
21 | import org.slf4j.Logger; | 24 | import org.slf4j.Logger; |
22 | 25 | ||
23 | /** | 26 | /** |
... | @@ -32,6 +35,7 @@ public class DefaultGroup extends DefaultGroupDescription | ... | @@ -32,6 +35,7 @@ public class DefaultGroup extends DefaultGroupDescription |
32 | private long life; | 35 | private long life; |
33 | private long packets; | 36 | private long packets; |
34 | private long bytes; | 37 | private long bytes; |
38 | + private long referenceCount; | ||
35 | private GroupId id; | 39 | private GroupId id; |
36 | 40 | ||
37 | /** | 41 | /** |
... | @@ -47,6 +51,29 @@ public class DefaultGroup extends DefaultGroupDescription | ... | @@ -47,6 +51,29 @@ public class DefaultGroup extends DefaultGroupDescription |
47 | this.life = 0; | 51 | this.life = 0; |
48 | this.packets = 0; | 52 | this.packets = 0; |
49 | this.bytes = 0; | 53 | this.bytes = 0; |
54 | + this.referenceCount = 0; | ||
55 | + } | ||
56 | + | ||
57 | + /** | ||
58 | + * Default group object constructor with the available information | ||
59 | + * from data plane. | ||
60 | + * | ||
61 | + * @param id group identifier | ||
62 | + * @param deviceId device identifier | ||
63 | + * @param type type of the group | ||
64 | + * @param buckets immutable list of group bucket | ||
65 | + */ | ||
66 | + public DefaultGroup(GroupId id, | ||
67 | + DeviceId deviceId, | ||
68 | + GroupDescription.Type type, | ||
69 | + GroupBuckets buckets) { | ||
70 | + super(deviceId, type, buckets); | ||
71 | + this.id = id; | ||
72 | + this.state = GroupState.PENDING_ADD; | ||
73 | + this.life = 0; | ||
74 | + this.packets = 0; | ||
75 | + this.bytes = 0; | ||
76 | + this.referenceCount = 0; | ||
50 | } | 77 | } |
51 | 78 | ||
52 | /** | 79 | /** |
... | @@ -139,4 +166,43 @@ public class DefaultGroup extends DefaultGroupDescription | ... | @@ -139,4 +166,43 @@ public class DefaultGroup extends DefaultGroupDescription |
139 | this.bytes = bytes; | 166 | this.bytes = bytes; |
140 | } | 167 | } |
141 | 168 | ||
169 | + @Override | ||
170 | + public void setReferenceCount(long referenceCount) { | ||
171 | + this.referenceCount = referenceCount; | ||
172 | + } | ||
173 | + | ||
174 | + @Override | ||
175 | + public long referenceCount() { | ||
176 | + return referenceCount; | ||
177 | + } | ||
178 | + | ||
179 | + /* | ||
180 | + * The deviceId, type and buckets are used for hash. | ||
181 | + * | ||
182 | + * (non-Javadoc) | ||
183 | + * @see java.lang.Object#equals(java.lang.Object) | ||
184 | + */ | ||
185 | + @Override | ||
186 | + public int hashCode() { | ||
187 | + return super.hashCode() + Objects.hash(id); | ||
188 | + } | ||
189 | + | ||
190 | + /* | ||
191 | + * The deviceId, groupId, type and buckets should be same. | ||
192 | + * | ||
193 | + * (non-Javadoc) | ||
194 | + * @see java.lang.Object#equals(java.lang.Object) | ||
195 | + */ | ||
196 | + @Override | ||
197 | + public boolean equals(Object obj) { | ||
198 | + if (this == obj) { | ||
199 | + return true; | ||
200 | + } | ||
201 | + if (obj instanceof DefaultGroup) { | ||
202 | + DefaultGroup that = (DefaultGroup) obj; | ||
203 | + return super.equals(obj) && | ||
204 | + Objects.equals(id, that.id); | ||
205 | + } | ||
206 | + return false; | ||
207 | + } | ||
142 | } | 208 | } | ... | ... |
... | @@ -18,6 +18,8 @@ package org.onosproject.net.group; | ... | @@ -18,6 +18,8 @@ package org.onosproject.net.group; |
18 | import static com.google.common.base.Preconditions.checkArgument; | 18 | import static com.google.common.base.Preconditions.checkArgument; |
19 | import static com.google.common.base.Preconditions.checkNotNull; | 19 | import static com.google.common.base.Preconditions.checkNotNull; |
20 | 20 | ||
21 | +import java.util.Objects; | ||
22 | + | ||
21 | import org.onosproject.core.GroupId; | 23 | import org.onosproject.core.GroupId; |
22 | import org.onosproject.net.PortNumber; | 24 | import org.onosproject.net.PortNumber; |
23 | import org.onosproject.net.flow.TrafficTreatment; | 25 | import org.onosproject.net.flow.TrafficTreatment; |
... | @@ -178,4 +180,36 @@ public final class DefaultGroupBucket implements GroupBucket { | ... | @@ -178,4 +180,36 @@ public final class DefaultGroupBucket implements GroupBucket { |
178 | public GroupId watchGroup() { | 180 | public GroupId watchGroup() { |
179 | return watchGroup; | 181 | return watchGroup; |
180 | } | 182 | } |
183 | + | ||
184 | + /* | ||
185 | + * The type and treatment can change on a given bucket | ||
186 | + * | ||
187 | + * (non-Javadoc) | ||
188 | + * @see java.lang.Object#equals(java.lang.Object) | ||
189 | + */ | ||
190 | + @Override | ||
191 | + public int hashCode() { | ||
192 | + return Objects.hash(type, treatment); | ||
193 | + } | ||
194 | + | ||
195 | + /* | ||
196 | + * The priority and statistics can change on a given treatment and selector | ||
197 | + * | ||
198 | + * (non-Javadoc) | ||
199 | + * @see java.lang.Object#equals(java.lang.Object) | ||
200 | + */ | ||
201 | + @Override | ||
202 | + public boolean equals(Object obj) { | ||
203 | + if (this == obj) { | ||
204 | + return true; | ||
205 | + } | ||
206 | + if (obj instanceof DefaultGroupBucket) { | ||
207 | + DefaultGroupBucket that = (DefaultGroupBucket) obj; | ||
208 | + return Objects.equals(type, that.type) && | ||
209 | + this.treatment.instructions().containsAll(that.treatment.instructions()) && | ||
210 | + that.treatment.instructions().containsAll(this.treatment.instructions()); | ||
211 | + } | ||
212 | + return false; | ||
213 | + } | ||
214 | + | ||
181 | } | 215 | } | ... | ... |
... | @@ -17,6 +17,8 @@ package org.onosproject.net.group; | ... | @@ -17,6 +17,8 @@ package org.onosproject.net.group; |
17 | 17 | ||
18 | import static com.google.common.base.Preconditions.checkNotNull; | 18 | import static com.google.common.base.Preconditions.checkNotNull; |
19 | 19 | ||
20 | +import java.util.Objects; | ||
21 | + | ||
20 | import org.onosproject.core.ApplicationId; | 22 | import org.onosproject.core.ApplicationId; |
21 | import org.onosproject.net.DeviceId; | 23 | import org.onosproject.net.DeviceId; |
22 | 24 | ||
... | @@ -49,8 +51,8 @@ public class DefaultGroupDescription implements GroupDescription { | ... | @@ -49,8 +51,8 @@ public class DefaultGroupDescription implements GroupDescription { |
49 | this.type = checkNotNull(type); | 51 | this.type = checkNotNull(type); |
50 | this.deviceId = checkNotNull(deviceId); | 52 | this.deviceId = checkNotNull(deviceId); |
51 | this.buckets = checkNotNull(buckets); | 53 | this.buckets = checkNotNull(buckets); |
52 | - this.appCookie = checkNotNull(appCookie); | 54 | + this.appCookie = appCookie; |
53 | - this.appId = checkNotNull(appId); | 55 | + this.appId = appId; |
54 | } | 56 | } |
55 | 57 | ||
56 | /** | 58 | /** |
... | @@ -61,11 +63,27 @@ public class DefaultGroupDescription implements GroupDescription { | ... | @@ -61,11 +63,27 @@ public class DefaultGroupDescription implements GroupDescription { |
61 | * | 63 | * |
62 | */ | 64 | */ |
63 | public DefaultGroupDescription(GroupDescription groupDesc) { | 65 | public DefaultGroupDescription(GroupDescription groupDesc) { |
64 | - this.type = checkNotNull(groupDesc.type()); | 66 | + this.type = groupDesc.type(); |
65 | - this.deviceId = checkNotNull(groupDesc.deviceId()); | 67 | + this.deviceId = groupDesc.deviceId(); |
66 | - this.buckets = checkNotNull(groupDesc.buckets()); | 68 | + this.buckets = groupDesc.buckets(); |
67 | - this.appCookie = checkNotNull(groupDesc.appCookie()); | 69 | + this.appCookie = groupDesc.appCookie(); |
68 | - this.appId = checkNotNull(groupDesc.appId()); | 70 | + this.appId = groupDesc.appId(); |
71 | + } | ||
72 | + | ||
73 | + /** | ||
74 | + * Constructor to be used by group subsystem internal components. | ||
75 | + * Creates group description object from the information retrieved | ||
76 | + * from data plane. | ||
77 | + * | ||
78 | + * @param deviceId device identifier | ||
79 | + * @param type type of the group | ||
80 | + * @param buckets immutable list of group bucket | ||
81 | + * | ||
82 | + */ | ||
83 | + public DefaultGroupDescription(DeviceId deviceId, | ||
84 | + GroupDescription.Type type, | ||
85 | + GroupBuckets buckets) { | ||
86 | + this(deviceId, type, buckets, null, null); | ||
69 | } | 87 | } |
70 | 88 | ||
71 | /** | 89 | /** |
... | @@ -118,4 +136,36 @@ public class DefaultGroupDescription implements GroupDescription { | ... | @@ -118,4 +136,36 @@ public class DefaultGroupDescription implements GroupDescription { |
118 | return this.buckets; | 136 | return this.buckets; |
119 | } | 137 | } |
120 | 138 | ||
139 | + @Override | ||
140 | + /* | ||
141 | + * The deviceId, type and buckets are used for hash. | ||
142 | + * | ||
143 | + * (non-Javadoc) | ||
144 | + * @see java.lang.Object#equals(java.lang.Object) | ||
145 | + */ | ||
146 | + public int hashCode() { | ||
147 | + return Objects.hash(deviceId, type, buckets); | ||
148 | + } | ||
149 | + | ||
150 | + @Override | ||
151 | + /* | ||
152 | + * The deviceId, type and buckets should be same. | ||
153 | + * | ||
154 | + * (non-Javadoc) | ||
155 | + * @see java.lang.Object#equals(java.lang.Object) | ||
156 | + */ | ||
157 | + public boolean equals(Object obj) { | ||
158 | + if (this == obj) { | ||
159 | + return true; | ||
160 | + } | ||
161 | + if (obj instanceof DefaultGroupDescription) { | ||
162 | + DefaultGroupDescription that = (DefaultGroupDescription) obj; | ||
163 | + return Objects.equals(deviceId, that.deviceId) && | ||
164 | + Objects.equals(type, that.type) && | ||
165 | + Objects.equals(buckets, that.buckets); | ||
166 | + | ||
167 | + } | ||
168 | + return false; | ||
169 | + } | ||
170 | + | ||
121 | } | 171 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -26,6 +26,10 @@ public interface Group extends GroupDescription { | ... | @@ -26,6 +26,10 @@ public interface Group extends GroupDescription { |
26 | */ | 26 | */ |
27 | public enum GroupState { | 27 | public enum GroupState { |
28 | /** | 28 | /** |
29 | + * Group create request is queued as group AUDIT is in progress. | ||
30 | + */ | ||
31 | + WAITING_AUDIT_COMPLETE, | ||
32 | + /** | ||
29 | * Group create request is processed by ONOS and not yet | 33 | * Group create request is processed by ONOS and not yet |
30 | * received the confirmation from data plane. | 34 | * received the confirmation from data plane. |
31 | */ | 35 | */ |
... | @@ -81,4 +85,11 @@ public interface Group extends GroupDescription { | ... | @@ -81,4 +85,11 @@ public interface Group extends GroupDescription { |
81 | * @return number of bytes | 85 | * @return number of bytes |
82 | */ | 86 | */ |
83 | long bytes(); | 87 | long bytes(); |
88 | + | ||
89 | + /** | ||
90 | + * Returns the number of flow rules or other groups reference this group. | ||
91 | + * | ||
92 | + * @return number of flow rules or other groups pointing to this group | ||
93 | + */ | ||
94 | + long referenceCount(); | ||
84 | } | 95 | } | ... | ... |
... | @@ -45,4 +45,25 @@ public final class GroupBuckets { | ... | @@ -45,4 +45,25 @@ public final class GroupBuckets { |
45 | return buckets; | 45 | return buckets; |
46 | } | 46 | } |
47 | 47 | ||
48 | + @Override | ||
49 | + public int hashCode() { | ||
50 | + int result = 17; | ||
51 | + int combinedHash = 0; | ||
52 | + for (GroupBucket bucket:buckets) { | ||
53 | + combinedHash = combinedHash + bucket.hashCode(); | ||
54 | + } | ||
55 | + result = 31 * result + combinedHash; | ||
56 | + | ||
57 | + return result; | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public boolean equals(Object obj) { | ||
62 | + if (obj instanceof GroupBuckets) { | ||
63 | + return (this.buckets.containsAll(((GroupBuckets) obj).buckets) && | ||
64 | + ((GroupBuckets) obj).buckets.containsAll(this.buckets)); | ||
65 | + } | ||
66 | + return false; | ||
67 | + } | ||
68 | + | ||
48 | } | 69 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -17,6 +17,8 @@ package org.onosproject.net.group; | ... | @@ -17,6 +17,8 @@ package org.onosproject.net.group; |
17 | 17 | ||
18 | import static com.google.common.base.Preconditions.checkNotNull; | 18 | import static com.google.common.base.Preconditions.checkNotNull; |
19 | 19 | ||
20 | +import java.util.Objects; | ||
21 | + | ||
20 | import org.onosproject.core.GroupId; | 22 | import org.onosproject.core.GroupId; |
21 | 23 | ||
22 | /** | 24 | /** |
... | @@ -142,4 +144,37 @@ public final class GroupOperation { | ... | @@ -142,4 +144,37 @@ public final class GroupOperation { |
142 | public GroupBuckets buckets() { | 144 | public GroupBuckets buckets() { |
143 | return this.buckets; | 145 | return this.buckets; |
144 | } | 146 | } |
147 | + | ||
148 | + @Override | ||
149 | + /* | ||
150 | + * The deviceId, type and buckets are used for hash. | ||
151 | + * | ||
152 | + * (non-Javadoc) | ||
153 | + * @see java.lang.Object#equals(java.lang.Object) | ||
154 | + */ | ||
155 | + public int hashCode() { | ||
156 | + return (buckets != null) ? Objects.hash(groupId, opType, buckets) : | ||
157 | + Objects.hash(groupId, opType); | ||
158 | + } | ||
159 | + | ||
160 | + @Override | ||
161 | + /* | ||
162 | + * The deviceId, type and buckets should be same. | ||
163 | + * | ||
164 | + * (non-Javadoc) | ||
165 | + * @see java.lang.Object#equals(java.lang.Object) | ||
166 | + */ | ||
167 | + public boolean equals(Object obj) { | ||
168 | + if (this == obj) { | ||
169 | + return true; | ||
170 | + } | ||
171 | + if (obj instanceof GroupOperation) { | ||
172 | + GroupOperation that = (GroupOperation) obj; | ||
173 | + return Objects.equals(groupId, that.groupId) && | ||
174 | + Objects.equals(opType, that.opType) && | ||
175 | + Objects.equals(buckets, that.buckets); | ||
176 | + | ||
177 | + } | ||
178 | + return false; | ||
179 | + } | ||
145 | } | 180 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.group; | ||
17 | + | ||
18 | +import org.onosproject.net.provider.ProviderRegistry; | ||
19 | + | ||
20 | +/** | ||
21 | + * Abstraction for a group provider registry. | ||
22 | + */ | ||
23 | +public interface GroupProviderRegistry | ||
24 | + extends ProviderRegistry<GroupProvider, GroupProviderService> { | ||
25 | +} |
... | @@ -16,7 +16,6 @@ | ... | @@ -16,7 +16,6 @@ |
16 | package org.onosproject.net.group; | 16 | package org.onosproject.net.group; |
17 | 17 | ||
18 | import org.onosproject.core.ApplicationId; | 18 | import org.onosproject.core.ApplicationId; |
19 | -import org.onosproject.net.Device; | ||
20 | import org.onosproject.net.DeviceId; | 19 | import org.onosproject.net.DeviceId; |
21 | 20 | ||
22 | /** | 21 | /** |
... | @@ -27,7 +26,7 @@ import org.onosproject.net.DeviceId; | ... | @@ -27,7 +26,7 @@ import org.onosproject.net.DeviceId; |
27 | * specified in a group. | 26 | * specified in a group. |
28 | * "group" can also be used for grouping common actions of different flows, | 27 | * "group" can also be used for grouping common actions of different flows, |
29 | * so that in some scenarios only one group entry required to be modified | 28 | * so that in some scenarios only one group entry required to be modified |
30 | - * for all the referencing flow entries instead of modifying all of them | 29 | + * for all the referencing flow entries instead of modifying all of them. |
31 | * | 30 | * |
32 | * This implements semantics of a distributed authoritative group store | 31 | * This implements semantics of a distributed authoritative group store |
33 | * where the master copy of the groups lies with the controller and | 32 | * where the master copy of the groups lies with the controller and |
... | @@ -60,7 +59,7 @@ public interface GroupService { | ... | @@ -60,7 +59,7 @@ public interface GroupService { |
60 | * NOTE1: The presence of group object in the system does not | 59 | * NOTE1: The presence of group object in the system does not |
61 | * guarantee that the "group" is actually created in device. | 60 | * guarantee that the "group" is actually created in device. |
62 | * GROUP_ADDED notification would confirm the creation of | 61 | * GROUP_ADDED notification would confirm the creation of |
63 | - * this group in data plane | 62 | + * this group in data plane. |
64 | * | 63 | * |
65 | * @param deviceId device identifier | 64 | * @param deviceId device identifier |
66 | * @param appCookie application cookie to be used for lookup | 65 | * @param appCookie application cookie to be used for lookup |
... | @@ -73,7 +72,7 @@ public interface GroupService { | ... | @@ -73,7 +72,7 @@ public interface GroupService { |
73 | * Appends buckets to existing group. The caller can optionally | 72 | * Appends buckets to existing group. The caller can optionally |
74 | * associate a new cookie during this updation. GROUP_UPDATED or | 73 | * associate a new cookie during this updation. GROUP_UPDATED or |
75 | * GROUP_UPDATE_FAILED notifications would be provided along with | 74 | * GROUP_UPDATE_FAILED notifications would be provided along with |
76 | - * cookie depending on the result of the operation on the device | 75 | + * cookie depending on the result of the operation on the device. |
77 | * | 76 | * |
78 | * @param deviceId device identifier | 77 | * @param deviceId device identifier |
79 | * @param oldCookie cookie to be used to retrieve the existing group | 78 | * @param oldCookie cookie to be used to retrieve the existing group |
... | @@ -91,7 +90,7 @@ public interface GroupService { | ... | @@ -91,7 +90,7 @@ public interface GroupService { |
91 | * Removes buckets from existing group. The caller can optionally | 90 | * Removes buckets from existing group. The caller can optionally |
92 | * associate a new cookie during this updation. GROUP_UPDATED or | 91 | * associate a new cookie during this updation. GROUP_UPDATED or |
93 | * GROUP_UPDATE_FAILED notifications would be provided along with | 92 | * GROUP_UPDATE_FAILED notifications would be provided along with |
94 | - * cookie depending on the result of the operation on the device | 93 | + * cookie depending on the result of the operation on the device. |
95 | * | 94 | * |
96 | * @param deviceId device identifier | 95 | * @param deviceId device identifier |
97 | * @param oldCookie cookie to be used to retrieve the existing group | 96 | * @param oldCookie cookie to be used to retrieve the existing group |
... | @@ -99,7 +98,7 @@ public interface GroupService { | ... | @@ -99,7 +98,7 @@ public interface GroupService { |
99 | * @param newCookie immutable cookie to be used post update operation | 98 | * @param newCookie immutable cookie to be used post update operation |
100 | * @param appId Application Id | 99 | * @param appId Application Id |
101 | */ | 100 | */ |
102 | - void removeBucketsFromGroup(Device deviceId, | 101 | + void removeBucketsFromGroup(DeviceId deviceId, |
103 | GroupKey oldCookie, | 102 | GroupKey oldCookie, |
104 | GroupBuckets buckets, | 103 | GroupBuckets buckets, |
105 | GroupKey newCookie, | 104 | GroupKey newCookie, |
... | @@ -109,13 +108,13 @@ public interface GroupService { | ... | @@ -109,13 +108,13 @@ public interface GroupService { |
109 | * Deletes a group associated to an application cookie. | 108 | * Deletes a group associated to an application cookie. |
110 | * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be | 109 | * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be |
111 | * provided along with cookie depending on the result of the | 110 | * provided along with cookie depending on the result of the |
112 | - * operation on the device | 111 | + * operation on the device. |
113 | * | 112 | * |
114 | * @param deviceId device identifier | 113 | * @param deviceId device identifier |
115 | * @param appCookie application cookie to be used for lookup | 114 | * @param appCookie application cookie to be used for lookup |
116 | * @param appId Application Id | 115 | * @param appId Application Id |
117 | */ | 116 | */ |
118 | - void removeGroup(Device deviceId, GroupKey appCookie, ApplicationId appId); | 117 | + void removeGroup(DeviceId deviceId, GroupKey appCookie, ApplicationId appId); |
119 | 118 | ||
120 | /** | 119 | /** |
121 | * Retrieves all groups created by an application in the specified device | 120 | * Retrieves all groups created by an application in the specified device |
... | @@ -125,7 +124,7 @@ public interface GroupService { | ... | @@ -125,7 +124,7 @@ public interface GroupService { |
125 | * @param appId application id | 124 | * @param appId application id |
126 | * @return collection of immutable group objects created by the application | 125 | * @return collection of immutable group objects created by the application |
127 | */ | 126 | */ |
128 | - Iterable<Group> getGroups(Device deviceId, ApplicationId appId); | 127 | + Iterable<Group> getGroups(DeviceId deviceId, ApplicationId appId); |
129 | 128 | ||
130 | /** | 129 | /** |
131 | * Adds the specified group listener. | 130 | * Adds the specified group listener. | ... | ... |
... | @@ -73,12 +73,14 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { | ... | @@ -73,12 +73,14 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { |
73 | * @param deviceId the device ID | 73 | * @param deviceId the device ID |
74 | * @param oldAppCookie the current group key | 74 | * @param oldAppCookie the current group key |
75 | * @param type update type | 75 | * @param type update type |
76 | - * @param newGroupDesc group description with updates | 76 | + * @param newBuckets group buckets for updates |
77 | + * @param newAppCookie optional new group key | ||
77 | */ | 78 | */ |
78 | void updateGroupDescription(DeviceId deviceId, | 79 | void updateGroupDescription(DeviceId deviceId, |
79 | GroupKey oldAppCookie, | 80 | GroupKey oldAppCookie, |
80 | UpdateType type, | 81 | UpdateType type, |
81 | - GroupDescription newGroupDesc); | 82 | + GroupBuckets newBuckets, |
83 | + GroupKey newAppCookie); | ||
82 | 84 | ||
83 | /** | 85 | /** |
84 | * Triggers deleting the existing group entry. | 86 | * Triggers deleting the existing group entry. |
... | @@ -102,4 +104,43 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { | ... | @@ -102,4 +104,43 @@ public interface GroupStore extends Store<GroupEvent, GroupStoreDelegate> { |
102 | * @param group group entry | 104 | * @param group group entry |
103 | */ | 105 | */ |
104 | void removeGroupEntry(Group group); | 106 | void removeGroupEntry(Group group); |
107 | + | ||
108 | + /** | ||
109 | + * A group entry that is present in switch but not in the store. | ||
110 | + * | ||
111 | + * @param group group entry | ||
112 | + */ | ||
113 | + void addOrUpdateExtraneousGroupEntry(Group group); | ||
114 | + | ||
115 | + /** | ||
116 | + * Remove the group entry from extraneous database. | ||
117 | + * | ||
118 | + * @param group group entry | ||
119 | + */ | ||
120 | + void removeExtraneousGroupEntry(Group group); | ||
121 | + | ||
122 | + /** | ||
123 | + * Returns the extraneous groups associated with a device. | ||
124 | + * | ||
125 | + * @param deviceId the device ID | ||
126 | + * | ||
127 | + * @return the extraneous group entries | ||
128 | + */ | ||
129 | + Iterable<Group> getExtraneousGroups(DeviceId deviceId); | ||
130 | + | ||
131 | + /** | ||
132 | + * Indicates the first group audit is completed. | ||
133 | + * | ||
134 | + * @param deviceId the device ID | ||
135 | + */ | ||
136 | + void deviceInitialAuditCompleted(DeviceId deviceId); | ||
137 | + | ||
138 | + /** | ||
139 | + * Retrieves the initial group audit status for a device. | ||
140 | + * | ||
141 | + * @param deviceId the device ID | ||
142 | + * | ||
143 | + * @return initial group audit status | ||
144 | + */ | ||
145 | + boolean deviceInitialAuditStatus(DeviceId deviceId); | ||
105 | } | 146 | } | ... | ... |
... | @@ -49,4 +49,10 @@ public interface StoredGroupEntry extends Group { | ... | @@ -49,4 +49,10 @@ public interface StoredGroupEntry extends Group { |
49 | */ | 49 | */ |
50 | void setBytes(long bytes); | 50 | void setBytes(long bytes); |
51 | 51 | ||
52 | + /** | ||
53 | + * Sets number of flow rules or groups referencing this group entry. | ||
54 | + * | ||
55 | + * @param referenceCount reference count | ||
56 | + */ | ||
57 | + void setReferenceCount(long referenceCount); | ||
52 | } | 58 | } | ... | ... |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.group.impl; | ||
17 | + | ||
18 | +import static org.slf4j.LoggerFactory.getLogger; | ||
19 | + | ||
20 | +import java.util.Arrays; | ||
21 | +import java.util.Collection; | ||
22 | +import java.util.Iterator; | ||
23 | +import java.util.Set; | ||
24 | + | ||
25 | +import org.apache.felix.scr.annotations.Activate; | ||
26 | +import org.apache.felix.scr.annotations.Component; | ||
27 | +import org.apache.felix.scr.annotations.Deactivate; | ||
28 | +import org.apache.felix.scr.annotations.Reference; | ||
29 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
30 | +import org.apache.felix.scr.annotations.Service; | ||
31 | +import org.onosproject.core.ApplicationId; | ||
32 | +import org.onosproject.event.AbstractListenerRegistry; | ||
33 | +import org.onosproject.event.EventDeliveryService; | ||
34 | +import org.onosproject.net.DeviceId; | ||
35 | +import org.onosproject.net.group.Group; | ||
36 | +import org.onosproject.net.group.GroupBuckets; | ||
37 | +import org.onosproject.net.group.GroupDescription; | ||
38 | +import org.onosproject.net.group.GroupEvent; | ||
39 | +import org.onosproject.net.group.GroupKey; | ||
40 | +import org.onosproject.net.group.GroupListener; | ||
41 | +import org.onosproject.net.group.GroupOperation; | ||
42 | +import org.onosproject.net.group.GroupOperations; | ||
43 | +import org.onosproject.net.group.GroupProvider; | ||
44 | +import org.onosproject.net.group.GroupProviderRegistry; | ||
45 | +import org.onosproject.net.group.GroupProviderService; | ||
46 | +import org.onosproject.net.group.GroupService; | ||
47 | +import org.onosproject.net.group.GroupStore; | ||
48 | +import org.onosproject.net.group.GroupStore.UpdateType; | ||
49 | +import org.onosproject.net.group.GroupStoreDelegate; | ||
50 | +import org.onosproject.net.provider.AbstractProviderRegistry; | ||
51 | +import org.onosproject.net.provider.AbstractProviderService; | ||
52 | +import org.slf4j.Logger; | ||
53 | + | ||
54 | +import com.google.common.collect.Sets; | ||
55 | + | ||
56 | +/** | ||
57 | + * Provides implementation of the group service APIs. | ||
58 | + */ | ||
59 | +@Component(immediate = true) | ||
60 | +@Service | ||
61 | +public class GroupManager | ||
62 | + extends AbstractProviderRegistry<GroupProvider, GroupProviderService> | ||
63 | + implements GroupService, GroupProviderRegistry { | ||
64 | + | ||
65 | + private final Logger log = getLogger(getClass()); | ||
66 | + | ||
67 | + private final AbstractListenerRegistry<GroupEvent, GroupListener> | ||
68 | + listenerRegistry = new AbstractListenerRegistry<>(); | ||
69 | + private final GroupStoreDelegate delegate = new InternalGroupStoreDelegate(); | ||
70 | + | ||
71 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
72 | + protected GroupStore store; | ||
73 | + | ||
74 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
75 | + protected EventDeliveryService eventDispatcher; | ||
76 | + | ||
77 | + @Activate | ||
78 | + public void activate() { | ||
79 | + store.setDelegate(delegate); | ||
80 | + eventDispatcher.addSink(GroupEvent.class, listenerRegistry); | ||
81 | + log.info("Started"); | ||
82 | + } | ||
83 | + | ||
84 | + @Deactivate | ||
85 | + public void deactivate() { | ||
86 | + store.unsetDelegate(delegate); | ||
87 | + eventDispatcher.removeSink(GroupEvent.class); | ||
88 | + log.info("Stopped"); | ||
89 | + } | ||
90 | + | ||
91 | + /** | ||
92 | + * Create a group in the specified device with the provided parameters. | ||
93 | + * | ||
94 | + * @param groupDesc group creation parameters | ||
95 | + * | ||
96 | + */ | ||
97 | + @Override | ||
98 | + public void addGroup(GroupDescription groupDesc) { | ||
99 | + store.storeGroupDescription(groupDesc); | ||
100 | + } | ||
101 | + | ||
102 | + /** | ||
103 | + * Return a group object associated to an application cookie. | ||
104 | + * | ||
105 | + * NOTE1: The presence of group object in the system does not | ||
106 | + * guarantee that the "group" is actually created in device. | ||
107 | + * GROUP_ADDED notification would confirm the creation of | ||
108 | + * this group in data plane. | ||
109 | + * | ||
110 | + * @param deviceId device identifier | ||
111 | + * @param appCookie application cookie to be used for lookup | ||
112 | + * @return group associated with the application cookie or | ||
113 | + * NULL if Group is not found for the provided cookie | ||
114 | + */ | ||
115 | + @Override | ||
116 | + public Group getGroup(DeviceId deviceId, GroupKey appCookie) { | ||
117 | + return store.getGroup(deviceId, appCookie); | ||
118 | + } | ||
119 | + | ||
120 | + /** | ||
121 | + * Append buckets to existing group. The caller can optionally | ||
122 | + * associate a new cookie during this updation. GROUP_UPDATED or | ||
123 | + * GROUP_UPDATE_FAILED notifications would be provided along with | ||
124 | + * cookie depending on the result of the operation on the device. | ||
125 | + * | ||
126 | + * @param deviceId device identifier | ||
127 | + * @param oldCookie cookie to be used to retrieve the existing group | ||
128 | + * @param buckets immutable list of group bucket to be added | ||
129 | + * @param newCookie immutable cookie to be used post update operation | ||
130 | + * @param appId Application Id | ||
131 | + */ | ||
132 | + @Override | ||
133 | + public void addBucketsToGroup(DeviceId deviceId, | ||
134 | + GroupKey oldCookie, | ||
135 | + GroupBuckets buckets, | ||
136 | + GroupKey newCookie, | ||
137 | + ApplicationId appId) { | ||
138 | + store.updateGroupDescription(deviceId, | ||
139 | + oldCookie, | ||
140 | + UpdateType.ADD, | ||
141 | + buckets, | ||
142 | + newCookie); | ||
143 | + } | ||
144 | + | ||
145 | + /** | ||
146 | + * Remove buckets from existing group. The caller can optionally | ||
147 | + * associate a new cookie during this updation. GROUP_UPDATED or | ||
148 | + * GROUP_UPDATE_FAILED notifications would be provided along with | ||
149 | + * cookie depending on the result of the operation on the device. | ||
150 | + * | ||
151 | + * @param deviceId device identifier | ||
152 | + * @param oldCookie cookie to be used to retrieve the existing group | ||
153 | + * @param buckets immutable list of group bucket to be removed | ||
154 | + * @param newCookie immutable cookie to be used post update operation | ||
155 | + * @param appId Application Id | ||
156 | + */ | ||
157 | + @Override | ||
158 | + public void removeBucketsFromGroup(DeviceId deviceId, | ||
159 | + GroupKey oldCookie, | ||
160 | + GroupBuckets buckets, | ||
161 | + GroupKey newCookie, | ||
162 | + ApplicationId appId) { | ||
163 | + store.updateGroupDescription(deviceId, | ||
164 | + oldCookie, | ||
165 | + UpdateType.REMOVE, | ||
166 | + buckets, | ||
167 | + newCookie); | ||
168 | + } | ||
169 | + | ||
170 | + /** | ||
171 | + * Delete a group associated to an application cookie. | ||
172 | + * GROUP_DELETED or GROUP_DELETE_FAILED notifications would be | ||
173 | + * provided along with cookie depending on the result of the | ||
174 | + * operation on the device. | ||
175 | + * | ||
176 | + * @param deviceId device identifier | ||
177 | + * @param appCookie application cookie to be used for lookup | ||
178 | + * @param appId Application Id | ||
179 | + */ | ||
180 | + @Override | ||
181 | + public void removeGroup(DeviceId deviceId, | ||
182 | + GroupKey appCookie, | ||
183 | + ApplicationId appId) { | ||
184 | + store.deleteGroupDescription(deviceId, appCookie); | ||
185 | + } | ||
186 | + | ||
187 | + /** | ||
188 | + * Retrieve all groups created by an application in the specified device | ||
189 | + * as seen by current controller instance. | ||
190 | + * | ||
191 | + * @param deviceId device identifier | ||
192 | + * @param appId application id | ||
193 | + * @return collection of immutable group objects created by the application | ||
194 | + */ | ||
195 | + @Override | ||
196 | + public Iterable<Group> getGroups(DeviceId deviceId, | ||
197 | + ApplicationId appId) { | ||
198 | + return store.getGroups(deviceId); | ||
199 | + } | ||
200 | + | ||
201 | + /** | ||
202 | + * Adds the specified group listener. | ||
203 | + * | ||
204 | + * @param listener group listener | ||
205 | + */ | ||
206 | + @Override | ||
207 | + public void addListener(GroupListener listener) { | ||
208 | + listenerRegistry.addListener(listener); | ||
209 | + } | ||
210 | + | ||
211 | + /** | ||
212 | + * Removes the specified group listener. | ||
213 | + * | ||
214 | + * @param listener group listener | ||
215 | + */ | ||
216 | + @Override | ||
217 | + public void removeListener(GroupListener listener) { | ||
218 | + listenerRegistry.removeListener(listener); | ||
219 | + } | ||
220 | + | ||
221 | + @Override | ||
222 | + protected GroupProviderService createProviderService(GroupProvider provider) { | ||
223 | + return new InternalGroupProviderService(provider); | ||
224 | + } | ||
225 | + | ||
226 | + private class InternalGroupStoreDelegate implements GroupStoreDelegate { | ||
227 | + @Override | ||
228 | + public void notify(GroupEvent event) { | ||
229 | + final Group group = event.subject(); | ||
230 | + GroupProvider groupProvider = | ||
231 | + getProvider(group.deviceId()); | ||
232 | + GroupOperations groupOps = null; | ||
233 | + switch (event.type()) { | ||
234 | + case GROUP_ADD_REQUESTED: | ||
235 | + GroupOperation groupAddOp = GroupOperation. | ||
236 | + createAddGroupOperation(group.id(), | ||
237 | + group.type(), | ||
238 | + group.buckets()); | ||
239 | + groupOps = new GroupOperations( | ||
240 | + Arrays.asList(groupAddOp)); | ||
241 | + groupProvider.performGroupOperation(group.deviceId(), groupOps); | ||
242 | + break; | ||
243 | + | ||
244 | + case GROUP_UPDATE_REQUESTED: | ||
245 | + GroupOperation groupModifyOp = GroupOperation. | ||
246 | + createModifyGroupOperation(group.id(), | ||
247 | + group.type(), | ||
248 | + group.buckets()); | ||
249 | + groupOps = new GroupOperations( | ||
250 | + Arrays.asList(groupModifyOp)); | ||
251 | + groupProvider.performGroupOperation(group.deviceId(), groupOps); | ||
252 | + break; | ||
253 | + | ||
254 | + case GROUP_REMOVE_REQUESTED: | ||
255 | + GroupOperation groupDeleteOp = GroupOperation. | ||
256 | + createDeleteGroupOperation(group.id(), | ||
257 | + group.type()); | ||
258 | + groupOps = new GroupOperations( | ||
259 | + Arrays.asList(groupDeleteOp)); | ||
260 | + groupProvider.performGroupOperation(group.deviceId(), groupOps); | ||
261 | + break; | ||
262 | + | ||
263 | + case GROUP_ADDED: | ||
264 | + case GROUP_UPDATED: | ||
265 | + case GROUP_REMOVED: | ||
266 | + eventDispatcher.post(event); | ||
267 | + break; | ||
268 | + | ||
269 | + default: | ||
270 | + break; | ||
271 | + } | ||
272 | + } | ||
273 | + } | ||
274 | + | ||
275 | + private class InternalGroupProviderService | ||
276 | + extends AbstractProviderService<GroupProvider> | ||
277 | + implements GroupProviderService { | ||
278 | + | ||
279 | + protected InternalGroupProviderService(GroupProvider provider) { | ||
280 | + super(provider); | ||
281 | + } | ||
282 | + | ||
283 | + @Override | ||
284 | + public void groupOperationFailed(GroupOperation operation) { | ||
285 | + // TODO Auto-generated method stub | ||
286 | + | ||
287 | + } | ||
288 | + | ||
289 | + private void groupMissing(Group group) { | ||
290 | + checkValidity(); | ||
291 | + GroupProvider gp = getProvider(group.deviceId()); | ||
292 | + switch (group.state()) { | ||
293 | + case PENDING_DELETE: | ||
294 | + store.removeGroupEntry(group); | ||
295 | + break; | ||
296 | + case ADDED: | ||
297 | + case PENDING_ADD: | ||
298 | + GroupOperation groupAddOp = GroupOperation. | ||
299 | + createAddGroupOperation(group.id(), | ||
300 | + group.type(), | ||
301 | + group.buckets()); | ||
302 | + GroupOperations groupOps = new GroupOperations( | ||
303 | + Arrays.asList(groupAddOp)); | ||
304 | + gp.performGroupOperation(group.deviceId(), groupOps); | ||
305 | + break; | ||
306 | + default: | ||
307 | + log.debug("Group {} has not been installed.", group); | ||
308 | + break; | ||
309 | + } | ||
310 | + } | ||
311 | + | ||
312 | + | ||
313 | + private void extraneousGroup(Group group) { | ||
314 | + log.debug("Group {} is on switch but not in store.", group); | ||
315 | + checkValidity(); | ||
316 | + store.addOrUpdateExtraneousGroupEntry(group); | ||
317 | + } | ||
318 | + | ||
319 | + private void groupAdded(Group group) { | ||
320 | + checkValidity(); | ||
321 | + | ||
322 | + log.trace("Group {}", group); | ||
323 | + store.addOrUpdateGroupEntry(group); | ||
324 | + } | ||
325 | + | ||
326 | + @Override | ||
327 | + public void pushGroupMetrics(DeviceId deviceId, | ||
328 | + Collection<Group> groupEntries) { | ||
329 | + boolean deviceInitialAuditStatus = | ||
330 | + store.deviceInitialAuditStatus(deviceId); | ||
331 | + Set<Group> southboundGroupEntries = | ||
332 | + Sets.newHashSet(groupEntries); | ||
333 | + Set<Group> storedGroupEntries = | ||
334 | + Sets.newHashSet(store.getGroups(deviceId)); | ||
335 | + Set<Group> extraneousStoredEntries = | ||
336 | + Sets.newHashSet(store.getExtraneousGroups(deviceId)); | ||
337 | + | ||
338 | + for (Iterator<Group> it = southboundGroupEntries.iterator(); it.hasNext();) { | ||
339 | + Group group = it.next(); | ||
340 | + if (storedGroupEntries.remove(group)) { | ||
341 | + // we both have the group, let's update some info then. | ||
342 | + groupAdded(group); | ||
343 | + it.remove(); | ||
344 | + } | ||
345 | + } | ||
346 | + for (Group group : southboundGroupEntries) { | ||
347 | + // there are groups in the switch that aren't in the store | ||
348 | + extraneousStoredEntries.remove(group); | ||
349 | + extraneousGroup(group); | ||
350 | + } | ||
351 | + for (Group group : storedGroupEntries) { | ||
352 | + // there are groups in the store that aren't in the switch | ||
353 | + groupMissing(group); | ||
354 | + } | ||
355 | + for (Group group : extraneousStoredEntries) { | ||
356 | + // there are groups in the extraneous store that | ||
357 | + // aren't in the switch | ||
358 | + store.removeExtraneousGroupEntry(group); | ||
359 | + } | ||
360 | + | ||
361 | + if (!deviceInitialAuditStatus) { | ||
362 | + store.deviceInitialAuditCompleted(deviceId); | ||
363 | + } | ||
364 | + } | ||
365 | + } | ||
366 | +} |
1 | +/* | ||
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 | + */ | ||
16 | + | ||
17 | +/** | ||
18 | + * Core subsystem for group state. | ||
19 | + */ | ||
20 | +package org.onosproject.net.group.impl; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
1 | +/* | ||
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 | + */ | ||
16 | +package org.onosproject.net.group.impl; | ||
17 | + | ||
18 | +import static org.junit.Assert.assertEquals; | ||
19 | +import static org.junit.Assert.assertFalse; | ||
20 | +import static org.junit.Assert.assertNotEquals; | ||
21 | +import static org.junit.Assert.assertTrue; | ||
22 | + | ||
23 | +import java.util.ArrayList; | ||
24 | +import java.util.Arrays; | ||
25 | +import java.util.Collections; | ||
26 | +import java.util.List; | ||
27 | + | ||
28 | +import org.junit.After; | ||
29 | +import org.junit.Before; | ||
30 | +import org.junit.Test; | ||
31 | +import org.onlab.packet.MacAddress; | ||
32 | +import org.onosproject.core.ApplicationId; | ||
33 | +import org.onosproject.core.DefaultApplicationId; | ||
34 | +import org.onosproject.core.DefaultGroupId; | ||
35 | +import org.onosproject.core.GroupId; | ||
36 | +import org.onosproject.event.impl.TestEventDispatcher; | ||
37 | +import org.onosproject.net.DeviceId; | ||
38 | +import org.onosproject.net.PortNumber; | ||
39 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
40 | +import org.onosproject.net.flow.TrafficTreatment; | ||
41 | +import org.onosproject.net.group.DefaultGroup; | ||
42 | +import org.onosproject.net.group.DefaultGroupBucket; | ||
43 | +import org.onosproject.net.group.DefaultGroupDescription; | ||
44 | +import org.onosproject.net.group.Group; | ||
45 | +import org.onosproject.net.group.GroupBucket; | ||
46 | +import org.onosproject.net.group.GroupBuckets; | ||
47 | +import org.onosproject.net.group.GroupDescription; | ||
48 | +import org.onosproject.net.group.GroupEvent; | ||
49 | +import org.onosproject.net.group.GroupKey; | ||
50 | +import org.onosproject.net.group.GroupListener; | ||
51 | +import org.onosproject.net.group.GroupOperation; | ||
52 | +import org.onosproject.net.group.GroupOperations; | ||
53 | +import org.onosproject.net.group.GroupProvider; | ||
54 | +import org.onosproject.net.group.GroupProviderRegistry; | ||
55 | +import org.onosproject.net.group.GroupProviderService; | ||
56 | +import org.onosproject.net.group.GroupService; | ||
57 | +import org.onosproject.net.group.StoredGroupEntry; | ||
58 | +import org.onosproject.net.provider.AbstractProvider; | ||
59 | +import org.onosproject.net.provider.ProviderId; | ||
60 | +import org.onosproject.store.trivial.impl.SimpleGroupStore; | ||
61 | + | ||
62 | +import com.google.common.collect.Iterables; | ||
63 | + | ||
64 | +/** | ||
65 | + * Test codifying the group service & group provider service contracts. | ||
66 | + */ | ||
67 | +public class GroupManagerTest { | ||
68 | + | ||
69 | + private static final ProviderId PID = new ProviderId("of", "groupfoo"); | ||
70 | + private static final DeviceId DID = DeviceId.deviceId("of:001"); | ||
71 | + | ||
72 | + private GroupManager mgr; | ||
73 | + private GroupService groupService; | ||
74 | + private GroupProviderRegistry providerRegistry; | ||
75 | + private TestGroupListener internalListener = new TestGroupListener(); | ||
76 | + private GroupListener listener = internalListener; | ||
77 | + private TestGroupProvider internalProvider; | ||
78 | + private GroupProvider provider; | ||
79 | + private GroupProviderService providerService; | ||
80 | + private ApplicationId appId; | ||
81 | + | ||
82 | + @Before | ||
83 | + public void setUp() { | ||
84 | + mgr = new GroupManager(); | ||
85 | + groupService = mgr; | ||
86 | + mgr.store = new SimpleGroupStore(); | ||
87 | + mgr.eventDispatcher = new TestEventDispatcher(); | ||
88 | + providerRegistry = mgr; | ||
89 | + | ||
90 | + mgr.activate(); | ||
91 | + mgr.addListener(listener); | ||
92 | + | ||
93 | + internalProvider = new TestGroupProvider(PID); | ||
94 | + provider = internalProvider; | ||
95 | + providerService = providerRegistry.register(provider); | ||
96 | + appId = new DefaultApplicationId(2, "org.groupmanager.test"); | ||
97 | + assertTrue("provider should be registered", | ||
98 | + providerRegistry.getProviders().contains(provider.id())); | ||
99 | + } | ||
100 | + | ||
101 | + @After | ||
102 | + public void tearDown() { | ||
103 | + providerRegistry.unregister(provider); | ||
104 | + assertFalse("provider should not be registered", | ||
105 | + providerRegistry.getProviders().contains(provider.id())); | ||
106 | + mgr.removeListener(listener); | ||
107 | + mgr.deactivate(); | ||
108 | + mgr.eventDispatcher = null; | ||
109 | + } | ||
110 | + | ||
111 | + private class TestGroupKey implements GroupKey { | ||
112 | + private String groupId; | ||
113 | + | ||
114 | + public TestGroupKey(String id) { | ||
115 | + this.groupId = id; | ||
116 | + } | ||
117 | + | ||
118 | + public String id() { | ||
119 | + return this.groupId; | ||
120 | + } | ||
121 | + | ||
122 | + @Override | ||
123 | + public int hashCode() { | ||
124 | + return groupId.hashCode(); | ||
125 | + } | ||
126 | + | ||
127 | + @Override | ||
128 | + public boolean equals(Object obj) { | ||
129 | + if (obj instanceof TestGroupKey) { | ||
130 | + return this.groupId.equals(((TestGroupKey) obj).id()); | ||
131 | + } | ||
132 | + return false; | ||
133 | + } | ||
134 | + } | ||
135 | + | ||
136 | + /** | ||
137 | + * Tests group service north bound and south bound interfaces. | ||
138 | + * The following operations are tested: | ||
139 | + * a)Tests group creation before the device group AUDIT completes | ||
140 | + * b)Tests initial device group AUDIT process | ||
141 | + * c)Tests deletion process of any extraneous groups | ||
142 | + * d)Tests execution of any pending group creation requests | ||
143 | + * after the device group AUDIT completes | ||
144 | + * e)Tests re-apply process of any missing groups | ||
145 | + * f)Tests event notifications after receiving confirmation for | ||
146 | + * any operations from data plane | ||
147 | + * g)Tests group bucket modifications (additions and deletions) | ||
148 | + * h)Tests group deletion | ||
149 | + */ | ||
150 | + @Test | ||
151 | + public void testGroupService() { | ||
152 | + PortNumber[] ports1 = {PortNumber.portNumber(31), | ||
153 | + PortNumber.portNumber(32)}; | ||
154 | + PortNumber[] ports2 = {PortNumber.portNumber(41), | ||
155 | + PortNumber.portNumber(42)}; | ||
156 | + // Test Group creation before AUDIT process | ||
157 | + TestGroupKey key = new TestGroupKey("group1BeforeAudit"); | ||
158 | + List<GroupBucket> buckets = new ArrayList<GroupBucket>(); | ||
159 | + List<PortNumber> outPorts = new ArrayList<PortNumber>(); | ||
160 | + outPorts.addAll(Arrays.asList(ports1)); | ||
161 | + outPorts.addAll(Arrays.asList(ports2)); | ||
162 | + for (PortNumber portNumber: outPorts) { | ||
163 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
164 | + tBuilder.setOutput(portNumber) | ||
165 | + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) | ||
166 | + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) | ||
167 | + .pushMpls() | ||
168 | + .setMpls(106); | ||
169 | + buckets.add(DefaultGroupBucket.createSelectGroupBucket( | ||
170 | + tBuilder.build())); | ||
171 | + } | ||
172 | + GroupBuckets groupBuckets = new GroupBuckets(buckets); | ||
173 | + GroupDescription newGroupDesc = new DefaultGroupDescription(DID, | ||
174 | + Group.Type.SELECT, | ||
175 | + groupBuckets, | ||
176 | + key, | ||
177 | + appId); | ||
178 | + groupService.addGroup(newGroupDesc); | ||
179 | + internalProvider.validate(DID, null); | ||
180 | + assertEquals(null, groupService.getGroup(DID, key)); | ||
181 | + assertEquals(0, Iterables.size(groupService.getGroups(DID, appId))); | ||
182 | + | ||
183 | + // Test initial group audit process | ||
184 | + GroupId gId1 = new DefaultGroupId(1); | ||
185 | + Group group1 = createSouthboundGroupEntry(gId1, | ||
186 | + Arrays.asList(ports1), | ||
187 | + 0); | ||
188 | + GroupId gId2 = new DefaultGroupId(2); | ||
189 | + // Non zero reference count will make the group manager to queue | ||
190 | + // the extraneous groups until reference count is zero. | ||
191 | + Group group2 = createSouthboundGroupEntry(gId2, | ||
192 | + Arrays.asList(ports2), | ||
193 | + 2); | ||
194 | + List<Group> groupEntries = Arrays.asList(group1, group2); | ||
195 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
196 | + // First group metrics would trigger the device audit completion | ||
197 | + // post which all pending group requests are also executed. | ||
198 | + Group createdGroup = groupService.getGroup(DID, key); | ||
199 | + int createdGroupId = createdGroup.id().id(); | ||
200 | + assertNotEquals(gId1.id(), createdGroupId); | ||
201 | + assertNotEquals(gId2.id(), createdGroupId); | ||
202 | + List<GroupOperation> expectedGroupOps = Arrays.asList( | ||
203 | + GroupOperation.createDeleteGroupOperation(gId1, | ||
204 | + Group.Type.SELECT), | ||
205 | + GroupOperation.createAddGroupOperation( | ||
206 | + createdGroup.id(), | ||
207 | + Group.Type.SELECT, | ||
208 | + groupBuckets)); | ||
209 | + internalProvider.validate(DID, expectedGroupOps); | ||
210 | + | ||
211 | + group1 = createSouthboundGroupEntry(gId1, | ||
212 | + Arrays.asList(ports1), | ||
213 | + 0); | ||
214 | + group2 = createSouthboundGroupEntry(gId2, | ||
215 | + Arrays.asList(ports2), | ||
216 | + 0); | ||
217 | + groupEntries = Arrays.asList(group1, group2); | ||
218 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
219 | + expectedGroupOps = Arrays.asList( | ||
220 | + GroupOperation.createDeleteGroupOperation(gId1, | ||
221 | + Group.Type.SELECT), | ||
222 | + GroupOperation.createDeleteGroupOperation(gId2, | ||
223 | + Group.Type.SELECT), | ||
224 | + GroupOperation.createAddGroupOperation(createdGroup.id(), | ||
225 | + Group.Type.SELECT, | ||
226 | + groupBuckets)); | ||
227 | + internalProvider.validate(DID, expectedGroupOps); | ||
228 | + | ||
229 | + createdGroup = new DefaultGroup(createdGroup.id(), | ||
230 | + DID, | ||
231 | + Group.Type.SELECT, | ||
232 | + groupBuckets); | ||
233 | + groupEntries = Arrays.asList(createdGroup); | ||
234 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
235 | + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_ADDED)); | ||
236 | + | ||
237 | + // Test group add bucket operations | ||
238 | + TestGroupKey addKey = new TestGroupKey("group1AddBuckets"); | ||
239 | + PortNumber[] addPorts = {PortNumber.portNumber(51), | ||
240 | + PortNumber.portNumber(52)}; | ||
241 | + outPorts.clear(); | ||
242 | + outPorts.addAll(Arrays.asList(addPorts)); | ||
243 | + List<GroupBucket> addBuckets = new ArrayList<GroupBucket>(); | ||
244 | + for (PortNumber portNumber: outPorts) { | ||
245 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
246 | + tBuilder.setOutput(portNumber) | ||
247 | + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) | ||
248 | + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) | ||
249 | + .pushMpls() | ||
250 | + .setMpls(106); | ||
251 | + addBuckets.add(DefaultGroupBucket.createSelectGroupBucket( | ||
252 | + tBuilder.build())); | ||
253 | + buckets.add(DefaultGroupBucket.createSelectGroupBucket( | ||
254 | + tBuilder.build())); | ||
255 | + } | ||
256 | + GroupBuckets groupAddBuckets = new GroupBuckets(addBuckets); | ||
257 | + groupService.addBucketsToGroup(DID, | ||
258 | + key, | ||
259 | + groupAddBuckets, | ||
260 | + addKey, | ||
261 | + appId); | ||
262 | + GroupBuckets updatedBuckets = new GroupBuckets(buckets); | ||
263 | + expectedGroupOps = Arrays.asList( | ||
264 | + GroupOperation.createModifyGroupOperation(createdGroup.id(), | ||
265 | + Group.Type.SELECT, | ||
266 | + updatedBuckets)); | ||
267 | + internalProvider.validate(DID, expectedGroupOps); | ||
268 | + Group existingGroup = groupService.getGroup(DID, addKey); | ||
269 | + groupEntries = Arrays.asList(existingGroup); | ||
270 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
271 | + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED)); | ||
272 | + | ||
273 | + // Test group remove bucket operations | ||
274 | + TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets"); | ||
275 | + PortNumber[] removePorts = {PortNumber.portNumber(31), | ||
276 | + PortNumber.portNumber(32)}; | ||
277 | + outPorts.clear(); | ||
278 | + outPorts.addAll(Arrays.asList(removePorts)); | ||
279 | + List<GroupBucket> removeBuckets = new ArrayList<GroupBucket>(); | ||
280 | + for (PortNumber portNumber: outPorts) { | ||
281 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
282 | + tBuilder.setOutput(portNumber) | ||
283 | + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) | ||
284 | + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) | ||
285 | + .pushMpls() | ||
286 | + .setMpls(106); | ||
287 | + removeBuckets.add(DefaultGroupBucket.createSelectGroupBucket( | ||
288 | + tBuilder.build())); | ||
289 | + buckets.remove(DefaultGroupBucket.createSelectGroupBucket( | ||
290 | + tBuilder.build())); | ||
291 | + } | ||
292 | + GroupBuckets groupRemoveBuckets = new GroupBuckets(removeBuckets); | ||
293 | + groupService.removeBucketsFromGroup(DID, | ||
294 | + addKey, | ||
295 | + groupRemoveBuckets, | ||
296 | + removeKey, | ||
297 | + appId); | ||
298 | + updatedBuckets = new GroupBuckets(buckets); | ||
299 | + expectedGroupOps = Arrays.asList( | ||
300 | + GroupOperation.createModifyGroupOperation(createdGroup.id(), | ||
301 | + Group.Type.SELECT, | ||
302 | + updatedBuckets)); | ||
303 | + internalProvider.validate(DID, expectedGroupOps); | ||
304 | + existingGroup = groupService.getGroup(DID, removeKey); | ||
305 | + groupEntries = Arrays.asList(existingGroup); | ||
306 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
307 | + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_UPDATED)); | ||
308 | + | ||
309 | + // Test group remove operations | ||
310 | + groupService.removeGroup(DID, removeKey, appId); | ||
311 | + expectedGroupOps = Arrays.asList( | ||
312 | + GroupOperation.createDeleteGroupOperation(createdGroup.id(), | ||
313 | + Group.Type.SELECT)); | ||
314 | + internalProvider.validate(DID, expectedGroupOps); | ||
315 | + groupEntries = Collections.emptyList(); | ||
316 | + providerService.pushGroupMetrics(DID, groupEntries); | ||
317 | + internalListener.validateEvent(Arrays.asList(GroupEvent.Type.GROUP_REMOVED)); | ||
318 | + } | ||
319 | + | ||
320 | + private Group createSouthboundGroupEntry(GroupId gId, | ||
321 | + List<PortNumber> ports, | ||
322 | + long referenceCount) { | ||
323 | + List<PortNumber> outPorts = new ArrayList<PortNumber>(); | ||
324 | + outPorts.addAll(ports); | ||
325 | + | ||
326 | + List<GroupBucket> buckets = new ArrayList<GroupBucket>(); | ||
327 | + for (PortNumber portNumber: outPorts) { | ||
328 | + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder(); | ||
329 | + tBuilder.setOutput(portNumber) | ||
330 | + .setEthDst(MacAddress.valueOf("00:00:00:00:00:02")) | ||
331 | + .setEthSrc(MacAddress.valueOf("00:00:00:00:00:01")) | ||
332 | + .pushMpls() | ||
333 | + .setMpls(106); | ||
334 | + buckets.add(DefaultGroupBucket.createSelectGroupBucket( | ||
335 | + tBuilder.build())); | ||
336 | + } | ||
337 | + GroupBuckets groupBuckets = new GroupBuckets(buckets); | ||
338 | + StoredGroupEntry group = new DefaultGroup( | ||
339 | + gId, DID, Group.Type.SELECT, groupBuckets); | ||
340 | + group.setReferenceCount(referenceCount); | ||
341 | + return group; | ||
342 | + } | ||
343 | + | ||
344 | + private static class TestGroupListener implements GroupListener { | ||
345 | + final List<GroupEvent> events = new ArrayList<>(); | ||
346 | + | ||
347 | + @Override | ||
348 | + public void event(GroupEvent event) { | ||
349 | + events.add(event); | ||
350 | + } | ||
351 | + | ||
352 | + public void validateEvent(List<GroupEvent.Type> expectedEvents) { | ||
353 | + int i = 0; | ||
354 | + System.err.println("events :" + events); | ||
355 | + for (GroupEvent e : events) { | ||
356 | + assertEquals("unexpected event", expectedEvents.get(i), e.type()); | ||
357 | + i++; | ||
358 | + } | ||
359 | + assertEquals("mispredicted number of events", | ||
360 | + expectedEvents.size(), events.size()); | ||
361 | + events.clear(); | ||
362 | + } | ||
363 | + } | ||
364 | + | ||
365 | + private class TestGroupProvider | ||
366 | + extends AbstractProvider implements GroupProvider { | ||
367 | + DeviceId lastDeviceId; | ||
368 | + List<GroupOperation> groupOperations = new ArrayList<GroupOperation>(); | ||
369 | + | ||
370 | + protected TestGroupProvider(ProviderId id) { | ||
371 | + super(id); | ||
372 | + } | ||
373 | + | ||
374 | + @Override | ||
375 | + public void performGroupOperation(DeviceId deviceId, | ||
376 | + GroupOperations groupOps) { | ||
377 | + lastDeviceId = deviceId; | ||
378 | + groupOperations.addAll(groupOps.operations()); | ||
379 | + } | ||
380 | + | ||
381 | + public void validate(DeviceId expectedDeviceId, | ||
382 | + List<GroupOperation> expectedGroupOps) { | ||
383 | + if (expectedGroupOps == null) { | ||
384 | + assertTrue("events generated", groupOperations.isEmpty()); | ||
385 | + return; | ||
386 | + } | ||
387 | + | ||
388 | + assertEquals(lastDeviceId, expectedDeviceId); | ||
389 | + assertTrue((this.groupOperations.containsAll(expectedGroupOps) && | ||
390 | + expectedGroupOps.containsAll(groupOperations))); | ||
391 | + | ||
392 | + groupOperations.clear(); | ||
393 | + lastDeviceId = null; | ||
394 | + } | ||
395 | + | ||
396 | + } | ||
397 | + | ||
398 | +} | ||
399 | + | ||
400 | + |
... | @@ -19,6 +19,7 @@ import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsent | ... | @@ -19,6 +19,7 @@ import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsent |
19 | import static org.slf4j.LoggerFactory.getLogger; | 19 | import static org.slf4j.LoggerFactory.getLogger; |
20 | 20 | ||
21 | import java.util.ArrayList; | 21 | import java.util.ArrayList; |
22 | +import java.util.HashMap; | ||
22 | import java.util.List; | 23 | import java.util.List; |
23 | import java.util.concurrent.ConcurrentHashMap; | 24 | import java.util.concurrent.ConcurrentHashMap; |
24 | import java.util.concurrent.ConcurrentMap; | 25 | import java.util.concurrent.ConcurrentMap; |
... | @@ -62,11 +63,21 @@ public class SimpleGroupStore | ... | @@ -62,11 +63,21 @@ public class SimpleGroupStore |
62 | 63 | ||
63 | private final Logger log = getLogger(getClass()); | 64 | private final Logger log = getLogger(getClass()); |
64 | 65 | ||
66 | + private final int dummyId = 0xffffffff; | ||
67 | + private final GroupId dummyGroupId = new DefaultGroupId(dummyId); | ||
68 | + | ||
65 | // inner Map is per device group table | 69 | // inner Map is per device group table |
66 | private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>> | 70 | private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>> |
67 | groupEntriesByKey = new ConcurrentHashMap<>(); | 71 | groupEntriesByKey = new ConcurrentHashMap<>(); |
68 | private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>> | 72 | private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>> |
69 | groupEntriesById = new ConcurrentHashMap<>(); | 73 | groupEntriesById = new ConcurrentHashMap<>(); |
74 | + private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>> | ||
75 | + pendingGroupEntriesByKey = new ConcurrentHashMap<>(); | ||
76 | + private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>> | ||
77 | + extraneousGroupEntriesById = new ConcurrentHashMap<>(); | ||
78 | + | ||
79 | + private final HashMap<DeviceId, Boolean> deviceAuditStatus = | ||
80 | + new HashMap<DeviceId, Boolean>(); | ||
70 | 81 | ||
71 | private final AtomicInteger groupIdGen = new AtomicInteger(); | 82 | private final AtomicInteger groupIdGen = new AtomicInteger(); |
72 | 83 | ||
... | @@ -82,14 +93,26 @@ public class SimpleGroupStore | ... | @@ -82,14 +93,26 @@ public class SimpleGroupStore |
82 | log.info("Stopped"); | 93 | log.info("Stopped"); |
83 | } | 94 | } |
84 | 95 | ||
85 | - private static NewConcurrentHashMap<GroupKey, StoredGroupEntry> lazyEmptyGroupKeyTable() { | 96 | + private static NewConcurrentHashMap<GroupKey, StoredGroupEntry> |
97 | + lazyEmptyGroupKeyTable() { | ||
86 | return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded(); | 98 | return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded(); |
87 | } | 99 | } |
88 | 100 | ||
89 | - private static NewConcurrentHashMap<GroupId, StoredGroupEntry> lazyEmptyGroupIdTable() { | 101 | + private static NewConcurrentHashMap<GroupId, StoredGroupEntry> |
102 | + lazyEmptyGroupIdTable() { | ||
90 | return NewConcurrentHashMap.<GroupId, StoredGroupEntry>ifNeeded(); | 103 | return NewConcurrentHashMap.<GroupId, StoredGroupEntry>ifNeeded(); |
91 | } | 104 | } |
92 | 105 | ||
106 | + private static NewConcurrentHashMap<GroupKey, StoredGroupEntry> | ||
107 | + lazyEmptyPendingGroupKeyTable() { | ||
108 | + return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded(); | ||
109 | + } | ||
110 | + | ||
111 | + private static NewConcurrentHashMap<GroupId, Group> | ||
112 | + lazyEmptyExtraneousGroupIdTable() { | ||
113 | + return NewConcurrentHashMap.<GroupId, Group>ifNeeded(); | ||
114 | + } | ||
115 | + | ||
93 | /** | 116 | /** |
94 | * Returns the group key table for specified device. | 117 | * Returns the group key table for specified device. |
95 | * | 118 | * |
... | @@ -113,6 +136,31 @@ public class SimpleGroupStore | ... | @@ -113,6 +136,31 @@ public class SimpleGroupStore |
113 | } | 136 | } |
114 | 137 | ||
115 | /** | 138 | /** |
139 | + * Returns the pending group key table for specified device. | ||
140 | + * | ||
141 | + * @param deviceId identifier of the device | ||
142 | + * @return Map representing group key table of given device. | ||
143 | + */ | ||
144 | + private ConcurrentMap<GroupKey, StoredGroupEntry> | ||
145 | + getPendingGroupKeyTable(DeviceId deviceId) { | ||
146 | + return createIfAbsentUnchecked(pendingGroupEntriesByKey, | ||
147 | + deviceId, lazyEmptyPendingGroupKeyTable()); | ||
148 | + } | ||
149 | + | ||
150 | + /** | ||
151 | + * Returns the extraneous group id table for specified device. | ||
152 | + * | ||
153 | + * @param deviceId identifier of the device | ||
154 | + * @return Map representing group key table of given device. | ||
155 | + */ | ||
156 | + private ConcurrentMap<GroupId, Group> | ||
157 | + getExtraneousGroupIdTable(DeviceId deviceId) { | ||
158 | + return createIfAbsentUnchecked(extraneousGroupEntriesById, | ||
159 | + deviceId, | ||
160 | + lazyEmptyExtraneousGroupIdTable()); | ||
161 | + } | ||
162 | + | ||
163 | + /** | ||
116 | * Returns the number of groups for the specified device in the store. | 164 | * Returns the number of groups for the specified device in the store. |
117 | * | 165 | * |
118 | * @return number of groups for the specified device | 166 | * @return number of groups for the specified device |
... | @@ -133,20 +181,16 @@ public class SimpleGroupStore | ... | @@ -133,20 +181,16 @@ public class SimpleGroupStore |
133 | @Override | 181 | @Override |
134 | public Iterable<Group> getGroups(DeviceId deviceId) { | 182 | public Iterable<Group> getGroups(DeviceId deviceId) { |
135 | // flatten and make iterator unmodifiable | 183 | // flatten and make iterator unmodifiable |
136 | - if (groupEntriesByKey.get(deviceId) != null) { | 184 | + return FluentIterable.from(getGroupKeyTable(deviceId).values()) |
137 | - return FluentIterable.from(groupEntriesByKey.get(deviceId).values()) | 185 | + .transform( |
138 | - .transform( | 186 | + new Function<StoredGroupEntry, Group>() { |
139 | - new Function<StoredGroupEntry, Group>() { | 187 | + |
140 | - | 188 | + @Override |
141 | - @Override | 189 | + public Group apply( |
142 | - public Group apply( | 190 | + StoredGroupEntry input) { |
143 | - StoredGroupEntry input) { | 191 | + return input; |
144 | - return input; | 192 | + } |
145 | - } | 193 | + }); |
146 | - }); | ||
147 | - } else { | ||
148 | - return null; | ||
149 | - } | ||
150 | } | 194 | } |
151 | 195 | ||
152 | /** | 196 | /** |
... | @@ -164,6 +208,30 @@ public class SimpleGroupStore | ... | @@ -164,6 +208,30 @@ public class SimpleGroupStore |
164 | null; | 208 | null; |
165 | } | 209 | } |
166 | 210 | ||
211 | + private int getFreeGroupIdValue(DeviceId deviceId) { | ||
212 | + int freeId = groupIdGen.incrementAndGet(); | ||
213 | + | ||
214 | + while (true) { | ||
215 | + Group existing = ( | ||
216 | + groupEntriesById.get(deviceId) != null) ? | ||
217 | + groupEntriesById.get(deviceId).get(new DefaultGroupId(freeId)) : | ||
218 | + null; | ||
219 | + if (existing == null) { | ||
220 | + existing = ( | ||
221 | + extraneousGroupEntriesById.get(deviceId) != null) ? | ||
222 | + extraneousGroupEntriesById.get(deviceId). | ||
223 | + get(new DefaultGroupId(freeId)) : | ||
224 | + null; | ||
225 | + } | ||
226 | + if (existing != null) { | ||
227 | + freeId = groupIdGen.incrementAndGet(); | ||
228 | + } else { | ||
229 | + break; | ||
230 | + } | ||
231 | + } | ||
232 | + return freeId; | ||
233 | + } | ||
234 | + | ||
167 | /** | 235 | /** |
168 | * Stores a new group entry using the information from group description. | 236 | * Stores a new group entry using the information from group description. |
169 | * | 237 | * |
... | @@ -171,16 +239,32 @@ public class SimpleGroupStore | ... | @@ -171,16 +239,32 @@ public class SimpleGroupStore |
171 | */ | 239 | */ |
172 | @Override | 240 | @Override |
173 | public void storeGroupDescription(GroupDescription groupDesc) { | 241 | public void storeGroupDescription(GroupDescription groupDesc) { |
174 | - /* Check if a group is existing with the same key */ | 242 | + // Check if a group is existing with the same key |
175 | if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { | 243 | if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) { |
176 | return; | 244 | return; |
177 | } | 245 | } |
178 | 246 | ||
179 | - /* Get a new group identifier */ | 247 | + if (deviceAuditStatus.get(groupDesc.deviceId()) == null) { |
180 | - GroupId id = new DefaultGroupId(groupIdGen.incrementAndGet()); | 248 | + // Device group audit has not completed yet |
181 | - /* Create a group entry object */ | 249 | + // Add this group description to pending group key table |
250 | + // Create a group entry object with Dummy Group ID | ||
251 | + StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc); | ||
252 | + group.setState(GroupState.WAITING_AUDIT_COMPLETE); | ||
253 | + ConcurrentMap<GroupKey, StoredGroupEntry> pendingKeyTable = | ||
254 | + getPendingGroupKeyTable(groupDesc.deviceId()); | ||
255 | + pendingKeyTable.put(groupDesc.appCookie(), group); | ||
256 | + return; | ||
257 | + } | ||
258 | + | ||
259 | + storeGroupDescriptionInternal(groupDesc); | ||
260 | + } | ||
261 | + | ||
262 | + private void storeGroupDescriptionInternal(GroupDescription groupDesc) { | ||
263 | + // Get a new group identifier | ||
264 | + GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId())); | ||
265 | + // Create a group entry object | ||
182 | StoredGroupEntry group = new DefaultGroup(id, groupDesc); | 266 | StoredGroupEntry group = new DefaultGroup(id, groupDesc); |
183 | - /* Insert the newly created group entry into concurrent key and id maps */ | 267 | + // Insert the newly created group entry into concurrent key and id maps |
184 | ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = | 268 | ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = |
185 | getGroupKeyTable(groupDesc.deviceId()); | 269 | getGroupKeyTable(groupDesc.deviceId()); |
186 | keyTable.put(groupDesc.appCookie(), group); | 270 | keyTable.put(groupDesc.appCookie(), group); |
... | @@ -198,14 +282,16 @@ public class SimpleGroupStore | ... | @@ -198,14 +282,16 @@ public class SimpleGroupStore |
198 | * @param deviceId the device ID | 282 | * @param deviceId the device ID |
199 | * @param oldAppCookie the current group key | 283 | * @param oldAppCookie the current group key |
200 | * @param type update type | 284 | * @param type update type |
201 | - * @param newGroupDesc group description with updates | 285 | + * @param newBuckets group buckets for updates |
286 | + * @param newAppCookie optional new group key | ||
202 | */ | 287 | */ |
203 | @Override | 288 | @Override |
204 | public void updateGroupDescription(DeviceId deviceId, | 289 | public void updateGroupDescription(DeviceId deviceId, |
205 | GroupKey oldAppCookie, | 290 | GroupKey oldAppCookie, |
206 | UpdateType type, | 291 | UpdateType type, |
207 | - GroupDescription newGroupDesc) { | 292 | + GroupBuckets newBuckets, |
208 | - /* Check if a group is existing with the provided key */ | 293 | + GroupKey newAppCookie) { |
294 | + // Check if a group is existing with the provided key | ||
209 | Group oldGroup = getGroup(deviceId, oldAppCookie); | 295 | Group oldGroup = getGroup(deviceId, oldAppCookie); |
210 | if (oldGroup == null) { | 296 | if (oldGroup == null) { |
211 | return; | 297 | return; |
... | @@ -213,15 +299,16 @@ public class SimpleGroupStore | ... | @@ -213,15 +299,16 @@ public class SimpleGroupStore |
213 | 299 | ||
214 | List<GroupBucket> newBucketList = getUpdatedBucketList(oldGroup, | 300 | List<GroupBucket> newBucketList = getUpdatedBucketList(oldGroup, |
215 | type, | 301 | type, |
216 | - newGroupDesc.buckets()); | 302 | + newBuckets); |
217 | if (newBucketList != null) { | 303 | if (newBucketList != null) { |
218 | - /* Create a new group object from the old group */ | 304 | + // Create a new group object from the old group |
219 | GroupBuckets updatedBuckets = new GroupBuckets(newBucketList); | 305 | GroupBuckets updatedBuckets = new GroupBuckets(newBucketList); |
306 | + GroupKey newCookie = (newAppCookie != null) ? newAppCookie : oldAppCookie; | ||
220 | GroupDescription updatedGroupDesc = new DefaultGroupDescription( | 307 | GroupDescription updatedGroupDesc = new DefaultGroupDescription( |
221 | oldGroup.deviceId(), | 308 | oldGroup.deviceId(), |
222 | oldGroup.type(), | 309 | oldGroup.type(), |
223 | updatedBuckets, | 310 | updatedBuckets, |
224 | - newGroupDesc.appCookie(), | 311 | + newCookie, |
225 | oldGroup.appId()); | 312 | oldGroup.appId()); |
226 | StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(), | 313 | StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(), |
227 | updatedGroupDesc); | 314 | updatedGroupDesc); |
... | @@ -229,9 +316,7 @@ public class SimpleGroupStore | ... | @@ -229,9 +316,7 @@ public class SimpleGroupStore |
229 | newGroup.setLife(oldGroup.life()); | 316 | newGroup.setLife(oldGroup.life()); |
230 | newGroup.setPackets(oldGroup.packets()); | 317 | newGroup.setPackets(oldGroup.packets()); |
231 | newGroup.setBytes(oldGroup.bytes()); | 318 | newGroup.setBytes(oldGroup.bytes()); |
232 | - /* Remove the old entry from maps and add new entry | 319 | + // Remove the old entry from maps and add new entry using new key |
233 | - * using new key | ||
234 | - */ | ||
235 | ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = | 320 | ConcurrentMap<GroupKey, StoredGroupEntry> keyTable = |
236 | getGroupKeyTable(oldGroup.deviceId()); | 321 | getGroupKeyTable(oldGroup.deviceId()); |
237 | ConcurrentMap<GroupId, StoredGroupEntry> idTable = | 322 | ConcurrentMap<GroupId, StoredGroupEntry> idTable = |
... | @@ -253,9 +338,8 @@ public class SimpleGroupStore | ... | @@ -253,9 +338,8 @@ public class SimpleGroupStore |
253 | boolean groupDescUpdated = false; | 338 | boolean groupDescUpdated = false; |
254 | 339 | ||
255 | if (type == UpdateType.ADD) { | 340 | if (type == UpdateType.ADD) { |
256 | - /* Check if the any of the new buckets are part of the | 341 | + // Check if the any of the new buckets are part of |
257 | - * old bucket list | 342 | + // the old bucket list |
258 | - */ | ||
259 | for (GroupBucket addBucket:buckets.buckets()) { | 343 | for (GroupBucket addBucket:buckets.buckets()) { |
260 | if (!newBucketList.contains(addBucket)) { | 344 | if (!newBucketList.contains(addBucket)) { |
261 | newBucketList.add(addBucket); | 345 | newBucketList.add(addBucket); |
... | @@ -263,9 +347,8 @@ public class SimpleGroupStore | ... | @@ -263,9 +347,8 @@ public class SimpleGroupStore |
263 | } | 347 | } |
264 | } | 348 | } |
265 | } else if (type == UpdateType.REMOVE) { | 349 | } else if (type == UpdateType.REMOVE) { |
266 | - /* Check if the to be removed buckets are part of the | 350 | + // Check if the to be removed buckets are part of the |
267 | - * old bucket list | 351 | + // old bucket list |
268 | - */ | ||
269 | for (GroupBucket removeBucket:buckets.buckets()) { | 352 | for (GroupBucket removeBucket:buckets.buckets()) { |
270 | if (newBucketList.contains(removeBucket)) { | 353 | if (newBucketList.contains(removeBucket)) { |
271 | newBucketList.remove(removeBucket); | 354 | newBucketList.remove(removeBucket); |
... | @@ -290,7 +373,7 @@ public class SimpleGroupStore | ... | @@ -290,7 +373,7 @@ public class SimpleGroupStore |
290 | @Override | 373 | @Override |
291 | public void deleteGroupDescription(DeviceId deviceId, | 374 | public void deleteGroupDescription(DeviceId deviceId, |
292 | GroupKey appCookie) { | 375 | GroupKey appCookie) { |
293 | - /* Check if a group is existing with the provided key */ | 376 | + // Check if a group is existing with the provided key |
294 | StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ? | 377 | StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ? |
295 | groupEntriesByKey.get(deviceId).get(appCookie) : | 378 | groupEntriesByKey.get(deviceId).get(appCookie) : |
296 | null; | 379 | null; |
... | @@ -362,4 +445,56 @@ public class SimpleGroupStore | ... | @@ -362,4 +445,56 @@ public class SimpleGroupStore |
362 | notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing)); | 445 | notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing)); |
363 | } | 446 | } |
364 | } | 447 | } |
448 | + | ||
449 | + @Override | ||
450 | + public void deviceInitialAuditCompleted(DeviceId deviceId) { | ||
451 | + synchronized (deviceAuditStatus) { | ||
452 | + deviceAuditStatus.putIfAbsent(deviceId, true); | ||
453 | + // Execute all pending group requests | ||
454 | + ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests = | ||
455 | + getPendingGroupKeyTable(deviceId); | ||
456 | + for (Group group:pendingGroupRequests.values()) { | ||
457 | + GroupDescription tmp = new DefaultGroupDescription( | ||
458 | + group.deviceId(), | ||
459 | + group.type(), | ||
460 | + group.buckets(), | ||
461 | + group.appCookie(), | ||
462 | + group.appId()); | ||
463 | + storeGroupDescriptionInternal(tmp); | ||
464 | + } | ||
465 | + getPendingGroupKeyTable(deviceId).clear(); | ||
466 | + } | ||
467 | + } | ||
468 | + | ||
469 | + @Override | ||
470 | + public boolean deviceInitialAuditStatus(DeviceId deviceId) { | ||
471 | + synchronized (deviceAuditStatus) { | ||
472 | + return (deviceAuditStatus.get(deviceId) != null) ? true : false; | ||
473 | + } | ||
474 | + } | ||
475 | + | ||
476 | + @Override | ||
477 | + public void addOrUpdateExtraneousGroupEntry(Group group) { | ||
478 | + ConcurrentMap<GroupId, Group> extraneousIdTable = | ||
479 | + getExtraneousGroupIdTable(group.deviceId()); | ||
480 | + extraneousIdTable.put(group.id(), group); | ||
481 | + // Check the reference counter | ||
482 | + if (group.referenceCount() == 0) { | ||
483 | + notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group)); | ||
484 | + } | ||
485 | + } | ||
486 | + | ||
487 | + @Override | ||
488 | + public void removeExtraneousGroupEntry(Group group) { | ||
489 | + ConcurrentMap<GroupId, Group> extraneousIdTable = | ||
490 | + getExtraneousGroupIdTable(group.deviceId()); | ||
491 | + extraneousIdTable.remove(group.id()); | ||
492 | + } | ||
493 | + | ||
494 | + @Override | ||
495 | + public Iterable<Group> getExtraneousGroups(DeviceId deviceId) { | ||
496 | + // flatten and make iterator unmodifiable | ||
497 | + return FluentIterable.from( | ||
498 | + getExtraneousGroupIdTable(deviceId).values()); | ||
499 | + } | ||
365 | } | 500 | } | ... | ... |
... | @@ -40,8 +40,10 @@ import org.onosproject.net.group.GroupBuckets; | ... | @@ -40,8 +40,10 @@ import org.onosproject.net.group.GroupBuckets; |
40 | import org.onosproject.net.group.GroupDescription; | 40 | import org.onosproject.net.group.GroupDescription; |
41 | import org.onosproject.net.group.GroupEvent; | 41 | import org.onosproject.net.group.GroupEvent; |
42 | import org.onosproject.net.group.GroupKey; | 42 | import org.onosproject.net.group.GroupKey; |
43 | -import org.onosproject.net.group.GroupStoreDelegate; | ||
44 | import org.onosproject.net.group.GroupStore.UpdateType; | 43 | import org.onosproject.net.group.GroupStore.UpdateType; |
44 | +import org.onosproject.net.group.GroupStoreDelegate; | ||
45 | + | ||
46 | +import com.google.common.collect.Iterables; | ||
45 | 47 | ||
46 | /** | 48 | /** |
47 | * Test of the simple DeviceStore implementation. | 49 | * Test of the simple DeviceStore implementation. |
... | @@ -135,8 +137,24 @@ public class SimpleGroupStoreTest { | ... | @@ -135,8 +137,24 @@ public class SimpleGroupStoreTest { |
135 | } | 137 | } |
136 | } | 138 | } |
137 | 139 | ||
140 | + /** | ||
141 | + * Tests group store operations. The following operations are tested: | ||
142 | + * a)Tests device group audit completion status change | ||
143 | + * b)Tests storeGroup operation | ||
144 | + * c)Tests getGroupCount operation | ||
145 | + * d)Tests getGroup operation | ||
146 | + * e)Tests getGroups operation | ||
147 | + * f)Tests addOrUpdateGroupEntry operation from southbound | ||
148 | + * g)Tests updateGroupDescription for ADD operation from northbound | ||
149 | + * h)Tests updateGroupDescription for REMOVE operation from northbound | ||
150 | + * i)Tests deleteGroupDescription operation from northbound | ||
151 | + * j)Tests removeGroupEntry operation from southbound | ||
152 | + */ | ||
138 | @Test | 153 | @Test |
139 | public void testGroupStoreOperations() { | 154 | public void testGroupStoreOperations() { |
155 | + // Set the Device AUDIT completed in the store | ||
156 | + simpleGroupStore.deviceInitialAuditCompleted(D1); | ||
157 | + | ||
140 | ApplicationId appId = | 158 | ApplicationId appId = |
141 | new DefaultApplicationId(2, "org.groupstore.test"); | 159 | new DefaultApplicationId(2, "org.groupstore.test"); |
142 | TestGroupKey key = new TestGroupKey("group1"); | 160 | TestGroupKey key = new TestGroupKey("group1"); |
... | @@ -169,17 +187,17 @@ public class SimpleGroupStoreTest { | ... | @@ -169,17 +187,17 @@ public class SimpleGroupStoreTest { |
169 | groupBuckets, | 187 | groupBuckets, |
170 | GroupEvent.Type.GROUP_ADD_REQUESTED); | 188 | GroupEvent.Type.GROUP_ADD_REQUESTED); |
171 | simpleGroupStore.setDelegate(checkStoreGroupDelegate); | 189 | simpleGroupStore.setDelegate(checkStoreGroupDelegate); |
172 | - /* Testing storeGroup operation */ | 190 | + // Testing storeGroup operation |
173 | simpleGroupStore.storeGroupDescription(groupDesc); | 191 | simpleGroupStore.storeGroupDescription(groupDesc); |
174 | 192 | ||
175 | - /* Testing getGroupCount operation */ | 193 | + // Testing getGroupCount operation |
176 | assertEquals(1, simpleGroupStore.getGroupCount(D1)); | 194 | assertEquals(1, simpleGroupStore.getGroupCount(D1)); |
177 | 195 | ||
178 | - /* Testing getGroup operation */ | 196 | + // Testing getGroup operation |
179 | Group createdGroup = simpleGroupStore.getGroup(D1, key); | 197 | Group createdGroup = simpleGroupStore.getGroup(D1, key); |
180 | checkStoreGroupDelegate.verifyGroupId(createdGroup.id()); | 198 | checkStoreGroupDelegate.verifyGroupId(createdGroup.id()); |
181 | 199 | ||
182 | - /* Testing getGroups operation */ | 200 | + // Testing getGroups operation |
183 | Iterable<Group> createdGroups = simpleGroupStore.getGroups(D1); | 201 | Iterable<Group> createdGroups = simpleGroupStore.getGroups(D1); |
184 | int groupCount = 0; | 202 | int groupCount = 0; |
185 | for (Group group:createdGroups) { | 203 | for (Group group:createdGroups) { |
... | @@ -189,7 +207,7 @@ public class SimpleGroupStoreTest { | ... | @@ -189,7 +207,7 @@ public class SimpleGroupStoreTest { |
189 | assertEquals(1, groupCount); | 207 | assertEquals(1, groupCount); |
190 | simpleGroupStore.unsetDelegate(checkStoreGroupDelegate); | 208 | simpleGroupStore.unsetDelegate(checkStoreGroupDelegate); |
191 | 209 | ||
192 | - /* Testing addOrUpdateGroupEntry operation from southbound */ | 210 | + // Testing addOrUpdateGroupEntry operation from southbound |
193 | InternalGroupStoreDelegate addGroupEntryDelegate = | 211 | InternalGroupStoreDelegate addGroupEntryDelegate = |
194 | new InternalGroupStoreDelegate(key, | 212 | new InternalGroupStoreDelegate(key, |
195 | groupBuckets, | 213 | groupBuckets, |
... | @@ -198,7 +216,7 @@ public class SimpleGroupStoreTest { | ... | @@ -198,7 +216,7 @@ public class SimpleGroupStoreTest { |
198 | simpleGroupStore.addOrUpdateGroupEntry(createdGroup); | 216 | simpleGroupStore.addOrUpdateGroupEntry(createdGroup); |
199 | simpleGroupStore.unsetDelegate(addGroupEntryDelegate); | 217 | simpleGroupStore.unsetDelegate(addGroupEntryDelegate); |
200 | 218 | ||
201 | - /* Testing updateGroupDescription for ADD operation from northbound */ | 219 | + // Testing updateGroupDescription for ADD operation from northbound |
202 | TestGroupKey addKey = new TestGroupKey("group1AddBuckets"); | 220 | TestGroupKey addKey = new TestGroupKey("group1AddBuckets"); |
203 | PortNumber[] newNeighborPorts = {PortNumber.portNumber(41), | 221 | PortNumber[] newNeighborPorts = {PortNumber.portNumber(41), |
204 | PortNumber.portNumber(42)}; | 222 | PortNumber.portNumber(42)}; |
... | @@ -225,19 +243,14 @@ public class SimpleGroupStoreTest { | ... | @@ -225,19 +243,14 @@ public class SimpleGroupStoreTest { |
225 | updatedGroupBuckets, | 243 | updatedGroupBuckets, |
226 | GroupEvent.Type.GROUP_UPDATE_REQUESTED); | 244 | GroupEvent.Type.GROUP_UPDATE_REQUESTED); |
227 | simpleGroupStore.setDelegate(updateGroupDescDelegate); | 245 | simpleGroupStore.setDelegate(updateGroupDescDelegate); |
228 | - GroupDescription newGroupDesc = new DefaultGroupDescription( | ||
229 | - D1, | ||
230 | - Group.Type.SELECT, | ||
231 | - toAddGroupBuckets, | ||
232 | - addKey, | ||
233 | - appId); | ||
234 | simpleGroupStore.updateGroupDescription(D1, | 246 | simpleGroupStore.updateGroupDescription(D1, |
235 | key, | 247 | key, |
236 | UpdateType.ADD, | 248 | UpdateType.ADD, |
237 | - newGroupDesc); | 249 | + toAddGroupBuckets, |
250 | + addKey); | ||
238 | simpleGroupStore.unsetDelegate(updateGroupDescDelegate); | 251 | simpleGroupStore.unsetDelegate(updateGroupDescDelegate); |
239 | 252 | ||
240 | - /* Testing updateGroupDescription for REMOVE operation from northbound */ | 253 | + // Testing updateGroupDescription for REMOVE operation from northbound |
241 | TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets"); | 254 | TestGroupKey removeKey = new TestGroupKey("group1RemoveBuckets"); |
242 | List<GroupBucket> toRemoveBuckets = new ArrayList<GroupBucket>(); | 255 | List<GroupBucket> toRemoveBuckets = new ArrayList<GroupBucket>(); |
243 | toRemoveBuckets.add(updatedGroupBuckets.buckets().get(0)); | 256 | toRemoveBuckets.add(updatedGroupBuckets.buckets().get(0)); |
... | @@ -252,23 +265,18 @@ public class SimpleGroupStoreTest { | ... | @@ -252,23 +265,18 @@ public class SimpleGroupStoreTest { |
252 | remainingGroupBuckets, | 265 | remainingGroupBuckets, |
253 | GroupEvent.Type.GROUP_UPDATE_REQUESTED); | 266 | GroupEvent.Type.GROUP_UPDATE_REQUESTED); |
254 | simpleGroupStore.setDelegate(removeGroupDescDelegate); | 267 | simpleGroupStore.setDelegate(removeGroupDescDelegate); |
255 | - GroupDescription removeGroupDesc = new DefaultGroupDescription( | ||
256 | - D1, | ||
257 | - Group.Type.SELECT, | ||
258 | - toRemoveGroupBuckets, | ||
259 | - removeKey, | ||
260 | - appId); | ||
261 | simpleGroupStore.updateGroupDescription(D1, | 268 | simpleGroupStore.updateGroupDescription(D1, |
262 | addKey, | 269 | addKey, |
263 | UpdateType.REMOVE, | 270 | UpdateType.REMOVE, |
264 | - removeGroupDesc); | 271 | + toRemoveGroupBuckets, |
272 | + removeKey); | ||
265 | simpleGroupStore.unsetDelegate(removeGroupDescDelegate); | 273 | simpleGroupStore.unsetDelegate(removeGroupDescDelegate); |
266 | 274 | ||
267 | - /* Testing getGroup operation */ | 275 | + // Testing getGroup operation |
268 | Group existingGroup = simpleGroupStore.getGroup(D1, removeKey); | 276 | Group existingGroup = simpleGroupStore.getGroup(D1, removeKey); |
269 | checkStoreGroupDelegate.verifyGroupId(existingGroup.id()); | 277 | checkStoreGroupDelegate.verifyGroupId(existingGroup.id()); |
270 | 278 | ||
271 | - /* Testing addOrUpdateGroupEntry operation from southbound */ | 279 | + // Testing addOrUpdateGroupEntry operation from southbound |
272 | InternalGroupStoreDelegate updateGroupEntryDelegate = | 280 | InternalGroupStoreDelegate updateGroupEntryDelegate = |
273 | new InternalGroupStoreDelegate(removeKey, | 281 | new InternalGroupStoreDelegate(removeKey, |
274 | remainingGroupBuckets, | 282 | remainingGroupBuckets, |
... | @@ -277,7 +285,7 @@ public class SimpleGroupStoreTest { | ... | @@ -277,7 +285,7 @@ public class SimpleGroupStoreTest { |
277 | simpleGroupStore.addOrUpdateGroupEntry(existingGroup); | 285 | simpleGroupStore.addOrUpdateGroupEntry(existingGroup); |
278 | simpleGroupStore.unsetDelegate(updateGroupEntryDelegate); | 286 | simpleGroupStore.unsetDelegate(updateGroupEntryDelegate); |
279 | 287 | ||
280 | - /* Testing deleteGroupDescription operation from northbound */ | 288 | + // Testing deleteGroupDescription operation from northbound |
281 | InternalGroupStoreDelegate deleteGroupDescDelegate = | 289 | InternalGroupStoreDelegate deleteGroupDescDelegate = |
282 | new InternalGroupStoreDelegate(removeKey, | 290 | new InternalGroupStoreDelegate(removeKey, |
283 | remainingGroupBuckets, | 291 | remainingGroupBuckets, |
... | @@ -286,7 +294,7 @@ public class SimpleGroupStoreTest { | ... | @@ -286,7 +294,7 @@ public class SimpleGroupStoreTest { |
286 | simpleGroupStore.deleteGroupDescription(D1, removeKey); | 294 | simpleGroupStore.deleteGroupDescription(D1, removeKey); |
287 | simpleGroupStore.unsetDelegate(deleteGroupDescDelegate); | 295 | simpleGroupStore.unsetDelegate(deleteGroupDescDelegate); |
288 | 296 | ||
289 | - /* Testing removeGroupEntry operation from southbound */ | 297 | + // Testing removeGroupEntry operation from southbound |
290 | InternalGroupStoreDelegate removeGroupEntryDelegate = | 298 | InternalGroupStoreDelegate removeGroupEntryDelegate = |
291 | new InternalGroupStoreDelegate(removeKey, | 299 | new InternalGroupStoreDelegate(removeKey, |
292 | remainingGroupBuckets, | 300 | remainingGroupBuckets, |
... | @@ -294,17 +302,10 @@ public class SimpleGroupStoreTest { | ... | @@ -294,17 +302,10 @@ public class SimpleGroupStoreTest { |
294 | simpleGroupStore.setDelegate(removeGroupEntryDelegate); | 302 | simpleGroupStore.setDelegate(removeGroupEntryDelegate); |
295 | simpleGroupStore.removeGroupEntry(existingGroup); | 303 | simpleGroupStore.removeGroupEntry(existingGroup); |
296 | 304 | ||
297 | - /* Testing getGroup operation */ | 305 | + // Testing getGroup operation |
298 | existingGroup = simpleGroupStore.getGroup(D1, removeKey); | 306 | existingGroup = simpleGroupStore.getGroup(D1, removeKey); |
299 | assertEquals(null, existingGroup); | 307 | assertEquals(null, existingGroup); |
300 | - Iterable<Group> existingGroups = simpleGroupStore.getGroups(D1); | 308 | + assertEquals(0, Iterables.size(simpleGroupStore.getGroups(D1))); |
301 | - groupCount = 0; | ||
302 | - for (Group tmp:existingGroups) { | ||
303 | - /* To avoid warning */ | ||
304 | - assertEquals(null, tmp); | ||
305 | - groupCount++; | ||
306 | - } | ||
307 | - assertEquals(0, groupCount); | ||
308 | assertEquals(0, simpleGroupStore.getGroupCount(D1)); | 309 | assertEquals(0, simpleGroupStore.getGroupCount(D1)); |
309 | 310 | ||
310 | simpleGroupStore.unsetDelegate(removeGroupEntryDelegate); | 311 | simpleGroupStore.unsetDelegate(removeGroupEntryDelegate); | ... | ... |
-
Please register or login to post a comment