internal static async Task ToRpcSharedMemoryAsync()

in src/WebJobs.Script.Grpc/Extensions/RpcSharedMemoryDataExtensions.cs [15:112]


        internal static async Task<RpcSharedMemory> ToRpcSharedMemoryAsync(this object value, DataType dataType, ILogger logger, string invocationId, ISharedMemoryManager sharedMemoryManager)
        {
            if (value == null)
            {
                return new RpcSharedMemory();
            }

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

            SharedMemoryMetadata sharedMemoryMetadata;
            bool needToFreeAfterInvocation = true;

            // Check if the cache is being used or not.
            // The binding extension will only hand out ICacheAwareReadObject if the FunctionDataCache is available and enabled.
            if (value is ICacheAwareReadObject obj)
            {
                if (obj.IsCacheHit)
                {
                    // Content was already present in shared memory (cache hit)
                    logger.LogTrace("Object already present in shared memory for invocation id: {Id}", invocationId);
                    sharedMemoryMetadata = obj.CacheObject;
                    needToFreeAfterInvocation = false;
                }
                else
                {
                    // Put the content into shared memory and get the name of the shared memory map written to.
                    // This will make the SharedMemoryManager keep an active reference to the memory map.
                    sharedMemoryMetadata = await sharedMemoryManager.PutObjectAsync(obj.BlobStream);
                    if (sharedMemoryMetadata != null)
                    {
                        FunctionDataCacheKey cacheKey = obj.CacheKey;

                        // Try to add the object into the cache and keep an active ref-count for it so that it does not get
                        // evicted while it is still being used by the invocation.
                        if (obj.TryPutToCache(sharedMemoryMetadata, isIncrementActiveReference: true))
                        {
                            logger.LogTrace("Put object: {CacheKey} in cache with metadata: {SharedMemoryMetadata} for invocation id: {Id}", cacheKey, sharedMemoryMetadata, invocationId);
                            // We don't need to free the object after the invocation; it will be freed as part of the cache's
                            // eviction policy.
                            needToFreeAfterInvocation = false;
                        }
                        else
                        {
                            logger.LogTrace("Cannot put object: {CacheKey} in cache with metadata: {SharedMemoryMetadata} for invocation id: {Id}", cacheKey, sharedMemoryMetadata, invocationId);
                            // Since we could not add this object to the cache (and therefore the cache will not be able to evict
                            // it as part of its eviction policy) we will need to free it after the invocation is done.
                            needToFreeAfterInvocation = true;
                        }
                    }
                }
            }
            else
            {
                // Put the content into shared memory and get the name of the shared memory map written to
                sharedMemoryMetadata = await sharedMemoryManager.PutObjectAsync(value);
                needToFreeAfterInvocation = true;
            }

            // Check if the object was either already in shared memory or written to shared memory
            if (sharedMemoryMetadata == null)
            {
                logger.LogTrace("Cannot write to shared memory for invocation id: {Id}", invocationId);
                return null;
            }

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

            // When using the cache, we don't need to free the memory map after using it;
            // it will be freed as per the eviction policy of the cache.
            // However, if either the cache was not enabled or the object could not be added to the cache,
            // we will need to free it after the invocation.
            if (needToFreeAfterInvocation)
            {
                // If written to shared memory successfully, add this shared memory map to the list of maps for this invocation
                // so that once the invocation is over, the memory map's resources can be freed.
                sharedMemoryManager.AddSharedMemoryMapForInvocation(invocationId, sharedMemoryMetadata.MemoryMapName);
            }

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

            logger.LogTrace("Put object in shared memory for invocation id: {Id}", invocationId);
            return sharedMem;
        }