diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index 47d08050..1a87ad00 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -49,6 +49,7 @@ import me.lucko.luckperms.common.storage.Datastore; import me.lucko.luckperms.common.storage.StorageFactory; import me.lucko.luckperms.common.tracks.TrackManager; import me.lucko.luckperms.common.users.UserManager; +import me.lucko.luckperms.common.utils.BufferedRequest; import me.lucko.luckperms.common.utils.LocaleManager; import me.lucko.luckperms.common.utils.LogFactory; import org.bukkit.World; @@ -84,6 +85,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { private ContextManager contextManager; private WorldCalculator worldCalculator; private CalculatorFactory calculatorFactory; + private BufferedRequest updateTaskBuffer; @Override public void onEnable() { @@ -139,10 +141,19 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { contextManager.registerListener(new AutoOPListener()); } + final LPBukkitPlugin i = this; + updateTaskBuffer = new BufferedRequest(5000L, this::doAsync) { + @Override + protected Void perform() { + getServer().getScheduler().runTaskAsynchronously(i, new UpdateTask(i)); + return null; + } + }; + int mins = getConfiguration().getSyncTime(); if (mins > 0) { long ticks = mins * 60 * 20; - getServer().getScheduler().runTaskTimerAsynchronously(this, new UpdateTask(this), ticks, ticks); + getServer().getScheduler().runTaskTimerAsynchronously(this, () -> updateTaskBuffer.request(), ticks, ticks); } getServer().getScheduler().runTaskTimer(this, BukkitSenderFactory.get(this), 1L, 1L); @@ -188,7 +199,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { @Override public void onDisable() { getLog().info("Closing datastore..."); - datastore.shutdown(); + datastore.shutdown().getOrDefault(null); getLog().info("Unregistering API..."); ApiHandler.unregisterProvider(); @@ -209,6 +220,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { getServer().getScheduler().runTask(this, r); } + @Override + public void doAsyncRepeating(Runnable r, long interval) { + getServer().getScheduler().runTaskTimerAsynchronously(this, r, interval, interval); + } + @Override public String getVersion() { return getDescription().getVersion(); @@ -347,11 +363,6 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { return getServer().getPluginManager().isPluginEnabled(name); } - @Override - public void runUpdateTask() { - getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this)); - } - private void registerPermissions(PermissionDefault def) { PluginManager pm = getServer().getPluginManager(); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeListener.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeListener.java index 3fd73f01..181fe957 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeListener.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeListener.java @@ -95,7 +95,7 @@ public class BungeeListener extends AbstractListener implements Listener { final PendingConnection c = e.getConnection(); if (!cache.isOnlineMode()) { - UUID uuid = plugin.getDatastore().getUUID(c.getName()); + UUID uuid = plugin.getDatastore().getUUID(c.getName()).getOrDefault(null); if (uuid != null) { cache.addToCache(c.getUniqueId(), uuid); } else { @@ -105,7 +105,7 @@ public class BungeeListener extends AbstractListener implements Listener { plugin.getDatastore().saveUUIDData(c.getName(), c.getUniqueId()); } } else { - UUID uuid = plugin.getDatastore().getUUID(c.getName()); + UUID uuid = plugin.getDatastore().getUUID(c.getName()).getOrDefault(null); if (uuid == null) { plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(c.getUniqueId(), c.getName())); } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index f75d2081..0fdfca83 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -268,4 +268,10 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { public void doSync(Runnable r) { r.run(); } + + @Override + public void doAsyncRepeating(Runnable r, long interval) { + long millis = interval * 50L; // convert from ticks to milliseconds + getProxy().getScheduler().schedule(this, r, millis, millis, TimeUnit.MILLISECONDS); + } } diff --git a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java index 4c378b9f..22a5bdc7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java @@ -38,6 +38,7 @@ import me.lucko.luckperms.common.groups.GroupManager; import me.lucko.luckperms.common.storage.Datastore; import me.lucko.luckperms.common.tracks.TrackManager; import me.lucko.luckperms.common.users.UserManager; +import me.lucko.luckperms.common.utils.BufferedRequest; import me.lucko.luckperms.common.utils.LocaleManager; import java.io.File; @@ -177,7 +178,7 @@ public interface LuckPermsPlugin { /** * Runs an update task */ - void runUpdateTask(); + BufferedRequest getUpdateTaskBuffer(); /** * Execute a runnable asynchronously @@ -191,4 +192,11 @@ public interface LuckPermsPlugin { */ void doSync(Runnable r); + /** + * Execute a runnable asynchronously on a loop + * @param r the task to run + * @param interval the time between runs in ticks + */ + void doAsyncRepeating(Runnable r, long interval); + } diff --git a/common/src/main/java/me/lucko/luckperms/common/api/internal/DatastoreLink.java b/common/src/main/java/me/lucko/luckperms/common/api/internal/DatastoreLink.java index f3730eb9..90324ebe 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/internal/DatastoreLink.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/internal/DatastoreLink.java @@ -22,19 +22,15 @@ package me.lucko.luckperms.common.api.internal; -import lombok.AccessLevel; import lombok.AllArgsConstructor; -import lombok.NoArgsConstructor; import lombok.NonNull; import me.lucko.luckperms.api.*; import me.lucko.luckperms.api.data.Callback; import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.storage.AbstractFuture; import java.util.Set; import java.util.UUID; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import static me.lucko.luckperms.common.api.internal.Utils.*; @@ -210,64 +206,68 @@ public class DatastoreLink implements Datastore { @Override public boolean logAction(@NonNull LogEntry entry) { - return master.logAction(entry); + return master.logAction(entry).getOrDefault(false); } @Override public Log getLog() { - return new LogLink(master.getLog()); + me.lucko.luckperms.common.data.Log log = master.getLog().getOrDefault(null); + if (log == null) { + return null; + } + return new LogLink(log); } @Override public boolean loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) { - return master.loadUser(uuid, checkUsername(username)); + return master.loadUser(uuid, checkUsername(username)).getOrDefault(false); } @Override public boolean loadUser(@NonNull UUID uuid) { - return master.loadUser(uuid, "null"); + return master.loadUser(uuid, "null").getOrDefault(false); } @Override public boolean loadUser(@NonNull UUID uuid, @NonNull String username) { - return master.loadUser(uuid, checkUsername(username)); + return master.loadUser(uuid, checkUsername(username)).getOrDefault(false); } @Override public boolean saveUser(@NonNull User user) { checkUser(user); - return master.saveUser(((UserLink) user).getMaster()); + return master.saveUser(((UserLink) user).getMaster()).getOrDefault(false); } @Override public boolean cleanupUsers() { - return master.cleanupUsers(); + return master.cleanupUsers().getOrDefault(false); } @Override public Set getUniqueUsers() { - return master.getUniqueUsers(); + return master.getUniqueUsers().getOrDefault(null); } @Override public boolean createAndLoadGroup(@NonNull String name) { - return master.createAndLoadGroup(checkName(name)); + return master.createAndLoadGroup(checkName(name)).getOrDefault(false); } @Override public boolean loadGroup(@NonNull String name) { - return master.loadGroup(checkName(name)); + return master.loadGroup(checkName(name)).getOrDefault(false); } @Override public boolean loadAllGroups() { - return master.loadAllGroups(); + return master.loadAllGroups().getOrDefault(false); } @Override public boolean saveGroup(@NonNull Group group) { checkGroup(group); - return master.saveGroup(((GroupLink) group).getMaster()); + return master.saveGroup(((GroupLink) group).getMaster()).getOrDefault(false); } @Override @@ -276,44 +276,44 @@ public class DatastoreLink implements Datastore { if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) { throw new IllegalArgumentException("Cannot delete the default group."); } - return master.deleteGroup(((GroupLink) group).getMaster()); + return master.deleteGroup(((GroupLink) group).getMaster()).getOrDefault(false); } @Override public boolean createAndLoadTrack(@NonNull String name) { - return master.createAndLoadTrack(checkName(name)); + return master.createAndLoadTrack(checkName(name)).getOrDefault(false); } @Override public boolean loadTrack(@NonNull String name) { - return master.loadTrack(checkName(name)); + return master.loadTrack(checkName(name)).getOrDefault(false); } @Override public boolean loadAllTracks() { - return master.loadAllTracks(); + return master.loadAllTracks().getOrDefault(false); } @Override public boolean saveTrack(@NonNull Track track) { checkTrack(track); - return master.saveTrack(((TrackLink) track).getMaster()); + return master.saveTrack(((TrackLink) track).getMaster()).getOrDefault(false); } @Override public boolean deleteTrack(@NonNull Track track) { checkTrack(track); - return master.deleteTrack(((TrackLink) track).getMaster()); + return master.deleteTrack(((TrackLink) track).getMaster()).getOrDefault(false); } @Override public boolean saveUUIDData(@NonNull String username, @NonNull UUID uuid) { - return master.saveUUIDData(checkUsername(username), uuid); + return master.saveUUIDData(checkUsername(username), uuid).getOrDefault(false); } @Override public UUID getUUID(@NonNull String username) { - return master.getUUID(checkUsername(username)); + return master.getUUID(checkUsername(username)).getOrDefault(null); } } @@ -323,193 +323,112 @@ public class DatastoreLink implements Datastore { @Override public java.util.concurrent.Future logAction(@NonNull LogEntry entry) { - LPFuture lpf = new LPFuture<>(); - master.logAction(entry, lpf); - return lpf; + return master.logAction(entry); } @Override public java.util.concurrent.Future getLog() { - LPFuture lpf = new LPFuture<>(); - master.getLog(log -> lpf.onComplete(new LogLink(log))); - return lpf; + AbstractFuture fut = new AbstractFuture<>(); + master.getLog(log -> fut.complete(new LogLink(log))); + return fut; } @Override public java.util.concurrent.Future loadOrCreateUser(@NonNull UUID uuid, @NonNull String username) { - LPFuture lpf = new LPFuture<>(); - master.loadUser(uuid, checkUsername(username), lpf); - return lpf; + return master.loadUser(uuid, checkUsername(username)); } @Override public java.util.concurrent.Future loadUser(@NonNull UUID uuid) { - LPFuture lpf = new LPFuture<>(); - master.loadUser(uuid, "null", lpf); - return lpf; + return master.loadUser(uuid, "null"); } @Override public java.util.concurrent.Future loadUser(@NonNull UUID uuid, @NonNull String username) { - LPFuture lpf = new LPFuture<>(); - master.loadUser(uuid, checkUsername(username), lpf); - return lpf; + return master.loadUser(uuid, checkUsername(username)); } @Override public java.util.concurrent.Future saveUser(@NonNull User user) { - LPFuture lpf = new LPFuture<>(); checkUser(user); - master.saveUser(((UserLink) user).getMaster(), lpf); - return lpf; + return master.saveUser(((UserLink) user).getMaster()); } @Override public java.util.concurrent.Future cleanupUsers() { - LPFuture lpf = new LPFuture<>(); - master.cleanupUsers(lpf); - return lpf; + return master.cleanupUsers(); } @Override public java.util.concurrent.Future> getUniqueUsers() { - LPFuture> lpf = new LPFuture<>(); - master.getUniqueUsers(lpf); - return lpf; + return master.getUniqueUsers(); } @Override public java.util.concurrent.Future createAndLoadGroup(@NonNull String name) { - LPFuture lpf = new LPFuture<>(); - master.createAndLoadGroup(checkName(name), lpf); - return lpf; + return master.createAndLoadGroup(checkName(name)); } @Override public java.util.concurrent.Future loadGroup(@NonNull String name) { - LPFuture lpf = new LPFuture<>(); - master.loadGroup(checkName(name), lpf); - return lpf; + return master.loadGroup(checkName(name)); } @Override public java.util.concurrent.Future loadAllGroups() { - LPFuture lpf = new LPFuture<>(); - master.loadAllGroups(lpf); - return lpf; + return master.loadAllGroups(); } @Override public java.util.concurrent.Future saveGroup(@NonNull Group group) { - LPFuture lpf = new LPFuture<>(); checkGroup(group); - master.saveGroup(((GroupLink) group).getMaster(), lpf); - return lpf; + return master.saveGroup(((GroupLink) group).getMaster()); } @Override public java.util.concurrent.Future deleteGroup(@NonNull Group group) { - LPFuture lpf = new LPFuture<>(); checkGroup(group); if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) { throw new IllegalArgumentException("Cannot delete the default group."); } - master.deleteGroup(((GroupLink) group).getMaster(), lpf); - return lpf; + return master.deleteGroup(((GroupLink) group).getMaster()); } @Override public java.util.concurrent.Future createAndLoadTrack(@NonNull String name) { - LPFuture lpf = new LPFuture<>(); - master.createAndLoadTrack(checkName(name), lpf); - return lpf; + return master.createAndLoadTrack(checkName(name)); } @Override public java.util.concurrent.Future loadTrack(@NonNull String name) { - LPFuture lpf = new LPFuture<>(); - master.loadTrack(checkName(name), lpf); - return lpf; + return master.loadTrack(checkName(name)); } @Override public java.util.concurrent.Future loadAllTracks() { - LPFuture lpf = new LPFuture<>(); - master.loadAllTracks(lpf); - return lpf; + return master.loadAllTracks(); } @Override public java.util.concurrent.Future saveTrack(@NonNull Track track) { - LPFuture lpf = new LPFuture<>(); checkTrack(track); - master.saveTrack(((TrackLink) track).getMaster(), lpf); - return lpf; + return master.saveTrack(((TrackLink) track).getMaster()); } @Override public java.util.concurrent.Future deleteTrack(@NonNull Track track) { - LPFuture lpf = new LPFuture<>(); checkTrack(track); - master.deleteTrack(((TrackLink) track).getMaster(), lpf); - return lpf; + return master.deleteTrack(((TrackLink) track).getMaster()); } @Override public java.util.concurrent.Future saveUUIDData(@NonNull String username, @NonNull UUID uuid) { - LPFuture lpf = new LPFuture<>(); - master.saveUUIDData(checkUsername(username), uuid, lpf); - return lpf; + return master.saveUUIDData(checkUsername(username), uuid); } @Override public java.util.concurrent.Future getUUID(@NonNull String username) { - LPFuture lpf = new LPFuture<>(); - master.getUUID(checkUsername(username), lpf); - return lpf; - } - } - - @NoArgsConstructor(access = AccessLevel.PRIVATE) - public static class LPFuture implements Callback, java.util.concurrent.Future { - private final CountDownLatch latch = new CountDownLatch(1); - private T value; - - @Override - public void onComplete(T t) { - value = t; - latch.countDown(); - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - // Not supported - return false; - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return latch.getCount() == 0; - } - - @Override - public T get() throws InterruptedException { - latch.await(); - return value; - } - - @Override - public T get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { - if (latch.await(timeout, unit)) { - return value; - } else { - throw new TimeoutException(); - } + return master.getUUID(checkUsername(username)); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/SubCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/SubCommand.java index accc671e..d2a12eff 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/SubCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/SubCommand.java @@ -162,7 +162,7 @@ public abstract class SubCommand { } public static void save(User user, Sender sender, LuckPermsPlugin plugin) { - if (plugin.getDatastore().saveUser(user)) { + if (plugin.getDatastore().saveUser(user).getOrDefault(false)) { Message.USER_SAVE_SUCCESS.send(sender); } else { Message.USER_SAVE_ERROR.send(sender); @@ -172,7 +172,7 @@ public abstract class SubCommand { } public static void save(Group group, Sender sender, LuckPermsPlugin plugin) { - if (plugin.getDatastore().saveGroup(group)) { + if (plugin.getDatastore().saveGroup(group).getOrDefault(false)) { Message.GROUP_SAVE_SUCCESS.send(sender); } else { Message.GROUP_SAVE_ERROR.send(sender); @@ -182,7 +182,7 @@ public abstract class SubCommand { } public static void save(Track track, Sender sender, LuckPermsPlugin plugin) { - if (plugin.getDatastore().saveTrack(track)) { + if (plugin.getDatastore().saveTrack(track).getOrDefault(false)) { Message.TRACK_SAVE_SUCCESS.send(sender); } else { Message.TRACK_SAVE_ERROR.send(sender); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAdd.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAdd.java index b0c86109..feda5054 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAdd.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAdd.java @@ -61,7 +61,7 @@ public class ParentAdd extends SecondarySubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadGroup(groupName)) { + if (!plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAddTemp.java b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAddTemp.java index f5c941ff..fcc3b14f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAddTemp.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/generic/parent/ParentAddTemp.java @@ -80,7 +80,7 @@ public class ParentAddTemp extends SecondarySubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadGroup(groupName)) { + if (!plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/CreateGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/CreateGroup.java index 45a70409..e1bdb33b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/CreateGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/CreateGroup.java @@ -51,12 +51,12 @@ public class CreateGroup extends SingleMainCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadGroup(groupName)) { + if (plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadGroup(groupName)) { + if (!plugin.getDatastore().createAndLoadGroup(groupName).getOrDefault(false)) { Message.CREATE_GROUP_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java index 1c559233..b049c245 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/DeleteGroup.java @@ -55,7 +55,7 @@ public class DeleteGroup extends SingleMainCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadGroup(groupName)) { + if (!plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } @@ -66,7 +66,7 @@ public class DeleteGroup extends SingleMainCommand { return CommandResult.LOADING_ERROR; } - if (!plugin.getDatastore().deleteGroup(group)) { + if (!plugin.getDatastore().deleteGroup(group).getOrDefault(false)) { Message.DELETE_GROUP_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupMainCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupMainCommand.java index f91984bd..d6a23566 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupMainCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/GroupMainCommand.java @@ -57,7 +57,7 @@ public class GroupMainCommand extends MainCommand { @Override protected Group getTarget(String target, LuckPermsPlugin plugin, Sender sender) { - if (!plugin.getDatastore().loadGroup(target)) { + if (!plugin.getDatastore().loadGroup(target).getOrDefault(false)) { Message.GROUP_NOT_FOUND.send(sender); return null; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/ListGroups.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/ListGroups.java index 98e3f52f..e4c61bda 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/ListGroups.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/ListGroups.java @@ -42,7 +42,7 @@ public class ListGroups extends SingleMainCommand { @Override protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) { - if (!plugin.getDatastore().loadAllGroups()) { + if (!plugin.getDatastore().loadAllGroups().getOrDefault(false)) { Message.GROUPS_LOAD_ERROR.send(sender); return CommandResult.LOADING_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupClone.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupClone.java index e696f92d..b5ce0ce3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupClone.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupClone.java @@ -47,12 +47,12 @@ public class GroupClone extends SubCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadGroup(newGroupName)) { + if (plugin.getDatastore().loadGroup(newGroupName).getOrDefault(false)) { Message.GROUP_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadGroup(newGroupName)) { + if (!plugin.getDatastore().createAndLoadGroup(newGroupName).getOrDefault(false)) { Message.CREATE_GROUP_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupRename.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupRename.java index aa105d2b..47c02c3f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupRename.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupRename.java @@ -47,12 +47,12 @@ public class GroupRename extends SubCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadGroup(newGroupName)) { + if (plugin.getDatastore().loadGroup(newGroupName).getOrDefault(false)) { Message.GROUP_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadGroup(newGroupName)) { + if (!plugin.getDatastore().createAndLoadGroup(newGroupName).getOrDefault(false)) { Message.CREATE_GROUP_ERROR.send(sender); return CommandResult.FAILURE; } @@ -63,7 +63,7 @@ public class GroupRename extends SubCommand { return CommandResult.LOADING_ERROR; } - if (!plugin.getDatastore().deleteGroup(group)) { + if (!plugin.getDatastore().deleteGroup(group).getOrDefault(false)) { Message.DELETE_GROUP_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupShowTracks.java b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupShowTracks.java index 94c3e1a9..c4280d65 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupShowTracks.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/group/subcommands/GroupShowTracks.java @@ -39,7 +39,7 @@ public class GroupShowTracks extends SubCommand { @Override public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List args, String label) { - if (!plugin.getDatastore().loadAllTracks()) { + if (!plugin.getDatastore().loadAllTracks().getOrDefault(false)) { Message.TRACKS_LOAD_ERROR.send(sender); return CommandResult.LOADING_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogMainCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogMainCommand.java index ed6141a2..ee999366 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/log/LogMainCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/LogMainCommand.java @@ -52,7 +52,7 @@ public class LogMainCommand extends MainCommand { @Override protected Log getTarget(String target, LuckPermsPlugin plugin, Sender sender) { - Log log = plugin.getDatastore().getLog(); + Log log = plugin.getDatastore().getLog().getOrDefault(null); if (log == null) { Message.LOG_LOAD_ERROR.send(sender); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogRecent.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogRecent.java index 953c3c08..a46584e9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogRecent.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogRecent.java @@ -74,7 +74,7 @@ public class LogRecent extends SubCommand { return CommandResult.INVALID_ARGS; } - UUID uuid = plugin.getDatastore().getUUID(s); + UUID uuid = plugin.getDatastore().getUUID(s).getOrDefault(null); if (uuid == null) { Message.USER_NOT_FOUND.send(sender); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogUserHistory.java b/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogUserHistory.java index 3fd72f69..8e2d2839 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogUserHistory.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/log/subcommands/LogUserHistory.java @@ -76,7 +76,7 @@ public class LogUserHistory extends SubCommand { return CommandResult.INVALID_ARGS; } - UUID uuid1 = plugin.getDatastore().getUUID(user); + UUID uuid1 = plugin.getDatastore().getUUID(user).getOrDefault(null); if (uuid1 == null) { Message.USER_NOT_FOUND.send(sender); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java index f499beac..b817ba98 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/misc/ExportCommand.java @@ -118,7 +118,7 @@ public class ExportCommand extends SingleMainCommand { // Export users log.info("Export: Exporting all users. Finding a list of unique users to export."); Datastore ds = plugin.getDatastore(); - Set users = ds.getUniqueUsers(); + Set users = ds.getUniqueUsers().getOrDefault(null); log.info("Export: Found " + users.size() + " unique users to export."); int userCount = 0; diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/CreateTrack.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/CreateTrack.java index 8adbd628..b837c64f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/CreateTrack.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/CreateTrack.java @@ -51,12 +51,12 @@ public class CreateTrack extends SingleMainCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadTrack(trackName)) { + if (plugin.getDatastore().loadTrack(trackName).getOrDefault(false)) { Message.TRACK_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadTrack(trackName)) { + if (!plugin.getDatastore().createAndLoadTrack(trackName).getOrDefault(false)) { Message.CREATE_TRACK_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/DeleteTrack.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/DeleteTrack.java index 78307c54..9d0e58c2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/DeleteTrack.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/DeleteTrack.java @@ -49,7 +49,7 @@ public class DeleteTrack extends SingleMainCommand { } String trackName = args.get(0).toLowerCase(); - if (!plugin.getDatastore().loadTrack(trackName)) { + if (!plugin.getDatastore().loadTrack(trackName).getOrDefault(false)) { Message.TRACK_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } @@ -60,7 +60,7 @@ public class DeleteTrack extends SingleMainCommand { return CommandResult.LOADING_ERROR; } - if (!plugin.getDatastore().deleteTrack(track)) { + if (!plugin.getDatastore().deleteTrack(track).getOrDefault(false)) { Message.DELETE_TRACK_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/ListTracks.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/ListTracks.java index 657e9803..87c1a9b7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/ListTracks.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/ListTracks.java @@ -40,7 +40,7 @@ public class ListTracks extends SingleMainCommand { @Override protected CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) { - if (!plugin.getDatastore().loadAllTracks()) { + if (!plugin.getDatastore().loadAllTracks().getOrDefault(false)) { Message.TRACKS_LOAD_ERROR.send(sender); return CommandResult.LOADING_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackMainCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackMainCommand.java index 567aa363..13de57e2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackMainCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/TrackMainCommand.java @@ -50,7 +50,7 @@ public class TrackMainCommand extends MainCommand { @Override protected Track getTarget(String target, LuckPermsPlugin plugin, Sender sender) { - if (!plugin.getDatastore().loadTrack(target)) { + if (!plugin.getDatastore().loadTrack(target).getOrDefault(false)) { Message.TRACK_NOT_FOUND.send(sender); return null; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackAppend.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackAppend.java index 31b189f5..3e19226d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackAppend.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackAppend.java @@ -50,7 +50,7 @@ public class TrackAppend extends SubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadGroup(groupName)) { + if (!plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackClone.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackClone.java index 85b20732..3180be71 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackClone.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackClone.java @@ -47,12 +47,12 @@ public class TrackClone extends SubCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadTrack(newTrackName)) { + if (plugin.getDatastore().loadTrack(newTrackName).getOrDefault(false)) { Message.TRACK_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadTrack(newTrackName)) { + if (!plugin.getDatastore().createAndLoadTrack(newTrackName).getOrDefault(false)) { Message.CREATE_TRACK_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackInsert.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackInsert.java index 255ee767..d3863ec7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackInsert.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackInsert.java @@ -61,7 +61,7 @@ public class TrackInsert extends SubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadGroup(groupName)) { + if (!plugin.getDatastore().loadGroup(groupName).getOrDefault(false)) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackRename.java b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackRename.java index 134c1291..c6e971c8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackRename.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/track/subcommands/TrackRename.java @@ -47,12 +47,12 @@ public class TrackRename extends SubCommand { return CommandResult.INVALID_ARGS; } - if (plugin.getDatastore().loadTrack(newTrackName)) { + if (plugin.getDatastore().loadTrack(newTrackName).getOrDefault(false)) { Message.TRACK_ALREADY_EXISTS.send(sender); return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().createAndLoadTrack(newTrackName)) { + if (!plugin.getDatastore().createAndLoadTrack(newTrackName).getOrDefault(false)) { Message.CREATE_TRACK_ERROR.send(sender); return CommandResult.FAILURE; } @@ -63,7 +63,7 @@ public class TrackRename extends SubCommand { return CommandResult.LOADING_ERROR; } - if (!plugin.getDatastore().deleteTrack(track)) { + if (!plugin.getDatastore().deleteTrack(track).getOrDefault(false)) { Message.DELETE_TRACK_ERROR.send(sender); return CommandResult.FAILURE; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/user/UserMainCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/user/UserMainCommand.java index c8026624..bd235f86 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/user/UserMainCommand.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/user/UserMainCommand.java @@ -70,7 +70,7 @@ public class UserMainCommand extends MainCommand { return null; } - u = plugin.getDatastore().getUUID(target); + u = plugin.getDatastore().getUUID(target).getOrDefault(null); if (u == null) { Message.USER_NOT_FOUND.send(sender); return null; @@ -80,10 +80,10 @@ public class UserMainCommand extends MainCommand { } } - String name = plugin.getDatastore().getName(u); + String name = plugin.getDatastore().getName(u).getOrDefault(null); if (name == null) name = "null"; - if (!plugin.getDatastore().loadUser(u, name)) { + if (!plugin.getDatastore().loadUser(u, name).getOrDefault(false)) { Message.LOADING_ERROR.send(sender); } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserDemote.java b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserDemote.java index a79df4d3..68f2aa6c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserDemote.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserDemote.java @@ -54,7 +54,7 @@ public class UserDemote extends SubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadTrack(trackName)) { + if (!plugin.getDatastore().loadTrack(trackName).getOrDefault(false)) { Message.TRACK_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } @@ -85,7 +85,7 @@ public class UserDemote extends SubCommand { return CommandResult.STATE_ERROR; } - if (!plugin.getDatastore().loadGroup(previous)) { + if (!plugin.getDatastore().loadGroup(previous).getOrDefault(false)) { Message.USER_DEMOTE_ERROR_MALFORMED.send(sender, previous); return CommandResult.STATE_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserPromote.java b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserPromote.java index 19f7162b..2cbfdc2a 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserPromote.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserPromote.java @@ -54,7 +54,7 @@ public class UserPromote extends SubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadTrack(trackName)) { + if (!plugin.getDatastore().loadTrack(trackName).getOrDefault(false)) { Message.TRACK_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } @@ -85,7 +85,7 @@ public class UserPromote extends SubCommand { return CommandResult.STATE_ERROR; } - if (!plugin.getDatastore().loadGroup(next)) { + if (!plugin.getDatastore().loadGroup(next).getOrDefault(false)) { Message.USER_PROMOTE_ERROR_MALFORMED.send(sender, next); return CommandResult.STATE_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowPos.java b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowPos.java index 9de7c10b..9de478d3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowPos.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowPos.java @@ -47,7 +47,7 @@ public class UserShowPos extends SubCommand { return CommandResult.INVALID_ARGS; } - if (!plugin.getDatastore().loadTrack(trackName)) { + if (!plugin.getDatastore().loadTrack(trackName).getOrDefault(false)) { Message.TRACK_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowTracks.java b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowTracks.java index c46f349a..9b0f1caa 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowTracks.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/user/subcommands/UserShowTracks.java @@ -40,7 +40,7 @@ public class UserShowTracks extends SubCommand { @Override public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List args, String label) { - if (!plugin.getDatastore().loadAllTracks()) { + if (!plugin.getDatastore().loadAllTracks().getOrDefault(false)) { Message.TRACKS_LOAD_ERROR.send(sender); return CommandResult.LOADING_ERROR; } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditGroup.java index 87630f49..a07309f3 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditGroup.java @@ -61,7 +61,7 @@ public class BulkEditGroup extends SubCommand { return CommandResult.FAILURE; } - Set uuids = datastore.getUniqueUsers(); + Set uuids = datastore.getUniqueUsers().getOrDefault(null); for (UUID u : uuids) { plugin.getDatastore().loadUser(u, "null"); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditPermission.java b/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditPermission.java index ba700c72..6a78dc02 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditPermission.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/usersbulkedit/subcommands/BulkEditPermission.java @@ -61,7 +61,7 @@ public class BulkEditPermission extends SubCommand { return CommandResult.FAILURE; } - Set uuids = datastore.getUniqueUsers(); + Set uuids = datastore.getUniqueUsers().getOrDefault(null); for (UUID u : uuids) { plugin.getDatastore().loadUser(u, "null"); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractDatastore.java new file mode 100644 index 00000000..bd1a2a21 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractDatastore.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.storage; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.groups.Group; +import me.lucko.luckperms.common.storage.backing.AbstractBacking; +import me.lucko.luckperms.common.tracks.Track; +import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.common.utils.LPFuture; + +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Future; +import java.util.function.Supplier; + +/** + * Converts a {@link AbstractBacking} to use {@link Future}s + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class AbstractDatastore implements Datastore { + public static Datastore wrap(AbstractBacking backing) { + return TolerantDatastore.wrap(new AbstractDatastore(backing)); + } + + private final AbstractBacking backing; + + private LPFuture makeFuture(Supplier supplier) { + AbstractFuture future = new AbstractFuture<>(); + backing.doAsync(() -> { + T result = supplier.get(); + future.complete(result); + }); + return future; + } + + @Override + public String getName() { + return backing.getName(); + } + + @Override + public boolean isAcceptingLogins() { + return backing.isAcceptingLogins(); + } + + @Override + public void setAcceptingLogins(boolean acceptingLogins) { + backing.setAcceptingLogins(acceptingLogins); + } + + @Override + public void doAsync(Runnable r) { + backing.doAsync(r); + } + + @Override + public void doSync(Runnable r) { + backing.doSync(r); + } + + @Override + public LPFuture init() { + return makeFuture(() -> { + backing.init(); + return null; + }); + } + + @Override + public LPFuture shutdown() { + return makeFuture(() -> { + backing.shutdown(); + return null; + }); + } + + @Override + public LPFuture logAction(LogEntry entry) { + return makeFuture(() -> backing.logAction(entry)); + } + + @Override + public LPFuture getLog() { + return makeFuture(backing::getLog); + } + + @Override + public LPFuture loadUser(UUID uuid, String username) { + return makeFuture(() -> backing.loadUser(uuid, username)); + } + + @Override + public LPFuture saveUser(User user) { + return makeFuture(() -> backing.saveUser(user)); + } + + @Override + public LPFuture cleanupUsers() { + return makeFuture(backing::cleanupUsers); + } + + @Override + public LPFuture> getUniqueUsers() { + return makeFuture(backing::getUniqueUsers); + } + + @Override + public LPFuture createAndLoadGroup(String name) { + return makeFuture(() -> backing.createAndLoadGroup(name)); + } + + @Override + public LPFuture loadGroup(String name) { + return makeFuture(() -> backing.loadGroup(name)); + } + + @Override + public LPFuture loadAllGroups() { + return makeFuture(backing::loadAllGroups); + } + + @Override + public LPFuture saveGroup(Group group) { + return makeFuture(() -> backing.saveGroup(group)); + } + + @Override + public LPFuture deleteGroup(Group group) { + return makeFuture(() -> backing.deleteGroup(group)); + } + + @Override + public LPFuture createAndLoadTrack(String name) { + return makeFuture(() -> backing.createAndLoadTrack(name)); + } + + @Override + public LPFuture loadTrack(String name) { + return makeFuture(() -> backing.loadTrack(name)); + } + + @Override + public LPFuture loadAllTracks() { + return makeFuture(backing::loadAllTracks); + } + + @Override + public LPFuture saveTrack(Track track) { + return makeFuture(() -> backing.saveTrack(track)); + } + + @Override + public LPFuture deleteTrack(Track track) { + return makeFuture(() -> backing.deleteTrack(track)); + } + + @Override + public LPFuture saveUUIDData(String username, UUID uuid) { + return makeFuture(() -> backing.saveUUIDData(username, uuid)); + } + + @Override + public LPFuture getUUID(String username) { + return makeFuture(() -> backing.getUUID(username)); + } + + @Override + public LPFuture getName(UUID uuid) { + return makeFuture(() -> backing.getName(uuid)); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractFuture.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractFuture.java new file mode 100644 index 00000000..e0b96328 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractFuture.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.storage; + +import me.lucko.luckperms.common.utils.LPFuture; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class AbstractFuture implements LPFuture { + private final CountDownLatch latch = new CountDownLatch(1); + private R value; + + public void complete(R r) { + value = r; + latch.countDown(); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + // Not supported + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return latch.getCount() == 0; + } + + @Override + public R get() throws InterruptedException { + latch.await(); + return value; + } + + @Override + public R get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { + if (latch.await(timeout, unit)) { + return value; + } else { + throw new TimeoutException(); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/BufferedOutputDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/BufferedOutputDatastore.java new file mode 100644 index 00000000..8771c315 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/BufferedOutputDatastore.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.storage; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.groups.Group; +import me.lucko.luckperms.common.tracks.Track; +import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.common.users.UserIdentifier; +import me.lucko.luckperms.common.utils.Buffer; +import me.lucko.luckperms.common.utils.LPFuture; + +import java.util.Set; +import java.util.UUID; + +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class BufferedOutputDatastore implements Datastore, Runnable { + public static BufferedOutputDatastore wrap(Datastore datastore, long flushTime) { + return new BufferedOutputDatastore(datastore, flushTime); + } + + @Getter + private final Datastore backing; + + private final long flushTime; + + private final Buffer logOutputBuffer = new Buffer() { + @Override + public Boolean dequeue(LogEntry logEntry) { + return backing.logAction(logEntry).getOrDefault(false); + } + }; + + private final Buffer userOutputBuffer = new Buffer() { + @Override + public Boolean dequeue(User user) { + return saveUser(user).getOrDefault(false); + } + }; + + private final Buffer groupOutputBuffer = new Buffer() { + @Override + public Boolean dequeue(Group group) { + return saveGroup(group).getOrDefault(false); + } + }; + + private final Buffer trackOutputBuffer = new Buffer() { + @Override + public Boolean dequeue(Track track) { + return saveTrack(track).getOrDefault(false); + } + }; + + private final Buffer uuidDataOutputBuffer = new Buffer() { + @Override + protected Boolean dequeue(UserIdentifier userIdentifier) { + return saveUUIDData(userIdentifier.getUsername(), userIdentifier.getUuid()).getOrDefault(false); + } + }; + + @Override + public void run() { + flush(flushTime); + } + + public void forceFlush() { + flush(-1); + } + + public void flush(long flushTime) { + logOutputBuffer.flush(flushTime); + userOutputBuffer.flush(flushTime); + groupOutputBuffer.flush(flushTime); + trackOutputBuffer.flush(flushTime); + userOutputBuffer.flush(flushTime); + } + + public Datastore force() { + return backing; + } + + @Override + public LPFuture init() { + return backing.init(); + } + + @Override + public LPFuture shutdown() { + forceFlush(); + return backing.shutdown(); + } + + @Override + public LPFuture logAction(LogEntry entry) { + return logOutputBuffer.enqueue(entry); + } + + @Override + public LPFuture getLog() { + return backing.getLog(); + } + + @Override + public LPFuture loadUser(UUID uuid, String username) { + return backing.loadUser(uuid, username); + } + + @Override + public LPFuture saveUser(User user) { + return userOutputBuffer.enqueue(user); + } + + @Override + public LPFuture cleanupUsers() { + return backing.cleanupUsers(); + } + + @Override + public LPFuture> getUniqueUsers() { + return backing.getUniqueUsers(); + } + + @Override + public LPFuture createAndLoadGroup(String name) { + return backing.createAndLoadGroup(name); + } + + @Override + public LPFuture loadGroup(String name) { + return backing.loadGroup(name); + } + + @Override + public LPFuture loadAllGroups() { + return backing.loadAllGroups(); + } + + @Override + public LPFuture saveGroup(Group group) { + return groupOutputBuffer.enqueue(group); + } + + @Override + public LPFuture deleteGroup(Group group) { + return backing.deleteGroup(group); + } + + @Override + public LPFuture createAndLoadTrack(String name) { + return backing.createAndLoadTrack(name); + } + + @Override + public LPFuture loadTrack(String name) { + return backing.loadTrack(name); + } + + @Override + public LPFuture loadAllTracks() { + return backing.loadAllTracks(); + } + + @Override + public LPFuture saveTrack(Track track) { + return trackOutputBuffer.enqueue(track); + } + + @Override + public LPFuture deleteTrack(Track track) { + return backing.deleteTrack(track); + } + + @Override + public LPFuture saveUUIDData(String username, UUID uuid) { + return uuidDataOutputBuffer.enqueue(UserIdentifier.of(uuid, username)); + } + + @Override + public LPFuture getUUID(String username) { + return backing.getUUID(username); + } + + @Override + public LPFuture getName(UUID uuid) { + return backing.getName(uuid); + } + + @Override + public String getName() { + return backing.getName(); + } + + @Override + public boolean isAcceptingLogins() { + return backing.isAcceptingLogins(); + } + + @Override + public void setAcceptingLogins(boolean acceptingLogins) { + backing.setAcceptingLogins(acceptingLogins); + } + + @Override + public void doAsync(Runnable r) { + backing.doAsync(r); + } + + @Override + public void doSync(Runnable r) { + backing.doSync(r); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Datastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/Datastore.java index 9d55a18c..6e209e93 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/Datastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/Datastore.java @@ -22,208 +22,191 @@ package me.lucko.luckperms.common.storage; -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Setter; import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.api.data.Callback; -import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.tracks.Track; import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.common.utils.LPFuture; import java.util.Set; import java.util.UUID; -@RequiredArgsConstructor(access = AccessLevel.PROTECTED) -public abstract class Datastore { - protected final LuckPermsPlugin plugin; - - @Getter - public final String name; - - @Getter - @Setter - private boolean acceptingLogins = false; +public interface Datastore { + + String getName(); + + boolean isAcceptingLogins(); + void setAcceptingLogins(boolean acceptingLogins); /** * Execute a runnable asynchronously * @param r the task to run */ - private void doAsync(Runnable r) { - plugin.doAsync(r); - } + void doAsync(Runnable r); /** * Execute a runnable synchronously * @param r the task to run */ - private void doSync(Runnable r) { - plugin.doSync(r); + void doSync(Runnable r); + + default Datastore force() { + return this; } - /* - These methods are called immediately and in the same thread as they are called in. - */ - public abstract void init(); - public abstract void shutdown(); - public abstract boolean logAction(LogEntry entry); - public abstract Log getLog(); - public abstract boolean loadUser(UUID uuid, String username); - public abstract boolean saveUser(User user); - public abstract boolean cleanupUsers(); - public abstract Set getUniqueUsers(); - public abstract boolean createAndLoadGroup(String name); - public abstract boolean loadGroup(String name); - public abstract boolean loadAllGroups(); - public abstract boolean saveGroup(Group group); - public abstract boolean deleteGroup(Group group); - public abstract boolean createAndLoadTrack(String name); - public abstract boolean loadTrack(String name); - public abstract boolean loadAllTracks(); - public abstract boolean saveTrack(Track track); - public abstract boolean deleteTrack(Track track); - public abstract boolean saveUUIDData(String username, UUID uuid); - public abstract UUID getUUID(String username); - public abstract String getName(UUID uuid); + LPFuture init(); + LPFuture shutdown(); + LPFuture logAction(LogEntry entry); + LPFuture getLog(); + LPFuture loadUser(UUID uuid, String username); + LPFuture saveUser(User user); + LPFuture cleanupUsers(); + LPFuture> getUniqueUsers(); + LPFuture createAndLoadGroup(String name); + LPFuture loadGroup(String name); + LPFuture loadAllGroups(); + LPFuture saveGroup(Group group); + LPFuture deleteGroup(Group group); + LPFuture createAndLoadTrack(String name); + LPFuture loadTrack(String name); + LPFuture loadAllTracks(); + LPFuture saveTrack(Track track); + LPFuture deleteTrack(Track track); + LPFuture saveUUIDData(String username, UUID uuid); + LPFuture getUUID(String username); + LPFuture getName(UUID uuid); - - - /* - These methods will schedule the operation to run async. The callback will be ran when the task is complete. - Callbacks are ran on the main server thread (except on BungeeCord) - */ - public void logAction(LogEntry entry, Callback callback) { + default void logAction(LogEntry entry, Callback callback) { doAsync(() -> { - boolean result = logAction(entry); + boolean result = logAction(entry).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void getLog(Callback callback) { + default void getLog(Callback callback) { doAsync(() -> { - Log result = getLog(); + Log result = getLog().getOrDefault(null); doSync(() -> callback.onComplete(result)); }); } - public void loadUser(UUID uuid, String username, Callback callback) { + default void loadUser(UUID uuid, String username, Callback callback) { doAsync(() -> { - boolean result = loadUser(uuid, username); + boolean result = loadUser(uuid, username).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void saveUser(User user, Callback callback) { + default void saveUser(User user, Callback callback) { doAsync(() -> { - boolean result = saveUser(user); + boolean result = saveUser(user).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void cleanupUsers(Callback callback) { + default void cleanupUsers(Callback callback) { doAsync(() -> { - boolean result = cleanupUsers(); + boolean result = cleanupUsers().getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void getUniqueUsers(Callback> callback) { + default void getUniqueUsers(Callback> callback) { doAsync(() -> { - Set result = getUniqueUsers(); + Set result = getUniqueUsers().getOrDefault(null); doSync(() -> callback.onComplete(result)); }); } - public void createAndLoadGroup(String name, Callback callback) { + default void createAndLoadGroup(String name, Callback callback) { doAsync(() -> { - boolean result = createAndLoadGroup(name); + boolean result = createAndLoadGroup(name).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void loadGroup(String name, Callback callback) { + default void loadGroup(String name, Callback callback) { doAsync(() -> { - boolean result = loadGroup(name); + boolean result = loadGroup(name).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void loadAllGroups(Callback callback) { + default void loadAllGroups(Callback callback) { doAsync(() -> { - boolean result = loadAllGroups(); + boolean result = loadAllGroups().getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void saveGroup(Group group, Callback callback) { + default void saveGroup(Group group, Callback callback) { doAsync(() -> { - boolean result = saveGroup(group); + boolean result = saveGroup(group).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void deleteGroup(Group group, Callback callback) { + default void deleteGroup(Group group, Callback callback) { doAsync(() -> { - boolean result = deleteGroup(group); + boolean result = deleteGroup(group).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void createAndLoadTrack(String name, Callback callback) { + default void createAndLoadTrack(String name, Callback callback) { doAsync(() -> { - boolean result = createAndLoadTrack(name); + boolean result = createAndLoadTrack(name).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void loadTrack(String name, Callback callback) { + default void loadTrack(String name, Callback callback) { doAsync(() -> { - boolean result = loadTrack(name); + boolean result = loadTrack(name).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void loadAllTracks(Callback callback) { + default void loadAllTracks(Callback callback) { doAsync(() -> { - boolean result = loadAllTracks(); + boolean result = loadAllTracks().getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void saveTrack(Track track, Callback callback) { + default void saveTrack(Track track, Callback callback) { doAsync(() -> { - boolean result = saveTrack(track); + boolean result = saveTrack(track).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void deleteTrack(Track track, Callback callback) { + default void deleteTrack(Track track, Callback callback) { doAsync(() -> { - boolean result = deleteTrack(track); + boolean result = deleteTrack(track).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void saveUUIDData(String username, UUID uuid, Callback callback) { + default void saveUUIDData(String username, UUID uuid, Callback callback) { doAsync(() -> { - boolean result = saveUUIDData(username, uuid); + boolean result = saveUUIDData(username, uuid).getOrDefault(false); doSync(() -> callback.onComplete(result)); }); } - public void getUUID(String username, Callback callback) { + default void getUUID(String username, Callback callback) { doAsync(() -> { - UUID result = getUUID(username); + UUID result = getUUID(username).getOrDefault(null); doSync(() -> callback.onComplete(result)); }); } - public void getName(UUID uuid, Callback callback) { + default void getName(UUID uuid, Callback callback) { doAsync(() -> { - String result = getName(uuid); + String result = getName(uuid).getOrDefault(null); doSync(() -> callback.onComplete(result)); }); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/SplitDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java similarity index 59% rename from common/src/main/java/me/lucko/luckperms/common/storage/SplitDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java index e15d7d30..a8c6eaea 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/SplitDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/SplitBacking.java @@ -23,136 +23,172 @@ package me.lucko.luckperms.common.storage; import com.google.common.collect.ImmutableMap; +import lombok.Getter; +import lombok.Setter; import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.tracks.Track; import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.common.utils.LPFuture; import java.util.Map; import java.util.Set; import java.util.UUID; -public class SplitDatastore extends Datastore { +public class SplitBacking implements Datastore { + + @Getter + @Setter + private boolean acceptingLogins = false; + + private final LuckPermsPlugin plugin; private final Map backing; private final Map types; - protected SplitDatastore(LuckPermsPlugin plugin, Map backing, Map types) { - super(plugin, "Split Storage"); + protected SplitBacking(LuckPermsPlugin plugin, Map backing, Map types) { + this.plugin = plugin; this.backing = ImmutableMap.copyOf(backing); this.types = ImmutableMap.copyOf(types); } @Override - public void init() { - backing.values().forEach(Datastore::init); - for (Datastore ds : backing.values()) { - if (!ds.isAcceptingLogins()) { - return; + public String getName() { + return "Split Storage"; + } + + @Override + public void doAsync(Runnable r) { + plugin.doAsync(r); + } + + @Override + public void doSync(Runnable r) { + plugin.doSync(r); + } + + @Override + public LPFuture init() { + AbstractFuture future = new AbstractFuture<>(); + doAsync(() -> { + boolean success = true; + backing.values().forEach(Datastore::init); + for (Datastore ds : backing.values()) { + if (!ds.isAcceptingLogins()) { + success = false; + } } - } - setAcceptingLogins(true); + setAcceptingLogins(success); + future.complete(null); + }); + return future; + } @Override - public void shutdown() { - backing.values().forEach(Datastore::shutdown); + public LPFuture shutdown() { + AbstractFuture future = new AbstractFuture<>(); + doAsync(() -> { + backing.values().forEach(Datastore::shutdown); + future.complete(null); + }); + return future; } @Override - public boolean logAction(LogEntry entry) { + public LPFuture logAction(LogEntry entry) { return backing.get(types.get("log")).logAction(entry); } @Override - public Log getLog() { + public LPFuture getLog() { return backing.get(types.get("log")).getLog(); } @Override - public boolean loadUser(UUID uuid, String username) { + public LPFuture loadUser(UUID uuid, String username) { return backing.get(types.get("user")).loadUser(uuid, username); } @Override - public boolean saveUser(User user) { + public LPFuture saveUser(User user) { return backing.get(types.get("user")).saveUser(user); } @Override - public boolean cleanupUsers() { + public LPFuture cleanupUsers() { return backing.get(types.get("user")).cleanupUsers(); } @Override - public Set getUniqueUsers() { + public LPFuture> getUniqueUsers() { return backing.get(types.get("user")).getUniqueUsers(); } @Override - public boolean createAndLoadGroup(String name) { + public LPFuture createAndLoadGroup(String name) { return backing.get(types.get("group")).createAndLoadGroup(name); } @Override - public boolean loadGroup(String name) { + public LPFuture loadGroup(String name) { return backing.get(types.get("group")).loadGroup(name); } @Override - public boolean loadAllGroups() { + public LPFuture loadAllGroups() { return backing.get(types.get("group")).loadAllGroups(); } @Override - public boolean saveGroup(Group group) { + public LPFuture saveGroup(Group group) { return backing.get(types.get("group")).saveGroup(group); } @Override - public boolean deleteGroup(Group group) { + public LPFuture deleteGroup(Group group) { return backing.get(types.get("group")).deleteGroup(group); } @Override - public boolean createAndLoadTrack(String name) { + public LPFuture createAndLoadTrack(String name) { return backing.get(types.get("track")).createAndLoadTrack(name); } @Override - public boolean loadTrack(String name) { + public LPFuture loadTrack(String name) { return backing.get(types.get("track")).loadTrack(name); } @Override - public boolean loadAllTracks() { + public LPFuture loadAllTracks() { return backing.get(types.get("track")).loadAllTracks(); } @Override - public boolean saveTrack(Track track) { + public LPFuture saveTrack(Track track) { return backing.get(types.get("track")).saveTrack(track); } @Override - public boolean deleteTrack(Track track) { + public LPFuture deleteTrack(Track track) { return backing.get(types.get("track")).deleteTrack(track); } @Override - public boolean saveUUIDData(String username, UUID uuid) { + public LPFuture saveUUIDData(String username, UUID uuid) { return backing.get(types.get("uuid")).saveUUIDData(username, uuid); } @Override - public UUID getUUID(String username) { + public LPFuture getUUID(String username) { return backing.get(types.get("uuid")).getUUID(username); } @Override - public String getName(UUID uuid) { + public LPFuture getName(UUID uuid) { return backing.get(types.get("uuid")).getName(uuid); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java b/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java index e1553cf6..b97539ff 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/StorageFactory.java @@ -25,7 +25,7 @@ package me.lucko.luckperms.common.storage; import com.google.common.collect.ImmutableSet; import lombok.experimental.UtilityClass; import me.lucko.luckperms.common.LuckPermsPlugin; -import me.lucko.luckperms.common.storage.methods.*; +import me.lucko.luckperms.common.storage.backing.*; import java.io.File; import java.util.HashMap; @@ -63,7 +63,7 @@ public class StorageFactory { backing.put(type, fromString(type, plugin)); } - datastore = new SplitDatastore(plugin, backing, types); + datastore = new SplitBacking(plugin, backing, types); } else { String storageMethod = plugin.getConfiguration().getStorageMethod().toLowerCase(); @@ -77,24 +77,26 @@ public class StorageFactory { } plugin.getLog().info("Initialising datastore..."); - datastore.init(); + datastore.init().getOrDefault(null); return datastore; } private static Datastore fromString(String storageMethod, LuckPermsPlugin plugin) { switch (storageMethod) { case "mysql": - return new MySQLDatastore(plugin, plugin.getConfiguration().getDatabaseValues()); + BufferedOutputDatastore bod = BufferedOutputDatastore.wrap(AbstractDatastore.wrap(new MySQLBacking(plugin, plugin.getConfiguration().getDatabaseValues())), 5000L); + plugin.doAsyncRepeating(bod, 20L); + return bod; case "sqlite": - return new SQLiteDatastore(plugin, new File(plugin.getDataFolder(), "luckperms.sqlite")); + return AbstractDatastore.wrap(new SQLiteBacking(plugin, new File(plugin.getDataFolder(), "luckperms.sqlite"))); case "h2": - return new H2Datastore(plugin, new File(plugin.getDataFolder(), "luckperms.db")); + return AbstractDatastore.wrap(new H2Backing(plugin, new File(plugin.getDataFolder(), "luckperms.db"))); case "mongodb": - return new MongoDBDatastore(plugin, plugin.getConfiguration().getDatabaseValues()); + return AbstractDatastore.wrap(new MongoDBBacking(plugin, plugin.getConfiguration().getDatabaseValues())); case "yaml": - return new YAMLDatastore(plugin, plugin.getDataFolder()); + return AbstractDatastore.wrap(new YAMLBacking(plugin, plugin.getDataFolder())); default: - return new JSONDatastore(plugin, plugin.getDataFolder()); + return AbstractDatastore.wrap(new JSONBacking(plugin, plugin.getDataFolder())); } } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/TolerantDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/TolerantDatastore.java new file mode 100644 index 00000000..48041e0b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/TolerantDatastore.java @@ -0,0 +1,282 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.storage; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.groups.Group; +import me.lucko.luckperms.common.tracks.Track; +import me.lucko.luckperms.common.users.User; +import me.lucko.luckperms.common.utils.LPFuture; + +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Phaser; + +/** + * A Datastore wrapping that ensures all tasks are completed before {@link Datastore#shutdown()} is called. + */ +@RequiredArgsConstructor(access = AccessLevel.PRIVATE) +public class TolerantDatastore implements Datastore { + public static TolerantDatastore wrap(Datastore datastore) { + return new TolerantDatastore(datastore); + } + + private final Datastore backing; + private final Phaser phaser = new Phaser(); + + @Override + public String getName() { + return backing.getName(); + } + + @Override + public boolean isAcceptingLogins() { + return backing.isAcceptingLogins(); + } + + @Override + public void setAcceptingLogins(boolean acceptingLogins) { + backing.setAcceptingLogins(acceptingLogins); + } + + @Override + public void doAsync(Runnable r) { + backing.doAsync(r); + } + + @Override + public void doSync(Runnable r) { + backing.doSync(r); + } + + @Override + public LPFuture init() { + phaser.register(); + try { + return backing.init(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture shutdown() { + phaser.register(); // Register self + phaser.arriveAndAwaitAdvance(); // Wait for other threads to finish. + + return backing.shutdown(); + } + + @Override + public LPFuture logAction(LogEntry entry) { + phaser.register(); + try { + return backing.logAction(entry); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture getLog() { + phaser.register(); + try { + return backing.getLog(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture loadUser(UUID uuid, String username) { + phaser.register(); + try { + return backing.loadUser(uuid, username); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture saveUser(User user) { + phaser.register(); + try { + return backing.saveUser(user); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture cleanupUsers() { + phaser.register(); + try { + return backing.cleanupUsers(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture> getUniqueUsers() { + phaser.register(); + try { + return backing.getUniqueUsers(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture createAndLoadGroup(String name) { + phaser.register(); + try { + return backing.createAndLoadGroup(name); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture loadGroup(String name) { + phaser.register(); + try { + return backing.loadGroup(name); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture loadAllGroups() { + phaser.register(); + try { + return backing.loadAllGroups(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture saveGroup(Group group) { + phaser.register(); + try { + return backing.saveGroup(group); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture deleteGroup(Group group) { + phaser.register(); + try { + return backing.deleteGroup(group); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture createAndLoadTrack(String name) { + phaser.register(); + try { + return backing.createAndLoadTrack(name); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture loadTrack(String name) { + phaser.register(); + try { + return backing.loadTrack(name); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture loadAllTracks() { + phaser.register(); + try { + return backing.loadAllTracks(); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture saveTrack(Track track) { + phaser.register(); + try { + return backing.saveTrack(track); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture deleteTrack(Track track) { + phaser.register(); + try { + return backing.deleteTrack(track); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture saveUUIDData(String username, UUID uuid) { + phaser.register(); + try { + return backing.saveUUIDData(username, uuid); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture getUUID(String username) { + phaser.register(); + try { + return backing.getUUID(username); + } finally { + phaser.arriveAndDeregister(); + } + } + + @Override + public LPFuture getName(UUID uuid) { + phaser.register(); + try { + return backing.getName(uuid); + } finally { + phaser.arriveAndDeregister(); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java new file mode 100644 index 00000000..3768486a --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/AbstractBacking.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.storage.backing; + +import lombok.AccessLevel; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.data.Log; +import me.lucko.luckperms.common.groups.Group; +import me.lucko.luckperms.common.tracks.Track; +import me.lucko.luckperms.common.users.User; + +import java.util.Set; +import java.util.UUID; + +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public abstract class AbstractBacking { + protected final LuckPermsPlugin plugin; + + @Getter + public final String name; + + @Getter + @Setter + private boolean acceptingLogins = false; + + /** + * Execute a runnable asynchronously + * @param r the task to run + */ + public void doAsync(Runnable r) { + plugin.doAsync(r); + } + + /** + * Execute a runnable synchronously + * @param r the task to run + */ + public void doSync(Runnable r) { + plugin.doSync(r); + } + + public abstract void init(); + public abstract void shutdown(); + public abstract boolean logAction(LogEntry entry); + public abstract Log getLog(); + public abstract boolean loadUser(UUID uuid, String username); + public abstract boolean saveUser(User user); + public abstract boolean cleanupUsers(); + public abstract Set getUniqueUsers(); + public abstract boolean createAndLoadGroup(String name); + public abstract boolean loadGroup(String name); + public abstract boolean loadAllGroups(); + public abstract boolean saveGroup(Group group); + public abstract boolean deleteGroup(Group group); + public abstract boolean createAndLoadTrack(String name); + public abstract boolean loadTrack(String name); + public abstract boolean loadAllTracks(); + public abstract boolean saveTrack(Track track); + public abstract boolean deleteTrack(Track track); + public abstract boolean saveUUIDData(String username, UUID uuid); + public abstract UUID getUUID(String username); + public abstract String getName(UUID uuid); + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/FlatfileDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/FlatfileBacking.java similarity index 96% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/FlatfileDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/FlatfileBacking.java index d6ef1ca6..4e5de670 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/FlatfileDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/FlatfileBacking.java @@ -20,14 +20,13 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import lombok.Cleanup; import me.lucko.luckperms.api.LogEntry; import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.constants.Constants; import me.lucko.luckperms.common.data.Log; -import me.lucko.luckperms.common.storage.Datastore; import java.io.*; import java.util.*; @@ -35,7 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.*; import java.util.logging.Formatter; -abstract class FlatfileDatastore extends Datastore { +abstract class FlatfileBacking extends AbstractBacking { private static final String LOG_FORMAT = "%s(%s): [%s] %s(%s) --> %s"; private final Logger actionLogger = Logger.getLogger("lp_actions"); @@ -48,7 +47,7 @@ abstract class FlatfileDatastore extends Datastore { File groupsDir; File tracksDir; - FlatfileDatastore(LuckPermsPlugin plugin, String name, File pluginDir) { + FlatfileBacking(LuckPermsPlugin plugin, String name, File pluginDir) { super(plugin, name); this.pluginDir = pluginDir; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/H2Datastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/H2Backing.java similarity index 96% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/H2Datastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/H2Backing.java index bc50f263..c0ed4ef5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/H2Datastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/H2Backing.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import lombok.Cleanup; import me.lucko.luckperms.common.LuckPermsPlugin; @@ -28,7 +28,7 @@ import me.lucko.luckperms.common.LuckPermsPlugin; import java.io.File; import java.sql.*; -public class H2Datastore extends SQLDatastore { +public class H2Backing extends SQLBacking { private static final String CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;"; private static final String CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`)) DEFAULT CHARSET=utf8;"; @@ -40,7 +40,7 @@ public class H2Datastore extends SQLDatastore { private Connection connection = null; private final Object connectionLock = new Object(); - public H2Datastore(LuckPermsPlugin plugin, File file) { + public H2Backing(LuckPermsPlugin plugin, File file) { super(plugin, "H2"); this.file = file; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/JSONDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java similarity index 99% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/JSONDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java index e888a89f..0def4cf0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/JSONDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; @@ -42,8 +42,8 @@ import java.util.stream.Collectors; import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy; @SuppressWarnings("ResultOfMethodCallIgnored") -public class JSONDatastore extends FlatfileDatastore { - public JSONDatastore(LuckPermsPlugin plugin, File pluginDir) { +public class JSONBacking extends FlatfileBacking { + public JSONBacking(LuckPermsPlugin plugin, File pluginDir) { super(plugin, "Flatfile - JSON", pluginDir); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/MongoDBDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java similarity index 98% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/MongoDBDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java index ae0854ac..a1d8646d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/MongoDBDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import com.mongodb.MongoClient; import com.mongodb.MongoCredential; @@ -34,7 +34,6 @@ import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.groups.GroupManager; -import me.lucko.luckperms.common.storage.Datastore; import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.tracks.Track; import me.lucko.luckperms.common.tracks.TrackManager; @@ -49,13 +48,13 @@ import java.util.stream.Collectors; import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy; @SuppressWarnings("unchecked") -public class MongoDBDatastore extends Datastore { +public class MongoDBBacking extends AbstractBacking { private final DatastoreConfiguration configuration; private MongoClient mongoClient; private MongoDatabase database; - public MongoDBDatastore(LuckPermsPlugin plugin, DatastoreConfiguration configuration) { + public MongoDBBacking(LuckPermsPlugin plugin, DatastoreConfiguration configuration) { super(plugin, "MongoDB"); this.configuration = configuration; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/MySQLDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MySQLBacking.java similarity index 97% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/MySQLDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/MySQLBacking.java index 362a58ee..21c7137f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/MySQLDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MySQLBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -33,7 +33,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -public class MySQLDatastore extends SQLDatastore { +public class MySQLBacking extends SQLBacking { private static final String CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`)) DEFAULT CHARSET=utf8;"; private static final String CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`)) DEFAULT CHARSET=utf8;"; @@ -44,7 +44,7 @@ public class MySQLDatastore extends SQLDatastore { private final DatastoreConfiguration configuration; private HikariDataSource hikari; - public MySQLDatastore(LuckPermsPlugin plugin, DatastoreConfiguration configuration) { + public MySQLBacking(LuckPermsPlugin plugin, DatastoreConfiguration configuration) { super(plugin, "MySQL"); this.configuration = configuration; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java similarity index 99% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java index 10681e66..d39813bb 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -29,7 +29,6 @@ import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.data.Log; import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.groups.GroupManager; -import me.lucko.luckperms.common.storage.Datastore; import me.lucko.luckperms.common.tracks.Track; import me.lucko.luckperms.common.tracks.TrackManager; import me.lucko.luckperms.common.users.User; @@ -44,7 +43,7 @@ import java.util.*; import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy; -abstract class SQLDatastore extends Datastore { +abstract class SQLBacking extends AbstractBacking { private static final QueryPS EMPTY_PS = preparedStatement -> {}; private static final Type NM_TYPE = new TypeToken>(){}.getType(); @@ -79,7 +78,7 @@ abstract class SQLDatastore extends Datastore { private final Gson gson; - SQLDatastore(LuckPermsPlugin plugin, String name) { + SQLBacking(LuckPermsPlugin plugin, String name) { super(plugin, name); gson = new Gson(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLiteDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLiteBacking.java similarity index 96% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLiteDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLiteBacking.java index 9b08a376..9e5189f9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/SQLiteDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLiteBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import lombok.Cleanup; import me.lucko.luckperms.common.LuckPermsPlugin; @@ -28,7 +28,7 @@ import me.lucko.luckperms.common.LuckPermsPlugin; import java.io.File; import java.sql.*; -public class SQLiteDatastore extends SQLDatastore { +public class SQLiteBacking extends SQLBacking { private static final String CREATETABLE_UUID = "CREATE TABLE IF NOT EXISTS `lp_uuid` (`name` VARCHAR(16) NOT NULL, `uuid` VARCHAR(36) NOT NULL, PRIMARY KEY (`name`));"; private static final String CREATETABLE_USERS = "CREATE TABLE IF NOT EXISTS `lp_users` (`uuid` VARCHAR(36) NOT NULL, `name` VARCHAR(16) NOT NULL, `primary_group` VARCHAR(36) NOT NULL, `perms` TEXT NOT NULL, PRIMARY KEY (`uuid`));"; @@ -40,7 +40,7 @@ public class SQLiteDatastore extends SQLDatastore { private Connection connection = null; private final Object connectionLock = new Object(); - public SQLiteDatastore(LuckPermsPlugin plugin, File file) { + public SQLiteBacking(LuckPermsPlugin plugin, File file) { super(plugin, "SQLite"); this.file = file; } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/methods/YAMLDatastore.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java similarity index 98% rename from common/src/main/java/me/lucko/luckperms/common/storage/methods/YAMLDatastore.java rename to common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java index ae52b488..9fe23292 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/methods/YAMLDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.storage.methods; +package me.lucko.luckperms.common.storage.backing; import lombok.Cleanup; import me.lucko.luckperms.common.LuckPermsPlugin; @@ -42,8 +42,8 @@ import java.util.stream.Collectors; import static me.lucko.luckperms.common.core.PermissionHolder.exportToLegacy; @SuppressWarnings({"unchecked", "ResultOfMethodCallIgnored"}) -public class YAMLDatastore extends FlatfileDatastore { - public YAMLDatastore(LuckPermsPlugin plugin, File pluginDir) { +public class YAMLBacking extends FlatfileBacking { + public YAMLBacking(LuckPermsPlugin plugin, File pluginDir) { super(plugin, "Flatfile - YAML", pluginDir); } diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java index d53b6a77..6182f172 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java @@ -41,7 +41,7 @@ public class AbstractListener { final UuidCache cache = plugin.getUuidCache(); if (!cache.isOnlineMode()) { - UUID uuid = plugin.getDatastore().getUUID(username); + UUID uuid = plugin.getDatastore().getUUID(username).getOrDefault(null); if (uuid != null) { cache.addToCache(u, uuid); } else { @@ -51,7 +51,7 @@ public class AbstractListener { plugin.getDatastore().saveUUIDData(username, u, Callback.empty()); } } else { - UUID uuid = plugin.getDatastore().getUUID(username); + UUID uuid = plugin.getDatastore().getUUID(username).getOrDefault(null); if (uuid == null) { plugin.getApiProvider().fireEventAsync(new UserFirstLoginEvent(u, username)); } diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java b/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java new file mode 100644 index 00000000..3bb9725f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.utils; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import me.lucko.luckperms.common.storage.AbstractFuture; + +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; + +/** + * Holds a buffer of objects to be processed after they've been in the buffer for a given time. + * @param the type of objects in the buffer + * @param the type of result produced by the final process + */ +public abstract class Buffer implements Runnable { + private static final long DEFAULT_FLUSH_TIME = 5000; // 5 seconds + + private final List> buffer = new LinkedList<>(); + + public LPFuture enqueue(@NonNull T t) { + synchronized (buffer) { + ListIterator> it = buffer.listIterator(); + + BufferedObject o = null; + + while (it.hasNext()) { + BufferedObject obj = it.next(); + + if (obj.getObject().equals(t)) { + o = obj; + it.remove(); + break; + } + } + + if (o == null) { + o = new BufferedObject<>(System.currentTimeMillis(), t, new AbstractFuture()); + } else { + o.setBufferTime(System.currentTimeMillis()); + } + + buffer.add(o); + return o.getFuture(); + } + } + + protected abstract R dequeue(T t); + + public void flush(long flushTime) { + long time = System.currentTimeMillis(); + + synchronized (buffer) { + ListIterator> it = buffer.listIterator(buffer.size()); + + while (it.hasPrevious()) { + BufferedObject obj = it.previous(); + long bufferedTime = time - obj.getBufferTime(); + + if (bufferedTime > flushTime) { + + // Flush + R r = dequeue(obj.getObject()); + obj.getFuture().complete(r); + it.remove(); + } + } + } + } + + @Override + public void run() { + flush(DEFAULT_FLUSH_TIME); + } + + @AllArgsConstructor + private static class BufferedObject { + + @Getter + @Setter + private long bufferTime; + + @Getter + private final T object; + + @Getter + private final AbstractFuture future; + + public boolean equals(Object o) { + if (o == this) return true; + if (!(o instanceof Buffer.BufferedObject)) return false; + + final BufferedObject other = (BufferedObject) o; + return this.getObject() == null ? other.getObject() == null : this.getObject().equals(other.getObject()); + } + + public int hashCode() { + return 59 + (this.getObject() == null ? 43 : this.getObject().hashCode()); + } + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java b/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java new file mode 100644 index 00000000..5f58f641 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.utils; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.common.storage.AbstractFuture; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Future; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.Consumer; +import java.util.function.Supplier; + +@RequiredArgsConstructor +public abstract class BufferedRequest { + private final long bufferTimeMillis; + private final Consumer executor; + + private WeakReference> processor = null; + + @Getter + private ReentrantLock lock = new ReentrantLock(); + + public Future request() { + lock.lock(); + try { + if (processor != null) { + Processor p = processor.get(); + if (p != null && p.isUsable()) { + return p.getAndExtend(); + } + } + + Processor p = new Processor<>(bufferTimeMillis, this::perform); + executor.accept(p); + processor = new WeakReference<>(p); + return p.get(); + + } finally { + lock.unlock(); + } + } + + protected abstract T perform(); + + + @RequiredArgsConstructor + private static class Processor implements Runnable { + private final long delayMillis; + private final Supplier supplier; + + @Getter + private boolean usable = true; + + private final ReentrantLock lock = new ReentrantLock(); + private long executionTime; + private final AbstractFuture future = new AbstractFuture<>(); + + @Override + public void run() { + lock.lock(); + try { + executionTime = System.currentTimeMillis() + delayMillis; + } finally { + lock.unlock(); + } + + while (true) { + lock.lock(); + try { + if (System.currentTimeMillis() > executionTime) { + usable = false; + break; + } + + } finally { + lock.unlock(); + } + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + R result = supplier.get(); + future.complete(result); + } + + public Future get() { + return future; + } + + public Future getAndExtend() { + lock.lock(); + try { + executionTime = System.currentTimeMillis() + delayMillis; + } finally { + lock.unlock(); + } + + return future; + } + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/LPFuture.java b/common/src/main/java/me/lucko/luckperms/common/utils/LPFuture.java new file mode 100644 index 00000000..ee2f3738 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/utils/LPFuture.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.utils; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public interface LPFuture extends Future { + + default T getOrDefault(T def) { + try { + return get(); + } catch (InterruptedException | ExecutionException e) { + return def; + } + } + +} diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java index bddf5246..c1676d3a 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -307,6 +307,11 @@ public class LPSpongePlugin implements LuckPermsPlugin { scheduler.createTaskBuilder().execute(r).submit(this); } + @Override + public void doAsyncRepeating(Runnable r, long interval) { + scheduler.createTaskBuilder().async().intervalTicks(interval).execute(r).submit(this); + } + private void registerPermission(PermissionService p, String node) { Optional builder = p.newDescriptionBuilder(this); if (!builder.isPresent()) return;