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(); }
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(); }
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); } }
/// <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)); }
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); } }
public static void ByteArrayBindingCacheHit( [Blob(ContainerName + "/" + InputBlobName, FileAccess.Read)] ICacheAwareReadObject blob) { Assert.IsTrue(blob.IsCacheHit); SharedMemoryMetadata cacheObj = blob.CacheObject; Assert.NotNull(cacheObj); _numCacheHits = 1; }
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))); } }
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); } }
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); }
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); } }
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)); } }
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); } }
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 _)); } }
/// <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 _)); } }
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); }
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); }
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); } }
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 _)); } }
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); }
/// <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); } }
/// <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); }