/**
* 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.openflowplugin.statistics;
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 org.opendaylight.openflowplugin.api.openflow.statistics.MessageObservatory;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* message counter (by type)
*/
public class MessageSpyCounterImpl implements MessageObservatory<DataContainer> {
private static final Logger LOG = LoggerFactory.getLogger(MessageSpyCounterImpl.class);
private static final class MessageCounters {
private static final AtomicLongFieldUpdater<MessageCounters> UPDATER = AtomicLongFieldUpdater.newUpdater(MessageCounters.class, "current");
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 final ConcurrentMap<STATISTIC_GROUP, ConcurrentMap<Class<? extends DataContainer>, MessageCounters>> inputStats = new ConcurrentHashMap<>();
@Override
public void spyIn(final DataContainer message) {
getCounters(message, STATISTIC_GROUP.FROM_SWITCH_TRANSLATE_IN_SUCCESS).increment();
}
@Override
public void spyOut(final DataContainer message) {
getCounters(message, STATISTIC_GROUP.FROM_SWITCH_TRANSLATE_OUT_SUCCESS).increment();
}
@Override
public void spyMessage(final DataContainer message, final STATISTIC_GROUP statGroup) {
getCounters(message, statGroup).increment();
}
/**
* @param message
* @param statGroup TODO
* @return
*/
private MessageCounters getCounters(final DataContainer message, final STATISTIC_GROUP statGroup) {
Class<? extends DataContainer> msgType = message.getImplementedInterface();
ConcurrentMap<Class<? extends DataContainer>, MessageCounters> groupData = getOrCreateGroupData(statGroup);
MessageCounters counters = getOrCreateCountersPair(msgType, groupData);
return counters;
}
private static MessageCounters getOrCreateCountersPair(final Class<? extends DataContainer> msgType, final ConcurrentMap<Class<? extends DataContainer>,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<? extends DataContainer>, MessageCounters> getOrCreateGroupData(final STATISTIC_GROUP statGroup) {
final ConcurrentMap<Class<? extends DataContainer>, MessageCounters> lookup = inputStats.get(statGroup);
if (lookup != null) {
return lookup;
}
final ConcurrentMap<Class<? extends DataContainer>, MessageCounters> newmap = new ConcurrentHashMap<>();
final ConcurrentMap<Class<? extends DataContainer>, 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 : dumpMessageCounts()) {
LOG.debug(counterItem);
}
}
}
@Override
public List<String> dumpMessageCounts() {
List<String> dump = new ArrayList<>();
for (STATISTIC_GROUP statGroup : STATISTIC_GROUP.values()) {
Map<Class<? extends DataContainer>, MessageCounters> groupData = inputStats.get(statGroup);
if (groupData != null) {
for (Entry<Class<? extends DataContainer>, 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;
}
}