/** * Licensed to Cloudera, Inc. under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. Cloudera, Inc. licenses this file * to you 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 com.cloudera.flume.agent; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; 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 com.cloudera.flume.conf.Context; import com.cloudera.flume.conf.FlumeBuilder; import com.cloudera.flume.conf.FlumeConfiguration; import com.cloudera.flume.conf.FlumeSpecException; import com.cloudera.flume.conf.LogicalNodeContext; import com.cloudera.flume.conf.ReportTestingContext; import com.cloudera.flume.conf.FlumeConfigData; import com.cloudera.flume.core.CompositeSink; import com.cloudera.flume.core.EventSink; import com.cloudera.flume.core.EventSource; import com.cloudera.flume.reporter.ReportEvent; import com.cloudera.flume.reporter.ReportManager; import com.cloudera.flume.reporter.Reportable; import com.cloudera.util.Clock; import com.cloudera.util.MultipleIOException; /** * This maintains a set of the logical nodes in the process. */ public class LogicalNodeManager implements Reportable { protected static final Logger LOG = LoggerFactory .getLogger(LogicalNodeManager.class); Map<String, LogicalNode> threads = new ConcurrentHashMap<String, LogicalNode>(); String physicalNode; public LogicalNodeManager(String physicalNode) { this.physicalNode = physicalNode; } synchronized public Collection<LogicalNode> getNodes() { return new ArrayList<LogicalNode>(threads.values()); } /** * Give a logical node name, and src and a sink spec, generate a new logical * node. */ synchronized public void spawn(String name, String src, String snk) throws IOException, FlumeSpecException { Context ctx = new LogicalNodeContext(physicalNode, name); spawn(ctx, name, FlumeBuilder.buildSource(src), new CompositeSink(ctx, snk)); } /** * Give a logical node name, and src and a sink spec, generate a new logical * node. This gives assumes the current version and is ONLY used for testing. */ synchronized public void testingSpawn(String name, String src, String snk) throws IOException, FlumeSpecException { LogicalNode nd = threads.get(name); if (nd == null) { Context ctx = new ReportTestingContext(new LogicalNodeContext( physicalNode, name)); LOG.info("creating new logical node " + name); nd = new LogicalNode(ctx, name); threads.put(nd.getName(), nd); } long ver = Clock.unixTime(); FlumeConfigData fcd = new FlumeConfigData(ver, src, snk, ver, ver, FlumeConfiguration.get().getDefaultFlowName()); nd.loadConfig(fcd); } // TODO (jon) make private synchronized void spawn(Context ctx, String name, EventSource src, EventSink snk) throws IOException { LogicalNode nd = threads.get(name); if (nd == null) { LOG.info("creating new logical node " + name); nd = new LogicalNode(ctx, name); threads.put(nd.getName(), nd); } nd.openLoadNode(src, snk); } /** * Turn a logical node off on a node */ synchronized public void decommission(String name) throws IOException { LogicalNode nd = threads.remove(name); if (nd == null) { throw new IOException("Attempting to decommission node '" + name + "' but it does not exist!"); } ReportManager.get().remove(nd); nd.close(); } @Override public ReportEvent getReport() { ReportEvent rpt = new ReportEvent(getName()); Collection<LogicalNode> copy = null; synchronized (this) { // copy the logical node list in an sychronized way, and make sure when // LogicalNode is locked we don't need the LogicalNodeManager lock. copy = getNodes(); } for (LogicalNode t : copy) { rpt.hierarchicalMerge(t.getName(), t.getReport()); } return rpt; } public String getPhysicalNodeName() { return physicalNode; } @Override public String getName() { return "LogicalNodeManager"; } synchronized public LogicalNode get(String ln) { return threads.get(ln); } /** * Decommission all logical nodes except for those found in the excludes list. */ synchronized public void decommissionAllBut(List<String> excludes) throws IOException { Set<String> decoms = new HashSet<String>(threads.keySet()); // copy keyset decoms.removeAll(excludes); List<IOException> exns = new ArrayList<IOException>(); for (String ln : decoms) { try { decommission(ln); } catch (IOException e) { exns.add(e); } } if (exns.size() > 0) { throw MultipleIOException.createIOException(exns); } } }