/// <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) { // NOTE: jh 2010.10.06 // this method differs a bit from the Java version due to a lack // of a proper ISet interfacea and SubSet implementation IFilter filter = m_filter; if (filter is IIndexAwareFilter) { // create delta set var setDelta = new HashSet(keys); // delegate to the not-ed filter, but only use the non-partial // indexes, since for a partial index the fact that it contains // keys for entries that fit the underlying filter does not // mean that it contains them all. As a result, the "negating" // operation may produce invalid result IFilter filterNew = ((IIndexAwareFilter)filter).ApplyIndex( indexes, setDelta); // see if any keys were filtered out //azzert(setDelta.getAdded().isEmpty()); var setRemoved = new HashSet(); foreach (object key in keys) { if (!CollectionUtils.Contains(setDelta, key)) { setRemoved.Add(key); } } if (filterNew == null || setDelta.Count == 0) { // invert the key selection by the delegated-to filter if (setRemoved.Count == 0) { // no keys were removed; therefore the result of the // "not" is to remove all keys (clear) CollectionUtils.Clear(keys); } else if (setDelta.Count == 0) { // all keys were removed; therefore the result of the // "not" is to retain all keys (remove none) } else { // some keys were removed; therefore the result of the // "not" is to retain only those removed keys CollectionUtils.RetainAll(keys, setRemoved); } // nothing left to do; the index fully resolved the filter return(null); } if (setRemoved.Count == 0) { // no obvious effect from the index application return(filterNew == filter ? this : new NotFilter(filterNew)); } // some keys have been removed; those are definitely "in"; // the remaining keys each need to be evaluated later var filterKey = new KeyFilter(setRemoved); var filterNot = filterNew == filter ? this : new NotFilter(filterNew); return(new AndFilter(filterKey, filterNot)); } return(this); }
/// <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 override IFilter ApplyIndex(IDictionary indexes, ICollection keys) { OptimizeFilterOrder(indexes, keys); IFilter[] filters = m_filters; int filterCount = filters.Length; var filterList = new ArrayList(filterCount); var matches = new HashSet(keys.Count); // filterList is an array of filters that will have to be re-applied // matches is an accumulating set of already matching keys for (int i = 0; i < filterCount; i++) { IFilter filter = filters[i]; if (filter is IIndexAwareFilter) { ICollection remain = new ArrayList(keys); if (matches.Count > 0) { CollectionUtils.RemoveAll(remain, matches); } IFilter filterDefer = ApplyFilter( (IIndexAwareFilter)filter, indexes, remain); if (filterDefer == null) { // these are definitely "in" CollectionUtils.AddAll(matches, remain); } else { int keyCount = keys.Count; int remaining = remain.Count; if (remaining < keyCount) { // some keys are definitely "out" for this filter; // we need to incorporate this knowledge into a deferred // filter if (remaining > 0) { var filterKey = new KeyFilter(remain); filterList.Add(new AndFilter(filterDefer, filterKey)); } //else { // though a filter was returned, the key set was // fully reduced; this should have the same effect // as a fully resolved filter without any matches } } else { filterList.Add(filterDefer); } } } else { filterList.Add(filter); } } int matchCount = matches.Count; filterCount = filterList.Count; if (filterCount == 0) { if (matchCount > 0) { CollectionUtils.RetainAll(keys, matches); } else { CollectionUtils.Clear(keys); } return(null); } if (filterCount == 1 && matchCount == 0) { return((IFilter)filterList[0]); } if (matchCount > 0) { // the keys that have been matched are definitely "in"; // the remaining keys each need to be evaluated later var filterKey = new KeyFilter(matches); filterList.Insert(0, filterKey); } return(new AnyFilter((IFilter[])filterList.ToArray(typeof(IFilter)))); }