⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 filechannelpool.java

📁 Wicket一个开发Java Web应用程序框架。它使得开发web应用程序变得容易而轻松。 Wicket利用一个POJO data beans组件使得它可以与任何持久层技术相结合。
💻 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.FileNotFoundException;import java.io.IOException;import java.io.RandomAccessFile;import java.nio.channels.FileChannel;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.Map;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;/** * Thread safe pool of {@link FileChannel} objects. * <p> * Opening and closing file is an expensive operation and under certain circumstances this can * significantly harm performances, because on every close the file system cache might be flushed. * <p> * To minimize the negative impact opened files can be pooled, which is a responsibility of * {@link FileChannelPool} class. * <p> * {@link FileChannelPool} allows to specify maximum number of opened {@link FileChannel}s. * <p> * Note that under certain circumstances (when there are no empty slots in pool) the initial * capacity can be exceeded (more files are opened then the specified capacity is). If this happens, * a warning is written to log, as this probably means that there is a problem with page store. *  * @author Matej Knopp */public class FileChannelPool{	private final Map /* <String, FileChannel> */nameToChannel = new HashMap();	private final Map /* <FileChannel, String> */channelToName = new HashMap();	private final Map /* <FileChannel, Integer> */channelToUseCount = new HashMap();	private final LinkedList /* <FileChannel> */idleChannels = new LinkedList();	private final Set /* <FileChannel> */channelsToDeleteOnReturn = new HashSet();	private final int capacity;	/**	 * Construct.	 * 	 * @param capacity	 *            Maximum number of opened file channels.	 */	public FileChannelPool(int capacity)	{		this.capacity = capacity;		if (capacity < 1)		{			throw new IllegalArgumentException("Capacity must be at least one.");		}		log.debug("Starting file channel pool with capacity of " + capacity + " channels");	};	/**	 * Creates a new file channel with specified file name.	 * 	 * @param fileName	 * @param createIfDoesNotExist	 *            in case the file does not exist this parameter determines if the file should be	 *            created	 * @return	 */	private FileChannel newFileChannel(String fileName, boolean createIfDoesNotExist)	{		File file = new File(fileName);		if (file.exists() == false && createIfDoesNotExist == false)		{			return null;		}		try		{			FileChannel channel = new RandomAccessFile(file, "rw").getChannel();			return channel;		}		catch (FileNotFoundException e)		{			throw new RuntimeException(e);		}	}	/**	 * Tries to reduce (close) enough channels to have at least one channel free (so that there are	 * maximum capacity - 1 opened channel).	 */	private void reduceChannels()	{		// how much channels we need to close?		int channelsToReduce = nameToChannel.size() - capacity + 1;		// while there are still channels to close and we have still idle		// channels left		while (channelsToReduce > 0 && idleChannels.isEmpty() == false)		{			FileChannel channel = (FileChannel)idleChannels.getFirst();			String channelName = (String)channelToName.get(channel);			// remove oldest idle channel			idleChannels.removeFirst();			nameToChannel.remove(channelName);			channelToName.remove(channel);			// this shouldn't really happen			if (channelToUseCount.get(channel) != null)			{				log.warn("Channel " + channelName + " is both idle and in use at the same time!");				channelToUseCount.remove(channel);			}			try			{				channel.close();			}			catch (IOException e)			{				log.error("Error closing file channel", e);			}			--channelsToReduce;		}		if (channelsToReduce > 0)		{			log.warn("Unable to reduce enough channels, no idle channels left to remove.");		}	}	/**	 * Returns a channel for given file. If the file doesn't exist, the createIfDoesNotExit	 * attribute specifies if the file should be created.	 * 	 * Do NOT call close on the returned chanel. Instead call	 * {@link #returnFileChannel(FileChannel)}	 * 	 * @param fileName	 * @param createIfDoesNotExist	 * @return	 */	public synchronized FileChannel getFileChannel(String fileName, boolean createIfDoesNotExist)	{		FileChannel channel = (FileChannel)nameToChannel.get(fileName);		if (channel == null)		{			channel = newFileChannel(fileName, createIfDoesNotExist);			if (channel != null)			{				// we need to create new channel				// first, check how many channels we have already opened				if (nameToChannel.size() >= capacity)				{					reduceChannels();				}				nameToChannel.put(fileName, channel);				channelToName.put(channel, fileName);			}		}		if (channel != null)		{			// increase the usage count for this channel			Integer count = (Integer)channelToUseCount.get(channel);			if (count == null || count.intValue() == 0)			{				channelToUseCount.put(channel, new Integer(1));				idleChannels.remove(channel);			}			else			{				count = new Integer(count.intValue() + 1);				channelToUseCount.put(channel, count);			}		}		return channel;	}	/**	 * Returns the channel to the pool. It is necessary to call this for every channel obtained by	 * calling {@link #getFileChannel(String, boolean)}.	 * 	 * @param channel	 */	public synchronized void returnFileChannel(FileChannel channel)	{		Integer count = (Integer)channelToUseCount.get(channel);		if (count == null || count.intValue() == 0)		{			throw new IllegalArgumentException("Trying to return unused channel");		}		count = new Integer(count.intValue() - 1);		// decrease the usage count		if (count.intValue() == 0)		{			channelToUseCount.remove(channel);			if (channelsToDeleteOnReturn.contains(channel))			{				closeAndDelete(channel);			}			else			{				// this was the last usage, add chanel to idle channels				idleChannels.addLast(channel);			}		}		else		{			channelToUseCount.put(channel, count);		}	}	private void closeAndDelete(FileChannel channel)	{		channelsToDeleteOnReturn.remove(channel);		String name = (String)channelToName.get(channel);		channelToName.remove(channel);		channelToUseCount.remove(channel);		idleChannels.remove(channel);		try		{			channel.close();		}		catch (IOException e)		{			log.error("Error closing file channel", e);		}		File file = new File(name);		file.delete();	}	/**	 * Closes the file channel with given name and removes it from pool. Also removes the file from	 * file system. If the channel is in use, the pool first waits until the chanel is returned to	 * the pool and then closes it.	 * 	 * @param name	 */	public synchronized void closeAndDeleteFileChannel(String name)	{		FileChannel channel = (FileChannel)nameToChannel.get(name);		if (channel != null)		{			nameToChannel.remove(name);			Integer count = (Integer)channelToUseCount.get(channel);			if (count != null && count.intValue() > 0)			{				channelsToDeleteOnReturn.add(channel);			}			else			{				closeAndDelete(channel);			}		}		else		{			File file = new File(name);			file.delete();		}	}	/**	 * Destroys the {@link FileChannel} pool and closes all opened channels.	 */	public synchronized void destroy()	{		log.debug("Destroying FileChannel pool");		for (Iterator i = channelToName.keySet().iterator(); i.hasNext();)		{			FileChannel channel = (FileChannel)i.next();			try			{				channel.close();			}			catch (IOException e)			{				log.error("Error closing file channel", e);			}		}	}	private static final Logger log = LoggerFactory.getLogger(FileChannelPool.class);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -