mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-11-03 01:31:21 +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