From 36fc34993ddeb5e2d744e9ef17453a66beb4410b Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Sat, 13 Aug 2011 15:39:09 +0200
Subject: [PATCH] Lock fairness test: check that fair ReentrantReadWriteLocks
 don't allow writers to starve. If this test passes on Java 5 and 6, we can
 get rid of SynchronizedDatabaseComponent and merge
 ReadWriteLockDatabaseComponent with DatabaseComponentImpl.

---
 test/build.xml                          |  1 +
 test/net/sf/briar/LockFairnessTest.java | 81 +++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 test/net/sf/briar/LockFairnessTest.java

diff --git a/test/build.xml b/test/build.xml
index 1036f8f05f..67ff69ddcb 100644
--- a/test/build.xml
+++ b/test/build.xml
@@ -14,6 +14,7 @@
 				<path refid='util-classes'/>
 			</classpath>
 			<test name='net.sf.briar.FileReadWriteTest'/>
+			<test name='net.sf.briar.LockFairnessTest'/>
 			<test name='net.sf.briar.crypto.CounterModeTest'/>
 			<test name='net.sf.briar.db.BasicH2Test'/>
 			<test name='net.sf.briar.db.DatabaseCleanerImplTest'/>
diff --git a/test/net/sf/briar/LockFairnessTest.java b/test/net/sf/briar/LockFairnessTest.java
new file mode 100644
index 0000000000..57a6daed16
--- /dev/null
+++ b/test/net/sf/briar/LockFairnessTest.java
@@ -0,0 +1,81 @@
+package net.sf.briar;
+
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import junit.framework.TestCase;
+
+import org.junit.Test;
+
+public class LockFairnessTest extends TestCase {
+
+	@Test
+	public void testWritersDoNotStarevWithFairLocks() throws Exception {
+		// Create a fair fair read-write lock
+		ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);
+		// Create a ton of reader threads that repeatedly acquire the read lock,
+		// sleep for a few ms and release the lock
+		Thread[] readers = new Thread[20];
+		for(int i = 0; i < readers.length; i++) {
+			readers[i] = new ReaderThread(lock);
+		}
+		// Stagger the start times of the readers so they release the read lock
+		// at different times
+		for(int i = 0; i < readers.length; i++) {
+			readers[i].start();
+			Thread.sleep(7);
+		}
+		// Create a writer thread, which should be able to acquire the lock
+		WriterThread writer = new WriterThread(lock);
+		writer.start();
+		Thread.sleep(1000);
+		// The writer should have acquired the lock
+		assertTrue(writer.acquiredLock);
+		// Stop the readers
+		for(int i = 0; i < readers.length; i++) readers[i].interrupt();
+	}
+
+	private static class ReaderThread extends Thread {
+
+		private final ReentrantReadWriteLock lock;
+
+		private ReaderThread(ReentrantReadWriteLock lock) {
+			this.lock = lock;
+		}
+
+		@Override
+		public void run() {
+			try {
+				while(true) {
+					lock.readLock().lock();
+					try {
+						Thread.sleep(13);
+					} finally {
+						lock.readLock().unlock();
+					}
+				}
+			} catch(InterruptedException quit) {
+				return;
+			}
+		}
+	}
+
+	private static class WriterThread extends Thread {
+
+		private final ReentrantReadWriteLock lock;
+		private volatile boolean acquiredLock = false;
+
+		private WriterThread(ReentrantReadWriteLock lock) {
+			this.lock = lock;
+		}
+
+		@Override
+		public void run() {
+			lock.writeLock().lock();
+			try {
+				acquiredLock = true;
+			} finally {
+				lock.writeLock().unlock();
+			}
+		}
+	}
+}
-- 
GitLab