/**
* 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.master;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloudera.flume.conf.FlumeConfiguration;
import com.cloudera.flume.conf.FlumeConfigData;
import com.cloudera.flume.master.StatusManager.NodeState;
import com.cloudera.flume.reporter.ReportEvent;
import com.cloudera.flume.reporter.ReportManager;
import com.cloudera.flume.reporter.Reportable;
import com.google.common.base.Preconditions;
/**
* Master-side implementation of the master<->client RPC interaction.
* Encapsulates the logic involved in processing client requests. Since the
* wire protocol is different for separate RPC implementations, they each
* run their own stub servers, then delegate all requests to this common class.
*/
public class MasterClientServer {
static final Logger LOG = LoggerFactory.getLogger(MasterClientServer.class);
final protected FlumeMaster master;
final protected FlumeConfiguration config;
RPCServer masterRPC;
public MasterClientServer(FlumeMaster master, FlumeConfiguration config)
throws IOException {
Preconditions.checkArgument(master != null,
"FlumeConfigMaster is null in MasterClientServer!");
this.master = master;
this.config = config;
String rpcType = config.getMasterHeartbeatRPC();
masterRPC = null;
if (FlumeConfiguration.RPC_TYPE_AVRO.equals(rpcType)) {
masterRPC = new MasterClientServerAvro(this);
} else if (FlumeConfiguration.RPC_TYPE_THRIFT.equals(rpcType)) {
masterRPC = new MasterClientServerThrift(this);
} else {
throw new IOException("No valid RPC framework specified in config");
}
}
public MasterClientServer(FlumeMaster master, FlumeConfiguration config,
RPCServer rpc) {
this.master = master;
this.config = config;
this.masterRPC = rpc;
}
/**
* For testing.
*/
public RPCServer getMasterRPC() {
return this.masterRPC;
}
public List<String> getLogicalNodes(String physNode) {
return master.getSpecMan().getLogicalNode(physNode);
}
public Map<String, Integer> getChokeMap(String physNode) {
return master.getSpecMan().getChokeMap(physNode);
}
public FlumeConfigData getConfig(String host) {
FlumeConfigData config = master.getSpecMan().getConfig(host);
if (config != null) {
return config;
}
return null;
}
/**
* Returns true if needs to do a update configuration Here host is the logical
* node name. Version is the node's current configuration version.
*/
public boolean heartbeat(String logicalNode, String physicalNode,
String clienthost, NodeState s, long version) {
// sanity check with physicalnode.
List<String> lns = master.getSpecMan().getLogicalNode(physicalNode);
if (lns == null || !lns.contains(logicalNode)) {
if (physicalNode.equals(logicalNode)) {
// auto add a default logical node if there are no logical nodes for a
// physical node.
master.getSpecMan().addLogicalNode(physicalNode, logicalNode);
}
LOG.warn("Recieved heartbeat from node '" + physicalNode + "/"
+ logicalNode + "' that is not be set by master ");
}
boolean configChanged = master.getStatMan().updateHeartbeatStatus(
clienthost, physicalNode, logicalNode, s, version);
FlumeConfigData cfg = master.getSpecMan().getConfig(logicalNode);
if (cfg == null || version < cfg.getTimestamp()) {
configChanged = true;
// version sent by node is older than current, return true to force config
// upgrade
}
return configChanged;
}
public void acknowledge(String ackid) {
master.getAckMan().acknowledge(ackid);
}
public boolean checkAck(String ackid) {
return master.getAckMan().check(ackid);
}
/**
* Adds a set of reports to the singleton ReportManager, after wrapping them
* in Reportable objects.
*/
public void putReports(Map<String, ReportEvent> reports) {
Preconditions.checkNotNull(reports,
"putReports called with null report map");
ReportManager rptManager = ReportManager.get();
for (final Entry<String, ReportEvent> r : reports.entrySet()) {
rptManager.add(new Reportable() {
@Override
public String getName() {
return r.getKey();
}
@Override
public ReportEvent getReport() {
return new ReportEvent(r.getValue());
}
});
}
}
public void serve() throws IOException {
this.masterRPC.serve();
}
public void stop () throws IOException {
if (this.masterRPC != null) {
this.masterRPC.stop();
}
}
}