Parallel process and load plans

This commit is contained in:
mastermc05 2022-03-30 19:37:29 +03:00
parent c5d113b77a
commit 4a97550b63
4 changed files with 212 additions and 40 deletions

View file

@ -1,8 +1,9 @@
package org.dynmap.common.chunk;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.dynmap.DynmapChunk;
import org.dynmap.DynmapCore;
@ -697,6 +698,14 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
protected abstract GenericChunk getLoadedChunk(DynmapChunk ch);
// Load generic chunk from unloaded chunk
protected abstract GenericChunk loadChunk(DynmapChunk ch);
// Load generic chunk from existing and already loaded chunk
protected Supplier<GenericChunk> getLoadedChunkAsync(DynmapChunk ch) {
throw new RuntimeException("Not implemeted");
}
// Load generic chunks from unloaded chunk async
protected Supplier<GenericChunk> loadChunkAsync(DynmapChunk ch){
throw new RuntimeException("Not implemeted");
}
/**
* Read NBT data from loaded chunks - needs to be called from server/world
@ -753,11 +762,75 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
}
return cnt;
}
public void getLoadedChunksAsync() {
class SimplePair{ //simple pair of the supplier that finishes read async, and a consumer that also finish his work async
final Supplier<GenericChunk> supplier;
final BiConsumer<GenericChunk, Long> consumer;
SimplePair(Supplier<GenericChunk> supplier, BiConsumer<GenericChunk, Long> consumer) {
this.supplier = supplier;
this.consumer = consumer;
}
}
if (!dw.isLoaded()) {
isempty = true;
unloadChunks();
return;
}
List<SimplePair> lastApply = new ArrayList<>();
for (DynmapChunk dynmapChunk : chunks) {
long startTime = System.nanoTime();
int chunkIndex = (dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim;
if (snaparray[chunkIndex] != null)
continue; // Skip if already processed
boolean vis = isChunkVisible(dynmapChunk);
/* Check if cached chunk snapshot found */
if (tryChunkCache(dynmapChunk, vis)) {
endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT);
}
// If chunk is loaded and not being unloaded, we're grabbing its NBT data
else {
// Get generic chunk from already loaded chunk, if we can
Supplier<GenericChunk> supplier = getLoadedChunkAsync(dynmapChunk);
long startPause = System.nanoTime();
BiConsumer<GenericChunk, Long> consumer = (ss, reloadTime) -> {
if (ss == null) return;
long pause = reloadTime - startPause;
if (vis) { // If visible
prepChunkSnapshot(dynmapChunk, ss);
} else {
if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) {
ss = getStone();
} else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) {
ss = getOcean();
} else {
ss = getEmpty();
}
}
snaparray[chunkIndex] = ss;
endChunkLoad(startTime - pause, ChunkStats.LOADED_CHUNKS);
};
lastApply.add(new SimplePair(supplier, consumer));
}
}
//impact on the main thread should be minimal, so we plan and finish the work after main thread finished it's part
lastApply.forEach(simplePair -> {
long reloadWork = System.nanoTime();
simplePair.consumer.accept(simplePair.supplier.get(), reloadWork);
});
}
@Override
public int loadChunks(int max_to_load) {
return getLoadedChunks() + readChunks(max_to_load);
}
public void loadChunksAsync() {
getLoadedChunksAsync();
readChunksAsync();
}
public int readChunks(int max_to_load) {
@ -840,6 +913,81 @@ public abstract class GenericMapChunkCache extends MapChunkCache {
return cnt;
}
public void readChunksAsync() {
if (!dw.isLoaded()) {
isempty = true;
unloadChunks();
return;
}
List<DynmapChunk> chunks;
if (iterator == null) {
iterator = Collections.emptyListIterator();
chunks = new ArrayList<>(this.chunks);
} else {
chunks = new ArrayList<>();
iterator.forEachRemaining(chunks::add);
}
// DynmapCore.setIgnoreChunkLoads(true);
List<DynmapChunk> cached = new ArrayList<>();
List<Map.Entry<Supplier<GenericChunk>,DynmapChunk>> notCached = new ArrayList<>();
iterator.forEachRemaining(chunks::add);
chunks.stream()
.filter(chunk -> snaparray[(chunk.x - x_min) + (chunk.z - z_min) * x_dim] == null)
.forEach(chunk -> {
if (cache.getSnapshot(dw.getName(),chunk.x, chunk.z) == null) {
notCached.add(new AbstractMap.SimpleEntry<>(loadChunkAsync(chunk),chunk));
} else {
cached.add(chunk);
}
});
cached.forEach(chunk -> {
long startTime = System.nanoTime();
tryChunkCache(chunk, isChunkVisible(chunk));
endChunkLoad(startTime, ChunkStats.CACHED_SNAPSHOT_HIT);
});
notCached.forEach(chunkSupplier -> {
long startTime = System.nanoTime();
GenericChunk chunk = chunkSupplier.getKey().get();
DynmapChunk dynmapChunk = chunkSupplier.getValue();
if (chunk != null) {
// If hidden
if (isChunkVisible(dynmapChunk)) {
// Prep snapshot
prepChunkSnapshot(dynmapChunk, chunk);
} else {
if (hidestyle == HiddenChunkStyle.FILL_STONE_PLAIN) {
chunk = getStone();
} else if (hidestyle == HiddenChunkStyle.FILL_OCEAN) {
chunk = getOcean();
} else {
chunk = getEmpty();
}
}
snaparray[(dynmapChunk.x - x_min) + (dynmapChunk.z - z_min) * x_dim] = chunk;
endChunkLoad(startTime, ChunkStats.UNLOADED_CHUNKS);
} else {
endChunkLoad(startTime, ChunkStats.UNGENERATED_CHUNKS);
}
});
// DynmapCore.setIgnoreChunkLoads(false);
isempty = true;
/* Fill missing chunks with empty dummy chunk */
for (int i = 0; i < snaparray.length; i++) {
if (snaparray[i] == null) {
snaparray[i] = getEmpty();
} else if (!snaparray[i].isEmpty) {
isempty = false;
}
}
}
/**
* Test if done loading
*/