/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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; import org.junit.Test; /** * @author Matej Knopp */ public class PageWindowManagerTest extends Assert { /** * https://issues.apache.org/jira/browse/WICKET-4572 */ @Test public void removeObsoleteIndices() { int page0id = 0, page1id = 1, page2id = 2; int maxSize = 10; PageWindowManager manager = new PageWindowManager(maxSize); // Add few pages. // All of them fully occupy the max space in the pageWindowManager. // So adding N+1st page removes the Nth page. manager.createPageWindow(page0id, maxSize); PageWindow page0Window = manager.getPageWindow(page0id); assertWindow(page0Window, page0id, page0Window.getFilePartOffset(), page0Window.getFilePartSize()); manager.createPageWindow(page1id, maxSize); PageWindow page1Window = manager.getPageWindow(page1id); assertWindow(page1Window, page1id, page1Window.getFilePartOffset(), page1Window.getFilePartSize()); // Try to get a page which has been lost with the adding of page1 assertNull("Page0 must be lost when Page1 has been added.", manager.getPageWindow(page0id)); manager.createPageWindow(page2id, maxSize); PageWindow page2Window = manager.getPageWindow(page2id); assertWindow(page2Window, page2id, page2Window.getFilePartOffset(), page2Window.getFilePartSize()); // Try to get a page which has been lost with the adding of page2 assertNull("Page1 must be lost when Page2 has been added.", manager.getPageWindow(page1id)); } /** * */ @Test public void addRemove() { PageWindowManager manager = new PageWindowManager(300); PageWindow window; window = manager.createPageWindow(1, 50); assertWindow(window, 1, 0, 50); window = manager.createPageWindow(2, 40); assertWindow(window, 2, 50, 40); assertEquals(manager.getTotalSize(), 90); window = manager.createPageWindow(2, 30); assertWindow(window, 2, 50, 30); assertEquals(manager.getTotalSize(), 80); manager.removePage(2); assertEquals(manager.getTotalSize(), 50); window = manager.createPageWindow(3, 30); assertWindow(window, 3, 50, 30); assertEquals(manager.getTotalSize(), 80); } /** * */ @Test public void pageWindowCycle() { PageWindowManager manager = new PageWindowManager(100); PageWindow window; window = manager.createPageWindow(1, 30); window = manager.createPageWindow(2, 30); window = manager.createPageWindow(3, 30); assertWindow(window, 3, 60, 30); window = manager.createPageWindow(4, 30); assertWindow(window, 4, 90, 30); // should start at the beginging window = manager.createPageWindow(5, 20); assertWindow(window, 5, 0, 20); assertNull(manager.getPageWindow(1)); window = manager.getPageWindow(2); assertWindow(window, 2, 30, 30); window = manager.createPageWindow(6, 10); assertWindow(window, 6, 20, 10); window = manager.getPageWindow(2); assertWindow(window, 2, 30, 30); window = manager.createPageWindow(6, 30); assertWindow(window, 6, 20, 30); assertNull(manager.getPageWindow(2)); assertNotNull(manager.getPageWindow(3)); window = manager.createPageWindow(6, 60); assertWindow(window, 6, 20, 60); assertNull(manager.getPageWindow(3)); window = manager.createPageWindow(7, 20); assertWindow(window, 7, 80, 20); assertNotNull(manager.getPageWindow(7)); // should start at the beginning again window = manager.createPageWindow(8, 10); assertWindow(window, 8, 0, 10); assertNull(manager.getPageWindow(5)); assertNotNull(manager.getPageWindow(6)); window = manager.createPageWindow(9, 20); assertWindow(window, 9, 10, 20); assertNull(manager.getPageWindow(6)); assertNotNull(manager.getPageWindow(7)); window = manager.createPageWindow(10, 20); assertWindow(window, 10, 30, 20); assertNull(manager.getPageWindow(6)); assertNotNull(manager.getPageWindow(7)); // make sure when replacing a page that's not last the old "instance" is // not valid anymore manager.createPageWindow(8, 10); window = manager.getPageWindow(8); assertWindow(window, 8, 50, 10); } private void assertWindow(PageWindow window, int pageId, int filePartOffset, int filePartSize) { 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(); @Override 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()); } } }