Updated Branches: refs/heads/master d7cb8c09d -> 4802fb774
WICKET-4572 DiskDataStore returns the wrong page when the page disk space is full Synchronize the public methods in PageWindowManager. Each Http Session has its own PageWindowManager instance. A blocking may occur when two or more requests in the same session touch different page instances or when the Asynchronous Queue used for writing pages' bytes is full. Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/4802fb77 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/4802fb77 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/4802fb77 Branch: refs/heads/master Commit: 4802fb774fe364217707b7447d8327f3d2eedf4b Parents: d7cb8c0 Author: Martin Tzvetanov Grigorov <[email protected]> Authored: Wed May 30 16:06:36 2012 +0300 Committer: Martin Tzvetanov Grigorov <[email protected]> Committed: Wed May 30 16:10:07 2012 +0300 ---------------------------------------------------------------------- .../apache/wicket/pageStore/PageWindowManager.java | 8 +- .../persistent/disk/PageWindowManagerTest.java | 117 +++++++++++++++ .../pageStore/AsynchronousDataStoreTest.java | 6 +- .../wicket/versioning/InMemoryPageStore.java | 5 +- .../java/org/apache/wicket/util/file/Files.java | 1 + 5 files changed, 129 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/4802fb77/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java index 03887bb..f194710 100644 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java @@ -371,7 +371,7 @@ public class PageWindowManager implements Serializable * @param size * @return page window */ - public PageWindow createPageWindow(int pageId, int size) + public synchronized PageWindow createPageWindow(int pageId, int size) { int index = getWindowIndex(pageId); @@ -403,7 +403,7 @@ public class PageWindowManager implements Serializable * @param pageId * @return page window or null */ - public PageWindow getPageWindow(int pageId) + public synchronized PageWindow getPageWindow(int pageId) { int index = getWindowIndex(pageId); if (index != -1) @@ -418,7 +418,7 @@ public class PageWindowManager implements Serializable * * @param pageId */ - public void removePage(int pageId) + public synchronized void removePage(int pageId) { int index = getWindowIndex(pageId); if (index != -1) @@ -499,7 +499,7 @@ public class PageWindowManager implements Serializable * * @return total size */ - public int getTotalSize() + public synchronized int getTotalSize() { return totalSize; } http://git-wip-us.apache.org/repos/asf/wicket/blob/4802fb77/wicket-core/src/test/java/org/apache/wicket/page/persistent/disk/PageWindowManagerTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/page/persistent/disk/PageWindowManagerTest.java b/wicket-core/src/test/java/org/apache/wicket/page/persistent/disk/PageWindowManagerTest.java index 44b5d71..7ede689 100644 --- a/wicket-core/src/test/java/org/apache/wicket/page/persistent/disk/PageWindowManagerTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/page/persistent/disk/PageWindowManagerTest.java @@ -16,6 +16,11 @@ */ package org.apache.wicket.page.persistent.disk; +import java.security.SecureRandom; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + import org.apache.wicket.pageStore.PageWindowManager; import org.apache.wicket.pageStore.PageWindowManager.PageWindow; import org.junit.Assert; @@ -180,4 +185,116 @@ public class PageWindowManagerTest extends Assert assertTrue(window.getPageId() == pageId && window.getFilePartOffset() == filePartOffset && window.getFilePartSize() == filePartSize); } + + /** how many operations to execute */ + private static final int EXECUTIONS = 10000; + + /** used to wait the executions */ + private static final CountDownLatch LATCH = new CountDownLatch(EXECUTIONS); + + private final PageWindowManager pageWindowManager = new PageWindowManager(1000L); + + /** the execution types */ + private final Runnable[] TASKS = new Runnable[] + { + new CreatePageWindowTask(pageWindowManager), + new GetPageWindowTask(pageWindowManager), + new RemovePageInSessionTask(pageWindowManager) + }; + + private static final SecureRandom RND = new SecureRandom(); + + /** + * Executes random mutator and accessor operations on {@link org.apache.wicket.pageStore.AsynchronousDataStore} validating + * that the used data structures can be used simultaneously. + * + * @throws Exception + */ + @Test + public void randomOperations() throws Exception + { + ExecutorService executorService = Executors.newFixedThreadPool(50); + + for (int i = 0; i < EXECUTIONS; i++) + { + Runnable task = TASKS[RND.nextInt(TASKS.length)]; + executorService.submit(task); + } + LATCH.await(); + executorService.shutdown(); + } + + private static abstract class AbstractTask implements Runnable + { + /** the ids for the stored/removed pages */ + private static final int[] PAGE_IDS = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + protected final PageWindowManager pageWindowManager; + + private AbstractTask(PageWindowManager pageWindowManager) + { + this.pageWindowManager = pageWindowManager; + } + + protected abstract void r(); + + public void run() + { + try + { + r(); + } + finally + { + LATCH.countDown(); + } + } + + protected int getPageId() + { + return PAGE_IDS[RND.nextInt(PAGE_IDS.length)]; + } + } + + private static class CreatePageWindowTask extends AbstractTask + { + private CreatePageWindowTask(PageWindowManager pageWindowManager) + { + super(pageWindowManager); + } + + @Override + public void r() + { + pageWindowManager.createPageWindow(getPageId(), 1000); + } + } + + private static class GetPageWindowTask extends AbstractTask + { + private GetPageWindowTask(PageWindowManager pageWindowManager) + { + super(pageWindowManager); + } + + @Override + public void r() + { + pageWindowManager.getPageWindow(getPageId()); + } + } + + private static class RemovePageInSessionTask extends AbstractTask + { + private RemovePageInSessionTask(PageWindowManager pageWindowManager) + { + super(pageWindowManager); + } + + @Override + public void r() + { + pageWindowManager.removePage(getPageId()); + } + } } http://git-wip-us.apache.org/repos/asf/wicket/blob/4802fb77/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousDataStoreTest.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousDataStoreTest.java b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousDataStoreTest.java index 208cb5e..7f5b2c1 100644 --- a/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousDataStoreTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/pageStore/AsynchronousDataStoreTest.java @@ -29,8 +29,11 @@ import org.junit.Test; */ public class AsynchronousDataStoreTest { +// private static final IDataStore WRAPPED_DATA_STORE = new DiskDataStore("asyncDataStoreApp", new StoreSettings(null).getFileStoreFolder(), Bytes.kilobytes(1)); + private static final IDataStore WRAPPED_DATA_STORE = new InMemoryPageStore(); + /** the data store under test */ - private static IDataStore DATA_STORE = new AsynchronousDataStore(new InMemoryPageStore(), 100); + private static final IDataStore DATA_STORE = new AsynchronousDataStore(WRAPPED_DATA_STORE, 100); /** the data for each page */ private static final byte[] DATA = new byte[] { 1, 2, 3 }; @@ -76,7 +79,6 @@ public class AsynchronousDataStoreTest private static abstract class AbstractTask implements Runnable { - protected abstract void r(); @Override http://git-wip-us.apache.org/repos/asf/wicket/blob/4802fb77/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java b/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java index ec684b3..d73e7fb 100644 --- a/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java +++ b/wicket-core/src/test/java/org/apache/wicket/versioning/InMemoryPageStore.java @@ -18,6 +18,7 @@ package org.apache.wicket.versioning; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.apache.wicket.pageStore.IDataStore; @@ -40,7 +41,7 @@ public class InMemoryPageStore implements IDataStore */ public InMemoryPageStore() { - store = new HashMap<String, Map<Integer, byte[]>>(); + store = new ConcurrentHashMap<String, Map<Integer, byte[]>> (); } @Override @@ -97,7 +98,7 @@ public class InMemoryPageStore implements IDataStore Map<Integer, byte[]> sessionPages = store.get(sessionId); if (sessionPages == null) { - sessionPages = new HashMap<Integer, byte[]>(); + sessionPages = new ConcurrentHashMap<Integer, byte[]>(); store.put(sessionId, sessionPages); } http://git-wip-us.apache.org/repos/asf/wicket/blob/4802fb77/wicket-util/src/main/java/org/apache/wicket/util/file/Files.java ---------------------------------------------------------------------- diff --git a/wicket-util/src/main/java/org/apache/wicket/util/file/Files.java b/wicket-util/src/main/java/org/apache/wicket/util/file/Files.java index dc4647f..72af504 100644 --- a/wicket-util/src/main/java/org/apache/wicket/util/file/Files.java +++ b/wicket-util/src/main/java/org/apache/wicket/util/file/Files.java @@ -452,6 +452,7 @@ public class Files try { Thread.sleep(100); + if (folder.exists()) return true; } catch (InterruptedException ix) {
