Introduce the ReferenceCache concept 17/5117/2
authorRobert Varga <rovarga@cisco.com>
Tue, 4 Feb 2014 13:15:08 +0000 (14:15 +0100)
committerRobert Varga <rovarga@cisco.com>
Wed, 5 Feb 2014 02:51:08 +0000 (03:51 +0100)
This is a simple CPU/memory tradeoff primitive, which allows for sharing
of object references in the cardinality/frequency of a particular object
type is favorable. AsNumber is typical candidate.

Change-Id: I79ab163f5da32ad5f99ba99246ae96005ac03df5
Signed-off-by: Robert Varga <rovarga@cisco.com>
bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/BGPExtensionProviderContext.java
bgp/parser-spi/src/main/java/org/opendaylight/protocol/bgp/parser/spi/pojo/SimpleBGPExtensionProviderContext.java
util/src/main/java/org/opendaylight/protocol/util/NoopReferenceCache.java [new file with mode: 0644]
util/src/main/java/org/opendaylight/protocol/util/ReferenceCache.java [new file with mode: 0644]

index deac97f208631db76650819096d3a71e94ee76d8..141a84324cc115c77b93143508192d11ac861d38 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.protocol.bgp.parser.spi;
 
+import org.opendaylight.protocol.util.ReferenceCache;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.CParameters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
@@ -38,4 +39,11 @@ public interface BGPExtensionProviderContext extends BGPExtensionConsumerContext
 
        AutoCloseable registerParameterParser(int parameterType, ParameterParser parser);
        AutoCloseable registerParameterSerializer(Class<? extends BgpParameters> paramClass, ParameterSerializer serializer);
+
+       /**
+        * Get the context-wide cache for a particular object type.
+        * 
+        * @return An object cache instance.
+        */
+       ReferenceCache getReferenceCache();
 }
index cd7c6b33ca34a48742142ac491e48cf0af025d75..1d168f81ca878d9404c396a49f16ba6d817129ec 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.protocol.bgp.parser.spi.pojo;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 import org.opendaylight.protocol.bgp.parser.spi.AttributeParser;
 import org.opendaylight.protocol.bgp.parser.spi.AttributeSerializer;
 import org.opendaylight.protocol.bgp.parser.spi.BGPExtensionProviderContext;
@@ -18,6 +20,7 @@ import org.opendaylight.protocol.bgp.parser.spi.NlriParser;
 import org.opendaylight.protocol.bgp.parser.spi.NlriSerializer;
 import org.opendaylight.protocol.bgp.parser.spi.ParameterParser;
 import org.opendaylight.protocol.bgp.parser.spi.ParameterSerializer;
+import org.opendaylight.protocol.util.ReferenceCache;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.BgpParameters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.message.rev130919.open.bgp.parameters.CParameters;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.types.rev130919.AddressFamily;
@@ -25,7 +28,42 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.bgp.type
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Notification;
 
+import com.google.common.base.Preconditions;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
 public class SimpleBGPExtensionProviderContext extends SimpleBGPExtensionConsumerContext implements BGPExtensionProviderContext {
+       public static final int DEFAULT_MAXIMUM_CACHED_OBJECTS = 100000;
+
+       private final AtomicReference<Cache<Object, Object>> cacheRef;
+       private final ReferenceCache referenceCache = new ReferenceCache() {
+               @Override
+               public <T> T getSharedReference(final T object) {
+                       final Cache<Object, Object> cache = cacheRef.get();
+
+                       @SuppressWarnings("unchecked")
+                       final T ret = (T) cache.getIfPresent(object);
+                       if (ret == null) {
+                               cache.put(object, object);
+                               return object;
+                       }
+
+                       return ret;
+               }
+       };
+       private final int maximumCachedObjects;
+
+       public SimpleBGPExtensionProviderContext() {
+               this(DEFAULT_MAXIMUM_CACHED_OBJECTS);
+       }
+
+       public SimpleBGPExtensionProviderContext(final int maximumCachedObjects) {
+               this.maximumCachedObjects = maximumCachedObjects;
+
+               final Cache<Object, Object> cache = CacheBuilder.newBuilder().maximumSize(maximumCachedObjects).build();
+               cacheRef = new AtomicReference<Cache<Object,Object>>(cache);
+       }
+
        @Override
        public AutoCloseable registerAddressFamily(final Class<? extends AddressFamily> clazz, final int number) {
                return afiReg.registerAddressFamily(clazz, number);
@@ -86,4 +124,21 @@ public class SimpleBGPExtensionProviderContext extends SimpleBGPExtensionConsume
        public AutoCloseable registerSubsequentAddressFamily(final Class<? extends SubsequentAddressFamily> clazz, final int number) {
                return safiReg.registerSubsequentAddressFamily(clazz, number);
        }
+
+       @Override
+       public ReferenceCache getReferenceCache() {
+               return referenceCache;
+       }
+
+       public final synchronized int getMaximumCachedObjects() {
+               return maximumCachedObjects;
+       }
+
+       public final synchronized void setMaximumCachedObjects(final int maximumCachedObjects) {
+               Preconditions.checkArgument(maximumCachedObjects >= 0);
+
+               Cache<Object, Object> newCache = CacheBuilder.newBuilder().maximumSize(maximumCachedObjects).build();
+               newCache.putAll(cacheRef.get().asMap());
+               cacheRef.set(newCache);
+       }
 }
diff --git a/util/src/main/java/org/opendaylight/protocol/util/NoopReferenceCache.java b/util/src/main/java/org/opendaylight/protocol/util/NoopReferenceCache.java
new file mode 100644 (file)
index 0000000..a7d21b1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.util;
+
+/**
+ * A simple reference cache which actually does not cache anything.
+ */
+public final class NoopReferenceCache implements ReferenceCache {
+       private static final class Holder {
+               static final NoopReferenceCache INSTANCE = new NoopReferenceCache();
+       }
+
+       private NoopReferenceCache() {
+
+       }
+
+       @Override
+       public <T> T getSharedReference(final T object) {
+               return object;
+       }
+
+       public static NoopReferenceCache getInstance() {
+               return Holder.INSTANCE;
+       }
+}
diff --git a/util/src/main/java/org/opendaylight/protocol/util/ReferenceCache.java b/util/src/main/java/org/opendaylight/protocol/util/ReferenceCache.java
new file mode 100644 (file)
index 0000000..9126447
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.protocol.util;
+
+/**
+ * The simple interface needed to battle object proliferation when many objects
+ * of a type with low cardinality are created. The idea is that you still create
+ * the object, but rather than hanging on to it, you pass it through the cache,
+ * which may replace your object with a reference to a previously-created object.
+ */
+public interface ReferenceCache {
+       /**
+        * Get a shared reference to an object. The contract here is that the
+        * returned object is an instance of the same class and compares equal
+        * to the passed object.
+        * 
+        * @param object An object to which you'd like to
+        * @return Shared reference to the object.
+        */
+       <T> T getSharedReference(T object);
+}