/// <summary> /// Add an index to the given dictionary of indexes, keyed by the given /// extractor. Also add the index as a listener to the given cache. /// </summary> /// <param name="extractor"> /// The IValueExtractor object that is used to extract an indexable /// property value from a cache entry. /// </param> /// <param name="ordered"> /// True if the contents of the indexed information should be ordered; /// false otherwise /// </param> /// <param name="comparator"> /// The IComparer object which imposes an ordering on entries in the /// indexed cache or <c>null</c> if the entries' values natural /// ordering should be used. /// </param> /// <param name="cache"> /// The cache that the newly created ICacheIndex will use for /// initialization and listen to for changes. /// </param> /// <param name="dictIndex"> /// The dictionary of indexes that the newly created ICacheIndex will /// be added to. /// </param> public static void AddIndex(IValueExtractor extractor, bool ordered, IComparer comparator, IObservableCache cache, IDictionary dictIndex) { var index = (ICacheIndex)dictIndex[extractor]; if (index == null) { for (int cAttempts = 4; ;) { if (extractor is IIndexAwareExtractor) { index = ((IIndexAwareExtractor)extractor). CreateIndex(ordered, comparator, dictIndex); if (index == null) { return; } } else { index = new SimpleCacheIndex(extractor, ordered, comparator); dictIndex[extractor] = index; } ICacheListener listener = EnsureListener(index); cache.AddCacheListener(listener, null, false); try { // build the index foreach (ICacheEntry entry in cache) { index.Insert(entry); } break; } catch (InvalidOperationException ioe) //collection was modified { cache.RemoveCacheListener(listener); if (--cAttempts == 0) { RemoveIndex(extractor, cache, dictIndex); CacheFactory.Log("Exception occured during index rebuild: " + ioe, CacheFactory.LogLevel.Error); throw; } } } } else if (!(ordered == index.IsOrdered && Equals(comparator, index.Comparer))) { throw new InvalidOperationException("Index for " + extractor + " already exists;" + " remove the index and add it with the new settings"); } }
/// <summary> /// Remove the index keyed by the given extractor from the given /// dictionary of indexes. Also, remove the index as a listener from /// the given cache. /// </summary> /// <param name="extractor"> /// The IValueExtractor object that is used to extract an indexable /// object from a value stored in the cache. /// </param> /// <param name="cache"> /// The resource map associated with the index. /// </param> /// <param name="dictIndex"> /// The dictionary of indexes to remove the ICacheIndex from. /// </param> public static void RemoveIndex(IValueExtractor extractor, IObservableCache cache, IDictionary dictIndex) { ICacheIndex index; if (extractor is IIndexAwareExtractor) { index = (extractor as IIndexAwareExtractor).DestroyIndex(dictIndex); } else { index = (ICacheIndex)dictIndex[extractor]; dictIndex.Remove(extractor); } if (index != null) { cache.RemoveCacheListener(EnsureListener(index)); } }
public void ConverterObservableCacheTests() { IObservableCache cache = InstantiateCache(); IConverter cDown = new ConvertDown(); IConverter cUp = new ConvertUp(); TestCacheListener listener = new TestCacheListener(); IObservableCache convCache = ConverterCollections.GetObservableCache(cache, cUp, cDown, cUp, cDown); Assert.IsNotNull(convCache); //AddCacheListener(listener) convCache.AddCacheListener(listener); Assert.AreEqual(listener.inserted, 0); convCache.Add(1, 1); Assert.AreEqual(listener.inserted, 1); Assert.AreEqual(listener.updated, 0); convCache[1] = 2; Assert.AreEqual(listener.updated, 1); Assert.AreEqual(listener.deleted, 0); convCache.Remove(1); Assert.AreEqual(listener.deleted, 1); //RemoveCacheListener(listener) convCache.RemoveCacheListener(listener); Assert.AreEqual(listener.inserted, 1); convCache.Add(1, 1); Assert.AreEqual(listener.inserted, 1); listener.inserted = listener.updated = listener.deleted = 0; convCache.Clear(); //AddCacheListener(listener, key, isLite); convCache.AddCacheListener(listener, "1", true); for (int i = 0; i < 3; i++) { convCache.Add(i, i); } Assert.AreEqual(listener.inserted, 1); Assert.AreEqual(listener.updated, 0); Assert.AreEqual(listener.deleted, 0); for (int i = 0; i < 3; i++) { convCache[i] = i + 1; } Assert.AreEqual(listener.inserted, 1); Assert.AreEqual(listener.updated, 1); Assert.AreEqual(listener.deleted, 0); convCache.Clear(); Assert.AreEqual(listener.inserted, 1); Assert.AreEqual(listener.updated, 1); Assert.AreEqual(listener.deleted, 1); //RemoveCacheListener(listener, key) convCache.RemoveCacheListener(listener, "1"); convCache.Add(1, 1); Assert.AreEqual(listener.inserted, 1); listener.inserted = listener.updated = listener.deleted = 0; convCache.Clear(); IFilter filter = AlwaysFilter.Instance; //AddCacheListener(listener, filter, isLite) convCache.AddCacheListener(listener, filter, true); for (int i = 0; i < 3; i++) { convCache.Add(i, i); } Assert.AreEqual(listener.inserted, 3); Assert.AreEqual(listener.updated, 0); Assert.AreEqual(listener.deleted, 0); for (int i = 0; i < 3; i++) { convCache[i] = i + 1; } Assert.AreEqual(listener.inserted, 3); Assert.AreEqual(listener.updated, 3); Assert.AreEqual(listener.deleted, 0); convCache.Clear(); Assert.AreEqual(listener.inserted, 3); Assert.AreEqual(listener.updated, 3); Assert.AreEqual(listener.deleted, 3); //RemoveCacheListener(listener, filter) convCache.RemoveCacheListener(listener, filter); convCache.Add(1, 1); Assert.AreEqual(listener.inserted, 3); Assert.IsInstanceOf(typeof(ConverterCollections.ConverterObservableCache), convCache); ConverterCollections.ConverterObservableCache coc = convCache as ConverterCollections.ConverterObservableCache; Assert.IsNotNull(coc); Assert.AreEqual(coc.ObservableCache, cache); }