Sho SHIMIZU
Committed by Gerrit Code Review

Separate the child map into two child maps for each resource type

Now, we have a child map for discrete type resources and
a child map for continuous type resources.

This is a refactoring for ONOS-4281.

Change-Id: I1fc931d6b6599885573908606600a61686073bee
...@@ -79,8 +79,9 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -79,8 +79,9 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
79 private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class); 79 private static final Logger log = LoggerFactory.getLogger(ConsistentResourceStore.class);
80 80
81 private static final String DISCRETE_CONSUMER_MAP = "onos-discrete-consumers"; 81 private static final String DISCRETE_CONSUMER_MAP = "onos-discrete-consumers";
82 + private static final String DISCRETE_CHILD_MAP = "onos-resource-discrete-children";
82 private static final String CONTINUOUS_CONSUMER_MAP = "onos-continuous-consumers"; 83 private static final String CONTINUOUS_CONSUMER_MAP = "onos-continuous-consumers";
83 - private static final String CHILD_MAP = "onos-resource-children"; 84 + private static final String CONTINUOUS_CHILD_MAP = "onos-resource-continuous-children";
84 private static final Serializer SERIALIZER = Serializer.using( 85 private static final Serializer SERIALIZER = Serializer.using(
85 Arrays.asList(KryoNamespaces.API), 86 Arrays.asList(KryoNamespaces.API),
86 ContinuousResourceAllocation.class); 87 ContinuousResourceAllocation.class);
...@@ -93,8 +94,9 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -93,8 +94,9 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
93 protected StorageService service; 94 protected StorageService service;
94 95
95 private ConsistentMap<DiscreteResourceId, ResourceConsumer> discreteConsumers; 96 private ConsistentMap<DiscreteResourceId, ResourceConsumer> discreteConsumers;
97 + private ConsistentMap<DiscreteResourceId, Set<DiscreteResource>> discreteChildMap;
96 private ConsistentMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumers; 98 private ConsistentMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumers;
97 - private ConsistentMap<DiscreteResourceId, Set<Resource>> childMap; 99 + private ConsistentMap<DiscreteResourceId, Set<ContinuousResource>> continuousChildMap;
98 100
99 @Activate 101 @Activate
100 public void activate() { 102 public void activate() {
...@@ -102,17 +104,23 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -102,17 +104,23 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
102 .withName(DISCRETE_CONSUMER_MAP) 104 .withName(DISCRETE_CONSUMER_MAP)
103 .withSerializer(SERIALIZER) 105 .withSerializer(SERIALIZER)
104 .build(); 106 .build();
107 + discreteChildMap = service.<DiscreteResourceId, Set<DiscreteResource>>consistentMapBuilder()
108 + .withName(DISCRETE_CHILD_MAP)
109 + .withSerializer(SERIALIZER)
110 + .build();
105 continuousConsumers = service.<ContinuousResourceId, ContinuousResourceAllocation>consistentMapBuilder() 111 continuousConsumers = service.<ContinuousResourceId, ContinuousResourceAllocation>consistentMapBuilder()
106 .withName(CONTINUOUS_CONSUMER_MAP) 112 .withName(CONTINUOUS_CONSUMER_MAP)
107 .withSerializer(SERIALIZER) 113 .withSerializer(SERIALIZER)
108 .build(); 114 .build();
109 - childMap = service.<DiscreteResourceId, Set<Resource>>consistentMapBuilder() 115 + continuousChildMap = service.<DiscreteResourceId, Set<ContinuousResource>>consistentMapBuilder()
110 - .withName(CHILD_MAP) 116 + .withName(CONTINUOUS_CHILD_MAP)
111 .withSerializer(SERIALIZER) 117 .withSerializer(SERIALIZER)
112 .build(); 118 .build();
113 119
114 - Tools.retryable(() -> childMap.put(Resource.ROOT.id(), new LinkedHashSet<>()), 120 + Tools.retryable(() -> discreteChildMap.put(Resource.ROOT.id(), new LinkedHashSet<>()),
115 - ConsistentMapException.class, MAX_RETRIES, RETRY_DELAY); 121 + ConsistentMapException.class, MAX_RETRIES, RETRY_DELAY);
122 + Tools.retryable(() -> continuousChildMap.put(Resource.ROOT.id(), new LinkedHashSet<>()),
123 + ConsistentMapException.class, MAX_RETRIES, RETRY_DELAY);
116 log.info("Started"); 124 log.info("Started");
117 } 125 }
118 126
...@@ -162,8 +170,10 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -162,8 +170,10 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
162 TransactionContext tx = service.transactionContextBuilder().build(); 170 TransactionContext tx = service.transactionContextBuilder().build();
163 tx.begin(); 171 tx.begin();
164 172
165 - TransactionalMap<DiscreteResourceId, Set<Resource>> childTxMap = 173 + TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteChildTxMap =
166 - tx.getTransactionalMap(CHILD_MAP, SERIALIZER); 174 + tx.getTransactionalMap(DISCRETE_CHILD_MAP, SERIALIZER);
175 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousChildTxMap =
176 + tx.getTransactionalMap(CONTINUOUS_CHILD_MAP, SERIALIZER);
167 177
168 // the order is preserved by LinkedHashMap 178 // the order is preserved by LinkedHashMap
169 Map<DiscreteResource, List<Resource>> resourceMap = resources.stream() 179 Map<DiscreteResource, List<Resource>> resourceMap = resources.stream()
...@@ -171,11 +181,11 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -171,11 +181,11 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
171 .collect(Collectors.groupingBy(x -> x.parent().get(), LinkedHashMap::new, Collectors.toList())); 181 .collect(Collectors.groupingBy(x -> x.parent().get(), LinkedHashMap::new, Collectors.toList()));
172 182
173 for (Map.Entry<DiscreteResource, List<Resource>> entry: resourceMap.entrySet()) { 183 for (Map.Entry<DiscreteResource, List<Resource>> entry: resourceMap.entrySet()) {
174 - if (!lookup(childTxMap, entry.getKey().id()).isPresent()) { 184 + if (!lookup(discreteChildTxMap, continuousChildTxMap, entry.getKey().id()).isPresent()) {
175 return abortTransaction(tx); 185 return abortTransaction(tx);
176 } 186 }
177 187
178 - if (!appendValues(childTxMap, entry.getKey().id(), entry.getValue())) { 188 + if (!appendValues(discreteChildTxMap, continuousChildTxMap, entry.getKey().id(), entry.getValue())) {
179 return abortTransaction(tx); 189 return abortTransaction(tx);
180 } 190 }
181 } 191 }
...@@ -201,12 +211,14 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -201,12 +211,14 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
201 TransactionContext tx = service.transactionContextBuilder().build(); 211 TransactionContext tx = service.transactionContextBuilder().build();
202 tx.begin(); 212 tx.begin();
203 213
204 - TransactionalMap<DiscreteResourceId, Set<Resource>> childTxMap =
205 - tx.getTransactionalMap(CHILD_MAP, SERIALIZER);
206 TransactionalMap<DiscreteResourceId, ResourceConsumer> discreteConsumerTxMap = 214 TransactionalMap<DiscreteResourceId, ResourceConsumer> discreteConsumerTxMap =
207 tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); 215 tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER);
216 + TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteChildTxMap =
217 + tx.getTransactionalMap(DISCRETE_CHILD_MAP, SERIALIZER);
208 TransactionalMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = 218 TransactionalMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumerTxMap =
209 tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); 219 tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER);
220 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousChildTxMap =
221 + tx.getTransactionalMap(CONTINUOUS_CHILD_MAP, SERIALIZER);
210 222
211 // Look up resources by resource IDs 223 // Look up resources by resource IDs
212 List<Resource> resources = ids.stream() 224 List<Resource> resources = ids.stream()
...@@ -216,7 +228,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -216,7 +228,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
216 if (x instanceof DiscreteResourceId) { 228 if (x instanceof DiscreteResourceId) {
217 return Optional.of(Resources.discrete((DiscreteResourceId) x).resource()); 229 return Optional.of(Resources.discrete((DiscreteResourceId) x).resource());
218 } else { 230 } else {
219 - return lookup(childTxMap, x); 231 + return lookup(continuousChildTxMap, (ContinuousResourceId) x);
220 } 232 }
221 }) 233 })
222 .filter(Optional::isPresent) 234 .filter(Optional::isPresent)
...@@ -245,7 +257,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -245,7 +257,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
245 return abortTransaction(tx); 257 return abortTransaction(tx);
246 } 258 }
247 259
248 - if (!removeValues(childTxMap, entry.getKey(), entry.getValue())) { 260 + if (!removeValues(discreteChildTxMap, continuousChildTxMap, entry.getKey(), entry.getValue())) {
249 log.warn("Failed to unregister {}: Failed to remove {} values.", 261 log.warn("Failed to unregister {}: Failed to remove {} values.",
250 entry.getKey(), entry.getValue().size()); 262 entry.getKey(), entry.getValue().size());
251 log.debug("Failed to unregister {}: Failed to remove values: {}", 263 log.debug("Failed to unregister {}: Failed to remove values: {}",
...@@ -275,16 +287,18 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -275,16 +287,18 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
275 TransactionContext tx = service.transactionContextBuilder().build(); 287 TransactionContext tx = service.transactionContextBuilder().build();
276 tx.begin(); 288 tx.begin();
277 289
278 - TransactionalMap<DiscreteResourceId, Set<Resource>> childTxMap =
279 - tx.getTransactionalMap(CHILD_MAP, SERIALIZER);
280 TransactionalMap<DiscreteResourceId, ResourceConsumer> discreteConsumerTxMap = 290 TransactionalMap<DiscreteResourceId, ResourceConsumer> discreteConsumerTxMap =
281 tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER); 291 tx.getTransactionalMap(DISCRETE_CONSUMER_MAP, SERIALIZER);
292 + TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteChildTxMap =
293 + tx.getTransactionalMap(DISCRETE_CHILD_MAP, SERIALIZER);
282 TransactionalMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumerTxMap = 294 TransactionalMap<ContinuousResourceId, ContinuousResourceAllocation> continuousConsumerTxMap =
283 tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER); 295 tx.getTransactionalMap(CONTINUOUS_CONSUMER_MAP, SERIALIZER);
296 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousChildTxMap =
297 + tx.getTransactionalMap(CONTINUOUS_CHILD_MAP, SERIALIZER);
284 298
285 for (Resource resource: resources) { 299 for (Resource resource: resources) {
286 // if the resource is not registered, then abort 300 // if the resource is not registered, then abort
287 - Optional<Resource> lookedUp = lookup(childTxMap, resource.id()); 301 + Optional<Resource> lookedUp = lookup(discreteChildTxMap, continuousChildTxMap, resource.id());
288 if (!lookedUp.isPresent()) { 302 if (!lookedUp.isPresent()) {
289 return abortTransaction(tx); 303 return abortTransaction(tx);
290 } 304 }
...@@ -372,7 +386,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -372,7 +386,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
372 // computational complexity: O(n) where n is the number of existing allocations for the resource 386 // computational complexity: O(n) where n is the number of existing allocations for the resource
373 private boolean isAvailable(ContinuousResource resource) { 387 private boolean isAvailable(ContinuousResource resource) {
374 // check if it's registered or not. 388 // check if it's registered or not.
375 - Versioned<Set<Resource>> children = childMap.get(resource.parent().get().id()); 389 + Versioned<Set<ContinuousResource>> children = continuousChildMap.get(resource.parent().get().id());
376 if (children == null) { 390 if (children == null) {
377 return false; 391 return false;
378 } 392 }
...@@ -380,7 +394,6 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -380,7 +394,6 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
380 ContinuousResource registered = children.value().stream() 394 ContinuousResource registered = children.value().stream()
381 .filter(c -> c.id().equals(resource.id())) 395 .filter(c -> c.id().equals(resource.id()))
382 .findFirst() 396 .findFirst()
383 - .map(c -> (ContinuousResource) c)
384 .get(); 397 .get();
385 if (registered.value() < resource.value()) { 398 if (registered.value() < resource.value()) {
386 // Capacity < requested, can never satisfy 399 // Capacity < requested, can never satisfy
...@@ -424,12 +437,21 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -424,12 +437,21 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
424 public Set<Resource> getChildResources(DiscreteResourceId parent) { 437 public Set<Resource> getChildResources(DiscreteResourceId parent) {
425 checkNotNull(parent); 438 checkNotNull(parent);
426 439
427 - Versioned<Set<Resource>> children = childMap.get(parent); 440 + Versioned<Set<DiscreteResource>> discreteChildren = discreteChildMap.get(parent);
428 - if (children == null) { 441 + Versioned<Set<ContinuousResource>> continuousChildren = continuousChildMap.get(parent);
442 +
443 + if (discreteChildren == null && continuousChildren == null) {
429 return ImmutableSet.of(); 444 return ImmutableSet.of();
445 + } else if (discreteChildren == null) {
446 + return ImmutableSet.copyOf(continuousChildren.value());
447 + } else if (continuousChildren == null) {
448 + return ImmutableSet.copyOf(discreteChildren.value());
449 + } else {
450 + return ImmutableSet.<Resource>builder()
451 + .addAll(discreteChildren.value())
452 + .addAll(continuousChildren.value())
453 + .build();
430 } 454 }
431 -
432 - return children.value();
433 } 455 }
434 456
435 // computational complexity: O(n) where n is the number of the children of the parent 457 // computational complexity: O(n) where n is the number of the children of the parent
...@@ -438,18 +460,18 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -438,18 +460,18 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
438 checkNotNull(parent); 460 checkNotNull(parent);
439 checkNotNull(cls); 461 checkNotNull(cls);
440 462
441 - Versioned<Set<Resource>> children = childMap.get(parent); 463 + Set<Resource> children = getChildResources(parent);
442 - if (children == null) { 464 + if (children.isEmpty()) {
443 - return ImmutableList.of(); 465 + return children;
444 } 466 }
445 467
446 - Stream<DiscreteResource> discrete = children.value().stream() 468 + Stream<DiscreteResource> discrete = children.stream()
447 .filter(x -> x.isTypeOf(cls)) 469 .filter(x -> x.isTypeOf(cls))
448 .filter(x -> x instanceof DiscreteResource) 470 .filter(x -> x instanceof DiscreteResource)
449 .map(x -> ((DiscreteResource) x)) 471 .map(x -> ((DiscreteResource) x))
450 .filter(x -> discreteConsumers.containsKey(x.id())); 472 .filter(x -> discreteConsumers.containsKey(x.id()));
451 473
452 - Stream<ContinuousResource> continuous = children.value().stream() 474 + Stream<ContinuousResource> continuous = children.stream()
453 .filter(x -> x.id().equals(parent.child(cls))) 475 .filter(x -> x.id().equals(parent.child(cls)))
454 .filter(x -> x instanceof ContinuousResource) 476 .filter(x -> x instanceof ContinuousResource)
455 .map(x -> (ContinuousResource) x) 477 .map(x -> (ContinuousResource) x)
...@@ -505,29 +527,77 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -505,29 +527,77 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
505 * Appends the values to the existing values associated with the specified key. 527 * Appends the values to the existing values associated with the specified key.
506 * If the map already has all the given values, appending will not happen. 528 * If the map already has all the given values, appending will not happen.
507 * 529 *
508 - * @param map map holding multiple values for a key 530 + * @param discreteTxMap map holding multiple discrete resources for a key
531 + * @param continuousTxMap map holding multiple continuous resources for a key
509 * @param key key specifying values 532 * @param key key specifying values
510 * @param values values to be appended 533 * @param values values to be appended
511 * @return true if the operation succeeds, false otherwise. 534 * @return true if the operation succeeds, false otherwise.
512 */ 535 */
513 // computational complexity: O(n) where n is the number of the specified value 536 // computational complexity: O(n) where n is the number of the specified value
514 - private boolean appendValues(TransactionalMap<DiscreteResourceId, Set<Resource>> map, 537 + private boolean appendValues(TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteTxMap,
538 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousTxMap,
515 DiscreteResourceId key, List<Resource> values) { 539 DiscreteResourceId key, List<Resource> values) {
516 - Set<Resource> requested = new LinkedHashSet<>(values); 540 + // it's assumed that the passed "values" is non-empty
517 - Set<Resource> oldValues = map.putIfAbsent(key, requested); 541 +
542 + // This is 2-pass scan. Nicer to have 1-pass scan
543 + List<DiscreteResource> discreteValues = values.stream()
544 + .filter(x -> x instanceof DiscreteResource)
545 + .map(x -> (DiscreteResource) x)
546 + .collect(Collectors.toList());
547 + List<ContinuousResource> continuousValues = values.stream()
548 + .filter(x -> x instanceof ContinuousResource)
549 + .map(x -> (ContinuousResource) x)
550 + .collect(Collectors.toList());
551 +
552 + // short-circuit decision avoiding unnecessary distributed map operations
553 + if (continuousValues.isEmpty()) {
554 + return appendValues(discreteTxMap, key, discreteValues, null);
555 + }
556 + if (discreteValues.isEmpty()) {
557 + return appendValues(continuousTxMap, key, continuousValues, null);
558 + }
559 +
560 + return appendValues(discreteTxMap, key, discreteValues, null)
561 + && appendValues(continuousTxMap, key, continuousValues, null);
562 + }
563 +
564 + private boolean appendValues(TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> map,
565 + DiscreteResourceId key, List<DiscreteResource> values, DiscreteResource dummy) {
566 + Set<DiscreteResource> requested = new LinkedHashSet<>(values);
567 + Set<DiscreteResource> oldValues = map.putIfAbsent(key, requested);
568 + if (oldValues == null) {
569 + return true;
570 + }
571 +
572 + Set<DiscreteResource> addedValues = Sets.difference(requested, oldValues);
573 + // no new value, then no-op
574 + if (addedValues.isEmpty()) {
575 + // don't write to map because all values are already stored
576 + return true;
577 + }
578 +
579 + Set<DiscreteResource> newValues = new LinkedHashSet<>(oldValues);
580 + newValues.addAll(addedValues);
581 + return map.replace(key, oldValues, newValues);
582 + }
583 +
584 + private boolean appendValues(TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> map,
585 + DiscreteResourceId key, List<ContinuousResource> values, ContinuousResource dummy) {
586 + Set<ContinuousResource> requested = new LinkedHashSet<>(values);
587 + Set<ContinuousResource> oldValues = map.putIfAbsent(key, requested);
518 if (oldValues == null) { 588 if (oldValues == null) {
519 return true; 589 return true;
520 } 590 }
521 591
522 - Set<Resource> addedValues = Sets.difference(requested, oldValues); 592 + Set<ContinuousResource> addedValues = Sets.difference(requested, oldValues);
523 // no new value, then no-op 593 // no new value, then no-op
524 if (addedValues.isEmpty()) { 594 if (addedValues.isEmpty()) {
525 // don't write to map because all values are already stored 595 // don't write to map because all values are already stored
526 return true; 596 return true;
527 } 597 }
528 598
529 - Set<ResourceId> addedIds = addedValues.stream() 599 + Set<ContinuousResourceId> addedIds = addedValues.stream()
530 - .map(Resource::id) 600 + .map(ContinuousResource::id)
531 .collect(Collectors.toSet()); 601 .collect(Collectors.toSet());
532 // if the value is not found but the same ID is found 602 // if the value is not found but the same ID is found
533 // (this happens only when being continuous resource) 603 // (this happens only when being continuous resource)
...@@ -535,7 +605,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -535,7 +605,7 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
535 // no-op, but indicating failure (reject the request) 605 // no-op, but indicating failure (reject the request)
536 return false; 606 return false;
537 } 607 }
538 - Set<Resource> newValues = new LinkedHashSet<>(oldValues); 608 + Set<ContinuousResource> newValues = new LinkedHashSet<>(oldValues);
539 newValues.addAll(addedValues); 609 newValues.addAll(addedValues);
540 return map.replace(key, oldValues, newValues); 610 return map.replace(key, oldValues, newValues);
541 } 611 }
...@@ -544,15 +614,41 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -544,15 +614,41 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
544 * Removes the values from the existing values associated with the specified key. 614 * Removes the values from the existing values associated with the specified key.
545 * If the map doesn't contain the given values, removal will not happen. 615 * If the map doesn't contain the given values, removal will not happen.
546 * 616 *
547 - * @param map map holding multiple values for a key 617 + * @param discreteTxMap map holding multiple discrete resources for a key
618 + * @param continuousTxMap map holding multiple continuous resources for a key
548 * @param key key specifying values 619 * @param key key specifying values
549 * @param values values to be removed 620 * @param values values to be removed
550 * @return true if the operation succeeds, false otherwise 621 * @return true if the operation succeeds, false otherwise
551 */ 622 */
552 - // computational complexity: O(n) where n is the number of the specified values 623 + private boolean removeValues(TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteTxMap,
553 - private boolean removeValues(TransactionalMap<DiscreteResourceId, Set<Resource>> map, 624 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousTxMap,
554 DiscreteResourceId key, List<Resource> values) { 625 DiscreteResourceId key, List<Resource> values) {
555 - Set<Resource> oldValues = map.putIfAbsent(key, new LinkedHashSet<>()); 626 + // it's assumed that the passed "values" is non-empty
627 +
628 + // This is 2-pass scan. Nicer to have 1-pass scan
629 + List<DiscreteResource> discreteValues = values.stream()
630 + .filter(x -> x instanceof DiscreteResource)
631 + .map(x -> (DiscreteResource) x)
632 + .collect(Collectors.toList());
633 + List<ContinuousResource> continuousValues = values.stream()
634 + .filter(x -> x instanceof ContinuousResource)
635 + .map(x -> (ContinuousResource) x)
636 + .collect(Collectors.toList());
637 +
638 + // short-circuit decision avoiding unnecessary distributed map operations
639 + if (continuousValues.isEmpty()) {
640 + return removeValues(discreteTxMap, key, discreteValues);
641 + }
642 + if (discreteValues.isEmpty()) {
643 + return removeValues(continuousTxMap, key, continuousValues);
644 + }
645 +
646 + return removeValues(discreteTxMap, key, discreteValues) && removeValues(continuousTxMap, key, continuousValues);
647 + }
648 +
649 + private <T extends Resource> boolean removeValues(TransactionalMap<DiscreteResourceId, Set<T>> map,
650 + DiscreteResourceId key, List<T> values) {
651 + Set<T> oldValues = map.putIfAbsent(key, new LinkedHashSet<>());
556 if (oldValues == null) { 652 if (oldValues == null) {
557 log.trace("No-Op removing values. key {} did not exist", key); 653 log.trace("No-Op removing values. key {} did not exist", key);
558 return true; 654 return true;
...@@ -564,47 +660,70 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour ...@@ -564,47 +660,70 @@ public class ConsistentResourceStore extends AbstractStore<ResourceEvent, Resour
564 return true; 660 return true;
565 } 661 }
566 662
567 - LinkedHashSet<Resource> newValues = new LinkedHashSet<>(oldValues); 663 + LinkedHashSet<T> newValues = new LinkedHashSet<>(oldValues);
568 newValues.removeAll(values); 664 newValues.removeAll(values);
569 return map.replace(key, oldValues, newValues); 665 return map.replace(key, oldValues, newValues);
570 - }
571 666
667 + }
572 /** 668 /**
573 * Returns the resource which has the same key as the specified resource ID 669 * Returns the resource which has the same key as the specified resource ID
574 * in the set as a value of the map. 670 * in the set as a value of the map.
575 * 671 *
576 - * @param childTxMap map storing parent - child relationship of resources 672 + * @param discreteTxMap map storing parent - child relationship of discrete resources
673 + * @param continuousTxMap map storing parent -child relationship of continuous resources
577 * @param id ID of resource to be checked 674 * @param id ID of resource to be checked
578 * @return the resource which is regarded as the same as the specified resource 675 * @return the resource which is regarded as the same as the specified resource
579 */ 676 */
580 // Naive implementation, which traverses all elements in the set when continuous resource 677 // Naive implementation, which traverses all elements in the set when continuous resource
581 // computational complexity: O(1) when discrete resource. O(n) when continuous resource 678 // computational complexity: O(1) when discrete resource. O(n) when continuous resource
582 // where n is the number of elements in the associated set 679 // where n is the number of elements in the associated set
583 - private Optional<Resource> lookup(TransactionalMap<DiscreteResourceId, Set<Resource>> childTxMap, ResourceId id) { 680 + private Optional<Resource> lookup(TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteTxMap,
681 + TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousTxMap,
682 + ResourceId id) {
683 + if (id instanceof DiscreteResourceId) {
684 + return lookup(discreteTxMap, (DiscreteResourceId) id);
685 + } else if (id instanceof ContinuousResourceId) {
686 + return lookup(continuousTxMap, (ContinuousResourceId) id);
687 + } else {
688 + return Optional.empty();
689 + }
690 + }
691 +
692 + // check the existence in the set: O(1) operation
693 + private Optional<Resource> lookup(TransactionalMap<DiscreteResourceId, Set<DiscreteResource>> discreteTxMap,
694 + DiscreteResourceId id) {
584 if (!id.parent().isPresent()) { 695 if (!id.parent().isPresent()) {
585 return Optional.of(Resource.ROOT); 696 return Optional.of(Resource.ROOT);
586 } 697 }
587 698
588 - Set<Resource> values = childTxMap.get(id.parent().get()); 699 + Set<DiscreteResource> values = discreteTxMap.get(id.parent().get());
589 if (values == null) { 700 if (values == null) {
590 return Optional.empty(); 701 return Optional.empty();
591 } 702 }
592 703
593 - // short-circuit if discrete resource 704 + DiscreteResource resource = Resources.discrete(id).resource();
594 - // check the existence in the set: O(1) operation 705 + if (values.contains(resource)) {
595 - if (id instanceof DiscreteResourceId) { 706 + return Optional.of(resource);
596 - DiscreteResource discrete = Resources.discrete((DiscreteResourceId) id).resource(); 707 + } else {
597 - if (values.contains(discrete)) { 708 + return Optional.empty();
598 - return Optional.of(discrete); 709 + }
599 - } else { 710 + }
600 - return Optional.empty(); 711 +
601 - } 712 + // iterate over the values in the set: O(n) operation
713 + private Optional<Resource> lookup(TransactionalMap<DiscreteResourceId, Set<ContinuousResource>> continuousTxMap,
714 + ContinuousResourceId id) {
715 + if (!id.parent().isPresent()) {
716 + return Optional.of(Resource.ROOT);
717 + }
718 +
719 + Set<ContinuousResource> values = continuousTxMap.get(id.parent().get());
720 + if (values == null) {
721 + return Optional.empty();
602 } 722 }
603 723
604 - // continuous resource case
605 - // iterate over the values in the set: O(n) operation
606 return values.stream() 724 return values.stream()
607 .filter(x -> x.id().equals(id)) 725 .filter(x -> x.id().equals(id))
726 + .map(x -> (Resource) x)
608 .findFirst(); 727 .findFirst();
609 } 728 }
610 729
......