📄 diskpagestore.java
字号:
/* * 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.protocol.http.pagestore;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.OutputStream;import java.io.Serializable;import java.nio.ByteBuffer;import java.nio.channels.FileChannel;import java.util.ArrayList;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Map.Entry;import org.apache.wicket.Application;import org.apache.wicket.Page;import org.apache.wicket.WicketRuntimeException;import org.apache.wicket.protocol.http.WebApplication;import org.apache.wicket.protocol.http.SecondLevelCacheSessionStore.IPageStore;import org.apache.wicket.protocol.http.SecondLevelCacheSessionStore.ISerializationAwarePageStore;import org.apache.wicket.protocol.http.pagestore.PageWindowManager.PageWindow;import org.apache.wicket.protocol.http.pagestore.SerializedPagesCache.SerializedPageWithSession;import org.apache.wicket.util.concurrent.ConcurrentHashMap;import org.apache.wicket.util.lang.Bytes;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * {@link IPageStore} implementation that stores the serialized pages grouped in a single file per * pagemap. * <p> * This store was designed to overcome the problems of {@link FilePageStore} which stores the pages * in separate files per page. * <p> * {@link DiskPageStore} allows to set maximum size for pagemap file and maximum size for session. * If the maximum size for session is exceeded, the last recently used pagemap file is removed. * * @author Matej Knopp */public class DiskPageStore extends AbstractPageStore implements ISerializationAwarePageStore{ /** * Each PageMap is represented by this class. * * @author Matej Knopp */ protected static class PageMapEntry implements Serializable { private static final long serialVersionUID = 1L; private String pageMapName; private String fileName; private PageWindowManager manager; /** * @return the name of pagemap */ public String getPageMapName() { return pageMapName; } /** * @return path of file that contains serialized pages in this pagemap */ public String getFileName() { return fileName; } /** * @return manager that maintains information about pages inside the file */ public PageWindowManager getManager() { return manager; } } /** * Represents a session, * * @author Matej Knopp */ protected static class SessionEntry implements Serializable { private static final long serialVersionUID = 1L; private String sessionId; private final List pageMapEntryList = new ArrayList(); private transient DiskPageStore diskPageStore; protected SessionEntry(DiskPageStore diskPageStore) { this.diskPageStore = diskPageStore; } /** * @return session id */ public String getSessionId() { return sessionId; } /** * @return summed size of all pagemap files */ public int getTotalSize() { int result = 0; for (Iterator i = pageMapEntryList.iterator(); i.hasNext();) { PageMapEntry entry = (PageMapEntry)i.next(); if (entry.manager != null) { result += entry.manager.getTotalSize(); } } return result; } /** * @return list of {@link PageMapEntry} for this session */ public List /* <PageMapEntry> */getPageMapEntryList() { return Collections.unmodifiableList(pageMapEntryList); } /** * Returns a {@link PageMapEntry} for specified pagemap. If the create attribute is set and * the pagemap does not exist, new {@link PageMapEntry} will be created. * * @param pageMapName * @param create * @return */ public PageMapEntry getPageMapEntry(String pageMapName, boolean create) { PageMapEntry result = null; for (Iterator i = pageMapEntryList.iterator(); i.hasNext();) { PageMapEntry entry = (PageMapEntry)i.next(); if (entry.pageMapName == pageMapName || (entry.pageMapName != null && entry.pageMapName.equals(pageMapName))) { result = entry; } } if (result == null && create) { result = new PageMapEntry(); result.pageMapName = pageMapName; result.fileName = diskPageStore.getPageMapFileName(sessionId, pageMapName, true); result.manager = new PageWindowManager(diskPageStore.getMaxSizePerPageMap()); pageMapEntryList.add(result); } return result; } /** * Removes the pagemap entry and deletes the file. * * @param entry */ private void removePageMapEntry(PageMapEntry entry) { diskPageStore.fileChannelPool.closeAndDeleteFileChannel(entry.fileName); pageMapEntryList.remove(entry); } /** * Removes the specified pagemap and deletes the file. * * @param pageMapName */ public synchronized void removePageMap(String pageMapName) { PageMapEntry entry = getPageMapEntry(pageMapName, false); if (entry != null) { removePageMapEntry(entry); } } /** * Saves the serialized page to appropriate pagemap file. * * @param page */ public synchronized void savePage(SerializedPage page) { // only save page that has some data if (page.getData() != null) { PageMapEntry entry = getPageMapEntry(page.getPageMapName(), true); // allocate window for page PageWindow window = entry.manager.createPageWindow(page.getPageId(), page.getVersionNumber(), page.getAjaxVersionNumber(), page.getData().length); // remove the entry and add it to the end of entry list (to mark // it as last accessed( pageMapEntryList.remove(entry); pageMapEntryList.add(entry); // if we exceeded maximum session size, try to remove as many // pagemap as necessary and possible while (getTotalSize() > diskPageStore.getMaxSizePerSession() && pageMapEntryList.size() > 1) { removePageMapEntry((PageMapEntry)pageMapEntryList.get(0)); } // take the filechannel from the pool FileChannel channel = diskPageStore.fileChannelPool.getFileChannel(entry.fileName, true); try { // write the content channel.write(ByteBuffer.wrap(page.getData()), window.getFilePartOffset()); } catch (IOException e) { log.error("Error writing to a channel " + channel, e); } finally { // return the "borrowed" file channel diskPageStore.fileChannelPool.returnFileChannel(channel); } } } /** * Removes the page from pagemap file. * * @param pageMapName * @param pageId */ public synchronized void removePage(String pageMapName, int pageId) { PageMapEntry entry = getPageMapEntry(pageMapName, false); if (entry != null) { entry.manager.removePage(pageId); } } /** * Loads the part of pagemap file specified by the given PageWindow. * * @param window * @param pageMapFileName * @return */ public byte[] loadPage(PageWindow window, String pageMapFileName) { byte[] result = null; FileChannel channel = diskPageStore.fileChannelPool.getFileChannel(pageMapFileName, false); if (channel != null) { ByteBuffer buffer = ByteBuffer.allocate(window.getFilePartSize()); try { channel.read(buffer, window.getFilePartOffset()); if (buffer.hasArray()) { result = buffer.array(); } } catch (IOException e) { log.error("Error reading from file channel " + channel, e); } finally { diskPageStore.fileChannelPool.returnFileChannel(channel); } } return result; } /** * Loads the specified page data. * * @param pageMapName * @param id * @param versionNumber * @param ajaxVersionNumber * @return page data or null if the page is no longer in pagemap file */ public synchronized byte[] loadPage(String pageMapName, int id, int versionNumber, int ajaxVersionNumber) { byte[] result = null; PageMapEntry entry = getPageMapEntry(pageMapName, false); if (entry != null) { PageWindow window = entry.manager.getPageWindow(id, versionNumber, ajaxVersionNumber); if (window != null) { result = loadPage(window, entry.fileName); } } return result; } /** * Deletes all files for this session. */ public synchronized void unbind() { while (pageMapEntryList.size() > 0) { removePageMapEntry((PageMapEntry)pageMapEntryList.get(pageMapEntryList.size() - 1)); } File sessionFolder = diskPageStore.getSessionFolder(sessionId, false); if (sessionFolder.exists()) { sessionFolder.delete(); } } /** * Returns true if the given page exists for specified pageMap * * @param pageMapName * @param pageId * @param versionNumber * @return */ public synchronized boolean exists(String pageMapName, int pageId, int versionNumber) { PageMapEntry entry = getPageMapEntry(pageMapName, false); return entry != null && entry.getManager().getPageWindow(pageId, versionNumber, -1) != null; } } private File getStoreFolder() { File storeFolder = new File(fileStoreFolder, appName + "-filestore"); return storeFolder; } /** * Returns the folder for the specified sessions. If the folder doesn't exist and the create * flag is set, the folder will be created. * * @param sessionId * @param create * @return */ private File getSessionFolder(String sessionId, boolean create) { File storeFolder = getStoreFolder(); File sessionFolder = new File(storeFolder, sessionId); if (create && sessionFolder.exists() == false) { mkdirs(sessionFolder); } return sessionFolder; } /** * Utility method for creating a directory * * @param file */ private void mkdirs(File file) { // for some reason, simple file.mkdirs sometimes fails under heavy load for (int j = 0; j < 5; ++j) { for (int i = 0; i < 10; ++i) { if (file.mkdirs()) { return; } } try { Thread.sleep(100); } catch (InterruptedException ignore) { } } log.error("Failed to make directory " + file); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -