public void CreateAndModifyMultithreaded() { Config config = ObjectTestHelper.GetConfigWithCaching(); ObjectMetadataStore metadata = new ObjectMetadataStore(config); ObjectVersionStore versions = new ObjectVersionStore(config, metadata); ObjectIndexerCache cache = new ObjectIndexerCache(metadata, versions); try { // Create 4 actions to simulate 4 threads // This test simulates 4 concurrent processes adding and reading items to the cache // while they are also removed. Action[] actions = new Action[4]; for (int i = 0; i < 4; i++) { string nextObjName = "Obj" + i; actions[i] = new Action(() => { for (int loops = 0; loops < 100; loops++) { object[][] cacheParams = new object[100][]; // create 100 cache entries for (int add = 0; add < 100; add++) { cacheParams[add] = new object[] { nextObjName, "Idx" + ((loops * 100) + add) }; cache.Set( new int[] { loops, loops + 1, loops + 2, loops + 3 }, cacheParams[add]); } // read 1000 entries for (int read = 0; read < 1000; read++) { int[] getIds = cache.Get(cacheParams[read % 100]); // may get removed so check for null if (null != getIds) { Assert.AreEqual(loops, getIds[0]); Assert.AreEqual(loops + 1, getIds[1]); } } // Remove 20 entries - this can remove objects added by other threads // Linq query is executed once write lock is aquired which is why this works cache.Remove(cache.EnumerateCache().Take(20)); } // that 100 times - total at end will equal 8000 entries and 32000 object ids }); } Parallel.Invoke(actions); Assert.AreEqual(8000 * actions.Length, cache.EnumerateCache().Count()); CacheTotals totals = cache.Totals; Assert.AreEqual(8000 * actions.Length, totals.TotalQueries); Assert.AreEqual(32000 * actions.Length, totals.TotalValues); cache.Reset(); Assert.AreEqual(0, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(0, totals.TotalQueries); Assert.AreEqual(0, totals.TotalValues); } finally { cache.Dispose(); versions.Dispose(); metadata.Dispose(); } }
public void CreateAndModify() { Config config = ObjectTestHelper.GetConfigWithCaching(); ObjectMetadataStore metadata = new ObjectMetadataStore(config); ObjectVersionStore versions = new ObjectVersionStore(config, metadata); ObjectIndexerCache cache = new ObjectIndexerCache(metadata, versions); string objectName = "TestObj"; string intVal1 = ObjectIndex.Create("IntIdx", 5).ToString(); string strVal1 = ObjectIndex.Create("StrIdx", "Val1").ToString(); string strVal2 = ObjectIndex.Create("StrIdx", "Val3").ToString(); object[] cacheParams = new object[] { objectName, intVal1, strVal1 }; object[] cacheParams2 = new object[] { objectName, intVal1, strVal2 }; int[] objectIds = new int[] { 1000, 2000 }; int[] objectIds2 = new int[] { 3000, 4000 }; try { Assert.AreEqual(0, cache.EnumerateCache().Count()); CacheTotals totals = cache.Totals; Assert.AreEqual(0, totals.TotalQueries); Assert.AreEqual(0, totals.TotalValues); Assert.IsNull(cache.Get(cacheParams)); cache.Reset(); Assert.AreEqual(0, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(0, totals.TotalQueries); Assert.AreEqual(0, totals.TotalValues); Assert.IsNull(cache.Get(cacheParams)); // add one query to cache cache.Set(objectIds, cacheParams); Assert.AreEqual(1, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(1, totals.TotalQueries); Assert.AreEqual(2, totals.TotalValues); int[] lookupIds = cache.Get(cacheParams); Assert.AreEqual(objectIds.Length, lookupIds.Length); Assert.AreEqual(objectIds[0], lookupIds[0]); Assert.AreEqual(objectIds[1], lookupIds[1]); cache.Reset(); Assert.AreEqual(0, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(0, totals.TotalQueries); Assert.AreEqual(0, totals.TotalValues); Assert.IsNull(cache.Get(cacheParams)); // add more than one query to cache cache.Set(objectIds, cacheParams); cache.Set(objectIds2, cacheParams2); Assert.AreEqual(2, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(2, totals.TotalQueries); Assert.AreEqual(4, totals.TotalValues); lookupIds = cache.Get(cacheParams); Assert.AreEqual(objectIds.Length, lookupIds.Length); Assert.AreEqual(objectIds[0], lookupIds[0]); Assert.AreEqual(objectIds[1], lookupIds[1]); lookupIds = cache.Get(cacheParams2); Assert.AreEqual(objectIds2.Length, lookupIds.Length); Assert.AreEqual(objectIds2[0], lookupIds[0]); Assert.AreEqual(objectIds2[1], lookupIds[1]); // add the same query to cache again - make sure it replaces the existing one cache.Set(objectIds2, cacheParams2); Assert.AreEqual(2, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(2, totals.TotalQueries); Assert.AreEqual(4, totals.TotalValues); lookupIds = cache.Get(cacheParams); Assert.AreEqual(objectIds.Length, lookupIds.Length); Assert.AreEqual(objectIds[0], lookupIds[0]); Assert.AreEqual(objectIds[1], lookupIds[1]); lookupIds = cache.Get(cacheParams2); Assert.AreEqual(objectIds2.Length, lookupIds.Length); Assert.AreEqual(objectIds2[0], lookupIds[0]); Assert.AreEqual(objectIds2[1], lookupIds[1]); // remove query from cache var entryToRemove = cache.EnumerateCache().Last(); // we don't know what order they will be returned so find out // which value is being removed object[] remainingCacheParams = cacheParams; int[] remainingObjectIds = objectIds; if (entryToRemove.Hash == ObjectIndexerCache.ConstructHash(cacheParams)) { // then the first entry as removed so the second will be the // remaining entry remainingCacheParams = cacheParams2; remainingObjectIds = objectIds2; } cache.Remove(new ICacheEntry[] { entryToRemove }); Assert.AreEqual(1, cache.EnumerateCache().Count()); totals = cache.Totals; Assert.AreEqual(1, totals.TotalQueries); Assert.AreEqual(2, totals.TotalValues); lookupIds = cache.Get(remainingCacheParams); Assert.AreEqual(remainingObjectIds.Length, lookupIds.Length); Assert.AreEqual(remainingObjectIds[0], lookupIds[0]); Assert.AreEqual(remainingObjectIds[1], lookupIds[1]); Assert.IsNull(cache.Get(cacheParams2)); } finally { cache.Dispose(); versions.Dispose(); metadata.Dispose(); } }