X-Git-Url: https://code.wpia.club/?p=gigi.git;a=blobdiff_plain;f=src%2Forg%2Fcacert%2Fgigi%2Fdatabase%2FDatabaseConnection.java;h=a855d706155faff34fd993cbbcbcf88fd0abb8c1;hp=bf7cd3be38bea730e76b90cf1e5accf1c577929b;hb=d7be034f96e06985f57d86d2779c434276b5bd4d;hpb=6e23ad9bc75d6cb2aa86cb36654a6ef44a167011 diff --git a/src/org/cacert/gigi/database/DatabaseConnection.java b/src/org/cacert/gigi/database/DatabaseConnection.java index bf7cd3be..a855d706 100644 --- a/src/org/cacert/gigi/database/DatabaseConnection.java +++ b/src/org/cacert/gigi/database/DatabaseConnection.java @@ -14,6 +14,7 @@ import java.util.HashSet; import java.util.Map.Entry; import java.util.Properties; import java.util.StringJoiner; +import java.util.concurrent.LinkedBlockingDeque; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -21,6 +22,28 @@ import org.cacert.gigi.database.SQLFileManager.ImportType; public class DatabaseConnection { + public static class Link implements AutoCloseable { + + private DatabaseConnection target; + + protected Link(DatabaseConnection target) { + this.target = target; + } + + @Override + public void close() { + synchronized (DatabaseConnection.class) { + Link i = instances.get(Thread.currentThread()); + if (i != this) { + throw new Error(); + } + instances.remove(Thread.currentThread()); + pool.add(target); + } + } + + } + public static final int MAX_CACHED_INSTANCES = 3; private static class StatementDescriptor { @@ -99,7 +122,7 @@ public class DatabaseConnection { } - public static final int CURRENT_SCHEMA_VERSION = 9; + public static final int CURRENT_SCHEMA_VERSION = 11; public static final int CONNECTION_TIMEOUT = 24 * 60 * 60; @@ -107,7 +130,7 @@ public class DatabaseConnection { private HashMap statements = new HashMap(); - HashSet underUse = new HashSet<>(); + private HashSet underUse = new HashSet<>(); private static Properties credentials; @@ -183,13 +206,23 @@ public class DatabaseConnection { lastAction = System.currentTimeMillis(); } - private static volatile DatabaseConnection instance; + private static HashMap instances = new HashMap<>(); + + private static LinkedBlockingDeque pool = new LinkedBlockingDeque<>(); + + private static int connCount = 0; public static synchronized DatabaseConnection getInstance() { - if (instance == null) { - instance = new DatabaseConnection(); + Link l = instances.get(Thread.currentThread()); + if (l == null) { + throw new Error("No database connection allocated"); } - return instance; + return l.target; + } + + public static synchronized boolean hasInstance() { + Link l = instances.get(Thread.currentThread()); + return l != null; } public static boolean isInited() { @@ -201,24 +234,24 @@ public class DatabaseConnection { throw new Error("Re-initiaizing is forbidden."); } credentials = conf; - int version = 0; - try (GigiPreparedStatement gigiPreparedStatement = new GigiPreparedStatement("SELECT version FROM \"schemeVersion\" ORDER BY version DESC LIMIT 1;")) { - GigiResultSet rs = gigiPreparedStatement.executeQuery(); - if (rs.next()) { - version = rs.getInt(1); + try (Link i = newLink(false)) { + int version = 0; + try (GigiPreparedStatement gigiPreparedStatement = new GigiPreparedStatement("SELECT version FROM \"schemeVersion\" ORDER BY version DESC LIMIT 1;")) { + GigiResultSet rs = gigiPreparedStatement.executeQuery(); + if (rs.next()) { + version = rs.getInt(1); + } } + if (version == CURRENT_SCHEMA_VERSION) { + return; // Good to go + } + if (version > CURRENT_SCHEMA_VERSION) { + throw new Error("Invalid database version. Please fix this."); + } + upgrade(version); + } catch (InterruptedException e) { + throw new Error(e); } - if (version == CURRENT_SCHEMA_VERSION) { - return; // Good to go - } - if (version > CURRENT_SCHEMA_VERSION) { - throw new Error("Invalid database version. Please fix this."); - } - upgrade(version); - } - - public void beginTransaction() throws SQLException { - c.setAutoCommit(false); } private static void upgrade(int version) { @@ -226,12 +259,7 @@ public class DatabaseConnection { Statement s = getInstance().c.createStatement(); try { while (version < CURRENT_SCHEMA_VERSION) { - try (InputStream resourceAsStream = DatabaseConnection.class.getResourceAsStream("upgrade/from_" + version + ".sql")) { - if (resourceAsStream == null) { - throw new Error("Upgrade script from version " + version + " was not found."); - } - SQLFileManager.addFile(s, resourceAsStream, ImportType.PRODUCTION); - } + addUpgradeScript(Integer.toString(version), s); version++; } s.addBatch("UPDATE \"schemeVersion\" SET version='" + version + "'"); @@ -248,19 +276,12 @@ public class DatabaseConnection { } } - public void commitTransaction() throws SQLException { - c.commit(); - c.setAutoCommit(true); - } - - public void quitTransaction() { - try { - if ( !c.getAutoCommit()) { - c.rollback(); - c.setAutoCommit(true); + private static void addUpgradeScript(String version, Statement s) throws Error, IOException, SQLException { + try (InputStream resourceAsStream = DatabaseConnection.class.getResourceAsStream("upgrade/from_" + version + ".sql")) { + if (resourceAsStream == null) { + throw new Error("Upgrade script from version " + version + " was not found."); } - } catch (SQLException e) { - e.printStackTrace(); + SQLFileManager.addFile(s, resourceAsStream, ImportType.PRODUCTION); } } @@ -322,4 +343,23 @@ public class DatabaseConnection { } } } + + public static synchronized Link newLink(boolean readOnly) throws InterruptedException { + if (instances.get(Thread.currentThread()) != null) { + throw new Error("There is already a connection allocated for this thread."); + } + if (pool.isEmpty() && connCount < 5) { + pool.addLast(new DatabaseConnection()); + connCount++; + } + DatabaseConnection conn = pool.takeFirst(); + try { + conn.c.setReadOnly(readOnly); + } catch (SQLException e) { + throw new Error(e); + } + Link l = new Link(conn); + instances.put(Thread.currentThread(), l); + return l; + } }