| /******************************************************************************* |
| * Copyright (c) 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.osgi.baseadaptor.bundlefile; |
| |
| import java.io.IOException; |
| |
| /** |
| * A simple/quick/small implementation of an MRU (Most Recently Used) list to keep |
| * track of open BundleFiles. The MRU will use the file limit specified by the property |
| * "osgi.bundlefile.limit" by default unless the MRU is constructed with a specific |
| * file limit. |
| */ |
| public class MRUBundleFileList { |
| private static final String PROP_FILE_LIMIT = "osgi.bundlefile.limit"; //$NON-NLS-1$ |
| private static final int MIN = 10; |
| // list of open bundle files |
| private BundleFile[] bundleFileList; |
| // list of open bundle files use stamps |
| private long[] useStampList; |
| // the current use stamp |
| private long curUseStamp = 0; |
| // the limit of open files to allow before least used bundle file is closed |
| private int fileLimit = 0; // value < MIN will disable MRU |
| // the current number of open bundle files |
| private int numOpen = 0; |
| |
| public MRUBundleFileList() { |
| try { |
| String prop = BundleFile.secureAction.getProperty(PROP_FILE_LIMIT); |
| if (prop != null) |
| init(Integer.parseInt(prop)); |
| } catch (NumberFormatException e) { |
| //MRU will be disabled |
| } |
| } |
| |
| public MRUBundleFileList(int fileLimit) { |
| init(fileLimit); |
| } |
| |
| private void init(int initFileLimit) { |
| // only enable the MRU if the initFileLimit is > MIN |
| if (initFileLimit >= MIN) { |
| this.fileLimit = initFileLimit; |
| this.bundleFileList = new BundleFile[initFileLimit]; |
| this.useStampList = new long[initFileLimit]; |
| } |
| } |
| |
| /** |
| * Adds a BundleFile which is about to be opened to the MRU list. If |
| * the number of open BundleFiles == the fileLimit then the least |
| * recently used BundleFile is closed. |
| * @param bundleFile the bundle file about to be opened. |
| * @throws IOException if an error occurs while closing the least recently used BundleFile |
| */ |
| public void add(BundleFile bundleFile) throws IOException { |
| if (fileLimit < MIN) |
| return; // MRU is disabled |
| synchronized (bundleFileList) { |
| int index = 0; // default to the first slot |
| if (numOpen < fileLimit) { |
| // numOpen does not exceed the fileLimit |
| // find the first null slot to use in the MRU |
| for (int i = 0; i < fileLimit; i++) |
| if (bundleFileList[i] == null) { |
| index = i; |
| break; |
| } |
| } else { |
| // numOpen has reached the fileLimit |
| // find the least recently used bundleFile and close it |
| // and use it slot for the new bundleFile to be opened. |
| index = 0; |
| for (int i = 1; i < fileLimit; i++) |
| if (useStampList[i] < useStampList[index]) |
| index = i; |
| BundleFile toRemove = bundleFileList[index]; |
| remove(toRemove); |
| toRemove.close(); |
| } |
| // found an index to place to bundleFile to be opened |
| bundleFileList[index] = bundleFile; |
| bundleFile.setMruIndex(index); |
| incUseStamp(index); |
| numOpen++; |
| } |
| } |
| |
| /** |
| * Removes a bundle file which is about to be closed |
| * @param bundleFile the bundle file about to be closed |
| * @return true if the bundleFile existed in the MRU; false otherwise |
| */ |
| public boolean remove(BundleFile bundleFile) { |
| if (fileLimit < MIN) |
| return false; // MRU is disabled |
| synchronized (bundleFileList) { |
| int index = bundleFile.getMruIndex(); |
| if ((index >= 0 || index < fileLimit) && bundleFileList[index] == bundleFile) { |
| bundleFileList[index] = null; |
| useStampList[index] = -1; |
| numOpen--; |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Increments the use stamp of a bundle file |
| * @param bundleFile the bundle file to increment the use stamp for |
| */ |
| public void use(BundleFile bundleFile) { |
| if (fileLimit < MIN) |
| return; // MRU is disabled |
| synchronized (bundleFileList) { |
| int index = bundleFile.getMruIndex(); |
| if ((index >= 0 || index < fileLimit) && bundleFileList[index] == bundleFile) |
| incUseStamp(index); |
| } |
| } |
| |
| private void incUseStamp(int index) { |
| if (curUseStamp == Long.MAX_VALUE) { |
| // we hit the curUseStamp max better reset all the stamps |
| for (int i = 0; i < fileLimit; i++) |
| useStampList[i] = 0; |
| curUseStamp = 0; |
| } |
| useStampList[index] = ++curUseStamp; |
| } |
| } |