mirror of
https://github.com/plan-player-analytics/Plan.git
synced 2025-01-03 06:57:36 +01:00
Make call-site for SQLite JVM wait more accurate
Affects issues: - #3436
This commit is contained in:
parent
e041e193fc
commit
2daf3943b7
@ -84,6 +84,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
|
||||
private Supplier<ExecutorService> transactionExecutorServiceProvider;
|
||||
private ExecutorService transactionExecutor;
|
||||
private static final ThreadLocal<StackTraceElement[]> TRANSACTION_ORIGIN = new ThreadLocal<>();
|
||||
|
||||
private final AtomicInteger transactionQueueSize = new AtomicInteger(0);
|
||||
private final AtomicBoolean dropUnimportantTransactions = new AtomicBoolean(false);
|
||||
@ -345,13 +346,17 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
return accessLock.performDatabaseOperation(() -> query.executeQuery(this), transaction);
|
||||
}
|
||||
|
||||
public static ThreadLocal<StackTraceElement[]> getTransactionOrigin() {
|
||||
return TRANSACTION_ORIGIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<?> executeTransaction(Transaction transaction) {
|
||||
if (getState() == State.CLOSED) {
|
||||
throw new DBClosedException("Transaction tried to execute although database is closed.");
|
||||
}
|
||||
|
||||
Exception origin = new Exception();
|
||||
StackTraceElement[] origin = Thread.currentThread().getStackTrace();
|
||||
|
||||
if (determineIfShouldDropUnimportantTransactions(transactionQueueSize.incrementAndGet())
|
||||
&& transaction instanceof ThrowawayTransaction) {
|
||||
@ -361,6 +366,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
|
||||
return CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
TRANSACTION_ORIGIN.set(origin);
|
||||
if (getState() == State.CLOSED) return CompletableFuture.completedFuture(null);
|
||||
|
||||
accessLock.performDatabaseOperation(() -> {
|
||||
@ -369,6 +375,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
} finally {
|
||||
transactionQueueSize.decrementAndGet();
|
||||
TRANSACTION_ORIGIN.remove();
|
||||
}
|
||||
}, getTransactionExecutor()).exceptionally(errorHandler(transaction, origin));
|
||||
}
|
||||
@ -389,7 +396,7 @@ public abstract class SQLDB extends AbstractDatabase {
|
||||
return dropTransactions;
|
||||
}
|
||||
|
||||
private Function<Throwable, CompletableFuture<Object>> errorHandler(Transaction transaction, Exception origin) {
|
||||
private Function<Throwable, CompletableFuture<Object>> errorHandler(Transaction transaction, StackTraceElement[] origin) {
|
||||
return throwable -> {
|
||||
if (throwable == null) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
|
@ -76,7 +76,7 @@ public class SQLiteDB extends SQLDB {
|
||||
super(() -> serverInfo.get().getServerUUID(), locale, config, files, runnableFactory, logger, errorLogger);
|
||||
dbName = databaseFile.getName();
|
||||
this.databaseFile = databaseFile;
|
||||
connectionLock = new SemaphoreAccessCounter(config);
|
||||
connectionLock = new SemaphoreAccessCounter();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -16,7 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.utilities;
|
||||
|
||||
import com.djrapitops.plan.settings.config.PlanConfig;
|
||||
import com.djrapitops.plan.storage.database.SQLDB;
|
||||
import com.djrapitops.plan.utilities.java.ThrowableUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
@ -27,14 +28,11 @@ import java.util.logging.Logger;
|
||||
|
||||
public class SemaphoreAccessCounter {
|
||||
|
||||
private final PlanConfig config;
|
||||
|
||||
private final AtomicInteger accessCounter;
|
||||
private final Object lockObject;
|
||||
private final Collection<String> holds = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
|
||||
public SemaphoreAccessCounter(PlanConfig config) {
|
||||
this.config = config;
|
||||
public SemaphoreAccessCounter() {
|
||||
accessCounter = new AtomicInteger(0);
|
||||
lockObject = new Object();
|
||||
}
|
||||
@ -43,7 +41,11 @@ public class SemaphoreAccessCounter {
|
||||
private static String getAccessingThing() {
|
||||
boolean previousWasAccess = false;
|
||||
List<StackTraceElement> accessors = new ArrayList<>();
|
||||
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
|
||||
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
|
||||
StackTraceElement[] origin = SQLDB.getTransactionOrigin().get();
|
||||
StackTraceElement[] callSite = ThrowableUtils.combineStackTrace(origin, stackTrace);
|
||||
|
||||
for (StackTraceElement e : callSite) {
|
||||
if (previousWasAccess) {
|
||||
accessors.add(e);
|
||||
previousWasAccess = false;
|
||||
@ -54,7 +56,7 @@ public class SemaphoreAccessCounter {
|
||||
previousWasAccess = true;
|
||||
}
|
||||
}
|
||||
if (accessors.isEmpty()) accessors.addAll(Arrays.asList(Thread.currentThread().getStackTrace()));
|
||||
if (accessors.isEmpty()) accessors.addAll(Arrays.asList(callSite));
|
||||
return accessors.toString();
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
*/
|
||||
package com.djrapitops.plan.utilities.java;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -30,20 +32,29 @@ public class ThrowableUtils {
|
||||
/* Static method class */
|
||||
}
|
||||
|
||||
public static void appendEntryPointToCause(Throwable throwable, Throwable originPoint) {
|
||||
public static void appendEntryPointToCause(Throwable throwable, StackTraceElement[] originPoint) {
|
||||
Throwable cause = throwable.getCause();
|
||||
while (cause.getCause() != null) {
|
||||
cause = cause.getCause();
|
||||
}
|
||||
|
||||
cause.setStackTrace(
|
||||
Stream.concat(
|
||||
Arrays.stream(cause.getStackTrace()),
|
||||
Arrays.stream(originPoint.getStackTrace())
|
||||
).toArray(StackTraceElement[]::new)
|
||||
combineStackTrace(originPoint, cause.getStackTrace())
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StackTraceElement[] combineStackTrace(StackTraceElement[] originPoint, StackTraceElement[] cause) {
|
||||
if (originPoint == null && cause == null) return new StackTraceElement[0];
|
||||
if (originPoint == null) return cause;
|
||||
if (cause == null) return originPoint;
|
||||
|
||||
return Stream.concat(
|
||||
Arrays.stream(cause),
|
||||
Arrays.stream(originPoint)
|
||||
).toArray(StackTraceElement[]::new);
|
||||
}
|
||||
|
||||
public static String findCallerAfterClass(StackTraceElement[] stackTrace, Class<?> afterThis) {
|
||||
boolean found = false;
|
||||
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
|
Loading…
Reference in New Issue
Block a user