Optimize anvil delete

This commit is contained in:
Jesse Boyd 2017-04-11 01:50:40 +10:00
parent ecedd05651
commit 974cb3fdaf
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
5 changed files with 139 additions and 66 deletions

View File

@ -3,6 +3,7 @@ package com.boydti.fawe.command;
import com.boydti.fawe.Fawe;
import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.jnbt.NBTStreamer;
import com.boydti.fawe.jnbt.anvil.MCAChunk;
import com.boydti.fawe.jnbt.anvil.MCAClipboard;
import com.boydti.fawe.jnbt.anvil.MCAFile;
@ -12,6 +13,9 @@ import com.boydti.fawe.jnbt.anvil.MCAQueue;
import com.boydti.fawe.object.FawePlayer;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.object.RunnableVal;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.RunnableVal4;
import com.boydti.fawe.object.mask.FaweBlockMatcher;
import com.boydti.fawe.object.number.MutableLong;
import com.boydti.fawe.util.ArrayUtil;
@ -44,6 +48,8 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import static com.google.common.base.Preconditions.checkNotNull;
@ -101,7 +107,7 @@ public class AnvilCommands {
max = 3
)
@CommandPermissions("worldedit.anvil.deleteallold")
public void deleteAllOld(Player player, EditSession editSession, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis) throws WorldEditException {
public void deleteAllOld(Player player, String folder, int inhabitedTicks, @Optional("60000") int fileAgeMillis) throws WorldEditException {
FaweQueue defaultQueue = SetQueue.IMP.getNewQueue(folder, true, false);
MCAQueue queue = new MCAQueue(folder, defaultQueue.getSaveFolder(), defaultQueue.hasSky());
MCAFilterCounter result = queue.filterWorld(new MCAFilterCounter() {
@ -115,16 +121,56 @@ public class AnvilCommands {
if (modified - creation < fileAgeMillis) {
mca.setDeleted(true);
get().add(512 * 512 * 256);
return null;
}
} catch (IOException | UnsupportedOperationException ignore) {}
return mca;
}
@Override
public MCAChunk applyChunk(MCAChunk chunk, MutableLong count) {
if (chunk.getInhabitedTime() <= inhabitedTicks) {
count.add(16 * 16 * 256);
chunk.setDeleted(true);
try {
ForkJoinPool pool = new ForkJoinPool();
mca.init();
mca.forEachSortedChunk(new RunnableVal4<Integer, Integer, Integer, Integer>() {
@Override
public void run(Integer x, Integer z, Integer offset, Integer size) {
try {
byte[] bytes = mca.getChunkCompressedBytes(offset);
if (bytes == null) return;
Runnable task = new Runnable() {
@Override
public void run() {
try {
mca.streamChunk(offset, new RunnableVal<NBTStreamer>() {
@Override
public void run(NBTStreamer value) {
value.addReader(".Level.InhabitedTime", new RunnableVal2<Integer, Long>() {
@Override
public void run(Integer index, Long value) {
if (value <= inhabitedTicks) {
MCAChunk chunk = new MCAChunk(queue, x, z);
chunk.setDeleted(true);
synchronized (mca) {
mca.setChunk(chunk);
}
get().add(16 * 16 * 256);
}
}
});
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
};
pool.submit(task);
} catch (IOException e) {
e.printStackTrace();
}
}
});
pool.awaitQuiescence(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
mca.close(pool);
pool.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

View File

@ -1,9 +1,9 @@
package com.boydti.fawe.jnbt;
import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.RunnableVal2;
import com.boydti.fawe.object.exception.FaweException;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.blocks.BaseBlock;
import java.io.IOException;
import java.util.HashMap;
@ -26,6 +26,21 @@ public class NBTStreamer {
is.close();
}
public void readQuick() throws IOException {
try {
is.readNamedTagLazy(new RunnableVal2<String, RunnableVal2>() {
@Override
public void run(String node, RunnableVal2 result) {
if (readers.isEmpty()) {
throw new FaweException(BBC.WORLDEDIT_CANCEL_REASON_MANUAL);
}
this.value2 = readers.remove(node);
}
});
} catch (FaweException ignore) {}
is.close();
}
public <T, V> void addReader(String node, RunnableVal2<T, V> run) {
if (run instanceof NBTStreamReader) {
((NBTStreamReader) run).init(node);

View File

@ -52,6 +52,51 @@ public class MCAChunk extends FaweChunk<Void> {
private int modified;
private boolean deleted;
public MCAChunk(FaweQueue queue, int x, int z) {
super(queue, x, z);
this.ids = new byte[16][];
this.data = new byte[16][];
this.skyLight = new byte[16][];
this.blockLight = new byte[16][];
this.biomes = new byte[256];
this.tiles = new HashMap<>();
this.entities = new HashMap<>();
this.lastUpdate = System.currentTimeMillis();
this.heightMap = new int[256];
this.setModified();
}
public MCAChunk(MCAChunk parent, boolean shallow) {
super(parent.getParent(), parent.getX(), parent.getZ());
if (shallow) {
this.ids = parent.ids;
this.data = parent.data;
this.skyLight = parent.skyLight;
this.blockLight = parent.blockLight;
this.biomes = parent.biomes;
this.tiles = parent.tiles;
this.entities = parent.entities;
this.inhabitedTime = parent.inhabitedTime;
this.lastUpdate = parent.lastUpdate;
this.heightMap = parent.heightMap;
this.modified = parent.modified;
this.deleted = parent.deleted;
} else {
this.ids = (byte[][]) MainUtil.copyNd(parent.ids);
this.data = (byte[][]) MainUtil.copyNd(parent.data);
this.skyLight = (byte[][]) MainUtil.copyNd(parent.skyLight);
this.blockLight = (byte[][]) MainUtil.copyNd(parent.blockLight);
this.biomes = parent.biomes.clone();
this.tiles = new HashMap<>(parent.tiles);
this.entities = new HashMap<>(parent.entities);
this.inhabitedTime = parent.inhabitedTime;
this.lastUpdate = parent.lastUpdate;
this.heightMap = parent.heightMap.clone();
this.modified = parent.modified;
this.deleted = parent.deleted;
}
}
public byte[] toBytes(byte[] buffer) throws IOException {
if (buffer == null) {
buffer = new byte[8192];
@ -393,51 +438,6 @@ public class MCAChunk extends FaweChunk<Void> {
return FaweCache.asTag(root);
}
public MCAChunk(FaweQueue queue, int x, int z) {
super(queue, x, z);
this.ids = new byte[16][];
this.data = new byte[16][];
this.skyLight = new byte[16][];
this.blockLight = new byte[16][];
this.biomes = new byte[256];
this.tiles = new HashMap<>();
this.entities = new HashMap<>();
this.lastUpdate = System.currentTimeMillis();
this.heightMap = new int[256];
this.setModified();
}
public MCAChunk(MCAChunk parent, boolean shallow) {
super(parent.getParent(), parent.getX(), parent.getZ());
if (shallow) {
this.ids = parent.ids;
this.data = parent.data;
this.skyLight = parent.skyLight;
this.blockLight = parent.blockLight;
this.biomes = parent.biomes;
this.tiles = parent.tiles;
this.entities = parent.entities;
this.inhabitedTime = parent.inhabitedTime;
this.lastUpdate = parent.lastUpdate;
this.heightMap = parent.heightMap;
this.modified = parent.modified;
this.deleted = parent.deleted;
} else {
this.ids = (byte[][]) MainUtil.copyNd(parent.ids);
this.data = (byte[][]) MainUtil.copyNd(parent.data);
this.skyLight = (byte[][]) MainUtil.copyNd(parent.skyLight);
this.blockLight = (byte[][]) MainUtil.copyNd(parent.blockLight);
this.biomes = parent.biomes.clone();
this.tiles = new HashMap<>(parent.tiles);
this.entities = new HashMap<>(parent.entities);
this.inhabitedTime = parent.inhabitedTime;
this.lastUpdate = parent.lastUpdate;
this.heightMap = parent.heightMap.clone();
this.modified = parent.modified;
this.deleted = parent.deleted;
}
}
public MCAChunk(NBTInputStream nis, FaweQueue parent, int x, int z, int compressedSize) throws IOException {
super(parent, x, z);
ids = new byte[16][];

View File

@ -262,7 +262,7 @@ public class MCAFile {
return values;
}
private byte[] getChunkCompressedBytes(int offset) throws IOException{
public byte[] getChunkCompressedBytes(int offset) throws IOException{
if (offset == 0) {
return null;
}
@ -296,15 +296,28 @@ public class MCAFile {
streamChunk(getOffset(cx, cz), addReaders);
}
public void streamChunk(int offset, RunnableVal<NBTStreamer> addReaders) throws IOException {
if (offset == 0) {
return;
public void streamChunk(int offset, RunnableVal<NBTStreamer> withStream) throws IOException {
byte[] data = getChunkCompressedBytes(offset);
streamChunk(data, withStream);
}
public void streamChunk(byte[] data, RunnableVal<NBTStreamer> withStream) throws IOException {
if (data != null) {
try {
FastByteArrayInputStream nbtIn = new FastByteArrayInputStream(data);
FastByteArrayInputStream bais = new FastByteArrayInputStream(data);
InflaterInputStream iis = new InflaterInputStream(bais, new Inflater(), 1);
fieldBuf2.set(iis, byteStore2.get());
BufferedInputStream bis = new BufferedInputStream(iis);
NBTInputStream nis = new NBTInputStream(bis);
fieldBuf3.set(nis, byteStore3.get());
NBTStreamer streamer = new NBTStreamer(nis);
withStream.run(streamer);
streamer.readQuick();
} catch (IllegalAccessException unlikely) {
unlikely.printStackTrace();
}
}
NBTInputStream is = getChunkIS(offset);
NBTStreamer ns = new NBTStreamer(is);
addReaders.run(ns);
ns.readFully();
is.close();
}
/**

View File

@ -340,7 +340,6 @@ public class MCAQueue extends NMSMappedFaweQueue<FaweQueue, FaweChunk, FaweChunk
}
}
} catch (Throwable e) {
System.out.println("Failed to load: r." + mcaX + "." + mcaZ + ".mca -> (local) " + rcx + "," + rcz);
e.printStackTrace();
}
}