// Appends the specified ResourceAllocation to the existing values stored in the map private boolean appendValue( TransactionalMap<ResourceId, ContinuousResourceAllocation> map, ContinuousResource original, ResourceAllocation value) { ContinuousResourceAllocation oldValue = map.putIfAbsent( original.id(), new ContinuousResourceAllocation(original, ImmutableList.of(value))); if (oldValue == null) { return true; } if (oldValue.allocations().contains(value)) { // don't write to map because all values are already stored return true; } ContinuousResourceAllocation newValue = new ContinuousResourceAllocation( original, ImmutableList.<ResourceAllocation>builder() .addAll(oldValue.allocations()) .add(value) .build()); return map.replace(original.id(), oldValue, newValue); }
@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(); }
/** * Checks if there is enough resource volume to allocated the requested resource against the * specified resource. * * @param original original resource * @param request requested resource * @param allocation current allocation of the resource * @return true if there is enough resource volume. Otherwise, false. */ private boolean hasEnoughResource( ContinuousResource original, ContinuousResource request, ContinuousResourceAllocation allocation) { if (allocation == null) { return request.value() <= original.value(); } double allocated = allocation .allocations() .stream() .filter(x -> x.resource() instanceof ContinuousResource) .map(x -> (ContinuousResource) x.resource()) .mapToDouble(ContinuousResource::value) .sum(); double left = original.value() - allocated; return request.value() <= left; }
@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; }