Committed by
Gerrit Code Review
Moving Dist flow rule store backup mechanism to use EC Map
Change-Id: I465cc2424004721bf09505ac9cde068884f04940
Showing
3 changed files
with
117 additions
and
214 deletions
... | @@ -22,7 +22,7 @@ import org.onosproject.net.DeviceId; | ... | @@ -22,7 +22,7 @@ import org.onosproject.net.DeviceId; |
22 | import org.slf4j.Logger; | 22 | import org.slf4j.Logger; |
23 | 23 | ||
24 | public class DefaultFlowEntry extends DefaultFlowRule | 24 | public class DefaultFlowEntry extends DefaultFlowRule |
25 | - implements FlowEntry, StoredFlowEntry { | 25 | + implements StoredFlowEntry { |
26 | 26 | ||
27 | private static final Logger log = getLogger(DefaultFlowEntry.class); | 27 | private static final Logger log = getLogger(DefaultFlowEntry.class); |
28 | 28 | ... | ... |
... | @@ -357,6 +357,10 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -357,6 +357,10 @@ public class EventuallyConsistentMapImpl<K, V> |
357 | } | 357 | } |
358 | 358 | ||
359 | private boolean removeInternal(K key, Timestamp timestamp) { | 359 | private boolean removeInternal(K key, Timestamp timestamp) { |
360 | + if (timestamp == null) { | ||
361 | + return false; | ||
362 | + } | ||
363 | + | ||
360 | counter.incrementCount(); | 364 | counter.incrementCount(); |
361 | final MutableBoolean updated = new MutableBoolean(false); | 365 | final MutableBoolean updated = new MutableBoolean(false); |
362 | 366 | ... | ... |
... | @@ -15,29 +15,25 @@ | ... | @@ -15,29 +15,25 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.store.flow.impl; | 16 | package org.onosproject.store.flow.impl; |
17 | 17 | ||
18 | -import com.google.common.cache.CacheBuilder; | ||
19 | -import com.google.common.cache.CacheLoader; | ||
20 | -import com.google.common.cache.LoadingCache; | ||
21 | import com.google.common.collect.ImmutableList; | 18 | import com.google.common.collect.ImmutableList; |
22 | import com.google.common.collect.Iterables; | 19 | import com.google.common.collect.Iterables; |
23 | import com.google.common.collect.Maps; | 20 | import com.google.common.collect.Maps; |
24 | import com.google.common.collect.Sets; | 21 | import com.google.common.collect.Sets; |
25 | -import com.hazelcast.core.IMap; | 22 | + |
26 | import org.apache.felix.scr.annotations.Activate; | 23 | import org.apache.felix.scr.annotations.Activate; |
27 | import org.apache.felix.scr.annotations.Component; | 24 | import org.apache.felix.scr.annotations.Component; |
28 | import org.apache.felix.scr.annotations.Deactivate; | 25 | import org.apache.felix.scr.annotations.Deactivate; |
29 | import org.apache.felix.scr.annotations.Reference; | 26 | import org.apache.felix.scr.annotations.Reference; |
30 | import org.apache.felix.scr.annotations.ReferenceCardinality; | 27 | import org.apache.felix.scr.annotations.ReferenceCardinality; |
31 | import org.apache.felix.scr.annotations.Service; | 28 | import org.apache.felix.scr.annotations.Service; |
32 | -import org.onlab.util.BoundedThreadPool; | ||
33 | import org.onlab.util.KryoNamespace; | 29 | import org.onlab.util.KryoNamespace; |
34 | -import org.onlab.util.NewConcurrentHashMap; | ||
35 | import org.onosproject.cluster.ClusterService; | 30 | import org.onosproject.cluster.ClusterService; |
36 | import org.onosproject.cluster.NodeId; | 31 | import org.onosproject.cluster.NodeId; |
37 | import org.onosproject.core.CoreService; | 32 | import org.onosproject.core.CoreService; |
38 | import org.onosproject.core.IdGenerator; | 33 | import org.onosproject.core.IdGenerator; |
39 | import org.onosproject.net.Device; | 34 | import org.onosproject.net.Device; |
40 | import org.onosproject.net.DeviceId; | 35 | import org.onosproject.net.DeviceId; |
36 | +import org.onosproject.net.device.DeviceClockService; | ||
41 | import org.onosproject.net.device.DeviceService; | 37 | import org.onosproject.net.device.DeviceService; |
42 | import org.onosproject.net.flow.CompletedBatchOperation; | 38 | import org.onosproject.net.flow.CompletedBatchOperation; |
43 | import org.onosproject.net.flow.DefaultFlowEntry; | 39 | import org.onosproject.net.flow.DefaultFlowEntry; |
... | @@ -56,28 +52,31 @@ import org.onosproject.net.flow.FlowRuleService; | ... | @@ -56,28 +52,31 @@ import org.onosproject.net.flow.FlowRuleService; |
56 | import org.onosproject.net.flow.FlowRuleStore; | 52 | import org.onosproject.net.flow.FlowRuleStore; |
57 | import org.onosproject.net.flow.FlowRuleStoreDelegate; | 53 | import org.onosproject.net.flow.FlowRuleStoreDelegate; |
58 | import org.onosproject.net.flow.StoredFlowEntry; | 54 | import org.onosproject.net.flow.StoredFlowEntry; |
55 | +import org.onosproject.store.AbstractStore; | ||
56 | +import org.onosproject.store.Timestamp; | ||
59 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; | 57 | import org.onosproject.store.cluster.messaging.ClusterCommunicationService; |
60 | import org.onosproject.store.cluster.messaging.ClusterMessage; | 58 | import org.onosproject.store.cluster.messaging.ClusterMessage; |
61 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; | 59 | import org.onosproject.store.cluster.messaging.ClusterMessageHandler; |
60 | +import org.onosproject.store.ecmap.EventuallyConsistentMap; | ||
61 | +import org.onosproject.store.ecmap.EventuallyConsistentMapImpl; | ||
62 | import org.onosproject.store.flow.ReplicaInfo; | 62 | import org.onosproject.store.flow.ReplicaInfo; |
63 | import org.onosproject.store.flow.ReplicaInfoEvent; | 63 | import org.onosproject.store.flow.ReplicaInfoEvent; |
64 | import org.onosproject.store.flow.ReplicaInfoEventListener; | 64 | import org.onosproject.store.flow.ReplicaInfoEventListener; |
65 | import org.onosproject.store.flow.ReplicaInfoService; | 65 | import org.onosproject.store.flow.ReplicaInfoService; |
66 | -import org.onosproject.store.hz.AbstractHazelcastStore; | 66 | +import org.onosproject.store.impl.ClockService; |
67 | -import org.onosproject.store.hz.SMap; | 67 | +import org.onosproject.store.impl.MastershipBasedTimestamp; |
68 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
68 | import org.onosproject.store.serializers.KryoSerializer; | 69 | import org.onosproject.store.serializers.KryoSerializer; |
69 | import org.onosproject.store.serializers.StoreSerializer; | 70 | import org.onosproject.store.serializers.StoreSerializer; |
70 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; | 71 | import org.onosproject.store.serializers.impl.DistributedStoreSerializers; |
71 | import org.slf4j.Logger; | 72 | import org.slf4j.Logger; |
72 | 73 | ||
73 | import java.io.IOException; | 74 | import java.io.IOException; |
74 | -import java.util.ArrayList; | ||
75 | import java.util.Arrays; | 75 | import java.util.Arrays; |
76 | +import java.util.Collection; | ||
76 | import java.util.Collections; | 77 | import java.util.Collections; |
77 | -import java.util.HashSet; | ||
78 | import java.util.List; | 78 | import java.util.List; |
79 | import java.util.Map; | 79 | import java.util.Map; |
80 | -import java.util.Map.Entry; | ||
81 | import java.util.Set; | 80 | import java.util.Set; |
82 | import java.util.concurrent.ConcurrentHashMap; | 81 | import java.util.concurrent.ConcurrentHashMap; |
83 | import java.util.concurrent.ConcurrentMap; | 82 | import java.util.concurrent.ConcurrentMap; |
... | @@ -90,8 +89,6 @@ import java.util.concurrent.TimeUnit; | ... | @@ -90,8 +89,6 @@ import java.util.concurrent.TimeUnit; |
90 | import java.util.concurrent.TimeoutException; | 89 | import java.util.concurrent.TimeoutException; |
91 | import java.util.stream.Collectors; | 90 | import java.util.stream.Collectors; |
92 | 91 | ||
93 | -import static com.google.common.base.Preconditions.checkNotNull; | ||
94 | -import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked; | ||
95 | import static org.onlab.util.Tools.groupedThreads; | 92 | import static org.onlab.util.Tools.groupedThreads; |
96 | import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; | 93 | import static org.onosproject.net.flow.FlowRuleEvent.Type.RULE_REMOVED; |
97 | import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.*; | 94 | import static org.onosproject.store.flow.impl.FlowStoreMessageSubjects.*; |
... | @@ -103,7 +100,7 @@ import static org.slf4j.LoggerFactory.getLogger; | ... | @@ -103,7 +100,7 @@ import static org.slf4j.LoggerFactory.getLogger; |
103 | @Component(immediate = true) | 100 | @Component(immediate = true) |
104 | @Service | 101 | @Service |
105 | public class DistributedFlowRuleStore | 102 | public class DistributedFlowRuleStore |
106 | - extends AbstractHazelcastStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> | 103 | + extends AbstractStore<FlowRuleBatchEvent, FlowRuleStoreDelegate> |
107 | implements FlowRuleStore { | 104 | implements FlowRuleStore { |
108 | 105 | ||
109 | private final Logger log = getLogger(getClass()); | 106 | private final Logger log = getLogger(getClass()); |
... | @@ -111,10 +108,7 @@ public class DistributedFlowRuleStore | ... | @@ -111,10 +108,7 @@ public class DistributedFlowRuleStore |
111 | // TODO: Make configurable. | 108 | // TODO: Make configurable. |
112 | private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 8; | 109 | private static final int MESSAGE_HANDLER_THREAD_POOL_SIZE = 8; |
113 | 110 | ||
114 | - private InternalFlowTable flowTable = new InternalFlowTable(); | 111 | + private InternalFlowTable flowTable; |
115 | - | ||
116 | - /*private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>> | ||
117 | - flowEntries = new ConcurrentHashMap<>();*/ | ||
118 | 112 | ||
119 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 113 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
120 | protected ReplicaInfoService replicaInfoManager; | 114 | protected ReplicaInfoService replicaInfoManager; |
... | @@ -129,21 +123,15 @@ public class DistributedFlowRuleStore | ... | @@ -129,21 +123,15 @@ public class DistributedFlowRuleStore |
129 | protected DeviceService deviceService; | 123 | protected DeviceService deviceService; |
130 | 124 | ||
131 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 125 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
126 | + protected DeviceClockService deviceClockService; | ||
127 | + | ||
128 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
132 | protected CoreService coreService; | 129 | protected CoreService coreService; |
133 | 130 | ||
134 | private Map<Long, NodeId> pendingResponses = Maps.newConcurrentMap(); | 131 | private Map<Long, NodeId> pendingResponses = Maps.newConcurrentMap(); |
135 | 132 | ||
136 | - // Cache of SMaps used for backup data. each SMap contain device flow table | ||
137 | - private LoadingCache<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> smaps; | ||
138 | - | ||
139 | private ExecutorService messageHandlingExecutor; | 133 | private ExecutorService messageHandlingExecutor; |
140 | 134 | ||
141 | - private final ExecutorService backupExecutors = | ||
142 | - BoundedThreadPool.newSingleThreadExecutor(groupedThreads("onos/flow", "async-backups")); | ||
143 | - //Executors.newSingleThreadExecutor(groupedThreads("onos/flow", "async-backups")); | ||
144 | - | ||
145 | - private boolean syncBackup = false; | ||
146 | - | ||
147 | protected static final StoreSerializer SERIALIZER = new KryoSerializer() { | 135 | protected static final StoreSerializer SERIALIZER = new KryoSerializer() { |
148 | @Override | 136 | @Override |
149 | protected void setupKryoPool() { | 137 | protected void setupKryoPool() { |
... | @@ -162,20 +150,13 @@ public class DistributedFlowRuleStore | ... | @@ -162,20 +150,13 @@ public class DistributedFlowRuleStore |
162 | 150 | ||
163 | private IdGenerator idGenerator; | 151 | private IdGenerator idGenerator; |
164 | 152 | ||
165 | - @Override | ||
166 | @Activate | 153 | @Activate |
167 | public void activate() { | 154 | public void activate() { |
168 | 155 | ||
169 | - super.serializer = SERIALIZER; | 156 | + flowTable = new InternalFlowTable(); |
170 | - super.theInstance = storeService.getHazelcastInstance(); | ||
171 | 157 | ||
172 | idGenerator = coreService.getIdGenerator(FlowRuleService.FLOW_OP_TOPIC); | 158 | idGenerator = coreService.getIdGenerator(FlowRuleService.FLOW_OP_TOPIC); |
173 | 159 | ||
174 | - // Cache to create SMap on demand | ||
175 | - smaps = CacheBuilder.newBuilder() | ||
176 | - .softValues() | ||
177 | - .build(new SMapLoader()); | ||
178 | - | ||
179 | final NodeId local = clusterService.getLocalNode().id(); | 160 | final NodeId local = clusterService.getLocalNode().id(); |
180 | 161 | ||
181 | messageHandlingExecutor = Executors.newFixedThreadPool( | 162 | messageHandlingExecutor = Executors.newFixedThreadPool( |
... | @@ -214,7 +195,7 @@ public class DistributedFlowRuleStore | ... | @@ -214,7 +195,7 @@ public class DistributedFlowRuleStore |
214 | public void handle(ClusterMessage message) { | 195 | public void handle(ClusterMessage message) { |
215 | DeviceId deviceId = SERIALIZER.decode(message.payload()); | 196 | DeviceId deviceId = SERIALIZER.decode(message.payload()); |
216 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); | 197 | log.trace("Received get flow entries request for {} from {}", deviceId, message.sender()); |
217 | - Set<FlowEntry> flowEntries = flowTable.getFlowEntries(deviceId); | 198 | + Set<StoredFlowEntry> flowEntries = flowTable.getFlowEntries(deviceId); |
218 | try { | 199 | try { |
219 | message.respond(SERIALIZER.encode(flowEntries)); | 200 | message.respond(SERIALIZER.encode(flowEntries)); |
220 | } catch (IOException e) { | 201 | } catch (IOException e) { |
... | @@ -315,7 +296,7 @@ public class DistributedFlowRuleStore | ... | @@ -315,7 +296,7 @@ public class DistributedFlowRuleStore |
315 | } | 296 | } |
316 | 297 | ||
317 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { | 298 | if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { |
318 | - return flowTable.getFlowEntries(deviceId); | 299 | + return flowTable.getFlowEntries(deviceId).stream().collect(Collectors.toSet()); |
319 | } | 300 | } |
320 | 301 | ||
321 | log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", | 302 | log.trace("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", |
... | @@ -412,7 +393,6 @@ public class DistributedFlowRuleStore | ... | @@ -412,7 +393,6 @@ public class DistributedFlowRuleStore |
412 | new CompletedBatchOperation(true, Collections.emptySet(), did))); | 393 | new CompletedBatchOperation(true, Collections.emptySet(), did))); |
413 | return; | 394 | return; |
414 | } | 395 | } |
415 | - updateBackup(did, currentOps); | ||
416 | 396 | ||
417 | notifyDelegate(FlowRuleBatchEvent.requested(new | 397 | notifyDelegate(FlowRuleBatchEvent.requested(new |
418 | FlowRuleBatchRequest(operation.id(), | 398 | FlowRuleBatchRequest(operation.id(), |
... | @@ -451,19 +431,6 @@ public class DistributedFlowRuleStore | ... | @@ -451,19 +431,6 @@ public class DistributedFlowRuleStore |
451 | ).filter(op -> op != null).collect(Collectors.toSet()); | 431 | ).filter(op -> op != null).collect(Collectors.toSet()); |
452 | } | 432 | } |
453 | 433 | ||
454 | - private void updateBackup(DeviceId deviceId, final Set<FlowRuleBatchEntry> entries) { | ||
455 | - Future<?> backup = backupExecutors.submit(new UpdateBackup(deviceId, entries)); | ||
456 | - | ||
457 | - if (syncBackup) { | ||
458 | - // wait for backup to complete | ||
459 | - try { | ||
460 | - backup.get(); | ||
461 | - } catch (InterruptedException | ExecutionException e) { | ||
462 | - log.error("Failed to create backups", e); | ||
463 | - } | ||
464 | - } | ||
465 | - } | ||
466 | - | ||
467 | @Override | 434 | @Override |
468 | public void deleteFlowRule(FlowRule rule) { | 435 | public void deleteFlowRule(FlowRule rule) { |
469 | storeBatch( | 436 | storeBatch( |
... | @@ -479,7 +446,7 @@ public class DistributedFlowRuleStore | ... | @@ -479,7 +446,7 @@ public class DistributedFlowRuleStore |
479 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); | 446 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); |
480 | final NodeId localId = clusterService.getLocalNode().id(); | 447 | final NodeId localId = clusterService.getLocalNode().id(); |
481 | if (localId.equals(replicaInfo.master().orNull())) { | 448 | if (localId.equals(replicaInfo.master().orNull())) { |
482 | - return addOrUpdateFlowRuleInternal(rule); | 449 | + return addOrUpdateFlowRuleInternal((StoredFlowEntry) rule); |
483 | } | 450 | } |
484 | 451 | ||
485 | log.warn("Tried to update FlowRule {} state," | 452 | log.warn("Tried to update FlowRule {} state," |
... | @@ -487,10 +454,7 @@ public class DistributedFlowRuleStore | ... | @@ -487,10 +454,7 @@ public class DistributedFlowRuleStore |
487 | return null; | 454 | return null; |
488 | } | 455 | } |
489 | 456 | ||
490 | - private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { | 457 | + private FlowRuleEvent addOrUpdateFlowRuleInternal(StoredFlowEntry rule) { |
491 | - final DeviceId did = rule.deviceId(); | ||
492 | - | ||
493 | - | ||
494 | // check if this new rule is an update to an existing entry | 458 | // check if this new rule is an update to an existing entry |
495 | StoredFlowEntry stored = flowTable.getFlowEntry(rule); | 459 | StoredFlowEntry stored = flowTable.getFlowEntry(rule); |
496 | if (stored != null) { | 460 | if (stored != null) { |
... | @@ -499,21 +463,15 @@ public class DistributedFlowRuleStore | ... | @@ -499,21 +463,15 @@ public class DistributedFlowRuleStore |
499 | stored.setPackets(rule.packets()); | 463 | stored.setPackets(rule.packets()); |
500 | if (stored.state() == FlowEntryState.PENDING_ADD) { | 464 | if (stored.state() == FlowEntryState.PENDING_ADD) { |
501 | stored.setState(FlowEntryState.ADDED); | 465 | stored.setState(FlowEntryState.ADDED); |
502 | - FlowRuleBatchEntry entry = | ||
503 | - new FlowRuleBatchEntry(FlowRuleOperation.ADD, stored); | ||
504 | - updateBackup(did, Sets.newHashSet(entry)); | ||
505 | return new FlowRuleEvent(Type.RULE_ADDED, rule); | 466 | return new FlowRuleEvent(Type.RULE_ADDED, rule); |
506 | } | 467 | } |
507 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); | 468 | return new FlowRuleEvent(Type.RULE_UPDATED, rule); |
508 | } | 469 | } |
509 | 470 | ||
510 | // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore | 471 | // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore |
511 | - // TODO: also update backup if the behavior is correct. | ||
512 | flowTable.add(rule); | 472 | flowTable.add(rule); |
513 | 473 | ||
514 | - | ||
515 | return null; | 474 | return null; |
516 | - | ||
517 | } | 475 | } |
518 | 476 | ||
519 | @Override | 477 | @Override |
... | @@ -554,9 +512,6 @@ public class DistributedFlowRuleStore | ... | @@ -554,9 +512,6 @@ public class DistributedFlowRuleStore |
554 | final DeviceId deviceId = rule.deviceId(); | 512 | final DeviceId deviceId = rule.deviceId(); |
555 | // This is where one could mark a rule as removed and still keep it in the store. | 513 | // This is where one could mark a rule as removed and still keep it in the store. |
556 | final boolean removed = flowTable.remove(deviceId, rule); //flowEntries.remove(deviceId, rule); | 514 | final boolean removed = flowTable.remove(deviceId, rule); //flowEntries.remove(deviceId, rule); |
557 | - FlowRuleBatchEntry entry = | ||
558 | - new FlowRuleBatchEntry(FlowRuleOperation.REMOVE, rule); | ||
559 | - updateBackup(deviceId, Sets.newHashSet(entry)); | ||
560 | if (removed) { | 515 | if (removed) { |
561 | return new FlowRuleEvent(RULE_REMOVED, rule); | 516 | return new FlowRuleEvent(RULE_REMOVED, rule); |
562 | } else { | 517 | } else { |
... | @@ -583,33 +538,10 @@ public class DistributedFlowRuleStore | ... | @@ -583,33 +538,10 @@ public class DistributedFlowRuleStore |
583 | } | 538 | } |
584 | } | 539 | } |
585 | 540 | ||
586 | - private void loadFromBackup(final DeviceId did) { | ||
587 | - | ||
588 | - | ||
589 | - try { | ||
590 | - log.debug("Loading FlowRules for {} from backups", did); | ||
591 | - SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did); | ||
592 | - for (Entry<FlowId, ImmutableList<StoredFlowEntry>> e | ||
593 | - : backupFlowTable.entrySet()) { | ||
594 | - | ||
595 | - log.trace("loading {}", e.getValue()); | ||
596 | - for (StoredFlowEntry entry : e.getValue()) { | ||
597 | - flowTable.getFlowEntriesById(entry).remove(entry); | ||
598 | - flowTable.getFlowEntriesById(entry).add(entry); | ||
599 | - | ||
600 | - | ||
601 | - } | ||
602 | - } | ||
603 | - } catch (ExecutionException e) { | ||
604 | - log.error("Failed to load backup flowtable for {}", did, e); | ||
605 | - } | ||
606 | - } | ||
607 | - | ||
608 | private void removeFromPrimary(final DeviceId did) { | 541 | private void removeFromPrimary(final DeviceId did) { |
609 | flowTable.clearDevice(did); | 542 | flowTable.clearDevice(did); |
610 | } | 543 | } |
611 | 544 | ||
612 | - | ||
613 | private final class OnStoreBatch implements ClusterMessageHandler { | 545 | private final class OnStoreBatch implements ClusterMessageHandler { |
614 | private final NodeId local; | 546 | private final NodeId local; |
615 | 547 | ||
... | @@ -626,10 +558,11 @@ public class DistributedFlowRuleStore | ... | @@ -626,10 +558,11 @@ public class DistributedFlowRuleStore |
626 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); | 558 | ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); |
627 | if (!local.equals(replicaInfo.master().orNull())) { | 559 | if (!local.equals(replicaInfo.master().orNull())) { |
628 | 560 | ||
629 | - Set<FlowRule> failures = new HashSet<>(operation.size()); | 561 | + Set<FlowRule> failures = operation.getOperations() |
630 | - for (FlowRuleBatchEntry op : operation.getOperations()) { | 562 | + .stream() |
631 | - failures.add(op.target()); | 563 | + .map(FlowRuleBatchEntry::target) |
632 | - } | 564 | + .collect(Collectors.toSet()); |
565 | + | ||
633 | CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures, deviceId); | 566 | CompletedBatchOperation allFailed = new CompletedBatchOperation(false, failures, deviceId); |
634 | // This node is no longer the master, respond as all failed. | 567 | // This node is no longer the master, respond as all failed. |
635 | // TODO: we might want to wrap response in envelope | 568 | // TODO: we might want to wrap response in envelope |
... | @@ -650,17 +583,6 @@ public class DistributedFlowRuleStore | ... | @@ -650,17 +583,6 @@ public class DistributedFlowRuleStore |
650 | } | 583 | } |
651 | } | 584 | } |
652 | 585 | ||
653 | - private final class SMapLoader | ||
654 | - extends CacheLoader<DeviceId, SMap<FlowId, ImmutableList<StoredFlowEntry>>> { | ||
655 | - | ||
656 | - @Override | ||
657 | - public SMap<FlowId, ImmutableList<StoredFlowEntry>> load(DeviceId id) | ||
658 | - throws Exception { | ||
659 | - IMap<byte[], byte[]> map = theInstance.getMap("flowtable_" + id.toString()); | ||
660 | - return new SMap<FlowId, ImmutableList<StoredFlowEntry>>(map, SERIALIZER); | ||
661 | - } | ||
662 | - } | ||
663 | - | ||
664 | private final class InternalReplicaInfoEventListener | 586 | private final class InternalReplicaInfoEventListener |
665 | implements ReplicaInfoEventListener { | 587 | implements ReplicaInfoEventListener { |
666 | 588 | ||
... | @@ -673,9 +595,10 @@ public class DistributedFlowRuleStore | ... | @@ -673,9 +595,10 @@ public class DistributedFlowRuleStore |
673 | switch (event.type()) { | 595 | switch (event.type()) { |
674 | case MASTER_CHANGED: | 596 | case MASTER_CHANGED: |
675 | if (local.equals(rInfo.master().orNull())) { | 597 | if (local.equals(rInfo.master().orNull())) { |
598 | + log.info("{} is now the master for {}. Will load flow rules from backup", local, did); | ||
676 | // This node is the new master, populate local structure | 599 | // This node is the new master, populate local structure |
677 | // from backup | 600 | // from backup |
678 | - loadFromBackup(did); | 601 | + flowTable.loadFromBackup(did); |
679 | } | 602 | } |
680 | //else { | 603 | //else { |
681 | // This node is no longer the master holder, | 604 | // This node is no longer the master holder, |
... | @@ -692,146 +615,122 @@ public class DistributedFlowRuleStore | ... | @@ -692,146 +615,122 @@ public class DistributedFlowRuleStore |
692 | } | 615 | } |
693 | } | 616 | } |
694 | 617 | ||
695 | - // Task to update FlowEntries in backup HZ store | 618 | + private class InternalFlowTable { |
696 | - private final class UpdateBackup implements Runnable { | ||
697 | - | ||
698 | - private final DeviceId deviceId; | ||
699 | - private final Set<FlowRuleBatchEntry> ops; | ||
700 | - | ||
701 | 619 | ||
702 | - public UpdateBackup(DeviceId deviceId, | 620 | + private final Map<DeviceId, Map<FlowId, Set<StoredFlowEntry>>> |
703 | - Set<FlowRuleBatchEntry> ops) { | 621 | + flowEntries = Maps.newConcurrentMap(); |
704 | - this.deviceId = checkNotNull(deviceId); | ||
705 | - this.ops = checkNotNull(ops); | ||
706 | 622 | ||
707 | - } | 623 | + private final KryoNamespace.Builder flowSerializer = KryoNamespace.newBuilder() |
708 | - | 624 | + .register(KryoNamespaces.API) |
709 | - @Override | 625 | + .register(MastershipBasedTimestamp.class); |
710 | - public void run() { | ||
711 | - try { | ||
712 | - log.trace("update backup {} {}", deviceId, ops | ||
713 | - ); | ||
714 | - final SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(deviceId); | ||
715 | - | ||
716 | - | ||
717 | - ops.stream().forEach( | ||
718 | - op -> { | ||
719 | - final FlowRule entry = op.target(); | ||
720 | - final FlowId id = entry.id(); | ||
721 | - ImmutableList<StoredFlowEntry> original = backupFlowTable.get(id); | ||
722 | - List<StoredFlowEntry> list = new ArrayList<>(); | ||
723 | - if (original != null) { | ||
724 | - list.addAll(original); | ||
725 | - } | ||
726 | - list.remove(op.target()); | ||
727 | - if (op.operator() == FlowRuleOperation.ADD) { | ||
728 | - list.add((StoredFlowEntry) entry); | ||
729 | - } | ||
730 | 626 | ||
731 | - ImmutableList<StoredFlowEntry> newValue = ImmutableList.copyOf(list); | 627 | + private final ClockService<FlowId, StoredFlowEntry> clockService = |
732 | - boolean success; | 628 | + new ClockService<FlowId, StoredFlowEntry>() { |
733 | - if (original == null) { | 629 | + @Override |
734 | - success = (backupFlowTable.putIfAbsent(id, newValue) == null); | 630 | + public Timestamp getTimestamp(FlowId flowId, StoredFlowEntry flowEntry) { |
735 | - } else { | 631 | + if (flowEntry == null) { |
736 | - success = backupFlowTable.replace(id, original, newValue); | 632 | + return null; |
737 | - } | 633 | + } |
738 | - if (!success) { | 634 | + return deviceClockService.getTimestamp(flowEntry.deviceId()); |
739 | - log.error("Updating backup failed."); | 635 | + } |
740 | - } | 636 | + }; |
741 | - | 637 | + |
742 | - } | 638 | + private final EventuallyConsistentMap<FlowId, StoredFlowEntry> backupMap = |
743 | - ); | 639 | + new EventuallyConsistentMapImpl<>("flow-backup", |
744 | - } catch (ExecutionException e) { | 640 | + clusterService, |
745 | - log.error("Failed to write to backups", e); | 641 | + clusterCommunicator, |
642 | + flowSerializer, | ||
643 | + clockService, | ||
644 | + (key, flowEntry) -> getPeerNodes()); | ||
645 | + | ||
646 | + private Collection<NodeId> getPeerNodes() { | ||
647 | + List<NodeId> nodes = clusterService.getNodes() | ||
648 | + .stream() | ||
649 | + .map(node -> node.id()) | ||
650 | + .filter(id -> !id.equals(clusterService.getLocalNode().id())) | ||
651 | + .collect(Collectors.toList()); | ||
652 | + | ||
653 | + if (nodes.isEmpty()) { | ||
654 | + return ImmutableList.of(); | ||
655 | + } else { | ||
656 | + Collections.shuffle(nodes); | ||
657 | + return ImmutableList.of(nodes.get(0)); | ||
746 | } | 658 | } |
747 | - | ||
748 | } | 659 | } |
749 | - } | ||
750 | - | ||
751 | - private class InternalFlowTable { | ||
752 | - | ||
753 | - /* | ||
754 | - TODO: This needs to be cleaned up. Perhaps using the eventually consistent | ||
755 | - map when it supports distributed to a sequence of instances. | ||
756 | - */ | ||
757 | - | ||
758 | 660 | ||
759 | - private final ConcurrentMap<DeviceId, ConcurrentMap<FlowId, Set<StoredFlowEntry>>> | 661 | + public void loadFromBackup(DeviceId deviceId) { |
760 | - flowEntries = new ConcurrentHashMap<>(); | 662 | + ConcurrentMap<FlowId, Set<StoredFlowEntry>> flowTable = new ConcurrentHashMap<>(); |
761 | 663 | ||
762 | - | 664 | + backupMap.values() |
763 | - private NewConcurrentHashMap<FlowId, Set<StoredFlowEntry>> lazyEmptyFlowTable() { | 665 | + .stream() |
764 | - return NewConcurrentHashMap.<FlowId, Set<StoredFlowEntry>>ifNeeded(); | 666 | + .filter(entry -> entry.deviceId().equals(deviceId)) |
765 | - } | 667 | + .forEach(entry -> flowTable.computeIfPresent(entry.id(), (k, v) -> { |
766 | - | 668 | + if (v == null) { |
767 | - /** | 669 | + return Sets.newHashSet(entry); |
768 | - * Returns the flow table for specified device. | 670 | + } else { |
769 | - * | 671 | + v.add(entry); |
770 | - * @param deviceId identifier of the device | 672 | + } |
771 | - * @return Map representing Flow Table of given device. | 673 | + return v; |
772 | - */ | 674 | + })); |
773 | - private ConcurrentMap<FlowId, Set<StoredFlowEntry>> getFlowTable(DeviceId deviceId) { | 675 | + flowEntries.putIfAbsent(deviceId, flowTable); |
774 | - return createIfAbsentUnchecked(flowEntries, | ||
775 | - deviceId, lazyEmptyFlowTable()); | ||
776 | } | 676 | } |
777 | 677 | ||
778 | private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) { | 678 | private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) { |
779 | - final ConcurrentMap<FlowId, Set<StoredFlowEntry>> flowTable = getFlowTable(deviceId); | 679 | + return flowEntries |
780 | - Set<StoredFlowEntry> r = flowTable.get(flowId); | 680 | + .computeIfAbsent(deviceId, key -> Maps.newConcurrentMap()) |
781 | - if (r == null) { | 681 | + .computeIfAbsent(flowId, k -> new CopyOnWriteArraySet<>()); |
782 | - final Set<StoredFlowEntry> concurrentlyAdded; | ||
783 | - r = new CopyOnWriteArraySet<>(); | ||
784 | - concurrentlyAdded = flowTable.putIfAbsent(flowId, r); | ||
785 | - if (concurrentlyAdded != null) { | ||
786 | - return concurrentlyAdded; | ||
787 | - } | ||
788 | - } | ||
789 | - return r; | ||
790 | } | 682 | } |
791 | 683 | ||
792 | private StoredFlowEntry getFlowEntryInternal(FlowRule rule) { | 684 | private StoredFlowEntry getFlowEntryInternal(FlowRule rule) { |
793 | - for (StoredFlowEntry f : getFlowEntriesInternal(rule.deviceId(), rule.id())) { | 685 | + return getFlowEntriesInternal(rule.deviceId(), rule.id()) |
794 | - if (f.equals(rule)) { | 686 | + .stream() |
795 | - return f; | 687 | + .filter(element -> element.equals(rule)) |
796 | - } | 688 | + .findFirst() |
797 | - } | 689 | + .orElse(null); |
798 | - return null; | ||
799 | } | 690 | } |
800 | 691 | ||
801 | - private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) { | 692 | + private Set<StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId) { |
802 | - return getFlowTable(deviceId).values().stream() | 693 | + Set<StoredFlowEntry> entries = Sets.newHashSet(); |
803 | - .flatMap((list -> list.stream())).collect(Collectors.toSet()); | 694 | + flowEntries.computeIfAbsent(deviceId, key -> Maps.newConcurrentMap()) |
804 | - | 695 | + .values() |
696 | + .forEach(entries::addAll); | ||
697 | + return entries; | ||
805 | } | 698 | } |
806 | 699 | ||
807 | - | ||
808 | public StoredFlowEntry getFlowEntry(FlowRule rule) { | 700 | public StoredFlowEntry getFlowEntry(FlowRule rule) { |
809 | return getFlowEntryInternal(rule); | 701 | return getFlowEntryInternal(rule); |
810 | } | 702 | } |
811 | 703 | ||
812 | - public Set<FlowEntry> getFlowEntries(DeviceId deviceId) { | 704 | + public Set<StoredFlowEntry> getFlowEntries(DeviceId deviceId) { |
813 | return getFlowEntriesInternal(deviceId); | 705 | return getFlowEntriesInternal(deviceId); |
814 | } | 706 | } |
815 | 707 | ||
816 | - public Set<StoredFlowEntry> getFlowEntriesById(FlowEntry entry) { | 708 | + public void add(StoredFlowEntry rule) { |
817 | - return getFlowEntriesInternal(entry.deviceId(), entry.id()); | 709 | + getFlowEntriesInternal(rule.deviceId(), rule.id()).add(rule); |
818 | - } | ||
819 | 710 | ||
820 | - public void add(FlowEntry rule) { | 711 | + try { |
821 | - ((CopyOnWriteArraySet) | 712 | + backupMap.put(rule.id(), rule); |
822 | - getFlowEntriesInternal(rule.deviceId(), rule.id())).add(rule); | 713 | + } catch (Exception e) { |
714 | + log.warn("Failed to backup flow rule", e); | ||
715 | + } | ||
823 | } | 716 | } |
824 | 717 | ||
825 | public boolean remove(DeviceId deviceId, FlowEntry rule) { | 718 | public boolean remove(DeviceId deviceId, FlowEntry rule) { |
826 | - return ((CopyOnWriteArraySet) | 719 | + boolean status = |
827 | - getFlowEntriesInternal(deviceId, rule.id())).remove(rule); | 720 | + getFlowEntriesInternal(deviceId, rule.id()).remove(rule); |
828 | - //return flowEntries.remove(deviceId, rule); | 721 | + if (status) { |
722 | + try { | ||
723 | + backupMap.remove(rule.id(), (DefaultFlowEntry) rule); | ||
724 | + } catch (Exception e) { | ||
725 | + log.warn("Failed to remove backup of flow rule", e); | ||
726 | + } | ||
727 | + } | ||
728 | + return status; | ||
829 | } | 729 | } |
830 | 730 | ||
831 | public void clearDevice(DeviceId did) { | 731 | public void clearDevice(DeviceId did) { |
832 | flowEntries.remove(did); | 732 | flowEntries.remove(did); |
733 | + // Flow entries should continue to remain in backup map. | ||
833 | } | 734 | } |
834 | } | 735 | } |
835 | - | 736 | +} |
836 | - | ||
837 | -} | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment