/*
* Copyright (c) 2015 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.openflowplugin.impl.statistics.ofpspecific;
import com.google.common.base.Preconditions;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import javax.annotation.Nonnull;
import org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of {@link org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageIntelligenceAgency}.
* Class counts message of {@link org.opendaylight.openflowplugin.api.openflow.statistics.ofpspecific.MessageSpy.STATISTIC_GROUP} type
* and provides info as debug log.
*/
public class MessageIntelligenceAgencyImpl implements MessageIntelligenceAgency, MessageIntelligenceAgencyMXBean {
private static final Logger LOG = LoggerFactory.getLogger(MessageIntelligenceAgencyImpl.class);
private static final class MessageCounters {
private static final AtomicLongFieldUpdater<MessageCounters> UPDATER = AtomicLongFieldUpdater.newUpdater(MessageCounters.class, "current");
@SuppressWarnings("unused")
private volatile long current;
private long cumulative;
public synchronized long accumulate() {
final long inc = UPDATER.getAndSet(this, 0);
cumulative += inc;
return inc;
}
public synchronized long getCumulative() {
return cumulative;
}
public long increment() {
return UPDATER.incrementAndGet(this);
}
}
private ConcurrentMap<STATISTIC_GROUP, ConcurrentMap<Class<?>, MessageCounters>> inputStats = new ConcurrentHashMap<>();
@Override
public void spyMessage(@Nonnull final Class<?> message, final STATISTIC_GROUP statGroup) {
Preconditions.checkNotNull(message, "Message can't be null.");
getCounters(message, statGroup).increment();
}
/**
* @param message counted element
* @param statGroup statistic counter group
* @return corresponding counter
*/
private MessageCounters getCounters(final Class<?> message, final STATISTIC_GROUP statGroup) {
ConcurrentMap<Class<?>, MessageCounters> groupData = getOrCreateGroupData(statGroup);
MessageCounters counters = getOrCreateCountersPair(message, groupData);
return counters;
}
private static MessageCounters getOrCreateCountersPair(final Class<?> msgType, final ConcurrentMap<Class<?>, MessageCounters> groupData) {
final MessageCounters lookup = groupData.get(msgType);
if (lookup != null) {
return lookup;
}
final MessageCounters newCounters = new MessageCounters();
final MessageCounters check = groupData.putIfAbsent(msgType, newCounters);
return check == null ? newCounters : check;
}
private ConcurrentMap<Class<?>, MessageCounters> getOrCreateGroupData(final STATISTIC_GROUP statGroup) {
final ConcurrentMap<Class<?>, MessageCounters> lookup = inputStats.get(statGroup);
if (lookup != null) {
return lookup;
}
final ConcurrentMap<Class<?>, MessageCounters> newmap = new ConcurrentHashMap<>();
final ConcurrentMap<Class<?>, MessageCounters> check = inputStats.putIfAbsent(statGroup, newmap);
return check == null ? newmap : check;
}
@Override
public void run() {
// log current counters and cleans it
if (LOG.isDebugEnabled()) {
for (String counterItem : provideIntelligence()) {
LOG.debug(counterItem);
}
}
}
@Override
public List<String> provideIntelligence() {
List<String> dump = new ArrayList<>();
for (STATISTIC_GROUP statGroup : STATISTIC_GROUP.values()) {
Map<Class<?>, MessageCounters> groupData = inputStats.get(statGroup);
if (groupData != null) {
for (Entry<Class<?>, MessageCounters> statEntry : groupData.entrySet()) {
long amountPerInterval = statEntry.getValue().accumulate();
long cumulativeAmount = statEntry.getValue().getCumulative();
dump.add(String.format("%s: MSG[%s] -> +%d | %d",
statGroup,
statEntry.getKey().getSimpleName(),
amountPerInterval, cumulativeAmount));
}
} else {
dump.add(String.format("%s: no activity detected", statGroup));
}
}
return dump;
}
@Override
public void resetStatistics() {
inputStats = new ConcurrentHashMap<>();
}
}