/**
* Project: doris.admin.service.common-0.1.0-SNAPSHOT
*
* File Created at 2011-5-24
* $Id$
*
* Copyright 1999-2100 Alibaba.com Corporation Limited.
* All rights reserved.
*
* This software is the confidential and proprietary information of
* Alibaba Company. ("Confidential Information"). You shall not
* disclose such Confidential Information and shall use it only in
* accordance with the terms of the license agreement you entered into
* with Alibaba.com.
*/
package com.alibaba.doris.admin.service.failover.node.check;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.alibaba.doris.admin.service.common.Managerable;
import com.alibaba.doris.admin.service.common.node.NodesManager;
import com.alibaba.doris.client.net.Connection;
import com.alibaba.doris.client.net.OperationFuture;
import com.alibaba.doris.client.net.command.CheckCommand.CheckType;
import com.alibaba.doris.client.net.command.CheckCommand.Type;
import com.alibaba.doris.client.net.command.result.CheckResult;
import com.alibaba.doris.common.StoreNode;
/**
* check the node status.
*
* @author mian.hem
*/
public class NodeCheckManager implements Managerable {
private static NodeCheckManager instance = new NodeCheckManager();
private Map<String, NodeHealth> nodeHealthStatuses = new ConcurrentHashMap<String, NodeHealth>();
private static final Log log = LogFactory
.getLog(NodeCheckManager.class);
private ReentrantLock lock = new ReentrantLock();
private NodeCheckThread checkThread = null;
private NodeCheckManager() {
super();
checkThread = new NodeCheckThread(this);
}
public static NodeCheckManager getInstance() {
return instance;
}
/**
* Case 1: needRealAccessing == true <br/>
* Check the node health status. This method will really invoke node if the
* current cache indicates this node is OK for accessing real state. If
* returns NG, then it's might be from cache. <br/>
* Case 2: needRealAccessing == false<br/>
* Get the node heal status from cache.
*/
public NodeHealth checkNode(StoreNode node, boolean needRealAccessing) {
if (node == null) {
return null;
}
lock.lock();
NodeHealth health = null;
try {
health = nodeHealthStatuses.get(node.getPhId());
if (needRealAccessing && health == NodeHealth.OK) {
health = accessAndCacheResult(node);
}
} finally {
lock.unlock();
}
if (health == null) {
health = accessAndCacheResult(node);
}
return health;
}
private NodeHealth accessAndCacheResult(StoreNode node) {
NodeHealth health;
health = verifyNodeAcess(node);
//cache health result.
nodeHealthStatuses.put(node.getPhId(), health);
return health;
}
/**
* Check the node health status. This method will really invoke node if the
* current cache indicates this node is OK for accessing real state. If
* returns NG, then it's might be from cache.
*/
public NodeHealth checkNode(StoreNode node) {
return checkNode(node, true);
}
/**
* Check the node health status. This method will really invoke node if the
* current cache indicates this node is OK for accessing real state. If
* returns NG, then it's might be from cache.
*/
public NodeHealth checkNode(String physicalId) {
StoreNode storeNode = NodesManager.getInstance().getStoreNode(physicalId);
return checkNode(storeNode);
}
/**
* Check the node health status. This method will really invoke node if the
* current cache indicates this node is OK for accessing real state. If
* returns NG, then it's might be from cache.
*/
public NodeHealth checkNode(String physicalId, boolean needRealAccessing) {
StoreNode storeNode = NodesManager.getInstance().getStoreNode(physicalId);
return checkNode(storeNode, needRealAccessing);
}
public NodeHealth verifyNodeAcess(String physicalId) {
StoreNode storeNode = NodesManager.getInstance().getStoreNode(physicalId);
return verifyNodeAcess(storeNode);
}
public NodeHealth verifyNodeAcess(StoreNode node, Connection conn) {
NodeHealth nodeHealth = NodeHealth.NG;
try {
Type checkType = null;
switch (node.getSequence()) {
case TEMP_SEQUENCE: // 临时节点
checkType = CheckType.CHECK_TEMP_NODE;
break;
case STANDBY_SEQUENCE: // 备用接地那
checkType = CheckType.CHECK_STANDBY_NODE;
break;
case UNUSE_SEQUENCE: // 待用节点
checkType = null;
break;
default: //正常(Data)节点
checkType = CheckType.CHECK_NORMAL_NODE;
break;
}
OperationFuture<CheckResult> future = conn.check(checkType);
CheckResult checkResult = null;
try {
checkResult = future.get(NodeCheckThread.nodeCheckTimeout, TimeUnit.MILLISECONDS);
} catch (Exception e) {
log.error("check failed for node :" + node.getPhId());
log.error(e.getMessage(), e);
checkResult = null;
}
if (checkResult == null) {
nodeHealth = NodeHealth.NG;
if (checkResult == null) {
log.warn("Check result is null for node :" + node.getPhId());
}
} else if (checkResult.isSuccess()) {
nodeHealth = NodeHealth.OK;
} else {
nodeHealth = NodeHealth.NG;
log.warn("Check result is NG for node :" + node.getPhId() + ", Message:"
+ checkResult.getMessage());
}
} catch (Exception e) {
log.debug("fail to check node :" + node.getPhId(), e);
updateNodeHealth(node, NodeHealth.NG);
return NodeHealth.NG;
}
updateNodeHealth(node, nodeHealth);
return nodeHealth;
}
/**
* Make put and get invocation to node for it's health state.
*/
public NodeHealth verifyNodeAcess(StoreNode node) {
if (node == null ) {
return null;
}
try {
Connection conn = NodesManager.getInstance().getNodeConnection(node);
return verifyNodeAcess(node, conn);
} catch (Exception e) {
log.debug("fail to check node :" + node.getPhId(), e);
updateNodeHealth(node, NodeHealth.NG);
return NodeHealth.NG;
}
}
public void updateNodeHealth(StoreNode node, NodeHealth nodeHealth) {
lock.lock();
try {
nodeHealthStatuses.put(node.getPhId(), nodeHealth);
} finally {
lock.unlock();
}
}
public void updateNodeHealth(String physicalId, NodeHealth nodeHealth) {
lock.lock();
try {
nodeHealthStatuses.put(physicalId, nodeHealth);
} finally {
lock.unlock();
}
}
/**
* Returns node health snapshot of all nodes.
*/
public Map<String, NodeHealth> getNodeHealthStatuses() {
return nodeHealthStatuses;
}
public void start() {
checkThread.start();
}
public void stop() {
checkThread.over();
}
}