mirror of https://github.com/Minestom/Minestom.git
177 lines
6.6 KiB
Java
177 lines
6.6 KiB
Java
package thread;
|
|
|
|
import net.minestom.server.Tickable;
|
|
import net.minestom.server.thread.ThreadDispatcher;
|
|
import net.minestom.server.thread.ThreadProvider;
|
|
import net.minestom.server.thread.TickThread;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.CopyOnWriteArraySet;
|
|
import java.util.concurrent.Phaser;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.IntStream;
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
public class ThreadDispatcherTest {
|
|
|
|
@Test
|
|
public void elementTick() {
|
|
final AtomicInteger counter = new AtomicInteger();
|
|
ThreadDispatcher<Object> dispatcher = ThreadDispatcher.singleThread();
|
|
assertEquals(1, dispatcher.threads().size());
|
|
assertThrows(Exception.class, () -> dispatcher.threads().add(new TickThread(new Phaser(), 1)));
|
|
|
|
var partition = new Object();
|
|
Tickable element = (time) -> counter.incrementAndGet();
|
|
dispatcher.createPartition(partition);
|
|
dispatcher.updateElement(element, partition);
|
|
assertEquals(0, counter.get());
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
dispatcher.updateElement(element, partition); // Should be ignored
|
|
dispatcher.createPartition(partition); // Ignored too
|
|
assertEquals(1, counter.get());
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(2, counter.get());
|
|
|
|
dispatcher.removeElement(element);
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(2, counter.get());
|
|
|
|
dispatcher.shutdown();
|
|
}
|
|
|
|
@Test
|
|
public void partitionTick() {
|
|
// Partitions implementing Tickable should be ticked same as elements
|
|
final AtomicInteger counter1 = new AtomicInteger();
|
|
final AtomicInteger counter2 = new AtomicInteger();
|
|
ThreadDispatcher<Tickable> dispatcher = ThreadDispatcher.singleThread();
|
|
assertEquals(1, dispatcher.threads().size());
|
|
|
|
Tickable partition = (time) -> counter1.incrementAndGet();
|
|
Tickable element = (time) -> counter2.incrementAndGet();
|
|
dispatcher.createPartition(partition);
|
|
dispatcher.updateElement(element, partition);
|
|
assertEquals(0, counter1.get());
|
|
assertEquals(0, counter2.get());
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(1, counter1.get());
|
|
assertEquals(1, counter2.get());
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(2, counter1.get());
|
|
assertEquals(2, counter2.get());
|
|
|
|
dispatcher.deletePartition(partition);
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(2, counter1.get());
|
|
assertEquals(2, counter2.get());
|
|
|
|
dispatcher.shutdown();
|
|
}
|
|
|
|
@Test
|
|
public void uniqueThread() {
|
|
// Ensure that partitions are properly dispatched across threads
|
|
final int threadCount = 10;
|
|
ThreadDispatcher<Tickable> dispatcher = ThreadDispatcher.of(ThreadProvider.counter(), threadCount);
|
|
assertEquals(threadCount, dispatcher.threads().size());
|
|
|
|
final AtomicInteger counter = new AtomicInteger();
|
|
Set<Thread> threads = new CopyOnWriteArraySet<>();
|
|
Set<Tickable> partitions = IntStream.range(0, threadCount)
|
|
.mapToObj(value -> (Tickable) (time) -> {
|
|
final Thread thread = Thread.currentThread();
|
|
assertInstanceOf(TickThread.class, thread);
|
|
assertEquals(1, ((TickThread) thread).entries().size());
|
|
assertTrue(threads.add(thread));
|
|
counter.getAndIncrement();
|
|
})
|
|
.collect(Collectors.toUnmodifiableSet());
|
|
assertEquals(threadCount, partitions.size());
|
|
|
|
partitions.forEach(dispatcher::createPartition);
|
|
assertEquals(0, counter.get());
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
assertEquals(threadCount, counter.get());
|
|
|
|
dispatcher.shutdown();
|
|
}
|
|
|
|
@Test
|
|
public void threadUpdate() {
|
|
// Ensure that partitions threads are properly updated every tick
|
|
// when RefreshType.ALWAYS is used
|
|
interface Updater extends Tickable {
|
|
int getValue();
|
|
}
|
|
|
|
final int threadCount = 10;
|
|
ThreadDispatcher<Updater> dispatcher = ThreadDispatcher.of(new ThreadProvider<>() {
|
|
@Override
|
|
public int findThread(@NotNull Updater partition) {
|
|
return partition.getValue();
|
|
}
|
|
|
|
@Override
|
|
public @NotNull RefreshType refreshType() {
|
|
return RefreshType.ALWAYS;
|
|
}
|
|
}, threadCount);
|
|
assertEquals(threadCount, dispatcher.threads().size());
|
|
|
|
Map<Updater, Thread> threads = new ConcurrentHashMap<>();
|
|
Map<Updater, Thread> threads2 = new ConcurrentHashMap<>();
|
|
Set<Updater> partitions = IntStream.range(0, threadCount)
|
|
.mapToObj(value -> new Updater() {
|
|
private int v = value;
|
|
|
|
@Override
|
|
public int getValue() {
|
|
return v;
|
|
}
|
|
|
|
@Override
|
|
public void tick(long time) {
|
|
final Thread currentThread = Thread.currentThread();
|
|
assertInstanceOf(TickThread.class, currentThread);
|
|
if (threads.putIfAbsent(this, currentThread) == null) {
|
|
this.v = value + 1;
|
|
} else {
|
|
assertEquals(value + 1, v);
|
|
threads2.putIfAbsent(this, currentThread);
|
|
}
|
|
}
|
|
}).collect(Collectors.toUnmodifiableSet());
|
|
assertEquals(threadCount, partitions.size());
|
|
|
|
partitions.forEach(dispatcher::createPartition);
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
|
|
dispatcher.refreshThreads();
|
|
|
|
dispatcher.updateAndAwait(System.currentTimeMillis());
|
|
|
|
assertEquals(threads2.size(), threads.size());
|
|
assertNotEquals(threads, threads2, "Threads have not been updated at all");
|
|
for (var entry : threads.entrySet()) {
|
|
final Thread thread1 = entry.getValue();
|
|
final Thread thread2 = threads2.get(entry.getKey());
|
|
assertNotEquals(thread1, thread2);
|
|
}
|
|
|
|
dispatcher.shutdown();
|
|
}
|
|
}
|