Skip to content

Commit

Permalink
Thread safety fixes (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
HaHaWTH authored Feb 11, 2025
1 parent 19fbe8c commit bdccf34
Show file tree
Hide file tree
Showing 3 changed files with 235 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ for the case of some NPC plugins which using real entity type, e.g. Citizens.
But it is still recommending to use those packet based, virtual entity
based NPC plugins, e.g. ZNPC Plus, Adyeshach, Fancy NPC, etc.

diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index dd2509996bfd08e8c3f9f2be042229eac6d7692d..a35e9fae8f8da0c42f0616c4f78dc396492673aa 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -342,7 +342,7 @@ public final class RegionizedPlayerChunkLoader {
private boolean canGenerateChunks = true;

private final ArrayDeque<ChunkHolderManager.TicketOperation<?, ?>> delayedTicketOps = new ArrayDeque<>();
- private final LongOpenHashSet sentChunks = new LongOpenHashSet();
+ private final LongOpenHashSet sentChunks = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && !org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled ? new org.dreeam.leaf.util.map.ConcurrentLongHashSet() : new LongOpenHashSet(); // Leaf - Multithreaded tracker

private static final byte CHUNK_TICKET_STAGE_NONE = 0;
private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 5d9d233e3a568aa6297ed9c703fa450f98158602..8986c059e7aadb58ae8d9ab7b848de10f9faa6b2 100644
--- a/net/minecraft/server/level/ChunkMap.java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Original license: GPL v3
Original project: https://github.com/pufferfish-gg/Pufferfish

Co-authored-by: booky10 <[email protected]>
Co-authored-by: HaHaWTH <[email protected]>

This patch aims to reduce the main-thread impact of mob spawning by
offloading as much work as possible to other threads. It is possible for
Expand All @@ -22,9 +23,18 @@ and, in my opinion, worth the low risk of minor mob-spawning-related
inconsistencies.

diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
index c21e00812f1aaa1279834a0562d360d6b89e146c..877d2095a066854939f260ca4b0b8c7b5abb620f 100644
index c21e00812f1aaa1279834a0562d360d6b89e146c..4ae478c04ef44c91408a7f3f0405291f91794873 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
@@ -10,7 +10,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
public static final int ITERATOR_FLAG_SEE_ADDITIONS = 1 << 0;

private final Reference2IntLinkedOpenHashMap<E> indexMap;
- private int firstInvalidIndex = -1;
+ private volatile int firstInvalidIndex = -1; // Leaf - Async mob spawning - volatile

/* list impl */
private E[] listElements;
@@ -18,7 +18,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {

private final double maxFragFactor;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
package org.dreeam.leaf.util.map;

import it.unimi.dsi.fastutil.longs.LongCollection;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import it.unimi.dsi.fastutil.longs.LongSet;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
* A thread-safe implementation of {@link LongOpenHashSet} using ConcurrentHashMap.KeySetView as backing storage.
* This implementation provides concurrent access and high performance for concurrent operations.
*/
@SuppressWarnings({"unused", "deprecation"})
public final class ConcurrentLongHashSet extends LongOpenHashSet implements LongSet { // Extending LongOpenHashSet for some moonrise usages
private final ConcurrentHashMap.KeySetView<Long, Boolean> backing;

/**
* Creates a new empty concurrent long set.
*/
public ConcurrentLongHashSet() {
this.backing = ConcurrentHashMap.newKeySet();
}

@Override
public int size() {
return backing.size();
}

@Override
public boolean isEmpty() {
return backing.isEmpty();
}

@Override
public @NotNull LongIterator iterator() {
return new WrappingLongIterator(backing.iterator());
}

@NotNull
@Override
public Object @NotNull [] toArray() {
return backing.toArray();
}

@NotNull
@Override
public <T> T @NotNull [] toArray(@NotNull T @NotNull [] array) {
Objects.requireNonNull(array, "Array cannot be null");
return backing.toArray(array);
}

@Override
public boolean containsAll(@NotNull Collection<?> collection) {
Objects.requireNonNull(collection, "Collection cannot be null");
return backing.containsAll(collection);
}

@Override
public boolean addAll(@NotNull Collection<? extends Long> collection) {
Objects.requireNonNull(collection, "Collection cannot be null");
return backing.addAll(collection);
}

@Override
public boolean removeAll(@NotNull Collection<?> collection) {
Objects.requireNonNull(collection, "Collection cannot be null");
return backing.removeAll(collection);
}

@Override
public boolean retainAll(@NotNull Collection<?> collection) {
Objects.requireNonNull(collection, "Collection cannot be null");
return backing.retainAll(collection);
}

@Override
public void clear() {
backing.clear();
}

@Override
public boolean add(long key) {
return backing.add(key);
}

@Override
public boolean contains(long key) {
return backing.contains(key);
}

@Override
public long[] toLongArray() {
int size = backing.size();
long[] result = new long[size];
int i = 0;
for (Long value : backing) {
result[i++] = value;
}
return result;
}

@Override
public long[] toArray(long[] array) {
Objects.requireNonNull(array, "Array cannot be null");
long[] result = toLongArray();
if (array.length < result.length) {
return result;
}
System.arraycopy(result, 0, array, 0, result.length);
if (array.length > result.length) {
array[result.length] = 0;
}
return array;
}

@Override
public boolean addAll(LongCollection c) {
Objects.requireNonNull(c, "Collection cannot be null");
boolean modified = false;
LongIterator iterator = c.iterator();
while (iterator.hasNext()) {
modified |= add(iterator.nextLong());
}
return modified;
}

@Override
public boolean containsAll(LongCollection c) {
Objects.requireNonNull(c, "Collection cannot be null");
LongIterator iterator = c.iterator();
while (iterator.hasNext()) {
if (!contains(iterator.nextLong())) {
return false;
}
}
return true;
}

@Override
public boolean removeAll(LongCollection c) {
Objects.requireNonNull(c, "Collection cannot be null");
boolean modified = false;
LongIterator iterator = c.iterator();
while (iterator.hasNext()) {
modified |= remove(iterator.nextLong());
}
return modified;
}

@Override
public boolean retainAll(LongCollection c) {
Objects.requireNonNull(c, "Collection cannot be null");
return backing.retainAll(c);
}

@Override
public boolean remove(long k) {
return backing.remove(k);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof LongSet that)) return false;
if (size() != that.size()) return false;
return containsAll(that);
}

@Override
public int hashCode() {
return backing.hashCode();
}

@Override
public String toString() {
return backing.toString();
}

static class WrappingLongIterator implements LongIterator {
private final Iterator<Long> backing;

WrappingLongIterator(Iterator<Long> backing) {
this.backing = Objects.requireNonNull(backing);
}

@Override
public boolean hasNext() {
return backing.hasNext();
}

@Override
public long nextLong() {
return backing.next();
}

@Override
public Long next() {
return backing.next();
}

@Override
public void remove() {
backing.remove();
}
}
}

0 comments on commit bdccf34

Please sign in to comment.