Sho SHIMIZU
Committed by Gerrit Code Review

Reduce the memory usage by RangeSet in backing data structure

- Typically resource query is more frequent than resource registration.
  This patch optimizes memory usage for resource query rather than registration

Change-Id: Ic680c09c83b4299e80d4493d01e642081549fa24
(cherry picked from commit fd18ded0)
...@@ -117,7 +117,7 @@ final class EncodableDiscreteResources implements DiscreteResources { ...@@ -117,7 +117,7 @@ final class EncodableDiscreteResources implements DiscreteResources {
117 @Override 117 @Override
118 public Set<DiscreteResource> values() { 118 public Set<DiscreteResource> values() {
119 return values.values().stream() 119 return values.values().stream()
120 - .flatMap(x -> x.resources(parent.id()).stream()) 120 + .flatMap(x -> x.values(parent.id()).stream())
121 .collect(Collectors.toCollection(LinkedHashSet::new)); 121 .collect(Collectors.toCollection(LinkedHashSet::new));
122 } 122 }
123 123
......
...@@ -43,7 +43,7 @@ class EncodableDiscreteResourcesSerializer extends Serializer<EncodableDiscreteR ...@@ -43,7 +43,7 @@ class EncodableDiscreteResourcesSerializer extends Serializer<EncodableDiscreteR
43 43
44 return EncodableDiscreteResources.of(parent, 44 return EncodableDiscreteResources.of(parent,
45 resources.stream() 45 resources.stream()
46 - .flatMap(x -> x.resources(parent.id()).stream()) 46 + .flatMap(x -> x.values(parent.id()).stream())
47 .collect(Collectors.toCollection(LinkedHashSet::new))); 47 .collect(Collectors.toCollection(LinkedHashSet::new)));
48 } 48 }
49 } 49 }
......
...@@ -15,6 +15,10 @@ ...@@ -15,6 +15,10 @@
15 */ 15 */
16 package org.onosproject.store.resource.impl; 16 package org.onosproject.store.resource.impl;
17 17
18 +import com.google.common.collect.DiscreteDomain;
19 +import com.google.common.collect.Range;
20 +import com.google.common.collect.RangeSet;
21 +import com.google.common.collect.TreeRangeSet;
18 import org.onlab.util.Tools; 22 import org.onlab.util.Tools;
19 import org.onosproject.net.resource.DiscreteResource; 23 import org.onosproject.net.resource.DiscreteResource;
20 import org.onosproject.net.resource.DiscreteResourceCodec; 24 import org.onosproject.net.resource.DiscreteResourceCodec;
...@@ -24,39 +28,45 @@ import org.onosproject.net.resource.Resources; ...@@ -24,39 +28,45 @@ import org.onosproject.net.resource.Resources;
24 import java.util.LinkedHashSet; 28 import java.util.LinkedHashSet;
25 import java.util.Set; 29 import java.util.Set;
26 import java.util.stream.Collectors; 30 import java.util.stream.Collectors;
31 +import java.util.stream.IntStream;
27 32
28 /** 33 /**
29 * Represents discrete resources encoded by a codec. 34 * Represents discrete resources encoded by a codec.
30 */ 35 */
31 final class EncodedDiscreteResources { 36 final class EncodedDiscreteResources {
32 - private final Set<Integer> rawValues; 37 + private final RangeSet<Integer> rangeSet;
33 private final DiscreteResourceCodec codec; 38 private final DiscreteResourceCodec codec;
34 39
35 - EncodedDiscreteResources(Set<Integer> rawValues, DiscreteResourceCodec codec) { 40 + EncodedDiscreteResources(RangeSet<Integer> rangeSet, DiscreteResourceCodec codec) {
36 - this.rawValues = rawValues; 41 + this.rangeSet = rangeSet;
37 this.codec = codec; 42 this.codec = codec;
38 } 43 }
39 44
40 static EncodedDiscreteResources of(Set<DiscreteResource> resources, DiscreteResourceCodec codec) { 45 static EncodedDiscreteResources of(Set<DiscreteResource> resources, DiscreteResourceCodec codec) {
41 - Set<Integer> rawValues = resources.stream() 46 + RangeSet<Integer> rangeSet = TreeRangeSet.create();
47 + resources.stream()
42 .map(x -> x.valueAs(Object.class)) 48 .map(x -> x.valueAs(Object.class))
43 .flatMap(Tools::stream) 49 .flatMap(Tools::stream)
44 .map(x -> codec.encode(x)) 50 .map(x -> codec.encode(x))
45 - .collect(Collectors.toCollection(LinkedHashSet::new)); 51 + .map(Range::singleton)
52 + .map(x -> x.canonical(DiscreteDomain.integers()))
53 + .forEach(rangeSet::add);
46 54
47 - return new EncodedDiscreteResources(rawValues, codec); 55 + return new EncodedDiscreteResources(rangeSet, codec);
48 } 56 }
49 57
50 - Set<Integer> rawValues() { 58 + RangeSet<Integer> rangeSet() {
51 - return rawValues; 59 + return rangeSet;
52 } 60 }
53 61
54 DiscreteResourceCodec codec() { 62 DiscreteResourceCodec codec() {
55 return codec; 63 return codec;
56 } 64 }
57 65
58 - Set<DiscreteResource> resources(DiscreteResourceId parent) { 66 + Set<DiscreteResource> values(DiscreteResourceId parent) {
59 - return rawValues.stream() 67 + return rangeSet.asRanges().stream()
68 + .flatMapToInt(x1 -> IntStream.range(x1.lowerEndpoint(), x1.upperEndpoint()))
69 + .boxed()
60 .map(x -> codec.decode(x)) 70 .map(x -> codec.decode(x))
61 .map(x -> Resources.discrete(parent, x).resource()) 71 .map(x -> Resources.discrete(parent, x).resource())
62 .collect(Collectors.toCollection(LinkedHashSet::new)); 72 .collect(Collectors.toCollection(LinkedHashSet::new));
...@@ -64,10 +74,10 @@ final class EncodedDiscreteResources { ...@@ -64,10 +74,10 @@ final class EncodedDiscreteResources {
64 74
65 @SuppressWarnings("unchecked") 75 @SuppressWarnings("unchecked")
66 boolean contains(DiscreteResource resource) { 76 boolean contains(DiscreteResource resource) {
67 - return rawValues.contains(codec.encode(resource)); 77 + return rangeSet.contains(codec.encode(resource));
68 } 78 }
69 79
70 boolean isEmpty() { 80 boolean isEmpty() {
71 - return rawValues.isEmpty(); 81 + return rangeSet.isEmpty();
72 } 82 }
73 } 83 }
......
...@@ -19,18 +19,15 @@ import com.esotericsoftware.kryo.Kryo; ...@@ -19,18 +19,15 @@ import com.esotericsoftware.kryo.Kryo;
19 import com.esotericsoftware.kryo.Serializer; 19 import com.esotericsoftware.kryo.Serializer;
20 import com.esotericsoftware.kryo.io.Input; 20 import com.esotericsoftware.kryo.io.Input;
21 import com.esotericsoftware.kryo.io.Output; 21 import com.esotericsoftware.kryo.io.Output;
22 -import com.google.common.collect.DiscreteDomain;
23 import com.google.common.collect.Range; 22 import com.google.common.collect.Range;
23 +import com.google.common.collect.RangeSet;
24 import com.google.common.collect.TreeRangeSet; 24 import com.google.common.collect.TreeRangeSet;
25 import org.onlab.util.ClosedOpenRange; 25 import org.onlab.util.ClosedOpenRange;
26 import org.onosproject.net.resource.DiscreteResourceCodec; 26 import org.onosproject.net.resource.DiscreteResourceCodec;
27 27
28 import java.util.ArrayList; 28 import java.util.ArrayList;
29 -import java.util.HashSet;
30 -import java.util.LinkedHashSet;
31 import java.util.List; 29 import java.util.List;
32 import java.util.stream.Collectors; 30 import java.util.stream.Collectors;
33 -import java.util.stream.IntStream;
34 31
35 /** 32 /**
36 * Kryo Serializer for {@link EncodedDiscreteResources}. 33 * Kryo Serializer for {@link EncodedDiscreteResources}.
...@@ -38,12 +35,7 @@ import java.util.stream.IntStream; ...@@ -38,12 +35,7 @@ import java.util.stream.IntStream;
38 final class EncodedResourcesSerializer extends Serializer<EncodedDiscreteResources> { 35 final class EncodedResourcesSerializer extends Serializer<EncodedDiscreteResources> {
39 @Override 36 @Override
40 public void write(Kryo kryo, Output output, EncodedDiscreteResources object) { 37 public void write(Kryo kryo, Output output, EncodedDiscreteResources object) {
41 - TreeRangeSet<Integer> rangeSet = TreeRangeSet.create(); 38 + List<ClosedOpenRange> ranges = object.rangeSet().asRanges().stream()
42 - object.rawValues().stream()
43 - .map(Range::singleton)
44 - .map(x -> x.canonical(DiscreteDomain.integers()))
45 - .forEach(rangeSet::add);
46 - List<ClosedOpenRange> ranges = rangeSet.asRanges().stream()
47 .map(ClosedOpenRange::of) 39 .map(ClosedOpenRange::of)
48 .collect(Collectors.toList()); 40 .collect(Collectors.toList());
49 kryo.writeObject(output, ranges); 41 kryo.writeObject(output, ranges);
...@@ -56,10 +48,10 @@ final class EncodedResourcesSerializer extends Serializer<EncodedDiscreteResourc ...@@ -56,10 +48,10 @@ final class EncodedResourcesSerializer extends Serializer<EncodedDiscreteResourc
56 List<ClosedOpenRange> ranges = kryo.readObject(input, ArrayList.class); 48 List<ClosedOpenRange> ranges = kryo.readObject(input, ArrayList.class);
57 DiscreteResourceCodec codec = (DiscreteResourceCodec) kryo.readClassAndObject(input); 49 DiscreteResourceCodec codec = (DiscreteResourceCodec) kryo.readClassAndObject(input);
58 50
59 - HashSet<Integer> rawValues = ranges.stream() 51 + RangeSet<Integer> rangeSet = TreeRangeSet.create();
60 - .flatMapToInt(x -> IntStream.range(x.lowerBound(), x.upperBound())) 52 + ranges.stream()
61 - .boxed() 53 + .map(x -> Range.closedOpen(x.lowerBound(), x.upperBound()))
62 - .collect(Collectors.toCollection(LinkedHashSet::new)); 54 + .forEach(rangeSet::add);
63 - return new EncodedDiscreteResources(rawValues, codec); 55 + return new EncodedDiscreteResources(rangeSet, codec);
64 } 56 }
65 } 57 }
......