package com.alibaba.doris.admin.service.common.migrate.status;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.alibaba.doris.admin.service.common.node.NodesManager;
import com.alibaba.doris.common.MigrateStatusEnum;
import com.alibaba.doris.common.MigrateTypeEnum;
/**
* 记录迁移中节点的迁移状态,toString()可获得状态详细信息
*
* @author frank
*/
public class MigrateStatus {
private static final Log log = LogFactory.getLog(MigrateStatus.class);
private String physicalId;
private Map<String, MigrateStatus> statusItemMap; // 扩容迁移:null,失效恢复迁移:<迁出node,迁出状态>
private int schedule = 0; // 迁移进度
private MigrateStatusEnum migerateStatus = MigrateStatusEnum.PREPARE; // 迁移状态
private MigrateTypeEnum migerateType; // 迁移类型
private long waitingReportTime; // 距上次报告状态经过的时间,单位ms
private long reportTimeStamp; // 上次报告状态系统时间,单位ms
private String message;
private static final String SPLIT = " ";
private boolean hadReportTimeout = false; // 已经发送超时报警,报警只发一次。
private static final long reportTimeout = 240000; // 报告超时时间,4分钟。
public MigrateStatus(String physicalId, MigrateTypeEnum migerateType, MigrateStatusEnum status) {
this.physicalId = physicalId;
this.statusItemMap = new HashMap<String, MigrateStatus>();
this.migerateType = migerateType;
this.migerateStatus = status;
this.reportTimeStamp = System.currentTimeMillis();// 用当前系统时间初始化
}
public Map<String, MigrateStatus> getStatusItemMap() {
return statusItemMap;
}
public void setStatusItemMap(Map<String, MigrateStatus> statusItemMap) {
this.statusItemMap = statusItemMap;
}
public int getSchedule() {
return schedule;
}
/**
* 设置进度
*
* @param sourcePhysicalId
* @param schedule
* @param statusEnum TODO
* @param message TODO
*/
public synchronized void setSchedule(String sourcePhysicalId, int schedule, MigrateStatusEnum statusEnum,
String message) {
if (migerateType.equals(MigrateTypeEnum.EXPANSION)) {// expansion
buildMyself(this, schedule, statusEnum, message);
} else {// fail over
if (statusItemMap == null) {
statusItemMap = new ConcurrentHashMap<String, MigrateStatus>();
}
MigrateStatus ms = statusItemMap.get(sourcePhysicalId);
if (ms == null) {
ms = new MigrateStatus(sourcePhysicalId, migerateType, MigrateStatusEnum.MIGERATING);
statusItemMap.put(sourcePhysicalId, ms);
}
buildMyself(ms, schedule, statusEnum, message);
int weight = statusItemMap.size();
int scheduleByWeight = 0;
boolean allItemFinish = true;
for (Entry<String, MigrateStatus> entry : statusItemMap.entrySet()) {
int itemSchedule = entry.getValue().getSchedule();
if (itemSchedule != 100) {
allItemFinish = false;
}
scheduleByWeight += itemSchedule / weight;
}
if (allItemFinish) {
scheduleByWeight = 100;
}
buildMyself(this, scheduleByWeight, statusEnum.equals(MigrateStatusEnum.FINISH)?MigrateStatusEnum.MIGERATING:statusEnum, message);
}
}
/**
* 根据报告的进度,重构状态
*
* @param ms
* @param schedule
*/
private void buildMyself(MigrateStatus ms, int schedule, MigrateStatusEnum statusEnum, String message) {
if (log.isDebugEnabled()) {
log.debug("build migrate status:" + ms.getPhysicalId() + " schedule:" + schedule);
}
ms.schedule = schedule;
ms.migerateStatus = statusEnum == null ? MigrateStatusEnum.MIGERATING : statusEnum;
ms.reportTimeStamp = System.currentTimeMillis();
ms.message = message;
if (schedule == -1) {
ms.migerateStatus = MigrateStatusEnum.MIGERATE_ERROR;
}
if (schedule == 100) {// schedule=100也是finish
ms.migerateStatus = MigrateStatusEnum.FINISH;
}
}
public synchronized void resetReportTime() {
waitingReportTime = System.currentTimeMillis() - reportTimeStamp;
this.hadReportTimeout = false;// 超时开关恢复
if (statusItemMap != null && !statusItemMap.isEmpty()) {
for (Entry<String, MigrateStatus> entry : statusItemMap.entrySet()) {
entry.getValue().setWaitingReportTime(
System.currentTimeMillis()
- entry.getValue().getReportTimeStamp());
entry.getValue().hadReportTimeout = false;// 超时开关恢复
}
}
}
/**
* 迁移过程报告超时
*
* @param status
* @return
*/
public boolean isTimeout() {
if (!this.isHadReportTimeout() && this.getWaitingReportTime() >= MigrateStatus.getReporttimeout()) {
this.setHadReportTimeout(true);
return true;
}
Map<String, MigrateStatus> statusItemMap = this.getStatusItemMap();
if (statusItemMap != null && !statusItemMap.isEmpty()) {
for (Entry<String, MigrateStatus> statusItem : statusItemMap.entrySet()) {
MigrateStatus ms = statusItem.getValue();
if (!ms.isHadReportTimeout() && ms.getWaitingReportTime() >= MigrateStatus.getReporttimeout()) {
ms.setHadReportTimeout(true);
return true;
}
}
}
return false;
}
public MigrateStatusEnum getMigerateStatus() {
return migerateStatus;
}
public void setMigerateStatus(MigrateStatusEnum migerateStatus) {
this.migerateStatus = migerateStatus;
}
public String getPhysicalId() {
return physicalId;
}
public MigrateTypeEnum getMigerateType() {
return migerateType;
}
public long getReportTimeStamp() {
return reportTimeStamp;
}
public void setReportTimeStamp(long reportTimeStamp) {
this.reportTimeStamp = reportTimeStamp;
}
public long getWaitingReportTime() {
return waitingReportTime;
}
public void setWaitingReportTime(long waitingReportTime) {
this.waitingReportTime = waitingReportTime;
}
public boolean isHadReportTimeout() {
return hadReportTimeout;
}
public void setHadReportTimeout(boolean hadReportTimeout) {
this.hadReportTimeout = hadReportTimeout;
}
public static long getReporttimeout() {
return reportTimeout;
}
public String toString() {
String item = "";
if (statusItemMap != null && !statusItemMap.isEmpty()) {
item = "------item detail:";
for (Entry<String, MigrateStatus> entry : statusItemMap.entrySet()) {
item += entry.getValue().toString();
}
}
return NodesManager.getInstance().getLogFormatNodeId(physicalId) + SPLIT + physicalId + SPLIT + "Before "
+ waitingReportTime + "ms " + SPLIT + migerateType.getValue() + SPLIT + migerateStatus.getValue()
+ SPLIT + schedule + "%" + "M:" + message + SPLIT + item;
}
}