Lucene.Net  3.0.3
Lucene.Net is a .NET port of the Java Lucene Indexing Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties
SegmentCache.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Text;
22 using System.Threading;
23 
24 using Lucene.Net.Index;
25 
26 namespace Lucene.Net.Util.Cache
27 {
32  public abstract class AbstractSegmentCache
33  {
39  public abstract void Warm(IndexReader reader, string key);
40  }
41 
48  public abstract class SegmentCache<T> : AbstractSegmentCache
49  {
53  private Dictionary<WeakKey, Dictionary<string, T>> readerCache = new Dictionary<WeakKey, Dictionary<string, T>>();
54 
58  private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
59 
66  protected abstract T CreateValue(IndexReader reader, string key);
67 
71  public int KeyCount
72  {
73  get { return this.readerCache.Count; }
74  }
75 
81  public override void Warm(IndexReader reader, string key)
82  {
83  this.Get(reader, key);
84  }
85 
92  public virtual T Get(IndexReader reader, string key)
93  {
94  WeakKey readerRef = new SegmentCache<T>.WeakKey(reader);
95 
96  Dictionary<string, T> innerCache;
97  T retVal = default(T);
98  this.cacheLock.EnterReadLock();
99  try
100  {
101  if (readerCache.TryGetValue(readerRef, out innerCache))
102  {
103  innerCache.TryGetValue(key, out retVal);
104  }
105  }
106  finally
107  {
108  this.cacheLock.ExitReadLock();
109  }
110 
111  if (retVal == null)
112  {
113  retVal = this.CreateValue(reader, key);
114  this.cacheLock.EnterWriteLock();
115  try
116  {
117  if (!readerCache.TryGetValue(readerRef, out innerCache))
118  {
119  innerCache = new Dictionary<string, T>();
120  readerCache.Add(readerRef, innerCache);
121  }
122  if (!innerCache.ContainsKey(key))
123  {
124  innerCache[key] = retVal;
125  }
126  else
127  {
128  // another thread must have put it in while waiting for the write lock
129  // assumption is that the previous thread already flushed the old items
130  return retVal;
131  }
132 
133  // release the old items and yank the gc'd weak references
134  var keys = from wr in this.readerCache.Keys where !wr.IsAlive select wr;
135  List<WeakKey> keysToRemove = keys.ToList();
136  foreach (WeakKey wk in keysToRemove)
137  {
138  this.readerCache.Remove(wk);
139  }
140  }
141  finally
142  {
143  this.cacheLock.ExitWriteLock();
144  }
145  }
146 
147  return retVal;
148  }
149 
150 
156  internal class WeakKey : WeakReference
157  {
161  private int hashCode;
162 
167  internal WeakKey(object target)
168  : base(target)
169  {
170  this.hashCode = target.GetHashCode();
171  }
172 
177  public override int GetHashCode()
178  {
179  return this.hashCode;
180  }
181 
187  public override bool Equals(object obj)
188  {
189  WeakKey other = obj as WeakKey;
190  if (other == null)
191  {
192  return false;
193  }
194 
195  object a = this.Target;
196  object b = other.Target;
197 
198  if (a == null && b == null)
199  {
200  return true;
201  }
202  else if (a == null || b == null)
203  {
204  return false;
205  }
206  else
207  {
208  return a.Equals(b);
209  }
210  }
211  }
212  }
213 }