From e11401c2dcec0dffc951beec2e384ded6417a864 Mon Sep 17 00:00:00 2001 From: PascalSenn Date: Sun, 25 Jun 2023 20:51:50 +0200 Subject: [PATCH] Memory Optimization on Schema (#6290) --- .../Core/src/Types/Schema.Initialization.cs | 32 ++++++++++++------- .../Core/src/Types/Types/DirectiveType.cs | 22 +++++++------ 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/HotChocolate/Core/src/Types/Schema.Initialization.cs b/src/HotChocolate/Core/src/Types/Schema.Initialization.cs index 52632fed2a3..194e887e08b 100644 --- a/src/HotChocolate/Core/src/Types/Schema.Initialization.cs +++ b/src/HotChocolate/Core/src/Types/Schema.Initialization.cs @@ -9,7 +9,7 @@ namespace HotChocolate; public partial class Schema { - private readonly Action _configure; + private Action _configure; private bool _sealed; protected internal Schema() @@ -24,18 +24,30 @@ public Schema(Action configure) protected virtual void Configure(ISchemaTypeDescriptor descriptor) { } - protected sealed override SchemaTypeDefinition CreateDefinition( - ITypeDiscoveryContext context) + protected sealed override SchemaTypeDefinition CreateDefinition(ITypeDiscoveryContext context) { - var descriptor = SchemaTypeDescriptor.New( - context.DescriptorContext, - GetType()); + var descriptor = SchemaTypeDescriptor.New(context.DescriptorContext, GetType()); _configure(descriptor); return descriptor.CreateDefinition(); } + protected override void OnAfterInitialize( + ITypeDiscoveryContext context, + DefinitionBase definition) + { + base.OnAfterInitialize(context, definition); + + // we clear the configuration delegate to make sure that we do not hold on to any references + // if we do not do this all the instances used during initialization will be kept in memory + // until the schema is phased out. + // We do this in OnAfterInitialized because after this point the schema is marked as + // initialized. This means that a subsequent call to Initialize will throw anyway and + // therefore we do not need to keep the configuration delegate. + _configure = null; + } + protected override void OnRegisterDependencies( ITypeDiscoveryContext context, SchemaTypeDefinition definition) @@ -46,10 +58,7 @@ protected override void OnRegisterDependencies( { foreach (var directive in definition.Directives) { - context.Dependencies.Add( - new( - directive.Type, - TypeDependencyFulfilled.Completed)); + context.Dependencies.Add(new(directive.Type, TypeDependencyFulfilled.Completed)); } } @@ -72,8 +81,7 @@ protected override void OnCompleteType( Services = context.Services; } - internal void CompleteSchema( - SchemaTypesDefinition schemaTypesDefinition) + internal void CompleteSchema(SchemaTypesDefinition schemaTypesDefinition) { if (schemaTypesDefinition is null) { diff --git a/src/HotChocolate/Core/src/Types/Types/DirectiveType.cs b/src/HotChocolate/Core/src/Types/Types/DirectiveType.cs index e1a214478a3..743959c6540 100644 --- a/src/HotChocolate/Core/src/Types/Types/DirectiveType.cs +++ b/src/HotChocolate/Core/src/Types/Types/DirectiveType.cs @@ -11,16 +11,17 @@ namespace HotChocolate.Types; /// +/// /// A GraphQL schema describes directives which are used to annotate various parts of a /// GraphQL document as an indicator that they should be evaluated differently by a /// validator, executor, or client tool such as a code generator. -/// -/// http://spec.graphql.org/draft/#sec-Type-System.Directives +/// +/// http://spec.graphql.org/draft/#sec-Type-System.Directives /// public partial class DirectiveType : TypeSystemObjectBase - , IHasRuntimeType - , IHasTypeIdentity + , IHasRuntimeType + , IHasTypeIdentity { private Action? _configure; private Func _createInstance = default!; @@ -81,12 +82,11 @@ public static DirectiveType CreateUnsafe(DirectiveTypeDefinition definition) /// /// Gets the directive field middleware. /// - public DirectiveMiddleware? Middleware { get; private set; } = - default!; + public DirectiveMiddleware? Middleware { get; private set; } /// - /// Defines that this directive can be used in executable GraphQL documents. - /// + /// Defines that this directive can be used in executable GraphQL documents. + /// /// In order to be executable a directive must at least be valid /// in one of the following locations: /// QUERY () @@ -97,12 +97,13 @@ public static DirectiveType CreateUnsafe(DirectiveTypeDefinition definition) /// FRAGMENT_SPREAD () /// INLINE_FRAGMENT () /// VARIABLE_DEFINITION () + /// /// public bool IsExecutableDirective { get; private set; } /// - /// Defines that this directive can be applied to type system members. - /// + /// Defines that this directive can be applied to type system members. + /// /// In order to be a type system directive it must at least be valid /// in one of the following locations: /// SCHEMA () @@ -116,6 +117,7 @@ public static DirectiveType CreateUnsafe(DirectiveTypeDefinition definition) /// ENUM_VALUE () /// INPUT_OBJECT () /// INPUT_FIELD_DEFINITION () + /// /// public bool IsTypeSystemDirective { get; private set; }