@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 boolean allocate(List<Resource> resources, ResourceConsumer consumer) { checkNotNull(resources); checkNotNull(consumer); TransactionContext tx = service.transactionContextBuilder().build(); tx.begin(); TransactionalMap<DiscreteResource, Set<Resource>> childTxMap = tx.getTransactionalMap(CHILD_MAP, SERIALIZER); TransactionalMap<DiscreteResource, ResourceConsumer> discreteConsumerTxMap = tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); for (Resource resource : resources) { if (resource instanceof DiscreteResource) { if (!lookup(childTxMap, resource).isPresent()) { return abortTransaction(tx); } ResourceConsumer oldValue = discreteConsumerTxMap.put((DiscreteResource) resource, consumer); if (oldValue != null) { return abortTransaction(tx); } } else if (resource instanceof ContinuousResource) { Optional<ContinuousResource> continuous = lookup(childTxMap, (ContinuousResource) resource); if (!continuous.isPresent()) { return abortTransaction(tx); } ContinuousResourceAllocation allocations = continuousConsumerTxMap.get(continuous.get().id()); if (!hasEnoughResource(continuous.get(), (ContinuousResource) resource, allocations)) { return abortTransaction(tx); } boolean success = appendValue( continuousConsumerTxMap, continuous.get(), new ResourceAllocation(continuous.get(), consumer)); if (!success) { return abortTransaction(tx); } } } return tx.commit(); }
@Override public boolean release(List<Resource> resources, List<ResourceConsumer> consumers) { checkNotNull(resources); checkNotNull(consumers); checkArgument(resources.size() == consumers.size()); TransactionContext tx = service.transactionContextBuilder().build(); tx.begin(); TransactionalMap<DiscreteResource, ResourceConsumer> discreteConsumerTxMap = tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); Iterator<Resource> resourceIte = resources.iterator(); Iterator<ResourceConsumer> consumerIte = consumers.iterator(); while (resourceIte.hasNext() && consumerIte.hasNext()) { Resource resource = resourceIte.next(); ResourceConsumer consumer = consumerIte.next(); if (resource instanceof DiscreteResource) { // if this single release fails (because the resource is allocated to another consumer, // the whole release fails if (!discreteConsumerTxMap.remove((DiscreteResource) resource, consumer)) { return abortTransaction(tx); } } else if (resource instanceof ContinuousResource) { ContinuousResource continuous = (ContinuousResource) resource; ContinuousResourceAllocation allocation = continuousConsumerTxMap.get(continuous.id()); ImmutableList<ResourceAllocation> newAllocations = allocation .allocations() .stream() .filter( x -> !(x.consumer().equals(consumer) && ((ContinuousResource) x.resource()).value() == continuous.value())) .collect(GuavaCollectors.toImmutableList()); if (!continuousConsumerTxMap.replace( continuous.id(), allocation, new ContinuousResourceAllocation(allocation.original(), newAllocations))) { return abortTransaction(tx); } } } return tx.commit(); }
@Override public boolean register(List<Resource> resources) { checkNotNull(resources); if (log.isTraceEnabled()) { resources.forEach(r -> log.trace("registering {}", r)); } TransactionContext tx = service.transactionContextBuilder().build(); tx.begin(); TransactionalMap<DiscreteResource, Set<Resource>> childTxMap = tx.getTransactionalMap(CHILD_MAP, SERIALIZER); Map<DiscreteResource, List<Resource>> resourceMap = resources .stream() .filter(x -> x.parent().isPresent()) .collect(Collectors.groupingBy(x -> x.parent().get())); for (Map.Entry<DiscreteResource, List<Resource>> entry : resourceMap.entrySet()) { Optional<DiscreteResource> child = lookup(childTxMap, entry.getKey()); if (!child.isPresent()) { return abortTransaction(tx); } if (!appendValues(childTxMap, entry.getKey(), entry.getValue())) { return abortTransaction(tx); } } boolean success = tx.commit(); if (success) { List<ResourceEvent> events = resources .stream() .filter(x -> x.parent().isPresent()) .map(x -> new ResourceEvent(RESOURCE_ADDED, x)) .collect(Collectors.toList()); notifyDelegate(events); } return success; }
@Override public boolean unregister(List<Resource> resources) { checkNotNull(resources); TransactionContext tx = service.transactionContextBuilder().build(); tx.begin(); TransactionalMap<DiscreteResource, Set<Resource>> childTxMap = tx.getTransactionalMap(CHILD_MAP, SERIALIZER); TransactionalMap<DiscreteResource, ResourceConsumer> discreteConsumerTxMap = tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); TransactionalMap<ResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); // Extract Discrete instances from resources Map<DiscreteResource, List<Resource>> resourceMap = resources .stream() .filter(x -> x.parent().isPresent()) .collect(Collectors.groupingBy(x -> x.parent().get())); // even if one of the resources is allocated to a consumer, // all unregistrations are regarded as failure for (Map.Entry<DiscreteResource, List<Resource>> entry : resourceMap.entrySet()) { boolean allocated = entry .getValue() .stream() .anyMatch( x -> { if (x instanceof DiscreteResource) { return discreteConsumerTxMap.get((DiscreteResource) x) != null; } else if (x instanceof ContinuousResource) { ContinuousResourceAllocation allocations = continuousConsumerTxMap.get(x.id()); return allocations != null && !allocations.allocations().isEmpty(); } else { return false; } }); if (allocated) { return abortTransaction(tx); } if (!removeValues(childTxMap, entry.getKey(), entry.getValue())) { return abortTransaction(tx); } } boolean success = tx.commit(); if (success) { List<ResourceEvent> events = resources .stream() .filter(x -> x.parent().isPresent()) .map(x -> new ResourceEvent(RESOURCE_REMOVED, x)) .collect(Collectors.toList()); notifyDelegate(events); } return success; }