Yuta HIGUCHI
Committed by Yuta Higuchi

DistributedFlowRuleStore: synchronized -> Reader/Writer lock

fix for ONOS-195

Change-Id: I3e15104225878d1616fa790095695400bcc43697
...@@ -60,6 +60,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe ...@@ -60,6 +60,7 @@ public interface FlowRuleStore extends Store<FlowRuleBatchEvent, FlowRuleStoreDe
60 * Stores a batch of flow rules. 60 * Stores a batch of flow rules.
61 * 61 *
62 * @param batchOperation batch of flow rules. 62 * @param batchOperation batch of flow rules.
63 + * A batch can contain flow rules for a single device only.
63 * @return Future response indicating success/failure of the batch operation 64 * @return Future response indicating success/failure of the batch operation
64 * all the way down to the device. 65 * all the way down to the device.
65 */ 66 */
......
...@@ -36,6 +36,7 @@ import java.util.concurrent.Future; ...@@ -36,6 +36,7 @@ import java.util.concurrent.Future;
36 import java.util.concurrent.TimeUnit; 36 import java.util.concurrent.TimeUnit;
37 import java.util.concurrent.TimeoutException; 37 import java.util.concurrent.TimeoutException;
38 import java.util.concurrent.atomic.AtomicInteger; 38 import java.util.concurrent.atomic.AtomicInteger;
39 +import java.util.concurrent.locks.ReentrantReadWriteLock;
39 import java.util.List; 40 import java.util.List;
40 41
41 import org.apache.felix.scr.annotations.Activate; 42 import org.apache.felix.scr.annotations.Activate;
...@@ -109,7 +110,8 @@ public class DistributedFlowRuleStore ...@@ -109,7 +110,8 @@ public class DistributedFlowRuleStore
109 private final Logger log = getLogger(getClass()); 110 private final Logger log = getLogger(getClass());
110 111
111 // primary data: 112 // primary data:
112 - // read/write needs to be synchronized 113 + // read/write needs to be locked
114 + private final ReentrantReadWriteLock flowEntriesLock = new ReentrantReadWriteLock();
113 // store entries as a pile of rules, no info about device tables 115 // store entries as a pile of rules, no info about device tables
114 private final Multimap<DeviceId, StoredFlowEntry> flowEntries 116 private final Multimap<DeviceId, StoredFlowEntry> flowEntries
115 = ArrayListMultimap.<DeviceId, StoredFlowEntry>create(); 117 = ArrayListMultimap.<DeviceId, StoredFlowEntry>create();
...@@ -186,7 +188,7 @@ public class DistributedFlowRuleStore ...@@ -186,7 +188,7 @@ public class DistributedFlowRuleStore
186 @Override 188 @Override
187 public void handle(ClusterMessage message) { 189 public void handle(ClusterMessage message) {
188 FlowRule rule = SERIALIZER.decode(message.payload()); 190 FlowRule rule = SERIALIZER.decode(message.payload());
189 - log.info("received get flow entry request for {}", rule); 191 + log.debug("received get flow entry request for {}", rule);
190 FlowEntry flowEntry = getFlowEntryInternal(rule); 192 FlowEntry flowEntry = getFlowEntryInternal(rule);
191 try { 193 try {
192 message.respond(SERIALIZER.encode(flowEntry)); 194 message.respond(SERIALIZER.encode(flowEntry));
...@@ -201,7 +203,7 @@ public class DistributedFlowRuleStore ...@@ -201,7 +203,7 @@ public class DistributedFlowRuleStore
201 @Override 203 @Override
202 public void handle(ClusterMessage message) { 204 public void handle(ClusterMessage message) {
203 DeviceId deviceId = SERIALIZER.decode(message.payload()); 205 DeviceId deviceId = SERIALIZER.decode(message.payload());
204 - log.info("Received get flow entries request for {} from {}", deviceId, message.sender()); 206 + log.debug("Received get flow entries request for {} from {}", deviceId, message.sender());
205 Set<FlowEntry> flowEntries = getFlowEntriesInternal(deviceId); 207 Set<FlowEntry> flowEntries = getFlowEntriesInternal(deviceId);
206 try { 208 try {
207 message.respond(SERIALIZER.encode(flowEntries)); 209 message.respond(SERIALIZER.encode(flowEntries));
...@@ -240,21 +242,20 @@ public class DistributedFlowRuleStore ...@@ -240,21 +242,20 @@ public class DistributedFlowRuleStore
240 } 242 }
241 243
242 @Override 244 @Override
243 - public synchronized FlowEntry getFlowEntry(FlowRule rule) { 245 + public FlowEntry getFlowEntry(FlowRule rule) {
244 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId()); 246 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(rule.deviceId());
245 247
246 if (!replicaInfo.master().isPresent()) { 248 if (!replicaInfo.master().isPresent()) {
247 log.warn("No master for {}", rule); 249 log.warn("No master for {}", rule);
248 - // TODO: revisit if this should be returning null. 250 + // TODO: should we try returning from backup?
249 - // FIXME: throw a FlowStoreException 251 + return null;
250 - throw new RuntimeException("No master for " + rule);
251 } 252 }
252 253
253 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) { 254 if (replicaInfo.master().get().equals(clusterService.getLocalNode().id())) {
254 return getFlowEntryInternal(rule); 255 return getFlowEntryInternal(rule);
255 } 256 }
256 257
257 - log.info("Forwarding getFlowEntry to {}, which is the primary (master) for device {}", 258 + log.debug("Forwarding getFlowEntry to {}, which is the primary (master) for device {}",
258 replicaInfo.master().orNull(), rule.deviceId()); 259 replicaInfo.master().orNull(), rule.deviceId());
259 260
260 ClusterMessage message = new ClusterMessage( 261 ClusterMessage message = new ClusterMessage(
...@@ -271,25 +272,28 @@ public class DistributedFlowRuleStore ...@@ -271,25 +272,28 @@ public class DistributedFlowRuleStore
271 } 272 }
272 } 273 }
273 274
274 - private synchronized StoredFlowEntry getFlowEntryInternal(FlowRule rule) { 275 + private StoredFlowEntry getFlowEntryInternal(FlowRule rule) {
276 + flowEntriesLock.readLock().lock();
277 + try {
275 for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) { 278 for (StoredFlowEntry f : flowEntries.get(rule.deviceId())) {
276 if (f.equals(rule)) { 279 if (f.equals(rule)) {
277 return f; 280 return f;
278 } 281 }
279 } 282 }
283 + } finally {
284 + flowEntriesLock.readLock().unlock();
285 + }
280 return null; 286 return null;
281 } 287 }
282 288
283 @Override 289 @Override
284 - public synchronized Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) { 290 + public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
285 291
286 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId); 292 ReplicaInfo replicaInfo = replicaInfoManager.getReplicaInfoFor(deviceId);
287 293
288 if (!replicaInfo.master().isPresent()) { 294 if (!replicaInfo.master().isPresent()) {
289 log.warn("No master for {}", deviceId); 295 log.warn("No master for {}", deviceId);
290 - // TODO: revisit if this should be returning empty collection or throwing exception. 296 + // TODO: should we try returning from backup?
291 - // FIXME: throw a FlowStoreException
292 - //throw new RuntimeException("No master for " + deviceId);
293 return Collections.emptyList(); 297 return Collections.emptyList();
294 } 298 }
295 299
...@@ -297,7 +301,7 @@ public class DistributedFlowRuleStore ...@@ -297,7 +301,7 @@ public class DistributedFlowRuleStore
297 return getFlowEntriesInternal(deviceId); 301 return getFlowEntriesInternal(deviceId);
298 } 302 }
299 303
300 - log.info("Forwarding getFlowEntries to {}, which is the primary (master) for device {}", 304 + log.debug("Forwarding getFlowEntries to {}, which is the primary (master) for device {}",
301 replicaInfo.master().orNull(), deviceId); 305 replicaInfo.master().orNull(), deviceId);
302 306
303 ClusterMessage message = new ClusterMessage( 307 ClusterMessage message = new ClusterMessage(
...@@ -314,12 +318,17 @@ public class DistributedFlowRuleStore ...@@ -314,12 +318,17 @@ public class DistributedFlowRuleStore
314 } 318 }
315 } 319 }
316 320
317 - private synchronized Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) { 321 + private Set<FlowEntry> getFlowEntriesInternal(DeviceId deviceId) {
322 + flowEntriesLock.readLock().lock();
323 + try {
318 Collection<? extends FlowEntry> rules = flowEntries.get(deviceId); 324 Collection<? extends FlowEntry> rules = flowEntries.get(deviceId);
319 if (rules == null) { 325 if (rules == null) {
320 return Collections.emptySet(); 326 return Collections.emptySet();
321 } 327 }
322 return ImmutableSet.copyOf(rules); 328 return ImmutableSet.copyOf(rules);
329 + } finally {
330 + flowEntriesLock.readLock().unlock();
331 + }
323 } 332 }
324 333
325 @Override 334 @Override
...@@ -327,7 +336,6 @@ public class DistributedFlowRuleStore ...@@ -327,7 +336,6 @@ public class DistributedFlowRuleStore
327 storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule)))); 336 storeBatch(new FlowRuleBatchOperation(Arrays.asList(new FlowRuleBatchEntry(FlowRuleOperation.ADD, rule))));
328 } 337 }
329 338
330 - // FIXME document that all of the FlowEntries must be about same device
331 @Override 339 @Override
332 public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) { 340 public Future<CompletedBatchOperation> storeBatch(FlowRuleBatchOperation operation) {
333 341
...@@ -351,7 +359,7 @@ public class DistributedFlowRuleStore ...@@ -351,7 +359,7 @@ public class DistributedFlowRuleStore
351 return storeBatchInternal(operation); 359 return storeBatchInternal(operation);
352 } 360 }
353 361
354 - log.info("Forwarding storeBatch to {}, which is the primary (master) for device {}", 362 + log.debug("Forwarding storeBatch to {}, which is the primary (master) for device {}",
355 replicaInfo.master().orNull(), deviceId); 363 replicaInfo.master().orNull(), deviceId);
356 364
357 ClusterMessage message = new ClusterMessage( 365 ClusterMessage message = new ClusterMessage(
...@@ -368,13 +376,16 @@ public class DistributedFlowRuleStore ...@@ -368,13 +376,16 @@ public class DistributedFlowRuleStore
368 } 376 }
369 } 377 }
370 378
371 - private synchronized ListenableFuture<CompletedBatchOperation> 379 + private ListenableFuture<CompletedBatchOperation>
372 storeBatchInternal(FlowRuleBatchOperation operation) { 380 storeBatchInternal(FlowRuleBatchOperation operation) {
373 381
374 final List<StoredFlowEntry> toRemove = new ArrayList<>(); 382 final List<StoredFlowEntry> toRemove = new ArrayList<>();
375 final List<StoredFlowEntry> toAdd = new ArrayList<>(); 383 final List<StoredFlowEntry> toAdd = new ArrayList<>();
376 DeviceId did = null; 384 DeviceId did = null;
377 385
386 +
387 + flowEntriesLock.writeLock().lock();
388 + try {
378 for (FlowRuleBatchEntry batchEntry : operation.getOperations()) { 389 for (FlowRuleBatchEntry batchEntry : operation.getOperations()) {
379 FlowRule flowRule = batchEntry.getTarget(); 390 FlowRule flowRule = batchEntry.getTarget();
380 FlowRuleOperation op = batchEntry.getOperator(); 391 FlowRuleOperation op = batchEntry.getOperator();
...@@ -401,8 +412,10 @@ public class DistributedFlowRuleStore ...@@ -401,8 +412,10 @@ public class DistributedFlowRuleStore
401 } 412 }
402 413
403 // create remote backup copies 414 // create remote backup copies
404 - final DeviceId deviceId = did; 415 + updateBackup(did, toAdd, toRemove);
405 - updateBackup(deviceId, toAdd, toRemove); 416 + } finally {
417 + flowEntriesLock.writeLock().unlock();
418 + }
406 419
407 SettableFuture<CompletedBatchOperation> r = SettableFuture.create(); 420 SettableFuture<CompletedBatchOperation> r = SettableFuture.create();
408 final int batchId = localBatchIdGen.incrementAndGet(); 421 final int batchId = localBatchIdGen.incrementAndGet();
...@@ -451,9 +464,11 @@ public class DistributedFlowRuleStore ...@@ -451,9 +464,11 @@ public class DistributedFlowRuleStore
451 return null; 464 return null;
452 } 465 }
453 466
454 - private synchronized FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) { 467 + private FlowRuleEvent addOrUpdateFlowRuleInternal(FlowEntry rule) {
455 final DeviceId did = rule.deviceId(); 468 final DeviceId did = rule.deviceId();
456 469
470 + flowEntriesLock.writeLock().lock();
471 + try {
457 // check if this new rule is an update to an existing entry 472 // check if this new rule is an update to an existing entry
458 StoredFlowEntry stored = getFlowEntryInternal(rule); 473 StoredFlowEntry stored = getFlowEntryInternal(rule);
459 if (stored != null) { 474 if (stored != null) {
...@@ -472,6 +487,9 @@ public class DistributedFlowRuleStore ...@@ -472,6 +487,9 @@ public class DistributedFlowRuleStore
472 // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore 487 // TODO: Confirm if this behavior is correct. See SimpleFlowRuleStore
473 // TODO: also update backup. 488 // TODO: also update backup.
474 flowEntries.put(did, new DefaultFlowEntry(rule)); 489 flowEntries.put(did, new DefaultFlowEntry(rule));
490 + } finally {
491 + flowEntriesLock.writeLock().unlock();
492 + }
475 return null; 493 return null;
476 494
477 } 495 }
...@@ -491,8 +509,10 @@ public class DistributedFlowRuleStore ...@@ -491,8 +509,10 @@ public class DistributedFlowRuleStore
491 return null; 509 return null;
492 } 510 }
493 511
494 - private synchronized FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) { 512 + private FlowRuleEvent removeFlowRuleInternal(FlowEntry rule) {
495 final DeviceId deviceId = rule.deviceId(); 513 final DeviceId deviceId = rule.deviceId();
514 + flowEntriesLock.writeLock().lock();
515 + try {
496 // This is where one could mark a rule as removed and still keep it in the store. 516 // This is where one could mark a rule as removed and still keep it in the store.
497 final boolean removed = flowEntries.remove(deviceId, rule); 517 final boolean removed = flowEntries.remove(deviceId, rule);
498 updateBackup(deviceId, Collections.<StoredFlowEntry>emptyList(), Arrays.asList(rule)); 518 updateBackup(deviceId, Collections.<StoredFlowEntry>emptyList(), Arrays.asList(rule));
...@@ -501,6 +521,9 @@ public class DistributedFlowRuleStore ...@@ -501,6 +521,9 @@ public class DistributedFlowRuleStore
501 } else { 521 } else {
502 return null; 522 return null;
503 } 523 }
524 + } finally {
525 + flowEntriesLock.writeLock().unlock();
526 + }
504 } 527 }
505 528
506 @Override 529 @Override
...@@ -515,9 +538,9 @@ public class DistributedFlowRuleStore ...@@ -515,9 +538,9 @@ public class DistributedFlowRuleStore
515 notifyDelegate(event); 538 notifyDelegate(event);
516 } 539 }
517 540
518 - private synchronized void loadFromBackup(final DeviceId did) { 541 + private void loadFromBackup(final DeviceId did) {
519 - // should relax synchronized condition
520 542
543 + flowEntriesLock.writeLock().lock();
521 try { 544 try {
522 log.info("Loading FlowRules for {} from backups", did); 545 log.info("Loading FlowRules for {} from backups", did);
523 SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did); 546 SMap<FlowId, ImmutableList<StoredFlowEntry>> backupFlowTable = smaps.get(did);
...@@ -534,11 +557,19 @@ public class DistributedFlowRuleStore ...@@ -534,11 +557,19 @@ public class DistributedFlowRuleStore
534 } 557 }
535 } catch (ExecutionException e) { 558 } catch (ExecutionException e) {
536 log.error("Failed to load backup flowtable for {}", did, e); 559 log.error("Failed to load backup flowtable for {}", did, e);
560 + } finally {
561 + flowEntriesLock.writeLock().unlock();
537 } 562 }
538 } 563 }
539 564
540 - private synchronized void removeFromPrimary(final DeviceId did) { 565 + private void removeFromPrimary(final DeviceId did) {
541 - Collection<StoredFlowEntry> removed = flowEntries.removeAll(did); 566 + Collection<StoredFlowEntry> removed = null;
567 + flowEntriesLock.writeLock().lock();
568 + try {
569 + removed = flowEntries.removeAll(did);
570 + } finally {
571 + flowEntriesLock.writeLock().unlock();
572 + }
542 log.debug("removedFromPrimary {}", removed); 573 log.debug("removedFromPrimary {}", removed);
543 } 574 }
544 575
......