/* * Copyright (c) 2014 André Martins 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.l2switch.hosttracker.plugin.internal; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.l2switch.hosttracker.plugin.inventory.Host; import org.opendaylight.l2switch.hosttracker.plugin.util.Utilities; import org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140624.HostId; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This will (try to) submit all writes and deletes in to the MD-SAL database. * The removeLocally and putLocally methods should be used when dataChanges are dealt locally and not update to MD-SAL. */ public class ConcurrentClusterAwareHostHashMap { private static final Logger LOG = LoggerFactory.getLogger(ConcurrentClusterAwareHostHashMap.class); private final OperationProcessor opProcessor; private final String topologyId; /** * The instance identifiers for each host submitted to MD-SAL. */ private final ConcurrentHashMap, HostId> instanceIDs = new ConcurrentHashMap<>(); /** * The local Hosts' HashMap. */ private final ConcurrentHashMap hostHashMap = new ConcurrentHashMap<>(); public ConcurrentClusterAwareHostHashMap(OperationProcessor opProcessor, String topologyId) { this.opProcessor = opProcessor; this.topologyId = topologyId; } /** * Removes, if exists, the Host with the given * InstanceIdentifier<Node> from this local HashMap. Ideally used for * host data listener events. * * @param iiN * the InstanceIdentifier<Node> of the Host to remove. * @return the removed Host if exits, null if it doesn't exist. */ public synchronized Host removeLocally(InstanceIdentifier iiN) { HostId hostId = this.instanceIDs.remove(iiN); if (hostId != null) { return this.hostHashMap.remove(hostId); } return null; } /** * Removes, if exists, the Host with the given Key (HostId) from this local * HashMap. Ideally used for host data listener events. * * @param key * the key (HostId) of the Host to remove. * @return the removed Host if exits, null if it doesn't exist. */ public synchronized Host removeLocally(HostId key) { Iterator, HostId>> iterator = this.instanceIDs.entrySet().iterator(); while (iterator.hasNext()) { if (iterator.next().getValue().equals(key)) { iterator.remove(); break; } } return hostHashMap.remove(key); } /** * Puts the given value (Host) only in this local HashMap. Ideally used for * host data listener events. * * @param ii * the value's (Host's) InstanceIdentifier<Node> * @param value * the Host to store locally. * @return the previous value associated with {@code key}, or {@code null} * if there was no mapping for {@code key} */ public synchronized Host putLocally(InstanceIdentifier ii, Host value) { Host host = value; LOG.trace("Putting locally {}", host.getId()); this.instanceIDs.put(ii, host.getId()); return this.hostHashMap.put(host.getId(), value); } /** * Removes the given hosts both locally and on MD-SAL database. * * @param hosts * the hosts to remove. */ public synchronized void removeAll(List hosts) { for (final Map.Entry, HostId> e : this.instanceIDs.entrySet()) { for (Host h : hosts) { if (e.getValue().equals(h.getId())) { this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey())); this.hostHashMap.remove(e.getValue()); break; } } } } /** * Forces the local Host with the given HostId to be merged into MD-SAL * database. * * @param hostid * the Host's hostId that will be merged into MD-SAL database. */ public synchronized void submit(HostId hostid) { Host host = this.hostHashMap.get(hostid); final Node hostNode = host.getHostNode(); final InstanceIdentifier buildNodeIID = Utilities.buildNodeIID(hostNode.key(), topologyId); this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true)); putLocally(buildNodeIID, host); this.instanceIDs.put(buildNodeIID, host.getId()); LOG.trace("Enqueued for MD-SAL transaction {}", hostNode.getNodeId()); } /** * Puts all the given hosts into this local HashMap and into MD-SAL * database. * * @param hosts * the hosts to be sent into MD-SAL database. */ public synchronized void putAll(List hosts) { for (Host h : hosts) { final Node hostNode = h.getHostNode(); final InstanceIdentifier buildNodeIID = Utilities.buildNodeIID(hostNode.key(), topologyId); this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true)); putLocally(buildNodeIID, h); this.instanceIDs.put(buildNodeIID, h.getId()); LOG.trace("Putting MD-SAL {}", hostNode.getNodeId()); } } /** * Puts the given host in the this local HashMap and into MD-SAL database. * * @param hostId * the key for the map * @param host * the value for the map * @return the old value from the local cache if present, null otherwise. */ public synchronized Host put(HostId hostId, Host host) { final Node hostNode = host.getHostNode(); final InstanceIdentifier buildNodeIID = Utilities.buildNodeIID(hostNode.key(), topologyId); this.opProcessor.enqueueOperation(tx -> tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true)); LOG.trace("Putting MD-SAL {}", hostNode.getNodeId()); return putLocally(buildNodeIID, host); } /** * Removes the value (Host) with the given hostId from this local HashMap * and MD-SAL database. * * @param hostId * the Host's hostId to remove * @return the old value from the local cache if present, null otherwise. */ public synchronized Host remove(HostId hostId) { Host removedValue = this.hostHashMap.remove(hostId); if (removedValue != null) { Node hostNode = removedValue.getHostNode(); final InstanceIdentifier hnIID = Utilities.buildNodeIID(hostNode.key(), topologyId); this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, hnIID)); this.instanceIDs.remove(hnIID); } return removedValue; } public boolean containsKey(Object key) { return this.hostHashMap.containsKey(key); } public Host get(HostId key) { return this.hostHashMap.get(key); } /** * Removes all of the mappings from this local HashMap and from MD-SAL. The * local HashMap will be empty after this call returns. */ public synchronized void clear() { for (final Map.Entry, HostId> e : this.instanceIDs.entrySet()) { this.opProcessor.enqueueOperation(tx -> tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey())); } this.hostHashMap.clear(); } /** * Returns the Values from this local HashMap. * * @return the Values from this local HashMap. */ public Collection values() { return this.hostHashMap.values(); } }