blob: 9c88c54b4e26616fcab5bde91b10c76c1b221484 [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;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070024import org.onosproject.net.newresource.ResourceConsumer;
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070025import org.onosproject.net.newresource.ResourcePath;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070026import 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
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070063 private ConsistentMap<ResourcePath, ResourceConsumer> consumers;
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070064
65 @Activate
66 public void activate() {
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070067 consumers = service.<ResourcePath, ResourceConsumer>consistentMapBuilder()
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070068 .withName(MAP_NAME)
69 .withSerializer(SERIALIZER)
70 .build();
71 }
72
73 @Override
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070074 public Optional<ResourceConsumer> getConsumer(ResourcePath resource) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070075 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
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070086 public boolean allocate(List<ResourcePath> resources, ResourceConsumer consumer) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070087 checkNotNull(resources);
88 checkNotNull(consumer);
89
90 TransactionContext tx = service.transactionContextBuilder().build();
91 tx.begin();
92
93 try {
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -070094 TransactionalMap<ResourcePath, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
95 for (ResourcePath resource: resources) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -070096 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
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700111 public boolean release(List<ResourcePath> resources, List<ResourceConsumer> consumers) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700112 checkNotNull(resources);
113 checkNotNull(consumers);
114 checkArgument(resources.size() == consumers.size());
115
116 TransactionContext tx = service.transactionContextBuilder().build();
117 tx.begin();
118
119 try {
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700120 TransactionalMap<ResourcePath, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
121 Iterator<ResourcePath> resourceIte = resources.iterator();
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700122 Iterator<ResourceConsumer> consumerIte = consumers.iterator();
123
124 while (resourceIte.hasNext() && consumerIte.hasNext()) {
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700125 ResourcePath resource = resourceIte.next();
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700126 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
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700143 public Collection<ResourcePath> getResources(ResourceConsumer consumer) {
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700144 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
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700154 @Override
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700155 public <T> Collection<ResourcePath> getAllocatedResources(ResourcePath parent, Class<T> cls) {
156 checkNotNull(parent);
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700157 checkNotNull(cls);
158
159 // NOTE: getting all entries may become performance bottleneck
160 // TODO: revisit for better backend data structure
161 return consumers.entrySet().stream()
Sho SHIMIZU1f5e5912015-08-10 17:00:00 -0700162 .filter(x -> x.getKey().parent().isPresent() && x.getKey().parent().get().equals(parent))
163 .filter(x -> x.getKey().lastComponent().getClass() == cls)
164 .map(Map.Entry::getKey)
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700165 .collect(Collectors.toList());
166 }
Sho SHIMIZUd29847f2015-08-13 09:10:59 -0700167
168 /**
169 * Abort the transaction.
170 *
171 * @param tx transaction context
172 * @return always false
173 */
174 private boolean abortTransaction(TransactionContext tx) {
175 tx.abort();
176 return false;
177 }
178
179 /**
180 * Commit the transaction.
181 *
182 * @param tx transaction context
183 * @return always true
184 */
185 private boolean commitTransaction(TransactionContext tx) {
186 tx.commit();
187 return true;
188 }
Sho SHIMIZU78ee25c2015-07-16 15:54:14 -0700189}