Fix a lot of FAWE-freezing properly

- Add a "loadPrivately" method to be used when GetChunks are called to avoid synchronocity issues with super classes being used on different threads
 - Synchronise the call method so we're not attempting to call whilst also loading/updating
This commit is contained in:
dordsor21 2021-01-13 19:02:51 +00:00
parent e94e3b7b05
commit be9866ddb3
No known key found for this signature in database
GPG Key ID: 1E53E88969FFCF0B
6 changed files with 50 additions and 31 deletions

View File

@ -376,7 +376,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_15_2_Copy(world) : null;
try {
@ -424,7 +424,7 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
copy.storeSection(layer, loadPrivately(layer).clone());
}
ChunkSection newSection;
@ -458,12 +458,12 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
} else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) {
this.reset(layer);
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::load, setArr, fastmode);
newSection = BukkitAdapter_1_15_2.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
if (!BukkitAdapter_1_15_2.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
} else {
@ -676,6 +676,14 @@ public class BukkitGetBlocks_1_15_2 extends CharGetBlocks implements BukkitGetBl
}
}
private char[] loadPrivately(int layer) {
if (super.sections[layer].isFull()) {
return super.blocks[layer];
} else {
return BukkitGetBlocks_1_15_2.this.update(layer, null);
}
}
@Override
public synchronized void send(int mask, boolean lighting) {
BukkitAdapter_1_15_2.sendChunk(world, chunkX, chunkZ, mask, lighting);

View File

@ -376,7 +376,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_1_Copy(world) : null;
try {
@ -424,7 +424,7 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
copy.storeSection(layer, loadPrivately(layer).clone());
}
ChunkSection newSection;
@ -458,13 +458,13 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
} else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) {
this.reset(layer);
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_16_1
.newChunkSection(layer, this::load, setArr, fastmode);
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
if (!BukkitAdapter_1_16_1
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
@ -678,6 +678,14 @@ public class BukkitGetBlocks_1_16_1 extends CharGetBlocks implements BukkitGetBl
}
}
private char[] loadPrivately(int layer) {
if (super.sections[layer].isFull()) {
return super.blocks[layer];
} else {
return BukkitGetBlocks_1_16_1.this.update(layer, null);
}
}
@Override
public synchronized void send(int mask, boolean lighting) {
BukkitAdapter_1_16_1.sendChunk(world, chunkX, chunkZ, mask, lighting);

View File

@ -379,7 +379,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_2_Copy(world) : null;
try {
@ -427,7 +427,7 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
copy.storeSection(layer, loadPrivately(layer).clone());
}
ChunkSection newSection;
@ -461,13 +461,13 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
} else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) {
this.reset(layer);
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_16_2
.newChunkSection(layer, this::load, setArr, fastmode);
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
if (!BukkitAdapter_1_16_2
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
@ -681,6 +681,14 @@ public class BukkitGetBlocks_1_16_2 extends CharGetBlocks implements BukkitGetBl
}
}
private char[] loadPrivately(int layer) {
if (super.sections[layer].isFull()) {
return super.blocks[layer];
} else {
return BukkitGetBlocks_1_16_2.this.update(layer, null);
}
}
@Override
public synchronized void send(int mask, boolean lighting) {
BukkitAdapter_1_16_2.sendChunk(world, chunkX, chunkZ, mask, lighting);

View File

@ -379,7 +379,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
public synchronized <T extends Future<T>> T call(IChunkSet set, Runnable finalizer) {
forceLoadSections = false;
copy = createCopy ? new BukkitGetBlocks_1_16_4_Copy(world) : null;
try {
@ -427,7 +427,7 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl
char[] setArr = set.load(layer).clone();
if (createCopy) {
copy.storeSection(layer, load(layer).clone());
copy.storeSection(layer, loadPrivately(layer).clone());
}
ChunkSection newSection;
@ -461,13 +461,13 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl
} else if (existingSection != getSections(false)[layer]) {
this.sections[layer] = existingSection;
this.reset();
} else if (!Arrays.equals(update(layer, new char[4096]), load(layer))) {
} else if (!Arrays.equals(update(layer, new char[4096]), loadPrivately(layer))) {
this.reset(layer);
} else if (lock.isModified()) {
this.reset(layer);
}
newSection = BukkitAdapter_1_16_4
.newChunkSection(layer, this::load, setArr, fastmode);
.newChunkSection(layer, this::loadPrivately, setArr, fastmode);
if (!BukkitAdapter_1_16_4
.setSectionAtomic(sections, existingSection, newSection, layer)) {
log.error("Failed to set chunk section:" + chunkX + "," + chunkZ + " layer: " + layer);
@ -681,6 +681,14 @@ public class BukkitGetBlocks_1_16_4 extends CharGetBlocks implements BukkitGetBl
}
}
private char[] loadPrivately(int layer) {
if (super.sections[layer].isFull()) {
return super.blocks[layer];
} else {
return BukkitGetBlocks_1_16_4.this.update(layer, null);
}
}
@Override
public synchronized void send(int mask, boolean lighting) {
BukkitAdapter_1_16_4.sendChunk(world, chunkX, chunkZ, mask, lighting);

View File

@ -9,8 +9,6 @@ import org.jetbrains.annotations.Range;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.locks.ReentrantLock;
public abstract class CharBlocks implements IBlocks {
public static final Logger logger = LoggerFactory.getLogger(CharBlocks.class);

View File

@ -250,19 +250,8 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
// - memory is low & queue size > num threads + 8
// - queue size > target size and primary queue has less than num threads submissions
if (enabledQueue && ((lowMem && size > Settings.IMP.QUEUE.PARALLEL_THREADS + 8) || (size > Settings.IMP.QUEUE.TARGET_SIZE && Fawe.get().getQueueHandler().isUnderutilized()))) {
int i = 0;
boolean found = false;
while (i < chunks.size() && (chunk = chunks.get(i)) != null) {
if (Thread.holdsLock(chunk)) {
found = true;
break;
}
i++;
}
Future future = null;
if (found) {
future = submitUnchecked(chunk);
}
chunk = chunks.removeFirst();
final Future future = submitUnchecked(chunk);
if (future != null && !future.isDone()) {
final int targetSize;
if (lowMem) {