http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java new file mode 100644 index 0000000..8a03507 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistedPage.java @@ -0,0 +1,44 @@ +/* + * 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.pageStore; + +import java.io.Serializable; + +import org.apache.wicket.util.lang.Bytes; + +/** + * Information about a persisted page in an {@link IPersistentPageStore}. + * + * @see IPersistentPageStore#getPersistentPages(String, int) + */ +public interface IPersistedPage extends Serializable +{ + /** + * Id of page. + */ + int getPageId(); + + /** + * Size of page. + */ + Bytes getPageSize(); + + /** + * Type of page. + */ + String getPageType(); +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java new file mode 100644 index 0000000..b42746d --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/IPersistentPageStore.java @@ -0,0 +1,51 @@ +/* + * 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.pageStore; + +import java.util.List; +import java.util.Set; + +import org.apache.wicket.util.lang.Bytes; + +/** + * A store that can provide information about stored pages. + */ +public interface IPersistentPageStore extends IPageStore +{ + + /** + * Get the identifier for pages stored for the given context. + */ + String getSessionIdentifier(IPageContext context); + + /** + * Get the identifiers for all pages stored in all contexts. + */ + Set<String> getSessionIdentifiers(); + + /** + * Get information about all persisted pages with the given session identifier. + */ + List<IPersistedPage> getPersistentPages(String sessionIdentifier); + + /** + * Get total size of all stored pages. + * + * @return + */ + Bytes getTotalSize(); +} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java new file mode 100644 index 0000000..fc11901 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/InMemoryPageStore.java @@ -0,0 +1,352 @@ +/* + * 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.pageStore; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +import org.apache.wicket.Application; +import org.apache.wicket.Session; +import org.apache.wicket.core.util.lang.WicketObjects; +import org.apache.wicket.page.IManageablePage; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.lang.Bytes; + +/** + * A storage of pages in memory. + */ +public class InMemoryPageStore implements IPersistentPageStore +{ + + /** + * A registry of all page instances. + */ + private static final ConcurrentMap<String, InMemoryPageStore> IN_MEMORY_STORES = new ConcurrentHashMap<>(); + + private static final String KEY = "wicket:InMemoryPageStore"; + + private final Map<String, MemoryData> datas = new ConcurrentHashMap<>(); + + private String applicationName; + + private int maxPages; + + /** + * @param applicationName + * {@link Application#getName()} + * @param maxPages + * max pages per session + */ + public InMemoryPageStore(String applicationName, int maxPages) + { + this.applicationName = Args.notNull(applicationName, "applicationName"); + this.maxPages = maxPages; + + IN_MEMORY_STORES.put(applicationName, this); + } + + /** + * + * + * @return <code>true</code> always + */ + @Override + public boolean canBeAsynchronous(IPageContext context) + { + // session attribute must be added here *before* any asynchronous calls + // when session is no longer available + getSessionAttribute(context, true); + + return true; + } + + protected SessionAttribute getSessionAttribute(IPageContext context, boolean create) + { + context.bind(); + + SessionAttribute attribute = context.getSessionAttribute(KEY); + if (attribute == null && create) + { + attribute = new SessionAttribute(applicationName, context.getSessionId()); + context.setSessionAttribute(KEY, attribute); + } + return attribute; + } + + @Override + public void destroy() + { + datas.clear(); + + IN_MEMORY_STORES.remove(applicationName); + } + + @Override + public IManageablePage getPage(IPageContext context, int id) + { + MemoryData data = getMemoryData(context, false); + if (data == null) + { + return null; + } + + return data.get(id); + } + + @Override + public void removePage(IPageContext context, final IManageablePage page) + { + MemoryData data = getMemoryData(context, false); + + if (data != null) + { + synchronized (data) + { + data.remove(page); + } + } + } + + @Override + public void removeAllPages(IPageContext context) + { + MemoryData data = getMemoryData(context, false); + + if (data != null) + { + synchronized (data) + { + data.removeAll(); + } + } + } + + @Override + public void addPage(IPageContext context, IManageablePage page) + { + MemoryData data = getMemoryData(context, true); + + data.add(page, maxPages); + } + + @Override + public String getSessionIdentifier(IPageContext context) + { + return context.getSessionId(); + } + + @Override + public Set<String> getSessionIdentifiers() + { + return datas.keySet(); + } + + @Override + public List<IPersistedPage> getPersistentPages(String sessionIdentifier) + { + MemoryData data = datas.get(sessionIdentifier); + if (data == null) + { + return new ArrayList<>(); + } + + synchronized (data) + { + return StreamSupport.stream(data.spliterator(), false) + .map(page -> new MermoryPersistedPage(page, getSize(page))) + .collect(Collectors.toList()); + } + } + + @Override + public Bytes getTotalSize() + { + int size = 0; + + for (MemoryData data : datas.values()) + { + synchronized (data) + { + for (IManageablePage page : data) + { + size += getSize(page); + } + } + } + + return Bytes.bytes(size); + } + + protected long getSize(IManageablePage page) + { + return WicketObjects.sizeof(page); + } + + private MemoryData getMemoryData(IPageContext context, boolean create) + { + SessionAttribute attribute = getSessionAttribute(context, create); + + if (!create) + { + if (attribute == null) { + return null; + } else { + return datas.get(attribute.identifier); + } + } + + MemoryData data = new MemoryData(); + MemoryData existing = datas.putIfAbsent(attribute.identifier, data); + return existing != null ? existing : data; + } + + private void removeMemoryData(String identifier) + { + datas.remove(identifier); + } + + /** + * Data kept in memory. + */ + static class MemoryData implements Iterable<IManageablePage> + { + private LinkedHashMap<Integer, IManageablePage> pages = new LinkedHashMap<>(); + + @Override + public Iterator<IManageablePage> iterator() + { + return pages.values().iterator(); + } + + public synchronized void add(IManageablePage page, int maxPages) + { + pages.remove(page.getPageId()); + pages.put(page.getPageId(), page); + + Iterator<IManageablePage> iterator = pages.values().iterator(); + int size = pages.size(); + while (size > maxPages) + { + iterator.next(); + + iterator.remove(); + size--; + } + } + + public void remove(IManageablePage page) + { + pages.remove(page.getPageId()); + } + + public void removeAll() + { + pages.clear(); + } + + public IManageablePage get(int id) + { + IManageablePage page = pages.get(id); + + return page; + } + } + + /** + * Attribute held in session. + */ + static class SessionAttribute implements Serializable, HttpSessionBindingListener + { + + private final String applicationName; + + /** + * The identifier of the session, must not be equal to {@link Session#getId()}, e.g. when + * the container changes the id after authorization. + */ + public final String identifier; + + public SessionAttribute(String applicationName, String sessionIdentifier) + { + this.applicationName = Args.notNull(applicationName, "applicationName"); + this.identifier = Args.notNull(sessionIdentifier, "sessionIdentifier"); + } + + + @Override + public void valueBound(HttpSessionBindingEvent event) + { + } + + @Override + public void valueUnbound(HttpSessionBindingEvent event) + { + InMemoryPageStore store = IN_MEMORY_STORES.get(applicationName); + if (store != null) + { + store.removeMemoryData(identifier); + } + } + } + + private static class MermoryPersistedPage implements IPersistedPage + { + + private final int id; + + private final String type; + + private final long size; + + public MermoryPersistedPage(IManageablePage page, long size) + { + this.id = page.getPageId(); + this.type = page.getClass().getName(); + this.size = size; + } + + @Override + public int getPageId() + { + return id; + } + + @Override + public String getPageType() + { + return type; + } + + @Override + public Bytes getPageSize() + { + return Bytes.bytes(size); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java new file mode 100644 index 0000000..3914464 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/InSessionPageStore.java @@ -0,0 +1,268 @@ +/* + * 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.pageStore; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +import javax.servlet.http.HttpSession; + +import org.apache.wicket.MetaDataKey; +import org.apache.wicket.Session; +import org.apache.wicket.WicketRuntimeException; +import org.apache.wicket.page.IManageablePage; +import org.apache.wicket.serialize.ISerializer; +import org.apache.wicket.util.lang.Args; + +/** + * A store keeping a configurable maximum of pages in the session, delegating all or excessive pages + * to another store. + */ +public class InSessionPageStore extends DelegatingPageStore +{ + + private static final MetaDataKey<SessionData> KEY = new MetaDataKey<SessionData>() + { + private static final long serialVersionUID = 1L; + }; + + private ISerializer serializer; + + private int maxPages; + + private boolean delegateAll = false; + + /** + * Use this constructor, if sessions are never serialized. + * + * @param delegate + * store to delegate to + * @param maxPages + * maximum pages to keep in session + */ + public InSessionPageStore(IPageStore delegate, int maxPages) + { + this(delegate, new ISerializer() + { + @Override + public byte[] serialize(Object object) + { + throw new WicketRuntimeException("InSessionPageStore not configured for serialization"); + } + + @Override + public Object deserialize(byte[] data) + { + throw new WicketRuntimeException("InSessionPageStore not configured for serialization"); + } + }, maxPages); + } + + /** + * @param delegate + * store to delegate to + * @param serializer + * serializer to use if session gets persisted + * @param maxPages + * maximum pages to keep in session + */ + public InSessionPageStore(IPageStore delegate, ISerializer serializer, int maxPages) + { + super(delegate); + + this.serializer = Args.notNull(serializer, "serializer"); + + this.maxPages = maxPages; + } + + /** + * Delegated all pages, even those that are still kept in the session. + */ + public InSessionPageStore delegateAll() + { + delegateAll = true; + + return this; + } + + @Override + public IManageablePage getPage(IPageContext context, int id) + { + IManageablePage page = getSessionData(context).get(id); + if (page != null) + { + return page; + } + + return super.getPage(context, id); + } + + @Override + public void addPage(IPageContext context, IManageablePage page) + { + SessionData data = getSessionData(context); + + data.addAndDelegate(context, page, maxPages, delegateAll, getDelegate()); + } + + @Override + public void removePage(IPageContext context, IManageablePage page) + { + getSessionData(context).remove(page); + + super.removePage(context, page); + } + + @Override + public void removeAllPages(IPageContext context) + { + getSessionData(context).removeAll(); + + super.removeAllPages(context); + } + + private SessionData getSessionData(IPageContext context) + { + SessionData data = context.getSessionData(KEY); + if (data == null) + { + context.bind(); + data = new SessionData(); + + context.setSessionData(KEY, data); + } + + // data might be deserialized so initialize again + data.init(serializer); + + return data; + } + + /** + * Data kept in the {@link Session}, might get serialized along with its containing + * {@link HttpSession}. + */ + static class SessionData implements Serializable + { + + transient ISerializer serializer; + + /** + * Pages, may partly be serialized. + */ + private LinkedHashMap<Integer, Serializable> pages = new LinkedHashMap<>(); + + /** + * This method <em>must</em> be called each time it is retrieved from the session: <br/> + * After deserializing from persisted session the serializer is no longer referenced and all + * contained pages are in a serialized state. + */ + public void init(ISerializer serializer) + { + this.serializer = Args.notNull(serializer, "serializer"); + } + + public synchronized void addAndDelegate(IPageContext context, IManageablePage page, + int maxPages, boolean delegateAll, IPageStore delegate) + { + pages.remove(page.getPageId()); + pages.put(page.getPageId(), page); + + Serializable expelled = null; + if (pages.size() > maxPages) + { + Iterator<Serializable> iterator = pages.values().iterator(); + expelled = iterator.next(); + iterator.remove(); + } + + if (delegateAll) + { + delegate.addPage(context, page); + } + else + { + // when pages are not delegated automatically, we have to catch up + // on an expelled page now + if (expelled != null) + { + if (expelled instanceof byte[]) + { + // ... which results in this suboptimal case, when the session was persisted: + // in that case the expelled page is still in a serialized state, so we have + // to deserialize it first to be able to delegate it + expelled = (IManageablePage)serializer.deserialize((byte[])expelled); + } + delegate.addPage(context, (IManageablePage)expelled); + } + } + } + + public synchronized void remove(IManageablePage page) + { + pages.remove(page.getPageId()); + } + + public synchronized void removeAll() + { + pages.clear(); + } + + public synchronized IManageablePage get(int id) + { + Serializable serializable = pages.get(id); + + if (serializable instanceof byte[]) + { + if (serializer == null) + { + throw new IllegalStateException("SessionData#init() was not called"); + } + serializable = (Serializable)serializer.deserialize((byte[])serializable); + + pages.put(id, serializable); + } + + return (IManageablePage)serializable; + } + + /** + * Serialize pages before writing to output. + */ + private void writeObject(final ObjectOutputStream output) throws IOException + { + // serialize pages if not already + for (Entry<Integer, Serializable> entry : pages.entrySet()) + { + if (entry.getValue() instanceof IManageablePage) + { + if (serializer == null) + { + throw new IllegalStateException("SessionData#init() was not called"); + } + entry.setValue(serializer.serialize(entry.getValue())); + } + } + + output.defaultWriteObject(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java new file mode 100644 index 0000000..846c858 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/NoopPageStore.java @@ -0,0 +1,53 @@ +/* + * 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.pageStore; + +import org.apache.wicket.page.IManageablePage; + +/** + * A non-storage of pages. + */ +public class NoopPageStore implements IPageStore +{ + + @Override + public boolean canBeAsynchronous(IPageContext context) + { + return true; + } + + @Override + public void addPage(IPageContext context, IManageablePage page) + { + } + + @Override + public void removePage(IPageContext context, IManageablePage page) + { + } + + @Override + public void removeAllPages(IPageContext context) + { + } + + @Override + public IManageablePage getPage(IPageContext context, int id) + { + return null; + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/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 deleted file mode 100644 index f194710..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PageWindowManager.java +++ /dev/null @@ -1,506 +0,0 @@ -/* - * 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.pageStore; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import org.apache.wicket.util.collections.IntHashMap; - -/** - * Manages positions and size of serialized pages in the pagemap file. - * <p> - * The pages are stored inside the file in a cyclic way. Newer pages are placed after older ones, - * until the maximum file size is reached. After that, the next page is stored in the beginning of - * the file. - * - * @author Matej Knopp - */ -public class PageWindowManager implements Serializable -{ - private static final long serialVersionUID = 1L; - - /** - * Contains information about a page inside the file. - * - * @author Matej Knopp - */ - private static class PageWindowInternal implements Serializable - { - private static final long serialVersionUID = 1L; - - /** id of page or -1 if the window is empty */ - private int pageId; - - /** offset in the file where the serialized page data begins */ - private int filePartOffset; - - /** size of serialized page data */ - private int filePartSize; - } - - /** list of PageWindowInternal objects */ - private final List<PageWindowInternal> windows = new ArrayList<PageWindowInternal>(); - - /** - * map from page id to list of pagewindow indices (referring to the windows list) - to improve - * searching speed the index must be cleaned when the instances in the windows list change their - * indexes (e.g. items are shifted on page window removal) - */ - private IntHashMap<Integer> idToWindowIndex = null; - - /** - * Inversed index of #idToWindowIndex - */ - private IntHashMap<Integer> windowIndexToPageId = null; - - /** index of last added page */ - private int indexPointer = -1; - - private int totalSize = 0; - - /** - * Maximum page size. After this size is exceeded, the pages will be saved starting at the - * beginning of file. - */ - private final long maxSize; - - /** - * - * @param pageId - * @param windowIndex - */ - private void putWindowIndex(int pageId, int windowIndex) - { - if (idToWindowIndex != null && pageId != -1 && windowIndex != -1) - { - Integer oldPageId = windowIndexToPageId.remove(windowIndex); - if (oldPageId != null) - { - idToWindowIndex.remove(oldPageId); - } - idToWindowIndex.put(pageId, windowIndex); - windowIndexToPageId.put(windowIndex, pageId); - } - } - - /** - * - * @param pageId - */ - private void removeWindowIndex(int pageId) - { - Integer windowIndex = idToWindowIndex.remove(pageId); - if (windowIndex != null) - { - windowIndexToPageId.remove(windowIndex); - } - } - - /** - * - */ - private void rebuildIndices() - { - idToWindowIndex = null; - idToWindowIndex = new IntHashMap<Integer>(); - windowIndexToPageId = null; - windowIndexToPageId = new IntHashMap<Integer>(); - for (int i = 0; i < windows.size(); ++i) - { - PageWindowInternal window = windows.get(i); - putWindowIndex(window.pageId, i); - } - } - - /** - * Returns the index of the given page in the {@link #windows} list. - * - * @param pageId - * @return window index - */ - private int getWindowIndex(int pageId) - { - if (idToWindowIndex == null) - { - rebuildIndices(); - } - - Integer result = idToWindowIndex.get(pageId); - return result != null ? result : -1; - } - - /** - * Increments the {@link #indexPointer}. If the maximum file size has been reached, the - * {@link #indexPointer} is set to 0. - * - * @return new index pointer - */ - private int incrementIndexPointer() - { - if ((maxSize > 0) && (totalSize >= maxSize) && (indexPointer == windows.size() - 1)) - { - indexPointer = 0; - } - else - { - ++indexPointer; - } - return indexPointer; - } - - /** - * Returns the offset in file of the window on given index. The offset is counted by getting the - * previous page offset and adding the previous page size to it. - * - * @param index - * @return window file offset - */ - private int getWindowFileOffset(int index) - { - if (index > 0) - { - PageWindowInternal window = windows.get(index - 1); - return window.filePartOffset + window.filePartSize; - } - return 0; - } - - /** - * Splits the window with given index to two windows. First of those will have size specified by - * the argument, the other one will fill up the rest of the original window. - * - * @param index - * @param size - */ - private void splitWindow(int index, int size) - { - PageWindowInternal window = windows.get(index); - int delta = window.filePartSize - size; - - if (index == windows.size() - 1) - { - // if this is last window - totalSize -= delta; - window.filePartSize = size; - } - else if (window.filePartSize != size) - { - PageWindowInternal newWindow = new PageWindowInternal(); - newWindow.pageId = -1; - window.filePartSize = size; - - windows.add(index + 1, newWindow); - - newWindow.filePartOffset = getWindowFileOffset(index + 1); - newWindow.filePartSize = delta; - } - - idToWindowIndex = null; - windowIndexToPageId = null; - } - - /** - * Merges the window with given index with the next window. The resulting window will have size - * of the two windows summed together. - * - * @param index - */ - private void mergeWindowWithNext(int index) - { - if (index < windows.size() - 1) - { - PageWindowInternal window = windows.get(index); - PageWindowInternal next = windows.get(index + 1); - window.filePartSize += next.filePartSize; - - windows.remove(index + 1); - idToWindowIndex = null; // reset index - windowIndexToPageId = null; - } - } - - /** - * Adjusts the window on given index to the specified size. If the new size is smaller than the - * window size, the window will be split. Otherwise the window will be merged with as many - * subsequent window as necessary. In case the window is last window in the file, the size will - * be adjusted without splitting or merging. - * - * @param index - * @param size - */ - private void adjustWindowSize(int index, int size) - { - PageWindowInternal window = windows.get(index); - - // last window, just adjust size - if (index == windows.size() - 1) - { - int delta = size - window.filePartSize; - totalSize += delta; - window.filePartSize = size; - } - else - { - // merge as many times as necessary - while (window.filePartSize < size && index < windows.size() - 1) - { - mergeWindowWithNext(index); - } - - // done merging - do we have enough room ? - if (window.filePartSize < size) - { - // no, this is the last window - int delta = size - window.filePartSize; - totalSize += delta; - window.filePartSize = size; - } - else - { - // yes, we might want to split the window, so that we don't lose - // space when the created window was too big - splitWindow(index, size); - } - } - - window.pageId = -1; - } - - /** - * Allocates window on given index with to size. If the index is pointing to existing window, - * the window size will be adjusted. Otherwise a new window with appropriated size will be - * created. - * - * @param index - * @param size - * @return page window - */ - private PageWindowInternal allocatePageWindow(int index, int size) - { - final PageWindowInternal window; - - // new window - if (index == windows.size()) - { - // new page window - window = new PageWindowInternal(); - window.filePartOffset = getWindowFileOffset(index); - totalSize += size; - window.filePartSize = size; - windows.add(window); - } - else - { - // get the window - window = windows.get(index); - - // adjust if necessary - if (window.filePartSize != size) - { - adjustWindowSize(index, size); - } - } - - return window; - } - - /** - * Public (read only) version of page window. - * - * @author Matej Knopp - */ - public static class PageWindow - { - private final PageWindowInternal pageWindowInternal; - - /** - * Construct. - * - * @param pageWindowInternal - */ - private PageWindow(PageWindowInternal pageWindowInternal) - { - this.pageWindowInternal = pageWindowInternal; - } - - /** - * @return page Id - */ - public int getPageId() - { - return pageWindowInternal.pageId; - } - - /** - * @return offset in the pagemap file where the serialized page data starts - */ - public int getFilePartOffset() - { - return pageWindowInternal.filePartOffset; - } - - /** - * @return size of the serialized page data - */ - public int getFilePartSize() - { - return pageWindowInternal.filePartSize; - } - } - - /** - * Creates and returns a new page window for given page. - * - * @param pageId - * @param size - * @return page window - */ - public synchronized PageWindow createPageWindow(int pageId, int size) - { - int index = getWindowIndex(pageId); - - // if we found the page window, mark it as invalid - if (index != -1) - { - removeWindowIndex(pageId); - (windows.get(index)).pageId = -1; - } - - // if we are not going to reuse a page window (because it's not on - // indexPointer position or because we didn't find it), increment the - // indexPointer - if (index == -1 || index != indexPointer) - { - index = incrementIndexPointer(); - } - - PageWindowInternal window = allocatePageWindow(index, size); - window.pageId = pageId; - - putWindowIndex(pageId, index); - return new PageWindow(window); - } - - /** - * Returns the page window for given page or null if no window was found. - * - * @param pageId - * @return page window or null - */ - public synchronized PageWindow getPageWindow(int pageId) - { - int index = getWindowIndex(pageId); - if (index != -1) - { - return new PageWindow(windows.get(index)); - } - return null; - } - - /** - * Removes the page window for given page. - * - * @param pageId - */ - public synchronized void removePage(int pageId) - { - int index = getWindowIndex(pageId); - if (index != -1) - { - PageWindowInternal window = windows.get(index); - removeWindowIndex(pageId); - if (index == windows.size() - 1) - { - windows.remove(index); - totalSize -= window.filePartSize; - if (indexPointer == index) - { - --indexPointer; - } - } - else - { - window.pageId = -1; - } - } - } - - /** - * Returns last n saved page windows. - * - * @param count - * @return list of page windows - */ - public synchronized List<PageWindow> getLastPageWindows(int count) - { - List<PageWindow> result = new ArrayList<PageWindow>(); - - // start from current index to 0 - int currentIndex = indexPointer; - - do - { - if (currentIndex == -1) - { - break; - } - - if (currentIndex < windows.size()) - { - PageWindowInternal window = windows.get(currentIndex); - if (window.pageId != -1) - { - result.add(new PageWindow(window)); - } - } - - --currentIndex; - if (currentIndex == -1) - { - // rewind to the last entry and collect all entries until current index - currentIndex = windows.size() - 1; - } - } - while (result.size() < count && currentIndex != indexPointer); - - return result; - } - - /** - * Creates a new PageWindowManager. - * - * @param maxSize - * maximum page size. After this size is exceeded, the pages will be saved starting - * at the beginning of file - */ - public PageWindowManager(long maxSize) - { - this.maxSize = maxSize; - } - - /** - * Returns the size of all saved pages - * - * @return total size - */ - public synchronized int getTotalSize() - { - return totalSize; - } -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java deleted file mode 100644 index 4a21f4c..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/PerSessionPageStore.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * 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.pageStore; - -import java.lang.ref.SoftReference; -import java.util.Comparator; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ConcurrentSkipListMap; - -import org.apache.wicket.page.IManageablePage; -import org.apache.wicket.serialize.ISerializer; -import org.apache.wicket.util.lang.Args; - -/** - * A page store that uses a SecondLevelPageCache with the last N used page instances - * per session. - * - * <strong>Note</strong>: the size of the cache depends on the {@code cacheSize} constructor - * parameter multiplied by the number of the active http sessions. - * - * It depends on the application use cases but usually a reasonable value of - * {@code cacheSize} would be just a few pages (2-3). If the application don't expect many - * active http sessions and the work flow involves usage of the browser/application history - * then the {@code cacheSize} value may be increased to a bigger value. - */ -public class PerSessionPageStore extends AbstractCachingPageStore<IManageablePage> -{ - /** - * Constructor. - * - * @param pageSerializer - * the {@link org.apache.wicket.serialize.ISerializer} that will be used to convert pages from/to byte arrays - * @param dataStore - * the {@link org.apache.wicket.pageStore.IDataStore} that actually stores the pages - * @param cacheSize - * the number of pages to cache in memory before passing them to - * {@link org.apache.wicket.pageStore.IDataStore#storeData(String, int, byte[])} - */ - public PerSessionPageStore(final ISerializer pageSerializer, final IDataStore dataStore, - final int cacheSize) - { - super(pageSerializer, dataStore, new PagesCache(cacheSize)); - } - - @Override - public IManageablePage convertToPage(final Object object) - { - if (object == null) - { - return null; - } - else if (object instanceof IManageablePage) - { - return (IManageablePage)object; - } - - String type = object.getClass().getName(); - throw new IllegalArgumentException("Unknown object type: " + type); - } - - /** - * An implementation of SecondLevelPageCache that stores the last used N live page instances - * per http session. - */ - protected static class PagesCache implements SecondLevelPageCache<String, Integer, IManageablePage> - { - /** - * Helper class used to compare the page entries in the cache by their - * access time - */ - private static class PageValue - { - /** - * The id of the cached page - */ - private final int pageId; - - /** - * The last time this page has been used/accessed. - */ - private long accessTime; - - private PageValue(IManageablePage page) - { - this(page.getPageId()); - } - - private PageValue(int pageId) - { - this.pageId = pageId; - touch(); - } - - /** - * Updates the access time with the current time - */ - private void touch() - { - accessTime = System.nanoTime(); - } - - @Override - public boolean equals(Object o) - { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PageValue pageValue = (PageValue) o; - - return pageId == pageValue.pageId; - } - - @Override - public int hashCode() - { - return pageId; - } - } - - private static class PageComparator implements Comparator<PageValue> - { - @Override - public int compare(PageValue p1, PageValue p2) - { - return Long.compare(p1.accessTime, p2.accessTime); - } - } - - private final int maxEntriesPerSession; - - private final ConcurrentMap<String, SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>>> cache; - - /** - * Constructor. - * - * @param maxEntriesPerSession - * The number of cache entries per session - */ - public PagesCache(final int maxEntriesPerSession) - { - this.maxEntriesPerSession = maxEntriesPerSession; - cache = new ConcurrentHashMap<>(); - } - - /** - * - * @param sessionId - * The id of the http session - * @param pageId - * The id of the page to remove from the cache - * @return the removed {@link org.apache.wicket.page.IManageablePage} or <code>null</code> - otherwise - */ - @Override - public IManageablePage removePage(final String sessionId, final Integer pageId) - { - IManageablePage result = null; - - if (maxEntriesPerSession > 0) - { - Args.notNull(sessionId, "sessionId"); - Args.notNull(pageId, "pageId"); - - SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId); - if (pagesPerSession != null) - { - ConcurrentMap<PageValue, IManageablePage> pages = pagesPerSession.get(); - if (pages != null) - { - PageValue sample = new PageValue(pageId); - Iterator<Map.Entry<PageValue, IManageablePage>> iterator = pages.entrySet().iterator(); - while (iterator.hasNext()) - { - Map.Entry<PageValue, IManageablePage> entry = iterator.next(); - if (sample.equals(entry.getKey())) - { - result = entry.getValue(); - iterator.remove(); - break; - } - } - } - } - } - - return result; - } - - /** - * Removes all {@link org.apache.wicket.page.IManageablePage}s for the session - * with <code>sessionId</code> from the cache. - * - * @param sessionId - * The id of the expired http session - */ - @Override - public void removePages(String sessionId) - { - Args.notNull(sessionId, "sessionId"); - - if (maxEntriesPerSession > 0) - { - cache.remove(sessionId); - } - } - - /** - * Returns a {@link org.apache.wicket.page.IManageablePage} by looking it up by <code>sessionId</code> and - * <code>pageId</code>. If there is a match then it is <i>touched</i>, i.e. it is moved at - * the top of the cache. - * - * @param sessionId - * The id of the http session - * @param pageId - * The id of the page to find - * @return the found serialized page or <code>null</code> when not found - */ - @Override - public IManageablePage getPage(String sessionId, Integer pageId) - { - IManageablePage result = null; - - if (maxEntriesPerSession > 0) - { - Args.notNull(sessionId, "sessionId"); - Args.notNull(pageId, "pageId"); - - SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId); - if (pagesPerSession != null) - { - ConcurrentSkipListMap<PageValue, IManageablePage> pages = pagesPerSession.get(); - if (pages != null) - { - PageValue sample = new PageValue(pageId); - for (Map.Entry<PageValue, IManageablePage> entry : pages.entrySet()) - { - if (sample.equals(entry.getKey())) - { - // touch the entry - entry.getKey().touch(); - result = entry.getValue(); - break; - } - } - } - } - } - return result; - } - - /** - * Store the serialized page in cache - * - * @param page - * the data to serialize (page id, session id, bytes) - */ - @Override - public void storePage(String sessionId, Integer pageId, IManageablePage page) - { - if (maxEntriesPerSession > 0) - { - Args.notNull(sessionId, "sessionId"); - Args.notNull(pageId, "pageId"); - - SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> pagesPerSession = cache.get(sessionId); - if (pagesPerSession == null) - { - ConcurrentSkipListMap<PageValue, IManageablePage> pages = new ConcurrentSkipListMap<>(new PageComparator()); - pagesPerSession = new SoftReference<>(pages); - SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> old = cache.putIfAbsent(sessionId, pagesPerSession); - if (old != null) - { - pagesPerSession = old; - } - } - - ConcurrentSkipListMap<PageValue, IManageablePage> pages = pagesPerSession.get(); - if (pages == null) - { - pages = new ConcurrentSkipListMap<>(); - pagesPerSession = new SoftReference<>(pages); - SoftReference<ConcurrentSkipListMap<PageValue, IManageablePage>> old = cache.putIfAbsent(sessionId, pagesPerSession); - if (old != null) - { - pages = old.get(); - } - } - - if (pages != null) - { - removePage(sessionId, pageId); - - PageValue pv = new PageValue(page); - pages.put(pv, page); - - while (pages.size() > maxEntriesPerSession) - { - pages.pollFirstEntry(); - } - } - } - } - - @Override - public void destroy() - { - cache.clear(); - } - } - - @Override - public boolean canBeAsynchronous() - { - return false; // NOTE: not analyzed neither tested yet, this page store being wrapped by asynchronous one - } -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java new file mode 100644 index 0000000..2420768 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/RequestPageStore.java @@ -0,0 +1,159 @@ +/* + * 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.pageStore; + +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.wicket.MetaDataKey; +import org.apache.wicket.page.IManageablePage; +import org.apache.wicket.request.cycle.RequestCycle; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Buffer pages till the end of the request, when they are delegated to another store in + * the reverse order they where accessed. + */ +public class RequestPageStore extends DelegatingPageStore +{ + + private static final Logger log = LoggerFactory.getLogger(RequestPageStore.class); + + private static final MetaDataKey<RequestData> KEY = new MetaDataKey<>() + { + private static final long serialVersionUID = 1L; + }; + + public RequestPageStore(IPageStore delegate) + { + super(delegate); + } + + @Override + public IManageablePage getPage(IPageContext context, int id) + { + IManageablePage page = getRequestData(context).get(id); + if (page != null) + { + return page; + } + + return super.getPage(context, id); + } + + @Override + public void addPage(IPageContext context, IManageablePage page) + { + getRequestData(context).add(page); + } + + @Override + public void removePage(IPageContext context, IManageablePage page) + { + getRequestData(context).remove(page); + + super.removePage(context, page); + } + + @Override + public void removeAllPages(IPageContext context) + { + getRequestData(context).removeAll(); + + super.removeAllPages(context); + } + + @Override + public void detach(IPageContext context) + { + RequestData requestData = getRequestData(context); + for (IManageablePage page : requestData.pages()) + { + boolean isPageStateless; + try + { + isPageStateless = page.isPageStateless(); + } + catch (Exception x) + { + log.warn("An error occurred while checking whether a page is stateless. Assuming it is stateful.", x); + isPageStateless = false; + } + + if (isPageStateless == false) + { + super.addPage(context, page); + } + } + requestData.removeAll(); + + super.detach(context); + } + + private RequestData getRequestData(IPageContext context) + { + RequestData requestData = context.getRequestData(KEY); + if (requestData == null) + { + requestData = new RequestData(); + + context.setRequestData(KEY, requestData); + } + return requestData; + } + + /** + * Data kept in the {@link RequestCycle}. + */ + static class RequestData + { + private Map<Integer, IManageablePage> pages = new LinkedHashMap<>(); + + public void add(IManageablePage page) + { + pages.remove(page.getPageId()); + + pages.put(page.getPageId(), page); + } + + public Iterable<IManageablePage> pages() + { + return pages.values(); + } + + public IManageablePage get(int id) { + IManageablePage page = pages.get(id); + + if (page != null) { + pages.put(id, page); + } + + return page; + } + + public void remove(IManageablePage page) + { + pages.remove(page.getPageId()); + } + + public void removeAll() + { + pages.clear(); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java deleted file mode 100644 index 3d30857..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/SecondLevelPageCache.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.pageStore; - -/** - * An application scoped cache that holds the last N used pages in the application. - * Acts as a second level cache between the Http Session (first level) and the - * disk (third level cache). - * - * @param <S> - * The type of the session identifier - * @param <PI> - * The type of the page identifier - * @param <P> - * The type of the stored page - */ -public interface SecondLevelPageCache<S, PI, P> -{ - P removePage(S session, PI pageId); - - void removePages(S session); - - P getPage(S session, PI pageId); - - void storePage(S session, PI pageId, P page); - - void destroy(); -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java new file mode 100644 index 0000000..5f59d34 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/pageStore/disk/PageWindowManager.java @@ -0,0 +1,493 @@ +/* + * 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.pageStore.disk; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import org.apache.wicket.pageStore.IPersistedPage; +import org.apache.wicket.util.collections.IntHashMap; +import org.apache.wicket.util.lang.Bytes; + +/** + * Manages positions and size of chunks of data in a file. + * <p> + * The data is stored inside the file in a cyclic way. Newer pages are placed after older ones, + * until the maximum file size is reached. After that, the next page is stored in the beginning of + * the file. + * + * @author Matej Knopp + */ +public class PageWindowManager implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** + * Contains information about a page inside the file. + * + * @author Matej Knopp + */ + public static class FileWindow implements IPersistedPage, Serializable + { + private static final long serialVersionUID = 1L; + + /** id of data or -1 if the window is empty */ + private int id; + + private String type; + + /** offset in the file where the serialized page data begins */ + private int filePartOffset; + + /** size of serialized page data */ + private int filePartSize; + + @Override + public int getPageId() + { + return id; + } + + @Override + public String getPageType() { + return type; + } + + @Override + public Bytes getPageSize() + { + return Bytes.bytes(filePartSize); + } + + public int getFilePartOffset() + { + return filePartOffset; + } + + public int getFilePartSize() + { + return filePartSize; + } + } + + private final List<FileWindow> windows = new ArrayList<FileWindow>(); + + /** + * map from page id to list of pagewindow indices (referring to the windows list) - to improve + * searching speed the index must be cleaned when the instances in the windows list change their + * indexes (e.g. items are shifted on page window removal) + */ + private IntHashMap<Integer> idToWindowIndex = null; + + /** + * Inversed index of #idToWindowIndex + */ + private IntHashMap<Integer> windowIndexToPageId = null; + + /** index of last added page */ + private int indexPointer = -1; + + private int totalSize = 0; + + /** + * Maximum page size. After this size is exceeded, the pages will be saved starting at the + * beginning of file. + */ + private final long maxSize; + + /** + * + * @param pageId + * @param windowIndex + */ + private void putWindowIndex(int pageId, int windowIndex) + { + if (idToWindowIndex != null && pageId != -1 && windowIndex != -1) + { + Integer oldPageId = windowIndexToPageId.remove(windowIndex); + if (oldPageId != null) + { + idToWindowIndex.remove(oldPageId); + } + idToWindowIndex.put(pageId, windowIndex); + windowIndexToPageId.put(windowIndex, pageId); + } + } + + /** + * + * @param pageId + */ + private void removeWindowIndex(int pageId) + { + Integer windowIndex = idToWindowIndex.remove(pageId); + if (windowIndex != null) + { + windowIndexToPageId.remove(windowIndex); + } + } + + /** + * + */ + private void rebuildIndices() + { + idToWindowIndex = null; + idToWindowIndex = new IntHashMap<Integer>(); + windowIndexToPageId = null; + windowIndexToPageId = new IntHashMap<Integer>(); + for (int i = 0; i < windows.size(); ++i) + { + FileWindow window = windows.get(i); + putWindowIndex(window.id, i); + } + } + + /** + * Returns the index of the given page in the {@link #windows} list. + * + * @param pageId + * @return window index + */ + private int getWindowIndex(int pageId) + { + if (idToWindowIndex == null) + { + rebuildIndices(); + } + + Integer result = idToWindowIndex.get(pageId); + return result != null ? result : -1; + } + + /** + * Increments the {@link #indexPointer}. If the maximum file size has been reached, the + * {@link #indexPointer} is set to 0. + * + * @return new index pointer + */ + private int incrementIndexPointer() + { + if ((maxSize > 0) && (totalSize >= maxSize) && (indexPointer == windows.size() - 1)) + { + indexPointer = 0; + } + else + { + ++indexPointer; + } + return indexPointer; + } + + /** + * Returns the offset in file of the window on given index. The offset is counted by getting the + * previous page offset and adding the previous page size to it. + * + * @param index + * @return window file offset + */ + private int getWindowFileOffset(int index) + { + if (index > 0) + { + FileWindow window = windows.get(index - 1); + return window.filePartOffset + window.filePartSize; + } + return 0; + } + + /** + * Splits the window with given index to two windows. First of those will have size specified by + * the argument, the other one will fill up the rest of the original window. + * + * @param index + * @param size + */ + private void splitWindow(int index, int size) + { + FileWindow window = windows.get(index); + int delta = window.filePartSize - size; + + if (index == windows.size() - 1) + { + // if this is last window + totalSize -= delta; + window.filePartSize = size; + } + else if (window.filePartSize != size) + { + FileWindow newWindow = new FileWindow(); + newWindow.id = -1; + window.filePartSize = size; + + windows.add(index + 1, newWindow); + + newWindow.filePartOffset = getWindowFileOffset(index + 1); + newWindow.filePartSize = delta; + } + + idToWindowIndex = null; + windowIndexToPageId = null; + } + + /** + * Merges the window with given index with the next window. The resulting window will have size + * of the two windows summed together. + * + * @param index + */ + private void mergeWindowWithNext(int index) + { + if (index < windows.size() - 1) + { + FileWindow window = windows.get(index); + FileWindow next = windows.get(index + 1); + window.filePartSize += next.filePartSize; + + windows.remove(index + 1); + idToWindowIndex = null; // reset index + windowIndexToPageId = null; + } + } + + /** + * Adjusts the window on given index to the specified size. If the new size is smaller than the + * window size, the window will be split. Otherwise the window will be merged with as many + * subsequent window as necessary. In case the window is last window in the file, the size will + * be adjusted without splitting or merging. + * + * @param index + * @param size + */ + private void adjustWindowSize(int index, int size) + { + FileWindow window = windows.get(index); + + // last window, just adjust size + if (index == windows.size() - 1) + { + int delta = size - window.filePartSize; + totalSize += delta; + window.filePartSize = size; + } + else + { + // merge as many times as necessary + while (window.filePartSize < size && index < windows.size() - 1) + { + mergeWindowWithNext(index); + } + + // done merging - do we have enough room ? + if (window.filePartSize < size) + { + // no, this is the last window + int delta = size - window.filePartSize; + totalSize += delta; + window.filePartSize = size; + } + else + { + // yes, we might want to split the window, so that we don't lose + // space when the created window was too big + splitWindow(index, size); + } + } + + window.id = -1; + } + + /** + * Allocates window on given index with to size. If the index is pointing to existing window, + * the window size will be adjusted. Otherwise a new window with appropriated size will be + * created. + * + * @param index + * @param size + * @return page window + */ + private FileWindow allocatePageWindow(int index, int size) + { + final FileWindow window; + + // new window + if (index == windows.size()) + { + // new page window + window = new FileWindow(); + window.filePartOffset = getWindowFileOffset(index); + totalSize += size; + window.filePartSize = size; + windows.add(window); + } + else + { + // get the window + window = windows.get(index); + + // adjust if necessary + if (window.filePartSize != size) + { + adjustWindowSize(index, size); + } + } + + return window; + } + + /** + * Creates and returns a new page window for given page. + * + * @param pageId + * @param type + * @param size + * @return page window + */ + public synchronized FileWindow createPageWindow(int pageId, Class<?> type, int size) + { + int index = getWindowIndex(pageId); + + // if we found the page window, mark it as invalid + if (index != -1) + { + removeWindowIndex(pageId); + (windows.get(index)).id = -1; + } + + // if we are not going to reuse a page window (because it's not on + // indexPointer position or because we didn't find it), increment the + // indexPointer + if (index == -1 || index != indexPointer) + { + index = incrementIndexPointer(); + } + + FileWindow window = allocatePageWindow(index, size); + window.id = pageId; + window.type = type.getName(); + + putWindowIndex(pageId, index); + return window; + } + + /** + * Returns the page window for given page or null if no window was found. + * + * @param pageId + * @return page window or null + */ + public synchronized FileWindow getPageWindow(int pageId) + { + int index = getWindowIndex(pageId); + if (index != -1) + { + return windows.get(index); + } + return null; + } + + /** + * Removes the page window for given page. + * + * @param pageId + */ + public synchronized void removePage(int pageId) + { + int index = getWindowIndex(pageId); + if (index != -1) + { + FileWindow window = windows.get(index); + removeWindowIndex(pageId); + if (index == windows.size() - 1) + { + windows.remove(index); + totalSize -= window.filePartSize; + if (indexPointer == index) + { + --indexPointer; + } + } + else + { + window.id = -1; + } + } + } + + /** + * Returns last n saved page windows. + * + * @return list of page windows + */ + public synchronized List<FileWindow> getFileWindows() + { + List<FileWindow> result = new ArrayList<FileWindow>(); + + // start from current index to 0 + int currentIndex = indexPointer; + + do + { + if (currentIndex == -1) + { + break; + } + + if (currentIndex < windows.size()) + { + FileWindow window = windows.get(currentIndex); + if (window.id != -1) + { + result.add(window); + } + } + + --currentIndex; + if (currentIndex == -1) + { + // rewind to the last entry and collect all entries until current index + currentIndex = windows.size() - 1; + } + } + while (currentIndex != indexPointer); + + return result; + } + + /** + * Creates a new PageWindowManager. + * + * @param maxSize + * maximum page size. After this size is exceeded, the pages will be saved starting + * at the beginning of file + */ + public PageWindowManager(long maxSize) + { + this.maxSize = maxSize; + } + + /** + * Returns the size of all saved pages + * + * @return total size + */ + public synchronized int getTotalSize() + { + return totalSize; + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java deleted file mode 100644 index fcc4f7a..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/HttpSessionDataStore.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * 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.pageStore.memory; - -import javax.servlet.http.HttpSession; - -import org.apache.wicket.Session; -import org.apache.wicket.page.IPageManagerContext; -import org.apache.wicket.pageStore.IDataStore; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A {@link IDataStore} which stores the pages in the {@link HttpSession}. Uses - * {@link IDataStoreEvictionStrategy} to keep the memory footprint reasonable. - * - * <p> - * Usage: - * - * <pre> - * <!--@formatter:off--> - * MyApp#init() - * { - * - * setPageManagerProvider(new DefaultPageManagerProvider(this) - * { - * protected IDataStore newDataStore() - * { - * return new HttpSessionDataStore(pageManagerContext, new PageNumberEvictionStrategy(20)); - * } - * } - * } - * <!--@formatter:on--> - * </pre> - */ -public class HttpSessionDataStore implements IDataStore -{ - private static final Logger LOG = LoggerFactory.getLogger(HttpSessionDataStore.class); - - /** the session attribute key. auto-prefixed with application.getSessionAttributePrefix() */ - private static final String PAGE_TABLE_KEY = "page:store:memory"; - - private final IPageManagerContext pageManagerContext; - - private final IDataStoreEvictionStrategy evictionStrategy; - - /** - * Construct. - * - * @param pageManagerContext - * @param evictionStrategy - */ - public HttpSessionDataStore(IPageManagerContext pageManagerContext, - IDataStoreEvictionStrategy evictionStrategy) - { - this.pageManagerContext = pageManagerContext; - this.evictionStrategy = evictionStrategy; - } - - /** - * @param sessionId - * Ignored. Only pages from the current http session can be read - * @see org.apache.wicket.pageStore.IDataStore#getData(java.lang.String, int) - */ - @Override - public byte[] getData(String sessionId, int pageId) - { - PageTable pageTable = getPageTable(false, false); - byte[] pageAsBytes = null; - if (pageTable != null) - { - pageAsBytes = pageTable.getPage(pageId); - } - - if (LOG.isDebugEnabled()) - { - int bytesLength = pageAsBytes != null ? pageAsBytes.length : -1; - LOG.debug("Loaded '{}' bytes for page with id '{}' in session '{}'", - bytesLength, pageId, sessionId); - } - - - return pageAsBytes; - } - - @Override - public void removeData(String sessionId, int pageId) - { - PageTable pageTable = getPageTable(false, true); - if (pageTable != null) - { - byte[] bytes = pageTable.removePage(pageId); - - if (LOG.isDebugEnabled() && bytes != null) - { - LOG.debug("Removed page '{}' in session '{}'", pageId, sessionId); - } - } - } - - @Override - public void removeData(String sessionId) - { - PageTable pageTable = getPageTable(false, true); - if (pageTable != null) - { - pageTable.clear(); - LOG.debug("Removed all pages in session '{}'", sessionId); - } - } - - @Override - public void storeData(String sessionId, int pageId, byte[] pageAsBytes) - { - PageTable pageTable = getPageTable(true, true); - if (pageTable != null) - { - pageTable.storePage(pageId, pageAsBytes); - if (LOG.isDebugEnabled()) - { - LOG.debug("Stored '{}' bytes for page '{}' in session '{}'", - pageAsBytes.length, pageId, sessionId); - } - evictionStrategy.evict(pageTable); - } - else - { - LOG.error("Cannot store the data for page with id '{}' in session with id '{}'", - pageId, sessionId); - } - } - - @Override - public void destroy() - { - // do nothing - // this is application lifecycle thread (WicketFilter#destroy()) - // so there is no reachable http session - } - - @Override - public boolean isReplicated() - { - return true; - } - - private PageTable getPageTable(boolean create, boolean rewriteToSession) - { - PageTable pageTable = null; - if (Session.exists()) - { - pageTable = (PageTable)pageManagerContext.getSessionAttribute(PAGE_TABLE_KEY); - if (pageTable == null && create) - { - pageTable = new PageTable(); - pageManagerContext.setSessionAttribute(PAGE_TABLE_KEY, pageTable); - } else if (rewriteToSession) { - pageManagerContext.setSessionAttribute(PAGE_TABLE_KEY, pageTable); - } - } - return pageTable; - } - - @Override - public final boolean canBeAsynchronous() - { - // HttpSessionDataStore needs access to the current http session - // and this is not possible in AsychronousDataStore - return false; - } - -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java deleted file mode 100644 index 6b6e556..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/IDataStoreEvictionStrategy.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.pageStore.memory; - - -/** - * An eviction strategy that decides whether the in-memory data structure used as page store should - * be compacted - */ -@FunctionalInterface -public interface IDataStoreEvictionStrategy -{ - - /** - * Called after each {@link org.apache.wicket.pageStore.IDataStore#storeData(String, int, byte[])} call. - * - * @param pageTable - * the in-memory data store with <strong>all</strong> pages - */ - void evict(PageTable pageTable); -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java deleted file mode 100644 index 92f985b..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/MemorySizeEvictionStrategy.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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.pageStore.memory; - -import org.apache.wicket.util.lang.Args; -import org.apache.wicket.util.lang.Bytes; -import org.apache.wicket.core.util.lang.WicketObjects; - -/** - * An eviction strategy that keeps the data store size up to configured bytes - */ -public class MemorySizeEvictionStrategy implements IDataStoreEvictionStrategy -{ - - private final Bytes maxBytes; - - /** - * Construct. - * - * @param maxBytes - * the maximum size of the data store - */ - public MemorySizeEvictionStrategy(Bytes maxBytes) - { - Args.notNull(maxBytes, "maxBytes"); - - this.maxBytes = maxBytes; - } - - /** - * - * @see IDataStoreEvictionStrategy#evict(org.apache.wicket.pageStore.memory.PageTable) - */ - @Override - public void evict(PageTable pageTable) - { - - long storeCurrentSize = WicketObjects.sizeof(pageTable); - - if (storeCurrentSize > maxBytes.bytes()) - { - PageTableCleaner cleaner = new PageTableCleaner(); - cleaner.drop(pageTable, 1); - - // recurse until enough space is cleaned - evict(pageTable); - } - } - -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java deleted file mode 100644 index 9857a6b..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageNumberEvictionStrategy.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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.pageStore.memory; - - -/** - * An eviction strategy which decides whether to evict entries from the in-memory data store - * depending on the number of stored paged per session - */ -public class PageNumberEvictionStrategy implements IDataStoreEvictionStrategy -{ - - private final int pagesNumber; - - /** - * Construct. - * - * @param pagesNumber - * the maximum number of pages the data store can hold - */ - public PageNumberEvictionStrategy(int pagesNumber) - { - if (pagesNumber < 1) - { - throw new IllegalArgumentException("'pagesNumber' must be greater than 0."); - } - - this.pagesNumber = pagesNumber; - } - - /** - * - * @see IDataStoreEvictionStrategy#evict(org.apache.wicket.pageStore.memory.PageTable) - */ - @Override - public void evict(PageTable pageTable) - { - int size = pageTable.size(); - int pagesToDrop = size - pagesNumber; - - if (pagesToDrop > 0) - { - PageTableCleaner cleaner = new PageTableCleaner(); - cleaner.drop(pageTable, pagesToDrop); - } - } - -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java deleted file mode 100644 index dfad4af..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTable.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * 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.pageStore.memory; - -import java.util.Iterator; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentMap; - -import org.apache.wicket.util.io.IClusterable; - -/** - * A structure that holds page id => pageAsBytes. - * - * <p> - * Additionally it has an index of the least recently used pages - */ -public class PageTable implements IClusterable -{ - private static final long serialVersionUID = 1L; - - /** - * Holds the index of last/least recently used page ids. The most recently used page id is in - * the tail, the least recently used is in the head. - */ - /* - * Can be replaced later with PriorityQueue to deal with lightweight (Ajax) and heavyweight - * pages - */ - private final Queue<Integer> index; - - /** - * The actual container for the pages. - * - * <p> - * page id => page as bytes - */ - private final ConcurrentMap<Integer, byte[]> pages; - - public PageTable() - { - pages = new ConcurrentHashMap<>(); - index = new ConcurrentLinkedQueue<>(); - } - - public void storePage(Integer pageId, byte[] pageAsBytes) - { - synchronized (index) - { - pages.put(pageId, pageAsBytes); - - updateIndex(pageId); - } - } - - public byte[] getPage(final Integer pageId) - { - synchronized (index) - { - updateIndex(pageId); - - return pages.get(pageId); - } - } - - public byte[] removePage(Integer pageId) - { - synchronized (index) - { - index.remove(pageId); - - return pages.remove(pageId); - } - } - - public void clear() - { - synchronized (index) - { - index.clear(); - pages.clear(); - } - } - - public int size() - { - return pages.size(); - } - - public Integer getOldest() - { - return index.peek(); - } - - public Iterator<Integer> indexIterator() - { - return index.iterator(); - } - - /** - * Updates the index of last/least recently used pages by removing the page id from the index - * (in case it is already in) and (re-)adding it at the head - * - * @param pageId - * the id of a recently used page - */ - private void updateIndex(Integer pageId) - { - index.remove(pageId); - index.offer(pageId); - } - -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java b/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java deleted file mode 100644 index 2c9a9cb..0000000 --- a/wicket-core/src/main/java/org/apache/wicket/pageStore/memory/PageTableCleaner.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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.pageStore.memory; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Helper class that knows how to remove the nth oldest pages from {@link PageTable} - */ -public class PageTableCleaner -{ - private static final Logger LOG = LoggerFactory.getLogger(PageTableCleaner.class); - - /** - * Removes {@code pagesNumber} of pages from the {@link PageTable pageTable} - * - * @param pageTable - * the {@link PageTable} to clean - * @param pagesNumber - * the number of pages to remove - */ - public void drop(final PageTable pageTable, final int pagesNumber) - { - for (int i = 0; i < pagesNumber; i++) - { - Integer pageIdOfTheOldest = pageTable.getOldest(); - pageTable.removePage(pageIdOfTheOldest); - LOG.debug("Evicted page with id '{}' from the HttpSessionDataStore"); - } - } -} http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java index 8852208..63a5499 100644 --- a/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java +++ b/wicket-core/src/main/java/org/apache/wicket/settings/StoreSettings.java @@ -50,8 +50,6 @@ public class StoreSettings private static final int DEFAULT_ASYNCHRONOUS_QUEUE_CAPACITY = 100; - private int inmemoryCacheSize = DEFAULT_CACHE_SIZE; - private Bytes maxSizePerSession = DEFAULT_MAX_SIZE_PER_SESSION; private File fileStoreFolder = null; @@ -70,30 +68,6 @@ public class StoreSettings } /** - * @return the number of page instances which will be stored in the application scoped cache for - * faster retrieval - */ - public int getInmemoryCacheSize() - { - return inmemoryCacheSize; - } - - /** - * Sets the maximum number of page instances which will be stored in the application scoped - * second level cache for faster retrieval - * - * @param inmemoryCacheSize - * the maximum number of page instances which will be held in the application scoped - * cache - * @return {@code this} object for chaining - */ - public StoreSettings setInmemoryCacheSize(int inmemoryCacheSize) - { - this.inmemoryCacheSize = inmemoryCacheSize; - return this; - } - - /** * @return maximum page size. After this size is exceeded, * the {@link org.apache.wicket.pageStore.DiskDataStore} will start saving the * pages at the beginning of file. http://git-wip-us.apache.org/repos/asf/wicket/blob/bcf76f51/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java ---------------------------------------------------------------------- diff --git a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java index 54e7808..4012a5f 100644 --- a/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java +++ b/wicket-core/src/main/java/org/apache/wicket/util/tester/BaseWicketTester.java @@ -92,11 +92,11 @@ import org.apache.wicket.markup.html.list.ListView; import org.apache.wicket.markup.parser.XmlPullParser; import org.apache.wicket.markup.parser.XmlTag; import org.apache.wicket.mock.MockApplication; -import org.apache.wicket.mock.MockPageManager; +import org.apache.wicket.mock.MockPageStore; import org.apache.wicket.mock.MockRequestParameters; import org.apache.wicket.model.PropertyModel; import org.apache.wicket.page.IPageManager; -import org.apache.wicket.page.IPageManagerContext; +import org.apache.wicket.page.PageManager; import org.apache.wicket.protocol.http.AjaxEnclosureListener; import org.apache.wicket.protocol.http.IMetaDataBufferingWebResponse; import org.apache.wicket.protocol.http.WebApplication; @@ -2926,9 +2926,9 @@ public class BaseWicketTester private static class TestPageManagerProvider implements IPageManagerProvider { @Override - public IPageManager apply(IPageManagerContext pageManagerContext) + public IPageManager get() { - return new MockPageManager(); + return new PageManager(new MockPageStore()); } }
