Skip to content

Conversation

@edwardneal
Copy link
Contributor

Description

This is a minor set of improvements in memory usage which I noticed while looking at the XML access pathway and thinking about some of the layers of caching within SqlClient.

The first commit caches and reuses XmlWriterSettings objects. As per the remarks in the documentation, these can be reused and so don't need to be allocated every time. I've promoted these to a static readonly field in the SqlStreamingXml class because this is only used when reading XML data. The other places this is used are TdsParser and ValueUtilsSmi, and these don't necessarily need to use XML functionality so I lazily allocate them on first use.

In the second commit, we eliminate allocations of MemoryCacheEntryOptions objects. These are essentially DTOs which are used to modify the expiration times of entries in various MemoryCaches. Rather than allocating a new object, we can use a different overload which accepts the expiration timespan directly.

Issues

None.

Testing

Local tests of these pathways pass - could someone run CI please?

Lazily initialize these where the class might be used without needing to support XML.
@edwardneal edwardneal requested a review from a team as a code owner November 20, 2025 21:30
@cheenamalhotra
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(ThreadRetryCacheTimeoutInMinutes)
};
ThreadRetryCache.Set<string>(Thread.CurrentThread.ManagedThreadId.ToString(), retryThreadID, options);
ThreadRetryCache.Set<string>(Thread.CurrentThread.ManagedThreadId.ToString(), retryThreadID, absoluteExpirationRelativeToNow: TimeSpan.FromMinutes(10));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continue to use constant for timeout

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks - I've reintroduced the various constants in this comment and elsewhere.

Comment on lines -21 to -22
// Cache timeout of 8 hours to be consistent with jwt validity.
private static int enclaveCacheTimeOutInHours = 8;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continue using constant (convert it to const instead)

AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(10)
};
_cache.Set<bool>(cacheLookupKey, result, options);
_cache.Set<bool>(cacheLookupKey, result, absoluteExpirationRelativeToNow: TimeSpan.FromDays(10));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduce const for magic number

AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(10)
};
_cache.Set<Dictionary<string, SqlCipherMetadata>>(cacheLookupKey, cipherMetadataDictionary, options);
TimeSpan expirationPeriod = TimeSpan.FromHours(10);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduce const for magic number

AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(1)
};
rootSigningCertificateCache.Set<X509Certificate2Collection>(attestationUrl, certificateCollection, options);
rootSigningCertificateCache.Set<X509Certificate2Collection>(attestationUrl, certificateCollection, absoluteExpirationRelativeToNow: TimeSpan.FromDays(1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduce const for magic number

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements two memory optimization improvements: (1) reuses XmlWriterSettings objects via static fields instead of allocating them repeatedly, and (2) eliminates allocations of MemoryCacheEntryOptions objects by using the MemoryCache.Set overload that accepts expiration timespan directly.

  • Caches XmlWriterSettings objects in static fields with lazy initialization in TdsParser, ValueUtilsSmi, and SqlStreamingXml
  • Refactors all MemoryCache.Set calls to use absoluteExpirationRelativeToNow parameter directly instead of creating MemoryCacheEntryOptions objects
  • Improves code clarity by moving cache timeout comments closer to their usage points

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
VirtualSecureModeEnclaveProviderBase.cs Eliminates MemoryCacheEntryOptions allocation by using direct parameter
TdsParser.cs Adds static fields for async/sync XmlWriterSettings with lazy initialization
SqlSymmetricKeyCache.cs Eliminates MemoryCacheEntryOptions allocation by using direct parameter
SqlStream.cs Adds static readonly XmlWriterSettings field in SqlStreamingXml class
SqlQueryMetadataCache.cs Eliminates MemoryCacheEntryOptions allocations and extracts expiration period to local variable for reuse
SignatureVerificationCache.cs Eliminates MemoryCacheEntryOptions allocation by using direct parameter
ValueUtilsSmi.cs Adds static field for XmlWriterSettings with lazy initialization
EnclaveSessionCache.cs Eliminates MemoryCacheEntryOptions allocation and moves timeout comment inline
EnclaveProviderBase.cs Eliminates MemoryCacheEntryOptions allocation and inlines constant value
AzureAttestationBasedEnclaveProvider.cs Eliminates MemoryCacheEntryOptions allocation by using direct parameter
Comments suppressed due to low confidence (2)

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs:12775

  • Write to static field from instance method, property, or constructor.
                ? (s_asyncWriterSettings ??= new() { CloseOutput = false, ConformanceLevel = ConformanceLevel.Fragment, Async = true })

src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParser.cs:12776

  • Write to static field from instance method, property, or constructor.
                : (s_syncWriterSettings ??= new() { CloseOutput = false, ConformanceLevel = ConformanceLevel.Fragment });

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Introduce and reintroduce constants containing cache expiration periods
@paulmedynski paulmedynski self-assigned this Nov 24, 2025
@paulmedynski
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

Turn the lazy field initialisation into a property, and the TimeOutInX constants which were only used to create a TimeSpan into a static readonly TimeSpan.
@paulmedynski
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 2 pipeline(s).

Copy link
Contributor

@paulmedynski paulmedynski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants