Package net.floodlightcontroller.debugevent

Source Code of net.floodlightcontroller.debugevent.DebugEvent$EventUpdaterImpl

package net.floodlightcontroller.debugevent;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import net.floodlightcontroller.core.module.FloodlightModuleContext;
import net.floodlightcontroller.core.module.FloodlightModuleException;
import net.floodlightcontroller.core.module.IFloodlightModule;
import net.floodlightcontroller.core.module.IFloodlightService;
import net.floodlightcontroller.debugevent.web.DebugEventRoutable;
import net.floodlightcontroller.restserver.IRestApiService;

import com.google.common.collect.Sets;
/**
* This class implements a central store for all events used for debugging the
* system. The basic idea is that given the functionality provided by this class,
* it should be unnecessary to resort to scraping through system DEBUG/TRACE logs
* to understand behavior in a running system.
*
* @author Saurav
*/
public class DebugEvent implements IFloodlightModule, IDebugEventService {
    protected static Logger log = LoggerFactory.getLogger(DebugEvent.class);

    /**
     *  Every registered event type gets an event id, the value for which is obtained
     *  while holding the lock.
     */
    protected int eventIdCounter = 0;
    protected Object eventIdLock = new Object();

    private static final long MIN_FLUSH_DELAY = 100; //ms
    private static final int PCT_LOCAL_CAP = 10; // % of global capacity
    private static final int MIN_LOCAL_CAPACITY = 10; //elements

    /**
     * Event Information
     */
    public class EventInfo {
        int eventId;
        boolean enabled;
        int bufferCapacity;
        EventType etype;
        String eventDesc;
        String eventName;
        String moduleName;
        String moduleEventName;
        Class<?> eventClass;
        String[] metaData;

        public EventInfo(int eventId, boolean enabled, int bufferCapacity,
                         EventType etype, Class<?> eventClass, String eventDesc,
                         String eventName, String moduleName, String... metaData) {
            this.enabled = enabled;
            this.eventId = eventId;
            this.bufferCapacity = bufferCapacity;
            this.etype = etype;
            this.eventClass = eventClass;
            this.eventDesc = eventDesc;
            this.eventName = eventName;
            this.moduleName = moduleName;
            this.moduleEventName = moduleName + "/" + eventName;
            this.metaData = metaData;
        }

        public int getEventId() { return eventId; }
        public boolean isEnabled() { return enabled; }
        public int getBufferCapacity() { return bufferCapacity; }
        public EventType getEtype() { return etype; }
        public String getEventDesc() { return eventDesc; }
        public String getEventName() { return eventName; }
        public String getModuleName() { return moduleName; }
        public String getModuleEventName() { return moduleEventName; }
        public String[] getMetaData() { return metaData; }
    }

    //******************
    //   Global stores
    //******************

    /**
     * Event history for a particular event-id is stored in a circular buffer
     */
    protected class DebugEventHistory {
        EventInfo einfo;
        CircularBuffer<Event> eventBuffer;

        public DebugEventHistory(EventInfo einfo, int capacity) {
            this.einfo = einfo;
            this.eventBuffer = new CircularBuffer<Event>(capacity);
        }
    }

    /**
     * Global storage for all event types and their corresponding event buffers.
     * A particular event type is accessed by directly indexing into the array
     * with the corresponding event-id.
     */
    protected DebugEventHistory[] allEvents =
                    new DebugEventHistory[MAX_EVENTS];

    /**
     * Global storage for all event ids registered for a module. The map is indexed
     * by the module name and event name and returns the event-ids that correspond to the
     * event types registered by that module (for example module 'linkdiscovery'
     * may register events that have ids 0 and 1 that correspond to link up/down
     * events, and receiving malformed LLDP packets, respectively).
     */
    protected ConcurrentHashMap<String, ConcurrentHashMap<String, Integer>>
        moduleEvents = new ConcurrentHashMap<String,
                                ConcurrentHashMap<String, Integer>>();

    /**
     * A collection of event ids that are currently enabled for logging
     */
    protected Set<Integer> currentEvents = Collections.newSetFromMap(
                                       new ConcurrentHashMap<Integer,Boolean>());

    //******************
    // Thread local stores
    //******************

    /**
     * Thread local storage for events
     */
    protected class LocalEventHistory {
        int nextIndex;
        int maxCapacity;
        boolean enabled;
        ArrayList<Event> eventList;
        long lastFlushTime;
        boolean flushNow;

        public LocalEventHistory(boolean enabled, int maxCapacity, boolean flushNow) {
            this.nextIndex = 0;
            this.maxCapacity = maxCapacity;
            this.enabled = enabled;
            this.eventList = new ArrayList<Event>();
            this.flushNow = flushNow;
        }
    }

    /**
     * Thread local event buffers used for maintaining event history local to
     * a thread. Eventually this locally maintained information is flushed
     * into the global event buffers.
     */
    protected final ThreadLocal<LocalEventHistory[]> threadlocalEvents =
            new ThreadLocal<LocalEventHistory[]>() {
        @Override
        protected LocalEventHistory[] initialValue() {
            return new LocalEventHistory[MAX_EVENTS];
        }
    };

    /**
     * Thread local cache for event-ids that are currently active.
     */
    protected final ThreadLocal<Set<Integer>> threadlocalCurrentEvents =
            new ThreadLocal<Set<Integer>>() {
        @Override
        protected Set<Integer> initialValue() {
            return new HashSet<Integer>();
        }
    };

    //*******************************
    //   IEventUpdater
    //*******************************

    protected class EventUpdaterImpl<T> implements IEventUpdater<T> {
        private final int eventId;

        public EventUpdaterImpl(int evId) {
            this.eventId = evId;
        }

        @Override
        public void updateEventNoFlush(Object event) {
            if (!validEventId()) return;
            updateEvent(eventId, false, event);
        }

        @Override
        public void updateEventWithFlush(Object event) {
            if (!validEventId()) return;
            updateEvent(eventId, true, event);
        }

        private boolean validEventId() {
            if (eventId < 0 || eventId >= MAX_EVENTS) {
                throw new IllegalStateException();
            }
            return true;
        }

    }

    //*******************************
    //   IDebugEventService
    //*******************************

    @Override
    public <T> IEventUpdater<T> registerEvent(String moduleName, String eventName,
                                              String eventDescription, EventType et,
                                              Class<T> eventClass, int bufferCapacity,
                                              String... metaData) throws MaxEventsRegistered {
        int eventId = -1;
        synchronized (eventIdLock) {
             eventId = Integer.valueOf(eventIdCounter++);
        }
        if (eventId > MAX_EVENTS-1) {
            throw new MaxEventsRegistered();
        }

        // register event id for moduleName
        if (!moduleEvents.containsKey(moduleName)) {
            moduleEvents.put(moduleName, new ConcurrentHashMap<String, Integer>());
        }
        if (!moduleEvents.get(moduleName).containsKey(eventName)) {
            moduleEvents.get(moduleName).put(eventName, new Integer(eventId));
        } else {
            int existingEventId = moduleEvents.get(moduleName).get(eventName);
            log.error("Duplicate event registration for moduleName {} eventName {}",
                      moduleName, eventName);
            return new EventUpdaterImpl<T>(existingEventId);
        }

        // create storage for event-type
        boolean enabled = (et == EventType.ALWAYS_LOG) ? true : false;
        EventInfo ei = new EventInfo(eventId, enabled, bufferCapacity,
                                     et, eventClass, eventDescription, eventName,
                                     moduleName, metaData);
        allEvents[eventId] = new DebugEventHistory(ei, bufferCapacity);
        if (enabled) {
            currentEvents.add(eventId);
        }

        return new EventUpdaterImpl<T>(eventId);
    }

    private void updateEvent(int eventId, boolean flushNow, Object eventData) {
        if (eventId < 0 || eventId > MAX_EVENTS-1) return;

        LocalEventHistory[] thishist = this.threadlocalEvents.get();
        if (thishist[eventId] == null) {
            // seeing this event for the first time in this thread - create local
            // store by consulting global store
            DebugEventHistory de = allEvents[eventId];
            if (de != null) {
                boolean enabled = de.einfo.enabled;
                int localCapacity = de.einfo.bufferCapacity * PCT_LOCAL_CAP/ 100;
                if (localCapacity < 10localCapacity = MIN_LOCAL_CAPACITY;
                thishist[eventId] = new LocalEventHistory(enabled, localCapacity,
                                                          flushNow);
                if (enabled) {
                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
                    thisset.add(eventId);
                }
            } else {
                log.error("updateEvent seen locally for event {} but no global"
                          + "storage exists for it yet .. not updating", eventId);
                return;
            }
        }

        // update local store if enabled locally for updating
        LocalEventHistory le = thishist[eventId];
        if (le.enabled) {
            long timestamp = System.currentTimeMillis();
            long thisthread = Thread.currentThread().getId();
            String thisthreadname = Thread.currentThread().getName();
            if (le.nextIndex < le.eventList.size()) {
                if (le.eventList.get(le.nextIndex) == null) {
                    le.eventList.set(le.nextIndex, new Event(timestamp, thisthread,
                                                             thisthreadname,
                                                             eventData));
                } else {
                    Event e = le.eventList.get(le.nextIndex);
                    e.timestamp = timestamp;
                    e.threadId = thisthread;
                    e.eventData = eventData;
                }
            } else {
                le.eventList.add(new Event(timestamp, thisthread, thisthreadname, eventData));
            }
            le.nextIndex++;

            if (le.nextIndex >= le.maxCapacity || le.flushNow) {
                // flush this buffer now
                DebugEventHistory de = allEvents[eventId];
                if (de.einfo.enabled) {
                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
                } else {
                    // global buffer is disabled - don't flush, disable locally
                    le.enabled = false;
                    Set<Integer> thisset = this.threadlocalCurrentEvents.get();
                    thisset.remove(eventId);
                }
                le.nextIndex = 0;
                le.lastFlushTime = timestamp;
            }
        }
    }

    @Override
    public void flushEvents() {
        LocalEventHistory[] thishist = this.threadlocalEvents.get();
        Set<Integer> thisset = this.threadlocalCurrentEvents.get();
        long timestamp = System.currentTimeMillis();
        ArrayList<Integer> temp = new ArrayList<Integer>();

        for (int eventId : thisset) {
            LocalEventHistory le = thishist[eventId];
            if (le != null && le.nextIndex > 0 &&
                    (le.flushNow || (timestamp - le.lastFlushTime) > MIN_FLUSH_DELAY)) {
                // flush this buffer now
                DebugEventHistory de = allEvents[eventId];
                if (de.einfo.enabled) {
                    le.eventList = de.eventBuffer.addAll(le.eventList, le.nextIndex);
                } else {
                    // global buffer is disabled - don't flush, disable locally
                    le.enabled = false;
                    temp.add(eventId);
                }
                le.nextIndex = 0;
                le.lastFlushTime = timestamp;
            }
        }
        for (int eId : temp)
            thisset.remove(eId);

        // sync thread local currently enabled set of eventIds with global set.
        Sets.SetView<Integer> sv = Sets.difference(currentEvents, thisset);
        for (int eventId : sv) {
            if (thishist[eventId] != null) {
                thishist[eventId].enabled = true;
                thisset.add(eventId);
            }
        }

    }

    @Override
    public boolean containsModuleEventName(String moduleName, String eventName) {
        if (!moduleEvents.containsKey(moduleName)) return false;
        if (moduleEvents.get(moduleName).containsKey(eventName)) return true;
        return false;
    }

    @Override
    public boolean containsModuleName(String moduleName) {
        return moduleEvents.containsKey(moduleName);
    }

    @Override
    public List<DebugEventInfo> getAllEventHistory() {
        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
        for (Map<String, Integer> modev : moduleEvents.values()) {
            for (int eventId : modev.values()) {
                DebugEventHistory de = allEvents[eventId];
                if (de != null) {
                    List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
                    for (Event e : de.eventBuffer) {
                        ret.add(e.getFormattedEvent(de.einfo.eventClass,
                                                    de.einfo.moduleEventName));
                    }
                    moduleEventList.add(new DebugEventInfo(de.einfo, ret));
                }
            }
        }
        return moduleEventList;
    }

    @Override
    public List<DebugEventInfo> getModuleEventHistory(String moduleName) {
        if (!moduleEvents.containsKey(moduleName)) return Collections.emptyList();
        List<DebugEventInfo> moduleEventList = new ArrayList<DebugEventInfo>();
        for (int eventId : moduleEvents.get(moduleName).values()) {
            DebugEventHistory de = allEvents[eventId];
            if (de != null) {
                List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
                for (Event e : de.eventBuffer) {
                    ret.add(e.getFormattedEvent(de.einfo.eventClass,
                                                de.einfo.moduleEventName));
                }
                moduleEventList.add(new DebugEventInfo(de.einfo, ret));
            }
        }
        return moduleEventList;
    }

    @Override
    public DebugEventInfo getSingleEventHistory(String moduleName, String eventName,
                                                int last) {
        if (!moduleEvents.containsKey(moduleName)) return null;
        Integer eventId = moduleEvents.get(moduleName).get(eventName);
        if (eventId == null) return null;
        DebugEventHistory de = allEvents[eventId];
        if (de != null) {
            int num = 1;
            List<Map<String,String>> ret = new ArrayList<Map<String,String>>();
            for (Event e : de.eventBuffer) {
                if (num > last)
                    break;
                Map<String, String> temp = e.getFormattedEvent(de.einfo.eventClass,
                                                               de.einfo.moduleEventName);
                temp.put("#", String.valueOf(num++));
                ret.add(temp);
            }
            return new DebugEventInfo(de.einfo, ret);
        }
        return null;
    }

    @Override
    public void resetAllEvents() {
        for (Map<String, Integer> eventMap : moduleEvents.values()) {
            for (Integer evId : eventMap.values()) {
                allEvents[evId].eventBuffer.clear();
            }
        }
    }

    @Override
    public void resetAllModuleEvents(String moduleName) {
        if (!moduleEvents.containsKey(moduleName)) return;
        Map<String, Integer> modEvents = moduleEvents.get(moduleName);
        for (Integer evId : modEvents.values()) {
            allEvents[evId].eventBuffer.clear();
        }
    }

    @Override
    public void resetSingleEvent(String moduleName, String eventName) {
        if (!moduleEvents.containsKey(moduleName)) return;
        Integer eventId = moduleEvents.get(moduleName).get(eventName);
        if (eventId == null) return;
        DebugEventHistory de = allEvents[eventId];
        if (de != null) {
            de.eventBuffer.clear();
        }
    }

    @Override
    public List<String> getModuleList() {
        List<String> el = new ArrayList<String>();
        el.addAll(moduleEvents.keySet());
        return el;
    }

    @Override
    public List<String> getModuleEventList(String moduleName) {
        if (!moduleEvents.containsKey(moduleName))
            return Collections.emptyList();
        List<String> el = new ArrayList<String>();
        el.addAll(moduleEvents.get(moduleName).keySet());
        return el;
    }

    //*******************************
    //   IFloodlightModule
    //*******************************

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleServices() {
        Collection<Class<? extends IFloodlightService>> l =
                new ArrayList<Class<? extends IFloodlightService>>();
        l.add(IDebugEventService.class);
        return l;
    }

    @Override
    public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() {
        Map<Class<? extends IFloodlightService>, IFloodlightService> m =
                new HashMap<Class<? extends IFloodlightService>, IFloodlightService>();
        m.put(IDebugEventService.class, this);
        return m;
    }

    @Override
    public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
        ArrayList<Class<? extends IFloodlightService>> deps =
                new ArrayList<Class<? extends IFloodlightService>>();
        deps.add(IRestApiService.class);
        return deps;
    }

    @Override
    public void init(FloodlightModuleContext context)
            throws FloodlightModuleException {
    }

    @Override
    public void startUp(FloodlightModuleContext context)
            throws FloodlightModuleException {
        IRestApiService restService =
                context.getServiceImpl(IRestApiService.class);
        restService.addRestletRoutable(new DebugEventRoutable());
        DebugEventAppender.setDebugEventServiceImpl(this);
    }

}
TOP

Related Classes of net.floodlightcontroller.debugevent.DebugEvent$EventUpdaterImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.