Committed by
Gerrit Code Review
ONOS-3296: Support continuous type resources
Change-Id: I155e41e7a7c1750ff45986a55bedab353485d3fa
Showing
7 changed files
with
308 additions
and
94 deletions
... | @@ -126,13 +126,13 @@ public interface ResourceService extends ListenerService<ResourceEvent, Resource | ... | @@ -126,13 +126,13 @@ public interface ResourceService extends ListenerService<ResourceEvent, Resource |
126 | boolean release(ResourceConsumer consumer); | 126 | boolean release(ResourceConsumer consumer); |
127 | 127 | ||
128 | /** | 128 | /** |
129 | - * Returns resource allocation of the specified resource. | 129 | + * Returns resource allocations of the specified resource. |
130 | * | 130 | * |
131 | * @param resource resource to check the allocation | 131 | * @param resource resource to check the allocation |
132 | - * @return allocation information enclosed by Optional. | 132 | + * @return list of allocation information. |
133 | - * If the resource is not allocated, the return value is empty. | 133 | + * If the resource is not allocated, the return value is an empty list. |
134 | */ | 134 | */ |
135 | - Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource); | 135 | + List<ResourceAllocation> getResourceAllocation(ResourcePath resource); |
136 | 136 | ||
137 | /** | 137 | /** |
138 | * Returns allocated resources being as children of the specified parent and being the specified resource type. | 138 | * Returns allocated resources being as children of the specified parent and being the specified resource type. | ... | ... |
1 | /* | 1 | /* |
2 | - * Copyright 2015 Open Networking Laboratory | 2 | + * Copyright 2015-2016 Open Networking Laboratory |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
... | @@ -20,7 +20,6 @@ import org.onosproject.store.Store; | ... | @@ -20,7 +20,6 @@ import org.onosproject.store.Store; |
20 | 20 | ||
21 | import java.util.Collection; | 21 | import java.util.Collection; |
22 | import java.util.List; | 22 | import java.util.List; |
23 | -import java.util.Optional; | ||
24 | 23 | ||
25 | /** | 24 | /** |
26 | * Service for storing resource and consumer information. | 25 | * Service for storing resource and consumer information. |
... | @@ -77,12 +76,23 @@ public interface ResourceStore extends Store<ResourceEvent, ResourceStoreDelegat | ... | @@ -77,12 +76,23 @@ public interface ResourceStore extends Store<ResourceEvent, ResourceStoreDelegat |
77 | boolean release(List<ResourcePath> resources, List<ResourceConsumer> consumers); | 76 | boolean release(List<ResourcePath> resources, List<ResourceConsumer> consumers); |
78 | 77 | ||
79 | /** | 78 | /** |
80 | - * Returns the resource consumer to whom the specified resource is allocated. | 79 | + * Returns the resource consumers to whom the specified resource is allocated. |
80 | + * The return value is a list having only one element when the given resource is discrete type. | ||
81 | + * The return value may have multiple elements when the given resource is continuous type. | ||
81 | * | 82 | * |
82 | * @param resource resource whose allocated consumer to be returned | 83 | * @param resource resource whose allocated consumer to be returned |
83 | - * @return resource consumer who are allocated the resource | 84 | + * @return resource consumers who are allocated the resource. |
85 | + * Returns empty list if there is no such consumer. | ||
84 | */ | 86 | */ |
85 | - Optional<ResourceConsumer> getConsumer(ResourcePath resource); | 87 | + List<ResourceConsumer> getConsumers(ResourcePath resource); |
88 | + | ||
89 | + /** | ||
90 | + * Returns the availability of the specified resource. | ||
91 | + * | ||
92 | + * @param resource resource to check the availability | ||
93 | + * @return true if available, otherwise false | ||
94 | + */ | ||
95 | + boolean isAvailable(ResourcePath resource); | ||
86 | 96 | ||
87 | /** | 97 | /** |
88 | * Returns a collection of the resources allocated to the specified consumer. | 98 | * Returns a collection of the resources allocated to the specified consumer. | ... | ... |
... | @@ -313,9 +313,11 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu | ... | @@ -313,9 +313,11 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu |
313 | OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port()); | 313 | OchPort ochPort = (OchPort) deviceService.getPort(ochCP.deviceId(), ochCP.port()); |
314 | Optional<IntentId> intentId = | 314 | Optional<IntentId> intentId = |
315 | resourceService.getResourceAllocation(ResourcePath.discrete(ochCP.deviceId(), ochCP.port())) | 315 | resourceService.getResourceAllocation(ResourcePath.discrete(ochCP.deviceId(), ochCP.port())) |
316 | + .stream() | ||
316 | .map(ResourceAllocation::consumer) | 317 | .map(ResourceAllocation::consumer) |
317 | .filter(x -> x instanceof IntentId) | 318 | .filter(x -> x instanceof IntentId) |
318 | - .map(x -> (IntentId) x); | 319 | + .map(x -> (IntentId) x) |
320 | + .findAny(); | ||
319 | 321 | ||
320 | if (isAvailable(intentId.orElse(null))) { | 322 | if (isAvailable(intentId.orElse(null))) { |
321 | return ochPort; | 323 | return ochPort; |
... | @@ -332,9 +334,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu | ... | @@ -332,9 +334,12 @@ public class OpticalCircuitIntentCompiler implements IntentCompiler<OpticalCircu |
332 | 334 | ||
333 | Optional<IntentId> intentId = | 335 | Optional<IntentId> intentId = |
334 | resourceService.getResourceAllocation(ResourcePath.discrete(oduPort.deviceId(), port.number())) | 336 | resourceService.getResourceAllocation(ResourcePath.discrete(oduPort.deviceId(), port.number())) |
337 | + .stream() | ||
335 | .map(ResourceAllocation::consumer) | 338 | .map(ResourceAllocation::consumer) |
336 | .filter(x -> x instanceof IntentId) | 339 | .filter(x -> x instanceof IntentId) |
337 | - .map(x -> (IntentId) x); | 340 | + .map(x -> (IntentId) x) |
341 | + .findAny(); | ||
342 | + | ||
338 | if (isAvailable(intentId.orElse(null))) { | 343 | if (isAvailable(intentId.orElse(null))) { |
339 | return (OchPort) port; | 344 | return (OchPort) port; |
340 | } | 345 | } | ... | ... |
1 | /* | 1 | /* |
2 | - * Copyright 2015 Open Networking Laboratory | 2 | + * Copyright 2015-2016 Open Networking Laboratory |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
... | @@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate; | ... | @@ -23,6 +23,7 @@ import org.apache.felix.scr.annotations.Deactivate; |
23 | import org.apache.felix.scr.annotations.Reference; | 23 | import org.apache.felix.scr.annotations.Reference; |
24 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
25 | import org.apache.felix.scr.annotations.Service; | 25 | import org.apache.felix.scr.annotations.Service; |
26 | +import org.onlab.util.GuavaCollectors; | ||
26 | import org.onosproject.event.AbstractListenerManager; | 27 | import org.onosproject.event.AbstractListenerManager; |
27 | import org.onosproject.net.newresource.ResourceAdminService; | 28 | import org.onosproject.net.newresource.ResourceAdminService; |
28 | import org.onosproject.net.newresource.ResourceAllocation; | 29 | import org.onosproject.net.newresource.ResourceAllocation; |
... | @@ -34,10 +35,8 @@ import org.onosproject.net.newresource.ResourcePath; | ... | @@ -34,10 +35,8 @@ import org.onosproject.net.newresource.ResourcePath; |
34 | import org.onosproject.net.newresource.ResourceStore; | 35 | import org.onosproject.net.newresource.ResourceStore; |
35 | import org.onosproject.net.newresource.ResourceStoreDelegate; | 36 | import org.onosproject.net.newresource.ResourceStoreDelegate; |
36 | 37 | ||
37 | -import java.util.ArrayList; | ||
38 | import java.util.Collection; | 38 | import java.util.Collection; |
39 | import java.util.List; | 39 | import java.util.List; |
40 | -import java.util.Optional; | ||
41 | import java.util.stream.Collectors; | 40 | import java.util.stream.Collectors; |
42 | 41 | ||
43 | import static com.google.common.base.Preconditions.checkNotNull; | 42 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -107,11 +106,13 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent | ... | @@ -107,11 +106,13 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent |
107 | } | 106 | } |
108 | 107 | ||
109 | @Override | 108 | @Override |
110 | - public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) { | 109 | + public List<ResourceAllocation> getResourceAllocation(ResourcePath resource) { |
111 | checkNotNull(resource); | 110 | checkNotNull(resource); |
112 | 111 | ||
113 | - Optional<ResourceConsumer> consumer = store.getConsumer(resource); | 112 | + List<ResourceConsumer> consumers = store.getConsumers(resource); |
114 | - return consumer.map(x -> new ResourceAllocation(resource, x)); | 113 | + return consumers.stream() |
114 | + .map(x -> new ResourceAllocation(resource, x)) | ||
115 | + .collect(GuavaCollectors.toImmutableList()); | ||
115 | } | 116 | } |
116 | 117 | ||
117 | @Override | 118 | @Override |
... | @@ -119,17 +120,12 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent | ... | @@ -119,17 +120,12 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent |
119 | checkNotNull(parent); | 120 | checkNotNull(parent); |
120 | checkNotNull(cls); | 121 | checkNotNull(cls); |
121 | 122 | ||
122 | - Collection<ResourcePath> resources = store.getAllocatedResources(parent, cls); | ||
123 | - List<ResourceAllocation> allocations = new ArrayList<>(resources.size()); | ||
124 | - for (ResourcePath resource: resources) { | ||
125 | // We access store twice in this method, then the store may be updated by others | 123 | // We access store twice in this method, then the store may be updated by others |
126 | - Optional<ResourceConsumer> consumer = store.getConsumer(resource); | 124 | + Collection<ResourcePath> resources = store.getAllocatedResources(parent, cls); |
127 | - if (consumer.isPresent()) { | 125 | + return resources.stream() |
128 | - allocations.add(new ResourceAllocation(resource, consumer.get())); | 126 | + .flatMap(resource -> store.getConsumers(resource).stream() |
129 | - } | 127 | + .map(consumer -> new ResourceAllocation(resource, consumer))) |
130 | - } | 128 | + .collect(GuavaCollectors.toImmutableList()); |
131 | - | ||
132 | - return allocations; | ||
133 | } | 129 | } |
134 | 130 | ||
135 | @Override | 131 | @Override |
... | @@ -149,7 +145,7 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent | ... | @@ -149,7 +145,7 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent |
149 | Collection<ResourcePath> children = store.getChildResources(parent); | 145 | Collection<ResourcePath> children = store.getChildResources(parent); |
150 | return children.stream() | 146 | return children.stream() |
151 | // We access store twice in this method, then the store may be updated by others | 147 | // We access store twice in this method, then the store may be updated by others |
152 | - .filter(x -> !store.getConsumer(x).isPresent()) | 148 | + .filter(store::isAvailable) |
153 | .collect(Collectors.toList()); | 149 | .collect(Collectors.toList()); |
154 | } | 150 | } |
155 | 151 | ||
... | @@ -157,8 +153,7 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent | ... | @@ -157,8 +153,7 @@ public final class ResourceManager extends AbstractListenerManager<ResourceEvent |
157 | public boolean isAvailable(ResourcePath resource) { | 153 | public boolean isAvailable(ResourcePath resource) { |
158 | checkNotNull(resource); | 154 | checkNotNull(resource); |
159 | 155 | ||
160 | - Optional<ResourceConsumer> consumer = store.getConsumer(resource); | 156 | + return store.isAvailable(resource); |
161 | - return !consumer.isPresent(); | ||
162 | } | 157 | } |
163 | 158 | ||
164 | @Override | 159 | @Override | ... | ... |
... | @@ -66,9 +66,10 @@ class MockResourceService implements ResourceService { | ... | @@ -66,9 +66,10 @@ class MockResourceService implements ResourceService { |
66 | } | 66 | } |
67 | 67 | ||
68 | @Override | 68 | @Override |
69 | - public Optional<ResourceAllocation> getResourceAllocation(ResourcePath resource) { | 69 | + public List<ResourceAllocation> getResourceAllocation(ResourcePath resource) { |
70 | return Optional.ofNullable(assignment.get(resource)) | 70 | return Optional.ofNullable(assignment.get(resource)) |
71 | - .map(x -> new ResourceAllocation(resource, x)); | 71 | + .map(x -> ImmutableList.of(new ResourceAllocation(resource, x))) |
72 | + .orElse(ImmutableList.of()); | ||
72 | } | 73 | } |
73 | 74 | ||
74 | @Override | 75 | @Override | ... | ... |
1 | /* | 1 | /* |
2 | - * Copyright 2015 Open Networking Laboratory | 2 | + * Copyright 2015-2016 Open Networking Laboratory |
3 | * | 3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. | 5 | * you may not use this file except in compliance with the License. |
... | @@ -17,14 +17,18 @@ package org.onosproject.store.newresource.impl; | ... | @@ -17,14 +17,18 @@ package org.onosproject.store.newresource.impl; |
17 | 17 | ||
18 | import com.google.common.annotations.Beta; | 18 | import com.google.common.annotations.Beta; |
19 | import com.google.common.collect.ImmutableList; | 19 | import com.google.common.collect.ImmutableList; |
20 | +import com.google.common.collect.Maps; | ||
20 | import org.apache.felix.scr.annotations.Activate; | 21 | import org.apache.felix.scr.annotations.Activate; |
21 | import org.apache.felix.scr.annotations.Component; | 22 | import org.apache.felix.scr.annotations.Component; |
22 | import org.apache.felix.scr.annotations.Reference; | 23 | import org.apache.felix.scr.annotations.Reference; |
23 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 24 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
24 | import org.apache.felix.scr.annotations.Service; | 25 | import org.apache.felix.scr.annotations.Service; |
26 | +import org.onlab.util.GuavaCollectors; | ||
25 | import org.onlab.util.Tools; | 27 | import org.onlab.util.Tools; |
28 | +import org.onosproject.net.newresource.ResourceAllocation; | ||
26 | import org.onosproject.net.newresource.ResourceConsumer; | 29 | import org.onosproject.net.newresource.ResourceConsumer; |
27 | import org.onosproject.net.newresource.ResourceEvent; | 30 | import org.onosproject.net.newresource.ResourceEvent; |
31 | +import org.onosproject.net.newresource.ResourceId; | ||
28 | import org.onosproject.net.newresource.ResourcePath; | 32 | import org.onosproject.net.newresource.ResourcePath; |
29 | import org.onosproject.net.newresource.ResourceStore; | 33 | import org.onosproject.net.newresource.ResourceStore; |
30 | import org.onosproject.net.newresource.ResourceStoreDelegate; | 34 | import org.onosproject.net.newresource.ResourceStoreDelegate; |
... | @@ -40,7 +44,6 @@ import org.onosproject.store.service.Versioned; | ... | @@ -40,7 +44,6 @@ import org.onosproject.store.service.Versioned; |
40 | import org.slf4j.Logger; | 44 | import org.slf4j.Logger; |
41 | import org.slf4j.LoggerFactory; | 45 | import org.slf4j.LoggerFactory; |
42 | 46 | ||
43 | -import java.util.ArrayList; | ||
44 | import java.util.Arrays; | 47 | import java.util.Arrays; |
45 | import java.util.Collection; | 48 | import java.util.Collection; |
46 | import java.util.Collections; | 49 | import java.util.Collections; |
... | @@ -49,7 +52,9 @@ import java.util.LinkedHashSet; | ... | @@ -49,7 +52,9 @@ import java.util.LinkedHashSet; |
49 | import java.util.List; | 52 | import java.util.List; |
50 | import java.util.Map; | 53 | import java.util.Map; |
51 | import java.util.Optional; | 54 | import java.util.Optional; |
55 | +import java.util.Set; | ||
52 | import java.util.stream.Collectors; | 56 | import java.util.stream.Collectors; |
57 | +import java.util.stream.Stream; | ||
53 | 58 | ||
54 | import static com.google.common.base.Preconditions.checkArgument; | 59 | import static com.google.common.base.Preconditions.checkArgument; |
55 | import static com.google.common.base.Preconditions.checkNotNull; | 60 | import static com.google.common.base.Preconditions.checkNotNull; |
... | @@ -65,10 +70,12 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -65,10 +70,12 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
65 | implements ResourceStore { | 70 | implements ResourceStore { |
66 | private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class); | 71 | private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class); |
67 | 72 | ||
68 | - private static final String CONSUMER_MAP = "onos-resource-consumers"; | 73 | + private static final String DISCRETE_CONSUMER_MAP = "onos-discrete-consumers"; |
74 | + private static final String CONTINUOUS_CONSUMER_MAP = "onos-continuous-consumers"; | ||
69 | private static final String CHILD_MAP = "onos-resource-children"; | 75 | private static final String CHILD_MAP = "onos-resource-children"; |
70 | private static final Serializer SERIALIZER = Serializer.using( | 76 | private static final Serializer SERIALIZER = Serializer.using( |
71 | - Arrays.asList(KryoNamespaces.BASIC, KryoNamespaces.API)); | 77 | + Arrays.asList(KryoNamespaces.BASIC, KryoNamespaces.API), |
78 | + ContinuousResourceAllocation.class); | ||
72 | 79 | ||
73 | // TODO: We should provide centralized values for this | 80 | // TODO: We should provide centralized values for this |
74 | private static final int MAX_RETRIES = 5; | 81 | private static final int MAX_RETRIES = 5; |
... | @@ -77,35 +84,61 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -77,35 +84,61 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
77 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 84 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
78 | protected StorageService service; | 85 | protected StorageService service; |
79 | 86 | ||
80 | - private ConsistentMap<ResourcePath, ResourceConsumer> consumerMap; | 87 | + private ConsistentMap<ResourcePath.Discrete, ResourceConsumer> discreteConsumers; |
81 | - private ConsistentMap<ResourcePath, List<ResourcePath>> childMap; | 88 | + private ConsistentMap<ResourceId, ContinuousResourceAllocation> continuousConsumers; |
89 | + private ConsistentMap<ResourcePath.Discrete, Set<ResourcePath>> childMap; | ||
82 | 90 | ||
83 | @Activate | 91 | @Activate |
84 | public void activate() { | 92 | public void activate() { |
85 | - consumerMap = service.<ResourcePath, ResourceConsumer>consistentMapBuilder() | 93 | + discreteConsumers = service.<ResourcePath.Discrete, ResourceConsumer>consistentMapBuilder() |
86 | - .withName(CONSUMER_MAP) | 94 | + .withName(DISCRETE_CONSUMER_MAP) |
87 | .withSerializer(SERIALIZER) | 95 | .withSerializer(SERIALIZER) |
88 | .build(); | 96 | .build(); |
89 | - childMap = service.<ResourcePath, List<ResourcePath>>consistentMapBuilder() | 97 | + continuousConsumers = service.<ResourceId, ContinuousResourceAllocation>consistentMapBuilder() |
98 | + .withName(CONTINUOUS_CONSUMER_MAP) | ||
99 | + .withSerializer(SERIALIZER) | ||
100 | + .build(); | ||
101 | + childMap = service.<ResourcePath.Discrete, Set<ResourcePath>>consistentMapBuilder() | ||
90 | .withName(CHILD_MAP) | 102 | .withName(CHILD_MAP) |
91 | .withSerializer(SERIALIZER) | 103 | .withSerializer(SERIALIZER) |
92 | .build(); | 104 | .build(); |
93 | 105 | ||
94 | - Tools.retryable(() -> childMap.put(ResourcePath.ROOT, ImmutableList.of()), | 106 | + Tools.retryable(() -> childMap.put(ResourcePath.ROOT, new LinkedHashSet<>()), |
95 | ConsistentMapException.class, MAX_RETRIES, RETRY_DELAY); | 107 | ConsistentMapException.class, MAX_RETRIES, RETRY_DELAY); |
96 | log.info("Started"); | 108 | log.info("Started"); |
97 | } | 109 | } |
98 | 110 | ||
99 | @Override | 111 | @Override |
100 | - public Optional<ResourceConsumer> getConsumer(ResourcePath resource) { | 112 | + public List<ResourceConsumer> getConsumers(ResourcePath resource) { |
101 | checkNotNull(resource); | 113 | checkNotNull(resource); |
114 | + checkArgument(resource instanceof ResourcePath.Discrete || resource instanceof ResourcePath.Continuous); | ||
115 | + | ||
116 | + if (resource instanceof ResourcePath.Discrete) { | ||
117 | + return getConsumer((ResourcePath.Discrete) resource); | ||
118 | + } else { | ||
119 | + return getConsumer((ResourcePath.Continuous) resource); | ||
120 | + } | ||
121 | + } | ||
102 | 122 | ||
103 | - Versioned<ResourceConsumer> consumer = consumerMap.get(resource); | 123 | + private List<ResourceConsumer> getConsumer(ResourcePath.Discrete resource) { |
124 | + Versioned<ResourceConsumer> consumer = discreteConsumers.get(resource); | ||
104 | if (consumer == null) { | 125 | if (consumer == null) { |
105 | - return Optional.empty(); | 126 | + return ImmutableList.of(); |
127 | + } | ||
128 | + | ||
129 | + return ImmutableList.of(consumer.value()); | ||
130 | + } | ||
131 | + | ||
132 | + private List<ResourceConsumer> getConsumer(ResourcePath.Continuous resource) { | ||
133 | + Versioned<ContinuousResourceAllocation> allocations = continuousConsumers.get(resource.id()); | ||
134 | + if (allocations == null) { | ||
135 | + return ImmutableList.of(); | ||
106 | } | 136 | } |
107 | 137 | ||
108 | - return Optional.of(consumer.value()); | 138 | + return allocations.value().allocations().stream() |
139 | + .filter(x -> x.resource().equals(resource)) | ||
140 | + .map(ResourceAllocation::consumer) | ||
141 | + .collect(GuavaCollectors.toImmutableList()); | ||
109 | } | 142 | } |
110 | 143 | ||
111 | @Override | 144 | @Override |
... | @@ -115,15 +148,16 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -115,15 +148,16 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
115 | TransactionContext tx = service.transactionContextBuilder().build(); | 148 | TransactionContext tx = service.transactionContextBuilder().build(); |
116 | tx.begin(); | 149 | tx.begin(); |
117 | 150 | ||
118 | - TransactionalMap<ResourcePath, List<ResourcePath>> childTxMap = | 151 | + TransactionalMap<ResourcePath.Discrete, Set<ResourcePath>> childTxMap = |
119 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); | 152 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); |
120 | 153 | ||
121 | - Map<ResourcePath, List<ResourcePath>> resourceMap = resources.stream() | 154 | + Map<ResourcePath.Discrete, List<ResourcePath>> resourceMap = resources.stream() |
122 | .filter(x -> x.parent().isPresent()) | 155 | .filter(x -> x.parent().isPresent()) |
123 | .collect(Collectors.groupingBy(x -> x.parent().get())); | 156 | .collect(Collectors.groupingBy(x -> x.parent().get())); |
124 | 157 | ||
125 | - for (Map.Entry<ResourcePath, List<ResourcePath>> entry: resourceMap.entrySet()) { | 158 | + for (Map.Entry<ResourcePath.Discrete, List<ResourcePath>> entry: resourceMap.entrySet()) { |
126 | - if (!isRegistered(childTxMap, entry.getKey())) { | 159 | + Optional<ResourcePath.Discrete> child = lookup(childTxMap, entry.getKey()); |
160 | + if (!child.isPresent()) { | ||
127 | return abortTransaction(tx); | 161 | return abortTransaction(tx); |
128 | } | 162 | } |
129 | 163 | ||
... | @@ -150,19 +184,32 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -150,19 +184,32 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
150 | TransactionContext tx = service.transactionContextBuilder().build(); | 184 | TransactionContext tx = service.transactionContextBuilder().build(); |
151 | tx.begin(); | 185 | tx.begin(); |
152 | 186 | ||
153 | - TransactionalMap<ResourcePath, List<ResourcePath>> childTxMap = | 187 | + TransactionalMap<ResourcePath.Discrete, Set<ResourcePath>> childTxMap = |
154 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); | 188 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); |
155 | - TransactionalMap<ResourcePath, ResourceConsumer> consumerTxMap = | 189 | + TransactionalMap<ResourcePath.Discrete, ResourceConsumer> discreteConsumerTxMap = |
156 | - tx.getTransactionalMap(CONSUMER_MAP, SERIALIZER); | 190 | + tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); |
191 | + TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = | ||
192 | + tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); | ||
157 | 193 | ||
158 | - Map<ResourcePath, List<ResourcePath>> resourceMap = resources.stream() | 194 | + // Extract Discrete instances from resources |
195 | + Map<ResourcePath.Discrete, List<ResourcePath>> resourceMap = resources.stream() | ||
159 | .filter(x -> x.parent().isPresent()) | 196 | .filter(x -> x.parent().isPresent()) |
160 | .collect(Collectors.groupingBy(x -> x.parent().get())); | 197 | .collect(Collectors.groupingBy(x -> x.parent().get())); |
161 | 198 | ||
162 | // even if one of the resources is allocated to a consumer, | 199 | // even if one of the resources is allocated to a consumer, |
163 | // all unregistrations are regarded as failure | 200 | // all unregistrations are regarded as failure |
164 | - for (Map.Entry<ResourcePath, List<ResourcePath>> entry: resourceMap.entrySet()) { | 201 | + for (Map.Entry<ResourcePath.Discrete, List<ResourcePath>> entry: resourceMap.entrySet()) { |
165 | - if (entry.getValue().stream().anyMatch(x -> consumerTxMap.get(x) != null)) { | 202 | + boolean allocated = entry.getValue().stream().anyMatch(x -> { |
203 | + if (x instanceof ResourcePath.Discrete) { | ||
204 | + return discreteConsumerTxMap.get((ResourcePath.Discrete) x) != null; | ||
205 | + } else if (x instanceof ResourcePath.Continuous) { | ||
206 | + ContinuousResourceAllocation allocations = continuousConsumerTxMap.get(x.id()); | ||
207 | + return allocations != null && !allocations.allocations().isEmpty(); | ||
208 | + } else { | ||
209 | + return false; | ||
210 | + } | ||
211 | + }); | ||
212 | + if (allocated) { | ||
166 | return abortTransaction(tx); | 213 | return abortTransaction(tx); |
167 | } | 214 | } |
168 | 215 | ||
... | @@ -190,20 +237,40 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -190,20 +237,40 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
190 | TransactionContext tx = service.transactionContextBuilder().build(); | 237 | TransactionContext tx = service.transactionContextBuilder().build(); |
191 | tx.begin(); | 238 | tx.begin(); |
192 | 239 | ||
193 | - TransactionalMap<ResourcePath, List<ResourcePath>> childTxMap = | 240 | + TransactionalMap<ResourcePath.Discrete, Set<ResourcePath>> childTxMap = |
194 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); | 241 | tx.getTransactionalMap(CHILD_MAP, SERIALIZER); |
195 | - TransactionalMap<ResourcePath, ResourceConsumer> consumerTxMap = | 242 | + TransactionalMap<ResourcePath.Discrete, ResourceConsumer> discreteConsumerTxMap = |
196 | - tx.getTransactionalMap(CONSUMER_MAP, SERIALIZER); | 243 | + tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); |
244 | + TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = | ||
245 | + tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); | ||
197 | 246 | ||
198 | for (ResourcePath resource: resources) { | 247 | for (ResourcePath resource: resources) { |
199 | - if (!isRegistered(childTxMap, resource)) { | 248 | + if (resource instanceof ResourcePath.Discrete) { |
249 | + if (!lookup(childTxMap, resource).isPresent()) { | ||
200 | return abortTransaction(tx); | 250 | return abortTransaction(tx); |
201 | } | 251 | } |
202 | 252 | ||
203 | - ResourceConsumer oldValue = consumerTxMap.put(resource, consumer); | 253 | + ResourceConsumer oldValue = discreteConsumerTxMap.put((ResourcePath.Discrete) resource, consumer); |
204 | if (oldValue != null) { | 254 | if (oldValue != null) { |
205 | return abortTransaction(tx); | 255 | return abortTransaction(tx); |
206 | } | 256 | } |
257 | + } else if (resource instanceof ResourcePath.Continuous) { | ||
258 | + Optional<ResourcePath.Continuous> continuous = lookup(childTxMap, (ResourcePath.Continuous) resource); | ||
259 | + if (!continuous.isPresent()) { | ||
260 | + return abortTransaction(tx); | ||
261 | + } | ||
262 | + | ||
263 | + ContinuousResourceAllocation allocations = continuousConsumerTxMap.get(continuous.get().id()); | ||
264 | + if (!hasEnoughResource(continuous.get(), (ResourcePath.Continuous) resource, allocations)) { | ||
265 | + return abortTransaction(tx); | ||
266 | + } | ||
267 | + | ||
268 | + boolean success = appendValue(continuousConsumerTxMap, | ||
269 | + continuous.get(), new ResourceAllocation(continuous.get(), consumer)); | ||
270 | + if (!success) { | ||
271 | + return abortTransaction(tx); | ||
272 | + } | ||
273 | + } | ||
207 | } | 274 | } |
208 | 275 | ||
209 | return tx.commit(); | 276 | return tx.commit(); |
... | @@ -218,8 +285,10 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -218,8 +285,10 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
218 | TransactionContext tx = service.transactionContextBuilder().build(); | 285 | TransactionContext tx = service.transactionContextBuilder().build(); |
219 | tx.begin(); | 286 | tx.begin(); |
220 | 287 | ||
221 | - TransactionalMap<ResourcePath, ResourceConsumer> consumerTxMap = | 288 | + TransactionalMap<ResourcePath.Discrete, ResourceConsumer> discreteConsumerTxMap = |
222 | - tx.getTransactionalMap(CONSUMER_MAP, SERIALIZER); | 289 | + tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); |
290 | + TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = | ||
291 | + tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); | ||
223 | Iterator<ResourcePath> resourceIte = resources.iterator(); | 292 | Iterator<ResourcePath> resourceIte = resources.iterator(); |
224 | Iterator<ResourceConsumer> consumerIte = consumers.iterator(); | 293 | Iterator<ResourceConsumer> consumerIte = consumers.iterator(); |
225 | 294 | ||
... | @@ -227,33 +296,76 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -227,33 +296,76 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
227 | ResourcePath resource = resourceIte.next(); | 296 | ResourcePath resource = resourceIte.next(); |
228 | ResourceConsumer consumer = consumerIte.next(); | 297 | ResourceConsumer consumer = consumerIte.next(); |
229 | 298 | ||
299 | + if (resource instanceof ResourcePath.Discrete) { | ||
230 | // if this single release fails (because the resource is allocated to another consumer, | 300 | // if this single release fails (because the resource is allocated to another consumer, |
231 | // the whole release fails | 301 | // the whole release fails |
232 | - if (!consumerTxMap.remove(resource, consumer)) { | 302 | + if (!discreteConsumerTxMap.remove((ResourcePath.Discrete) resource, consumer)) { |
233 | return abortTransaction(tx); | 303 | return abortTransaction(tx); |
234 | } | 304 | } |
305 | + } else if (resource instanceof ResourcePath.Continuous) { | ||
306 | + ResourcePath.Continuous continuous = (ResourcePath.Continuous) resource; | ||
307 | + ContinuousResourceAllocation allocation = continuousConsumerTxMap.get(continuous.id()); | ||
308 | + ImmutableList<ResourceAllocation> newAllocations = allocation.allocations().stream() | ||
309 | + .filter(x -> !(x.consumer().equals(consumer) && | ||
310 | + ((ResourcePath.Continuous) x.resource()).value() == continuous.value())) | ||
311 | + .collect(GuavaCollectors.toImmutableList()); | ||
312 | + | ||
313 | + if (!continuousConsumerTxMap.replace(continuous.id(), allocation, | ||
314 | + new ContinuousResourceAllocation(allocation.original(), newAllocations))) { | ||
315 | + return abortTransaction(tx); | ||
316 | + } | ||
317 | + } | ||
235 | } | 318 | } |
236 | 319 | ||
237 | return tx.commit(); | 320 | return tx.commit(); |
238 | } | 321 | } |
239 | 322 | ||
240 | @Override | 323 | @Override |
324 | + public boolean isAvailable(ResourcePath resource) { | ||
325 | + checkNotNull(resource); | ||
326 | + checkArgument(resource instanceof ResourcePath.Discrete || resource instanceof ResourcePath.Continuous); | ||
327 | + | ||
328 | + if (resource instanceof ResourcePath.Discrete) { | ||
329 | + return getConsumer((ResourcePath.Discrete) resource).isEmpty(); | ||
330 | + } else { | ||
331 | + return isAvailable((ResourcePath.Continuous) resource); | ||
332 | + } | ||
333 | + } | ||
334 | + | ||
335 | + private boolean isAvailable(ResourcePath.Continuous resource) { | ||
336 | + Versioned<ContinuousResourceAllocation> allocation = continuousConsumers.get(resource.id()); | ||
337 | + if (allocation == null) { | ||
338 | + return false; | ||
339 | + } | ||
340 | + | ||
341 | + return hasEnoughResource(allocation.value().original(), resource, allocation.value()); | ||
342 | + } | ||
343 | + | ||
344 | + @Override | ||
241 | public Collection<ResourcePath> getResources(ResourceConsumer consumer) { | 345 | public Collection<ResourcePath> getResources(ResourceConsumer consumer) { |
242 | checkNotNull(consumer); | 346 | checkNotNull(consumer); |
243 | 347 | ||
244 | // NOTE: getting all entries may become performance bottleneck | 348 | // NOTE: getting all entries may become performance bottleneck |
245 | // TODO: revisit for better backend data structure | 349 | // TODO: revisit for better backend data structure |
246 | - return consumerMap.entrySet().stream() | 350 | + Stream<ResourcePath.Discrete> discreteStream = discreteConsumers.entrySet().stream() |
247 | .filter(x -> x.getValue().value().equals(consumer)) | 351 | .filter(x -> x.getValue().value().equals(consumer)) |
248 | - .map(Map.Entry::getKey) | 352 | + .map(Map.Entry::getKey); |
249 | - .collect(Collectors.toList()); | 353 | + |
354 | + Stream<ResourcePath.Continuous> continuousStream = continuousConsumers.values().stream() | ||
355 | + .flatMap(x -> x.value().allocations().stream() | ||
356 | + .map(y -> Maps.immutableEntry(x.value().original(), y))) | ||
357 | + .filter(x -> x.getValue().consumer().equals(consumer)) | ||
358 | + .map(x -> x.getKey()); | ||
359 | + | ||
360 | + return Stream.concat(discreteStream, continuousStream).collect(Collectors.toList()); | ||
250 | } | 361 | } |
251 | 362 | ||
252 | @Override | 363 | @Override |
253 | public Collection<ResourcePath> getChildResources(ResourcePath parent) { | 364 | public Collection<ResourcePath> getChildResources(ResourcePath parent) { |
254 | checkNotNull(parent); | 365 | checkNotNull(parent); |
366 | + checkArgument(parent instanceof ResourcePath.Discrete); | ||
255 | 367 | ||
256 | - Versioned<List<ResourcePath>> children = childMap.get(parent); | 368 | + Versioned<Set<ResourcePath>> children = childMap.get((ResourcePath.Discrete) parent); |
257 | if (children == null) { | 369 | if (children == null) { |
258 | return Collections.emptyList(); | 370 | return Collections.emptyList(); |
259 | } | 371 | } |
... | @@ -265,16 +377,28 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -265,16 +377,28 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
265 | public <T> Collection<ResourcePath> getAllocatedResources(ResourcePath parent, Class<T> cls) { | 377 | public <T> Collection<ResourcePath> getAllocatedResources(ResourcePath parent, Class<T> cls) { |
266 | checkNotNull(parent); | 378 | checkNotNull(parent); |
267 | checkNotNull(cls); | 379 | checkNotNull(cls); |
380 | + checkArgument(parent instanceof ResourcePath.Discrete); | ||
268 | 381 | ||
269 | - Versioned<List<ResourcePath>> children = childMap.get(parent); | 382 | + Versioned<Set<ResourcePath>> children = childMap.get((ResourcePath.Discrete) parent); |
270 | if (children == null) { | 383 | if (children == null) { |
271 | return Collections.emptyList(); | 384 | return Collections.emptyList(); |
272 | } | 385 | } |
273 | 386 | ||
274 | - return children.value().stream() | 387 | + Stream<ResourcePath.Discrete> discrete = children.value().stream() |
275 | .filter(x -> x.last().getClass().equals(cls)) | 388 | .filter(x -> x.last().getClass().equals(cls)) |
276 | - .filter(consumerMap::containsKey) | 389 | + .filter(x -> x instanceof ResourcePath.Discrete) |
277 | - .collect(Collectors.toList()); | 390 | + .map(x -> (ResourcePath.Discrete) x) |
391 | + .filter(discreteConsumers::containsKey); | ||
392 | + | ||
393 | + Stream<ResourcePath.Continuous> continuous = children.value().stream() | ||
394 | + .filter(x -> x.last().getClass().equals(cls)) | ||
395 | + .filter(x -> x instanceof ResourcePath.Continuous) | ||
396 | + .map(x -> (ResourcePath.Continuous) x) | ||
397 | + .filter(x -> continuousConsumers.containsKey(x.id())) | ||
398 | + .filter(x -> continuousConsumers.get(x.id()) != null) | ||
399 | + .filter(x -> !continuousConsumers.get(x.id()).value().allocations().isEmpty()); | ||
400 | + | ||
401 | + return Stream.concat(discrete, continuous).collect(Collectors.toList()); | ||
278 | } | 402 | } |
279 | 403 | ||
280 | /** | 404 | /** |
... | @@ -288,6 +412,27 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -288,6 +412,27 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
288 | return false; | 412 | return false; |
289 | } | 413 | } |
290 | 414 | ||
415 | + // Appends the specified ResourceAllocation to the existing values stored in the map | ||
416 | + private boolean appendValue(TransactionalMap<ResourceId, ContinuousResourceAllocation> map, | ||
417 | + ResourcePath.Continuous original, ResourceAllocation value) { | ||
418 | + ContinuousResourceAllocation oldValue = map.putIfAbsent(original.id(), | ||
419 | + new ContinuousResourceAllocation(original, ImmutableList.of(value))); | ||
420 | + if (oldValue == null) { | ||
421 | + return true; | ||
422 | + } | ||
423 | + | ||
424 | + if (oldValue.allocations().contains(value)) { | ||
425 | + // don't write to map because all values are already stored | ||
426 | + return true; | ||
427 | + } | ||
428 | + | ||
429 | + ContinuousResourceAllocation newValue = new ContinuousResourceAllocation(original, | ||
430 | + ImmutableList.<ResourceAllocation>builder() | ||
431 | + .addAll(oldValue.allocations()) | ||
432 | + .add(value) | ||
433 | + .build()); | ||
434 | + return map.replace(original.id(), oldValue, newValue); | ||
435 | + } | ||
291 | /** | 436 | /** |
292 | * Appends the values to the existing values associated with the specified key. | 437 | * Appends the values to the existing values associated with the specified key. |
293 | * If the map already has all the given values, appending will not happen. | 438 | * If the map already has all the given values, appending will not happen. |
... | @@ -299,20 +444,20 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -299,20 +444,20 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
299 | * @param <V> type of the element of the list | 444 | * @param <V> type of the element of the list |
300 | * @return true if the operation succeeds, false otherwise. | 445 | * @return true if the operation succeeds, false otherwise. |
301 | */ | 446 | */ |
302 | - private <K, V> boolean appendValues(TransactionalMap<K, List<V>> map, K key, List<V> values) { | 447 | + private <K, V> boolean appendValues(TransactionalMap<K, Set<V>> map, K key, List<V> values) { |
303 | - List<V> oldValues = map.putIfAbsent(key, new ArrayList<>(values)); | 448 | + Set<V> oldValues = map.putIfAbsent(key, new LinkedHashSet<>(values)); |
304 | if (oldValues == null) { | 449 | if (oldValues == null) { |
305 | return true; | 450 | return true; |
306 | } | 451 | } |
307 | 452 | ||
308 | - LinkedHashSet<V> oldSet = new LinkedHashSet<>(oldValues); | 453 | + if (oldValues.containsAll(values)) { |
309 | - if (oldSet.containsAll(values)) { | ||
310 | // don't write to map because all values are already stored | 454 | // don't write to map because all values are already stored |
311 | return true; | 455 | return true; |
312 | } | 456 | } |
313 | 457 | ||
314 | - oldSet.addAll(values); | 458 | + LinkedHashSet<V> newValues = new LinkedHashSet<>(oldValues); |
315 | - return map.replace(key, oldValues, new ArrayList<>(oldSet)); | 459 | + newValues.addAll(values); |
460 | + return map.replace(key, oldValues, newValues); | ||
316 | } | 461 | } |
317 | 462 | ||
318 | /** | 463 | /** |
... | @@ -326,37 +471,93 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour | ... | @@ -326,37 +471,93 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour |
326 | * @param <V> type of the element of the list | 471 | * @param <V> type of the element of the list |
327 | * @return true if the operation succeeds, false otherwise | 472 | * @return true if the operation succeeds, false otherwise |
328 | */ | 473 | */ |
329 | - private <K, V> boolean removeValues(TransactionalMap<K, List<V>> map, K key, List<V> values) { | 474 | + private <K, V> boolean removeValues(TransactionalMap<K, Set<V>> map, K key, List<? extends V> values) { |
330 | - List<V> oldValues = map.get(key); | 475 | + Set<V> oldValues = map.putIfAbsent(key, new LinkedHashSet<>()); |
331 | if (oldValues == null) { | 476 | if (oldValues == null) { |
332 | - map.put(key, new ArrayList<>()); | ||
333 | return true; | 477 | return true; |
334 | } | 478 | } |
335 | 479 | ||
336 | - LinkedHashSet<V> oldSet = new LinkedHashSet<>(oldValues); | 480 | + if (values.stream().allMatch(x -> !oldValues.contains(x))) { |
337 | - if (values.stream().allMatch(x -> !oldSet.contains(x))) { | ||
338 | // don't write map because none of the values are stored | 481 | // don't write map because none of the values are stored |
339 | return true; | 482 | return true; |
340 | } | 483 | } |
341 | 484 | ||
342 | - oldSet.removeAll(values); | 485 | + LinkedHashSet<V> newValues = new LinkedHashSet<>(oldValues); |
343 | - return map.replace(key, oldValues, new ArrayList<>(oldSet)); | 486 | + newValues.removeAll(values); |
487 | + return map.replace(key, oldValues, newValues); | ||
344 | } | 488 | } |
345 | 489 | ||
346 | /** | 490 | /** |
347 | - * Checks if the specified resource is registered as a child of a resource in the map. | 491 | + * Returns the resource which has the same key as the key of the specified resource |
492 | + * in the list as a value of the map. | ||
348 | * | 493 | * |
349 | * @param map map storing parent - child relationship of resources | 494 | * @param map map storing parent - child relationship of resources |
350 | - * @param resource resource to be checked | 495 | + * @param resource resource to be checked for its key |
351 | - * @return true if the resource is registered, false otherwise. | 496 | + * @return the resource which is regarded as the same as the specified resource |
352 | */ | 497 | */ |
353 | - private boolean isRegistered(TransactionalMap<ResourcePath, List<ResourcePath>> map, ResourcePath resource) { | 498 | + // Naive implementation, which traverses all elements in the list |
354 | - // root is always regarded to be registered | 499 | + private <T extends ResourcePath> Optional<T> lookup( |
500 | + TransactionalMap<ResourcePath.Discrete, Set<ResourcePath>> map, T resource) { | ||
501 | + // if it is root, always returns itself | ||
355 | if (!resource.parent().isPresent()) { | 502 | if (!resource.parent().isPresent()) { |
356 | - return true; | 503 | + return Optional.of(resource); |
357 | } | 504 | } |
358 | 505 | ||
359 | - List<ResourcePath> value = map.get(resource.parent().get()); | 506 | + Set<ResourcePath> values = map.get(resource.parent().get()); |
360 | - return value != null && value.contains(resource); | 507 | + if (values == null) { |
508 | + return Optional.empty(); | ||
509 | + } | ||
510 | + | ||
511 | + @SuppressWarnings("unchecked") | ||
512 | + Optional<T> result = values.stream() | ||
513 | + .filter(x -> x.id().equals(resource.id())) | ||
514 | + .map(x -> (T) x) | ||
515 | + .findFirst(); | ||
516 | + return result; | ||
517 | + } | ||
518 | + | ||
519 | + /** | ||
520 | + * Checks if there is enough resource volume to allocated the requested resource | ||
521 | + * against the specified resource. | ||
522 | + * | ||
523 | + * @param original original resource | ||
524 | + * @param request requested resource | ||
525 | + * @param allocation current allocation of the resource | ||
526 | + * @return true if there is enough resource volume. Otherwise, false. | ||
527 | + */ | ||
528 | + private boolean hasEnoughResource(ResourcePath.Continuous original, | ||
529 | + ResourcePath.Continuous request, | ||
530 | + ContinuousResourceAllocation allocation) { | ||
531 | + if (allocation == null) { | ||
532 | + return request.value() <= original.value(); | ||
533 | + } | ||
534 | + | ||
535 | + double allocated = allocation.allocations().stream() | ||
536 | + .filter(x -> x.resource() instanceof ResourcePath.Continuous) | ||
537 | + .map(x -> (ResourcePath.Continuous) x.resource()) | ||
538 | + .mapToDouble(ResourcePath.Continuous::value) | ||
539 | + .sum(); | ||
540 | + double left = original.value() - allocated; | ||
541 | + return request.value() <= left; | ||
542 | + } | ||
543 | + | ||
544 | + // internal use only | ||
545 | + private static final class ContinuousResourceAllocation { | ||
546 | + private final ResourcePath.Continuous original; | ||
547 | + private final ImmutableList<ResourceAllocation> allocations; | ||
548 | + | ||
549 | + private ContinuousResourceAllocation(ResourcePath.Continuous original, | ||
550 | + ImmutableList<ResourceAllocation> allocations) { | ||
551 | + this.original = original; | ||
552 | + this.allocations = allocations; | ||
553 | + } | ||
554 | + | ||
555 | + private ResourcePath.Continuous original() { | ||
556 | + return original; | ||
557 | + } | ||
558 | + | ||
559 | + private ImmutableList<ResourceAllocation> allocations() { | ||
560 | + return allocations; | ||
561 | + } | ||
361 | } | 562 | } |
362 | } | 563 | } | ... | ... |
... | @@ -204,6 +204,7 @@ import java.util.Arrays; | ... | @@ -204,6 +204,7 @@ import java.util.Arrays; |
204 | import java.util.Collections; | 204 | import java.util.Collections; |
205 | import java.util.HashMap; | 205 | import java.util.HashMap; |
206 | import java.util.HashSet; | 206 | import java.util.HashSet; |
207 | +import java.util.LinkedHashSet; | ||
207 | import java.util.LinkedList; | 208 | import java.util.LinkedList; |
208 | import java.util.Optional; | 209 | import java.util.Optional; |
209 | import java.util.concurrent.ConcurrentHashMap; | 210 | import java.util.concurrent.ConcurrentHashMap; |
... | @@ -239,7 +240,8 @@ public final class KryoNamespaces { | ... | @@ -239,7 +240,8 @@ public final class KryoNamespaces { |
239 | .register(CopyOnWriteArraySet.class) | 240 | .register(CopyOnWriteArraySet.class) |
240 | .register(ArrayList.class, | 241 | .register(ArrayList.class, |
241 | LinkedList.class, | 242 | LinkedList.class, |
242 | - HashSet.class | 243 | + HashSet.class, |
244 | + LinkedHashSet.class | ||
243 | ) | 245 | ) |
244 | .register(Maps.immutableEntry("a", "b").getClass()) | 246 | .register(Maps.immutableEntry("a", "b").getClass()) |
245 | .register(new ArraysAsListSerializer(), Arrays.asList().getClass()) | 247 | .register(new ArraysAsListSerializer(), Arrays.asList().getClass()) | ... | ... |
-
Please register or login to post a comment