Ejemplo n.º 1
0
        public async Task BindToCacheableReadBlob_VerifyCacheMiss()
        {
            bool isIncrementActiveReference = true;
            SharedMemoryMetadata outVal     = null;

            // Enable the cache
            _fixture.CacheMock
            .Setup(c => c.IsEnabled)
            .Returns(true);

            // Mock a cache miss
            _fixture.CacheMock
            .Setup(c => c.TryGet(It.IsAny <FunctionDataCacheKey>(), isIncrementActiveReference, out outVal))
            .Returns(false)
            .Verifiable();

            // Invoke the function which will verify that it was a cache miss
            await _fixture.JobHost.CallAsync(typeof(CacheableBlobsEndToEndTests).GetMethod("ByteArrayBindingCacheMissAsync"));

            // Verify that it was a cache miss
            Assert.AreEqual(1, _numCacheMisses);
            Assert.AreEqual(0, _numCacheHits);
            // Verify that TryGet was called on the cache
            _fixture.CacheMock.Verify();
        }
Ejemplo n.º 2
0
        public async Task BindToCacheableReadBlob_VerifyCacheHit()
        {
            bool isIncrementActiveReference = true;

            // Enable the cache
            _fixture.CacheMock
            .Setup(c => c.IsEnabled)
            .Returns(true);

            // Mock the cache hit scenario
            Mock <SharedMemoryMetadata> cacheObjMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        cacheObj     = cacheObjMock.Object;

            // This access to the cache should be a cache hit (mocking the case where the first access would
            // have inserted the object into the cache)
            _fixture.CacheMock
            .Setup(c => c.TryGet(It.IsAny <FunctionDataCacheKey>(), isIncrementActiveReference, out cacheObj))
            .Returns(true)
            .Verifiable();
            _fixture.CacheMock
            .Setup(c => c.DecrementActiveReference(It.IsAny <FunctionDataCacheKey>()))
            .Verifiable();

            // Invoke the function which will verify that it was a cache hit
            await _fixture.JobHost.CallAsync(typeof(CacheableBlobsEndToEndTests).GetMethod("ByteArrayBindingCacheHit"));

            // Verify that it was a cache hit
            Assert.AreEqual(1, _numCacheHits);
            Assert.AreEqual(0, _numCacheMisses);
            // Verify that TryGet was called on the cache
            _fixture.CacheMock.Verify();
        }
Ejemplo n.º 3
0
        public async Task BindToCacheableReadBlob_VerifyFunctionDataCacheKey()
        {
            bool isIncrementActiveReference = true;

            // Enable the cache
            _fixture.CacheMock
            .Setup(c => c.IsEnabled)
            .Returns(true);

            // Mock the cache hit scenario
            Mock <SharedMemoryMetadata> cacheObjMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        cacheObj     = cacheObjMock.Object;

            // This access to the cache should be a cache hit (mocking the case where the first access would
            // have inserted the object into the cache)
            _fixture.CacheMock
            .Setup(c => c.TryGet(_expectedBlobCacheKey, isIncrementActiveReference, out cacheObj))
            .Returns(true)
            .Verifiable();
            _fixture.CacheMock
            .Setup(c => c.DecrementActiveReference(_expectedBlobCacheKey))
            .Verifiable();

            // Invoke the function which will verify that it was a cache hit
            await _fixture.JobHost.CallAsync(typeof(CacheableBlobsEndToEndTests).GetMethod("ByteArrayBindingCacheHitVerifyFunctionDataCacheKey"));

            // Verify that TryGet was called on the cache
            _fixture.CacheMock.Verify();

            // The function call would raise an exception if the FunctionDataCacheKey does not match
            // match the key generated for the blob.
        }
        public async Task PutObject_NoActiveReferences_ForceOneEviction_VerifyCorrectEviction()
        {
            int    contentSize  = 2 * 1024 * 1024; // 2MB
            int    cacheSize    = 6 * 1024 * 1024; // 6MB
            string cacheSizeVal = cacheSize.ToString();

            IEnvironment environment = new TestEnvironment();

            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheMaximumSizeBytesSettingName, cacheSizeVal);
            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheEnabledSettingName, "1");

            using (ISharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
                using (FunctionDataCache cache = new FunctionDataCache(manager, _loggerFactory, environment))
                {
                    // Prepare content
                    byte[] content = TestUtils.GetRandomBytesInArray(contentSize);

                    // Put into shared memory as three distinct objects
                    SharedMemoryMetadata metadata1 = await manager.PutObjectAsync(content);

                    SharedMemoryMetadata metadata2 = await manager.PutObjectAsync(content);

                    SharedMemoryMetadata metadata3 = await manager.PutObjectAsync(content);

                    // Put the three objects into the cache
                    FunctionDataCacheKey key1 = new FunctionDataCacheKey("foo1", "bar1");
                    FunctionDataCacheKey key2 = new FunctionDataCacheKey("foo2", "bar2");
                    FunctionDataCacheKey key3 = new FunctionDataCacheKey("foo3", "bar3");
                    Assert.True(cache.TryPut(key1, metadata1, isIncrementActiveReference: false, isDeleteOnFailure: false));
                    Assert.True(cache.TryPut(key2, metadata2, isIncrementActiveReference: false, isDeleteOnFailure: false));
                    Assert.True(cache.TryPut(key3, metadata3, isIncrementActiveReference: false, isDeleteOnFailure: false));

                    // Verify that the cache is full
                    Assert.Equal(0, cache.RemainingCapacityBytes);

                    // At this point, the cache is full.
                    // We will create another object and try to insert it.
                    // This should be inserted (as another object will be evicted to make room for this).
                    SharedMemoryMetadata metadata4 = await manager.PutObjectAsync(content);

                    FunctionDataCacheKey key4 = new FunctionDataCacheKey("foo4", "bar4");
                    Assert.True(cache.TryPut(key4, metadata4, isIncrementActiveReference: false, isDeleteOnFailure: false));

                    // The first object should be evicted (least recently used) by now
                    Assert.False(cache.TryGet(key1, isIncrementActiveReference: false, out var _));

                    // Try to open the shared memory map of the first object and ensure it is removed and cannot be opened
                    Assert.False(_mapAccessor.TryOpen(metadata1.MemoryMapName, out var _));

                    // The last three objects (the first two added before eviction and the one resulting in eviction) should be present
                    Assert.True(cache.TryGet(key2, isIncrementActiveReference: false, out var _));
                    Assert.True(cache.TryGet(key3, isIncrementActiveReference: false, out var _));
                    Assert.True(cache.TryGet(key4, isIncrementActiveReference: false, out var _));

                    // Verify that the cache is full
                    Assert.Equal(0, cache.RemainingCapacityBytes);
                }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Used when the object was found in the cache.
 /// </summary>
 /// <param name="cacheKey">Key associated to this object to address it in the <see cref="IFunctionDataCache"/>.</param>
 /// <param name="cacheObject">Describes the shared memory region containing this object.</param>
 /// <param name="functionDataCache">Cache in which to put this object when required.</param>
 public CacheableReadBlob(FunctionDataCacheKey cacheKey, SharedMemoryMetadata cacheObject, IFunctionDataCache functionDataCache)
 {
     IsCacheHit         = true;
     CacheKey           = cacheKey;
     CacheObject        = cacheObject;
     _functionDataCache = functionDataCache;
     _isDisposed        = false;
     _decrementRefCountInCacheOnDispose = true;
 }
        public bool TryPut(FunctionDataCacheKey cacheKey, SharedMemoryMetadata sharedMemoryMeta, bool isIncrementActiveReference, bool isDeleteOnFailure)
        {
            bool isFailure = true;

            try
            {
                lock (_lock)
                {
                    // Check if the key is already present in the cache
                    if (_localCache.ContainsKey(cacheKey))
                    {
                        // Key already exists in the local cache; do not overwrite and don't delete the existing data.
                        _logger.LogTrace("Cannot insert object into cache, it already exists: {ObjectName} and version: {Version}", cacheKey.Id, cacheKey.Version);

                        isFailure = false;
                        return(false);
                    }

                    long bytesRequired = sharedMemoryMeta.Count;
                    if (!EvictUntilCapacityAvailable(bytesRequired))
                    {
                        _logger.LogTrace("Cannot insert object into cache, not enough space (required: {RequiredBytes} < available: {CapacityBytes})", bytesRequired, RemainingCapacityBytes);

                        return(false);
                    }

                    // Add the mapping into the local cache
                    _localCache.Add(cacheKey, sharedMemoryMeta);

                    // Update the LRU list (mark this key as the most recently used)
                    AddToEndOfLRU(cacheKey);

                    if (isIncrementActiveReference)
                    {
                        IncrementActiveReference(cacheKey);
                    }

                    // Update the cache utilization
                    RemainingCapacityBytes -= sharedMemoryMeta.Count;

                    _logger.LogTrace("Object inserted into cache: {ObjectName} and version: {Version} with size: {Size} in shared memory map: {MapName} with updated capacity: {CapacityBytes} bytes", cacheKey.Id, cacheKey.Version, sharedMemoryMeta.Count, sharedMemoryMeta.MemoryMapName, RemainingCapacityBytes);

                    isFailure = false;
                    return(true);
                }
            }
            finally
            {
                if (isFailure && isDeleteOnFailure)
                {
                    if (!_sharedMemoryManager.TryFreeSharedMemoryMap(sharedMemoryMeta.MemoryMapName))
                    {
                        _logger.LogTrace("Cannot free shared memory map: {MapName} with size: {Size} bytes on failure to insert into the cache", sharedMemoryMeta.MemoryMapName, sharedMemoryMeta.Count);
                    }
                }
            }
        }
        public bool TryPutToCache(SharedMemoryMetadata cacheObject, bool isIncrementActiveReference)
        {
            if (IsCacheHit)
            {
                return(false);
            }

            return(_functionDataCache.TryPut(CacheKey, cacheObject, isIncrementActiveReference, isDeleteOnFailure: false));
        }
Ejemplo n.º 8
0
        public async Task PutObject_EmptyByteArray_VerifyFailure()
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Put into shared memory
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(new byte[0]);

                // Verify expected results
                Assert.Null(metadata);
            }
        }
Ejemplo n.º 9
0
        public static void ByteArrayBindingCacheHit(
            [Blob(ContainerName + "/" + InputBlobName, FileAccess.Read)] ICacheAwareReadObject blob)
        {
            Assert.IsTrue(blob.IsCacheHit);

            SharedMemoryMetadata cacheObj = blob.CacheObject;

            Assert.NotNull(cacheObj);

            _numCacheHits = 1;
        }
Ejemplo n.º 10
0
        public async Task GetObject_EmptyContent_SharedMemoryObject_VerifyException()
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
                using (Stream content = new MemoryStream())
                {
                    // Put content into shared memory
                    SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                    // Get object from shared memory
                    await Assert.ThrowsAnyAsync <Exception>(() => manager.GetObjectAsync(metadata.MemoryMapName, 0, (int)content.Length, typeof(SharedMemoryObject)));
                }
        }
Ejemplo n.º 11
0
        public async Task PutObject_String_VerifySuccess(string content)
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Put into shared memory
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                // Verify expected results
                Assert.NotNull(metadata);
                Assert.NotNull(metadata.MemoryMapName);
                Assert.True(Guid.TryParse(metadata.MemoryMapName, out _));
                Assert.Equal(content.Length, metadata.Count);
            }
        }
Ejemplo n.º 12
0
        public void CreateCacheableReadBlob_IsCacheHit()
        {
            // Arrange
            FunctionDataCacheKey        key               = CreateFunctionDataCacheKey();
            Mock <IFunctionDataCache>   cacheMock         = CreateMockFunctionDataCache();
            IFunctionDataCache          cache             = cacheMock.Object;
            Mock <SharedMemoryMetadata> sharedMemMetaMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        sharedMemMeta     = sharedMemMetaMock.Object;
            CacheableReadBlob           cacheableReadBlob = CreateProductUnderTest(key, sharedMemMeta, cache);

            // Act
            bool isCacheHit = cacheableReadBlob.IsCacheHit;

            // Assert
            Assert.True(isCacheHit);
        }
Ejemplo n.º 13
0
        public async Task GetObject_String_VerifyMatches(string content)
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Put content into shared memory
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                // Get object from shared memory
                object readObject = await manager.GetObjectAsync(metadata.MemoryMapName, 0, content.Length, typeof(string));

                string readContent = readObject as string;

                // Verify read content matches the content that was written
                Assert.Equal(content, readContent);
            }
        }
Ejemplo n.º 14
0
        public async Task GetObject_ByteArray_VerifyMatches(int contentSize)
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Prepare content and put into shared memory
                byte[] content = TestUtils.GetRandomBytesInArray(contentSize);
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                // Get object from shared memory
                object readObject = await manager.GetObjectAsync(metadata.MemoryMapName, 0, contentSize, typeof(byte[]));

                byte[] readContent = readObject as byte[];

                // Verify read content matches the content that was written
                Assert.True(TestUtils.UnsafeCompare(content, readContent));
            }
        }
Ejemplo n.º 15
0
        public async Task PutObject_ByteArray_VerifySuccess(int contentSize)
        {
            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Prepare content
                byte[] content = TestUtils.GetRandomBytesInArray(contentSize);

                // Put into shared memory
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                // Verify expected results
                Assert.NotNull(metadata);
                Assert.NotNull(metadata.MemoryMapName);
                Assert.True(Guid.TryParse(metadata.MemoryMapName, out _));
                Assert.Equal(contentSize, metadata.Count);
            }
        }
Ejemplo n.º 16
0
        public async Task FreeSharedMemoryMap_VerifySuccess()
        {
            // Prepare content
            string content = "foobar";

            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
            {
                // Put content into shared memory
                SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                string mapName = metadata.MemoryMapName;

                // Free the shared memory map and try top open it after freeing; should not open
                Assert.True(manager.TryFreeSharedMemoryMap(mapName));
                Assert.False(_mapAccessor.TryOpen(mapName, out _));
            }
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Put this object in the <see cref="IFunctionDataCache"/>.
        /// </summary>
        /// <param name="cacheObject">Details about the shared memory region where this object exists.</param>
        /// <param name="isIncrementActiveReference">If true, increases the reference counter for this object in the
        /// <see cref="IFunctionDataCache"/>.</param>
        /// <returns>True if the object was successfully put into the cache, false otherwise.</returns>
        public bool TryPutToCache(SharedMemoryMetadata cacheObject, bool isIncrementActiveReference)
        {
            if (IsCacheHit)
            {
                // The object is already cached
                return(false);
            }

            if (!_functionDataCache.TryPut(CacheKey, cacheObject, isIncrementActiveReference: isIncrementActiveReference, isDeleteOnFailure: false))
            {
                return(false);
            }

            // If the ref-count was increased in the cache when adding, it needs to be decremented when this object is disposed
            _decrementRefCountInCacheOnDispose = isIncrementActiveReference;

            return(true);
        }
        public async Task PutObject_ActiveReference_VerifyNotEvicted()
        {
            int    contentSize  = 2 * 1024 * 1024; // 2MB
            int    cacheSize    = 3 * 1024 * 1024; // 3MB
            string cacheSizeVal = cacheSize.ToString();

            IEnvironment environment = new TestEnvironment();

            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheMaximumSizeBytesSettingName, cacheSizeVal);
            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheEnabledSettingName, "1");

            using (ISharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
                using (FunctionDataCache cache = new FunctionDataCache(manager, _loggerFactory, environment))
                {
                    // Prepare content
                    byte[] content = TestUtils.GetRandomBytesInArray(contentSize);

                    // Put into shared memory as two objects
                    SharedMemoryMetadata metadata1 = await manager.PutObjectAsync(content);

                    SharedMemoryMetadata metadata2 = await manager.PutObjectAsync(content);

                    // Put one object into the cache and keep an active reference
                    FunctionDataCacheKey key1 = new FunctionDataCacheKey("foo1", "bar1");
                    Assert.True(cache.TryPut(key1, metadata1, isIncrementActiveReference: true, isDeleteOnFailure: false));

                    // The first object has used up the cache space.
                    // When trying to insert the second object into the cache, it should fail
                    // since the first has an active reference and cannot be evicted.
                    FunctionDataCacheKey key2 = new FunctionDataCacheKey("foo2", "bar2");
                    Assert.False(cache.TryPut(key2, metadata2, isIncrementActiveReference: false, isDeleteOnFailure: false));
                    // Ensure that the first object was not evicted
                    Assert.True(cache.TryGet(key1, isIncrementActiveReference: false, out var _));

                    // Drop the active reference on the first object
                    cache.DecrementActiveReference(key1);

                    // Now, when trying to insert the second object into the cache, it should succeed
                    // since the first object can be evicted (since its active reference was dropped).
                    Assert.True(cache.TryPut(key2, metadata2, isIncrementActiveReference: false, isDeleteOnFailure: false));
                    // Ensure that the first object was evicted
                    Assert.False(cache.TryGet(key1, isIncrementActiveReference: false, out var _));
                }
        }
Ejemplo n.º 19
0
        internal static async Task <RpcSharedMemory> ToRpcSharedMemoryAsync(this object value, ILogger logger, string invocationId, ISharedMemoryManager sharedMemoryManager)
        {
            if (value == null)
            {
                return(new RpcSharedMemory());
            }

            if (!sharedMemoryManager.IsSupported(value))
            {
                return(null);
            }

            // Put the content into shared memory and get the name of the shared memory map written to
            SharedMemoryMetadata putResponse = await sharedMemoryManager.PutObjectAsync(value);

            if (putResponse == null)
            {
                logger.LogTrace("Cannot write to shared memory for invocation id: {Id}", invocationId);
                return(null);
            }

            // If written to shared memory successfully, add this shared memory map to the list of maps for this invocation
            sharedMemoryManager.AddSharedMemoryMapForInvocation(invocationId, putResponse.Name);

            RpcDataType?dataType = GetRpcDataType(value);

            if (!dataType.HasValue)
            {
                logger.LogTrace("Cannot get shared memory data type for invocation id: {Id}", invocationId);
                return(null);
            }

            // Generate a response
            RpcSharedMemory sharedMem = new RpcSharedMemory()
            {
                Name   = putResponse.Name,
                Offset = 0,
                Count  = putResponse.Count,
                Type   = dataType.Value
            };

            logger.LogTrace("Put object in shared memory for invocation id: {Id}", invocationId);
            return(sharedMem);
        }
Ejemplo n.º 20
0
        public void TryPutToCacheAlreadyCached_VerifyFailure()
        {
            // Arrange
            FunctionDataCacheKey key            = CreateFunctionDataCacheKey();
            bool isIncrementActiveRefs          = true;
            Mock <IFunctionDataCache> cacheMock = CreateMockFunctionDataCache();

            cacheMock
            .Setup(c => c.TryPut(key, It.IsAny <SharedMemoryMetadata>(), isIncrementActiveRefs, false))
            .Throws(new Exception("This should not be called"));
            IFunctionDataCache          cache             = cacheMock.Object;
            Mock <SharedMemoryMetadata> sharedMemMetaMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        sharedMemMeta     = sharedMemMetaMock.Object;
            CacheableReadBlob           cacheableReadBlob = CreateProductUnderTest(key, sharedMemMeta, cache);

            // Act
            bool result = cacheableReadBlob.TryPutToCache(sharedMemMeta, isIncrementActiveRefs);

            // Assert
            Assert.IsFalse(result);
        }
Ejemplo n.º 21
0
        public void CacheHit_Dispose_VerifyCacheRefCountDecremented()
        {
            // Arrange
            FunctionDataCacheKey        key = CreateFunctionDataCacheKey();
            Mock <SharedMemoryMetadata> sharedMemMetaMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        sharedMemMeta     = sharedMemMetaMock.Object;
            Mock <IFunctionDataCache>   cacheMock         = CreateMockFunctionDataCache();

            cacheMock
            .Setup(c => c.DecrementActiveReference(key))
            .Verifiable();
            IFunctionDataCache cache             = cacheMock.Object;
            CacheableReadBlob  cacheableReadBlob = CreateProductUnderTest(key, sharedMemMeta, cache);

            // Act
            cacheableReadBlob.Dispose();

            // Assert
            // This will ensure that the appropriate method was called on the cache
            cacheMock.Verify();
        }
        public async Task PutObject_NoEvictions_VerifyGet(int contentSize)
        {
            using (ISharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
                using (FunctionDataCache cache = new FunctionDataCache(manager, _loggerFactory, _testEnvironment))
                {
                    // Prepare content
                    byte[] content = TestUtils.GetRandomBytesInArray(contentSize);

                    // Put into shared memory
                    SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                    // Put into cache
                    FunctionDataCacheKey key = new FunctionDataCacheKey("foo", "bar");
                    Assert.True(cache.TryPut(key, metadata, isIncrementActiveReference: false, isDeleteOnFailure: false));

                    // Get from cache
                    Assert.True(cache.TryGet(key, isIncrementActiveReference: false, out SharedMemoryMetadata getMetadata));

                    // Compare if the obtained values are equal
                    Assert.Equal(metadata, getMetadata);
                }
        }
Ejemplo n.º 23
0
        public void CacheMiss_Dispose_VerifyBlobStreamDisposed()
        {
            // Arrange
            FunctionDataCacheKey        key               = CreateFunctionDataCacheKey();
            Mock <IFunctionDataCache>   cacheMock         = CreateMockFunctionDataCache();
            IFunctionDataCache          cache             = cacheMock.Object;
            Mock <SharedMemoryMetadata> sharedMemMetaMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        sharedMemMeta     = sharedMemMetaMock.Object;
            Mock <Stream> blobStreamMock = CreateMockBlobStream();

            blobStreamMock
            .Setup(s => s.Close())     // Close is called internally when Stream is Disposed
            .Verifiable();
            Stream            blobStream        = blobStreamMock.Object;
            CacheableReadBlob cacheableReadBlob = CreateProductUnderTest(key, blobStream, cache);

            // Act
            cacheableReadBlob.Dispose();

            // Assert
            // This will ensure that the appropriate method was called on the stream
            blobStreamMock.Verify();
        }
        public async Task PutObject_FailToPut_DoNotDeleteOnFailure()
        {
            int    contentSize  = 4 * 1024 * 1024; // 4MB
            int    cacheSize    = 3 * 1024 * 1024; // 3MB
            string cacheSizeVal = cacheSize.ToString();

            IEnvironment environment = new TestEnvironment();

            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheMaximumSizeBytesSettingName, cacheSizeVal);
            environment.SetEnvironmentVariable(FunctionDataCacheConstants.FunctionDataCacheEnabledSettingName, "1");

            using (SharedMemoryManager manager = new SharedMemoryManager(_loggerFactory, _mapAccessor))
                using (FunctionDataCache cache = new FunctionDataCache(manager, _loggerFactory, environment))
                {
                    // Prepare content
                    byte[] content = TestUtils.GetRandomBytesInArray(contentSize);

                    // Put into shared memory
                    SharedMemoryMetadata metadata = await manager.PutObjectAsync(content);

                    // Try to put the object into the cache; this will fail because the cache is smaller than the object size.
                    // Since isDeleteOnFailure is false, the object will not be deleted from shared memory.
                    FunctionDataCacheKey key = new FunctionDataCacheKey("foo", "bar");
                    Assert.False(cache.TryPut(key, metadata, isIncrementActiveReference: true, isDeleteOnFailure: false));

                    // Ensure that nothing was cached and no references are held
                    Assert.Empty(cache.LRUList);
                    Assert.Empty(cache.ActiveReferences);
                    Assert.Equal(cacheSize, cache.RemainingCapacityBytes);

                    // Ensure that the SharedMemoryManager has the allocated memory map and it was not deleted
                    Assert.Equal(1, manager.AllocatedSharedMemoryMaps.Count);

                    // Try to open the shared memory map of the first object and ensure it exists and can be opened
                    Assert.True(_mapAccessor.TryOpen(metadata.MemoryMapName, out var _));
                }
        }
Ejemplo n.º 25
0
        public async Task TryPutToCache_BlobPropertiesNotFound_VerifyFailure()
        {
            // Arrange
            Mock <SharedMemoryMetadata> sharedMemMetaMock = CreateMockSharedMemoryMetadata();
            SharedMemoryMetadata        sharedMemMeta     = sharedMemMetaMock.Object;
            bool isIncrementActiveRefs          = false;
            bool isDeleteOnFailure              = false;
            Mock <IFunctionDataCache> cacheMock = CreateMockFunctionDataCache();

            cacheMock
            .Setup(c => c.TryPut(It.IsAny <FunctionDataCacheKey>(), sharedMemMeta, isIncrementActiveRefs, isDeleteOnFailure))
            .Throws(new Exception("This should not be called"));
            IFunctionDataCache cache = cacheMock.Object;
            BlobWithContainer <BlobBaseClient> blob = CreateBlobReference(ContainerName, "blobNotExists", createBlob: false);
            Mock <Stream>      mockBlobStream       = CreateMockBlobStream();
            Stream             blobStream           = mockBlobStream.Object;
            CacheableWriteBlob cacheableWriteBlob   = CreateProductUnderTest(blob, sharedMemMeta, blobStream, cache);

            // Act
            bool result = await cacheableWriteBlob.TryPutToCacheAsync(isDeleteOnFailure);

            // Assert
            Assert.IsFalse(result);
        }
Ejemplo n.º 26
0
 /// <summary>
 /// Create a <see cref="CacheableReadBlob"/> to use for a test.
 /// </summary>
 /// <param name="cacheKey">Key associated to this object to address it in the <see cref="IFunctionDataCache"/>.</param>
 /// <param name="blobStream">Stream to use for writing this object to storage.</param>
 /// <param name="functionDataCache">Cache in which to put this object when required.</param>
 /// <returns>A <see cref="CacheableReadBlob"/> object to use for a test.</returns>
 private static CacheableReadBlob CreateProductUnderTest(FunctionDataCacheKey cacheKey, SharedMemoryMetadata sharedMemMeta, IFunctionDataCache functionDataCache)
 {
     return(new CacheableReadBlob(cacheKey, sharedMemMeta, functionDataCache));
 }
        public bool TryGet(FunctionDataCacheKey cacheKey, bool isIncrementActiveReference, out SharedMemoryMetadata sharedMemoryMeta)
        {
            lock (_lock)
            {
                // Get the value from the local cache
                if (!_localCache.TryGetValue(cacheKey, out sharedMemoryMeta))
                {
                    // Key does not exist in the local cache
                    _logger.LogTrace("Cache miss for object: {ObjectName} and version: {Version}", cacheKey.Id, cacheKey.Version);

                    return(false);
                }

                // Update the LRU list (mark this key as the most recently used)
                AddToEndOfLRU(cacheKey);

                if (isIncrementActiveReference)
                {
                    IncrementActiveReference(cacheKey);
                }

                _logger.LogTrace("Cache hit for object: {ObjectName} and version: {Version} with size: {Size} in shared memory map: {MapName}", cacheKey.Id, cacheKey.Version, sharedMemoryMeta.Count, sharedMemoryMeta.MemoryMapName);

                return(true);
            }
        }
Ejemplo n.º 28
0
 /// <summary>
 /// Create a <see cref="CacheableWriteBlob"/> to use for a test.
 /// </summary>
 /// <param name="blob">Blob for this object in storage.</param>
 /// <param name="cacheObject">Describes the shared memory region containing this object.</param>
 /// <param name="blobStream">Stream to use for writing this object to storage.</param>
 /// <param name="functionDataCache">Cache in which to put this object when required.</param>
 /// <returns>A <see cref="CacheableWriteBlob"/> object to use for a test.</returns>
 private static CacheableWriteBlob CreateProductUnderTest(BlobWithContainer <BlobBaseClient> blob, SharedMemoryMetadata cacheObject, Stream blobStream, IFunctionDataCache functionDataCache)
 {
     return(new CacheableWriteBlob(blob, cacheObject, blobStream, functionDataCache));
 }
        public async Task ToRpcInvocationRequest_RpcSharedMemoryDataTransfer_UsingFunctionDataCache_CacheHit()
        {
            var logger = new TestLogger("test");

            var httpContext = new DefaultHttpContext();

            httpContext.Request.Host   = new HostString("local");
            httpContext.Request.Path   = "/test";
            httpContext.Request.Method = "Post";

            var poco = new TestPoco {
                Id = 1, Name = "Test"
            };

            var bindingData = new Dictionary <string, object>
            {
                { "req", httpContext.Request },
                { "$request", httpContext.Request },
                { "headers", httpContext.Request.Headers.ToDictionary(p => p.Key, p => p.Value) },
                { "query", httpContext.Request.QueryString.ToString() },
                { "sys", new SystemBindingData() }
            };

            const int inputStringLength = 2 * 1024 * 1024;
            string    inputString       = TestUtils.GetRandomString(inputStringLength);

            SharedMemoryMetadata sharedMemObj1 = await _sharedMemoryManager.PutObjectAsync(inputString);

            FunctionDataCacheKey     key1      = new FunctionDataCacheKey("fooStr", "0x1");
            MockCacheAwareReadObject cacheObj1 = new MockCacheAwareReadObject(key1, sharedMemObj1, _functionDataCache);

            const int inputBytesLength = 2 * 1024 * 1024;

            byte[] inputBytes = TestUtils.GetRandomBytesInArray(inputBytesLength);

            SharedMemoryMetadata sharedMemObj2 = await _sharedMemoryManager.PutObjectAsync(inputBytes);

            FunctionDataCacheKey     key2      = new FunctionDataCacheKey("fooBytes", "0x1");
            MockCacheAwareReadObject cacheObj2 = new MockCacheAwareReadObject(key2, sharedMemObj2, _functionDataCache);

            var inputs = new List <(string name, DataType type, object val)>
            {
                ("req", DataType.String, httpContext.Request),
                ("fooStr", DataType.String, cacheObj1),
                ("fooBytes", DataType.Binary, cacheObj2),
            };

            var invocationContext = new ScriptInvocationContext()
            {
                ExecutionContext = new ExecutionContext()
                {
                    InvocationId = Guid.NewGuid(),
                    FunctionName = "Test",
                },
                BindingData           = bindingData,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                Logger                = logger,
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture()
            };

            var functionMetadata = new FunctionMetadata
            {
                Name = "Test"
            };

            var httpTriggerBinding = new BindingMetadata
            {
                Name      = "req",
                Type      = "httpTrigger",
                Direction = BindingDirection.In,
                Raw       = new JObject()
            };

            var fooStrInputBinding = new BindingMetadata
            {
                Name      = "fooStr",
                Type      = "fooStr",
                Direction = BindingDirection.In
            };

            var fooBytesInputBinding = new BindingMetadata
            {
                Name      = "fooBytes",
                Type      = "fooBytes",
                Direction = BindingDirection.In
            };

            var httpOutputBinding = new BindingMetadata
            {
                Name      = "res",
                Type      = "http",
                Direction = BindingDirection.Out,
                Raw       = new JObject(),
                DataType  = DataType.String
            };

            functionMetadata.Bindings.Add(httpTriggerBinding);
            functionMetadata.Bindings.Add(fooStrInputBinding);
            functionMetadata.Bindings.Add(fooBytesInputBinding);
            functionMetadata.Bindings.Add(httpOutputBinding);
            invocationContext.FunctionMetadata = functionMetadata;

            GrpcCapabilities capabilities = new GrpcCapabilities(logger);
            var result = await invocationContext.ToRpcInvocationRequest(logger, capabilities, isSharedMemoryDataTransferEnabled : true, _sharedMemoryManager);

            Assert.Equal(3, result.InputData.Count);

            Assert.Equal("fooStr", result.InputData[1].Name);
            Assert.Equal("fooBytes", result.InputData[2].Name);

            // The input data should be transferred over shared memory
            RpcSharedMemory sharedMem1 = result.InputData[1].RpcSharedMemory;

            // This is what the expected byte[] representation of the string should be
            // We use that to find expected length
            byte[] contentBytes = Encoding.UTF8.GetBytes(inputString);
            Assert.Equal(contentBytes.Length, sharedMem1.Count);

            // Check that the name of the shared memory map is a valid GUID
            Assert.True(Guid.TryParse(sharedMem1.Name, out _));

            // Check the type being sent
            Assert.Equal(sharedMem1.Type, RpcDataType.String);

            // The input data should be transferred over shared memory
            RpcSharedMemory sharedMem2 = result.InputData[2].RpcSharedMemory;

            Assert.Equal(inputBytes.Length, sharedMem2.Count);

            // Check that the name of the shared memory map is a valid GUID
            Assert.True(Guid.TryParse(sharedMem2.Name, out _));

            // Check the type being sent
            Assert.Equal(sharedMem2.Type, RpcDataType.Bytes);
        }