mirror of
https://github.com/funkemunky/AntiVPN.git
synced 2026-05-31 01:21:55 +00:00
Fixing SQL load errors
This commit is contained in:
@@ -63,7 +63,7 @@
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<minimizeJar>true</minimizeJar>
|
||||
<minimizeJar>false</minimizeJar>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>org.yaml.snakeyaml</pattern>
|
||||
@@ -148,7 +148,7 @@
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>9.1.0</version>
|
||||
<version>9.3.0</version>
|
||||
<type>jar</type>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
@@ -182,7 +182,6 @@
|
||||
<version>3.1.8</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mongodb</groupId>
|
||||
<artifactId>mongo-java-driver</artifactId>
|
||||
|
||||
@@ -57,10 +57,10 @@ import java.util.List;
|
||||
@MavenLibrary(
|
||||
groupId = "com.mysql",
|
||||
artifactId = "mysql-connector-j",
|
||||
version = "9.1.0",
|
||||
version = "9.3.0",
|
||||
relocations = {
|
||||
@Relocate(from = "com.my\\" + "sql.cj", to = "dev.brighten.antivpn.shaded.com.mysql.cj"),
|
||||
@Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc")
|
||||
@Relocate(from = "com.my\\" + "sql.jdbc", to = "dev.brighten.antivpn.shaded.com.mysql.jdbc"),
|
||||
}
|
||||
)
|
||||
@MavenLibrary(groupId = "com.\\github\\.ben-manes\\.caffeine", artifactId = "caffeine", version = "3.1.8",
|
||||
|
||||
@@ -359,15 +359,37 @@ public class H2VPN implements VPNDatabase {
|
||||
public void backupDatabase() {
|
||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||
|
||||
if(!dataFolder.exists()) {
|
||||
if(!dataFolder.exists() || MySQL.isClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<File> files = new ArrayList<>(List.of(Optional.ofNullable(dataFolder.listFiles()).orElse(new File[0])));
|
||||
files.sort(Comparator.comparingLong(File::lastModified));
|
||||
try {
|
||||
var connection = Query.getConn();
|
||||
if (connection == null || connection.getMetaData() == null
|
||||
|| !connection.getMetaData().getDatabaseProductName().equalsIgnoreCase("H2")) {
|
||||
return;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Could not verify database type before H2 backup.", e);
|
||||
return;
|
||||
}
|
||||
|
||||
for (File file : files) {
|
||||
MySQL.backupOldDB(file, dataFolder);
|
||||
File backupDir = new File(dataFolder, "backups");
|
||||
if (!backupDir.exists() && !backupDir.mkdirs()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Could not create backup directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File backupFile = new File(backupDir, "database.h2_backup_" + System.currentTimeMillis() + ".zip");
|
||||
String backupPath = backupFile.getAbsolutePath()
|
||||
.replace("\\", "/")
|
||||
.replace("'", "''");
|
||||
|
||||
try (var statement = Query.prepare("BACKUP TO '" + backupPath + "'")) {
|
||||
statement.execute();
|
||||
AntiVPN.getInstance().getExecutor().log("Created H2 backup at " + backupFile.getName());
|
||||
} catch (SQLException e) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Could not create H2 backup before migration.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import dev.brighten.antivpn.database.sql.utils.Query;
|
||||
import dev.brighten.antivpn.database.version.Version;
|
||||
import dev.brighten.antivpn.utils.MiscUtils;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
@@ -51,11 +52,11 @@ public class First implements Version<VPNDatabase> {
|
||||
.append(versionNumber())).execute();
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Creating indexes...");
|
||||
closeOnEnd(Query.prepare("create index if not exists `uuid_1` on `whitelisted` (`uuid`)")).execute();
|
||||
closeOnEnd(Query.prepare("create index if not exists `ip_1` on `responses` (`ip`)")).execute();
|
||||
closeOnEnd(Query.prepare("create index if not exists `proxy_1` on `responses` (`proxy`)")).execute();
|
||||
closeOnEnd(Query.prepare("create index if not exists `inserted_1` on `responses` (`inserted`)")).execute();
|
||||
closeOnEnd(Query.prepare("create index if not exists `ip_1` on `whitelisted-ips` (`ip`)")).execute();
|
||||
createIndexIfAbsent("whitelisted", "uuid_1", "`uuid`");
|
||||
createIndexIfAbsent("responses", "ip_1", "`ip`");
|
||||
createIndexIfAbsent("responses", "proxy_1", "`proxy`");
|
||||
createIndexIfAbsent("responses", "inserted_1", "`inserted`");
|
||||
createIndexIfAbsent("whitelisted-ips", "ip_1", "`ip`");
|
||||
} catch (SQLException e) {
|
||||
throw new DatabaseException("Failed to update database", e);
|
||||
} finally {
|
||||
@@ -69,6 +70,47 @@ public class First implements Version<VPNDatabase> {
|
||||
return statement;
|
||||
}
|
||||
|
||||
protected void createIndexIfAbsent(String tableName, String indexName, String columnList) throws SQLException {
|
||||
if (hasIndex(tableName, indexName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeOnEnd(Query.prepare(String.format(
|
||||
"create index `%s` on `%s` (%s)",
|
||||
indexName,
|
||||
tableName,
|
||||
columnList
|
||||
))).execute();
|
||||
}
|
||||
|
||||
protected void dropIndexIfPresent(String tableName, String indexName) throws SQLException {
|
||||
if (!hasIndex(tableName, indexName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
closeOnEnd(Query.prepare(String.format(
|
||||
"drop index `%s` on `%s`",
|
||||
indexName,
|
||||
tableName
|
||||
))).execute();
|
||||
}
|
||||
|
||||
protected boolean hasIndex(String tableName, String indexName) throws SQLException {
|
||||
DatabaseMetaData metaData = Query.getConn().getMetaData();
|
||||
|
||||
try (ResultSet indexes = metaData.getIndexInfo(null, null, tableName, false, false)) {
|
||||
while (indexes.next()) {
|
||||
String existingIndexName = indexes.getString("INDEX_NAME");
|
||||
|
||||
if (existingIndexName != null && existingIndexName.equalsIgnoreCase(indexName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int versionNumber() {
|
||||
return 0;
|
||||
@@ -78,7 +120,7 @@ public class First implements Version<VPNDatabase> {
|
||||
public boolean needsUpdate(VPNDatabase database) {
|
||||
try(var statement = Query.prepare("select * from `database_version` where version = 0")) {
|
||||
try(ResultSet set = statement.executeQuery()) {
|
||||
return set.getFetchSize() == 0;
|
||||
return !set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
return true;
|
||||
|
||||
+8
-11
@@ -20,6 +20,7 @@ import dev.brighten.antivpn.AntiVPN;
|
||||
import dev.brighten.antivpn.database.DatabaseException;
|
||||
import dev.brighten.antivpn.database.VPNDatabase;
|
||||
import dev.brighten.antivpn.database.local.H2VPN;
|
||||
import dev.brighten.antivpn.database.sql.MySqlVPN;
|
||||
import dev.brighten.antivpn.database.sql.utils.ExecutableStatement;
|
||||
import dev.brighten.antivpn.database.sql.utils.Query;
|
||||
import dev.brighten.antivpn.database.version.Version;
|
||||
@@ -31,12 +32,12 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Second implements Version<VPNDatabase> {
|
||||
public class Second extends First implements Version<VPNDatabase> {
|
||||
private final List<AutoCloseable> toClose = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void update(VPNDatabase database) throws DatabaseException {
|
||||
if(database instanceof H2VPN h2VPN) {
|
||||
if(database instanceof H2VPN h2VPN && !(database instanceof MySqlVPN)) {
|
||||
h2VPN.backupDatabase();
|
||||
}
|
||||
List<String> whitelistedIps = new ArrayList<>();
|
||||
@@ -58,7 +59,7 @@ public class Second implements Version<VPNDatabase> {
|
||||
"ip_start BIGINT NOT NULL, " +
|
||||
"ip_end BIGINT NOT NULL)"))
|
||||
.execute();
|
||||
closeOnEnd(Query.prepare("CREATE INDEX idx_ip_range ON `whitelisted-ranges` (ip_start, ip_end)")).execute();
|
||||
createIndexIfAbsent("whitelisted-ranges", "idx_ip_range", "ip_start, ip_end");
|
||||
|
||||
var cidrs = whitelistedIps.stream().map(ip -> {
|
||||
try {
|
||||
@@ -84,7 +85,7 @@ public class Second implements Version<VPNDatabase> {
|
||||
}
|
||||
}
|
||||
|
||||
closeOnEnd(Query.prepare("DROP INDEX ip_1 on `whitelisted-ips`")).execute();
|
||||
dropIndexIfPresent("whitelisted-ips", "ip_1");
|
||||
closeOnEnd(Query.prepare("DROP TABLE `whitelisted-ips`")).execute();
|
||||
closeOnEnd(Query.prepare("INSERT INTO `database_version` (`version`) VALUES (?)").append(versionNumber())).execute();
|
||||
} catch (Throwable e) {
|
||||
@@ -109,9 +110,7 @@ public class Second implements Version<VPNDatabase> {
|
||||
|
||||
private void rollback(List<String> ipAddresses) throws SQLException {
|
||||
AntiVPN.getInstance().getExecutor().log("Rolling back to version 0...");
|
||||
try(var statement = Query.prepare("DROP INDEX idx_ip_range ON `whitelisted-ranges`")) {
|
||||
statement.execute();
|
||||
}
|
||||
dropIndexIfPresent("whitelisted-ranges", "idx_ip_range");
|
||||
try(var statement = Query.prepare("DROP TABLE `whitelisted-ranges`")) {
|
||||
statement.execute();
|
||||
}
|
||||
@@ -124,9 +123,7 @@ public class Second implements Version<VPNDatabase> {
|
||||
statement.execute();
|
||||
}
|
||||
|
||||
try(var statement = Query.prepare("create index if not exists `ip_1` on `whitelisted-ips` (`ip`)")) {
|
||||
statement.execute();
|
||||
}
|
||||
createIndexIfAbsent("whitelisted-ips", "ip_1", "`ip`");
|
||||
|
||||
try(var statement = Query.prepare("DELETE FROM `whitelisted-ips`")) {
|
||||
statement.execute();
|
||||
@@ -151,7 +148,7 @@ public class Second implements Version<VPNDatabase> {
|
||||
public boolean needsUpdate(VPNDatabase database) {
|
||||
try (var statement = Query.prepare("select * from `database_version` where version = 1")) {
|
||||
try(var set = statement.executeQuery()) {
|
||||
return set.getFetchSize() == 0;
|
||||
return !set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
return true;
|
||||
|
||||
@@ -106,7 +106,7 @@ public class Third implements Version<VPNDatabase> {
|
||||
public boolean needsUpdate(VPNDatabase database) {
|
||||
try (var statement = Query.prepare("select * from `database_version` where version = 2")) {
|
||||
try(var set = statement.executeQuery()) {
|
||||
return set.getFetchSize() == 0;
|
||||
return !set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
return true;
|
||||
|
||||
@@ -54,14 +54,11 @@ public class MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean didRetry = false;
|
||||
|
||||
public static void initH2() {
|
||||
if(didRetry) {
|
||||
AntiVPN.getInstance().getExecutor().log(Level.WARNING,
|
||||
"Already attempted to retry H2 connection, skipping.");
|
||||
return;
|
||||
}
|
||||
initH2(true);
|
||||
}
|
||||
|
||||
private static void initH2(boolean allowRetry) {
|
||||
File dataFolder = new File(AntiVPN.getInstance().getPluginFolder(), "databases");
|
||||
if (!dataFolder.exists() && dataFolder.mkdirs()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Created database directory");
|
||||
@@ -85,9 +82,13 @@ public class MySQL {
|
||||
AntiVPN.getInstance().getExecutor()
|
||||
.log("H2 database file is incompatible with this version of AntiVPN. " +
|
||||
"Backing up old database file...");
|
||||
backupOldDB(dbFile, dataFolder);
|
||||
initH2();
|
||||
didRetry = true;
|
||||
shutdown();
|
||||
if (allowRetry && backupOldDB(dbFile, dataFolder)) {
|
||||
initH2(false);
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().log(
|
||||
"Could not back up and remove the incompatible H2 database file automatically.");
|
||||
}
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().logException("Failed to load H2 database: " + ex.getCause().toString(), ex);
|
||||
}
|
||||
@@ -97,31 +98,42 @@ public class MySQL {
|
||||
}
|
||||
}
|
||||
|
||||
public static void backupOldDB(File dbFile, File dataFolder) {
|
||||
if (dbFile.exists()) {
|
||||
try {
|
||||
// Optional: Make backup first
|
||||
File backupDir = new File(dataFolder, "backups");
|
||||
if(backupDir.mkdirs()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Created backup directory");
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().log("Backup directory already exists");
|
||||
}
|
||||
File backupFile = new File(backupDir, dbFile.getName() + ".backup_" + System.currentTimeMillis());
|
||||
Files.copy(dbFile.toPath(), backupFile.toPath());
|
||||
|
||||
// Actually delete the file
|
||||
if (!dbFile.delete()) {
|
||||
// If normal delete fails, try force delete on JVM exit
|
||||
dbFile.deleteOnExit();
|
||||
AntiVPN.getInstance().getExecutor().log("Could not delete database file - will try again on shutdown");
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().log("Successfully deleted incompatible database file");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Failed to handle database file", ex);
|
||||
}
|
||||
public static boolean backupOldDB(File dbFile, File dataFolder) {
|
||||
if (!dbFile.exists()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!dbFile.isFile()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Skipping backup for non-file path: " + dbFile.getAbsolutePath());
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
File backupDir = new File(dataFolder, "backups");
|
||||
if(backupDir.mkdirs()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Created backup directory");
|
||||
} else if (backupDir.exists()) {
|
||||
AntiVPN.getInstance().getExecutor().log("Backup directory already exists");
|
||||
} else {
|
||||
AntiVPN.getInstance().getExecutor().log("Could not create backup directory");
|
||||
return false;
|
||||
}
|
||||
File backupFile = new File(backupDir, dbFile.getName() + ".backup_" + System.currentTimeMillis());
|
||||
Files.copy(dbFile.toPath(), backupFile.toPath());
|
||||
|
||||
if (!dbFile.delete()) {
|
||||
dbFile.deleteOnExit();
|
||||
AntiVPN.getInstance().getExecutor().log("Could not delete database file - will try again on shutdown");
|
||||
return false;
|
||||
}
|
||||
|
||||
AntiVPN.getInstance().getExecutor().log("Successfully deleted incompatible database file");
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
AntiVPN.getInstance().getExecutor().logException("Failed to handle database file", ex);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void use() {
|
||||
|
||||
Reference in New Issue
Block a user