Use external null checks to avoid computeIfAbsent calls in FlowRuleStore
Change-Id: Ib5cc1bb77dfcd8f38b52cb175f21e1f1055447a5
diff --git a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
index 204f98f..b89bd58 100644
--- a/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
+++ b/core/store/dist/src/main/java/org/onosproject/store/flow/impl/ECFlowRuleStore.java
@@ -783,43 +783,37 @@
* @return Map representing Flow Table of given device.
*/
private Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> getFlowTable(DeviceId deviceId) {
+ // Use an external get/null check to avoid locks.
+ // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8161372
if (persistenceEnabled) {
- return flowEntries.computeIfAbsent(deviceId, id -> persistenceService
- .<FlowId, Map<StoredFlowEntry, StoredFlowEntry>>persistentMapBuilder()
+ Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> flowTable = flowEntries.get(deviceId);
+ return flowTable != null ? flowTable
+ : flowEntries.computeIfAbsent(deviceId, id ->
+ persistenceService.<FlowId, Map<StoredFlowEntry, StoredFlowEntry>>persistentMapBuilder()
.withName("FlowTable:" + deviceId.toString())
.withSerializer(serializer)
.build());
} else {
- return flowEntries.computeIfAbsent(deviceId, id -> Maps.newConcurrentMap());
+ Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> flowTable = flowEntries.get(deviceId);
+ return flowTable != null ? flowTable
+ : flowEntries.computeIfAbsent(deviceId, id -> Maps.newConcurrentMap());
}
}
private FlowBucket getFlowBucket(BucketId bucketId) {
- if (persistenceEnabled) {
- return new FlowBucket(bucketId, flowEntries.computeIfAbsent(bucketId.deviceId(), id ->
- persistenceService.<FlowId, Map<StoredFlowEntry, StoredFlowEntry>>persistentMapBuilder()
- .withName("FlowTable:" + bucketId.deviceId().toString())
- .withSerializer(serializer)
- .build())
- .entrySet()
- .stream()
- .filter(entry -> isInBucket(entry.getKey(), bucketId.bucket()))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
- } else {
- Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> copy = Maps.newHashMap();
- flowEntries.computeIfAbsent(bucketId.deviceId(), id -> Maps.newConcurrentMap())
- .entrySet()
- .stream()
- .filter(entry -> isInBucket(entry.getKey(), bucketId.bucket()))
- .forEach(entry -> {
- copy.put(entry.getKey(), Maps.newHashMap(entry.getValue()));
- });
- return new FlowBucket(bucketId, copy);
- }
+ return new FlowBucket(bucketId, getFlowTable(bucketId.deviceId())
+ .entrySet()
+ .stream()
+ .filter(entry -> isInBucket(entry.getKey(), bucketId.bucket()))
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
}
private Map<StoredFlowEntry, StoredFlowEntry> getFlowEntriesInternal(DeviceId deviceId, FlowId flowId) {
- return getFlowTable(deviceId).computeIfAbsent(flowId, id -> Maps.newConcurrentMap());
+ // Use an external get/null check to avoid locks.
+ // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8161372
+ Map<FlowId, Map<StoredFlowEntry, StoredFlowEntry>> flowTable = getFlowTable(deviceId);
+ Map<StoredFlowEntry, StoredFlowEntry> flowEntries = flowTable.get(flowId);
+ return flowEntries != null ? flowEntries : flowTable.computeIfAbsent(flowId, id -> Maps.newConcurrentMap());
}
private StoredFlowEntry getFlowEntryInternal(FlowRule rule) {