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;
}