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
This commit is contained in:
crast 2013-06-01 13:52:30 -06:00
parent 002a6a15e5
commit fc77a4d2d3

View file

@ -12,7 +12,7 @@ import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
public abstract class MetadataStoreBase<T> { 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 * 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); entry = new WeakHashMap<Plugin, MetadataValue>(1);
metadataMap.put(key, entry); 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) * @see MetadataStore#getMetadata(Object, String)
*/ */
@NotNull @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); String key = disambiguate(subject, metadataKey);
if (metadataMap.containsKey(key)) { Map<Plugin, MetadataValue> entry = metadataMap.get(key);
Collection<MetadataValue> values = metadataMap.get(key).values(); if (entry != null) {
Collection<MetadataValue> values = entry.values();
return Collections.unmodifiableList(new ArrayList<MetadataValue>(values)); return Collections.unmodifiableList(new ArrayList<MetadataValue>(values));
} else { } else {
return Collections.emptyList(); return Collections.emptyList();
@ -78,7 +81,7 @@ public abstract class MetadataStoreBase<T> {
* @param metadataKey the unique metadata key being queried. * @param metadataKey the unique metadata key being queried.
* @return the existence of the metadataKey within subject. * @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); String key = disambiguate(subject, metadataKey);
return metadataMap.containsKey(key); return metadataMap.containsKey(key);
} }
@ -94,17 +97,18 @@ public abstract class MetadataStoreBase<T> {
* @see MetadataStore#removeMetadata(Object, String, * @see MetadataStore#removeMetadata(Object, String,
* org.bukkit.plugin.Plugin) * 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"); Preconditions.checkArgument(owningPlugin != null, "Plugin cannot be null");
String key = disambiguate(subject, metadataKey); String key = disambiguate(subject, metadataKey);
Map<Plugin, MetadataValue> entry = metadataMap.get(key); Map<Plugin, MetadataValue> entry = metadataMap.get(key);
if (entry == null) { if (entry == null) {
return; return;
} }
synchronized (entry) {
entry.remove(owningPlugin); entry.remove(owningPlugin);
if (entry.isEmpty()) { if (entry.isEmpty()) {
metadataMap.remove(key); metadataMap.remove(key);
}
} }
} }
@ -117,7 +121,7 @@ public abstract class MetadataStoreBase<T> {
* @throws IllegalArgumentException If plugin is null * @throws IllegalArgumentException If plugin is null
* @see MetadataStore#invalidateAll(org.bukkit.plugin.Plugin) * @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"); Preconditions.checkArgument(owningPlugin != null, "Plugin cannot be null");
for (Map<Plugin, MetadataValue> values : metadataMap.values()) { for (Map<Plugin, MetadataValue> values : metadataMap.values()) {
if (values.containsKey(owningPlugin)) { if (values.containsKey(owningPlugin)) {