Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DynamoDb SDK is not trim-safe for Native AOT at Table.LoadTable #2574

Closed
2 tasks
Beau-Gosse-dev opened this issue Mar 24, 2023 · 3 comments
Closed
2 tasks
Labels
dynamodb feature-request A feature should be added or improved.

Comments

@Beau-Gosse-dev
Copy link

Describe the feature

When calling Table.LoadTable under a Native AOT build, there is trim unsafe code that throws the below error at runtime.

Copy of Original Issue

Originally opened as this issue: awslabs/dotnet-nativeaot-labs#10
I wrote a lambda function with .net 7 native AOT. Without a database access, it worked properly. I tried to code access to DynamoDB table. Here is my code:

internal class DbRepository : IDbRepository
{
    private static readonly IAmazonDynamoDB _dbClient = new AmazonDynamoDBClient();

    public DbRepository()
    {
        DbTable = Table.LoadTable(_dbClient, Utils.GetRequiredEnvVariable("DDB_TABLE"));
    }

    public Table DbTable { get; }

In the constructor for the statement Table.LoadTable I got following exception:

---> System.TypeInitializationException: A type initializer threw an exception. To determine which type, inspect the InnerException's StackTrace property. 
---> System.NotSupportedException: 'System.Nullable`1[System.Byte]' is missing native code or metadata. This can happen for code that is not compatible with trimming or AOT. Inspect and fix trimming and AOT related warnings that were generated when the app was published. For more information see https://aka.ms/nativeaot-compatibility
at System.Reflection.Runtime.General.TypeUnifier.WithVerifiedTypeHandle(RuntimeConstructedGenericTypeInfo, RuntimeTypeInfo[]) + 0x98 
at Amazon.DynamoDBv2.Converter`1.<GetTargetTypes>d__0.MoveNext() + 0xdf
at Amazon.DynamoDBv2.ConverterCache.AddConverter(Converter converter, DynamoDBEntryConversion conversion) + 0x99 
at Amazon.DynamoDBv2.DynamoDBEntryConversion.AddConverters(String suffix) + 0x1ca
at Amazon.DynamoDBv2.DynamoDBEntryConversion..ctor(ConversionSchema schema, Boolean isImmutable) + 0xa1
at Amazon.DynamoDBv2.DynamoDBEntryConversion..cctor() + 0x27
at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb9

I'm using the latest version of AWSSDK.DynamoDBv2 (3.7.102.5). I added the AWSSDK.DynamoDBv2 in the rd-config file too:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <Assembly Name="bootstrap" Dynamic="Required All"></Assembly>
	<Assembly Name="AWSSDK.SimpleSystemsManagement" Dynamic="Required All"></Assembly>
	<Assembly Name="AWSSDK.Core" Dynamic="Required All"></Assembly>
	<Assembly Name="AWSSDK.DynamoDBv2" Dynamic="Required All"></Assembly>
  </Application>
</Directives>

I'm using Windows 11 Pro 10.0.22621 with dotnet version 7.0.100. And here is my project file:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <AWSProjectType>Lambda</AWSProjectType>
    <AssemblyName>bootstrap</AssemblyName>
    <!-- This property makes the build directory similar to a publish directory and helps the AWS .NET Lambda Mock Test Tool find project dependencies. -->
    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
    <!-- Generate Native AOT image during publishing to improve cold start time. -->
    <PublishAot>true</PublishAot>
    <!-- StripSymbols tells the compiler to strip debugging symbols from the final executable if we're on Linux and put them into their own file. 
    This will greatly reduce the final executable's size.-->
    <StripSymbols>true</StripSymbols>
  </PropertyGroup>
  <!-- 
  When publishing Lambda functions for ARM64 to the provided.al2 runtime a newer version of libicu needs to be included
  in the deployment bundle because .NET requires a newer version of libicu then is preinstalled with Amazon Linux 2.
  -->
  <ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-arm64'">
    <RuntimeHostConfigurationOption Include="System.Globalization.AppLocalIcu" Value="68.2.0.9" />
    <PackageReference Include="Microsoft.ICU.ICU4C.Runtime" Version="68.2.0.9" />
  </ItemGroup>
  <ItemGroup>
    <PackageReference Include="Amazon.Lambda.APIGatewayEvents" Version="2.6.0" />
    <PackageReference Include="Amazon.Lambda.RuntimeSupport" Version="1.8.2" />
    <PackageReference Include="Amazon.Lambda.Core" Version="2.1.0" />
    <PackageReference Include="Amazon.Lambda.Serialization.SystemTextJson" Version="2.3.0" />
    <PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.102.5" />
    <PackageReference Include="AWSSDK.SimpleSystemsManagement" Version="3.7.103.37" />
    <PackageReference Include="LazyCache.AspNetCore" Version="2.4.0" />
  </ItemGroup>
   
  <ItemGroup>
    <!--The runtime directives file allows the compiler to know what types and assemblies to not trim out of the final binary, even if they don't appear to be used.-->
    <RdXmlFile Include="rd.xml" />
  </ItemGroup>
</Project>

Use Case

Without trim safety, certain DynamoDb calls can't be used with Native AOT to speed up cold start times.

Proposed Solution

Remove reflection calls from here:

public override IEnumerable<Type> GetTargetTypes()

With a local version I tried to attribute the generic type with DynamicallyAccessedMembers, but the problem seems to be that it's not T that is getting trimmed, it's Nullable<T>.
Example:

public static IEnumerable<Type> GetTargetTypes<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
{
      var type = typeof(T);
      yield return type;

      var typeInfo = TypeFactory.GetTypeInfo(type);
      if (typeInfo.IsValueType)
      {
          //yield return typeof(Nullable<T>);
          var nullableType = typeof(Nullable<>).MakeGenericType(type);
          yield return nullableType;
      }
}

Other Information

Unfortunately, this seems to be an error that can't be fixed by telling the compiler not to trim the DynamoDb library since the thing actually being trimmed out is in a System library. So using a TrimmerRootAssembly or rd.xml didn't work.

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

AWS .NET SDK and/or Package version used

<PackageReference Include="AWSSDK.DynamoDBv2" Version="3.7.102.5" />

Targeted .NET Platform

.NET 7

Operating System and version

Windows 10

@Beau-Gosse-dev Beau-Gosse-dev added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. labels Mar 24, 2023
@ashishdhingra
Copy link
Contributor

@Beau-Gosse-dev Thanks for reporting the issue. There is another issue related to DynamoDB trimming support #2542. Could we close this issue and instead track it there?

@ashishdhingra ashishdhingra removed the needs-triage This issue or PR still needs to be triaged. label Mar 24, 2023
@Beau-Gosse-dev
Copy link
Author

Ah, thanks Ashish, yes. That looks like the same CollectionConverter.GetTargetTypes method causing the error. Sorry for the duplicate.

@github-actions
Copy link

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see.
If you need more assistance, please either tag a team member or open a new issue that references this one.
If you wish to keep having a conversation with other community members under this issue feel free to do so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dynamodb feature-request A feature should be added or improved.
Projects
None yet
Development

No branches or pull requests

2 participants