diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
index 0e51240b20753856455beee07dd86036c881736a..8f65c0d4874e1e31134406a959be45863d049ce5 100644
--- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
+++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
@@ -28,6 +28,10 @@ import java.util.Map;
 /**
  * Encapsulates the database implementation and exposes high-level operations
  * to other components.
+ * <p>
+ * This interface's methods are blocking, but they do not call out into other
+ * components except to broadcast {@link org.briarproject.api.event.Event
+ * Events}, so they can safely be called while holding locks.
  */
 public interface DatabaseComponent {
 
diff --git a/briar-api/src/org/briarproject/api/event/EventListener.java b/briar-api/src/org/briarproject/api/event/EventListener.java
index 8ab59aa04ba33559475784b2a96606b2ce2e912f..89598d79e1e4bbdccf702da3edc35feed070acb5 100644
--- a/briar-api/src/org/briarproject/api/event/EventListener.java
+++ b/briar-api/src/org/briarproject/api/event/EventListener.java
@@ -3,5 +3,9 @@ package org.briarproject.api.event;
 /** An interface for receiving notifications when events occur. */
 public interface EventListener {
 
+	/**
+	 * Called when an event is broadcast. Implementations of this method must
+	 * not block.
+	 */
 	void eventOccurred(Event e);
 }
diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
index 9c99e2819c3b3cfbc5773e0a9041cfd69db21c79..b1fa018fc63caae5a1bee6bcf0a2a04fb154c947 100644
--- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
+++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
@@ -101,7 +101,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
 		dbExecutor.execute(new Runnable() {
 			public void run() {
 				TransportKeyManager m = new TransportKeyManager(db, crypto,
-						dbExecutor, timer, clock, t, maxLatency);
+						timer, clock, t, maxLatency);
 				// Don't add transport twice if event is received during startup
 				if (managers.putIfAbsent(t, m) == null) m.start();
 			}
diff --git a/briar-core/src/org/briarproject/transport/TransportKeyManager.java b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
index 7fd3c42bfcb1a77a27d7117a04c4a409d0e13917..2df96ccc71dc88fb2d19e8d4ea1574d740286588 100644
--- a/briar-core/src/org/briarproject/transport/TransportKeyManager.java
+++ b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
@@ -18,10 +18,6 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.TimerTask;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.logging.Logger;
 
@@ -37,7 +33,6 @@ class TransportKeyManager extends TimerTask {
 
 	private final DatabaseComponent db;
 	private final CryptoComponent crypto;
-	private final ExecutorService dbExecutor;
 	private final Timer timer;
 	private final Clock clock;
 	private final TransportId transportId;
@@ -50,11 +45,10 @@ class TransportKeyManager extends TimerTask {
 	private final Map<ContactId, MutableTransportKeys> keys;
 
 	TransportKeyManager(DatabaseComponent db, CryptoComponent crypto,
-			ExecutorService dbExecutor, Timer timer, Clock clock,
-			TransportId transportId, long maxLatency) {
+			Timer timer, Clock clock, TransportId transportId,
+			long maxLatency) {
 		this.db = db;
 		this.crypto = crypto;
-		this.dbExecutor = dbExecutor;
 		this.timer = timer;
 		this.clock = clock;
 		this.transportId = transportId;
@@ -66,36 +60,39 @@ class TransportKeyManager extends TimerTask {
 	}
 
 	void start() {
-		// Load the transport keys from the DB
-		Map<ContactId, TransportKeys> loaded;
-		try {
-			loaded = db.getTransportKeys(transportId);
-		} catch (DbException e) {
-			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
-			return;
-		}
-		// Rotate the keys to the current rotation period
-		Map<ContactId, TransportKeys> rotated =
-				new HashMap<ContactId, TransportKeys>();
-		Map<ContactId, TransportKeys> current =
-				new HashMap<ContactId, TransportKeys>();
 		long now = clock.currentTimeMillis();
-		long rotationPeriod = now / rotationPeriodLength;
-		for (Entry<ContactId, TransportKeys> e : loaded.entrySet()) {
-			ContactId c = e.getKey();
-			TransportKeys k = e.getValue();
-			TransportKeys k1 = crypto.rotateTransportKeys(k, rotationPeriod);
-			if (k1.getRotationPeriod() > k.getRotationPeriod())
-				rotated.put(c, k1);
-			current.put(c, k1);
-		}
 		lock.lock();
 		try {
+			// Load the transport keys from the DB
+			Map<ContactId, TransportKeys> loaded;
+			try {
+				loaded = db.getTransportKeys(transportId);
+			} catch (DbException e) {
+				if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+				return;
+			}
+			// Rotate the keys to the current rotation period
+			Map<ContactId, TransportKeys> rotated =
+					new HashMap<ContactId, TransportKeys>();
+			Map<ContactId, TransportKeys> current =
+					new HashMap<ContactId, TransportKeys>();
+			long rotationPeriod = now / rotationPeriodLength;
+			for (Entry<ContactId, TransportKeys> e : loaded.entrySet()) {
+				ContactId c = e.getKey();
+				TransportKeys k = e.getValue();
+				TransportKeys k1 = crypto.rotateTransportKeys(k,
+						rotationPeriod);
+				if (k1.getRotationPeriod() > k.getRotationPeriod())
+					rotated.put(c, k1);
+				current.put(c, k1);
+			}
 			// Initialise mutable state for all contacts
 			for (Entry<ContactId, TransportKeys> e : current.entrySet())
 				addKeys(e.getKey(), new MutableTransportKeys(e.getValue()));
 			// Write any rotated keys back to the DB
-			saveTransportKeys(rotated);
+			db.updateTransportKeys(rotated);
+		} catch (DbException e) {
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 		} finally {
 			lock.unlock();
 		}
@@ -123,54 +120,29 @@ class TransportKeyManager extends TimerTask {
 		}
 	}
 
-	private void saveTransportKeys(
-			final Map<ContactId, TransportKeys> rotated) {
-		dbExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					db.updateTransportKeys(rotated);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
-
 	void addContact(ContactId c, SecretKey master, long timestamp,
 			boolean alice) {
-		// Work out what rotation period the timestamp belongs to
-		long rotationPeriod = timestamp / rotationPeriodLength;
-		// Derive the transport keys
-		TransportKeys k = crypto.deriveTransportKeys(transportId, master,
-				rotationPeriod, alice);
-		// Rotate the keys to the current rotation period if necessary
-		rotationPeriod = clock.currentTimeMillis() / rotationPeriodLength;
-		k = crypto.rotateTransportKeys(k, rotationPeriod);
 		lock.lock();
 		try {
+			// Work out what rotation period the timestamp belongs to
+			long rotationPeriod = timestamp / rotationPeriodLength;
+			// Derive the transport keys
+			TransportKeys k = crypto.deriveTransportKeys(transportId, master,
+					rotationPeriod, alice);
+			// Rotate the keys to the current rotation period if necessary
+			rotationPeriod = clock.currentTimeMillis() / rotationPeriodLength;
+			k = crypto.rotateTransportKeys(k, rotationPeriod);
 			// Initialise mutable state for the contact
 			addKeys(c, new MutableTransportKeys(k));
 			// Write the keys back to the DB
-			saveTransportKeys(c, k);
+			db.addTransportKeys(c, k);
+		} catch (DbException e) {
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 		} finally {
 			lock.unlock();
 		}
 	}
 
-	private void saveTransportKeys(final ContactId c, final TransportKeys k) {
-		dbExecutor.execute(new Runnable() {
-			public void run() {
-				try {
-					db.addTransportKeys(c, k);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-			}
-		});
-	}
-
 	void removeContact(ContactId c) {
 		lock.lock();
 		try {
@@ -187,8 +159,6 @@ class TransportKeyManager extends TimerTask {
 	}
 
 	StreamContext getStreamContext(ContactId c) {
-		StreamContext ctx;
-		Future<Void> saved;
 		lock.lock();
 		try {
 			// Look up the outgoing keys for the contact
@@ -196,48 +166,23 @@ class TransportKeyManager extends TimerTask {
 			if (outKeys == null) return null;
 			if (outKeys.getStreamCounter() > MAX_32_BIT_UNSIGNED) return null;
 			// Create a stream context
-			ctx = new StreamContext(c, transportId, outKeys.getTagKey(),
-					outKeys.getHeaderKey(), outKeys.getStreamCounter());
+			StreamContext ctx = new StreamContext(c, transportId,
+					outKeys.getTagKey(), outKeys.getHeaderKey(),
+					outKeys.getStreamCounter());
 			// Increment the stream counter and write it back to the DB
 			outKeys.incrementStreamCounter();
-			saved = saveIncrementedStreamCounter(c,
+			db.incrementStreamCounter(c, transportId,
 					outKeys.getRotationPeriod());
+			return ctx;
+		} catch (DbException e) {
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+			return null;
 		} finally {
 			lock.unlock();
 		}
-		// Wait for the save to complete before returning the stream context
-		try {
-			saved.get();
-		} catch (InterruptedException e) {
-			LOG.warning("Interrupted while incrementing stream counter");
-			Thread.currentThread().interrupt();
-			return null;
-		} catch (ExecutionException e) {
-			if (LOG.isLoggable(WARNING))
-				LOG.log(WARNING, e.toString(), e);
-			return null;
-		}
-		return ctx;
-	}
-
-	private Future<Void> saveIncrementedStreamCounter(final ContactId c,
-			final long rotationPeriod) {
-		return dbExecutor.submit(new Callable<Void>() {
-			public Void call() {
-				try {
-					db.incrementStreamCounter(c, transportId, rotationPeriod);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-				return null;
-			}
-		});
 	}
 
 	StreamContext recogniseTag(byte[] tag) {
-		StreamContext ctx;
-		Future<Void> saved;
 		lock.lock();
 		try {
 			// Look up the incoming keys for the tag
@@ -245,7 +190,7 @@ class TransportKeyManager extends TimerTask {
 			if (tagCtx == null) return null;
 			MutableIncomingKeys inKeys = tagCtx.inKeys;
 			// Create a stream context
-			ctx = new StreamContext(tagCtx.contactId, transportId,
+			StreamContext ctx = new StreamContext(tagCtx.contactId, transportId,
 					inKeys.getTagKey(), inKeys.getHeaderKey(),
 					tagCtx.streamNumber);
 			// Update the reordering window
@@ -265,45 +210,21 @@ class TransportKeyManager extends TimerTask {
 				inContexts.remove(new Bytes(removeTag));
 			}
 			// Write the window back to the DB
-			saved = saveReorderingWindow(tagCtx.contactId,
+			db.setReorderingWindow(tagCtx.contactId, transportId,
 					inKeys.getRotationPeriod(), window.getBase(),
 					window.getBitmap());
+			return ctx;
+		} catch (DbException e) {
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+			return null;
 		} finally {
 			lock.unlock();
 		}
-		// Wait for the save to complete before returning the stream context
-		try {
-			saved.get();
-		} catch (InterruptedException e) {
-			LOG.warning("Interrupted while updating reordering window");
-			Thread.currentThread().interrupt();
-			return null;
-		} catch (ExecutionException e) {
-			if (LOG.isLoggable(WARNING))
-				LOG.log(WARNING, e.toString(), e);
-			return null;
-		}
-		return ctx;
-	}
-
-	private Future<Void> saveReorderingWindow(final ContactId c,
-			final long rotationPeriod, final long base, final byte[] bitmap) {
-		return dbExecutor.submit(new Callable<Void>() {
-			public Void call() {
-				try {
-					db.setReorderingWindow(c, transportId, rotationPeriod,
-							base, bitmap);
-				} catch (DbException e) {
-					if (LOG.isLoggable(WARNING))
-						LOG.log(WARNING, e.toString(), e);
-				}
-				return null;
-			}
-		});
 	}
 
 	@Override
 	public void run() {
+		long now = clock.currentTimeMillis();
 		lock.lock();
 		try {
 			// Rotate the keys to the current rotation period
@@ -311,7 +232,6 @@ class TransportKeyManager extends TimerTask {
 					new HashMap<ContactId, TransportKeys>();
 			Map<ContactId, TransportKeys> current =
 					new HashMap<ContactId, TransportKeys>();
-			long now = clock.currentTimeMillis();
 			long rotationPeriod = now / rotationPeriodLength;
 			for (Entry<ContactId, MutableTransportKeys> e : keys.entrySet()) {
 				ContactId c = e.getKey();
@@ -329,12 +249,13 @@ class TransportKeyManager extends TimerTask {
 			for (Entry<ContactId, TransportKeys> e : current.entrySet())
 				addKeys(e.getKey(), new MutableTransportKeys(e.getValue()));
 			// Write any rotated keys back to the DB
-			saveTransportKeys(rotated);
+			db.updateTransportKeys(rotated);
+		} catch (DbException e) {
+			if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 		} finally {
 			lock.unlock();
 		}
 		// Schedule the next key rotation
-		long now = clock.currentTimeMillis();
 		long delay = rotationPeriodLength - now % rotationPeriodLength;
 		timer.schedule(this, delay);
 	}