mirror of
https://github.com/Minestom/Minestom.git
synced 2024-11-13 22:25:53 +01:00
Avoid slow synchronized path during reference building
This commit is contained in:
parent
fdd3e2c53c
commit
c009ef0505
@ -8,7 +8,8 @@ import java.util.*;
|
|||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
final class SnapshotUpdaterImpl implements SnapshotUpdater {
|
final class SnapshotUpdaterImpl implements SnapshotUpdater {
|
||||||
private final Map<Snapshotable, AtomicReference<Snapshot>> referenceMap = new IdentityHashMap<>();
|
private final IdentityHashMap<Snapshotable, AtomicReference<Snapshot>> referenceMap = new IdentityHashMap<>();
|
||||||
|
private IdentityHashMap<Snapshotable, AtomicReference<Snapshot>> readOnlyReferenceMap;
|
||||||
private List<Entry> queue = new ArrayList<>();
|
private List<Entry> queue = new ArrayList<>();
|
||||||
|
|
||||||
static <T extends Snapshot> @NotNull T update(@NotNull Snapshotable snapshotable) {
|
static <T extends Snapshot> @NotNull T update(@NotNull Snapshotable snapshotable) {
|
||||||
@ -19,13 +20,22 @@ final class SnapshotUpdaterImpl implements SnapshotUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized <T extends Snapshot> @NotNull AtomicReference<T> reference(@NotNull Snapshotable snapshotable) {
|
public <T extends Snapshot> @NotNull AtomicReference<T> reference(@NotNull Snapshotable snapshotable) {
|
||||||
AtomicReference<Snapshot> ref = new AtomicReference<>();
|
AtomicReference<Snapshot> ref;
|
||||||
|
// Very often the same snapshotable is referenced multiple times.
|
||||||
|
var readOnly = this.readOnlyReferenceMap;
|
||||||
|
if (readOnly != null && (ref = readOnly.get(snapshotable)) != null) {
|
||||||
|
return (AtomicReference<T>) ref;
|
||||||
|
}
|
||||||
|
// If this is a new snapshotable, we need to create a new reference.
|
||||||
|
synchronized (this) {
|
||||||
|
ref = new AtomicReference<>();
|
||||||
var prev = referenceMap.putIfAbsent(snapshotable, ref);
|
var prev = referenceMap.putIfAbsent(snapshotable, ref);
|
||||||
if (prev != null) return (AtomicReference<T>) prev;
|
if (prev != null) return (AtomicReference<T>) prev;
|
||||||
this.queue.add(new Entry(snapshotable, ref));
|
this.queue.add(new Entry(snapshotable, ref));
|
||||||
return (AtomicReference<T>) ref;
|
return (AtomicReference<T>) ref;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
record Entry(Snapshotable snapshotable, AtomicReference<Snapshot> ref) {
|
record Entry(Snapshotable snapshotable, AtomicReference<Snapshot> ref) {
|
||||||
}
|
}
|
||||||
@ -34,6 +44,7 @@ final class SnapshotUpdaterImpl implements SnapshotUpdater {
|
|||||||
List<Entry> temp;
|
List<Entry> temp;
|
||||||
while (!(temp = new ArrayList<>(queue)).isEmpty()) {
|
while (!(temp = new ArrayList<>(queue)).isEmpty()) {
|
||||||
queue = new ArrayList<>();
|
queue = new ArrayList<>();
|
||||||
|
readOnlyReferenceMap = (IdentityHashMap<Snapshotable, AtomicReference<Snapshot>>) referenceMap.clone();
|
||||||
temp.parallelStream().forEach(entry -> {
|
temp.parallelStream().forEach(entry -> {
|
||||||
Snapshotable snap = entry.snapshotable;
|
Snapshotable snap = entry.snapshotable;
|
||||||
entry.ref.set(Objects.requireNonNull(snap.updateSnapshot(this), "Snapshot must not be null after an update!"));
|
entry.ref.set(Objects.requireNonNull(snap.updateSnapshot(this), "Snapshot must not be null after an update!"));
|
||||||
|
Loading…
Reference in New Issue
Block a user