/* * Copyright 2015-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.store.flowobjective.impl; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.apache.felix.scr.annotations.Service; import org.onlab.util.KryoNamespace; import org.onosproject.net.behaviour.DefaultNextGroup; import org.onosproject.net.behaviour.NextGroup; import org.onosproject.net.flowobjective.FlowObjectiveStore; import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; import org.onosproject.net.flowobjective.ObjectiveEvent; import org.onosproject.store.AbstractStore; import org.onosproject.store.service.AtomicCounter; import org.onosproject.store.service.ConsistentMap; import org.onosproject.store.service.MapEvent; import org.onosproject.store.service.MapEventListener; import org.onosproject.store.service.Serializer; import org.onosproject.store.service.StorageService; import org.onosproject.store.service.Versioned; import org.slf4j.Logger; import static org.onlab.util.Tools.groupedThreads; import static org.slf4j.LoggerFactory.getLogger; import java.util.HashMap; import java.util.Map; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; /** * Manages the inventory of created next groups. */ @Component(immediate = true) @Service public class DistributedFlowObjectiveStore extends AbstractStore<ObjectiveEvent, FlowObjectiveStoreDelegate> implements FlowObjectiveStore { private final Logger log = getLogger(getClass()); private ConsistentMap<Integer, byte[]> nextGroups; @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) protected StorageService storageService; private AtomicCounter nextIds; private MapEventListener<Integer, byte[]> mapListener = new NextGroupListener(); // event queue to separate map-listener threads from event-handler threads (tpool) private BlockingQueue<ObjectiveEvent> eventQ; private ExecutorService tpool; @Activate public void activate() { tpool = Executors.newFixedThreadPool(4, groupedThreads("onos/flobj-notifier", "%d", log)); eventQ = new LinkedBlockingQueue<ObjectiveEvent>(); tpool.execute(new FlowObjectiveNotifier()); nextGroups = storageService.<Integer, byte[]>consistentMapBuilder() .withName("onos-flowobjective-groups") .withSerializer(Serializer.using( new KryoNamespace.Builder() .register(byte[].class) .register(Versioned.class) .build("DistributedFlowObjectiveStore"))) .build(); nextGroups.addListener(mapListener); nextIds = storageService.getAtomicCounter("next-objective-counter"); log.info("Started"); } @Deactivate public void deactivate() { nextGroups.removeListener(mapListener); tpool.shutdown(); log.info("Stopped"); } @Override public void putNextGroup(Integer nextId, NextGroup group) { nextGroups.put(nextId, group.data()); } @Override public NextGroup getNextGroup(Integer nextId) { Versioned<byte[]> versionGroup = nextGroups.get(nextId); if (versionGroup != null) { return new DefaultNextGroup(versionGroup.value()); } return null; } @Override public NextGroup removeNextGroup(Integer nextId) { Versioned<byte[]> versionGroup = nextGroups.remove(nextId); if (versionGroup != null) { return new DefaultNextGroup(versionGroup.value()); } return null; } @Override public Map<Integer, NextGroup> getAllGroups() { Map<Integer, NextGroup> nextGroupMappings = new HashMap<>(); for (int key : nextGroups.keySet()) { NextGroup nextGroup = getNextGroup(key); if (nextGroup != null) { nextGroupMappings.put(key, nextGroup); } } return nextGroupMappings; } @Override public int allocateNextId() { return (int) nextIds.incrementAndGet(); } private class FlowObjectiveNotifier implements Runnable { @Override public void run() { try { while (!Thread.currentThread().isInterrupted()) { notifyDelegate(eventQ.take()); } } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } } } private class NextGroupListener implements MapEventListener<Integer, byte[]> { @Override public void event(MapEvent<Integer, byte[]> event) { switch (event.type()) { case INSERT: eventQ.add(new ObjectiveEvent(ObjectiveEvent.Type.ADD, event.key())); break; case REMOVE: eventQ.add(new ObjectiveEvent(ObjectiveEvent.Type.REMOVE, event.key())); break; case UPDATE: // TODO Introduce UPDATE ObjectiveEvent when the map is being updated break; default: break; } } } }