blob: 1f51f7b9f9a4f88a60805b2f979f0121b7bdb558 [file] [log] [blame]
Sho SHIMIZU22fb2832016-05-06 11:44:03 -07001/*
2 * Copyright 2016-present 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.resource.impl;
17
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070018import org.onosproject.net.resource.DiscreteResource;
19import org.onosproject.net.resource.DiscreteResourceId;
20import org.onosproject.net.resource.Resource;
Naoki Shiotabd1974c2016-04-29 18:44:17 -070021import org.onosproject.net.resource.ResourceConsumerId;
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070022import org.onosproject.store.service.TransactionContext;
23import org.onosproject.store.service.TransactionalMap;
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070027import java.util.Optional;
Sho SHIMIZU34847b72016-06-07 14:31:54 -070028import java.util.Set;
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070029
30import static org.onosproject.store.resource.impl.ConsistentResourceStore.SERIALIZER;
31
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -070032class TransactionalDiscreteResourceSubStore {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070033 private final Logger log = LoggerFactory.getLogger(getClass());
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070034 private final TransactionalMap<DiscreteResourceId, DiscreteResources> childMap;
Naoki Shiotabd1974c2016-04-29 18:44:17 -070035 private final TransactionalMap<DiscreteResourceId, ResourceConsumerId> consumers;
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070036
Sho SHIMIZU7ecf5ea2016-05-13 15:28:59 -070037 TransactionalDiscreteResourceSubStore(TransactionContext tx) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070038 this.childMap = tx.getTransactionalMap(MapNames.DISCRETE_CHILD_MAP, SERIALIZER);
39 this.consumers = tx.getTransactionalMap(MapNames.DISCRETE_CONSUMER_MAP, SERIALIZER);
40 }
41
42 // check the existence in the set: O(1) operation
Sho SHIMIZUa81141b2016-05-11 08:05:45 -070043 Optional<DiscreteResource> lookup(DiscreteResourceId id) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070044 if (!id.parent().isPresent()) {
45 return Optional.of(Resource.ROOT);
46 }
47
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070048 DiscreteResources values = childMap.get(id.parent().get());
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070049 if (values == null) {
50 return Optional.empty();
51 }
52
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070053 return values.lookup(id);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070054 }
55
Sho SHIMIZU34847b72016-06-07 14:31:54 -070056 boolean register(DiscreteResourceId key, Set<DiscreteResource> values) {
Sho SHIMIZU1bf46b12016-05-06 15:42:29 -070057 // short-circuit: receiving empty resource is regarded as success
58 if (values.isEmpty()) {
59 return true;
60 }
61
Sho SHIMIZU34847b72016-06-07 14:31:54 -070062 DiscreteResources requested = DiscreteResources.of(values);
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070063 DiscreteResources oldValues = childMap.putIfAbsent(key, requested);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070064 if (oldValues == null) {
65 return true;
66 }
67
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070068 DiscreteResources addedValues = requested.difference(oldValues);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070069 // no new value, then no-op
70 if (addedValues.isEmpty()) {
71 // don't write to map because all values are already stored
72 return true;
73 }
74
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070075 DiscreteResources newValues = oldValues.add(addedValues);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070076 return childMap.replace(key, oldValues, newValues);
77 }
78
Sho SHIMIZU34847b72016-06-07 14:31:54 -070079 boolean unregister(DiscreteResourceId key, Set<DiscreteResource> values) {
Sho SHIMIZU1bf46b12016-05-06 15:42:29 -070080 // short-circuit: receiving empty resource is regarded as success
81 if (values.isEmpty()) {
82 return true;
83 }
84
Sho SHIMIZUc7ffdfe2016-05-06 18:38:41 -070085 // even if one of the resources is allocated to a consumer,
86 // all unregistrations are regarded as failure
87 boolean allocated = values.stream().anyMatch(x -> isAllocated(x.id()));
88 if (allocated) {
89 log.warn("Failed to unregister {}: allocation exists", key);
90 return false;
91 }
92
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070093 DiscreteResources oldValues = childMap.putIfAbsent(key, DiscreteResources.empty());
Sho SHIMIZU22fb2832016-05-06 11:44:03 -070094 if (oldValues == null) {
95 log.trace("No-Op removing values. key {} did not exist", key);
96 return true;
97 }
98
Sho SHIMIZUb85000d2016-05-17 14:00:05 -070099 if (!oldValues.containsAny(values)) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700100 // don't write map because none of the values are stored
101 log.trace("No-Op removing values. key {} did not contain {}", key, values);
102 return true;
103 }
104
Sho SHIMIZU7a6cfdd2016-06-07 15:38:05 -0700105 DiscreteResources requested = DiscreteResources.of(values);
106 DiscreteResources newValues = oldValues.difference(requested);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700107 return childMap.replace(key, oldValues, newValues);
108 }
109
Sho SHIMIZUd82dc5b2016-05-13 13:50:29 -0700110 private boolean isAllocated(DiscreteResourceId id) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700111 return consumers.get(id) != null;
112 }
113
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700114 boolean allocate(ResourceConsumerId consumerId, DiscreteResource resource) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700115 // if the resource is not registered, then abort
Sho SHIMIZUa81141b2016-05-11 08:05:45 -0700116 Optional<DiscreteResource> lookedUp = lookup(resource.id());
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700117 if (!lookedUp.isPresent()) {
118 return false;
119 }
120
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700121 ResourceConsumerId oldValue = consumers.put(resource.id(), consumerId);
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700122 return oldValue == null;
123 }
124
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700125 boolean release(DiscreteResource resource, ResourceConsumerId consumerId) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700126 // if this single release fails (because the resource is allocated to another consumer)
127 // the whole release fails
Naoki Shiotabd1974c2016-04-29 18:44:17 -0700128 if (!consumers.remove(resource.id(), consumerId)) {
Sho SHIMIZU22fb2832016-05-06 11:44:03 -0700129 return false;
130 }
131
132 return true;
133 }
134}