Move BufferedLinearRegionFileFlusher to data package

This commit is contained in:
2026-07-20 21:28:31 +08:00
parent 02b3686642
commit 755edf914e
3 changed files with 2 additions and 4 deletions
@@ -4,7 +4,6 @@ import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.Zstd;
import com.github.luben.zstd.ZstdInputStream;
import io.nanachiyo0721.shiroha.utils.BufferedLinearRegionFileFlusher;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
@@ -0,0 +1,132 @@
package io.nanachiyo0721.shiroha.data;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;
public class BufferedLinearRegionFileFlusher implements Runnable {
private static final Logger logger = LogUtils.getLogger();
private final Set<BufferedLinearRegionFile> inManagement = new ObjectArraySet<>();
private final ScheduledFuture<?> flusherChecker;
private final Executor ioWorkerPool;
private final long flushOfWriteTimeoutMs;
public BufferedLinearRegionFileFlusher(int nIoThreads, long checkIntervalMs, long flushOfWriteTimeoutMs) {
Validate.isTrue(nIoThreads > 0, "Number of I/O threads must > 0!");
Validate.isTrue(checkIntervalMs > 0, "Check interval must > 0");
Validate.isTrue(flushOfWriteTimeoutMs > 0, "Flush of write timeout must > 0");
this.ioWorkerPool = Executors.newFixedThreadPool(nIoThreads, new ThreadFactoryBuilder()
.setNameFormat("BufferedLinearRegionFile I/O Worker %d")
.setDaemon(true)
.build()
);
this.flusherChecker = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder()
.setNameFormat("BufferedLinearRegionFile Flusher Checker")
.setDaemon(true)
.build())
.scheduleWithFixedDelay(this, checkIntervalMs, checkIntervalMs, TimeUnit.MILLISECONDS);
this.flushOfWriteTimeoutMs = flushOfWriteTimeoutMs;
}
public void shutdown() {
this.flusherChecker.cancel(false);
((ExecutorService) this.ioWorkerPool).shutdown();
for (; ; ) {
try {
if (((ExecutorService) this.ioWorkerPool).awaitTermination(100, TimeUnit.MILLISECONDS)) {
break;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
@Override
public void run() {
final long currentNanos = System.nanoTime();
final BufferedLinearRegionFile[] copied;
synchronized (this) {
copied = this.inManagement.toArray(new BufferedLinearRegionFile[0]);
}
final List<BufferedLinearRegionFile> toRemove = new ObjectArrayList<>();
for (BufferedLinearRegionFile file : copied) {
// try acquiring the read lock
if (!file.softReadLock()) {
// if the read lock is unacquirable, it might mean there is another operations is processing(might be a writing operation)
continue;
}
boolean closed;
try {
// check if the file is closed
closed = file.isClosedRaw();
} finally {
file.releaseReadLock();
}
if (closed) {
// add to pending remove list so that we could clean the closed file correctly
toRemove.add(file);
continue;
}
// skip non sync-required files
if (!file.shouldSync()) {
continue;
}
final long lastWriteNanos = file.getLastWritten();
final long timeElapsed = (currentNanos - lastWriteNanos) / 1_000_000; // Convert to milliseconds
// if deadline(timeout) reached
if (timeElapsed >= this.flushOfWriteTimeoutMs) {
// already marked to flush
if (!file.markAsBeingSynced()) {
continue;
}
this.ioWorkerPool.execute(() -> {
try {
file.syncIfNeeded();
} catch (IOException e) {
logger.error("Failed to sync master file: ", e);
}
});
}
}
synchronized (this) {
// clean closed files
for (BufferedLinearRegionFile file : toRemove) {
this.inManagement.remove(file);
}
}
}
public void removeFile(BufferedLinearRegionFile fileToRemove) {
synchronized (this) {
this.inManagement.remove(fileToRemove);
}
}
public void addFile(BufferedLinearRegionFile fileToAdd) {
synchronized (this) {
this.inManagement.add(fileToAdd);
}
}
}