From fb62471a0743cb1d36bc8feb2bccb550ef1eee40 Mon Sep 17 00:00:00 2001 From: Saurav Das <saurav.das@bigswitch.com> Date: Tue, 26 Mar 2013 22:00:54 -0700 Subject: [PATCH] Implementing the rest of the debugCounters API --- .../debugcounter/DebugCounter.java | 165 ++++++++++++++---- .../debugcounter/IDebugCounterService.java | 65 ++++++- .../debugcounter/NullDebugCounter.java | 18 +- 3 files changed, 188 insertions(+), 60 deletions(-) diff --git a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java index 0b6555e03..10fd4656c 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/DebugCounter.java @@ -4,6 +4,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.List; @@ -39,7 +40,7 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { /** * Global debug-counter storage across all threads. These are - * updated from the local per thread counters by the update FIXME method. + * updated from the local per thread counters by the flush counters method. */ protected ConcurrentHashMap<String, AtomicLong> debugCounters = new ConcurrentHashMap<String, AtomicLong>(); @@ -82,11 +83,22 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { new ConcurrentHashMap<String, List<CounterInfo>>(); /** - * fast cache for counter names that are currently active + * fast global cache for counter names that are currently active */ Set<String> currentCounters = Collections.newSetFromMap( new ConcurrentHashMap<String,Boolean>()); + /** + * Thread local cache for counter names that are currently active. + */ + protected final ThreadLocal<Set<String>> threadlocalCurrentCounters = + new ThreadLocal<Set<String>>() { + @Override + protected Set<String> initialValue() { + return new HashSet<String>(); + } + }; + //******************************* // IDebugCounterService //******************************* @@ -118,31 +130,27 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { a.add(new CounterInfo(moduleCounterName, counterDescription, counterType)); // create counter in global map - debugCounters.put(moduleCounterName, new AtomicLong()); - - // create counter in local thread map - Map<String, MutableLong> thismap = this.threadlocalCounters.get(); - MutableLong ml = thismap.get(moduleCounterName); - if (ml == null) { - thismap.put(moduleCounterName, new MutableLong()); - } - - // finally add to cache if it is meant to be always counted + // and add to counter name cache if it is meant to be always counted if (counterType == CounterType.ALWAYS_COUNT) { currentCounters.add(moduleCounterName); + debugCounters.put(moduleCounterName, new AtomicLong()); } return true; } @Override public void updateCounter(String moduleCounterName) { - if (currentCounters.contains(moduleCounterName)) { - Map<String, MutableLong> thismap = this.threadlocalCounters.get(); - MutableLong ml = thismap.get(moduleCounterName); - if (ml == null) { + Map<String, MutableLong> thismap = this.threadlocalCounters.get(); + MutableLong ml = thismap.get(moduleCounterName); + if (ml == null) { + // check locally to see if this counter should be created or not + Set<String> thisset = this.threadlocalCurrentCounters.get(); + if (thisset.contains(moduleCounterName)) { ml = new MutableLong(); + ml.increment(); thismap.put(moduleCounterName, ml); } + } else { ml.increment(); } } @@ -154,58 +162,143 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { MutableLong curval = thismap.get(key); long delta = curval.get(); if (delta > 0) { - debugCounters.get(key).addAndGet(delta); - curval.set(0); + AtomicLong ctr = debugCounters.get(key); + if (ctr == null) { + // The global counter does not exist possibly because it has been + // disabled. It should thus be removed from the thread-local + // map (the counter) and set (the counter name). Removing it + // from the threadlocal set ensures that the counter will not be + // recreated (see updateCounter) + Set<String> thisset = this.threadlocalCurrentCounters.get(); + thisset.remove(key); + thismap.remove(key); + } else { + ctr.addAndGet(delta); + curval.set(0); + } } } + // At this point it is also possible that the threadlocal map/set does not + // include a counter that has been enabled and is present in the global + // current counter store. If so we need to sync such state so that the + // thread local counter can be created (in the updateCounter method) + Set<String> thisset = this.threadlocalCurrentCounters.get(); + if (thisset.size() != currentCounters.size()) { + thisset.addAll(currentCounters); + } + //printAllCounters(); } @Override public void resetCounter(String moduleCounterName) { - // TODO Auto-generated method stub - + if (debugCounters.containsKey(moduleCounterName)) { + debugCounters.get(moduleCounterName).set(0); + } } @Override public void resetAllCounters() { - // TODO Auto-generated method stub - + for (AtomicLong v : debugCounters.values()) { + v.set(0); + } } @Override public void resetAllModuleCounters(String moduleName) { - // TODO Auto-generated method stub - + List<CounterInfo> cil = moduleCounters.get(moduleName); + if (cil != null) { + for (CounterInfo ci : cil) { + if (debugCounters.containsKey(ci.moduleCounterName)) { + debugCounters.get(ci.moduleCounterName).set(0); + } + } + } else { + if (log.isDebugEnabled()) + log.debug("No module found with name {}", moduleName); + } } @Override public void enableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub - + currentCounters.add(moduleCounterName); + debugCounters.putIfAbsent(moduleCounterName, new AtomicLong()); } @Override public void disableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub - + String[] temp = moduleCounterName.split("-"); + if (temp.length < 2) { + log.error("moduleCounterName {} not recognized", moduleCounterName); + return; + } + String moduleName = temp[0]; + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + if (ci.moduleCounterName.equals(moduleCounterName) && + ci.ctype == CounterType.COUNT_ON_DEMAND) { + currentCounters.remove(moduleCounterName); + debugCounters.remove(moduleCounterName); + return; + } + } } @Override public DebugCounterInfo getCounterValue(String moduleCounterName) { - // TODO Auto-generated method stub + if (!debugCounters.containsKey(moduleCounterName)) return null; + long counterValue = debugCounters.get(moduleCounterName).longValue(); + + String[] temp = moduleCounterName.split("-"); + if (temp.length < 2) { + log.error("moduleCounterName {} not recognized", moduleCounterName); + return null; + } + String moduleName = temp[0]; + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + if (ci.moduleCounterName.equals(moduleCounterName)) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterinfo = ci; + dci.counterValue = counterValue; + return dci; + } + } return null; } @Override public List<DebugCounterInfo> getAllCounterValues() { - // TODO Auto-generated method stub - return null; + List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); + for (List<CounterInfo> cil : moduleCounters.values()) { + for (CounterInfo ci : cil) { + AtomicLong ctr = debugCounters.get(ci.moduleCounterName); + if (ctr != null) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterinfo = ci; + dci.counterValue = ctr.longValue(); + dcilist.add(dci); + } + } + } + return dcilist; } @Override - public List<DebugCounterInfo> getModuleCounterValues() { - // TODO Auto-generated method stub - return null; + public List<DebugCounterInfo> getModuleCounterValues(String moduleName) { + List<DebugCounterInfo> dcilist = new ArrayList<DebugCounterInfo>(); + if (moduleCounters.containsKey(moduleName)) { + List<CounterInfo> cil = moduleCounters.get(moduleName); + for (CounterInfo ci : cil) { + AtomicLong ctr = debugCounters.get(ci.moduleCounterName); + if (ctr != null) { + DebugCounterInfo dci = new DebugCounterInfo(); + dci.counterinfo = ci; + dci.counterValue = ctr.longValue(); + dcilist.add(dci); + } + } + } + return dcilist; } @@ -246,19 +339,17 @@ public class DebugCounter implements IFloodlightModule, IDebugCounterService { @Override public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // TODO Auto-generated method stub return null; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { - // TODO Auto-generated method stub } @Override public void startUp(FloodlightModuleContext context) { - // TODO Auto-generated method stub + } } diff --git a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java index 6e10e13ac..807144021 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/IDebugCounterService.java @@ -7,7 +7,8 @@ import java.util.List; public interface IDebugCounterService extends IFloodlightService { /** - * Different counter types. + * Different counter types. Counters that are meant to be counted on demand + * need to be separately enabled/disabled. */ public enum CounterType { ALWAYS_COUNT, @@ -28,6 +29,7 @@ public interface IDebugCounterService extends IFloodlightService { * @param moduleCounterName the counter name which MUST be have the following * syntax: <module name>-<counter name> * eg.: linkdiscovery-incoming + * There should be only a single '-' in the name * @param counterDescription a descriptive string that gives more information * of what the counter is measuring. For example, * "Measures the number of incoming packets seen by @@ -43,34 +45,85 @@ public interface IDebugCounterService extends IFloodlightService { CounterType counterType); /** - * Increments the counter by 1. + * Increments the counter by 1, if the counter is meant to be always counted, + * or if the counter has been enabled for counting. * @param moduleCounterName the registered counter name. */ public void updateCounter(String moduleCounterName); /** - * Update the global counter map with values from the thread local maps + * Update the global counter map with values from the thread local maps. This + * method is not intended for use by any module. It's typical usage is from + * floodlight core. As far as the modules are concerned, this should happen + * automatically for their counters. */ public void flushCounters(); /** - * - * @param moduleCounterName + * Resets the value of the counter to zero if it is currently enabled. Note + * that with live traffic, it is not necessary that the counter will display + * zero with a get call as it may get updated between the reset and get calls. + * @param moduleCounterName the registered counter name. */ public void resetCounter(String moduleCounterName); + /** + * Resets the values of all counters that are currently enabled to zero. + */ public void resetAllCounters(); + /** + * Resets the values of all counters that are currently active and belong + * to a module with the given 'moduleName'. The moduleName MUST be the + * part of the moduleCounterName with which the counters were registered. + * eg. if 'linkdiscovery-incoming' and 'linkdiscovery-lldpeol' are two counters + * the module name is 'linkdiscovery' + * @param moduleName + */ public void resetAllModuleCounters(String moduleName); + /** + * This method applies only to CounterType.COUNT_ON_DEMAND. It is used to + * enable counting on the counter. Note that this step is necessary to start + * counting for these counter types - merely registering the counter is not + * enough (as is the case for CounterType.ALWAYS_COUNT). Note that newly + * enabled counter starts from an initial value of zero. + * + * @param moduleCounterName the registered counter name. + */ public void enableCtrOnDemand(String moduleCounterName); + /** + * This method applies only to CounterType.ALWAYS_COUNT. It is used to disable + * counting on this counter. Note that disabling a counter results in a loss + * of the counter value. When re-enabled the counter will restart from zero. + * + * @param moduleCounterName the registered counter name. + */ public void disableCtrOnDemand(String moduleCounterName); + /** + * Get counter value and associated information for a specific counter + * + * @param moduleCounterName + * @return DebugCounterInfo or null if the counter could not be found + */ public DebugCounterInfo getCounterValue(String moduleCounterName); + /** + * Get counter values and associated information for all counters + * + * @return the list of values/info or an empty list + */ public List<DebugCounterInfo> getAllCounterValues(); - public List<DebugCounterInfo> getModuleCounterValues(); + /** + * Get counter values and associated information for all counters associated + * with a module. + * + * @param moduleName + * @return the list of values/info or an empty list + */ + public List<DebugCounterInfo> getModuleCounterValues(String moduleName); } diff --git a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java index 3807f9d96..8b6a1cb19 100644 --- a/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java +++ b/src/main/java/net/floodlightcontroller/debugcounter/NullDebugCounter.java @@ -15,28 +15,24 @@ public class NullDebugCounter implements IFloodlightModule, IDebugCounterService public boolean registerCounter(String moduleCounterName, String counterDescription, CounterType counterType) { - // TODO Auto-generated method stub return false; } @Override public Collection<Class<? extends IFloodlightService>> getModuleServices() { - // TODO Auto-generated method stub return null; } @Override public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { - // TODO Auto-generated method stub return null; } @Override public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { - // TODO Auto-generated method stub return null; } @@ -45,73 +41,61 @@ public class NullDebugCounter implements IFloodlightModule, IDebugCounterService void init(FloodlightModuleContext context) throws FloodlightModuleException { - // TODO Auto-generated method stub } @Override public void startUp(FloodlightModuleContext context) { - // TODO Auto-generated method stub } @Override public void updateCounter(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void flushCounters() { - // TODO Auto-generated method stub } @Override public void resetCounter(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void resetAllCounters() { - // TODO Auto-generated method stub } @Override public void resetAllModuleCounters(String moduleName) { - // TODO Auto-generated method stub } @Override public void enableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public void disableCtrOnDemand(String moduleCounterName) { - // TODO Auto-generated method stub } @Override public DebugCounterInfo getCounterValue(String moduleCounterName) { - // TODO Auto-generated method stub return null; } @Override public List<DebugCounterInfo> getAllCounterValues() { - // TODO Auto-generated method stub return null; } @Override - public List<DebugCounterInfo> getModuleCounterValues() { - // TODO Auto-generated method stub + public List<DebugCounterInfo> getModuleCounterValues(String moduleName) { return null; } -- GitLab