From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: crast <contact@jamescrasta.com> Date: Sat, 1 Jun 2013 13:52:30 -0600 Subject: [PATCH] Reduce thread synchronization in MetadataStoreBase Use ConcurrentHashMap to allow thread-safe access methods and very limited synchronized portions to allow much higher concurrency in MetadataStore as well as far less locking, especially on reads diff --git a/src/main/java/org/bukkit/metadata/MetadataStoreBase.java b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java index 6886a7003fb76d07e0fa9c1c352c56480f08a0db..a0698522f01619c9d37474f4bd55a17de58fff89 100644 --- a/src/main/java/org/bukkit/metadata/MetadataStoreBase.java +++ b/src/main/java/org/bukkit/metadata/MetadataStoreBase.java @@ -12,7 +12,7 @@ import org.bukkit.plugin.Plugin; import org.jetbrains.annotations.NotNull; public abstract class MetadataStoreBase<T> { - private Map<String, Map<Plugin, MetadataValue>> metadataMap = new HashMap<String, Map<Plugin, MetadataValue>>(); + private Map<String, Map<Plugin, MetadataValue>> metadataMap = new java.util.concurrent.ConcurrentHashMap<String, Map<Plugin, MetadataValue>>(); // Paper /** * Adds a metadata value to an object. Each metadata value is owned by a @@ -46,7 +46,9 @@ public abstract class MetadataStoreBase<T> { entry = new WeakHashMap<Plugin, MetadataValue>(1); metadataMap.put(key, entry); } - entry.put(owningPlugin, newMetadataValue); + synchronized (entry) { + entry.put(owningPlugin, newMetadataValue); + } } /** @@ -60,10 +62,11 @@ public abstract class MetadataStoreBase<T> { * @see MetadataStore#getMetadata(Object, String) */ @NotNull - public synchronized List<MetadataValue> getMetadata(@NotNull T subject, @NotNull String metadataKey) { + public List<MetadataValue> getMetadata(@NotNull T subject, @NotNull String metadataKey) { // Paper String key = disambiguate(subject, metadataKey); - if (metadataMap.containsKey(key)) { - Collection<MetadataValue> values = metadataMap.get(key).values(); + Map<Plugin, MetadataValue> entry = metadataMap.get(key); + if (entry != null) { + Collection<MetadataValue> values = entry.values(); return Collections.unmodifiableList(new ArrayList<MetadataValue>(values)); } else { return Collections.emptyList(); @@ -78,7 +81,7 @@ public abstract class MetadataStoreBase<T> { * @param metadataKey the unique metadata key being queried. * @return the existence of the metadataKey within subject. */ - public synchronized boolean hasMetadata(@NotNull T subject, @NotNull String metadataKey) { + public boolean hasMetadata(@NotNull T subject, @NotNull String metadataKey) { // Paper String key = disambiguate(subject, metadataKey); return metadataMap.containsKey(key); } @@ -94,17 +97,18 @@ public abstract class MetadataStoreBase<T> { * @see MetadataStore#removeMetadata(Object, String, * org.bukkit.plugin.Plugin) */ - public synchronized void removeMetadata(@NotNull T subject, @NotNull String metadataKey, @NotNull Plugin owningPlugin) { + public void removeMetadata(@NotNull T subject, @NotNull String metadataKey, @NotNull Plugin owningPlugin) { // Paper Preconditions.checkArgument(owningPlugin != null, "Plugin cannot be null"); String key = disambiguate(subject, metadataKey); Map<Plugin, MetadataValue> entry = metadataMap.get(key); if (entry == null) { return; } - - entry.remove(owningPlugin); - if (entry.isEmpty()) { - metadataMap.remove(key); + synchronized (entry) { + entry.remove(owningPlugin); + if (entry.isEmpty()) { + metadataMap.remove(key); + } } } @@ -117,7 +121,7 @@ public abstract class MetadataStoreBase<T> { * @throws IllegalArgumentException If plugin is null * @see MetadataStore#invalidateAll(org.bukkit.plugin.Plugin) */ - public synchronized void invalidateAll(@NotNull Plugin owningPlugin) { + public void invalidateAll(@NotNull Plugin owningPlugin) { // Paper Preconditions.checkArgument(owningPlugin != null, "Plugin cannot be null"); for (Map<Plugin, MetadataValue> values : metadataMap.values()) { if (values.containsKey(owningPlugin)) {