/// <summary> /// Given an IDictionary of available indexes, determine if this /// IIndexAwareFilter can use any of the indexes to assist in its /// processing, and if so, determine how effective the use of that /// index would be. /// </summary> /// <remarks> /// <p> /// The returned value is an effectiveness estimate of how well this /// filter can use the specified indexes to filter the specified /// keys. An operation that requires no more than a single access to /// the index content (i.e. Equals, NotEquals) has an effectiveness of /// <b>one</b>. Evaluation of a single entry is assumed to have an /// effectiveness that depends on the index implementation and is /// usually measured as a constant number of the single operations. /// This number is referred to as <i>evaluation cost</i>. /// </p> /// <p> /// If the effectiveness of a filter evaluates to a number larger /// than the keys.size() then a user could avoid using the index and /// iterate through the keys calling <tt>Evaluate</tt> rather than /// <tt>ApplyIndex</tt>. /// </p> /// </remarks> /// <param name="indexes"> /// The available <see cref="ICacheIndex"/> objects keyed by the /// related IValueExtractor; read-only. /// </param> /// <param name="keys"> /// The set of keys that will be filtered; read-only. /// </param> /// <returns> /// An effectiveness estimate of how well this filter can use the /// specified indexes to filter the specified keys. /// </returns> public int CalculateEffectiveness(IDictionary indexes, ICollection keys) { OptimizationPlan plan = m_plan; if (plan == OptimizationPlan.AlwaysFalse || plan == OptimizationPlan.AlwaysTrue) { return(1); } var index = (ICacheIndex)indexes[ValueExtractor]; if (index == null) { return(CalculateIteratorEffectiveness(keys.Count)); } if (plan == OptimizationPlan.ExactMatch) { return(1); } string pattern = Pattern; if (index.IsOrdered && pattern.IndexOf('%') != 0 && pattern.IndexOf('_') != 0) { return(Math.Max(index.IndexContents.Count / 4, 1)); } return(index.IndexContents.Count); }
/// <summary> /// Filter remaining keys using an IDictionary of available indexes. /// </summary> /// <remarks> /// The filter is responsible for removing all keys from the passed /// set of keys that the applicable indexes can prove should be /// filtered. If the filter does not fully evaluate the remaining /// keys using just the index information, it must return a filter /// (which may be an <see cref="IEntryFilter"/>) that can complete the /// task using an iterating implementation. If, on the other hand, the /// filter does fully evaluate the remaining keys using just the index /// information, then it should return <c>null</c> to indicate that no /// further filtering is necessary. /// </remarks> /// <param name="indexes"> /// The available <see cref="ICacheIndex"/> objects keyed by the /// related IValueExtractor; read-only. /// </param> /// <param name="keys"> /// The mutable set of keys that remain to be filtered. /// </param> /// <returns> /// An <see cref="IFilter"/> object that can be used to process the /// remaining keys, or <c>null</c> if no additional filter processing /// is necessary. /// </returns> public IFilter ApplyIndex(IDictionary indexes, ICollection keys) { OptimizationPlan plan = m_plan; switch (plan) { case OptimizationPlan.AlwaysFalse: CollectionUtils.Clear(keys); return(null); case OptimizationPlan.AlwaysTrue: return(null); } var index = (ICacheIndex)indexes[ValueExtractor]; if (index == null) { // there is no relevant index return(this); } if (plan == OptimizationPlan.ExactMatch) { var setEquals = (ICollection)index.IndexContents[m_part]; if (setEquals == null || setEquals.Count == 0) { CollectionUtils.Clear(keys); } else { CollectionUtils.RetainAll(keys, setEquals); } return(null); } IDictionary contents = index.IndexContents; ICollection matches; if ((plan == OptimizationPlan.StartsWithString || plan == OptimizationPlan.StartsWithChar) && index.IsOrdered) { try { string prefix = plan == OptimizationPlan.StartsWithString ? m_part : Char.ToString(m_partChar); SortedList tail = CollectionUtils.TailList(contents, prefix); matches = new HashSet(); foreach (DictionaryEntry entry in tail) { var value = (string)entry.Key; if (value.StartsWith(prefix)) { CollectionUtils.AddAll(matches, (ICollection)entry.Value); } else { break; } } CollectionUtils.RetainAll(keys, matches); return(null); } catch (InvalidCastException) { // incompatible types; go the long way } } matches = new HashSet(); foreach (DictionaryEntry entry in contents) { string value = entry.Key == null ? null : entry.Key.ToString(); if (IsMatch(value)) { CollectionUtils.AddAll(matches, (ICollection)entry.Value); } } CollectionUtils.RetainAll(keys, matches); return(null); }