mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-11-03 09:41:14 +01:00
ONOS-2387: Initial implement ResourceService
The current limitation are - Lack of unit tests for ResourceManager and ConsistentResourceStore - No means to declare the resource space (range) of a resource type - Not taking care of resource hierarchy (dependency) - Lack of automatic resource registration mechanism Change-Id: Ib2d6734de1e498827d6cc11b9d3e224b157a27aa
This commit is contained in:
parent
92ea9b30ee
commit
78ee25ce77
@ -0,0 +1,70 @@
|
|||||||
|
package org.onosproject.net.newresource;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service for storing resource and consumer information.
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
public interface ResourceStore {
|
||||||
|
/**
|
||||||
|
* Allocates the specified resources to the specified consumer in transactional way.
|
||||||
|
* The state after completion of this method is all the resources are allocated to the consumer,
|
||||||
|
* or no resource is allocated to the consumer. The whole allocation fails when any one of
|
||||||
|
* the resource can't be allocated.
|
||||||
|
*
|
||||||
|
* @param resources resources to be allocated
|
||||||
|
* @param consumer resource consumer which the resources are allocated to
|
||||||
|
* @return true if the allocation succeeds, false otherwise.
|
||||||
|
*/
|
||||||
|
boolean allocate(List<? extends Resource<?, ?>> resources, ResourceConsumer consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the specified resources allocated to the specified corresponding consumers
|
||||||
|
* in transactional way. The state after completion of this method is all the resources
|
||||||
|
* are released from the consumer, or no resource is released. The whole release fails
|
||||||
|
* when any one of the resource can't be released. The size of the list of resources and
|
||||||
|
* that of consumers must be equal. The resource and consumer with the same position from
|
||||||
|
* the head of each list correspond to each other.
|
||||||
|
*
|
||||||
|
* @param resources resources to be released
|
||||||
|
* @param consumers resource consumers to whom the resource allocated to
|
||||||
|
* @return true if succeeds, otherwise false
|
||||||
|
*/
|
||||||
|
boolean release(List<? extends Resource<?, ?>> resources, List<ResourceConsumer> consumers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the resource consumer to whom the specified resource is allocated.
|
||||||
|
*
|
||||||
|
* @param resource resource whose allocated consumer to be returned
|
||||||
|
* @param <S> type of subject of the resource
|
||||||
|
* @param <T> type of resource
|
||||||
|
* @return resource consumer who are allocated the resource
|
||||||
|
*/
|
||||||
|
<S, T> Optional<ResourceConsumer> getConsumer(Resource<S, T> resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of the resources allocated to the specified consumer.
|
||||||
|
*
|
||||||
|
* @param consumer resource consumer whose allocated resource are searched for
|
||||||
|
* @return a collection of the resources allocated to the specified consumer
|
||||||
|
*/
|
||||||
|
Collection<Resource<?, ?>> getResources(ResourceConsumer consumer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a collection of the resources which belongs to the specified subject and
|
||||||
|
* whose type is the specified class.
|
||||||
|
*
|
||||||
|
* @param subject subject of the resources to be returned
|
||||||
|
* @param cls class instance of the resources
|
||||||
|
* @param <S> type of the subject
|
||||||
|
* @param <T> type of the resource
|
||||||
|
* @return a collection of the resources which belongs to the specified subject and
|
||||||
|
* whose type is the specified class.
|
||||||
|
*/
|
||||||
|
<S, T> Collection<Resource<S, T>> getAllocatedResources(S subject, Class<T> cls);
|
||||||
|
}
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Open Networking Laboratory
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.onosproject.net.newresource.impl;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import org.apache.felix.scr.annotations.Component;
|
||||||
|
import org.apache.felix.scr.annotations.Reference;
|
||||||
|
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||||
|
import org.apache.felix.scr.annotations.Service;
|
||||||
|
import org.onosproject.net.newresource.DefaultResource;
|
||||||
|
import org.onosproject.net.newresource.DefaultResourceAllocation;
|
||||||
|
import org.onosproject.net.newresource.Resource;
|
||||||
|
import org.onosproject.net.newresource.ResourceAllocation;
|
||||||
|
import org.onosproject.net.newresource.ResourceConsumer;
|
||||||
|
import org.onosproject.net.newresource.ResourceService;
|
||||||
|
import org.onosproject.net.newresource.ResourceStore;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An implementation of ResourceService.
|
||||||
|
*/
|
||||||
|
@Component(immediate = true, enabled = false)
|
||||||
|
@Service
|
||||||
|
@Beta
|
||||||
|
public final class ResourceManager implements ResourceService {
|
||||||
|
|
||||||
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
|
protected ResourceStore store;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <S, T> Optional<ResourceAllocation<S, T>> allocate(ResourceConsumer consumer, Resource<S, T> resource) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
checkNotNull(resource);
|
||||||
|
|
||||||
|
List<ResourceAllocation<?, ?>> allocations = allocate(consumer, ImmutableList.of(resource));
|
||||||
|
if (allocations.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert allocations.size() == 1;
|
||||||
|
|
||||||
|
ResourceAllocation<?, ?> allocation = allocations.get(0);
|
||||||
|
|
||||||
|
assert allocation.subject().getClass() == resource.subject().getClass();
|
||||||
|
assert allocation.resource().getClass() == resource.resource().getClass();
|
||||||
|
|
||||||
|
// cast is ensured by the assertions above
|
||||||
|
return Optional.of((ResourceAllocation<S, T>) allocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceAllocation<?, ?>> allocate(ResourceConsumer consumer,
|
||||||
|
List<? extends Resource<?, ?>> resources) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
checkNotNull(resources);
|
||||||
|
|
||||||
|
if (resources.stream().anyMatch(x -> !isValid(x))) {
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: implement support of resource hierarchy
|
||||||
|
// allocation for a particular resource implies allocations for all of the sub-resources need to be done
|
||||||
|
|
||||||
|
boolean success = store.allocate(resources, consumer);
|
||||||
|
if (!success) {
|
||||||
|
return ImmutableList.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return resources.stream()
|
||||||
|
.map(x -> new DefaultResourceAllocation<>(x.subject(), x.resource(), consumer))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResourceAllocation<?, ?>> allocate(ResourceConsumer consumer, Resource<?, ?>... resources) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
checkNotNull(resources);
|
||||||
|
|
||||||
|
return allocate(consumer, Arrays.asList(resources));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S, T> boolean release(ResourceAllocation<S, T> allocation) {
|
||||||
|
checkNotNull(allocation);
|
||||||
|
|
||||||
|
return release(ImmutableList.of(allocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(List<? extends ResourceAllocation<?, ?>> allocations) {
|
||||||
|
checkNotNull(allocations);
|
||||||
|
|
||||||
|
List<DefaultResource<?, ?>> resources = allocations.stream()
|
||||||
|
.map(x -> new DefaultResource<>(x.subject(), x.resource()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
List<ResourceConsumer> consumers = allocations.stream()
|
||||||
|
.map(ResourceAllocation::consumer)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
return store.release(resources, consumers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(ResourceAllocation<?, ?>... allocations) {
|
||||||
|
checkNotNull(allocations);
|
||||||
|
|
||||||
|
return release(ImmutableList.copyOf(allocations));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(ResourceConsumer consumer) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
|
||||||
|
Collection<ResourceAllocation<?, ?>> allocations = getResourceAllocations(consumer);
|
||||||
|
return release(ImmutableList.copyOf(allocations));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S, T> Collection<ResourceAllocation<S, T>> getResourceAllocations(S subject, Class<T> cls) {
|
||||||
|
checkNotNull(subject);
|
||||||
|
checkNotNull(cls);
|
||||||
|
|
||||||
|
Collection<Resource<S, T>> resources = store.getAllocatedResources(subject, cls);
|
||||||
|
List<ResourceAllocation<S, T>> allocations = new ArrayList<>(resources.size());
|
||||||
|
for (Resource<S, T> resource: resources) {
|
||||||
|
// We access store twice in this method, then the store may be updated by others
|
||||||
|
Optional<ResourceConsumer> consumer = store.getConsumer(resource);
|
||||||
|
if (consumer.isPresent()) {
|
||||||
|
allocations.add(
|
||||||
|
new DefaultResourceAllocation<>(resource.subject(), resource.resource(), consumer.get()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ResourceAllocation<?, ?>> getResourceAllocations(ResourceConsumer consumer) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
|
||||||
|
Collection<Resource<?, ?>> resources = store.getResources(consumer);
|
||||||
|
return resources.stream()
|
||||||
|
.map(x -> new DefaultResourceAllocation<>(x.subject(), x.resource(), consumer))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S, T> boolean isAvailable(Resource<S, T> resource) {
|
||||||
|
checkNotNull(resource);
|
||||||
|
|
||||||
|
Optional<ResourceConsumer> consumer = store.getConsumer(resource);
|
||||||
|
return !consumer.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the specified resource is in the resource range.
|
||||||
|
* E.g. VLAN ID against a link must be within 12 bit address space.
|
||||||
|
*
|
||||||
|
* @param resource resource to be checked if it is within the resource range
|
||||||
|
* @param <S> type of the subject
|
||||||
|
* @param <T> type of the resource
|
||||||
|
* @return true if the resource within the range, false otherwise
|
||||||
|
*/
|
||||||
|
private <S, T> boolean isValid(Resource<S, T> resource) {
|
||||||
|
// TODO: implement
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
172
core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java
vendored
Normal file
172
core/store/dist/src/main/java/org/onosproject/store/newresource/impl/ConsistentResourceStore.java
vendored
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 Open Networking Laboratory
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.onosproject.store.newresource.impl;
|
||||||
|
|
||||||
|
import com.google.common.annotations.Beta;
|
||||||
|
import org.apache.felix.scr.annotations.Activate;
|
||||||
|
import org.apache.felix.scr.annotations.Component;
|
||||||
|
import org.apache.felix.scr.annotations.Reference;
|
||||||
|
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||||
|
import org.apache.felix.scr.annotations.Service;
|
||||||
|
import org.onosproject.net.newresource.Resource;
|
||||||
|
import org.onosproject.net.newresource.ResourceConsumer;
|
||||||
|
import org.onosproject.net.newresource.ResourceStore;
|
||||||
|
import org.onosproject.store.serializers.KryoNamespaces;
|
||||||
|
import org.onosproject.store.service.ConsistentMap;
|
||||||
|
import org.onosproject.store.service.Serializer;
|
||||||
|
import org.onosproject.store.service.StorageService;
|
||||||
|
import org.onosproject.store.service.TransactionContext;
|
||||||
|
import org.onosproject.store.service.TransactionException;
|
||||||
|
import org.onosproject.store.service.TransactionalMap;
|
||||||
|
import org.onosproject.store.service.Versioned;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of ResourceStore using TransactionalMap.
|
||||||
|
*/
|
||||||
|
@Component(immediate = true, enabled = false)
|
||||||
|
@Service
|
||||||
|
@Beta
|
||||||
|
public class ConsistentResourceStore implements ResourceStore {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class);
|
||||||
|
|
||||||
|
private static final String MAP_NAME = "onos-resource-consumers";
|
||||||
|
private static final Serializer SERIALIZER = Serializer.using(KryoNamespaces.API);
|
||||||
|
|
||||||
|
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||||
|
protected StorageService service;
|
||||||
|
|
||||||
|
private ConsistentMap<Resource<?, ?>, ResourceConsumer> consumers;
|
||||||
|
|
||||||
|
@Activate
|
||||||
|
public void activate() {
|
||||||
|
consumers = service.<Resource<?, ?>, ResourceConsumer>consistentMapBuilder()
|
||||||
|
.withName(MAP_NAME)
|
||||||
|
.withSerializer(SERIALIZER)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <S, T> Optional<ResourceConsumer> getConsumer(Resource<S, T> resource) {
|
||||||
|
checkNotNull(resource);
|
||||||
|
|
||||||
|
Versioned<ResourceConsumer> consumer = consumers.get(resource);
|
||||||
|
if (consumer == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.of(consumer.value());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean allocate(List<? extends Resource<?, ?>> resources, ResourceConsumer consumer) {
|
||||||
|
checkNotNull(resources);
|
||||||
|
checkNotNull(consumer);
|
||||||
|
|
||||||
|
TransactionContext tx = service.transactionContextBuilder().build();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
try {
|
||||||
|
TransactionalMap<Resource<?, ?>, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
|
||||||
|
for (Resource<?, ?> resource: resources) {
|
||||||
|
ResourceConsumer existing = txMap.putIfAbsent(resource, consumer);
|
||||||
|
// if the resource is already allocated to another consumer, the whole allocation fails
|
||||||
|
if (existing != null) {
|
||||||
|
tx.abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tx.commit();
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception thrown, abort the transaction", e);
|
||||||
|
tx.abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release(List<? extends Resource<?, ?>> resources, List<ResourceConsumer> consumers) {
|
||||||
|
checkNotNull(resources);
|
||||||
|
checkNotNull(consumers);
|
||||||
|
checkArgument(resources.size() == consumers.size());
|
||||||
|
|
||||||
|
TransactionContext tx = service.transactionContextBuilder().build();
|
||||||
|
tx.begin();
|
||||||
|
|
||||||
|
try {
|
||||||
|
TransactionalMap<Resource<?, ?>, ResourceConsumer> txMap = tx.getTransactionalMap(MAP_NAME, SERIALIZER);
|
||||||
|
Iterator<? extends Resource<?, ?>> resourceIte = resources.iterator();
|
||||||
|
Iterator<ResourceConsumer> consumerIte = consumers.iterator();
|
||||||
|
|
||||||
|
while (resourceIte.hasNext() && consumerIte.hasNext()) {
|
||||||
|
Resource<?, ?> resource = resourceIte.next();
|
||||||
|
ResourceConsumer consumer = consumerIte.next();
|
||||||
|
|
||||||
|
// if this single release fails (because the resource is allocated to another consumer,
|
||||||
|
// the whole release fails
|
||||||
|
if (!txMap.remove(resource, consumer)) {
|
||||||
|
tx.abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (TransactionException e) {
|
||||||
|
log.error("Exception thrown, abort the transaction", e);
|
||||||
|
tx.abort();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Resource<?, ?>> getResources(ResourceConsumer consumer) {
|
||||||
|
checkNotNull(consumer);
|
||||||
|
|
||||||
|
// NOTE: getting all entries may become performance bottleneck
|
||||||
|
// TODO: revisit for better backend data structure
|
||||||
|
return consumers.entrySet().stream()
|
||||||
|
.filter(x -> x.getValue().value().equals(consumer))
|
||||||
|
.map(Map.Entry::getKey)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public <S, T> Collection<Resource<S, T>> getAllocatedResources(S subject, Class<T> cls) {
|
||||||
|
checkNotNull(subject);
|
||||||
|
checkNotNull(cls);
|
||||||
|
|
||||||
|
// NOTE: getting all entries may become performance bottleneck
|
||||||
|
// TODO: revisit for better backend data structure
|
||||||
|
return consumers.entrySet().stream()
|
||||||
|
.filter(x -> x.getKey().subject().equals(subject) && x.getKey().resource().getClass() == cls)
|
||||||
|
// cast is ensured by the above filter method
|
||||||
|
.map(x -> (Resource<S, T>) x.getKey())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user