From 1efe66c217d53145ff46d7e0320da37127c51e8c Mon Sep 17 00:00:00 2001 From: David Boike Date: Thu, 1 Feb 2024 09:39:32 -0600 Subject: [PATCH] Fix memory leak in translating logical addresses to SQL queue addresses (#1281) --- .../Addressing/QueueAddressTranslator.cs | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/NServiceBus.Transport.SqlServer/Addressing/QueueAddressTranslator.cs b/src/NServiceBus.Transport.SqlServer/Addressing/QueueAddressTranslator.cs index 4ae63f799..3e76d560b 100644 --- a/src/NServiceBus.Transport.SqlServer/Addressing/QueueAddressTranslator.cs +++ b/src/NServiceBus.Transport.SqlServer/Addressing/QueueAddressTranslator.cs @@ -20,7 +20,9 @@ public QueueAddressTranslator(string defaultCatalog, string defaultSchema, strin public QueueAddress Generate(Transport.QueueAddress queueAddress) { - return logicalAddressCache.GetOrAdd(queueAddress, TranslateLogicalAddress); + // AddressKey has a GetHashCode implementation and can be used as a dictionary key, Transport.QueueAddress (from Core) does not (at this time) + var key = AddressKey.Create(queueAddress); + return logicalAddressCache.GetOrAdd(key, key => key.ToSqlQueueAddress()); } public CanonicalQueueAddress Parse(string address) @@ -50,32 +52,37 @@ static string Override(string configuredValue, string addressValue, string defau return configuredValue ?? addressValue ?? defaultValue; } - public static QueueAddress TranslateLogicalAddress(Transport.QueueAddress queueAddress) + QueueSchemaAndCatalogOptions queueOptions; + ConcurrentDictionary physicalAddressCache = new(); + ConcurrentDictionary logicalAddressCache = new(); + + record struct AddressKey(string BaseAddress, string Discriminator, string Qualifier, string Schema, string Catalog) { - var nonEmptyParts = new[] + public static AddressKey Create(Transport.QueueAddress a) { - queueAddress.BaseAddress, - queueAddress.Qualifier, - queueAddress.Discriminator - }.Where(p => !string.IsNullOrEmpty(p)); - - var tableName = string.Join(".", nonEmptyParts); + string schema = null; + string catalog = null; + if (a.Properties is not null) + { + a.Properties.TryGetValue(SettingsKeys.SchemaPropertyKey, out schema); + a.Properties.TryGetValue(SettingsKeys.CatalogPropertyKey, out catalog); + } + return new AddressKey(a.BaseAddress, a.Discriminator, a.Qualifier, schema, catalog); + } + public QueueAddress ToSqlQueueAddress() + { + var nonEmptyParts = new[] + { + BaseAddress, + Qualifier, + Discriminator + }.Where(p => !string.IsNullOrEmpty(p)); - string schemaName = null; - string catalogName = null; + var tableName = string.Join(".", nonEmptyParts); - if (queueAddress.Properties != null) - { - queueAddress?.Properties.TryGetValue(SettingsKeys.SchemaPropertyKey, out schemaName); - queueAddress?.Properties.TryGetValue(SettingsKeys.CatalogPropertyKey, out catalogName); + return new QueueAddress(tableName, Schema, Catalog); } - - return new QueueAddress(tableName, schemaName, catalogName); } - - QueueSchemaAndCatalogOptions queueOptions; - ConcurrentDictionary physicalAddressCache = new ConcurrentDictionary(); - ConcurrentDictionary logicalAddressCache = new ConcurrentDictionary(); } } \ No newline at end of file