Committed by
Gerrit Code Review
Enhance StatisticService to allow filtering by Application ID and Group ID
Resolve ONOS-205 Change-Id: Ie9318a5ade943bd8e47fb92ee856b7ebead5022e
Showing
5 changed files
with
331 additions
and
7 deletions
1 | +/* | ||
2 | + * Copyright 2014 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.onlab.onos.core; | ||
17 | + | ||
18 | +import com.google.common.base.MoreObjects; | ||
19 | + | ||
20 | +import java.util.Objects; | ||
21 | + | ||
22 | +/** | ||
23 | + * Default implementation of {@link GroupId}. | ||
24 | + */ | ||
25 | +public class DefaultGroupId implements GroupId { | ||
26 | + | ||
27 | + private final int id; | ||
28 | + | ||
29 | + public DefaultGroupId(int id) { | ||
30 | + this.id = id; | ||
31 | + } | ||
32 | + | ||
33 | + // Constructor for serialization | ||
34 | + private DefaultGroupId() { | ||
35 | + this.id = 0; | ||
36 | + } | ||
37 | + | ||
38 | + @Override | ||
39 | + public int id() { | ||
40 | + return 0; | ||
41 | + } | ||
42 | + | ||
43 | + @Override | ||
44 | + public int hashCode() { | ||
45 | + return Objects.hash(id); | ||
46 | + } | ||
47 | + | ||
48 | + @Override | ||
49 | + public boolean equals(Object obj) { | ||
50 | + if (this == obj) { | ||
51 | + return true; | ||
52 | + } | ||
53 | + if (!(obj instanceof DefaultGroupId)) { | ||
54 | + return false; | ||
55 | + } | ||
56 | + final DefaultGroupId other = (DefaultGroupId) obj; | ||
57 | + return Objects.equals(this.id, other.id); | ||
58 | + } | ||
59 | + | ||
60 | + @Override | ||
61 | + public String toString() { | ||
62 | + return MoreObjects.toStringHelper(this) | ||
63 | + .add("id", id) | ||
64 | + .toString(); | ||
65 | + } | ||
66 | +} |
1 | +/* | ||
2 | + * Copyright 2014 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.onlab.onos.core; | ||
17 | + | ||
18 | +/** | ||
19 | + * Group identifier. | ||
20 | + */ | ||
21 | +public interface GroupId { | ||
22 | + | ||
23 | + /** | ||
24 | + * Returns a group ID as short value. | ||
25 | + * The method is not intended for use by application developers. | ||
26 | + * Return data type may change in the future release. | ||
27 | + * | ||
28 | + * @return a group ID as short value | ||
29 | + */ | ||
30 | + int id(); | ||
31 | +} |
... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.statistic; | 16 | package org.onlab.onos.net.statistic; |
17 | 17 | ||
18 | +import org.onlab.onos.core.ApplicationId; | ||
19 | +import org.onlab.onos.core.GroupId; | ||
18 | import org.onlab.onos.net.ConnectPoint; | 20 | import org.onlab.onos.net.ConnectPoint; |
19 | import org.onlab.onos.net.Link; | 21 | import org.onlab.onos.net.Link; |
20 | import org.onlab.onos.net.Path; | 22 | import org.onlab.onos.net.Path; |
21 | import org.onlab.onos.net.flow.FlowRule; | 23 | import org.onlab.onos.net.flow.FlowRule; |
22 | 24 | ||
25 | +import java.util.Optional; | ||
26 | + | ||
23 | /** | 27 | /** |
24 | * Service for obtaining statistic information about link in the system. | 28 | * Service for obtaining statistic information about link in the system. |
25 | * Statistics are obtained from the FlowRuleService in order to minimize the | 29 | * Statistics are obtained from the FlowRuleService in order to minimize the |
... | @@ -68,4 +72,14 @@ public interface StatisticService { | ... | @@ -68,4 +72,14 @@ public interface StatisticService { |
68 | */ | 72 | */ |
69 | FlowRule highestHitter(ConnectPoint connectPoint); | 73 | FlowRule highestHitter(ConnectPoint connectPoint); |
70 | 74 | ||
75 | + /** | ||
76 | + * Obtain the load for a the ingress to the given link used by | ||
77 | + * the specified application ID and group ID. | ||
78 | + * | ||
79 | + * @param link link to query | ||
80 | + * @param appId application ID to filter with | ||
81 | + * @param groupId group ID to filter with | ||
82 | + * @return {@link Load Load} | ||
83 | + */ | ||
84 | + Load load(Link link, ApplicationId appId, Optional<GroupId> groupId); | ||
71 | } | 85 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2014 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.onlab.onos.core; | ||
17 | + | ||
18 | +import com.google.common.testing.EqualsTester; | ||
19 | +import org.junit.Test; | ||
20 | + | ||
21 | +/** | ||
22 | + * Test for DefaultGroupId. | ||
23 | + */ | ||
24 | +public class DefaultGroupIdTest { | ||
25 | + | ||
26 | + /** | ||
27 | + * Tests the equality of the instances. | ||
28 | + */ | ||
29 | + @Test | ||
30 | + public void testEquality() { | ||
31 | + DefaultGroupId id1 = new DefaultGroupId((short) 1); | ||
32 | + DefaultGroupId id2 = new DefaultGroupId((short) 1); | ||
33 | + DefaultGroupId id3 = new DefaultGroupId((short) 2); | ||
34 | + | ||
35 | + new EqualsTester() | ||
36 | + .addEqualityGroup(id1, id2) | ||
37 | + .addEqualityGroup(id3) | ||
38 | + .testEquals(); | ||
39 | + } | ||
40 | + | ||
41 | +} |
... | @@ -15,12 +15,18 @@ | ... | @@ -15,12 +15,18 @@ |
15 | */ | 15 | */ |
16 | package org.onlab.onos.net.statistic.impl; | 16 | package org.onlab.onos.net.statistic.impl; |
17 | 17 | ||
18 | +import com.google.common.base.MoreObjects; | ||
19 | +import com.google.common.base.Predicate; | ||
20 | +import com.google.common.collect.FluentIterable; | ||
21 | +import com.google.common.collect.ImmutableSet; | ||
18 | import org.apache.felix.scr.annotations.Activate; | 22 | import org.apache.felix.scr.annotations.Activate; |
19 | import org.apache.felix.scr.annotations.Component; | 23 | import org.apache.felix.scr.annotations.Component; |
20 | import org.apache.felix.scr.annotations.Deactivate; | 24 | import org.apache.felix.scr.annotations.Deactivate; |
21 | import org.apache.felix.scr.annotations.Reference; | 25 | import org.apache.felix.scr.annotations.Reference; |
22 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 26 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
23 | import org.apache.felix.scr.annotations.Service; | 27 | import org.apache.felix.scr.annotations.Service; |
28 | +import org.onlab.onos.core.ApplicationId; | ||
29 | +import org.onlab.onos.core.GroupId; | ||
24 | import org.onlab.onos.net.ConnectPoint; | 30 | import org.onlab.onos.net.ConnectPoint; |
25 | import org.onlab.onos.net.Link; | 31 | import org.onlab.onos.net.Link; |
26 | import org.onlab.onos.net.Path; | 32 | import org.onlab.onos.net.Path; |
... | @@ -35,8 +41,13 @@ import org.onlab.onos.net.statistic.Load; | ... | @@ -35,8 +41,13 @@ import org.onlab.onos.net.statistic.Load; |
35 | import org.onlab.onos.net.statistic.StatisticService; | 41 | import org.onlab.onos.net.statistic.StatisticService; |
36 | import org.onlab.onos.net.statistic.StatisticStore; | 42 | import org.onlab.onos.net.statistic.StatisticStore; |
37 | import org.slf4j.Logger; | 43 | import org.slf4j.Logger; |
44 | + | ||
45 | +import java.util.Collections; | ||
46 | +import java.util.Objects; | ||
47 | +import java.util.Optional; | ||
38 | import java.util.Set; | 48 | import java.util.Set; |
39 | 49 | ||
50 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
40 | import static org.slf4j.LoggerFactory.getLogger; | 51 | import static org.slf4j.LoggerFactory.getLogger; |
41 | 52 | ||
42 | /** | 53 | /** |
... | @@ -76,6 +87,25 @@ public class StatisticManager implements StatisticService { | ... | @@ -76,6 +87,25 @@ public class StatisticManager implements StatisticService { |
76 | } | 87 | } |
77 | 88 | ||
78 | @Override | 89 | @Override |
90 | + public Load load(Link link, ApplicationId appId, Optional<GroupId> groupId) { | ||
91 | + Statistics stats = getStatistics(link.src()); | ||
92 | + if (!stats.isValid()) { | ||
93 | + return new DefaultLoad(); | ||
94 | + } | ||
95 | + | ||
96 | + ImmutableSet<FlowEntry> current = FluentIterable.from(stats.current()) | ||
97 | + .filter(hasApplicationId(appId)) | ||
98 | + .filter(hasGroupId(groupId)) | ||
99 | + .toSet(); | ||
100 | + ImmutableSet<FlowEntry> previous = FluentIterable.from(stats.previous()) | ||
101 | + .filter(hasApplicationId(appId)) | ||
102 | + .filter(hasGroupId(groupId)) | ||
103 | + .toSet(); | ||
104 | + | ||
105 | + return new DefaultLoad(aggregate(current), aggregate(previous)); | ||
106 | + } | ||
107 | + | ||
108 | + @Override | ||
79 | public Load load(ConnectPoint connectPoint) { | 109 | public Load load(ConnectPoint connectPoint) { |
80 | return loadInternal(connectPoint); | 110 | return loadInternal(connectPoint); |
81 | } | 111 | } |
... | @@ -131,21 +161,63 @@ public class StatisticManager implements StatisticService { | ... | @@ -131,21 +161,63 @@ public class StatisticManager implements StatisticService { |
131 | } | 161 | } |
132 | 162 | ||
133 | private Load loadInternal(ConnectPoint connectPoint) { | 163 | private Load loadInternal(ConnectPoint connectPoint) { |
164 | + Statistics stats = getStatistics(connectPoint); | ||
165 | + if (!stats.isValid()) { | ||
166 | + return new DefaultLoad(); | ||
167 | + } | ||
168 | + | ||
169 | + return new DefaultLoad(aggregate(stats.current), aggregate(stats.previous)); | ||
170 | + } | ||
171 | + | ||
172 | + /** | ||
173 | + * Returns statistics of the specified port. | ||
174 | + * | ||
175 | + * @param connectPoint port to query | ||
176 | + * @return statistics | ||
177 | + */ | ||
178 | + private Statistics getStatistics(ConnectPoint connectPoint) { | ||
134 | Set<FlowEntry> current; | 179 | Set<FlowEntry> current; |
135 | Set<FlowEntry> previous; | 180 | Set<FlowEntry> previous; |
136 | synchronized (statisticStore) { | 181 | synchronized (statisticStore) { |
137 | - current = statisticStore.getCurrentStatistic(connectPoint); | 182 | + current = getCurrentStatistic(connectPoint); |
138 | - previous = statisticStore.getPreviousStatistic(connectPoint); | 183 | + previous = getPreviousStatistic(connectPoint); |
139 | } | 184 | } |
140 | - if (current == null || previous == null) { | 185 | + |
141 | - return new DefaultLoad(); | 186 | + return new Statistics(current, previous); |
142 | } | 187 | } |
143 | - long currentAggregate = aggregate(current); | ||
144 | - long previousAggregate = aggregate(previous); | ||
145 | 188 | ||
146 | - return new DefaultLoad(currentAggregate, previousAggregate); | 189 | + /** |
190 | + * Returns the current statistic of the specified port. | ||
191 | + | ||
192 | + * @param connectPoint port to query | ||
193 | + * @return set of flow entries | ||
194 | + */ | ||
195 | + private Set<FlowEntry> getCurrentStatistic(ConnectPoint connectPoint) { | ||
196 | + Set<FlowEntry> stats = statisticStore.getCurrentStatistic(connectPoint); | ||
197 | + if (stats == null) { | ||
198 | + return Collections.emptySet(); | ||
199 | + } else { | ||
200 | + return stats; | ||
201 | + } | ||
202 | + } | ||
203 | + | ||
204 | + /** | ||
205 | + * Returns the previous statistic of the specified port. | ||
206 | + * | ||
207 | + * @param connectPoint port to query | ||
208 | + * @return set of flow entries | ||
209 | + */ | ||
210 | + private Set<FlowEntry> getPreviousStatistic(ConnectPoint connectPoint) { | ||
211 | + Set<FlowEntry> stats = statisticStore.getCurrentStatistic(connectPoint); | ||
212 | + if (stats == null) { | ||
213 | + return Collections.emptySet(); | ||
214 | + } else { | ||
215 | + return stats; | ||
216 | + } | ||
147 | } | 217 | } |
148 | 218 | ||
219 | + // TODO: make aggregation function generic by passing a function | ||
220 | + // (applying Java 8 Stream API?) | ||
149 | /** | 221 | /** |
150 | * Aggregates a set of values. | 222 | * Aggregates a set of values. |
151 | * @param values the values to aggregate | 223 | * @param values the values to aggregate |
... | @@ -188,5 +260,105 @@ public class StatisticManager implements StatisticService { | ... | @@ -188,5 +260,105 @@ public class StatisticManager implements StatisticService { |
188 | } | 260 | } |
189 | } | 261 | } |
190 | 262 | ||
263 | + /** | ||
264 | + * Internal data class holding two set of flow entries. | ||
265 | + */ | ||
266 | + private static class Statistics { | ||
267 | + private final ImmutableSet<FlowEntry> current; | ||
268 | + private final ImmutableSet<FlowEntry> previous; | ||
269 | + | ||
270 | + public Statistics(Set<FlowEntry> current, Set<FlowEntry> previous) { | ||
271 | + this.current = ImmutableSet.copyOf(checkNotNull(current)); | ||
272 | + this.previous = ImmutableSet.copyOf(checkNotNull(previous)); | ||
273 | + } | ||
274 | + | ||
275 | + /** | ||
276 | + * Returns flow entries as the current value. | ||
277 | + * | ||
278 | + * @return flow entries as the current value | ||
279 | + */ | ||
280 | + public ImmutableSet<FlowEntry> current() { | ||
281 | + return current; | ||
282 | + } | ||
191 | 283 | ||
284 | + /** | ||
285 | + * Returns flow entries as the previous value. | ||
286 | + * | ||
287 | + * @return flow entries as the previous value | ||
288 | + */ | ||
289 | + public ImmutableSet<FlowEntry> previous() { | ||
290 | + return previous; | ||
291 | + } | ||
292 | + | ||
293 | + /** | ||
294 | + * Validates values are not empty. | ||
295 | + * | ||
296 | + * @return false if either of the sets is empty. Otherwise, true. | ||
297 | + */ | ||
298 | + public boolean isValid() { | ||
299 | + return !(current.isEmpty() || previous.isEmpty()); | ||
300 | + } | ||
301 | + | ||
302 | + @Override | ||
303 | + public int hashCode() { | ||
304 | + return Objects.hash(current, previous); | ||
305 | + } | ||
306 | + | ||
307 | + @Override | ||
308 | + public boolean equals(Object obj) { | ||
309 | + if (this == obj) { | ||
310 | + return true; | ||
311 | + } | ||
312 | + if (!(obj instanceof Statistics)) { | ||
313 | + return false; | ||
314 | + } | ||
315 | + final Statistics other = (Statistics) obj; | ||
316 | + return Objects.equals(this.current, other.current) && Objects.equals(this.previous, other.previous); | ||
317 | + } | ||
318 | + | ||
319 | + @Override | ||
320 | + public String toString() { | ||
321 | + return MoreObjects.toStringHelper(this) | ||
322 | + .add("current", current) | ||
323 | + .add("previous", previous) | ||
324 | + .toString(); | ||
325 | + } | ||
326 | + } | ||
327 | + | ||
328 | + /** | ||
329 | + * Creates a predicate that checks the application ID of a flow entry is the same as | ||
330 | + * the specified application ID. | ||
331 | + * | ||
332 | + * @param appId application ID to be checked | ||
333 | + * @return predicate | ||
334 | + */ | ||
335 | + private static Predicate<FlowEntry> hasApplicationId(ApplicationId appId) { | ||
336 | + return new Predicate<FlowEntry>() { | ||
337 | + @Override | ||
338 | + public boolean apply(FlowEntry flowEntry) { | ||
339 | + return flowEntry.appId() == appId.id(); | ||
340 | + } | ||
341 | + }; | ||
342 | + } | ||
343 | + | ||
344 | + /** | ||
345 | + * Create a predicate that checks the group ID of a flow entry is the same as | ||
346 | + * the specified group ID. | ||
347 | + * | ||
348 | + * @param groupId group ID to be checked | ||
349 | + * @return predicate | ||
350 | + */ | ||
351 | + private static Predicate<FlowEntry> hasGroupId(Optional<GroupId> groupId) { | ||
352 | + return new Predicate<FlowEntry>() { | ||
353 | + @Override | ||
354 | + public boolean apply(FlowEntry flowEntry) { | ||
355 | + if (!groupId.isPresent()) { | ||
356 | + return false; | ||
357 | + } | ||
358 | + // FIXME: The left hand type and right hand type don't match | ||
359 | + // FlowEntry.groupId() still returns a short value, not int. | ||
360 | + return flowEntry.groupId() == groupId.get().id(); | ||
361 | + } | ||
362 | + }; | ||
363 | + } | ||
192 | } | 364 | } | ... | ... |
-
Please register or login to post a comment