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