/hg/icedtea-web: CacheLRUWrapper now uses PropertiesFile locking...
jkang at icedtea.classpath.org
jkang at icedtea.classpath.org
Wed Sep 10 14:11:47 UTC 2014
changeset af89bcaa02a2 in /hg/icedtea-web
details: http://icedtea.classpath.org/hg/icedtea-web?cmd=changeset;node=af89bcaa02a2
author: Jie Kang <jkang at redhat.com>
date: Wed Sep 10 09:45:10 2014 -0400
CacheLRUWrapper now uses PropertiesFile locking system. Unit tests added
for CacheLRUWrapper.
2014-09-10 Jie Kang <jkang at redhat.com>
Changed CacheLRUWrapper to use PropertiesFile's provided locking system
Added unit tests for CacheLRUWrapper
* netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java
* tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java
diffstat:
ChangeLog | 7 +
netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java | 62 +--
tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java | 138 +++++++++-
3 files changed, 163 insertions(+), 44 deletions(-)
diffs (327 lines):
diff -r faeb3e209001 -r af89bcaa02a2 ChangeLog
--- a/ChangeLog Wed Sep 10 09:31:36 2014 -0400
+++ b/ChangeLog Wed Sep 10 09:45:10 2014 -0400
@@ -1,3 +1,10 @@
+2014-09-10 Jie Kang <jkang at redhat.com>
+
+ Changed CacheLRUWrapper to use PropertiesFile's provided locking system
+ Added unit tests for CacheLRUWrapper
+ * netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java
+ * tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java
+
2014-09-10 Jie Kang <jkang at redhat.com>
Added unit tests to PropertiesFile.java and refactored existing unit tests
diff -r faeb3e209001 -r af89bcaa02a2 netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java
--- a/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java Wed Sep 10 09:31:36 2014 -0400
+++ b/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java Wed Sep 10 09:45:10 2014 -0400
@@ -40,8 +40,6 @@
import java.io.File;
import java.io.IOException;
-import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -66,11 +64,6 @@
public enum CacheLRUWrapper {
INSTANCE;
- private int lockCount = 0;
-
- /* lock for the file RecentlyUsed */
- private FileLock fl = null;
-
/* location of cache directory */
private final String setCachePath = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR);
String cacheDir = new File(setCachePath != null ? setCachePath : System.getProperty("java.io.tmpdir")).getPath();
@@ -80,9 +73,11 @@
* recently used items. The items are to be kept with key = (current time
* accessed) followed by folder of item. value = path to file.
*/
+
+ public static final String CACHE_INDEX_FILE_NAME = "recently_used";
+
PropertiesFile cacheOrder = new PropertiesFile(
new File(cacheDir + File.separator + CACHE_INDEX_FILE_NAME));
- public static final String CACHE_INDEX_FILE_NAME = "recently_used";
private CacheLRUWrapper() {
File f = cacheOrder.getStoreFile();
@@ -164,8 +159,12 @@
/**
* Write file to disk.
*/
- public synchronized void store() {
- cacheOrder.store();
+ public synchronized boolean store() {
+ if (cacheOrder.isHeldByCurrentThread()) {
+ cacheOrder.store();
+ return true;
+ }
+ return false;
}
/**
@@ -176,7 +175,9 @@
* @return true if we successfully added to map, false otherwise.
*/
public synchronized boolean addEntry(String key, String path) {
- if (cacheOrder.containsKey(key)) return false;
+ if (cacheOrder.containsKey(key)) {
+ return false;
+ }
cacheOrder.setProperty(key, path);
return true;
}
@@ -188,7 +189,9 @@
* @return true if we successfully removed key from map, false otherwise.
*/
public synchronized boolean removeEntry(String key) {
- if (!cacheOrder.containsKey(key)) return false;
+ if (!cacheOrder.containsKey(key)) {
+ return false;
+ }
cacheOrder.remove(key);
return true;
}
@@ -243,31 +246,14 @@
* Lock the file to have exclusive access.
*/
public synchronized void lock() {
- try {
- fl = FileUtils.getFileLock(cacheOrder.getStoreFile().getPath(), false, true);
- } catch (OverlappingFileLockException e) { // if overlap we just increase the count.
- } catch (Exception e) { // We didn't get a lock..
- OutputController.getLogger().log(e);
- }
- if (fl != null) lockCount++;
+ cacheOrder.lock();
}
/**
* Unlock the file.
*/
public synchronized void unlock() {
- if (fl != null) {
- lockCount--;
- try {
- if (lockCount == 0) {
- fl.release();
- fl.channel().close();
- fl = null;
- }
- } catch (IOException e) {
- OutputController.getLogger().log(e);
- }
- }
+ cacheOrder.unlock();
}
/**
@@ -280,14 +266,12 @@
return cacheOrder.getProperty(key);
}
- /**
- * Test if we the key provided is in use.
- *
- * @param key key to be tested.
- * @return true if the key is in use.
- */
- public synchronized boolean contains(String key) {
- return cacheOrder.contains(key);
+ public synchronized boolean containsKey(String key) {
+ return cacheOrder.containsKey(key);
+ }
+
+ public synchronized boolean containsValue(String value) {
+ return cacheOrder.containsValue(value);
}
/**
diff -r faeb3e209001 -r af89bcaa02a2 tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java
--- a/tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java Wed Sep 10 09:31:36 2014 -0400
+++ b/tests/netx/unit/net/sourceforge/jnlp/cache/CacheLRUWrapperTest.java Wed Sep 10 09:45:10 2014 -0400
@@ -37,11 +37,18 @@
package net.sourceforge.jnlp.cache;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import org.junit.AfterClass;
+import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -58,6 +65,13 @@
private final int noEntriesCacheFile = 1000;
+ private ByteArrayOutputStream baos;
+ private PrintStream out;
+ private ExecutorService executorService;
+ Object listener = new Object();
+
+ int num = 0;
+
@BeforeClass
static public void setupJNLPRuntimeConfig() {
cacheDirBackup = clw.cacheDir;
@@ -72,14 +86,19 @@
clw.cacheDir = cacheDirBackup;
clw.cacheOrder = cacheOrderBackup;
}
-
+
+ @Before
+ public void setup() {
+ baos = new ByteArrayOutputStream();
+ out = new PrintStream(baos);
+ executorService = Executors.newSingleThreadExecutor();
+ }
+
@Test
public void testLoadStoreTiming() throws InterruptedException {
final File cacheIndexFile = new File(clw.cacheDir + File.separator + cacheIndexFileName);
cacheIndexFile.delete();
- //ensure it exists, so we can lock
- clw.store();
try{
int noLoops = 1000;
@@ -131,8 +150,6 @@
final File cacheIndexFile = new File(clw.cacheDir + File.separator + cacheIndexFileName);
cacheIndexFile.delete();
- //ensure it exists, so we can lock
- clw.store();
try{
clw.lock();
@@ -179,4 +196,115 @@
clw.unlock();
}
}
+
+ @Test
+ public void testAddEntry() {
+ String key = "key";
+ String value = "value";
+
+ clw.addEntry(key, value);
+ assertTrue(clw.containsKey(key) && clw.containsValue(value));
+ }
+
+ @Test
+ public void testRemoveEntry() {
+ String key = "key";
+ String value = "value";
+
+ clw.addEntry(key, value);
+ clw.removeEntry(key);
+ assertFalse(clw.containsKey(key) && clw.containsValue(value));
+ }
+
+ @Test
+ public void testLock() throws IOException {
+ try {
+ clw.lock();
+ assertTrue(clw.cacheOrder.isHeldByCurrentThread());
+ } finally {
+ clw.unlock();
+ }
+ }
+
+ @Test
+ public void testUnlock() throws IOException {
+ try {
+ clw.lock();
+ } finally {
+ clw.unlock();
+ }
+ assertTrue(!clw.cacheOrder.isHeldByCurrentThread());
+ }
+
+ @Test
+ public void testStoreFailsWithoutLock() throws IOException {
+ assertTrue(!clw.store());
+ }
+
+ @Test
+ public void testStoreWorksWithLocK() throws IOException {
+ try {
+ clw.lock();
+ assertTrue(clw.store());
+ } finally {
+ clw.unlock();
+ }
+ }
+
+ @Test
+ public void testMultithreadLockPreventsStore() throws IOException, InterruptedException {
+ Thread a = new Thread(new StoreWorker());
+ a.start();
+
+ Thread b = new Thread(new StoreWorker());
+ b.start();
+
+ Thread.sleep(2000l);
+
+ synchronized (listener) {
+ num = 1;
+ listener.notifyAll();
+ }
+
+ String out = baos.toString();
+ System.out.println();
+ assertTrue(out.contains("true") && out.contains("false"));
+ }
+
+ private class StoreWorker implements Runnable {
+
+ public StoreWorker() {
+ }
+ @Override
+ public void run() {
+ try {
+ clw.cacheOrder.tryLock();
+ boolean result = clw.store();
+ executorService.execute(new WriteRunnable(String.valueOf(result)));
+ while (num == 0) {
+ synchronized (listener) {
+ listener.wait();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ clw.unlock();
+ }
+ }
+ }
+
+ private class WriteRunnable implements Runnable {
+ private String msg;
+ public WriteRunnable(String msg) {
+ this.msg = msg;
+ }
+
+ @Override
+ public void run() {
+ out.println(msg);
+ out.flush();
+ }
+ }
+
}
More information about the distro-pkg-dev
mailing list