Skip to content

Commit b76c25b

Browse files
committed
Try fixing region issues, and other tweaks/optimizations (fixes GlowstoneMC#995)
1 parent 2e8ce31 commit b76c25b

File tree

1 file changed

+38
-56
lines changed

1 file changed

+38
-56
lines changed

src/main/java/net/glowstone/io/anvil/RegionFile.java

+38-56
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,8 @@ public class RegionFile {
9898

9999
private static final byte[] emptySector = new byte[SECTOR_BYTES];
100100
private final int[] offsets;
101-
private final int[] chunkTimestamps;
102101
private RandomAccessFile file;
103102
private BitSet sectorsUsed;
104-
private int totalSectors;
105103
private final AtomicInteger sizeDelta = new AtomicInteger();
106104
/**
107105
* Returns the modification timestamp of the region file when it was first opened by this
@@ -121,7 +119,6 @@ public class RegionFile {
121119
*/
122120
public RegionFile(File path) throws IOException {
123121
offsets = new int[SECTOR_INTS];
124-
chunkTimestamps = new int[SECTOR_INTS];
125122

126123
sizeDelta.set(0);
127124

@@ -167,24 +164,24 @@ public RegionFile(File path) throws IOException {
167164
}
168165

169166
// set up the available sector map
170-
totalSectors = (int) file.length() / SECTOR_BYTES;
167+
int totalSectors = (int) Math.ceil(file.length() / (double) SECTOR_BYTES);
171168
sectorsUsed = new BitSet(totalSectors);
172169

173-
sectorsUsed.set(0);
174-
sectorsUsed.set(1);
170+
// reserve the first two sectors
171+
sectorsUsed.set(0, 2);
175172

176173
// read offset table and timestamp tables
177174
file.seek(0);
178175

179-
ByteBuffer header = ByteBuffer.allocate(2 * SECTOR_BYTES);
176+
ByteBuffer header = ByteBuffer.allocate(SECTOR_BYTES);
180177
while (header.hasRemaining()) {
181178
if (file.getChannel().read(header) == -1) {
182179
throw new EOFException();
183180
}
184181
}
185-
header.clear();
182+
header.flip();
186183

187-
// populate the tables
184+
// populate the offset table
188185
IntBuffer headerAsInts = header.asIntBuffer();
189186
for (int i = 0; i < SECTOR_INTS; ++i) {
190187
int offset = headerAsInts.get();
@@ -194,20 +191,14 @@ public RegionFile(File path) throws IOException {
194191
int numSectors = offset & 255;
195192

196193
if (offset != 0 && startSector >= 0 && startSector + numSectors <= totalSectors) {
197-
for (int sectorNum = 0; sectorNum < numSectors; ++sectorNum) {
198-
sectorsUsed.set(startSector + sectorNum);
199-
}
194+
sectorsUsed.set(startSector, startSector + numSectors + 1);
200195
} else if (offset != 0) {
201196
GlowServer.logger.warning(
202197
"Region \"" + path + "\": offsets[" + i + "] = " + offset + " -> "
203198
+ startSector
204199
+ "," + numSectors + " does not fit");
205200
}
206201
}
207-
// read timestamps from timestamp table
208-
for (int i = 0; i < SECTOR_INTS; ++i) {
209-
chunkTimestamps[i] = headerAsInts.get();
210-
}
211202
}
212203

213204
/**
@@ -237,6 +228,7 @@ public DataInputStream getChunkDataInputStream(int x, int z) throws IOException
237228
return null;
238229
}
239230

231+
int totalSectors = sectorsUsed.length();
240232
int sectorNumber = offset >> 8;
241233
int numSectors = offset & 0xFF;
242234
if (sectorNumber + numSectors > totalSectors) {
@@ -320,56 +312,52 @@ protected void write(int x, int z, byte[] data, int length) throws IOException {
320312
/* we can simply overwrite the old sectors */
321313
write(sectorNumber, data, length);
322314
} else {
323-
/* we need to allocate new sectors */
324-
325315
/* mark the sectors previously used for this chunk as free */
326-
for (int i = 0; i < sectorsAllocated; ++i) {
327-
sectorsUsed.clear(sectorNumber + i);
316+
if (sectorNumber != 0) {
317+
sectorsUsed.clear(sectorNumber, sectorNumber + sectorsAllocated + 1);
328318
}
329319

330320
/* scan for a free space large enough to store this chunk */
331-
int runStart = 2;
332-
int runLength = 0;
333-
int currentSector = 2;
334-
while (runLength < sectorsNeeded) {
335-
int nextSector = sectorsUsed.nextClearBit(currentSector + 1);
336-
if (currentSector + 1 == nextSector) {
337-
runLength++;
338-
} else {
339-
runStart = nextSector;
340-
runLength = 1;
341-
}
342-
currentSector = nextSector;
343-
}
344-
345-
if (runLength >= sectorsNeeded) {
346-
/* we found a free space large enough */
347-
sectorNumber = runStart;
348-
setOffset(x, z, sectorNumber << 8 | sectorsNeeded);
349-
for (int i = 0; i < sectorsNeeded; ++i) {
350-
sectorsUsed.set(sectorNumber + i);
351-
}
352-
write(sectorNumber, data, length);
353-
} else {
321+
sectorNumber = findNewSectorStart(sectorsNeeded);
322+
if (sectorNumber == -1) {
354323
/*
355324
* no free space large enough found -- we need to grow the
356325
* file
357326
*/
358327
file.seek(file.length());
359-
sectorNumber = totalSectors;
360328
for (int i = 0; i < sectorsNeeded; ++i) {
361329
file.write(emptySector);
362-
sectorsUsed.set(totalSectors + i);
363330
}
364-
totalSectors += sectorsNeeded;
365331
sizeDelta.addAndGet(SECTOR_BYTES * sectorsNeeded);
332+
sectorNumber = sectorsUsed.length();
333+
}
334+
335+
sectorsUsed.set(sectorNumber, sectorNumber + sectorsNeeded + 1);
336+
write(sectorNumber, data, length);
337+
setOffset(x, z, sectorNumber << 8 | sectorsNeeded);
338+
}
339+
}
366340

367-
write(sectorNumber, data, length);
368-
setOffset(x, z, sectorNumber << 8 | sectorsNeeded);
341+
private int findNewSectorStart(int sectorsNeeded) {
342+
int start = -1;
343+
int runLength = 0;
344+
for (int i = sectorsUsed.nextClearBit(0); i < sectorsUsed.length(); i++) {
345+
if (sectorsUsed.get(i)) {
346+
// must reset
347+
start = -1;
348+
runLength = 0;
349+
} else {
350+
if (start == -1) {
351+
start = i;
352+
}
353+
runLength++;
354+
if (runLength >= sectorsNeeded) {
355+
return start;
356+
}
369357
}
370358
}
371-
setTimestamp(x, z, (int) (System.currentTimeMillis() / 1000L));
372-
//file.getChannel().force(true);
359+
// reached the end, append to the end of the region instead
360+
return -1;
373361
}
374362

375363
/* write a chunk data to the region file at specified sector number */
@@ -401,12 +389,6 @@ private void setOffset(int x, int z, int offset) throws IOException {
401389
file.writeInt(offset);
402390
}
403391

404-
private void setTimestamp(int x, int z, int value) throws IOException {
405-
chunkTimestamps[x + (z << 5)] = value;
406-
file.seek(SECTOR_BYTES + ((x + (z << 5)) << 2));
407-
file.writeInt(value);
408-
}
409-
410392
public void close() throws IOException {
411393
file.getChannel().force(true);
412394
file.close();

0 commit comments

Comments
 (0)