3
0
Mirror von https://github.com/PaperMC/Paper.git synchronisiert 2024-12-15 19:10:09 +01:00

Improve synchronization on ExpiringMap

Dieser Commit ist enthalten in:
Aikar 2018-09-21 21:43:50 -04:00
Ursprung 60b1ed9c76
Commit 1db10a30db
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 401ADFC9891FAAFE

Datei anzeigen

@ -1,4 +1,4 @@
From e9f487b844501e35de9892cd88dfb2c85835b8f9 Mon Sep 17 00:00:00 2001 From 8fc3810e70f40446333e8ff71983e7c238afcac3 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Sun, 16 Sep 2018 00:00:16 -0400 Date: Sun, 16 Sep 2018 00:00:16 -0400
Subject: [PATCH] Optimize and Fix ExpiringMap Issues Subject: [PATCH] Optimize and Fix ExpiringMap Issues
@ -14,10 +14,10 @@ manipulation, and instead to run clean
once per tick per active expiring map. once per tick per active expiring map.
diff --git a/src/main/java/net/minecraft/server/ExpiringMap.java b/src/main/java/net/minecraft/server/ExpiringMap.java diff --git a/src/main/java/net/minecraft/server/ExpiringMap.java b/src/main/java/net/minecraft/server/ExpiringMap.java
index 4006f5a69c..9a3b35ea1a 100644 index 4006f5a69c..127de5c8df 100644
--- a/src/main/java/net/minecraft/server/ExpiringMap.java --- a/src/main/java/net/minecraft/server/ExpiringMap.java
+++ b/src/main/java/net/minecraft/server/ExpiringMap.java +++ b/src/main/java/net/minecraft/server/ExpiringMap.java
@@ -2,29 +2,124 @@ package net.minecraft.server; @@ -2,38 +2,163 @@ package net.minecraft.server;
import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2LongLinkedOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2LongMap; import it.unimi.dsi.fastutil.longs.Long2LongMap;
@ -42,21 +42,32 @@ index 4006f5a69c..9a3b35ea1a 100644
this.a = j; this.a = j;
} }
- private void a(long i) { + // Paper start
+ private void setAccess(long i) { a(i); } // Paper - OBFHELPER
private void a(long i) {
- long j = SystemUtils.b(); - long j = SystemUtils.b();
- this.b.put(i, j); - this.b.put(i, j);
- ObjectIterator objectiterator = this.b.long2LongEntrySet().iterator(); - ObjectIterator objectiterator = this.b.long2LongEntrySet().iterator();
+ // Paper start -
+ private synchronized void setAccess(long i) { a(i); } // Paper - OBFHELPER - while(objectiterator.hasNext()) {
+ private synchronized void a(long i) { - Entry entry = (Entry)objectiterator.next();
+ long j = System.currentTimeMillis(); // Paper - Object object = super.get(entry.getLongKey());
+ this.ttl.put(i, j); - if (j - entry.getLongValue() <= (long)this.a) {
+ if (!registered) { - break;
+ registered = true; + synchronized (this.sync) {
+ MinecraftServer.getServer().expiringMaps.add(this); + long j = System.currentTimeMillis(); // Paper
+ this.ttl.put(i, j);
+ if (!registered) {
+ registered = true;
+ MinecraftServer.getServer().expiringMaps.add(this);
}
+ } + }
+ } + }
+
- if (object != null && this.a(object)) {
- super.remove(entry.getLongKey());
- objectiterator.remove();
- }
+ @Override + @Override
+ public T compute(long l, BiFunction<? super Long, ? super T, ? extends T> biFunction) { + public T compute(long l, BiFunction<? super Long, ? super T, ? extends T> biFunction) {
+ setAccess(l); + setAccess(l);
@ -130,61 +141,64 @@ index 4006f5a69c..9a3b35ea1a 100644
+ } + }
+ +
+ @Override + @Override
+ public synchronized void clear() { + public void clear() {
+ ttl.clear(); + synchronized (this.sync) {
+ super.clear(); + ttl.clear();
+ super.clear();
}
+ } + }
+
+ private boolean registered = false; + private boolean registered = false;
+ private boolean hasLeaked = false; + private boolean hasLeaked = false;
+ +
+ // Break clean to its own method to be ticked + // Break clean to its own method to be ticked
+ synchronized boolean clean() { + boolean clean() {
+ long now = System.currentTimeMillis(); + synchronized (this.sync) {
+ ObjectIterator<Long2LongMap.Entry> objectiterator = this.ttl.long2LongEntrySet().iterator(); // Paper + long now = System.currentTimeMillis();
+ ObjectIterator<Long2LongMap.Entry> objectiterator = this.ttl.long2LongEntrySet().iterator(); // Paper
while(objectiterator.hasNext()) { +
- Entry entry = (Entry)objectiterator.next(); + while (objectiterator.hasNext()) {
- Object object = super.get(entry.getLongKey()); + Long2LongMap.Entry entry = objectiterator.next(); // Paper
- if (j - entry.getLongValue() <= (long)this.a) { + T object = super.get(entry.getLongKey()); // Paper
+ Long2LongMap.Entry entry = objectiterator.next(); // Paper + if (now - entry.getLongValue() <= (long) this.a) {
+ T object = super.get(entry.getLongKey()); // Paper + break;
+ if (now - entry.getLongValue() <= (long)this.a) {
break;
}
@@ -33,7 +128,29 @@ public class ExpiringMap<T> extends Long2ObjectOpenHashMap<T> {
objectiterator.remove();
}
}
-
+ int ttlSize = this.ttl.size();
+ int thisSize = this.size();
+ if (ttlSize < thisSize) {
+ if (!hasLeaked) { // log once
+ hasLeaked = true;
+ MinecraftServer.LOGGER.warn("WARNING: ExpiringMap desync (" + ttlSize + ":" + thisSize + ")- Memory leak risk! We will recover from this, but this means there is still a bug. Please do not open an issue about this. Mention it in Discord (we don't need everyone reporting the same thing)");
+ }
+ try {
+ for (Entry<T> entry : this.long2ObjectEntrySet()) {
+ ttl.putIfAbsent(entry.getLongKey(), now);
+ } + }
+ } catch (Exception e) { } // Ignore any como's +
+ } else if (ttlSize > this.size()) { + if (object != null && this.a(object)) {
+ try { + super.remove(entry.getLongKey());
+ this.ttl.long2LongEntrySet().removeIf(entry -> !this.containsKey(entry.getLongKey())); + objectiterator.remove();
+ } catch (Exception e) { } // Ignore any como's + }
+ }
+ int ttlSize = this.ttl.size();
+ int thisSize = this.size();
+ if (ttlSize < thisSize) {
+ if (!hasLeaked) { // log once
+ hasLeaked = true;
+ MinecraftServer.LOGGER.warn("WARNING: ExpiringMap desync (" + ttlSize + ":" + thisSize + ")- Memory leak risk! We will recover from this, but this means there is still a bug. Please do not open an issue about this. Mention it in Discord (we don't need everyone reporting the same thing)");
+ }
+ try {
+ for (Entry<T> entry : this.long2ObjectEntrySet()) {
+ ttl.putIfAbsent(entry.getLongKey(), now);
+ }
+ } catch (Exception e) {
+ } // Ignore any como's
+ } else if (ttlSize > this.size()) {
+ try {
+ this.ttl.long2LongEntrySet().removeIf(entry -> !this.containsKey(entry.getLongKey()));
+ } catch (Exception e) {
+ } // Ignore any como's
+ }
+ if (isEmpty()) {
+ registered = false;
+ return true;
+ }
+ return false;
+ } + }
+ if (isEmpty()) {
+ registered = false;
+ return true;
+ }
+ return false;
+ // Paper end + // Paper end
} }
protected boolean a(T var1) { protected boolean a(T var1) {
@@ -51,8 +168,13 @@ public class ExpiringMap<T> extends Long2ObjectOpenHashMap<T> { @@ -51,8 +176,13 @@ public class ExpiringMap<T> extends Long2ObjectOpenHashMap<T> {
} }
public T get(long i) { public T get(long i) {