Skip to content

Commit

Permalink
Use StampedLocks for performance reasons
Browse files Browse the repository at this point in the history
  • Loading branch information
me4502 committed Jul 7, 2024
1 parent a53b057 commit a4f2a18
Showing 1 changed file with 88 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.StampedLock;
import javax.annotation.Nullable;

import static com.google.common.base.Preconditions.checkNotNull;
Expand All @@ -77,8 +76,8 @@ public class PlatformManager {
private final AtomicBoolean initialized = new AtomicBoolean();
private final AtomicBoolean configured = new AtomicBoolean();

private final ReadWriteLock platformsLock = new ReentrantReadWriteLock();
private final ReadWriteLock preferencesLock = new ReentrantReadWriteLock();
private final StampedLock platformsLock = new StampedLock();
private final StampedLock preferencesLock = new StampedLock();

/**
* Create a new platform manager.
Expand Down Expand Up @@ -106,11 +105,11 @@ public void register(Platform platform) {

// Just add the platform to the list of platforms: we'll pick favorites
// once all the platforms have been loaded
platformsLock.writeLock().lock();
long stamp = platformsLock.writeLock();
try {
platforms.add(platform);
} finally {
platformsLock.writeLock().unlock();
platformsLock.unlockWrite(stamp);
}

// Make sure that versions are in sync
Expand All @@ -137,40 +136,40 @@ public boolean unregister(Platform platform) {
checkNotNull(platform);

boolean removed;
platformsLock.writeLock().lock();
long platformsStamp = platformsLock.writeLock();

try {
removed = platforms.remove(platform);
} finally {
platformsLock.unlockWrite(platformsStamp);
}

if (removed) {
LOGGER.info("Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit");
if (removed) {
LOGGER.info("Unregistering " + platform.getClass().getCanonicalName() + " from WorldEdit");

boolean choosePreferred = false;
boolean choosePreferred = false;

preferencesLock.writeLock().lock();
long preferencesStamp = preferencesLock.writeLock();

try {
// Check whether this platform was chosen to be the preferred one
// for any capability and be sure to remove it
Iterator<Entry<Capability, Platform>> it = preferences.entrySet().iterator();
while (it.hasNext()) {
Entry<Capability, Platform> entry = it.next();
if (entry.getValue().equals(platform)) {
entry.getKey().uninitialize(this, entry.getValue());
it.remove();
choosePreferred = true; // Have to choose new favorites
}
try {
// Check whether this platform was chosen to be the preferred one
// for any capability and be sure to remove it
Iterator<Entry<Capability, Platform>> it = preferences.entrySet().iterator();
while (it.hasNext()) {
Entry<Capability, Platform> entry = it.next();
if (entry.getValue().equals(platform)) {
entry.getKey().uninitialize(this, entry.getValue());
it.remove();
choosePreferred = true; // Have to choose new favorites
}
} finally {
preferencesLock.writeLock().unlock();
}
} finally {
preferencesLock.unlockWrite(preferencesStamp);
}

if (choosePreferred) {
choosePreferred();
}
if (choosePreferred) {
choosePreferred();
}
} finally {
platformsLock.writeLock().unlock();
}

return removed;
Expand All @@ -184,24 +183,33 @@ public boolean unregister(Platform platform) {
* @throws NoCapablePlatformException thrown if no platform is capable
*/
public Platform queryCapability(Capability capability) throws NoCapablePlatformException {
preferencesLock.readLock().lock();
checkNotNull(capability);

long stamp = preferencesLock.tryOptimisticRead();
Platform platform = preferences.get(capability);
boolean hasNoPreferences = platform == null && preferences.isEmpty();

if (!preferencesLock.validate(stamp)) {
stamp = preferencesLock.readLock();
try {
platform = preferences.get(capability);
hasNoPreferences = platform == null && preferences.isEmpty();
} finally {
preferencesLock.unlockRead(stamp);
}
}

try {
Platform platform = preferences.get(checkNotNull(capability));
if (platform != null) {
return platform;
} else {
if (preferences.isEmpty()) {
// Not all platforms registered, this is being called too early!
throw new NoCapablePlatformException(
"Not all platforms have been registered yet!"
+ " Please wait until WorldEdit is initialized."
);
}
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
if (platform != null) {
return platform;
} else {
if (hasNoPreferences) {
// Not all platforms registered, this is being called too early!
throw new NoCapablePlatformException(
"Not all platforms have been registered yet!"
+ " Please wait until WorldEdit is initialized."
);
}
} finally {
preferencesLock.readLock().unlock();
throw new NoCapablePlatformException("No platform was found supporting " + capability.name());
}
}

Expand All @@ -212,31 +220,37 @@ private void choosePreferred() {
for (Capability capability : Capability.values()) {
Platform preferred = findMostPreferred(capability);
if (preferred != null) {
preferencesLock.writeLock().lock();
Platform oldPreferred;
long stamp = preferencesLock.writeLock();
try {
Platform oldPreferred = preferences.put(capability, preferred);
// only (re)initialize if it changed
if (preferred != oldPreferred) {
// uninitialize if needed
if (oldPreferred != null) {
capability.uninitialize(this, oldPreferred);
}
capability.initialize(this, preferred);
}
oldPreferred = preferences.put(capability, preferred);
} finally {
preferencesLock.writeLock().unlock();
preferencesLock.unlockWrite(stamp);
}
// only (re)initialize if it changed
if (preferred != oldPreferred) {
// uninitialize if needed
if (oldPreferred != null) {
capability.uninitialize(this, oldPreferred);
}
capability.initialize(this, preferred);
}
}
}

preferencesLock.readLock().lock();
try {
// Fire configuration event
if (preferences.containsKey(Capability.CONFIGURATION) && configured.compareAndSet(false, true)) {
worldEdit.getEventBus().post(new ConfigurationLoadEvent(queryCapability(Capability.CONFIGURATION).getConfiguration()));
long stamp = preferencesLock.tryOptimisticRead();
boolean hasConfiguration = preferences.containsKey(Capability.CONFIGURATION);
if (!preferencesLock.validate(stamp)) {
stamp = preferencesLock.readLock();
try {
hasConfiguration = preferences.containsKey(Capability.CONFIGURATION);
} finally {
preferencesLock.unlockRead(stamp);
}
} finally {
preferencesLock.readLock().unlock();
}
// Fire configuration event
if (hasConfiguration && configured.compareAndSet(false, true)) {
worldEdit.getEventBus().post(new ConfigurationLoadEvent(queryCapability(Capability.CONFIGURATION).getConfiguration()));
}
}

Expand Down Expand Up @@ -270,12 +284,18 @@ private void choosePreferred() {
* @return a list of platforms
*/
public List<Platform> getPlatforms() {
platformsLock.readLock().lock();
try {
return new ArrayList<>(platforms);
} finally {
platformsLock.readLock().unlock();
long stamp = platformsLock.tryOptimisticRead();
List<Platform> platformsCopy = new ArrayList<>(platforms);
if (!platformsLock.validate(stamp)) {
stamp = platformsLock.readLock();
try {
platformsCopy = new ArrayList<>(platforms);
} finally {
platformsLock.unlockRead(stamp);
}
}

return platformsCopy;
}

/**
Expand Down

0 comments on commit a4f2a18

Please sign in to comment.