/* * Copyright (c) 2016 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.groupbasedpolicy.sxp.ep.provider.impl.dao; import com.google.common.base.Optional; import com.google.common.collect.Iterables; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.regex.Pattern; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.apache.commons.net.util.SubnetUtils; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.SimpleCachedDao; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.util.EPTemplateUtil; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.util.SubnetInfoKeyDecorator; import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointForwardingTemplateBySubnet; /** * Purpose: generic implementation of {@link SimpleCachedDao} */ public class SimpleCachedDaoEPForwardingTemplateImpl implements SimpleCachedDao<IpPrefix, EndpointForwardingTemplateBySubnet> { private final ConcurrentMap<IpPrefix, EndpointForwardingTemplateBySubnet> plainCache; private final ConcurrentMap<SubnetInfoKeyDecorator, EndpointForwardingTemplateBySubnet> subnetCache; private final Pattern IP_MASK_EATER_RE = Pattern.compile("/[0-9]+"); public SimpleCachedDaoEPForwardingTemplateImpl() { plainCache = new ConcurrentHashMap<>(); subnetCache = new ConcurrentHashMap<>(); } @Override public EndpointForwardingTemplateBySubnet update(@Nonnull final IpPrefix key, @Nullable final EndpointForwardingTemplateBySubnet value) { final EndpointForwardingTemplateBySubnet previousValue; if (EPTemplateUtil.isPlain(key)) { previousValue = updatePlainCache(key, value); } else { previousValue = updateSubnetCache(key, value); } return previousValue; } private EndpointForwardingTemplateBySubnet updateSubnetCache(final IpPrefix key, final EndpointForwardingTemplateBySubnet value) { final EndpointForwardingTemplateBySubnet previousValue; final SubnetInfoKeyDecorator subnetKey = EPTemplateUtil.buildSubnetInfoKey(key); if (value != null) { previousValue = subnetCache.put(subnetKey, value); } else { previousValue = subnetCache.remove(subnetKey); } return previousValue; } private EndpointForwardingTemplateBySubnet updatePlainCache(final @Nonnull IpPrefix key, final @Nullable EndpointForwardingTemplateBySubnet value) { final EndpointForwardingTemplateBySubnet previousValue; if (value != null) { previousValue = plainCache.put(key, value); } else { previousValue = plainCache.remove(key); } return previousValue; } @Override public Optional<EndpointForwardingTemplateBySubnet> find(@Nonnull final IpPrefix key) { final Optional<EndpointForwardingTemplateBySubnet> template; if (EPTemplateUtil.isPlain(key)) { final Optional<EndpointForwardingTemplateBySubnet> fastPlain = Optional.fromNullable(plainCache.get(key)); if (fastPlain.isPresent()) { template = fastPlain; } else { template = lookupSlowSubnet(key.getIpv4Prefix().getValue()); } } else { final SubnetInfoKeyDecorator keyDecorator = EPTemplateUtil.buildSubnetInfoKey(key); final Optional<EndpointForwardingTemplateBySubnet> fastSubnet = Optional.fromNullable(subnetCache.get(keyDecorator)); if (fastSubnet.isPresent()) { template = fastSubnet; } else { template = Optional.absent(); } } return template; } private Optional<EndpointForwardingTemplateBySubnet> lookupSlowSubnet(final String value) { final String plainIp = IP_MASK_EATER_RE.matcher(value).replaceFirst(""); EndpointForwardingTemplateBySubnet valueCandidate = null; int addressCount = 0; for (Map.Entry<SubnetInfoKeyDecorator, EndpointForwardingTemplateBySubnet> entry : subnetCache.entrySet()) { final SubnetUtils.SubnetInfo subnetInfo = entry.getKey().getDelegate(); if (subnetInfo.isInRange(plainIp)) { final int addressCountTmp = subnetInfo.getAddressCount(); if (valueCandidate == null || addressCount > addressCountTmp) { valueCandidate = entry.getValue(); addressCount = addressCountTmp; } } } return Optional.fromNullable(valueCandidate); } @Override public void invalidateCache() { plainCache.clear(); subnetCache.clear(); } @Override public boolean isEmpty() { return plainCache.isEmpty() && subnetCache.isEmpty(); } @Override public Iterable<EndpointForwardingTemplateBySubnet> values() { return Iterables.unmodifiableIterable(Iterables.concat(plainCache.values(), subnetCache.values())); } @Override public Iterable<IpPrefix> keySet() { // bypassing subnets return Iterables.unmodifiableIterable(plainCache.keySet()); } }