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:
parent
0100c8791d
commit
c5dfe3d0b7
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
Reference in New Issue
Block a user