19 using System.Collections.Generic;
25 namespace Lucene.Net.Util
78 return CheckSanity(cache.GetCacheEntries());
91 return sanityChecker.
Check(cacheEntries);
103 if (null == cacheEntries || 0 == cacheEntries.Length)
108 for (
int i = 0; i < cacheEntries.Length; i++)
110 cacheEntries[i].EstimateSize(ramCalc);
118 MapOfSets<int,CacheEntry> valIdToItems =
new MapOfSets<int,CacheEntry>(
new Dictionary<int,HashSet<CacheEntry>>(17));
120 MapOfSets<ReaderField,int> readerFieldToValIds =
new MapOfSets<ReaderField,int>(
new Dictionary<ReaderField,HashSet<int>>(17));
124 HashSet<ReaderField> valMismatchKeys =
new HashSet<ReaderField>();
127 for (
int i = 0; i < cacheEntries.Length; i++)
130 System.Object val = item.Value;
132 if (val is Lucene.Net.Search.CreationPlaceholder)
135 ReaderField rf =
new ReaderField(item.ReaderKey, item.FieldName);
137 System.Int32 valId = val.GetHashCode();
140 valIdToItems.Put(valId, item);
141 if (1 < readerFieldToValIds.Put(rf, valId))
143 valMismatchKeys.Add(rf);
147 List<Insanity> insanity =
new List<Insanity>(valMismatchKeys.Count * 3);
149 insanity.AddRange(CheckValueMismatch(valIdToItems, readerFieldToValIds, valMismatchKeys));
150 insanity.AddRange(CheckSubreaders(valIdToItems, readerFieldToValIds));
152 return insanity.ToArray();
162 private List<Insanity> CheckValueMismatch(MapOfSets<int,CacheEntry> valIdToItems,
163 MapOfSets<ReaderField,int> readerFieldToValIds,
164 HashSet<ReaderField> valMismatchKeys)
167 List<Insanity> insanity =
new List<Insanity>(valMismatchKeys.Count * 3);
169 if (!(valMismatchKeys.Count == 0))
173 IDictionary<ReaderField,HashSet<int>> rfMap = readerFieldToValIds.Map;
174 IDictionary<int,HashSet<CacheEntry>> valMap = valIdToItems.Map;
175 foreach (ReaderField rf
in valMismatchKeys)
177 List<CacheEntry> badEntries =
new List<CacheEntry>(valMismatchKeys.Count * 2);
178 foreach (
int val
in rfMap[rf])
182 badEntries.Add(entry);
186 insanity.Add(
new Insanity(InsanityType.VALUEMISMATCH,
"Multiple distinct value objects for " + rf.ToString(), badEntries.ToArray()));
200 private List<Insanity> CheckSubreaders(MapOfSets<int,CacheEntry> valIdToItems,
201 MapOfSets<ReaderField,int> readerFieldToValIds)
203 List<Insanity> insanity =
new List<Insanity>(23);
205 Dictionary<ReaderField, HashSet<ReaderField>> badChildren =
new Dictionary<ReaderField, HashSet<ReaderField>>(17);
206 MapOfSets<ReaderField, ReaderField> badKids =
new MapOfSets<ReaderField, ReaderField>(badChildren);
208 IDictionary<int, HashSet<CacheEntry>> viToItemSets = valIdToItems.Map;
209 IDictionary<ReaderField, HashSet<int>> rfToValIdSets = readerFieldToValIds.Map;
211 HashSet<ReaderField> seen =
new HashSet<ReaderField>();
213 foreach (ReaderField rf
in rfToValIdSets.Keys)
215 if (seen.Contains(rf))
218 System.Collections.IList kids = GetAllDecendentReaderKeys(rf.readerKey);
219 foreach (Object kidKey
in kids)
221 ReaderField kid =
new ReaderField(kidKey, rf.fieldName);
223 if (badChildren.ContainsKey(kid))
227 badKids.Put(rf, kid);
228 badKids.PutAll(rf, badChildren[kid]);
229 badChildren.Remove(kid);
231 else if (rfToValIdSets.ContainsKey(kid))
234 badKids.Put(rf, kid);
242 foreach (ReaderField parent
in badChildren.Keys)
244 HashSet<ReaderField> kids = badChildren[parent];
246 List<CacheEntry> badEntries =
new List<CacheEntry>(kids.Count * 2);
250 foreach (
int val
in rfToValIdSets[parent])
252 badEntries.AddRange(viToItemSets[val]);
257 foreach (ReaderField kid
in kids)
259 foreach (
int val
in rfToValIdSets[kid])
261 badEntries.AddRange(viToItemSets[val]);
265 insanity.Add(
new Insanity(InsanityType.SUBREADER,
"Found caches for decendents of " + parent.ToString(), badEntries.ToArray()));
275 private System.Collections.IList GetAllDecendentReaderKeys(System.Object seed)
277 List<object> all =
new List<object>(17);
279 for (
int i = 0; i < all.Count; i++)
281 System.Object obj = all[i];
284 IndexReader[] subs = ((
IndexReader) obj).GetSequentialSubReaders();
285 for (
int j = 0; (null != subs) && (j < subs.Length); j++)
287 all.Add(subs[j].FieldCacheKey);
292 return all.GetRange(1, all.Count - 1);
296 private sealed
class ReaderField
298 public System.Object readerKey;
299 public System.String fieldName;
300 public ReaderField(System.Object readerKey, System.String fieldName)
302 this.readerKey = readerKey;
303 this.fieldName = fieldName;
305 public override int GetHashCode()
307 return readerKey.GetHashCode() * fieldName.GetHashCode();
309 public override bool Equals(System.Object that)
311 if (!(that is ReaderField))
314 ReaderField other = (ReaderField) that;
315 return (this.readerKey == other.readerKey &&
this.fieldName.Equals(other.fieldName));
317 public override System.String ToString()
319 return readerKey.ToString() +
"+" + fieldName;
330 private System.String msg;
336 throw new System.ArgumentException(
"Insanity requires non-null InsanityType");
338 if (null == entries || 0 == entries.Length)
340 throw new System.ArgumentException(
"Insanity requires non-null/non-empty CacheEntry[]");
344 this.entries = entries;
368 public override System.String ToString()
370 System.Text.StringBuilder buf =
new System.Text.StringBuilder();
371 buf.Append(Type).Append(
": ");
373 System.String m = Msg;
380 for (
int i = 0; i < ce.Length; i++)
382 buf.Append(
'\t').Append(ce[i].ToString()).Append(
'\n');
385 return buf.ToString();
401 private System.String label;
406 public override System.String ToString()