FlowRule : handle Future failure and timeouts.
Change-Id: Ie945b7ee936ae48ec3205592c309baebe8538ce0
Showing
3 changed files
with
53 additions
and
7 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,15 +391,22 @@ public class FlowRuleManager | ... | @@ -389,15 +391,22 @@ 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()); | ||
398 | } | 405 | } |
406 | + res = new CompletedBatchOperation(false, failures); | ||
399 | store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); | 407 | store.batchOperationComplete(FlowRuleBatchEvent.completed(request, res)); |
400 | } | 408 | } |
409 | + } | ||
401 | }); | 410 | }); |
402 | break; | 411 | break; |
403 | 412 | ... | ... |
... | @@ -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