diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala index eb982b0f7e..e31ed5cd1b 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/Databases.scala @@ -20,6 +20,8 @@ import java.io.File import java.sql.{Connection, DriverManager} import fr.acinq.eclair.db.sqlite._ +import grizzled.slf4j.Logging +import org.sqlite.SQLiteException trait Databases { @@ -35,24 +37,39 @@ trait Databases { val pendingRelay: PendingRelayDb - def backup(file: File) : Unit + def backup(file: File): Unit } -object Databases { +object Databases extends Logging { /** * Given a parent folder it creates or loads all the databases from a JDBC connection + * * @param dbdir * @return */ def sqliteJDBC(dbdir: File): Databases = { dbdir.mkdir() - val sqliteEclair = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "eclair.sqlite")}") - val sqliteNetwork = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "network.sqlite")}") - val sqliteAudit = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "audit.sqlite")}") - SqliteUtils.obtainExclusiveLock(sqliteEclair) // there should only be one process writing to this file + var sqliteEclair: Connection = null + var sqliteNetwork: Connection = null + var sqliteAudit: Connection = null + try { + sqliteEclair = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "eclair.sqlite")}") + sqliteNetwork = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "network.sqlite")}") + sqliteAudit = DriverManager.getConnection(s"jdbc:sqlite:${new File(dbdir, "audit.sqlite")}") + SqliteUtils.obtainExclusiveLock(sqliteEclair) // there should only be one process writing to this file + logger.info("successful lock on eclair.sqlite") + databaseByConnections(sqliteAudit, sqliteNetwork, sqliteEclair) + } catch { + case t: Throwable => { + logger.error("could not create connection to sqlite databases: ", t) + if (sqliteEclair != null) sqliteEclair.close() + if (sqliteNetwork != null) sqliteNetwork.close() + if (sqliteAudit != null) sqliteAudit.close() + throw t + } + } - databaseByConnections(sqliteAudit, sqliteNetwork, sqliteEclair) } def databaseByConnections(auditJdbc: Connection, networkJdbc: Connection, eclairJdbc: Connection) = new Databases { @@ -62,9 +79,10 @@ object Databases { override val peers = new SqlitePeersDb(eclairJdbc) override val payments = new SqlitePaymentsDb(eclairJdbc) override val pendingRelay = new SqlitePendingRelayDb(eclairJdbc) + override def backup(file: File): Unit = { SqliteUtils.using(eclairJdbc.createStatement()) { - statement => { + statement => { statement.executeUpdate(s"backup to ${file.getAbsolutePath}") } } diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteUtils.scala b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteUtils.scala index 4b5b957e1a..509ed89768 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteUtils.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/db/sqlite/SqliteUtils.scala @@ -99,7 +99,7 @@ object SqliteUtils { * * The lock will be kept until the database is closed, or if the locking mode is explicitly reset. */ - def obtainExclusiveLock(sqlite: Connection) { + def obtainExclusiveLock(sqlite: Connection) = synchronized { val statement = sqlite.createStatement() statement.execute("PRAGMA locking_mode = EXCLUSIVE") // we have to make a write to actually obtain the lock