blob: 70c9b5be3efe5c2770ae8a001b06de6d7267070a [file] [log] [blame]
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -07003 *
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 */
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080016package org.onosproject.store.resource.impl;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070017
18import com.google.common.annotations.Beta;
Sho SHIMIZU83258ae2016-01-29 17:39:07 -080019import com.google.common.collect.ImmutableSet;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
Sho SHIMIZU65de9612016-05-19 12:24:20 -070025import org.onlab.util.KryoNamespace;
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -070026import org.onlab.util.Tools;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080027import org.onosproject.net.resource.ContinuousResource;
28import org.onosproject.net.resource.ContinuousResourceId;
29import org.onosproject.net.resource.DiscreteResource;
30import org.onosproject.net.resource.DiscreteResourceId;
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070031import org.onosproject.net.resource.Resource;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080032import org.onosproject.net.resource.ResourceAllocation;
33import org.onosproject.net.resource.ResourceConsumer;
Naoki Shiotabd1974c2016-04-29 18:44:17 -070034import org.onosproject.net.resource.ResourceConsumerId;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080035import org.onosproject.net.resource.ResourceEvent;
36import org.onosproject.net.resource.ResourceId;
Sho SHIMIZUe18cb122016-02-22 21:04:56 -080037import org.onosproject.net.resource.ResourceStore;
38import org.onosproject.net.resource.ResourceStoreDelegate;
39import org.onosproject.net.resource.Resources;
Sho SHIMIZUfa62b472015-11-02 17:35:46 -080040import org.onosproject.store.AbstractStore;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070041import org.onosproject.store.serializers.KryoNamespaces;
Madan Jampani3780d4b2016-04-04 18:18:24 -070042import org.onosproject.store.service.CommitStatus;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070043import org.onosproject.store.service.Serializer;
44import org.onosproject.store.service.StorageService;
45import org.onosproject.store.service.TransactionContext;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070046import org.slf4j.Logger;
47import org.slf4j.LoggerFactory;
48
49import java.util.Collection;
Sho SHIMIZU69420fe2016-02-09 15:01:07 -080050import java.util.LinkedHashMap;
Sho SHIMIZU34847b72016-06-07 14:31:54 -070051import java.util.LinkedHashSet;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070052import java.util.List;
53import java.util.Map;
54import java.util.Optional;
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -080055import java.util.Set;
Sho SHIMIZU61936212017-01-09 17:50:56 -080056import java.util.function.Function;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070057import java.util.stream.Collectors;
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -080058import java.util.stream.Stream;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070059
60import static com.google.common.base.Preconditions.checkArgument;
61import static com.google.common.base.Preconditions.checkNotNull;
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070062import static org.onosproject.net.resource.ResourceEvent.Type.RESOURCE_ADDED;
63import static org.onosproject.net.resource.ResourceEvent.Type.RESOURCE_REMOVED;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070064
65/**
66 * Implementation of ResourceStore using TransactionalMap.
67 */
Sho SHIMIZU9a2b8292015-10-28 13:00:16 -070068@Component(immediate = true)
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070069@Service
70@Beta
Sho SHIMIZUfa62b472015-11-02 17:35:46 -080071public class ConsistentResourceStore extends AbstractStore<ResourceEvent, ResourceStoreDelegate>
72 implements ResourceStore {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070073 private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class);
74
Sho SHIMIZU65de9612016-05-19 12:24:20 -070075 static final Serializer SERIALIZER = Serializer.using(KryoNamespace.newBuilder()
76 .register(KryoNamespaces.API)
77 .register(UnifiedDiscreteResources.class)
78 .register(new EncodableDiscreteResourcesSerializer(), EncodableDiscreteResources.class)
Sho SHIMIZUf503a622016-05-25 11:12:23 -070079 .register(GenericDiscreteResources.class)
Sho SHIMIZU65de9612016-05-19 12:24:20 -070080 .register(EmptyDiscreteResources.class)
Sho SHIMIZU2795d632016-05-25 14:10:13 -070081 .register(new EncodedResourcesSerializer(), EncodedDiscreteResources.class)
Sho SHIMIZU65de9612016-05-19 12:24:20 -070082 .register(ContinuousResourceAllocation.class)
Sho SHIMIZU9db6da62016-06-01 12:31:21 -070083 .register(PortNumberCodec.class)
Sho SHIMIZU59512bf2016-06-01 11:30:58 -070084 .register(VlanIdCodec.class)
85 .register(MplsLabelCodec.class)
Sho SHIMIZU65de9612016-05-19 12:24:20 -070086 .build());
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070087
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected StorageService service;
90
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -070091 private ConsistentDiscreteResourceSubStore discreteStore;
92 private ConsistentContinuousResourceSubStore continuousStore;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070093
94 @Activate
95 public void activate() {
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -070096 discreteStore = new ConsistentDiscreteResourceSubStore(service);
97 continuousStore = new ConsistentContinuousResourceSubStore(service);
Sho SHIMIZUe7db6142015-11-04 11:24:22 -080098
Madan Jampanic7f49f92015-12-10 11:35:06 -080099 log.info("Started");
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700100 }
101
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800102 // Computational complexity: O(1) if the resource is discrete type.
103 // O(n) if the resource is continuous type where n is the number of the existing allocations for the resource
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700104 @Override
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800105 public List<ResourceAllocation> getResourceAllocations(ResourceId id) {
106 checkNotNull(id);
107 checkArgument(id instanceof DiscreteResourceId || id instanceof ContinuousResourceId);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700108
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800109 if (id instanceof DiscreteResourceId) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700110 return discreteStore.getResourceAllocations((DiscreteResourceId) id);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800111 } else {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700112 return continuousStore.getResourceAllocations((ContinuousResourceId) id);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800113 }
114 }
115
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700116 @Override
Sho SHIMIZUef835c92016-08-08 13:51:17 -0700117 public boolean register(List<? extends Resource> resources) {
Sho SHIMIZU83e17a02015-08-20 14:07:05 -0700118 checkNotNull(resources);
HIGUCHI Yuta6f828c32016-01-20 18:11:05 -0800119 if (log.isTraceEnabled()) {
120 resources.forEach(r -> log.trace("registering {}", r));
121 }
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700122
123 TransactionContext tx = service.transactionContextBuilder().build();
124 tx.begin();
125
Sho SHIMIZU69420fe2016-02-09 15:01:07 -0800126 // the order is preserved by LinkedHashMap
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800127 Map<DiscreteResource, List<Resource>> resourceMap = resources.stream()
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800128 .filter(x -> x.parent().isPresent())
Sho SHIMIZU69420fe2016-02-09 15:01:07 -0800129 .collect(Collectors.groupingBy(x -> x.parent().get(), LinkedHashMap::new, Collectors.toList()));
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700130
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700131 TransactionalDiscreteResourceSubStore discreteTxStore = discreteStore.transactional(tx);
132 TransactionalContinuousResourceSubStore continuousTxStore = continuousStore.transactional(tx);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700133 for (Map.Entry<DiscreteResource, List<Resource>> entry : resourceMap.entrySet()) {
Sho SHIMIZU001e3f22016-05-06 14:46:15 -0700134 DiscreteResourceId parentId = entry.getKey().id();
Sho SHIMIZUd66148a2016-05-06 14:47:47 -0700135 if (!discreteTxStore.lookup(parentId).isPresent()) {
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800136 return abortTransaction(tx);
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700137 }
138
Sho SHIMIZUa2d99eb2016-05-06 14:52:55 -0700139 if (!register(discreteTxStore, continuousTxStore, parentId, entry.getValue())) {
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800140 return abortTransaction(tx);
141 }
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700142 }
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800143
Madan Jampani3780d4b2016-04-04 18:18:24 -0700144 return tx.commit().whenComplete((status, error) -> {
145 if (status == CommitStatus.SUCCESS) {
146 log.trace("Transaction commit succeeded on registration: resources={}", resources);
147 List<ResourceEvent> events = resources.stream()
148 .filter(x -> x.parent().isPresent())
149 .map(x -> new ResourceEvent(RESOURCE_ADDED, x))
150 .collect(Collectors.toList());
151 notifyDelegate(events);
152 } else {
153 log.warn("Transaction commit failed on registration", error);
154 }
155 }).join() == CommitStatus.SUCCESS;
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700156 }
157
158 @Override
Sho SHIMIZUef835c92016-08-08 13:51:17 -0700159 public boolean unregister(List<? extends ResourceId> ids) {
Sho SHIMIZU72f81b12016-02-09 09:26:17 -0800160 checkNotNull(ids);
Sho SHIMIZU2d8a13a2015-08-18 22:37:41 -0700161
162 TransactionContext tx = service.transactionContextBuilder().build();
163 tx.begin();
164
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700165 TransactionalDiscreteResourceSubStore discreteTxStore = discreteStore.transactional(tx);
166 TransactionalContinuousResourceSubStore continuousTxStore = continuousStore.transactional(tx);
Sho SHIMIZU7d54d9c2016-02-17 13:58:46 -0800167 // Look up resources by resource IDs
Sho SHIMIZU72f81b12016-02-09 09:26:17 -0800168 List<Resource> resources = ids.stream()
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800169 .filter(x -> x.parent().isPresent())
Sho SHIMIZU7d54d9c2016-02-17 13:58:46 -0800170 .map(x -> {
171 // avoid access to consistent map in the case of discrete resource
172 if (x instanceof DiscreteResourceId) {
173 return Optional.of(Resources.discrete((DiscreteResourceId) x).resource());
174 } else {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700175 return continuousTxStore.lookup((ContinuousResourceId) x);
Sho SHIMIZU7d54d9c2016-02-17 13:58:46 -0800176 }
177 })
Sho SHIMIZUa4861d42016-05-26 12:25:07 -0700178 .flatMap(Tools::stream)
Sho SHIMIZU72f81b12016-02-09 09:26:17 -0800179 .collect(Collectors.toList());
Sho SHIMIZU69420fe2016-02-09 15:01:07 -0800180 // the order is preserved by LinkedHashMap
Sho SHIMIZU72f81b12016-02-09 09:26:17 -0800181 Map<DiscreteResourceId, List<Resource>> resourceMap = resources.stream()
Sho SHIMIZU69420fe2016-02-09 15:01:07 -0800182 .collect(Collectors.groupingBy(x -> x.parent().get().id(), LinkedHashMap::new, Collectors.toList()));
Sho SHIMIZU83e17a02015-08-20 14:07:05 -0700183
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700184 for (Map.Entry<DiscreteResourceId, List<Resource>> entry : resourceMap.entrySet()) {
Sho SHIMIZUa2d99eb2016-05-06 14:52:55 -0700185 if (!unregister(discreteTxStore, continuousTxStore, entry.getKey(), entry.getValue())) {
HIGUCHI Yuta6acdfd02016-02-18 10:39:43 -0800186 log.warn("Failed to unregister {}: Failed to remove {} values.",
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700187 entry.getKey(), entry.getValue().size());
HIGUCHI Yuta6acdfd02016-02-18 10:39:43 -0800188 log.debug("Failed to unregister {}: Failed to remove values: {}",
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700189 entry.getKey(), entry.getValue());
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800190 return abortTransaction(tx);
191 }
Sho SHIMIZU2d8a13a2015-08-18 22:37:41 -0700192 }
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800193
Madan Jampani3780d4b2016-04-04 18:18:24 -0700194 return tx.commit().whenComplete((status, error) -> {
195 if (status == CommitStatus.SUCCESS) {
196 List<ResourceEvent> events = resources.stream()
197 .filter(x -> x.parent().isPresent())
198 .map(x -> new ResourceEvent(RESOURCE_REMOVED, x))
199 .collect(Collectors.toList());
200 notifyDelegate(events);
201 } else {
Sho SHIMIZU61936212017-01-09 17:50:56 -0800202 String message = resources.stream()
203 .map(Resource::simpleTypeName)
204 .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
205 .entrySet().stream()
206 .map(e -> String.format("%d %s type resources", e.getValue(), e.getKey()))
207 .collect(Collectors.joining(", "));
208 log.warn("Failed to unregister {}: Commit failed.", message, error);
Madan Jampani3780d4b2016-04-04 18:18:24 -0700209 }
210 }).join() == CommitStatus.SUCCESS;
Sho SHIMIZU2d8a13a2015-08-18 22:37:41 -0700211 }
212
213 @Override
Sho SHIMIZUef835c92016-08-08 13:51:17 -0700214 public boolean allocate(List<? extends Resource> resources, ResourceConsumer consumer) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700215 checkNotNull(resources);
216 checkNotNull(consumer);
217
218 TransactionContext tx = service.transactionContextBuilder().build();
219 tx.begin();
220
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700221 TransactionalDiscreteResourceSubStore discreteTxStore = discreteStore.transactional(tx);
222 TransactionalContinuousResourceSubStore continuousTxStore = continuousStore.transactional(tx);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700223 for (Resource resource : resources) {
Sho SHIMIZU171a9382016-02-15 13:56:34 -0800224 if (resource instanceof DiscreteResource) {
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700225 if (!discreteTxStore.allocate(consumer.consumerId(), (DiscreteResource) resource)) {
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800226 return abortTransaction(tx);
227 }
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800228 } else if (resource instanceof ContinuousResource) {
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700229 if (!continuousTxStore.allocate(consumer.consumerId(), (ContinuousResource) resource)) {
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800230 return abortTransaction(tx);
231 }
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800232 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700233 }
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800234
Madan Jampani3780d4b2016-04-04 18:18:24 -0700235 return tx.commit().join() == CommitStatus.SUCCESS;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700236 }
237
238 @Override
Sho SHIMIZUfc64ffe2016-02-10 20:11:09 -0800239 public boolean release(List<ResourceAllocation> allocations) {
240 checkNotNull(allocations);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700241
242 TransactionContext tx = service.transactionContextBuilder().build();
243 tx.begin();
244
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700245 TransactionalDiscreteResourceSubStore discreteTxStore = discreteStore.transactional(tx);
246 TransactionalContinuousResourceSubStore continuousTxStore = continuousStore.transactional(tx);
Sho SHIMIZUfc64ffe2016-02-10 20:11:09 -0800247 for (ResourceAllocation allocation : allocations) {
248 Resource resource = allocation.resource();
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700249 ResourceConsumerId consumerId = allocation.consumerId();
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700250
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800251 if (resource instanceof DiscreteResource) {
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700252 if (!discreteTxStore.release((DiscreteResource) resource, consumerId)) {
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800253 return abortTransaction(tx);
254 }
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800255 } else if (resource instanceof ContinuousResource) {
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700256 if (!continuousTxStore.release((ContinuousResource) resource, consumerId)) {
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800257 return abortTransaction(tx);
258 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700259 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700260 }
Sho SHIMIZU1e0a34c2015-11-02 16:52:29 -0800261
Madan Jampani3780d4b2016-04-04 18:18:24 -0700262 return tx.commit().join() == CommitStatus.SUCCESS;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700263 }
264
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800265 // computational complexity: O(1) if the resource is discrete type.
266 // O(n) if the resource is continuous type where n is the number of the children of
267 // the specified resource's parent
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700268 @Override
Sho SHIMIZU8fa670a2016-01-14 11:17:18 -0800269 public boolean isAvailable(Resource resource) {
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800270 checkNotNull(resource);
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800271 checkArgument(resource instanceof DiscreteResource || resource instanceof ContinuousResource);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800272
Sho SHIMIZUf33b8932016-01-25 18:43:32 -0800273 if (resource instanceof DiscreteResource) {
HIGUCHI Yuta6f828c32016-01-20 18:11:05 -0800274 // check if already consumed
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700275 return discreteStore.isAvailable((DiscreteResource) resource);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800276 } else {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700277 return continuousStore.isAvailable((ContinuousResource) resource);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800278 }
279 }
280
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800281 // computational complexity: O(n + m) where n is the number of entries in discreteConsumers
282 // and m is the number of allocations for all continuous resources
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800283 @Override
Sho SHIMIZU8fa670a2016-01-14 11:17:18 -0800284 public Collection<Resource> getResources(ResourceConsumer consumer) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700285 checkNotNull(consumer);
286
287 // NOTE: getting all entries may become performance bottleneck
288 // TODO: revisit for better backend data structure
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700289 Stream<DiscreteResource> discrete = discreteStore.getResources(consumer.consumerId());
290 Stream<ContinuousResource> continuous = continuousStore.getResources(consumer.consumerId());
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800291
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700292 return Stream.concat(discrete, continuous).collect(Collectors.toList());
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700293 }
294
Sho SHIMIZU82bfe992016-02-10 09:55:32 -0800295 // computational complexity: O(1)
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700296 @Override
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800297 public Set<Resource> getChildResources(DiscreteResourceId parent) {
Sho SHIMIZUe7f4f3f2015-10-13 16:27:25 -0700298 checkNotNull(parent);
299
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700300 return ImmutableSet.<Resource>builder()
301 .addAll(discreteStore.getChildResources(parent))
302 .addAll(continuousStore.getChildResources(parent))
303 .build();
Sho SHIMIZUe7f4f3f2015-10-13 16:27:25 -0700304 }
305
Sho SHIMIZU9cc4a242016-05-26 12:55:35 -0700306 @Override
307 public <T> Set<Resource> getChildResources(DiscreteResourceId parent, Class<T> cls) {
308 checkNotNull(parent);
309 checkNotNull(cls);
310
311 return ImmutableSet.<Resource>builder()
312 .addAll(discreteStore.getChildResources(parent, cls))
313 .addAll(continuousStore.getChildResources(parent, cls))
314 .build();
315 }
316
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800317 // computational complexity: O(n) where n is the number of the children of the parent
Sho SHIMIZUe7f4f3f2015-10-13 16:27:25 -0700318 @Override
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800319 public <T> Collection<Resource> getAllocatedResources(DiscreteResourceId parent, Class<T> cls) {
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700320 checkNotNull(parent);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700321 checkNotNull(cls);
322
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700323 Stream<DiscreteResource> discrete = discreteStore.getAllocatedResources(parent, cls);
324 Stream<ContinuousResource> continuous = continuousStore.getAllocatedResources(parent, cls);
Sho SHIMIZU6c9e33a2016-01-07 18:45:27 -0800325
326 return Stream.concat(discrete, continuous).collect(Collectors.toList());
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700327 }
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700328
329 /**
330 * Abort the transaction.
331 *
332 * @param tx transaction context
333 * @return always false
334 */
335 private boolean abortTransaction(TransactionContext tx) {
336 tx.abort();
337 return false;
338 }
339
340 /**
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700341 * Appends the values to the existing values associated with the specified key.
Sho SHIMIZU4568c412015-08-21 16:39:07 -0700342 * If the map already has all the given values, appending will not happen.
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700343 *
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700344 * @param parent resource ID of the parent under which the given resources are registered
345 * @param resources resources to be registered
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700346 * @return true if the operation succeeds, false otherwise.
347 */
Sho SHIMIZUdd3750c2016-02-01 11:37:04 -0800348 // computational complexity: O(n) where n is the number of the specified value
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700349 private boolean register(TransactionalDiscreteResourceSubStore discreteTxStore,
350 TransactionalContinuousResourceSubStore continuousTxStore,
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700351 DiscreteResourceId parent, List<Resource> resources) {
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700352 // it's assumed that the passed "values" is non-empty
353
354 // This is 2-pass scan. Nicer to have 1-pass scan
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700355 Set<DiscreteResource> discreteResources = resources.stream()
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700356 .filter(x -> x instanceof DiscreteResource)
357 .map(x -> (DiscreteResource) x)
Sho SHIMIZU34847b72016-06-07 14:31:54 -0700358 .collect(Collectors.toCollection(LinkedHashSet::new));
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700359 Set<ContinuousResource> continuousResources = resources.stream()
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700360 .filter(x -> x instanceof ContinuousResource)
361 .map(x -> (ContinuousResource) x)
Sho SHIMIZU34847b72016-06-07 14:31:54 -0700362 .collect(Collectors.toCollection(LinkedHashSet::new));
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700363
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700364 return discreteTxStore.register(parent, discreteResources)
365 && continuousTxStore.register(parent, continuousResources);
Sho SHIMIZUba41fc12015-08-12 15:43:22 -0700366 }
367
368 /**
Sho SHIMIZUba1f83b2015-10-14 08:11:20 -0700369 * Removes the values from the existing values associated with the specified key.
Sho SHIMIZU5618ee52015-08-21 17:19:44 -0700370 * If the map doesn't contain the given values, removal will not happen.
Sho SHIMIZU2d8a13a2015-08-18 22:37:41 -0700371 *
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700372 * @param discreteTxStore map holding multiple discrete resources for a key
373 * @param continuousTxStore map holding multiple continuous resources for a key
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700374 * @param parent resource ID of the parent under which the given resources are unregistered
375 * @param resources resources to be unregistered
Sho SHIMIZU2d8a13a2015-08-18 22:37:41 -0700376 * @return true if the operation succeeds, false otherwise
377 */
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -0700378 private boolean unregister(TransactionalDiscreteResourceSubStore discreteTxStore,
379 TransactionalContinuousResourceSubStore continuousTxStore,
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700380 DiscreteResourceId parent, List<Resource> resources) {
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700381 // it's assumed that the passed "values" is non-empty
382
383 // This is 2-pass scan. Nicer to have 1-pass scan
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700384 Set<DiscreteResource> discreteResources = resources.stream()
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700385 .filter(x -> x instanceof DiscreteResource)
386 .map(x -> (DiscreteResource) x)
Sho SHIMIZU34847b72016-06-07 14:31:54 -0700387 .collect(Collectors.toCollection(LinkedHashSet::new));
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700388 Set<ContinuousResource> continuousResources = resources.stream()
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700389 .filter(x -> x instanceof ContinuousResource)
390 .map(x -> (ContinuousResource) x)
Sho SHIMIZU34847b72016-06-07 14:31:54 -0700391 .collect(Collectors.toCollection(LinkedHashSet::new));
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700392
Sho SHIMIZU0b4e9dd2016-06-28 17:42:05 -0700393 return discreteTxStore.unregister(parent, discreteResources)
394 && continuousTxStore.unregister(parent, continuousResources);
Sho SHIMIZU03be2662016-05-04 09:38:45 -0700395 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700396}