blob: 03d263788c236a3db1000e7d47ca207865349f7d [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) {
99 tx.abort();
100 return false;
101 }
102 }
103 tx.commit();
104 return true;
105 } catch (Exception e) {
106 log.error("Exception thrown, abort the transaction", e);
107 tx.abort();
108 return false;
109 }
110 }
111
112 @Override
113 public boolean release(List<? extends Resource<?, ?>> resources, List<ResourceConsumer> consumers) {
114 checkNotNull(resources);
115 checkNotNull(consumers);
116 checkArgument(resources.size() == consumers.size());
117
118 TransactionContext tx = service.transactionContextBuilder().build();
119 tx.begin();
120
121 try {
122 TransactionalMap<Resource<?, ?>, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
123 Iterator<? extends Resource<?, ?>> resourceIte = resources.iterator();
124 Iterator<ResourceConsumer> consumerIte = consumers.iterator();
125
126 while (resourceIte.hasNext() && consumerIte.hasNext()) {
127 Resource<?, ?> resource = resourceIte.next();
128 ResourceConsumer consumer = consumerIte.next();
129
130 // if this single release fails (because the resource is allocated to another consumer,
131 // the whole release fails
132 if (!txMap.remove(resource, consumer)) {
133 tx.abort();
134 return false;
135 }
136 }
137
138 return true;
139 } catch (TransactionException e) {
140 log.error("Exception thrown, abort the transaction", e);
141 tx.abort();
142 return false;
143 }
144 }
145
146 @Override
147 public Collection<Resource<?, ?>> getResources(ResourceConsumer consumer) {
148 checkNotNull(consumer);
149
150 // NOTE: getting all entries may become performance bottleneck
151 // TODO: revisit for better backend data structure
152 return consumers.entrySet().stream()
153 .filter(x -> x.getValue().value().equals(consumer))
154 .map(Map.Entry::getKey)
155 .collect(Collectors.toList());
156 }
157
158 @SuppressWarnings("unchecked")
159 @Override
160 public <S, T> Collection<Resource<S, T>> getAllocatedResources(S subject, Class<T> cls) {
161 checkNotNull(subject);
162 checkNotNull(cls);
163
164 // NOTE: getting all entries may become performance bottleneck
165 // TODO: revisit for better backend data structure
166 return consumers.entrySet().stream()
167 .filter(x -> x.getKey().subject().equals(subject) && x.getKey().resource().getClass() == cls)
168 // cast is ensured by the above filter method
169 .map(x -> (Resource<S, T>) x.getKey())
170 .collect(Collectors.toList());
171 }
172}