diff --git a/api/net/sf/briar/api/db/DatabaseDirectory.java b/api/net/sf/briar/api/db/DatabaseDirectory.java new file mode 100644 index 0000000000000000000000000000000000000000..ed5fcdc0ec0b1653c0384619735bef04935323ca --- /dev/null +++ b/api/net/sf/briar/api/db/DatabaseDirectory.java @@ -0,0 +1,15 @@ +package net.sf.briar.api.db; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +/** Annotation for injecting the directory where the database is stored. */ +@BindingAnnotation +@Target({ PARAMETER }) +@Retention(RUNTIME) +public @interface DatabaseDirectory {} diff --git a/api/net/sf/briar/api/db/DatabaseMaxSize.java b/api/net/sf/briar/api/db/DatabaseMaxSize.java new file mode 100644 index 0000000000000000000000000000000000000000..ec1a2fbae52f9da11edd834ed2bb1e9d92cfdb8d --- /dev/null +++ b/api/net/sf/briar/api/db/DatabaseMaxSize.java @@ -0,0 +1,15 @@ +package net.sf.briar.api.db; + +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import com.google.inject.BindingAnnotation; + +/** Annotation for injecting the maximum size in bytes of the database. */ +@BindingAnnotation +@Target({ PARAMETER }) +@Retention(RUNTIME) +public @interface DatabaseMaxSize {} diff --git a/components/net/sf/briar/db/DatabaseCleaner.java b/components/net/sf/briar/db/DatabaseCleaner.java index 635bc047f49bd447f2e7e5966977bd185acda8c5..25987e0d22a2de0ccd10e488fd6e4b595258dafb 100644 --- a/components/net/sf/briar/db/DatabaseCleaner.java +++ b/components/net/sf/briar/db/DatabaseCleaner.java @@ -6,9 +6,10 @@ interface DatabaseCleaner { /** * Starts a new thread to monitor the amount of free storage space - * available to the database and expire old messages as necessary. + * available to the database and expire old messages as necessary. The + * cleaner will pause for the given number of milliseconds between sweeps. */ - void startCleaning(); + void startCleaning(Callback callback, long msBetweenSweeps); /** Tells the cleaner thread to exit and returns when it has done so. */ void stopCleaning(); @@ -18,9 +19,9 @@ interface DatabaseCleaner { /** * Checks how much free storage space is available to the database, and * if necessary expires old messages until the free space is at least - * MIN_FREE_SPACE. While the free space is less than - * CRITICAL_FREE_SPACE, operations that attempt to store messages in - * the database will block. + * DatabaseConstants.MIN_FREE_SPACE. While the free space is less than + * DatabaseConstants.CRITICAL_FREE_SPACE, operations that attempt to + * store messages in the database will block. */ void checkFreeSpaceAndClean() throws DbException; diff --git a/components/net/sf/briar/db/DatabaseCleanerImpl.java b/components/net/sf/briar/db/DatabaseCleanerImpl.java index bd9dfc7f591c1ce81e2b478530be72ea86e3289a..6cf560738c28adf0a52f75160e7cb36d0299f5bd 100644 --- a/components/net/sf/briar/db/DatabaseCleanerImpl.java +++ b/components/net/sf/briar/db/DatabaseCleanerImpl.java @@ -2,22 +2,17 @@ package net.sf.briar.db; import java.util.concurrent.atomic.AtomicBoolean; -import com.google.inject.Inject; - class DatabaseCleanerImpl implements DatabaseCleaner, Runnable { - private final Callback db; - private final int msBetweenSweeps; private final AtomicBoolean stopped = new AtomicBoolean(false); private final Thread cleanerThread = new Thread(this); - @Inject - DatabaseCleanerImpl(Callback db, int msBetweenSweeps) { - this.db = db; - this.msBetweenSweeps = msBetweenSweeps; - } + private volatile Callback callback; + private volatile long msBetweenSweeps; - public void startCleaning() { + public void startCleaning(Callback callback, long msBetweenSweeps) { + this.callback = callback; + this.msBetweenSweeps = msBetweenSweeps; cleanerThread.start(); } @@ -35,8 +30,8 @@ class DatabaseCleanerImpl implements DatabaseCleaner, Runnable { public void run() { try { while(!stopped.get()) { - if(db.shouldCheckFreeSpace()) { - db.checkFreeSpaceAndClean(); + if(callback.shouldCheckFreeSpace()) { + callback.checkFreeSpaceAndClean(); } else { synchronized(stopped) { try { diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index c43c778a2ace0c9f9cf227d51c00d9201ae5ff7f..4f269012fbf667d5ec1f870831a666df4eba83e0 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -99,7 +99,7 @@ DatabaseCleaner.Callback { public void open(boolean resume) throws DbException { db.open(resume); - cleaner.startCleaning(); + cleaner.startCleaning(this, MAX_MS_BETWEEN_SPACE_CHECKS); } public void close() throws DbException { diff --git a/components/net/sf/briar/db/DatabaseConstants.java b/components/net/sf/briar/db/DatabaseConstants.java index 54b4feebc7aa4f511999c7c58b93946f897c0a93..e2c29910626cd6aa33bafec934e37168fd01a5c9 100644 --- a/components/net/sf/briar/db/DatabaseConstants.java +++ b/components/net/sf/briar/db/DatabaseConstants.java @@ -2,13 +2,15 @@ package net.sf.briar.db; interface DatabaseConstants { - static final int MEGABYTE = 1024 * 1024; - // FIXME: These should be configurable - static final long MIN_FREE_SPACE = 300L * MEGABYTE; - static final long CRITICAL_FREE_SPACE = 100L * MEGABYTE; - static final int MAX_BYTES_BETWEEN_SPACE_CHECKS = 5 * MEGABYTE; + static final long MIN_FREE_SPACE = 300 * 1024 * 1024; // 300 MiB + static final long CRITICAL_FREE_SPACE = 100 * 1024 * 1024; // 100 MiB + + static final int MAX_BYTES_BETWEEN_SPACE_CHECKS = 5 * 1024 * 1024; // 5 MiB static final long MAX_MS_BETWEEN_SPACE_CHECKS = 60L * 1000L; // 1 min - static final int BYTES_PER_SWEEP = 5 * MEGABYTE; + + static final long MS_PER_SWEEP = 10L * 1000L; // 10 sec + static final int BYTES_PER_SWEEP = 5 * 1024 * 1024; // 5 MiB + static final long EXPIRY_MODULUS = 60L * 60L * 1000L; // 1 hour } diff --git a/components/net/sf/briar/db/DatabaseModule.java b/components/net/sf/briar/db/DatabaseModule.java index 218b768438c5b81093f65fc1110a691b374f412b..903fb43458772d61ca785b05757753a4412554a0 100644 --- a/components/net/sf/briar/db/DatabaseModule.java +++ b/components/net/sf/briar/db/DatabaseModule.java @@ -1,16 +1,39 @@ package net.sf.briar.db; +import java.io.File; +import java.sql.Connection; + +import net.sf.briar.api.crypto.Password; import net.sf.briar.api.db.DatabaseComponent; +import net.sf.briar.api.db.DatabaseDirectory; +import net.sf.briar.api.db.DatabaseMaxSize; +import net.sf.briar.api.db.DatabasePassword; +import net.sf.briar.api.protocol.GroupFactory; +import net.sf.briar.api.transport.ConnectionWindowFactory; import com.google.inject.AbstractModule; +import com.google.inject.Provides; import com.google.inject.Singleton; public class DatabaseModule extends AbstractModule { @Override protected void configure() { - bind(Database.class).to(H2Database.class); - bind(DatabaseComponent.class).to(DatabaseComponentImpl.class).in( - Singleton.class); + bind(DatabaseCleaner.class).to(DatabaseCleanerImpl.class); + } + + @Provides + Database<Connection> getDatabase(@DatabaseDirectory File dir, + @DatabasePassword Password password, @DatabaseMaxSize long maxSize, + ConnectionWindowFactory connectionWindowFactory, + GroupFactory groupFactory) { + return new H2Database(dir, password, maxSize, connectionWindowFactory, + groupFactory); + } + + @Provides @Singleton + DatabaseComponent getDatabaseComponent(Database<Connection> db, + DatabaseCleaner cleaner) { + return new DatabaseComponentImpl<Connection>(db, cleaner); } } diff --git a/components/net/sf/briar/db/H2Database.java b/components/net/sf/briar/db/H2Database.java index 6a1548f75345da8b6853f0b81faf98cc8bf4e766..9bfcb69ebf1d7967ac8091df80015fcf4499e32b 100644 --- a/components/net/sf/briar/db/H2Database.java +++ b/components/net/sf/briar/db/H2Database.java @@ -11,6 +11,8 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.sf.briar.api.crypto.Password; +import net.sf.briar.api.db.DatabaseDirectory; +import net.sf.briar.api.db.DatabaseMaxSize; import net.sf.briar.api.db.DatabasePassword; import net.sf.briar.api.db.DbException; import net.sf.briar.api.protocol.GroupFactory; @@ -32,7 +34,8 @@ class H2Database extends JdbcDatabase { private final long maxSize; @Inject - H2Database(File dir, @DatabasePassword Password password, long maxSize, + H2Database(@DatabaseDirectory File dir, @DatabasePassword Password password, + @DatabaseMaxSize long maxSize, ConnectionWindowFactory connectionWindowFactory, GroupFactory groupFactory) { super(connectionWindowFactory, groupFactory, "BINARY(32)", "BINARY"); diff --git a/test/net/sf/briar/db/DatabaseCleanerImplTest.java b/test/net/sf/briar/db/DatabaseCleanerImplTest.java index 1042338aea4e5afb3cac0dbbfcf5d934545f8b76..0ccf73824273b4293090514266188bc8b9d66a0f 100644 --- a/test/net/sf/briar/db/DatabaseCleanerImplTest.java +++ b/test/net/sf/briar/db/DatabaseCleanerImplTest.java @@ -25,17 +25,15 @@ public class DatabaseCleanerImplTest extends TestCase { return false; } }; - // Configure the cleaner to wait for 30 seconds between sweeps - DatabaseCleanerImpl cleaner = - new DatabaseCleanerImpl(callback, 30 * 1000); + DatabaseCleanerImpl cleaner = new DatabaseCleanerImpl(); long start = System.currentTimeMillis(); // Start the cleaner and check that shouldCheckFreeSpace() is called - cleaner.startCleaning(); + cleaner.startCleaning(callback, 30L * 1000L); assertTrue(latch.await(5, TimeUnit.SECONDS)); // Stop the cleaner (it should be waiting between sweeps) cleaner.stopCleaning(); long end = System.currentTimeMillis(); // Check that much less than 30 seconds expired - assertTrue(end - start < 10 * 1000); + assertTrue(end - start < 10L * 1000L); } } diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index 4ebfe4c726b79b9b1d20fc98c880906eb2b9a332..878b8a05a92e28ad2337f28dc65b44d2b5db9d10 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -96,7 +96,9 @@ public abstract class DatabaseComponentTest extends TestCase { allowing(database).commitTransaction(txn); // open(false) oneOf(database).open(false); - oneOf(cleaner).startCleaning(); + oneOf(cleaner).startCleaning( + with(any(DatabaseCleaner.Callback.class)), + with(any(long.class))); // getRating(authorId) oneOf(database).getRating(txn, authorId); will(returnValue(Rating.UNRATED));