From eb360475aa309618fddc71d650859187463e5853 Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Fri, 7 Sep 2012 16:58:03 +0100 Subject: [PATCH] KeyRotatorImpl looks a *lot* like DatabaseCleanerImpl. --- .../net/sf/briar/db/DatabaseCleaner.java | 6 +-- .../net/sf/briar/db/DatabaseCleanerImpl.java | 6 +-- .../sf/briar/db/DatabaseComponentImpl.java | 3 +- .../net/sf/briar/db/DatabaseConstants.java | 2 +- components/net/sf/briar/db/KeyRotator.java | 24 +++++++++ .../net/sf/briar/db/KeyRotatorImpl.java | 41 ++++++++++++++ test/net/sf/briar/db/KeyRotatorImplTest.java | 53 +++++++++++++++++++ 7 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 components/net/sf/briar/db/KeyRotator.java create mode 100644 components/net/sf/briar/db/KeyRotatorImpl.java create mode 100644 test/net/sf/briar/db/KeyRotatorImplTest.java diff --git a/components/net/sf/briar/db/DatabaseCleaner.java b/components/net/sf/briar/db/DatabaseCleaner.java index 32ecfe316d..639c92d4e3 100644 --- a/components/net/sf/briar/db/DatabaseCleaner.java +++ b/components/net/sf/briar/db/DatabaseCleaner.java @@ -19,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 - * 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. + * DatabaseConstants.MIN_FREE_SPACE. If the free space is less than + * DatabaseConstants.CRITICAL_FREE_SPACE and there are no more messages + * to expire, an Error will be thrown. */ void checkFreeSpaceAndClean() throws DbException; diff --git a/components/net/sf/briar/db/DatabaseCleanerImpl.java b/components/net/sf/briar/db/DatabaseCleanerImpl.java index 71574267ed..71322acf82 100644 --- a/components/net/sf/briar/db/DatabaseCleanerImpl.java +++ b/components/net/sf/briar/db/DatabaseCleanerImpl.java @@ -33,12 +33,10 @@ class DatabaseCleanerImpl extends TimerTask implements DatabaseCleaner { callback.checkFreeSpaceAndClean(); } } catch(DbException e) { - if(LOG.isLoggable(Level.WARNING)) - LOG.warning(e.toString()); + if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); throw new Error(e); // Kill the application } catch(RuntimeException e) { - if(LOG.isLoggable(Level.WARNING)) - LOG.warning(e.toString()); + if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); throw new Error(e); // Kill the application } } diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index 408d415095..ebe17a3097 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -1548,8 +1548,7 @@ DatabaseCleaner.Callback { if(freeSpace < CRITICAL_FREE_SPACE && !expired) { // FIXME: Work out what to do here - the amount of free space // is critically low and there are no messages left to expire - System.err.println("Disk space is critical - shutting down"); - System.exit(1); + throw new Error("Disk space is critical"); } Thread.yield(); freeSpace = db.getFreeSpace(); diff --git a/components/net/sf/briar/db/DatabaseConstants.java b/components/net/sf/briar/db/DatabaseConstants.java index fa013a562d..d177b8c089 100644 --- a/components/net/sf/briar/db/DatabaseConstants.java +++ b/components/net/sf/briar/db/DatabaseConstants.java @@ -14,7 +14,7 @@ interface DatabaseConstants { /** * The minimum amount of space in bytes that must be kept free on the device * where the database is stored. If less than this much space is free and - * there are no more messages to expire, the program will shut down. + * there are no more messages to expire, an Error will be thrown. */ static final long CRITICAL_FREE_SPACE = 100 * 1024 * 1024; // 100 MiB diff --git a/components/net/sf/briar/db/KeyRotator.java b/components/net/sf/briar/db/KeyRotator.java new file mode 100644 index 0000000000..200a1ed24f --- /dev/null +++ b/components/net/sf/briar/db/KeyRotator.java @@ -0,0 +1,24 @@ +package net.sf.briar.db; + +import net.sf.briar.api.db.DbException; + +interface KeyRotator { + + /** + * Starts a new thread to rotate keys periodically. The rotator will pause + * for the given number of milliseconds between rotations. + */ + void startRotating(Callback callback, long msBetweenRotations); + + /** Tells the rotator thread to exit. */ + void stopRotating(); + + interface Callback { + + /** + * Rotates keys, replacing and destroying any keys that have passed the + * ends of their respective retention periods. + */ + void rotateKeys() throws DbException; + } +} diff --git a/components/net/sf/briar/db/KeyRotatorImpl.java b/components/net/sf/briar/db/KeyRotatorImpl.java new file mode 100644 index 0000000000..26db0228b3 --- /dev/null +++ b/components/net/sf/briar/db/KeyRotatorImpl.java @@ -0,0 +1,41 @@ +package net.sf.briar.db; + +import java.util.Timer; +import java.util.TimerTask; +import java.util.logging.Level; +import java.util.logging.Logger; + +import net.sf.briar.api.db.DbException; + +class KeyRotatorImpl extends TimerTask implements KeyRotator { + + private static final Logger LOG = + Logger.getLogger(KeyRotatorImpl.class.getName()); + + private volatile Callback callback = null; + private volatile Timer timer = null; + + public void startRotating(Callback callback, long msBetweenRotations) { + this.callback = callback; + timer = new Timer(); + timer.scheduleAtFixedRate(this, 0L, msBetweenRotations); + } + + public void stopRotating() { + if(timer == null) throw new IllegalStateException(); + timer.cancel(); + } + + public void run() { + if(callback == null) throw new IllegalStateException(); + try { + callback.rotateKeys(); + } catch(DbException e) { + if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); + throw new Error(e); // Kill the application + } catch(RuntimeException e) { + if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString()); + throw new Error(e); // Kill the application + } + } +} diff --git a/test/net/sf/briar/db/KeyRotatorImplTest.java b/test/net/sf/briar/db/KeyRotatorImplTest.java new file mode 100644 index 0000000000..2470e534e6 --- /dev/null +++ b/test/net/sf/briar/db/KeyRotatorImplTest.java @@ -0,0 +1,53 @@ +package net.sf.briar.db; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import net.sf.briar.BriarTestCase; +import net.sf.briar.api.db.DbException; +import net.sf.briar.db.KeyRotator.Callback; + +import org.junit.Test; + +public class KeyRotatorImplTest extends BriarTestCase { + + @Test + public void testCleanerRunsPeriodically() throws Exception { + final CountDownLatch latch = new CountDownLatch(5); + Callback callback = new Callback() { + + public void rotateKeys() throws DbException { + latch.countDown(); + } + }; + KeyRotatorImpl cleaner = new KeyRotatorImpl(); + // Start the rotator + cleaner.startRotating(callback, 10L); + // The keys should be rotated five times (allow 5 secs for system load) + assertTrue(latch.await(5, TimeUnit.SECONDS)); + // Stop the rotator + cleaner.stopRotating(); + } + + @Test + public void testStoppingCleanerWakesItUp() throws Exception { + final CountDownLatch latch = new CountDownLatch(1); + Callback callback = new Callback() { + + public void rotateKeys() throws DbException { + latch.countDown(); + } + }; + KeyRotatorImpl cleaner = new KeyRotatorImpl(); + long start = System.currentTimeMillis(); + // Start the rotator + cleaner.startRotating(callback, 10L * 1000L); + // The keys should be rotated once at startup + assertTrue(latch.await(5, TimeUnit.SECONDS)); + // Stop the rotator (it should be waiting between rotations) + cleaner.stopRotating(); + long end = System.currentTimeMillis(); + // Check that much less than 10 seconds expired + assertTrue(end - start < 10L * 1000L); + } +} -- GitLab