Madan Jampani
Committed by Gerrit Code Review

Moving Dist flow rule store backup mechanism to use EC Map

Change-Id: I465cc2424004721bf09505ac9cde068884f04940
...@@ -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
......