Welcome to mirror list, hosted at ThFree Co, Russian Federation.

FilterManager.cs « Search « core « src - github.com/mono/Lucene.Net.Light.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1afdc0b924892d3613e161f3ab10ac17d723afc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
/* 
 * 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.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using Lucene.Net.Support;

namespace Lucene.Net.Search
{
	
	/// <summary> Filter caching singleton.  It can be used 
	/// to save filters locally for reuse.
	/// This class makes it possble to cache Filters even when using RMI, as it
	/// keeps the cache on the seaercher side of the RMI connection.
	/// 
	/// Also could be used as a persistent storage for any filter as long as the
	/// filter provides a proper hashCode(), as that is used as the key in the cache.
	/// 
	/// The cache is periodically cleaned up from a separate thread to ensure the
	/// cache doesn't exceed the maximum size.
	/// </summary>
	public class FilterManager
	{
		
		protected internal static FilterManager manager;
		
		/// <summary>The default maximum number of Filters in the cache </summary>
		protected internal const int DEFAULT_CACHE_CLEAN_SIZE = 100;
		/// <summary>The default frequency of cache clenup </summary>
		protected internal const long DEFAULT_CACHE_SLEEP_TIME = 1000 * 60 * 10;
		
		/// <summary>The cache itself </summary>
		protected internal IDictionary<int, FilterItem> cache;
		/// <summary>Maximum allowed cache size </summary>
		protected internal int cacheCleanSize;
		/// <summary>Cache cleaning frequency </summary>
		protected internal long cleanSleepTime;
		/// <summary>Cache cleaner that runs in a separate thread </summary>
		protected internal FilterCleaner internalFilterCleaner;

	    private static readonly object _staticSyncObj = new object();
	    public static FilterManager Instance
	    {
	        get
	        {
	            lock (_staticSyncObj)
	            {
	                return manager ?? (manager = new FilterManager());
	            }
	        }
	    }

	    /// <summary> Sets up the FilterManager singleton.</summary>
		protected internal FilterManager()
		{
			cache = new HashMap<int, FilterItem>();
			cacheCleanSize = DEFAULT_CACHE_CLEAN_SIZE; // Let the cache get to 100 items
			cleanSleepTime = DEFAULT_CACHE_SLEEP_TIME; // 10 minutes between cleanings
			
			internalFilterCleaner = new FilterCleaner(this);
			ThreadClass fcThread = new ThreadClass(new System.Threading.ThreadStart(internalFilterCleaner.Run));
			// setto be a Daemon so it doesn't have to be stopped
			fcThread.IsBackground = true;
			fcThread.Start();
		}

	    /// <summary> Sets the max size that cache should reach before it is cleaned up</summary>
	    /// <param name="value"> maximum allowed cache size </param>
	    public virtual void SetCacheSize(int value)
	    {
	        this.cacheCleanSize = value;
	    }

	    /// <summary> Sets the cache cleaning frequency in milliseconds.</summary>
	    /// <param name="value"> cleaning frequency in millioseconds </param>
	    public virtual void SetCleanThreadSleepTime(long value)
	    {
	        this.cleanSleepTime = value;
	    }

	    /// <summary> Returns the cached version of the filter.  Allows the caller to pass up
		/// a small filter but this will keep a persistent version around and allow
		/// the caching filter to do its job.
		/// 
		/// </summary>
		/// <param name="filter">The input filter
		/// </param>
		/// <returns> The cached version of the filter
		/// </returns>
		public virtual Filter GetFilter(Filter filter)
		{
			lock (cache)
			{
				FilterItem fi = null;
				fi = cache[filter.GetHashCode()];
				if (fi != null)
				{
					fi.timestamp = System.DateTime.UtcNow.Ticks;
					return fi.filter;
				}
				cache[filter.GetHashCode()] = new FilterItem(filter);
				return filter;
			}
		}
		
		/// <summary> Holds the filter and the last time the filter was used, to make LRU-based
		/// cache cleaning possible.
		/// TODO: Clean this up when we switch to Java 1.5
		/// </summary>
		protected internal class FilterItem
		{
			public Filter filter;
			public long timestamp;
			
			public FilterItem(Filter filter)
			{
				this.filter = filter;
				this.timestamp = System.DateTime.UtcNow.Ticks;
			}
		}
		
		
		/// <summary> Keeps the cache from getting too big.
		/// If we were using Java 1.5, we could use LinkedHashMap and we would not need this thread
		/// to clean out the cache.
		/// 
		/// The SortedSet sortedFilterItems is used only to sort the items from the cache,
		/// so when it's time to clean up we have the TreeSet sort the FilterItems by
		/// timestamp.
		/// 
		/// Removes 1.5 * the numbers of items to make the cache smaller.
		/// For example:
		/// 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.
		/// This way we clean the cache a bit more, and avoid having the cache cleaner having to do it frequently.
		/// </summary>
		protected internal class FilterCleaner : IThreadRunnable
		{
            private class FilterItemComparer : IComparer<KeyValuePair<int, FilterItem>>
            {
                #region IComparer<FilterItem> Members

                public int Compare(KeyValuePair<int, FilterItem> x, KeyValuePair<int, FilterItem> y)
                {
                    return x.Value.timestamp.CompareTo(y.Value.timestamp);
                }

                #endregion
            }
			
			private bool running = true;
            private FilterManager manager;
            private ISet<KeyValuePair<int, FilterItem>> sortedFilterItems;
			
			public FilterCleaner(FilterManager enclosingInstance)
			{
                this.manager = enclosingInstance;
                sortedFilterItems = new SortedSet<KeyValuePair<int, FilterItem>>(new FilterItemComparer());
            }
			
			public virtual void  Run()
			{
				while (running)
				{
					// sort items from oldest to newest 
					// we delete the oldest filters 
                    if (this.manager.cache.Count > this.manager.cacheCleanSize)
					{
						// empty the temporary set
						sortedFilterItems.Clear();
                        lock (this.manager.cache)
						{
                            sortedFilterItems.UnionWith(this.manager.cache);
                            int numToDelete = (int)((this.manager.cache.Count - this.manager.cacheCleanSize) * 1.5);

                            //delete all of the cache entries not used in a while
                            sortedFilterItems.ExceptWith(sortedFilterItems.Take(numToDelete).ToArray());
						}
						// empty the set so we don't tie up the memory
                        sortedFilterItems.Clear();
					}
					// take a nap
					System.Threading.Thread.Sleep(new System.TimeSpan((System.Int64)10000 * this.manager.cleanSleepTime));
					
				}
			}
		}
	}
}