diff --git a/gradle.properties b/gradle.properties index 2d8d1e4dd150cb790e1efef522121e30222820d4..98026c56f7ececb04c7dc71c78524d831cf92b19 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1,2 @@ -android.useAndroidX=true \ No newline at end of file +android.useAndroidX=true +org.gradle.jvmargs=-Xmx1g diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt index 79fafc22b5f2ec588ad3a84d6b9eed1424dcb651..b46c2d3409b5dbade799c805863fe47b0ece68ee 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/JdbcDatabase.kt @@ -75,9 +75,9 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc throw DbException(e) } // Open the database and create the tables and indexes if necessary - val compact: Boolean - var connection = startTransaction() - try { + var compact = false + transaction(false) { txn -> + val connection = txn.unbox() compact = if (reopen) { val s: Settings = getSettings(connection, DB_SETTINGS_NAMESPACE) wasDirtyOnInitialisation = isDirty(s) @@ -92,10 +92,6 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc LOG.info("db dirty? $wasDirtyOnInitialisation") } createIndexes(connection) - commitTransaction(connection) - } catch (e: DbException) { - abortTransaction(connection) - throw e } // Compact the database if necessary if (compact) { @@ -105,13 +101,8 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc logDuration(LOG, { "Compacting database" }, start) // Allow the next transaction to reopen the DB synchronized(connectionsLock) { closed = false } - connection = startTransaction() - try { - storeLastCompacted(connection) - commitTransaction(connection) - } catch (e: DbException) { - abortTransaction(connection) - throw e + transaction(false) { txn -> + storeLastCompacted(txn.unbox()) } } } @@ -169,7 +160,15 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc @Throws(DbException::class) protected abstract fun compactAndClose() - override fun startTransaction(readOnly: Boolean): Transaction { + /** + * Starts a new transaction and returns an object representing it. + * + * This method acquires locks, so it must not be called while holding a + * lock. + * + * @param readOnly true if the transaction will only be used for reading. + */ + private fun startTransaction(readOnly: Boolean): Transaction { // Don't allow reentrant locking check(lock.readHoldCount <= 0) check(lock.writeHoldCount <= 0) @@ -506,15 +505,24 @@ abstract class JdbcDatabase(private val dbTypes: DatabaseTypes, private val cloc } } + /** + * Commits a transaction to the database. + */ @Throws(DbException::class) - override fun commitTransaction(txn: Transaction) { + private fun commitTransaction(txn: Transaction) { val connection: Connection = txn.unbox() as Connection check(!txn.isCommitted) txn.setCommitted() commitTransaction(connection) } - override fun endTransaction(txn: Transaction) { + /** + * Ends a transaction. If the transaction has not been committed, + * it will be aborted. If the transaction has been committed, + * any events attached to the transaction are broadcast. + * The database lock will be released in either case. + */ + private fun endTransaction(txn: Transaction) { try { val connection: Connection = txn.unbox() as Connection if (!txn.isCommitted) { diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Transaction.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Transaction.kt index 92283126e53e29202a449149277333dc9cf05708..81176661a8f34e4d72cc40f9c5860be56ba19748 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Transaction.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/Transaction.kt @@ -1,7 +1,9 @@ package org.briarproject.mailbox.core.db +import java.sql.Connection + class Transaction( - private val txn: Any, + private val txn: Connection, /** * Returns true if the transaction can only be used for reading. */ @@ -18,7 +20,7 @@ class Transaction( * Returns the database transaction. The type of the returned object * depends on the database implementation. */ - fun unbox(): Any { + fun unbox(): Connection { return txn } diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/TransactionManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/TransactionManager.kt index 8df28a720248df553d05347794e23b81e1c9b219..d663509b2d682e9d163075dd35ea438eb21f3ac8 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/TransactionManager.kt +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/db/TransactionManager.kt @@ -1,31 +1,6 @@ package org.briarproject.mailbox.core.db interface TransactionManager { - /** - * Starts a new transaction and returns an object representing it. - * - * - * This method acquires locks, so it must not be called while holding a - * lock. - * - * @param readOnly true if the transaction will only be used for reading. - */ - @Throws(DbException::class) - fun startTransaction(readOnly: Boolean): Transaction - - /** - * Commits a transaction to the database. - */ - @Throws(DbException::class) - fun commitTransaction(txn: Transaction) - - /** - * Ends a transaction. If the transaction has not been committed, - * it will be aborted. If the transaction has been committed, - * any events attached to the transaction are broadcast. - * The database lock will be released in either case. - */ - fun endTransaction(txn: Transaction) /** * Runs the given task within a transaction. diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java index 84c09ac354c59fd435a8ab289193340f96204bb6..2e8aa3ee71e0895b2cc056f5935972850c7482d0 100644 --- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java +++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/lifecycle/LifecycleManager.java @@ -29,9 +29,13 @@ public interface LifecycleManager { */ enum LifecycleState { - STOPPED, STARTING, MIGRATING_DATABASE, COMPACTING_DATABASE, + STOPPED, + STARTING, + MIGRATING_DATABASE, + COMPACTING_DATABASE, STARTING_SERVICES, - RUNNING, STOPPING; + RUNNING, + STOPPING; public boolean isAfter(LifecycleState state) { return ordinal() > state.ordinal(); diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt index 9fe113ef34c253b321bdcb949069c603467750e9..b711dcb000d1a6138ed7bf1cd3609a2963131d9c 100644 --- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt +++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/db/JdbcDatabaseTest.kt @@ -36,9 +36,6 @@ abstract class JdbcDatabaseTest { @Throws(Exception::class) open fun testPersistence() { // Store some records - var db: Database = open(false) - var txn = db.startTransaction(false) - val contact1 = Contact( 1, "4291ad1d-897d-4db4-9de9-ea3f78c5262e", @@ -51,37 +48,35 @@ abstract class JdbcDatabaseTest { "7931fa7a-077e-403a-8487-63261027d6d2", "12a61ca3-af0a-41d1-acc1-a0f4625f6e42" ) + var db: Database = open(false) + db.transaction(false) { txn -> - db.addContact(txn, contact1) - db.addContact(txn, contact2) - - db.commitTransaction(txn) + db.addContact(txn, contact1) + db.addContact(txn, contact2) + } db.close() // Check that the records are still there db = open(true) - txn = db.startTransaction(false) - val contact1Reloaded1 = db.getContact(txn, 1) - val contact2Reloaded1 = db.getContact(txn, 2) - assertEquals(contact1, contact1Reloaded1) - assertEquals(contact2, contact2Reloaded1) - - // Delete one of the records - db.removeContact(txn, 1) - - db.commitTransaction(txn) + db.transaction(false) { txn -> + val contact1Reloaded1 = db.getContact(txn, 1) + val contact2Reloaded1 = db.getContact(txn, 2) + assertEquals(contact1, contact1Reloaded1) + assertEquals(contact2, contact2Reloaded1) + + // Delete one of the records + db.removeContact(txn, 1) + } db.close() // Check that the record is gone db = open(true) - txn = db.startTransaction(true) - - val contact1Reloaded2 = db.getContact(txn, 1) - val contact2Reloaded2 = db.getContact(txn, 2) - assertNull(contact1Reloaded2) - assertEquals(contact2, contact2Reloaded2) - - db.commitTransaction(txn) + db.transaction(true) { txn -> + val contact1Reloaded2 = db.getContact(txn, 1) + val contact2Reloaded2 = db.getContact(txn, 2) + assertNull(contact1Reloaded2) + assertEquals(contact2, contact2Reloaded2) + } db.close() } @@ -98,17 +93,15 @@ abstract class JdbcDatabaseTest { merged["baz"] = "qux" var db: Database = open(false) - var txn = db.startTransaction(false) - - // store 'before' - db.mergeSettings(txn, before, "namespace") - assertEquals(before, db.getSettings(txn, "namespace")) - - // merge 'update' - db.mergeSettings(txn, update, "namespace") - assertEquals(merged, db.getSettings(txn, "namespace")) - - db.commitTransaction(txn) + var txn = db.transaction(false) { txn -> + // store 'before' + db.mergeSettings(txn, before, "namespace") + assertEquals(before, db.getSettings(txn, "namespace")) + + // merge 'update' + db.mergeSettings(txn, update, "namespace") + assertEquals(merged, db.getSettings(txn, "namespace")) + } db.close() }