Merge remote-tracking branch 'origin/master'
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/common/impl/package-info.java b/core/store/dist/src/main/java/org/onlab/onos/store/common/impl/package-info.java
deleted file mode 100644
index 992fd49..0000000
--- a/core/store/dist/src/main/java/org/onlab/onos/store/common/impl/package-info.java
+++ /dev/null
@@ -1,5 +0,0 @@
-/**
- * Common abstractions and facilities for implementing distributed store
- * using gossip protocol.
- */
-package org.onlab.onos.store.common.impl;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceDescriptions.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceDescriptions.java
index 03c293a..43008d2 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceDescriptions.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/DeviceDescriptions.java
@@ -15,7 +15,7 @@
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.store.Timestamp;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 /*
  * Collection of Description of a Device and Ports, given from a Provider.
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
index 2603da1..dac9cbc 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/GossipDeviceStore.java
@@ -38,7 +38,7 @@
 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
 import org.onlab.onos.store.cluster.messaging.MessageSubject;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 import org.onlab.onos.store.serializers.KryoSerializer;
 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
 import org.onlab.util.KryoPool;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InitDeviceDescs.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InitDeviceDescs.java
deleted file mode 100644
index 936723a..0000000
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InitDeviceDescs.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package org.onlab.onos.store.device.impl;
-
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import org.apache.commons.lang3.concurrent.ConcurrentException;
-import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
-import org.onlab.onos.net.device.DeviceDescription;
-import org.onlab.onos.store.common.impl.Timestamped;
-
-// FIXME: consider removing this class
-public final class InitDeviceDescs
-    implements ConcurrentInitializer<DeviceDescriptions> {
-
-    private final Timestamped<DeviceDescription> deviceDesc;
-
-    public InitDeviceDescs(Timestamped<DeviceDescription> deviceDesc) {
-        this.deviceDesc = checkNotNull(deviceDesc);
-    }
-    @Override
-    public DeviceDescriptions get() throws ConcurrentException {
-        return new DeviceDescriptions(deviceDesc);
-    }
-}
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEvent.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEvent.java
index 344fe73..623a6b1 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEvent.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEvent.java
@@ -3,7 +3,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.google.common.base.MoreObjects;
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
index 0d3d013..5f97afd 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalDeviceEventSerializer.java
@@ -3,7 +3,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.DeviceDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.Serializer;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEvent.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEvent.java
index d1fc73a..e036ec6 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEvent.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEvent.java
@@ -5,7 +5,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.google.common.base.MoreObjects;
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
index 6fff395..4f4a9e6 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortEventSerializer.java
@@ -5,7 +5,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.Serializer;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEvent.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEvent.java
index fd154da..ff59ab0 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEvent.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEvent.java
@@ -3,7 +3,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.google.common.base.MoreObjects;
 
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEventSerializer.java b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEventSerializer.java
index 8f0c2b0..9d2db47 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEventSerializer.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/device/impl/InternalPortStatusEventSerializer.java
@@ -3,7 +3,7 @@
 import org.onlab.onos.net.DeviceId;
 import org.onlab.onos.net.device.PortDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 import com.esotericsoftware.kryo.Kryo;
 import com.esotericsoftware.kryo.Serializer;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
index 4025d0c..202958e 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/host/impl/GossipHostStore.java
@@ -38,7 +38,7 @@
 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
 import org.onlab.onos.store.cluster.messaging.MessageSubject;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
 import org.onlab.onos.store.serializers.KryoSerializer;
 import org.onlab.packet.IpPrefix;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/common/impl/Timestamped.java b/core/store/dist/src/main/java/org/onlab/onos/store/impl/Timestamped.java
similarity index 88%
rename from core/store/dist/src/main/java/org/onlab/onos/store/common/impl/Timestamped.java
rename to core/store/dist/src/main/java/org/onlab/onos/store/impl/Timestamped.java
index 8d2aee1..ae79831 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/common/impl/Timestamped.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/impl/Timestamped.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.store.common.impl;
+package org.onlab.onos.store.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -58,12 +58,12 @@
     }
 
     /**
-     * Tests if this timestamp is newer thatn the specified timestamp.
-     * @param timestamp to compare agains
+     * Tests if this timestamp is newer than the specified timestamp.
+     * @param other timestamp to compare against
      * @return true if this instance is newer
      */
-    public boolean isNewer(Timestamp timestamp) {
-        return this.timestamp.compareTo(checkNotNull(timestamp)) > 0;
+    public boolean isNewer(Timestamp other) {
+        return this.timestamp.compareTo(checkNotNull(other)) > 0;
     }
 
     @Override
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
index 6e8a367..f9cb71c 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/GossipLinkStore.java
@@ -39,7 +39,7 @@
 import org.onlab.onos.store.cluster.messaging.ClusterMessage;
 import org.onlab.onos.store.cluster.messaging.ClusterMessageHandler;
 import org.onlab.onos.store.cluster.messaging.MessageSubject;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 import org.onlab.onos.store.serializers.DistributedStoreSerializers;
 import org.onlab.onos.store.serializers.KryoSerializer;
 import org.onlab.util.KryoPool;
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/InternalLinkEvent.java b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/InternalLinkEvent.java
index 9bb3445..74694ba 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/InternalLinkEvent.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/link/impl/InternalLinkEvent.java
@@ -4,7 +4,7 @@
 
 import org.onlab.onos.net.link.LinkDescription;
 import org.onlab.onos.net.provider.ProviderId;
-import org.onlab.onos.store.common.impl.Timestamped;
+import org.onlab.onos.store.impl.Timestamped;
 
 /**
  * Information published by GossipDeviceStore to notify peers of a device
diff --git a/core/store/dist/src/main/java/org/onlab/onos/store/serializers/DistributedStoreSerializers.java b/core/store/dist/src/main/java/org/onlab/onos/store/serializers/DistributedStoreSerializers.java
index a04539b..114150f 100644
--- a/core/store/dist/src/main/java/org/onlab/onos/store/serializers/DistributedStoreSerializers.java
+++ b/core/store/dist/src/main/java/org/onlab/onos/store/serializers/DistributedStoreSerializers.java
@@ -1,7 +1,7 @@
 package org.onlab.onos.store.serializers;
 
-import org.onlab.onos.store.common.impl.Timestamped;
 import org.onlab.onos.store.impl.MastershipBasedTimestamp;
+import org.onlab.onos.store.impl.Timestamped;
 import org.onlab.onos.store.impl.WallClockTimestamp;
 import org.onlab.util.KryoPool;
 
diff --git a/core/store/dist/src/test/java/org/onlab/onos/store/common/impl/TimestampedTest.java b/core/store/dist/src/test/java/org/onlab/onos/store/impl/TimestampedTest.java
similarity index 96%
rename from core/store/dist/src/test/java/org/onlab/onos/store/common/impl/TimestampedTest.java
rename to core/store/dist/src/test/java/org/onlab/onos/store/impl/TimestampedTest.java
index deb3e4d..3e7fec2 100644
--- a/core/store/dist/src/test/java/org/onlab/onos/store/common/impl/TimestampedTest.java
+++ b/core/store/dist/src/test/java/org/onlab/onos/store/impl/TimestampedTest.java
@@ -1,4 +1,4 @@
-package org.onlab.onos.store.common.impl;
+package org.onlab.onos.store.impl;
 
 import static org.junit.Assert.*;
 
@@ -6,7 +6,6 @@
 
 import org.junit.Test;
 import org.onlab.onos.store.Timestamp;
-import org.onlab.onos.store.impl.MastershipBasedTimestamp;
 import org.onlab.util.KryoPool;
 
 import com.google.common.testing.EqualsTester;
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
index 514a22e..30904ba 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleDeviceStore.java
@@ -5,8 +5,6 @@
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 
-import org.apache.commons.lang3.concurrent.ConcurrentException;
-import org.apache.commons.lang3.concurrent.ConcurrentInitializer;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -35,6 +33,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -71,8 +70,7 @@
     public static final String DEVICE_NOT_FOUND = "Device with ID %s not found";
 
     // collection of Description given from various providers
-    private final ConcurrentMap<DeviceId,
-                            ConcurrentMap<ProviderId, DeviceDescriptions>>
+    private final ConcurrentMap<DeviceId, Map<ProviderId, DeviceDescriptions>>
                                 deviceDescs = Maps.newConcurrentMap();
 
     // cache of Device and Ports generated by compositing descriptions from providers
@@ -117,15 +115,16 @@
                                      DeviceId deviceId,
                                      DeviceDescription deviceDescription) {
 
-        ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs
-            = getDeviceDescriptions(deviceId);
+        Map<ProviderId, DeviceDescriptions> providerDescs
+            = getOrCreateDeviceDescriptions(deviceId);
 
         synchronized (providerDescs) {
             // locking per device
 
             DeviceDescriptions descs
-                = createIfAbsentUnchecked(providerDescs, providerId,
-                        new InitDeviceDescs(deviceDescription));
+                = getOrCreateProviderDeviceDescriptions(providerDescs,
+                                                        providerId,
+                                                        deviceDescription);
 
             Device oldDevice = devices.get(deviceId);
             // update description
@@ -192,8 +191,8 @@
 
     @Override
     public DeviceEvent markOffline(DeviceId deviceId) {
-        ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs
-            = getDeviceDescriptions(deviceId);
+        Map<ProviderId, DeviceDescriptions> providerDescs
+            = getOrCreateDeviceDescriptions(deviceId);
 
         // locking device
         synchronized (providerDescs) {
@@ -218,7 +217,7 @@
         Device device = devices.get(deviceId);
         checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
 
-        ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
+        Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
         checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
 
         List<DeviceEvent> events = new ArrayList<>();
@@ -287,12 +286,12 @@
                                             Map<PortNumber, Port> ports,
                                             Set<PortNumber> processed) {
         List<DeviceEvent> events = new ArrayList<>();
-        Iterator<PortNumber> iterator = ports.keySet().iterator();
+        Iterator<Entry<PortNumber, Port>> iterator = ports.entrySet().iterator();
         while (iterator.hasNext()) {
-            PortNumber portNumber = iterator.next();
+            Entry<PortNumber, Port> e = iterator.next();
+            PortNumber portNumber = e.getKey();
             if (!processed.contains(portNumber)) {
-                events.add(new DeviceEvent(PORT_REMOVED, device,
-                                           ports.get(portNumber)));
+                events.add(new DeviceEvent(PORT_REMOVED, device, e.getValue()));
                 iterator.remove();
             }
         }
@@ -306,10 +305,36 @@
                 NewConcurrentHashMap.<PortNumber, Port>ifNeeded());
     }
 
-    private ConcurrentMap<ProviderId, DeviceDescriptions> getDeviceDescriptions(
+    private Map<ProviderId, DeviceDescriptions> getOrCreateDeviceDescriptions(
             DeviceId deviceId) {
-        return createIfAbsentUnchecked(deviceDescs, deviceId,
-                NewConcurrentHashMap.<ProviderId, DeviceDescriptions>ifNeeded());
+        Map<ProviderId, DeviceDescriptions> r;
+        r = deviceDescs.get(deviceId);
+        if (r != null) {
+            return r;
+        }
+        r = new HashMap<>();
+        final Map<ProviderId, DeviceDescriptions> concurrentlyAdded;
+        concurrentlyAdded = deviceDescs.putIfAbsent(deviceId, r);
+        if (concurrentlyAdded != null) {
+            return concurrentlyAdded;
+        } else {
+            return r;
+        }
+    }
+
+    // Guarded by deviceDescs value (=Device lock)
+    private DeviceDescriptions getOrCreateProviderDeviceDescriptions(
+                            Map<ProviderId, DeviceDescriptions> device,
+                            ProviderId providerId, DeviceDescription deltaDesc) {
+
+        synchronized (device) {
+            DeviceDescriptions r = device.get(providerId);
+            if (r == null) {
+                r = new DeviceDescriptions(deltaDesc);
+                device.put(providerId, r);
+            }
+            return r;
+        }
     }
 
     @Override
@@ -318,12 +343,12 @@
         Device device = devices.get(deviceId);
         checkArgument(device != null, DEVICE_NOT_FOUND, deviceId);
 
-        ConcurrentMap<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
+        Map<ProviderId, DeviceDescriptions> descsMap = deviceDescs.get(deviceId);
         checkArgument(descsMap != null, DEVICE_NOT_FOUND, deviceId);
 
         synchronized (descsMap) {
             DeviceDescriptions descs = descsMap.get(providerId);
-            // assuming all providers must to give DeviceDescription
+            // assuming all providers must give DeviceDescription first
             checkArgument(descs != null,
                     "Device description for Device ID %s from Provider %s was not found",
                     deviceId, providerId);
@@ -367,7 +392,7 @@
 
     @Override
     public DeviceEvent removeDevice(DeviceId deviceId) {
-        ConcurrentMap<ProviderId, DeviceDescriptions> descs = getDeviceDescriptions(deviceId);
+        Map<ProviderId, DeviceDescriptions> descs = getOrCreateDeviceDescriptions(deviceId);
         synchronized (descs) {
             Device device = devices.remove(deviceId);
             // should DEVICE_REMOVED carry removed ports?
@@ -390,7 +415,7 @@
      * @return Device instance
      */
     private Device composeDevice(DeviceId deviceId,
-            ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) {
+            Map<ProviderId, DeviceDescriptions> providerDescs) {
 
         checkArgument(!providerDescs.isEmpty(), "No Device descriptions supplied");
 
@@ -429,14 +454,14 @@
      *
      * @param device device the port is on
      * @param number port number
-     * @param providerDescs Collection of Descriptions from multiple providers
+     * @param descsMap Collection of Descriptions from multiple providers
      * @return Port instance
      */
     private Port composePort(Device device, PortNumber number,
-                ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) {
+                Map<ProviderId, DeviceDescriptions> descsMap) {
 
-        ProviderId primary = pickPrimaryPID(providerDescs);
-        DeviceDescriptions primDescs = providerDescs.get(primary);
+        ProviderId primary = pickPrimaryPID(descsMap);
+        DeviceDescriptions primDescs = descsMap.get(primary);
         // if no primary, assume not enabled
         // TODO: revisit this default port enabled/disabled behavior
         boolean isEnabled = false;
@@ -448,7 +473,7 @@
             annotations = merge(annotations, portDesc.annotations());
         }
 
-        for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) {
+        for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
             if (e.getKey().equals(primary)) {
                 continue;
             }
@@ -470,10 +495,9 @@
     /**
      * @return primary ProviderID, or randomly chosen one if none exists
      */
-    private ProviderId pickPrimaryPID(
-            ConcurrentMap<ProviderId, DeviceDescriptions> providerDescs) {
+    private ProviderId pickPrimaryPID(Map<ProviderId, DeviceDescriptions> descsMap) {
         ProviderId fallBackPrimary = null;
-        for (Entry<ProviderId, DeviceDescriptions> e : providerDescs.entrySet()) {
+        for (Entry<ProviderId, DeviceDescriptions> e : descsMap.entrySet()) {
             if (!e.getKey().isAncillary()) {
                 return e.getKey();
             } else if (fallBackPrimary == null) {
@@ -484,21 +508,6 @@
         return fallBackPrimary;
     }
 
-    public static final class InitDeviceDescs
-        implements ConcurrentInitializer<DeviceDescriptions> {
-
-        private final DeviceDescription deviceDesc;
-
-        public InitDeviceDescs(DeviceDescription deviceDesc) {
-            this.deviceDesc = checkNotNull(deviceDesc);
-        }
-        @Override
-        public DeviceDescriptions get() throws ConcurrentException {
-            return new DeviceDescriptions(deviceDesc);
-        }
-    }
-
-
     /**
      * Collection of Description of a Device and it's Ports given from a Provider.
      */
diff --git a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleLinkStore.java b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleLinkStore.java
index bcddda3..a9a0982 100644
--- a/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleLinkStore.java
+++ b/core/store/trivial/src/main/java/org/onlab/onos/store/trivial/impl/SimpleLinkStore.java
@@ -1,12 +1,10 @@
 package org.onlab.onos.store.trivial.impl;
 
 import com.google.common.base.Function;
-import com.google.common.base.Predicate;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.SetMultimap;
 
-import org.apache.commons.lang3.concurrent.ConcurrentUtils;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -20,7 +18,6 @@
 import org.onlab.onos.net.SparseAnnotations;
 import org.onlab.onos.net.Link.Type;
 import org.onlab.onos.net.LinkKey;
-import org.onlab.onos.net.Provided;
 import org.onlab.onos.net.link.DefaultLinkDescription;
 import org.onlab.onos.net.link.LinkDescription;
 import org.onlab.onos.net.link.LinkEvent;
@@ -28,11 +25,12 @@
 import org.onlab.onos.net.link.LinkStoreDelegate;
 import org.onlab.onos.net.provider.ProviderId;
 import org.onlab.onos.store.AbstractStore;
-import org.onlab.util.NewConcurrentHashMap;
 import org.slf4j.Logger;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 import java.util.Map.Entry;
 import java.util.concurrent.ConcurrentHashMap;
@@ -47,6 +45,7 @@
 import static org.slf4j.LoggerFactory.getLogger;
 import static com.google.common.collect.Multimaps.synchronizedSetMultimap;
 import static com.google.common.base.Predicates.notNull;
+import static com.google.common.base.Verify.verifyNotNull;
 
 /**
  * Manages inventory of infrastructure links using trivial in-memory structures
@@ -61,8 +60,7 @@
     private final Logger log = getLogger(getClass());
 
     // Link inventory
-    private final ConcurrentMap<LinkKey,
-            ConcurrentMap<ProviderId, LinkDescription>>
+    private final ConcurrentMap<LinkKey, Map<ProviderId, LinkDescription>>
                     linkDescs = new ConcurrentHashMap<>();
 
     // Link instance cache
@@ -151,7 +149,7 @@
                                         LinkDescription linkDescription) {
         LinkKey key = linkKey(linkDescription.src(), linkDescription.dst());
 
-        ConcurrentMap<ProviderId, LinkDescription> descs = getLinkDescriptions(key);
+        Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key);
         synchronized (descs) {
             final Link oldLink = links.get(key);
             // update description
@@ -166,7 +164,7 @@
 
     // Guarded by linkDescs value (=locking each Link)
     private LinkDescription createOrUpdateLinkDescription(
-                             ConcurrentMap<ProviderId, LinkDescription> descs,
+                             Map<ProviderId, LinkDescription> descs,
                              ProviderId providerId,
                              LinkDescription linkDescription) {
 
@@ -227,7 +225,7 @@
     @Override
     public LinkEvent removeLink(ConnectPoint src, ConnectPoint dst) {
         final LinkKey key = linkKey(src, dst);
-        ConcurrentMap<ProviderId, LinkDescription> descs = getLinkDescriptions(key);
+        Map<ProviderId, LinkDescription> descs = getOrCreateLinkDescriptions(key);
         synchronized (descs) {
             Link link = links.remove(key);
             descs.clear();
@@ -247,8 +245,8 @@
     /**
      * @return primary ProviderID, or randomly chosen one if none exists
      */
-    private ProviderId pickPrimaryPID(
-            ConcurrentMap<ProviderId, LinkDescription> providerDescs) {
+    // Guarded by linkDescs value (=locking each Link)
+    private ProviderId getBaseProviderId(Map<ProviderId, LinkDescription> providerDescs) {
 
         ProviderId fallBackPrimary = null;
         for (Entry<ProviderId, LinkDescription> e : providerDescs.entrySet()) {
@@ -262,9 +260,10 @@
         return fallBackPrimary;
     }
 
-    private Link composeLink(ConcurrentMap<ProviderId, LinkDescription> descs) {
-        ProviderId primary = pickPrimaryPID(descs);
-        LinkDescription base = descs.get(primary);
+    // Guarded by linkDescs value (=locking each Link)
+    private Link composeLink(Map<ProviderId, LinkDescription> descs) {
+        ProviderId primary = getBaseProviderId(descs);
+        LinkDescription base = descs.get(verifyNotNull(primary));
 
         ConnectPoint src = base.src();
         ConnectPoint dst = base.dst();
@@ -289,9 +288,20 @@
         return new DefaultLink(primary , src, dst, type, annotations);
     }
 
-    private ConcurrentMap<ProviderId, LinkDescription> getLinkDescriptions(LinkKey key) {
-        return ConcurrentUtils.createIfAbsentUnchecked(linkDescs, key,
-                NewConcurrentHashMap.<ProviderId, LinkDescription>ifNeeded());
+    private Map<ProviderId, LinkDescription> getOrCreateLinkDescriptions(LinkKey key) {
+        Map<ProviderId, LinkDescription> r;
+        r = linkDescs.get(key);
+        if (r != null) {
+            return r;
+        }
+        r = new HashMap<>();
+        final Map<ProviderId, LinkDescription> concurrentlyAdded;
+        concurrentlyAdded = linkDescs.putIfAbsent(key, r);
+        if (concurrentlyAdded == null) {
+            return r;
+        } else {
+            return concurrentlyAdded;
+        }
     }
 
     private final Function<LinkKey, Link> lookupLink = new LookupLink();
@@ -302,20 +312,11 @@
     private final class LookupLink implements Function<LinkKey, Link> {
         @Override
         public Link apply(LinkKey input) {
-            return links.get(input);
-        }
-    }
-
-    private static final Predicate<Provided> IS_PRIMARY = new IsPrimary();
-    private static final Predicate<Provided> isPrimary() {
-        return IS_PRIMARY;
-    }
-
-    private static final class IsPrimary implements Predicate<Provided> {
-
-        @Override
-        public boolean apply(Provided input) {
-            return !input.providerId().isAncillary();
+            if (input == null) {
+                return null;
+            } else {
+                return links.get(input);
+            }
         }
     }
 }