LotStepStatSpeedTime.java
package com.mycim.valueobject.wip;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
public class LotStepStatSpeedTime {
//STOP CODE
//只要当前状态为此值,则会把所有数据dump 到sum区,并且停止当前时间
public static final int STOP_CODE = 0xABABAC;
//基址
private final int WAIT_TIME_AREA = 0;
private final int HOLD_TIME_AREA = 8;
private final int RUN_TIME_AREA = 16;
//偏移量
private final int NEXT_COUNT_AREA = 64;
private final ByteBuffer bf;
private List<Long> operTimeArr;
// //获取最近一次操作的时间
// private long lastOperTime;
private final int MAX_LENGTH = 128;
public LotStepStatSpeedTime(byte[] dataStruct) {
if (dataStruct != null) {
bf = ByteBuffer.wrap(dataStruct);
} else {
bf = ByteBuffer.allocate(MAX_LENGTH);
}
initBaseData();
}
private void initBaseData() {
operTimeArr = Arrays.asList(bf.getLong(WAIT_TIME_AREA), bf.getLong(HOLD_TIME_AREA), bf.getLong(RUN_TIME_AREA));
}
//原来的字段统计了 批次总时间,
//需求#39709 lot query页面显示的W.T,R.T,H.T的值显示为lot在当前step在对应状态下累计的时间
//按照加字段的方式感觉不妥。 所以采用以下 二进制结构。
//为了防止发生ABA hold->waiting->hold->waiting->running
//设计两个区块 时间区 和 统计区。
//时间区存放 最后一次操作时间。
//统计区存放 ABA AB BA 中间所消耗的时间
/**冗余区 以后开发 去记录 banked active 等时间**/
//LAST WITETIME |LAST HOLDTIME |LAST RUN TIME | 冗余
//0-8 |8-16 |16-24 | 24-64 时间区 可多存放5个状态时间
//SUM WITETIME |SUM HOLDTIME |SUM RUN TIME | 冗余
//64-72 |72-80 |80-88 | 88-128 ABA统计区 可多存放5个统计
/** bytebuffer 模拟指针对数据块操作**/
//java 默认使用大端
//a&0xffff0000 取高8 先比较高4位
//a&0x0000ffff 取低8 如果高4一样比较低4位
//当前时间 - 状态时间 + 状态变更中间时间损耗
// now - a0xffff + (a<<64)&0xffff
//例如 上面数据结构 为bf 如果hold 是最大值 则说明hold 是最新一次的操作
// hold在当前步骤损耗时间, now - long(bf[8]) + long(bf[72])
//如果不是最新操作 则直接取统计区的值
/**
* by mingcz
*
* @param currentStat 当前操作状态
* @param beforeStat 特殊计算可能会用到。这里暂时没用,保留
* @return
*/
public byte[] createOrUpdateDataStruct(String currentStat, String beforeStat) {
//防止 ababc c与b 计算时间误差。
//更新 差值 更新时间
long now = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
for (int i = 0; i < operTimeArr.size(); i++) {
long item = operTimeArr.get(i);
//排除0
if (item == 0) {
continue;
}
long speedTime = now - item;
//写入统计区
//找到之前保存的时间
int countArea = NEXT_COUNT_AREA + i * 8;
long saveCount = bf.getLong(countArea);
//上个状态时间 到这次变更的时间统计
bf.putLong(countArea, saveCount + speedTime);
//时间区写0
bf.putLong(i * 8, 0L);
}
//根据状态写入值
if (String.valueOf(STOP_CODE).equals(currentStat)) {
//一些冻结的逻辑
} else if (LotStatus.isHold(currentStat)) {
bf.putLong(HOLD_TIME_AREA, now);
} else if (LotStatus.isRunning(currentStat)) {
bf.putLong(RUN_TIME_AREA, now);
} else if (
LotStatus.isWaiting(currentStat)||
LotStatus.isRunCardWaitMerge(currentStat)||
LotStatus.isRunCardWaitFinish(currentStat)) {
bf.putLong(WAIT_TIME_AREA, now);
} else if (LotStatus.isRunningHold(currentStat)) {
bf.putLong(HOLD_TIME_AREA, now);
bf.putLong(RUN_TIME_AREA, now);
} else if (LotStatus.isRunCardHold(currentStat)) {
bf.putLong(HOLD_TIME_AREA, now);
}else if (LotStatus.isRunCardFinish(currentStat)){
//当前状态是 runcardfinish 逻辑
}else if (LotStatus.isTerminated(currentStat)){
//当前状态是terminated 的逻辑
}
// if (LotStatus.isRunning(beforeStat)) {//发生cancel move running 时间依然要统计 后面需求变更临时注释 2021-8-11
// bf.putLong(RUN_TIME_AREA, now);
// }
return bf.array();
}
//解析step 每个操作 花费时间
public Map<String, String> resolveDataStruct() {
//兼容之前创建的单子 bytebuffer 为空
Map<String, String> returnMap = new HashMap();
returnMap.put("current_step_h_t", "0.0");
returnMap.put("current_step_w_t", "0.0");
returnMap.put("current_step_r_t", "0.0");
if (bf == null) {
return returnMap;
}
//时间取有值的 now -时间区 + 统计区
returnMap.clear();
returnMap.put("current_step_h_t",
calcBtwLastOperTime.apply(bf.getLong(HOLD_TIME_AREA), bf.getLong(HOLD_TIME_AREA + NEXT_COUNT_AREA)));
returnMap.put("current_step_w_t",
calcBtwLastOperTime.apply(bf.getLong(WAIT_TIME_AREA), bf.getLong(WAIT_TIME_AREA + NEXT_COUNT_AREA)));
returnMap.put("current_step_r_t",
calcBtwLastOperTime.apply(bf.getLong(RUN_TIME_AREA), bf.getLong(RUN_TIME_AREA + NEXT_COUNT_AREA)));
return returnMap;
}
//毫秒格式化 为小时 分钟秒 友善提示
private final Function<Long, String> formatMilli = (y) -> {
// 格式 23h 43m 5s
// long totalSeconds = y / 1000;
// long currentSeconds = totalSeconds % 60;
// long totalMinutes = totalSeconds / 60;
// long currentMintes = totalMinutes % 60;
// long totalHours = totalMinutes / 60;
// return String.format("%dh %dm %ds", totalHours, currentMintes, currentSeconds);
return String.format("%.2f",y==0?0.0:(y+0.0)/(3600000));
};
//计算now - 最近操作时间
private final BiFunction<Long, Long, String> calcBtwLastOperTime = (y, x) -> {
long nowMilli = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
Long millis = (y == 0 ? 0 : nowMilli - y) + x;
return formatMilli.apply(millis);
};
}