Fix issue where only the first request for a user subject would wait for the loading task to complete. Closes #108

This commit is contained in:
Luck 2016-12-30 00:42:33 +00:00
parent 2dad9f84fc
commit 2ce5679373
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B

View File

@ -52,14 +52,22 @@ import org.spongepowered.api.service.permission.PermissionService;
import co.aikar.timings.Timing; import co.aikar.timings.Timing;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class SpongeUserManager implements UserManager, LPSubjectCollection { public class SpongeUserManager implements UserManager, LPSubjectCollection {
private final LPSpongePlugin plugin; private final LPSpongePlugin plugin;
private final ReentrantLock loadingLock = new ReentrantLock();
private final Map<UUID, CountDownLatch> loadingLatches = Collections.synchronizedMap(new HashMap<>());
private final LoadingCache<UserIdentifier, SpongeUser> objects = CacheBuilder.newBuilder() private final LoadingCache<UserIdentifier, SpongeUser> objects = CacheBuilder.newBuilder()
.build(new CacheLoader<UserIdentifier, SpongeUser>() { .build(new CacheLoader<UserIdentifier, SpongeUser>() {
@Override @Override
@ -202,26 +210,68 @@ public class SpongeUserManager implements UserManager, LPSubjectCollection {
UUID u = plugin.getUuidCache().getUUID(uuid); UUID u = plugin.getUuidCache().getUUID(uuid);
// check if the user is loaded in memory. CountDownLatch latch;
if (isLoaded(UserIdentifier.of(u, null))) {
return get(u).getSpongeData();
} else {
// User isn't already loaded. hopefully this call is not on the main thread. :( loadingLock.lock();
//plugin.getLog().warn("User Subject '" + u + "' was requested, but is not loaded in memory. Loading them from storage now."); try {
long startTime = System.currentTimeMillis(); boolean loaded = isLoaded(UserIdentifier.of(u, null));
plugin.getStorage().loadUser(u, "null").join(); boolean locked = loadingLatches.containsKey(u);
SpongeUser user = get(u);
if (user == null) { if (loaded && !locked) {
plugin.getLog().severe("Error whilst loading user '" + u + "'."); return get(u).getSpongeData();
return plugin.getService().getFallbackUserSubjects().get(u.toString());
} }
user.setupData(false); if (!loaded && !locked) {
//plugin.getLog().warn("Loading '" + u + "' took " + (System.currentTimeMillis() - startTime) + " ms."); latch = new CountDownLatch(1);
return user.getSpongeData(); loadingLatches.put(u, latch);
// Request load.
plugin.doAsync(() -> {
try {
plugin.getStorage().loadUser(u, "null").get();
} catch (Exception e) {
e.printStackTrace();
}
SpongeUser user = get(u);
if (user == null) {
plugin.getLog().severe("Error whilst loading user '" + u + "'.");
latch.countDown();
return;
}
user.setupData(false);
latch.countDown();
loadingLatches.remove(u, latch);
});
} else {
// wait for the lock, then load.
latch = loadingLatches.get(u);
}
} finally {
loadingLock.unlock();
} }
// Wait for the task loading the user.
try {
latch.await(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
SpongeUser user = get(u);
if (user == null) {
plugin.getLog().warn("Failed to load user subject for id: " + id);
return plugin.getService().getFallbackUserSubjects().get(id); // fallback to the transient collection
}
if (user.getUserData() == null) {
plugin.getLog().warn("User data not present for requested user id: " + id);
}
return user.getSpongeData();
} }
} }