blob: a6921e44cb0870d15a348f0479713cceafad8dfd [file] [log] [blame]
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.store.newresource.impl;
17
18import com.google.common.annotations.Beta;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onosproject.net.newresource.Resource;
25import org.onosproject.net.newresource.ResourceConsumer;
26import org.onosproject.net.newresource.ResourceStore;
27import org.onosproject.store.serializers.KryoNamespaces;
28import org.onosproject.store.service.ConsistentMap;
29import org.onosproject.store.service.Serializer;
30import org.onosproject.store.service.StorageService;
31import org.onosproject.store.service.TransactionContext;
32import org.onosproject.store.service.TransactionException;
33import org.onosproject.store.service.TransactionalMap;
34import org.onosproject.store.service.Versioned;
35import org.slf4j.Logger;
36import org.slf4j.LoggerFactory;
37
38import java.util.Collection;
39import java.util.Iterator;
40import java.util.List;
41import java.util.Map;
42import java.util.Optional;
43import java.util.stream.Collectors;
44
45import static com.google.common.base.Preconditions.checkArgument;
46import static com.google.common.base.Preconditions.checkNotNull;
47
48/**
49 * Implementation of ResourceStore using TransactionalMap.
50 */
51@Component(immediate = true, enabled = false)
52@Service
53@Beta
54public class ConsistentResourceStore implements ResourceStore {
55 private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class);
56
57 private static final String MAP_NAME = "onos-resource-consumers";
58 private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API);
59
60 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 protected StorageService service;
62
63 private ConsistentMap<Resource<?, ?>, ResourceConsumer> consumers;
64
65 @Activate
66 public void activate() {
67 consumers = service.<Resource<?, ?>, ResourceConsumer>consistentMapBuilder()
68 .withName(MAP_NAME)
69 .withSerializer(SERIALIZER)
70 .build();
71 }
72
73 @Override
74 public <S, T> Optional<ResourceConsumer> getConsumer(Resource<S, T> resource) {
75 checkNotNull(resource);
76
77 Versioned<ResourceConsumer> consumer = consumers.get(resource);
78 if (consumer == null) {
79 return Optional.empty();
80 }
81
82 return Optional.of(consumer.value());
83 }
84
85 @Override
86 public boolean allocate(List<? extends Resource<?, ?>> resources, ResourceConsumer consumer) {
87 checkNotNull(resources);
88 checkNotNull(consumer);
89
90 TransactionContext tx = service.transactionContextBuilder().build();
91 tx.begin();
92
93 try {
94 TransactionalMap<Resource<?, ?>, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
95 for (Resource<?, ?> resource: resources) {
96 ResourceConsumer existing = txMap.putIfAbsent(resource, consumer);
97 // if the resource is already allocated to another consumer, the whole allocation fails
98 if (existing != null) {
Sho SHIMIZUd29847f2015-08-13 09:10:59 -070099 return abortTransaction(tx);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700100 }
101 }
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700102
103 return commitTransaction(tx);
Sho SHIMIZU264e4b72015-08-12 12:22:14 -0700104 } catch (TransactionException e) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700105 log.error("Exception thrown, abort the transaction", e);
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700106 return abortTransaction(tx);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700107 }
108 }
109
110 @Override
111 public boolean release(List<? extends Resource<?, ?>> resources, List<ResourceConsumer> consumers) {
112 checkNotNull(resources);
113 checkNotNull(consumers);
114 checkArgument(resources.size() == consumers.size());
115
116 TransactionContext tx = service.transactionContextBuilder().build();
117 tx.begin();
118
119 try {
120 TransactionalMap<Resource<?, ?>, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
121 Iterator<? extends Resource<?, ?>> resourceIte = resources.iterator();
122 Iterator<ResourceConsumer> consumerIte = consumers.iterator();
123
124 while (resourceIte.hasNext() && consumerIte.hasNext()) {
125 Resource<?, ?> resource = resourceIte.next();
126 ResourceConsumer consumer = consumerIte.next();
127
128 // if this single release fails (because the resource is allocated to another consumer,
129 // the whole release fails
130 if (!txMap.remove(resource, consumer)) {
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700131 return abortTransaction(tx);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700132 }
133 }
134
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700135 return commitTransaction(tx);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700136 } catch (TransactionException e) {
137 log.error("Exception thrown, abort the transaction", e);
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700138 return abortTransaction(tx);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700139 }
140 }
141
142 @Override
143 public Collection<Resource<?, ?>> getResources(ResourceConsumer consumer) {
144 checkNotNull(consumer);
145
146 // NOTE: getting all entries may become performance bottleneck
147 // TODO: revisit for better backend data structure
148 return consumers.entrySet().stream()
149 .filter(x -> x.getValue().value().equals(consumer))
150 .map(Map.Entry::getKey)
151 .collect(Collectors.toList());
152 }
153
154 @SuppressWarnings("unchecked")
155 @Override
156 public <S, T> Collection<Resource<S, T>> getAllocatedResources(S subject, Class<T> cls) {
157 checkNotNull(subject);
158 checkNotNull(cls);
159
160 // NOTE: getting all entries may become performance bottleneck
161 // TODO: revisit for better backend data structure
162 return consumers.entrySet().stream()
163 .filter(x -> x.getKey().subject().equals(subject) && x.getKey().resource().getClass() == cls)
164 // cast is ensured by the above filter method
165 .map(x -> (Resource<S, T>) x.getKey())
166 .collect(Collectors.toList());
167 }
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700168
169 /**
170 * Abort the transaction.
171 *
172 * @param tx transaction context
173 * @return always false
174 */
175 private boolean abortTransaction(TransactionContext tx) {
176 tx.abort();
177 return false;
178 }
179
180 /**
181 * Commit the transaction.
182 *
183 * @param tx transaction context
184 * @return always true
185 */
186 private boolean commitTransaction(TransactionContext tx) {
187 tx.commit();
188 return true;
189 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700190}