com.neko233.toolchain.storage.async.AbstractCacheDataSyncDao Maven / Gradle / Ivy
package com.neko233.toolchain.storage.async;
import com.neko233.toolchain.common.annotation.Experimental;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 抽象数据同步 DAO API, 具体写操作由外部实现
* ps: 不允许用作 Analysis 类 DAO
*
* @author SolarisNeko on 2023-02-05
**/
@Experimental(comment = "异步 DAO, 读取最新数据覆盖")
public abstract class AbstractCacheDataSyncDao> implements DataSyncApi {
// 全局数据同步 scheduler
private static final ScheduledExecutorService GLOBAL_DATA_SYNC_SCHEDULER = Executors.newScheduledThreadPool(1);
private final BlockingQueue mq;
private final Map asyncWriteCache = new ConcurrentHashMap<>();
public AbstractCacheDataSyncDao(int mqMaxSize, DataSyncScheduleParamDto dataSyncScheduleParamDto) {
dataSyncScheduleParamDto = dataSyncScheduleParamDto == null ? DataSyncScheduleParamDto.temp() : dataSyncScheduleParamDto;
int initialDelay = Math.max(0, dataSyncScheduleParamDto.getInitDelay());
int period = Math.max(10, dataSyncScheduleParamDto.getPeriod());
TimeUnit scheduleTimeUnit = Optional.ofNullable(dataSyncScheduleParamDto.getTimeUnit()).orElse(TimeUnit.SECONDS);
this.mq = new ArrayBlockingQueue<>(Math.max(10, mqMaxSize));
// scheduler
GLOBAL_DATA_SYNC_SCHEDULER.scheduleAtFixedRate(() -> {
flushAsyncWriteData();
}, initialDelay, period, scheduleTimeUnit);
Thread preShutdownThread = new Thread(this::flushAsyncWriteData);
Runtime.getRuntime().addShutdownHook(preShutdownThread);
}
private void flushAsyncWriteData() {
final List tempDataList = new ArrayList<>(mq.size());
mq.drainTo(tempDataList);
insertOrUpdate(tempDataList);
for (T t : tempDataList) {
asyncWriteCache.remove(t.uniqueId());
}
tempDataList.clear();
}
public List getAllAsyncWriteData() {
return new ArrayList<>(asyncWriteCache.values());
}
public T getAsyncWriteData(DataUniqueId queryData) {
return asyncWriteCache.get(queryData.uniqueId());
}
@Override
public boolean syncData(T data) {
insertOrUpdate(data);
return false;
}
@Override
public boolean asyncData(T data) {
boolean isOk = mq.offer(data);
if (isOk) {
asyncWriteCache.merge(data.uniqueId(), data, mergeNewData());
}
return isOk;
}
}