Saving Modifications

-Safer saving, it waits for the file to stop being used to close(still
has holes)
-If a chunk is too large, it is moved to the end of the file.
	-Calculates the efficiency of each region file in confirmHeaderHealth
-Fixed import warning
This commit is contained in:
opfromthestart 2021-09-09 16:52:55 -04:00
parent 0100c8791d
commit c5dfe3d0b7
3 changed files with 63 additions and 4 deletions

View File

@ -31,7 +31,6 @@ import ru.windcorp.progressia.common.comms.CommsChannel.State;
import ru.windcorp.progressia.common.comms.packets.Packet; import ru.windcorp.progressia.common.comms.packets.Packet;
import ru.windcorp.progressia.common.world.PacketSetGravityModel; import ru.windcorp.progressia.common.world.PacketSetGravityModel;
import ru.windcorp.progressia.common.world.PacketSetLocalPlayer; import ru.windcorp.progressia.common.world.PacketSetLocalPlayer;
import ru.windcorp.progressia.common.world.entity.EntityData;
import ru.windcorp.progressia.server.Player; import ru.windcorp.progressia.server.Player;
import ru.windcorp.progressia.server.Server; import ru.windcorp.progressia.server.Server;

View File

@ -30,9 +30,12 @@ import java.io.RandomAccessFile;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import org.apache.logging.log4j.LogManager;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.state.IOContext; import ru.windcorp.progressia.common.state.IOContext;
import ru.windcorp.progressia.common.world.DecodingException; import ru.windcorp.progressia.common.world.DecodingException;
@ -52,10 +55,15 @@ public class Region {
private static final int SECTORS_BYTES = Short.BYTES; private static final int SECTORS_BYTES = Short.BYTES;
private static final int SECTOR_SIZE = MAX_CHUNK_SIZE >> (SECTORS_BYTES*8); private static final int SECTOR_SIZE = MAX_CHUNK_SIZE >> (SECTORS_BYTES*8);
public int loadedChunks;
private static final int DEFINITION_SIZE = Integer.BYTES + Short.BYTES; private static final int DEFINITION_SIZE = Integer.BYTES + Short.BYTES;
private static final int HEADER_SIZE = DEFINITION_SIZE * REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER; private static final int HEADER_SIZE = DEFINITION_SIZE * REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER;
private AtomicBoolean isUsing = new AtomicBoolean(false);
private AtomicBoolean isClosed = new AtomicBoolean(false);
private final RandomAccessFile file; private final RandomAccessFile file;
private final ChunkMap<Integer> offsets = ChunkMaps.newHashMap(); private final ChunkMap<Integer> offsets = ChunkMaps.newHashMap();
@ -90,6 +98,7 @@ public class Region {
public void close() throws IOException { public void close() throws IOException {
this.file.close(); this.file.close();
isClosed.lazySet(true);;
} }
public int getOffset(Vec3i chunkLoc) { public int getOffset(Vec3i chunkLoc) {
@ -116,9 +125,20 @@ public class Region {
lengths.put(pos, length); lengths.put(pos, length);
} }
public AtomicBoolean isClosed()
{
return isClosed;
}
public AtomicBoolean isUsing()
{
return isUsing;
}
private void confirmHeaderHealth() throws IOException { private void confirmHeaderHealth() throws IOException {
Set<Integer> used = new HashSet<Integer>(); Set<Integer> used = new HashSet<Integer>();
int maxUsed = 0;
final int chunksPerRegion = REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER; final int chunksPerRegion = REGION_DIAMETER * REGION_DIAMETER * REGION_DIAMETER;
file.seek(0); file.seek(0);
@ -143,16 +163,22 @@ public class Region {
offsets.put(pos, offset); offsets.put(pos, offset);
lengths.put(pos, sectorLength); lengths.put(pos, sectorLength);
if (offset+sectorLength > maxUsed)
{
maxUsed = offset + sectorLength;
}
for (int sector = 0; sector < sectorLength; sector++) { for (int sector = 0; sector < sectorLength; sector++) {
if (!used.add(offset + sector)) { if (!used.add(offset + sector)) {
throw new IOException("A sector is used twice"); throw new IOException("A sector is used twice");
} }
} }
} }
LogManager.getLogger("Region").debug("Efficiency of {}", (double) used.size()/maxUsed);
} }
public void save(DefaultChunkData chunk, Server server) throws IOException { public void save(DefaultChunkData chunk, Server server) throws IOException {
isUsing.set(true);
Vec3i pos = TestWorldDiskIO.getInRegionCoords(chunk.getPosition()); Vec3i pos = TestWorldDiskIO.getInRegionCoords(chunk.getPosition());
int definitionOffset = DEFINITION_SIZE * (pos.z + REGION_DIAMETER * (pos.y + REGION_DIAMETER * pos.x)); int definitionOffset = DEFINITION_SIZE * (pos.z + REGION_DIAMETER * (pos.y + REGION_DIAMETER * pos.x));
@ -162,7 +188,16 @@ public class Region {
int dataOffset = getOffset(pos); int dataOffset = getOffset(pos);
byte[] buffer = saveToBuffer(chunk, server); byte[] buffer = saveToBuffer(chunk, server);
if (hasLength(pos) && buffer.length > getLength(pos)*SECTOR_SIZE )
{
byte emptyBuffer[] = new byte[getLength(pos)*SECTOR_SIZE];
writeBuffer(emptyBuffer, definitionOffset, dataOffset, pos);
allocateChunk(definitionOffset, pos);
dataOffset = getOffset(pos);
}
writeBuffer(buffer, definitionOffset, dataOffset, pos); writeBuffer(buffer, definitionOffset, dataOffset, pos);
isUsing.set(false);
} }
private byte[] saveToBuffer(DefaultChunkData chunk, Server server) throws IOException { private byte[] saveToBuffer(DefaultChunkData chunk, Server server) throws IOException {
@ -208,6 +243,7 @@ public class Region {
public DefaultChunkData load(Vec3i chunkPos, DefaultWorldData world, Server server) public DefaultChunkData load(Vec3i chunkPos, DefaultWorldData world, Server server)
throws IOException, throws IOException,
DecodingException { DecodingException {
isUsing.set(true);
int dataOffset = 0; int dataOffset = 0;
int sectorLength = 0; int sectorLength = 0;
@ -222,6 +258,7 @@ public class Region {
byte[] buffer = readBuffer(dataOffset, sectorLength); byte[] buffer = readBuffer(dataOffset, sectorLength);
DefaultChunkData result = loadFromBuffer(buffer, chunkPos, world, server); DefaultChunkData result = loadFromBuffer(buffer, chunkPos, world, server);
isUsing.set(false);
return result; return result;
} }

View File

@ -18,6 +18,8 @@
package ru.windcorp.progressia.test.region; package ru.windcorp.progressia.test.region;
import java.util.concurrent.atomic.AtomicBoolean;
import glm.vec._3.i.Vec3i; import glm.vec._3.i.Vec3i;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -227,8 +229,29 @@ public class TestWorldDiskIO implements WorldContainer {
@Override @Override
public void close() { public void close() {
try { try {
for (Region region : regions.values()) { ChunkMap<AtomicBoolean> isCloseds = ChunkMaps.newHashMap();
region.close(); ChunkMap<AtomicBoolean> isUsings = ChunkMaps.newHashMap();
for (Vec3i region : regions.keys())
{
isCloseds.put(region, regions.get(region).isClosed());
isUsings.put(region, regions.get(region).isUsing());
}
boolean stillOpen = true;
while (stillOpen)
{
stillOpen = false;
for (Vec3i region : regions.keys()) {
if (!isCloseds.get(region).get() && !isUsings.get(region).get())
{
regions.get(region).close();
}
else if (isUsings.get(region).get())
{
stillOpen = false;
}
}
} }
} catch (IOException e) { } catch (IOException e) {
throw CrashReports.report(e, "Could not close region files"); throw CrashReports.report(e, "Could not close region files");