Virtual Threads for database caching

This commit is contained in:
HaHaWTH 2024-03-28 15:21:22 +08:00
parent a93f0546e3
commit 6a96d993e1
3 changed files with 43 additions and 11 deletions

View File

@ -9,18 +9,22 @@ import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService; import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth; import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache; import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.output.ConsoleLoggerFactory; import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils;
import java.lang.reflect.Method;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -28,11 +32,10 @@ import java.util.stream.Collectors;
public class CacheDataSource implements DataSource { public class CacheDataSource implements DataSource {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(CacheDataSource.class); private final ConsoleLogger logger = ConsoleLoggerFactory.get(CacheDataSource.class);
private final DataSource source; private final DataSource source;
private final PlayerCache playerCache; private final PlayerCache playerCache;
private final LoadingCache<String, Optional<PlayerAuth>> cachedAuths; private final LoadingCache<String, Optional<PlayerAuth>> cachedAuths;
private final ListeningExecutorService executorService; private ListeningExecutorService executorService;
/** /**
* Constructor for CacheDataSource. * Constructor for CacheDataSource.
@ -43,13 +46,30 @@ public class CacheDataSource implements DataSource {
public CacheDataSource(DataSource source, PlayerCache playerCache) { public CacheDataSource(DataSource source, PlayerCache playerCache) {
this.source = source; this.source = source;
this.playerCache = playerCache; this.playerCache = playerCache;
if (AuthMe.settings.getProperty(DatabaseSettings.USE_VIRTUAL_THREADS)) {
executorService = MoreExecutors.listeningDecorator( try {
Executors.newCachedThreadPool(new ThreadFactoryBuilder() Method method = Executors.class.getMethod("newVirtualThreadPerTaskExecutor");
.setDaemon(true) method.setAccessible(true);
.setNameFormat("AuthMe-CacheLoader") ExecutorService ex = (ExecutorService) method.invoke(null);
.build()) executorService = MoreExecutors.listeningDecorator(ex);
); logger.info("Using virtual threads for cache loader");
} catch (Exception e) {
executorService = MoreExecutors.listeningDecorator(
Executors.newCachedThreadPool(new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("AuthMe-CacheLoader")
.build())
);
logger.info("Cannot enable virtual threads, fallback to CachedThread");
}
} else {
executorService = MoreExecutors.listeningDecorator(
Executors.newCachedThreadPool(new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("AuthMe-CacheLoader")
.build())
);
}
cachedAuths = CacheBuilder.newBuilder() cachedAuths = CacheBuilder.newBuilder()
.refreshAfterWrite(5, TimeUnit.MINUTES) .refreshAfterWrite(5, TimeUnit.MINUTES)
.expireAfterAccess(15, TimeUnit.MINUTES) .expireAfterAccess(15, TimeUnit.MINUTES)

View File

@ -98,11 +98,19 @@ public class BukkitService implements SettingsDependent {
* @throws IllegalArgumentException if task is null * @throws IllegalArgumentException if task is null
*/ */
public void runTask(Runnable task) { public void runTask(Runnable task) {
getScheduler().runTask(task); if (IS_FOLIA) {
getScheduler().runTask(task);
} else {
Bukkit.getScheduler().runTask(authMe, task);
}
} }
public void runTask(Entity entity, Runnable task) { public void runTask(Entity entity, Runnable task) {
getScheduler().runTask(entity, task); if (IS_FOLIA) {
getScheduler().runTask(entity, task);
} else {
Bukkit.getScheduler().runTask(authMe, task);
}
} }
public void runTask(Location location, Runnable task) { public void runTask(Location location, Runnable task) {

View File

@ -19,6 +19,10 @@ public final class DatabaseSettings implements SettingsHolder {
public static final Property<Boolean> USE_CACHING = public static final Property<Boolean> USE_CACHING =
newProperty("DataSource.caching", true); newProperty("DataSource.caching", true);
@Comment("Should we try to use VirtualThreads(Java 21+) for database cache loader?")
public static final Property<Boolean> USE_VIRTUAL_THREADS =
newProperty("DataSource.useVirtualThreadsCache", false);
@Comment("Database host address") @Comment("Database host address")
public static final Property<String> MYSQL_HOST = public static final Property<String> MYSQL_HOST =
newProperty("DataSource.mySQLHost", "127.0.0.1"); newProperty("DataSource.mySQLHost", "127.0.0.1");