1 package org.apache.lucene.search;
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership.
7 * The ASF licenses this file to You under the Apache License, Version 2.0
8 * (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
20 import java.util.Comparator;
21 import java.util.Date;
22 import java.util.HashMap;
23 import java.util.Iterator;
25 import java.util.TreeSet;
27 import org.apache.lucene.util.ThreadInterruptedException;
30 * Filter caching singleton. It can be used to save filters locally for reuse.
31 * This class makes it possible to cache Filters even when using RMI, as it
32 * keeps the cache on the searcher side of the RMI connection.
34 * Also could be used as a persistent storage for any filter as long as the
35 * filter provides a proper hashCode(), as that is used as the key in the cache.
37 * The cache is periodically cleaned up from a separate thread to ensure the
38 * cache doesn't exceed the maximum size.
40 * @deprecated used by remote package which is deprecated as well. You should
41 * use {@link CachingWrapperFilter} if you wish to cache
45 public class FilterManager {
47 protected static FilterManager manager;
49 /** The default maximum number of Filters in the cache */
50 protected static final int DEFAULT_CACHE_CLEAN_SIZE = 100;
51 /** The default frequency of cache cleanup */
52 protected static final long DEFAULT_CACHE_SLEEP_TIME = 1000 * 60 * 10;
54 /** The cache itself */
55 protected Map<Integer,FilterItem> cache;
56 /** Maximum allowed cache size */
57 protected int cacheCleanSize;
58 /** Cache cleaning frequency */
59 protected long cleanSleepTime;
60 /** Cache cleaner that runs in a separate thread */
61 protected FilterCleaner filterCleaner;
63 public synchronized static FilterManager getInstance() {
64 if (manager == null) {
65 manager = new FilterManager();
71 * Sets up the FilterManager singleton.
73 protected FilterManager() {
74 cache = new HashMap<Integer,FilterItem>();
75 cacheCleanSize = DEFAULT_CACHE_CLEAN_SIZE; // Let the cache get to 100 items
76 cleanSleepTime = DEFAULT_CACHE_SLEEP_TIME; // 10 minutes between cleanings
78 filterCleaner = new FilterCleaner();
79 Thread fcThread = new Thread(filterCleaner);
80 // set to be a Daemon so it doesn't have to be stopped
81 fcThread.setDaemon(true);
86 * Sets the max size that cache should reach before it is cleaned up
87 * @param cacheCleanSize maximum allowed cache size
89 public void setCacheSize(int cacheCleanSize) {
90 this.cacheCleanSize = cacheCleanSize;
94 * Sets the cache cleaning frequency in milliseconds.
95 * @param cleanSleepTime cleaning frequency in milliseconds
97 public void setCleanThreadSleepTime(long cleanSleepTime) {
98 this.cleanSleepTime = cleanSleepTime;
102 * Returns the cached version of the filter. Allows the caller to pass up
103 * a small filter but this will keep a persistent version around and allow
104 * the caching filter to do its job.
106 * @param filter The input filter
107 * @return The cached version of the filter
109 public Filter getFilter(Filter filter) {
110 synchronized(cache) {
111 FilterItem fi = null;
112 fi = cache.get(Integer.valueOf(filter.hashCode()));
114 fi.timestamp = new Date().getTime();
117 cache.put(Integer.valueOf(filter.hashCode()), new FilterItem(filter));
123 * Holds the filter and the last time the filter was used, to make LRU-based
124 * cache cleaning possible.
125 * TODO: Clean this up when we switch to Java 1.5
127 protected class FilterItem {
128 public Filter filter;
129 public long timestamp;
131 public FilterItem (Filter filter) {
132 this.filter = filter;
133 this.timestamp = new Date().getTime();
139 * Keeps the cache from getting too big.
140 * If we were using Java 1.5, we could use LinkedHashMap and we would not need this thread
141 * to clean out the cache.
143 * The SortedSet sortedFilterItems is used only to sort the items from the cache,
144 * so when it's time to clean up we have the TreeSet sort the FilterItems by
147 * Removes 1.5 * the numbers of items to make the cache smaller.
149 * If cache clean size is 10, and the cache is at 15, we would remove (15 - 10) * 1.5 = 7.5 round up to 8.
150 * This way we clean the cache a bit more, and avoid having the cache cleaner having to do it frequently.
152 protected class FilterCleaner implements Runnable {
154 private boolean running = true;
155 private TreeSet<Map.Entry<Integer,FilterItem>> sortedFilterItems;
157 public FilterCleaner() {
158 sortedFilterItems = new TreeSet<Map.Entry<Integer,FilterItem>>(new Comparator<Map.Entry<Integer,FilterItem>>() {
159 public int compare(Map.Entry<Integer,FilterItem> a, Map.Entry<Integer,FilterItem> b) {
160 FilterItem fia = a.getValue();
161 FilterItem fib = b.getValue();
162 if ( fia.timestamp == fib.timestamp ) {
165 // smaller timestamp first
166 if ( fia.timestamp < fib.timestamp ) {
169 // larger timestamp last
179 // sort items from oldest to newest
180 // we delete the oldest filters
181 if (cache.size() > cacheCleanSize) {
182 // empty the temporary set
183 sortedFilterItems.clear();
184 synchronized (cache) {
185 sortedFilterItems.addAll(cache.entrySet());
186 Iterator<Map.Entry<Integer,FilterItem>> it = sortedFilterItems.iterator();
187 int numToDelete = (int) ((cache.size() - cacheCleanSize) * 1.5);
189 // loop over the set and delete all of the cache entries not used in a while
190 while (it.hasNext() && counter++ < numToDelete) {
191 Map.Entry<Integer,FilterItem> entry = it.next();
192 cache.remove(entry.getKey());
195 // empty the set so we don't tie up the memory
196 sortedFilterItems.clear();
200 Thread.sleep(cleanSleepTime);
201 } catch (InterruptedException ie) {
202 throw new ThreadInterruptedException(ie);