Skip to content

Conversation

edwardneal
Copy link
Contributor

Description

This may need to be backported to 6.1.

#3251 refactored DbConnectionPoolCounters (a netfx-specific class) into a platform-independent SqlClientMetrics class. While the performance counter creation logic remained the same, I introduced a bug in the exception handling.

try
{
if (!ADP.IsEmpty(categoryName) && !ADP.IsEmpty(instanceName))
{
PerformanceCounter instance = new PerformanceCounter();
instance.CategoryName = categoryName;
instance.CounterName = counterName;
instance.InstanceName = instanceName;
instance.InstanceLifetime = PerformanceCounterInstanceLifetime.Process;
instance.ReadOnly = false;
instance.RawValue = 0; // make sure we start out at zero
_instance = instance;
}
}
catch (InvalidOperationException e)
{
ADP.TraceExceptionWithoutRethrow(e);
// TODO: generate Application EventLog entry about inability to find perf counter
}

In the original logic, if an InvalidOperationException was thrown then the exception handler ran before assigning a value to the class' performance counter. In the refactored logic, the counter was returned anyway.

The net effect of this is that if a performance counter failed to initialise (such as if the ".NET Data Provider for SqlServer" provider wasn't present) then it'd be returned in an uninitialised state. The next attempt to increment the counter would try to initialise it again, failing again.

Issues

Fixes #3595.

Testing

I don't think there's a way to add a non-intrusive automatic test, but a manual test works properly.

To break this, I ran:
unlodctr ".NET Data Provider for SqlServer"
main currently fails with an InvalidOperationException, and it's resolved by running:
lodctr "C:\Windows\INF\.NET Data Provider for SqlServer\_dataperfcounters_shared12_neutral.ini"

After this fix, the performance counters now silently fail (and tracing records the error while initializing.)

@edwardneal edwardneal requested a review from a team as a code owner September 20, 2025 20:36
@paulmedynski
Copy link
Contributor

/azp run

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.

Change looks good. Is there a way to alter one or more of the existing integration tests to remove the counter support before running these tests? Would that have caught the regression?

Copy link

codecov bot commented Sep 22, 2025

Codecov Report

❌ Patch coverage is 66.66667% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 58.45%. Comparing base (2655083) to head (3664525).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
...oft/Data/SqlClient/Diagnostics/SqlClientMetrics.cs 66.66% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (2655083) and HEAD (3664525). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (2655083) HEAD (3664525)
addons 1 0
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3623      +/-   ##
==========================================
- Coverage   67.94%   58.45%   -9.50%     
==========================================
  Files         276      270       -6     
  Lines       61641    61324     -317     
==========================================
- Hits        41885    35847    -6038     
- Misses      19756    25477    +5721     
Flag Coverage Δ
addons ?
netcore 62.46% <ø> (-7.42%) ⬇️
netfx 61.30% <66.66%> (-8.71%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@edwardneal
Copy link
Contributor Author

I gave some thought to writing a test, but I think it'd be pretty fragile. In theory we could have a test which manually runs unlodctr, tries to instantiate a connection, then runs lodctr. This would be a system-wide change though - any tests running in parallel on the machine would be impacted, so I think it'd risk generating test failures elsewhere if there are multiple CI runs operating (or multiple CI legs running on the same machine.)

@paulmedynski
Copy link
Contributor

Fair enough, if you tested manually then I'm happy.

I did happen to just discover that all Manual Tests are being run serially, so I guess such a test would work today without perturbing other tests :) I agree that it's probably not worth it currently though.

@mdaigle mdaigle merged commit a9d4238 into dotnet:main Sep 23, 2025
236 checks passed
@mdaigle mdaigle added this to the 7.0-preview2 milestone Sep 23, 2025
edwardneal added a commit to edwardneal/SqlClient that referenced this pull request Sep 23, 2025
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.

System.Diagnostics.PerformanceCounter.InitializeImpl() error
4 participants