FlowRule : handle Future failure and timeouts.
Change-Id: Ie945b7ee936ae48ec3205592c309baebe8538ce0
Showing
3 changed files
with
54 additions
and
8 deletions
| ... | @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; | ... | @@ -21,6 +21,7 @@ import com.google.common.collect.Lists; |
| 21 | import com.google.common.collect.Maps; | 21 | import com.google.common.collect.Maps; |
| 22 | import com.google.common.collect.Multimap; | 22 | import com.google.common.collect.Multimap; |
| 23 | import com.google.common.collect.Sets; | 23 | import com.google.common.collect.Sets; |
| 24 | + | ||
| 24 | import org.apache.felix.scr.annotations.Activate; | 25 | import org.apache.felix.scr.annotations.Activate; |
| 25 | import org.apache.felix.scr.annotations.Component; | 26 | import org.apache.felix.scr.annotations.Component; |
| 26 | import org.apache.felix.scr.annotations.Deactivate; | 27 | import org.apache.felix.scr.annotations.Deactivate; |
| ... | @@ -54,6 +55,7 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; | ... | @@ -54,6 +55,7 @@ import org.onlab.onos.net.provider.AbstractProviderRegistry; |
| 54 | import org.onlab.onos.net.provider.AbstractProviderService; | 55 | import org.onlab.onos.net.provider.AbstractProviderService; |
| 55 | import org.slf4j.Logger; | 56 | import org.slf4j.Logger; |
| 56 | 57 | ||
| 58 | +import java.util.HashSet; | ||
| 57 | import java.util.List; | 59 | import java.util.List; |
| 58 | import java.util.Map; | 60 | import java.util.Map; |
| 59 | import java.util.Set; | 61 | import java.util.Set; |
| ... | @@ -389,14 +391,21 @@ public class FlowRuleManager | ... | @@ -389,14 +391,21 @@ public class FlowRuleManager |
| 389 | futureService.submit(new Runnable() { | 391 | futureService.submit(new Runnable() { |
| 390 | @Override | 392 | @Override |
| 391 | public void run() { | 393 | public void run() { |
| 392 | - CompletedBatchOperation res = null; | 394 | + CompletedBatchOperation res; |
| 393 | try { | 395 | try { |
| 394 | res = result.get(TIMEOUT, TimeUnit.MILLISECONDS); | 396 | res = result.get(TIMEOUT, TimeUnit.MILLISECONDS); |
| 397 | + store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | ||
| 395 | } catch (TimeoutException | InterruptedException | ExecutionException e) { | 398 | } catch (TimeoutException | InterruptedException | ExecutionException e) { |
| 396 | log.warn("Something went wrong with the batch operation {}", | 399 | log.warn("Something went wrong with the batch operation {}", |
| 397 | - request.batchId()); | 400 | + request.batchId(), e); |
| 401 | + | ||
| 402 | + Set<FlowRule> failures = new HashSet<>(batchOperation.size()); | ||
| 403 | + for (FlowRuleBatchEntry op : batchOperation.getOperations()) { | ||
| 404 | + failures.add(op.getTarget()); | ||
| 405 | + } | ||
| 406 | + res = new CompletedBatchOperation(false, failures); | ||
| 407 | + store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | ||
| 398 | } | 408 | } |
| 399 | - store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | ||
| 400 | } | 409 | } |
| 401 | }); | 410 | }); |
| 402 | break; | 411 | break; | ... | ... |
| ... | @@ -85,6 +85,8 @@ import com.google.common.cache.Cache; | ... | @@ -85,6 +85,8 @@ import com.google.common.cache.Cache; |
| 85 | import com.google.common.cache.CacheBuilder; | 85 | import com.google.common.cache.CacheBuilder; |
| 86 | import com.google.common.cache.CacheLoader; | 86 | import com.google.common.cache.CacheLoader; |
| 87 | import com.google.common.cache.LoadingCache; | 87 | import com.google.common.cache.LoadingCache; |
| 88 | +import com.google.common.cache.RemovalListener; | ||
| 89 | +import com.google.common.cache.RemovalNotification; | ||
| 88 | import com.google.common.collect.ArrayListMultimap; | 90 | import com.google.common.collect.ArrayListMultimap; |
| 89 | import com.google.common.collect.ImmutableList; | 91 | import com.google.common.collect.ImmutableList; |
| 90 | import com.google.common.collect.ImmutableSet; | 92 | import com.google.common.collect.ImmutableSet; |
| ... | @@ -132,8 +134,7 @@ public class DistributedFlowRuleStore | ... | @@ -132,8 +134,7 @@ public class DistributedFlowRuleStore |
| 132 | private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = | 134 | private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = |
| 133 | CacheBuilder.newBuilder() | 135 | CacheBuilder.newBuilder() |
| 134 | .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) | 136 | .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) |
| 135 | - // TODO Explicitly fail the future if expired? | 137 | + .removalListener(new TimeoutFuture()) |
| 136 | - //.removalListener(listener) | ||
| 137 | .build(); | 138 | .build(); |
| 138 | 139 | ||
| 139 | // Cache of SMaps used for backup data. each SMap contain device flow table | 140 | // Cache of SMaps used for backup data. each SMap contain device flow table |
| ... | @@ -541,6 +542,17 @@ public class DistributedFlowRuleStore | ... | @@ -541,6 +542,17 @@ public class DistributedFlowRuleStore |
| 541 | log.debug("removedFromPrimary {}", removed); | 542 | log.debug("removedFromPrimary {}", removed); |
| 542 | } | 543 | } |
| 543 | 544 | ||
| 545 | + private static final class TimeoutFuture | ||
| 546 | + implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> { | ||
| 547 | + @Override | ||
| 548 | + public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) { | ||
| 549 | + // wrapping in ExecutionException to support Future.get | ||
| 550 | + notification.getValue() | ||
| 551 | + .setException(new ExecutionException("Timed out", | ||
| 552 | + new TimeoutException())); | ||
| 553 | + } | ||
| 554 | + } | ||
| 555 | + | ||
| 544 | private final class OnStoreBatch implements ClusterMessageHandler { | 556 | private final class OnStoreBatch implements ClusterMessageHandler { |
| 545 | private final NodeId local; | 557 | private final NodeId local; |
| 546 | 558 | ||
| ... | @@ -580,7 +592,18 @@ public class DistributedFlowRuleStore | ... | @@ -580,7 +592,18 @@ public class DistributedFlowRuleStore |
| 580 | 592 | ||
| 581 | @Override | 593 | @Override |
| 582 | public void run() { | 594 | public void run() { |
| 583 | - CompletedBatchOperation result = Futures.getUnchecked(f); | 595 | + CompletedBatchOperation result; |
| 596 | + try { | ||
| 597 | + result = f.get(); | ||
| 598 | + } catch (InterruptedException | ExecutionException e) { | ||
| 599 | + log.error("Batch operation failed", e); | ||
| 600 | + // create everything failed response | ||
| 601 | + Set<FlowRule> failures = new HashSet<>(operation.size()); | ||
| 602 | + for (FlowRuleBatchEntry op : operation.getOperations()) { | ||
| 603 | + failures.add(op.getTarget()); | ||
| 604 | + } | ||
| 605 | + result = new CompletedBatchOperation(false, failures); | ||
| 606 | + } | ||
| 584 | try { | 607 | try { |
| 585 | message.respond(SERIALIZER.encode(result)); | 608 | message.respond(SERIALIZER.encode(result)); |
| 586 | } catch (IOException e) { | 609 | } catch (IOException e) { | ... | ... |
| ... | @@ -18,6 +18,8 @@ package org.onlab.onos.store.trivial.impl; | ... | @@ -18,6 +18,8 @@ package org.onlab.onos.store.trivial.impl; |
| 18 | import com.google.common.base.Function; | 18 | import com.google.common.base.Function; |
| 19 | import com.google.common.cache.Cache; | 19 | import com.google.common.cache.Cache; |
| 20 | import com.google.common.cache.CacheBuilder; | 20 | import com.google.common.cache.CacheBuilder; |
| 21 | +import com.google.common.cache.RemovalListener; | ||
| 22 | +import com.google.common.cache.RemovalNotification; | ||
| 21 | import com.google.common.collect.FluentIterable; | 23 | import com.google.common.collect.FluentIterable; |
| 22 | import com.google.common.util.concurrent.Futures; | 24 | import com.google.common.util.concurrent.Futures; |
| 23 | import com.google.common.util.concurrent.SettableFuture; | 25 | import com.google.common.util.concurrent.SettableFuture; |
| ... | @@ -53,8 +55,10 @@ import java.util.List; | ... | @@ -53,8 +55,10 @@ import java.util.List; |
| 53 | import java.util.concurrent.ConcurrentHashMap; | 55 | import java.util.concurrent.ConcurrentHashMap; |
| 54 | import java.util.concurrent.ConcurrentMap; | 56 | import java.util.concurrent.ConcurrentMap; |
| 55 | import java.util.concurrent.CopyOnWriteArrayList; | 57 | import java.util.concurrent.CopyOnWriteArrayList; |
| 58 | +import java.util.concurrent.ExecutionException; | ||
| 56 | import java.util.concurrent.Future; | 59 | import java.util.concurrent.Future; |
| 57 | import java.util.concurrent.TimeUnit; | 60 | import java.util.concurrent.TimeUnit; |
| 61 | +import java.util.concurrent.TimeoutException; | ||
| 58 | import java.util.concurrent.atomic.AtomicInteger; | 62 | import java.util.concurrent.atomic.AtomicInteger; |
| 59 | 63 | ||
| 60 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | 64 | import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; |
| ... | @@ -86,8 +90,7 @@ public class SimpleFlowRuleStore | ... | @@ -86,8 +90,7 @@ public class SimpleFlowRuleStore |
| 86 | private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = | 90 | private Cache<Integer, SettableFuture<CompletedBatchOperation>> pendingFutures = |
| 87 | CacheBuilder.newBuilder() | 91 | CacheBuilder.newBuilder() |
| 88 | .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) | 92 | .expireAfterWrite(pendingFutureTimeoutMinutes, TimeUnit.MINUTES) |
| 89 | - // TODO Explicitly fail the future if expired? | 93 | + .removalListener(new TimeoutFuture()) |
| 90 | - //.removalListener(listener) | ||
| 91 | .build(); | 94 | .build(); |
| 92 | 95 | ||
| 93 | @Activate | 96 | @Activate |
| ... | @@ -303,4 +306,15 @@ public class SimpleFlowRuleStore | ... | @@ -303,4 +306,15 @@ public class SimpleFlowRuleStore |
| 303 | } | 306 | } |
| 304 | notifyDelegate(event); | 307 | notifyDelegate(event); |
| 305 | } | 308 | } |
| 309 | + | ||
| 310 | + private static final class TimeoutFuture | ||
| 311 | + implements RemovalListener<Integer, SettableFuture<CompletedBatchOperation>> { | ||
| 312 | + @Override | ||
| 313 | + public void onRemoval(RemovalNotification<Integer, SettableFuture<CompletedBatchOperation>> notification) { | ||
| 314 | + // wrapping in ExecutionException to support Future.get | ||
| 315 | + notification.getValue() | ||
| 316 | + .setException(new ExecutionException("Timed out", | ||
| 317 | + new TimeoutException())); | ||
| 318 | + } | ||
| 319 | + } | ||
| 306 | } | 320 | } | ... | ... |
-
Please register or login to post a comment