Example #1
0
        public void Test_TRexSpatialMemoryCacheTests_EvictedItemsRemoval()
        {
            const int _originX = 123;
            const int _originY = 456;
            const int _size    = 1000;

            // Create the cache with enough elements to hold one per context without eviction
            using (var cache = new TRexSpatialMemoryCache(1, 1000000, 0.5))
            {
                // Make the number of contexts requested, and a separate item to be placed in each one
                var context = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprint");

                var item1 = new TRexSpatialMemoryCacheContextTests_Element
                {
                    SizeInBytes  = _size,
                    CacheOriginX = _originX,
                    CacheOriginY = _originY
                };

                var item2 = new TRexSpatialMemoryCacheContextTests_Element
                {
                    SizeInBytes  = _size,
                    CacheOriginX = _originX + SubGridTreeConsts.SubGridTreeDimension,
                    CacheOriginY = _originY + SubGridTreeConsts.SubGridTreeDimension
                };

                cache.Add(context, item1, context.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);
                cache.Add(context, item2, context.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);

                Assert.True(context.TokenCount == 1, "Token count not one after addition of second element forcing eviction of first");
                Assert.True(cache.Get(context, item1.CacheOriginX, item1.CacheOriginY) == null, "Able to request item1 after it should have been evicted for item2");
                Assert.True(cache.Get(context, item2.CacheOriginX, item2.CacheOriginY) != null, "Unable to request item2 after it should have replaced item1");
            }
        }
Example #2
0
        public void Test_TRexSpatialMemoryCacheStorageTests_TimeCheckReusingElements(int numElements, int overflowBy)
        {
            var storage    = new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(numElements, numElements / 2);
            var dummyCache = new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(1000, 1000, 0), storage);

            var startTime = DateTime.Now;

            var item = new TRexSpatialMemoryCacheContextTests_Element
            {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            // Fill all available slots
            for (int i = 0; i < numElements; i++)
            {
                storage.Add(item, null);
            }

            var midTime = DateTime.Now;

            for (int i = 0; i < overflowBy; i++)
            {
                storage.Add(item, dummyCache);
            }

            Assert.False(true, $"Time for adding {numElements} elements is {midTime - startTime} and adding {overflowBy} overflows is {DateTime.Now - midTime}");
        }
Example #3
0
        public void CacheContext_Pressure_MRULRUManagement()
        {
            using var cache = new TRexSpatialMemoryCache(100, 1000000, 0.1);

            // Create a context with default invalidation sensitivity, add some data to it
            // and validate that a change bitmask causes appropriate invalidation in concurrent operations
            var contextHeight    = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprintHeight");
            var contextPassCount = cache.LocateOrCreateContext(Guid.Empty, GridDataType.PassCount, "fingerprintPasscount");

            var contexts = new[] { contextHeight, contextPassCount };

            var itemsHeight    = new TRexSpatialMemoryCacheContextTests_Element[100, 100];
            var itemsPassCount = new TRexSpatialMemoryCacheContextTests_Element[100, 100];

            var items = new[] { itemsHeight, itemsPassCount };

            for (var i = 0; i < 100; i++)
            {
                for (var j = 0; j < 100; j++)
                {
                    items.ForEach((x, index) => x[i, j] = new TRexSpatialMemoryCacheContextTests_Element
                    {
                        Context      = contexts[index],
                        CacheOriginX = i * SubGridTreeConsts.SubGridTreeDimension,
                        CacheOriginY = j * SubGridTreeConsts.SubGridTreeDimension,
                        SizeInBytes  = 1
                    });
                }
            }

            // Progressively add elements in the cache forcing elements to be removed to accomodate them given the cache's small size
            // Check the retrieved element is also in the expected cache
            var additionTask = Task.Run(() => {
                for (var loopCount = 0; loopCount < 100; loopCount++)
                {
                    for (var i = 0; i < 100; i++)
                    {
                        for (var j = 0; j < 100; j++)
                        {
                            for (var contextIndex = 0; contextIndex < contexts.Length; contextIndex++)
                            {
                                TRexSpatialMemoryCacheContextTests_Element elem;
                                if ((elem = (TRexSpatialMemoryCacheContextTests_Element)cache.Get(contexts[contextIndex], i, j)) != null)
                                {
                                    elem.Context.Should().Be(contexts[contextIndex]);
                                }
                                else
                                {
                                    cache.Add(contexts[contextIndex], items[contextIndex][i, j], contexts[contextIndex].InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);
                                }
                            }
                        }
                    }
                }
            });

            Task.WaitAll(new[] { additionTask });
        }
Example #4
0
        public void Test_TRexSpatialMemoryCacheContext_AddOneElement_FailWithInvalidationVersionMismatch()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            var element = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion + 1).Should().Be(CacheContextAdditionResult.RejectedDueToInvlidationVersionMismatch);
        }
Example #5
0
        public void Test_TRexCacheItem_Set()
        {
            var theObject = new TRexSpatialMemoryCacheContextTests_Element();
            TRexCacheItem <TRexSpatialMemoryCacheContextTests_Element> item = new TRexCacheItem <TRexSpatialMemoryCacheContextTests_Element>();

            item.Set(theObject, null, 100, 1, 2);

            Assert.True(ReferenceEquals(item.Item, theObject));
            Assert.True(item.Prev == 1);
            Assert.True(item.Next == 2);
            Assert.True(item.MRUEpochToken == 100);
        }
Example #6
0
        public void Test_TRexCacheItem_Creation_Specific()
        {
            var storage    = new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(10, 5);
            var dummyCache = new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(1000, 1000, 0), storage);

            var theObject = new TRexSpatialMemoryCacheContextTests_Element();
            TRexCacheItem <TRexSpatialMemoryCacheContextTests_Element> item = new TRexCacheItem <TRexSpatialMemoryCacheContextTests_Element>(theObject, dummyCache, 100, 1, 2);

            Assert.True(ReferenceEquals(item.Item, theObject));
            Assert.True(item.Prev == 1);
            Assert.True(item.Next == 2);
            Assert.True(item.MRUEpochToken == 100);
        }
Example #7
0
        public void Test_TRexSpatialMemoryCacheContext_FailOverwriteOfExistingElement()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            var element = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            Assert.True(context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion) == CacheContextAdditionResult.Added, "Result is false on addition of first element");
            Assert.True(context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion) == CacheContextAdditionResult.AlreadyExisting, "Result is true on second addition of same element");
        }
Example #8
0
        public void Test_TRexSpatialMemoryCacheTests_ProductionDataIngestInvalidation()
        {
            using (var cache = new TRexSpatialMemoryCache(20000, 1000000, 0.5))
            {
                // Create a context with default invalidation sensitivity, add some data to it
                // and validate that a change bitmask causes appropriate invalidation
                var context = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprint");

                var items = new TRexSpatialMemoryCacheContextTests_Element[100, 100];
                for (var i = 0; i < 100; i++)
                {
                    for (var j = 0; j < 100; j++)
                    {
                        items[i, j] = new TRexSpatialMemoryCacheContextTests_Element
                        {
                            CacheOriginX = i * SubGridTreeConsts.SubGridTreeDimension,
                            CacheOriginY = j * SubGridTreeConsts.SubGridTreeDimension,
                            SizeInBytes  = 1
                        };

                        cache.Add(context, items[i, j], context.InvalidationVersion);
                    }
                }

                Assert.True(context.TokenCount == 10000, "Token count incorrect after addition");

                // Create the bitmask
                ISubGridTreeBitMask mask = new SubGridTreeSubGridExistenceBitMask();

                for (var i = 0; i < 100; i++)
                {
                    for (var j = 0; j < 100; j++)
                    {
                        mask[(i * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                             (j * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel] = true;
                    }
                }

                cache.MRUList.TokenCount.Should().Be(context.TokenCount);

                cache.InvalidateDueToProductionDataIngest(Guid.Empty, Guid.NewGuid(), mask);

                cache.MRUList.TokenCount.Should().Be(0);
            }
        }
Example #9
0
        public void Test_TRexSpatialMemoryCacheContext_ReanimateViaItemAddition()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            var element = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            context.MarkForRemoval(DateTime.UtcNow);
            Assert.True(context.MarkedForRemoval, "Marking context for removal did not set state");

            // Reanimate by adding an element
            Assert.True(context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion) == CacheContextAdditionResult.Added, "Result is false on addition of first element");

            Assert.False(context.MarkedForRemoval, "Marking context for removal did not set state");
            Assert.True(context.MarkedForRemovalAtUtc == TRex.Common.Consts.MIN_DATETIME_AS_UTC, "Marking context for removal did not set date");
        }
Example #10
0
        public void InvalidateSubGrid()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            // context.InvalidateSubGrid facades context.InvalidateSubGrid
            context.InvalidateSubGrid(0, 0, out var present);
            present.Should().BeFalse();

            var element = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);

            context.InvalidateSubGrid(2000, 3000, out present);
            present.Should().BeTrue();
        }
Example #11
0
        public void Test_TRexSpatialMemoryCacheTests_Remove()
        {
            using (var cache = new TRexSpatialMemoryCache(10, 1000000, 0.5))
            {
                var context = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprint");
                var item    = new TRexSpatialMemoryCacheContextTests_Element
                {
                    CacheOriginX = 1000,
                    CacheOriginY = 1000,
                    SizeInBytes  = 1000
                };

                cache.Add(context, item, context.InvalidationVersion);
                Assert.True(context.TokenCount == 1, "Token count incorrect after addition");

                cache.Remove(context, item);
                Assert.True(context.TokenCount == 0, "Token count incorrect after removal");
            }
        }
Example #12
0
        public void Test_TRexSpatialMemoryCacheStorageTests_GetElement()
        {
            var storage    = new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50);
            var dummyCache = new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(1000, 1000, 0), storage);

            var item = new TRexSpatialMemoryCacheContextTests_Element
            {
                SizeInBytes  = 0,
                CacheOriginX = 2000,
                CacheOriginY = 3000
            };

            var index = storage.Add(item, dummyCache);

            Assert.True(storage.TokenCount == 1, $"Element count incorrect (= {storage.TokenCount})");

            var getItem = storage.Get(index);

            Assert.True(ReferenceEquals(item, getItem), "Item retrieved from storage not same as item placed in storage");
        }
Example #13
0
        public void Test_TRexSpatialMemoryCacheContext_AddOneElement()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            var element = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);

            Assert.True(context.TokenCount == 1, $"Element count incorrect (= {context.TokenCount})");
            Assert.True(context.MRUList.TokenCount == 1, $"MRU list count incorrect (= {context.MRUList.TokenCount})");

            // Check the newly added element in the context is present in the context map with a 1-based index
            int token = context.ContextTokens[element.CacheOriginX >> SubGridTreeConsts.SubGridIndexBitsPerLevel, element.CacheOriginY >> SubGridTreeConsts.SubGridIndexBitsPerLevel];

            Assert.True(token == 1, "Single newly added element does not have index of 1 present in ContextTokens");
        }
Example #14
0
        public void Test_TRexSpatialMemoryCacheContext_MarkForRemovalViaLastElementRemoved()
        {
            ITRexSpatialMemoryCacheContext context =
                new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(100, 1000000, 0.5),
                                                  new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50));

            Assert.False(context.MarkedForRemoval);

            var currentDate = DateTime.UtcNow;
            var element     = new TRexSpatialMemoryCacheContextTests_Element {
                SizeInBytes = 1000, CacheOriginX = 2000, CacheOriginY = 3000
            };

            Assert.True(context.OwnerMemoryCache.Add(context, element, context.InvalidationVersion) == CacheContextAdditionResult.Added, "Result is false on addition of first element");
            Assert.True(!context.MarkedForRemoval && context.TokenCount == 1);

            context.Remove(element);

            Assert.True(context.MarkedForRemoval, "Removing last element in context for removal did not mark for removal");
            Assert.True(context.MarkedForRemovalAtUtc >= currentDate, "Removal date not expected");
        }
Example #15
0
        public void Test_TRexSpatialMemoryCacheStorageTests_GetAfterRemove()
        {
            var storage    = new TRexSpatialMemoryCacheStorage <ITRexMemoryCacheItem>(100, 50);
            var dummyCache = new TRexSpatialMemoryCacheContext(new TRexSpatialMemoryCache(1000, 1000, 0), storage);
            var item       = new TRexSpatialMemoryCacheContextTests_Element
            {
                SizeInBytes  = 0,
                CacheOriginX = 2000,
                CacheOriginY = 3000
            };

            var index = storage.Add(item, dummyCache);

            Assert.True(storage.TokenCount == 1, $"Element count incorrect after add (= {storage.TokenCount})");
            Assert.True(storage.Get(index) != null);

            // Remove the item
            storage.Remove(index);

            Assert.True(storage.Get(index) == null, "Was able to extract item after invalidation");
            Assert.True(storage.TokenCount == 0, $"Element count incorrect after get after invalidation(= {storage.TokenCount})");
        }
Example #16
0
        public void Test_TRexSpatialMemoryCacheTests_ItemReplacement()
        {
            const int _originX = 123;
            const int _originY = 456;
            const int _size    = 1000;

            // Create the cache with enough elements to hold one per context without eviction
            using (var cache = new TRexSpatialMemoryCache(1, 1000000, 0.5))
            {
                // Make the number ofg contexts requested, and a separate item to be placed in each one
                var context = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprint");

                var item1 = new TRexSpatialMemoryCacheContextTests_Element
                {
                    SizeInBytes  = _size,
                    CacheOriginX = _originX,
                    CacheOriginY = _originY
                };

                Assert.True(cache.Add(context, item1, context.InvalidationVersion) == CacheContextAdditionResult.Added, "Failed to add element for the first time");
                Assert.False(cache.Add(context, item1, context.InvalidationVersion) == CacheContextAdditionResult.Added, "Succeeded overwriting element - bad!");
            }
        }
Example #17
0
        public void Test_TRexSpatialMemoryCacheTests_ConcurrentAccessWithDesignAndProductionDataIngestInvalidation()
        {
            using var cache = new TRexSpatialMemoryCache(20000, 1000000, 0.5);

            // Create a context with default invalidation sensitivity, add some data to it
            // and validate that a change bitmask causes appropriate invalidation in concurrent operations
            var contextHeight    = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprintHeight");
            var contextPassCount = cache.LocateOrCreateContext(Guid.Empty, GridDataType.PassCount, "fingerprintPasscount");

            var contexts = new[] { contextHeight, contextPassCount };

            var itemsHeight    = new TRexSpatialMemoryCacheContextTests_Element[100, 100];
            var itemsPassCount = new TRexSpatialMemoryCacheContextTests_Element[100, 100];

            var items = new[] { itemsHeight, itemsPassCount };

            // Create the bitmask
            ISubGridTreeBitMask mask = new SubGridTreeSubGridExistenceBitMask();

            for (var i = 0; i < 100; i++)
            {
                for (var j = 0; j < 100; j++)
                {
                    mask[(i * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                         (j * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel] = true;

                    items.ForEach(x => x[i, j] = new TRexSpatialMemoryCacheContextTests_Element {
                        CacheOriginX = i * SubGridTreeConsts.SubGridTreeDimension, CacheOriginY = j * SubGridTreeConsts.SubGridTreeDimension, SizeInBytes = 1
                    });
                }
            }

            var additionComplete     = false;
            var invalidationComplete = false;

            // Progressively add and invalidate the elements in the cache in separate tasks

            var additionTask = Task.Run(() => {
                for (var loopCount = 0; loopCount < 100; loopCount++)
                {
                    for (var i = 0; i < 100; i++)
                    {
                        for (var j = 0; j < 100; j++)
                        {
                            for (var contextIndex = 0; contextIndex < contexts.Length; contextIndex++)
                            {
                                if (cache.Get(contexts[contextIndex], i, j) == null)
                                {
                                    cache.Add(contexts[contextIndex], items[contextIndex][i, j], contexts[contextIndex].InvalidationVersion);
                                }
                            }
                        }
                    }
                }

                additionComplete = true;
            });

            var invalidationTask = Task.Run(() =>
            {
                for (var loopCount = 0; loopCount < 100; loopCount++)
                {
                    for (var i = 99; i >= 0; i--)
                    {
                        for (var j = 99; j >= 0; j--)
                        {
                            foreach (var context in contexts)
                            {
                                // Empty contexts are ignored
                                if (context.TokenCount > 0)
                                {
                                    context.InvalidateSubGrid(i * SubGridTreeConsts.SubGridTreeDimension, j * SubGridTreeConsts.SubGridTreeDimension, out var subGridPresentForInvalidation);
                                }
                            }
                        }
                    }
                }

                invalidationComplete = true;
            });

            var numDesignInvalidations = 0;
            var designUpdateTask       = Task.Run(async() =>
            {
                while (!additionComplete || !invalidationComplete)
                {
                    // Mimic design invalidation by periodically invalidating all sub grids
                    await Task.Delay(10);
                    contexts[numDesignInvalidations % contexts.Length].InvalidateAllSubGrids();

                    numDesignInvalidations++;
                }
            });

            Task.WaitAll(new[] { additionTask, invalidationTask, designUpdateTask });

            numDesignInvalidations.Should().BeGreaterThan(0);
        }
Example #18
0
        public void Test_TRexSpatialMemoryCacheTests_DesignChangeInvalidation()
        {
            var projectUid   = Guid.NewGuid();
            var gridDataType = Types.GridDataType.PassCount;
            var designUid    = Guid.NewGuid();
            var designUid2   = Guid.NewGuid();

            Guid[] includedSurveyedSurfaces  = new Guid[] { designUid };
            Guid[] includedSurveyedSurfaces2 = new Guid[] { designUid2 };

            using (var cache = new TRexSpatialMemoryCache(20000, 1000000, 0.5))
            {
                // Create a context with a included design and validate that a design change causes the appropriate invalidation
                var testGuid = Guid.NewGuid();
                var context  = cache.LocateOrCreateContext(projectUid, gridDataType, SpatialCacheFingerprint.ConstructFingerprint(projectUid, gridDataType, null, includedSurveyedSurfaces));
                // this content will remain in cache as it uses a different design
                var context2 = cache.LocateOrCreateContext(projectUid, gridDataType, SpatialCacheFingerprint.ConstructFingerprint(projectUid, gridDataType, null, includedSurveyedSurfaces2));

                Assert.True(context.MarkedForRemoval == true, "Empty contents should be marked for removal");

                TRexSpatialMemoryCacheContextTests_Element[,] items  = new TRexSpatialMemoryCacheContextTests_Element[100, 100];
                TRexSpatialMemoryCacheContextTests_Element[,] items2 = new TRexSpatialMemoryCacheContextTests_Element[100, 100];

                // Add content to our 2 contexts
                for (var k = 1; k < 3; k++)
                {
                    for (var i = 0; i < 100; i++)
                    {
                        for (var j = 0; j < 100; j++)
                        {
                            if (k == 1)
                            {
                                items[i, j] = new TRexSpatialMemoryCacheContextTests_Element
                                {
                                    CacheOriginX = (int)(i * SubGridTreeConsts.SubGridTreeDimension),
                                    CacheOriginY = (int)(j * SubGridTreeConsts.SubGridTreeDimension),
                                    SizeInBytes  = 1
                                };
                                cache.Add(context, items[i, j], context.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);;
                            }
                            else
                            {
                                items2[i, j] = new TRexSpatialMemoryCacheContextTests_Element
                                {
                                    CacheOriginX = (int)(i * SubGridTreeConsts.SubGridTreeDimension),
                                    CacheOriginY = (int)(j * SubGridTreeConsts.SubGridTreeDimension),
                                    SizeInBytes  = 1
                                };
                                cache.Add(context2, items2[i, j], context2.InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);
                            }
                        }
                    }
                }

                // verify items added OK
                Assert.True(context.MarkedForRemoval == false, "Context should not be marked for removal");
                Assert.True(context.TokenCount == 10000, "Token count incorrect after addition");
                Assert.True(context2.MarkedForRemoval == false, "Context2 should not be marked for removal");
                Assert.True(context2.TokenCount == 10000, "Token count incorrect after addition of context2");

                // invalidate first of the 2 contexts added
                cache.InvalidateDueToDesignChange(projectUid, designUid);

                cache.MRUList.TokenCount.Should().Be(10000);

                int counter = 0;
                for (var i = 0; i < 100; i++)
                {
                    for (var j = 0; j < 100; j++)
                    {
                        cache.MRUList.Get(counter++).Should().NotBe(items[i, j]);
                    }
                }

                for (var i = 0; i < 100; i++)
                {
                    for (var j = 0; j < 100; j++)
                    {
                        cache.MRUList.Get(counter++).Should().Be(items2[i, j]);
                    }
                }

                //Test context is removed
                Assert.True(context.MarkedForRemoval == true, "Empty context should be marked for removal");
                Assert.True(context.TokenCount == 0, "Token count incorrect after invalidation");
                // Test context2 remains
                Assert.True(context2.MarkedForRemoval == false, "Context2 should not be marked for removal");
                Assert.True(context2.TokenCount == 10000, "Token count incorrect after test");
            }
        }
Example #19
0
        public void CacheContext_Tenancy_IsUpheld_OnConcurrentRequests_WithLRUEvictionOnSmallCacheSize()
        {
            using var cache = new TRexSpatialMemoryCache(100, 1000000, 0.1);

            // Create a context with default invalidation sensitivity, add some data to it
            // and validate that a change bitmask causes appropriate invalidation in concurrent operations
            var contextHeight    = cache.LocateOrCreateContext(Guid.Empty, GridDataType.Height, "fingerprintHeight");
            var contextPassCount = cache.LocateOrCreateContext(Guid.Empty, GridDataType.PassCount, "fingerprintPasscount");

            var contexts = new[] { contextHeight, contextPassCount };

            var itemsHeight    = new TRexSpatialMemoryCacheContextTests_Element[100, 100];
            var itemsPassCount = new TRexSpatialMemoryCacheContextTests_Element[100, 100];

            var items = new[] { itemsHeight, itemsPassCount };

            // Create the bitmask
            ISubGridTreeBitMask mask = new SubGridTreeSubGridExistenceBitMask();

            for (var i = 0; i < 100; i++)
            {
                for (var j = 0; j < 100; j++)
                {
                    mask[(i * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                         (j * SubGridTreeConsts.SubGridTreeDimension) >> SubGridTreeConsts.SubGridIndexBitsPerLevel] = true;

                    items.ForEach((x, index) => x[i, j] = new TRexSpatialMemoryCacheContextTests_Element
                    {
                        Context      = contexts[index],
                        CacheOriginX = i * SubGridTreeConsts.SubGridTreeDimension,
                        CacheOriginY = j * SubGridTreeConsts.SubGridTreeDimension, SizeInBytes = 1
                    });
                }
            }

//      var additionComplete = false;
//      var invalidationComplete = false;

            // Progressively add elements in the cache forcing elements to be removed to accomodate them given the cache's small size
            var additionTask = Task.Run(() => {
                for (var loopCount = 0; loopCount < 100; loopCount++)
                {
                    for (var i = 0; i < 100; i++)
                    {
                        for (var j = 0; j < 100; j++)
                        {
                            for (var contextIndex = 0; contextIndex < contexts.Length; contextIndex++)
                            {
                                TRexSpatialMemoryCacheContextTests_Element elem;
                                if ((elem = (TRexSpatialMemoryCacheContextTests_Element)cache.Get(contexts[contextIndex], i, j)) != null)
                                {
                                    elem.Context.Should().Be(contexts[contextIndex]);
                                }
                                else
                                {
                                    cache.Add(contexts[contextIndex], items[contextIndex][i, j], contexts[contextIndex].InvalidationVersion).Should().Be(CacheContextAdditionResult.Added);
                                }
                            }
                        }
                    }
                }

//        additionComplete = true;
            });

            /*
             * var invalidationTask = Task.Run(() =>
             * {
             * for (var loopCount = 0; loopCount < 100; loopCount++)
             * {
             *  for (var i = 99; i >= 0; i--)
             *  {
             *    for (var j = 99; j >= 0; j--)
             *    {
             *      foreach (var context in contexts)
             *      {
             *        // Empty contexts are ignored
             *        if (context.TokenCount > 0)
             *        {
             *          context.InvalidateSubGrid(i * SubGridTreeConsts.SubGridTreeDimension, j * SubGridTreeConsts.SubGridTreeDimension, out var subGridPresentForInvalidation);
             *        }
             *      }
             *    }
             *  }
             * }
             *
             * invalidationComplete = true;
             * });
             */

/*      var numDesignInvalidations = 0;
 *    var designUpdateTask = Task.Run(async () =>
 *    {
 *      while (!additionComplete || !invalidationComplete)
 *      {
 *        // Mimic design invalidation by periodically invalidating all sub grids
 *        await Task.Delay(10);
 *        contexts[numDesignInvalidations % contexts.Length].InvalidateAllSubGrids();
 *
 *        numDesignInvalidations++;
 *      }
 *    });
 *
 */
            Task.WaitAll(new[] { additionTask /*, invalidationTask, designUpdateTask*/ });

//      numDesignInvalidations.Should().BeGreaterThan(0);
        }