perf: guard loggerExternal.entering/exiting with isLoggable(FINER) across the driver#2955
Open
Ananya2 wants to merge 9 commits into
Open
perf: guard loggerExternal.entering/exiting with isLoggable(FINER) across the driver#2955Ananya2 wants to merge 9 commits into
Ananya2 wants to merge 9 commits into
Conversation
Wrap 396 unguarded loggerExternal.entering() and exiting() calls in SQLServerResultSet with isLoggable(Level.FINER) checks. When logging is disabled (the common production case), this eliminates: - Autoboxing of primitive parameters (int -> Integer) for varargs - Object[] array creation for multi-arg entering/exiting calls - getClassNameLogging() call overhead Benchmarked with 10M iterations on JDK 21: Unguarded: 47.4ms Guarded: 24.2ms (~2x faster per getter call) For a typical query reading 1M rows x 10 columns, this eliminates ~20M unnecessary autoboxing allocations and array creations.
Single-file, zero-dependency benchmark that demonstrates the impact of guarding entering/exiting calls with isLoggable(FINER) in ResultSet getters. Compile and run: javac LoggerGuardBenchmark.java && java LoggerGuardBenchmark
Resolved conflicts in SQLServerResultSet, SQLServerCallableStatement, and SQLServerPreparedStatement by taking origin/main's content and re-applying the loggerExternal.entering/exiting isLoggable(Level.FINER) guards. Line endings preserved per-file to match origin/main convention (LF for most files, CRLF for ScrollWindow/SimpleInputStream/SQLServerConnectionPoolProxy).
1ddc8ba to
787a02e
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR applies the logging optimization from #2945 across additional Microsoft JDBC Driver classes by guarding loggerExternal.entering(...) / loggerExternal.exiting(...) call sites with loggerExternal.isLoggable(Level.FINER) to avoid unnecessary varargs allocations and boxing when FINER logging is disabled.
Changes:
- Wrapped many previously-unguarded
loggerExternal.entering/exitingcalls withisLoggable(Level.FINER)checks. - Standardized some logging-level references from fully-qualified
java.util.logging.Level.FINERtoLevel.FINER(with corresponding imports where needed).
Reviewed changes
Copilot reviewed 9 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java | Guards loggerExternal.entering/exiting calls in statement execution and property accessors. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java | Guards loggerExternal.entering/exiting across parameter-binding and execution paths. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java | Guards loggerExternal.entering/exiting for driver entry points and version/compliance methods. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java | Guards loggerExternal.entering/exiting across DataSource getters/setters and property helpers. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java | Guards loggerExternal.entering/exiting across connection lifecycle and statement factory methods. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkRecord.java | Adds FINER guards around bulk-record entering/exiting and imports Level. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java | Adds FINER guards around entering/exiting in constructors/close/metadata and imports Level. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java | Adds FINER guards around bulk-copy lifecycle and configuration methods. |
| src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java | Adds FINER guards around entering/exiting and imports Level. |
Comments suppressed due to low confidence (4)
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java:8138
prepareCall(String, int, int, int, SQLServerStatementColumnEncryptionSetting)logsloggerExternal.entering(..., "prepareStatement", ...), which misidentifies the method in FINER traces. Update the logged method name to "prepareCall".
public CallableStatement prepareCall(String sql, int nType, int nConcur, int resultSetHoldability,
SQLServerStatementColumnEncryptionSetting stmtColEncSetiing) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.entering(loggingClassName, "prepareStatement",
new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetiing});
}
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java:1629
getStringPropertyperformsif (loggerExternal.isLoggable(Level.FINER) && ...)and then immediately re-checksloggerExternal.isLoggable(Level.FINER)before callingexiting(...). The inner check is redundant; remove it to reduce clutter and minor overhead.
if (loggerExternal.isLoggable(Level.FINER) && !propKey.contains("password")
&& !propKey.contains("Password"))
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.exiting(getClassNameLogging(), "get" + propKey, propValue);
}
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java:1568
getMinorVersion()has two consecutiveloggerExternal.isLoggable(Level.FINER)checks surroundingentering/exitingwith no intervening work. Consolidate to a single guard/cached boolean to reduce redundancy and improve readability.
public int getMinorVersion() {
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.entering(getClassNameLogging(), "getMinorVersion");
}
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.exiting(getClassNameLogging(), "getMinorVersion", SQLJdbcVersion.MINOR);
}
src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java:1584
jdbcCompliant()has two consecutiveloggerExternal.isLoggable(Level.FINER)checks aroundentering/exitingwith no intervening work. Use a single guard (or cached boolean) for both calls to avoid redundantisLoggablechecks.
@Override
public boolean jdbcCompliant() {
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.entering(getClassNameLogging(), "jdbcCompliant");
}
if (loggerExternal.isLoggable(Level.FINER)) {
loggerExternal.exiting(getClassNameLogging(), "jdbcCompliant", Boolean.TRUE);
}
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends PR #2945 (which guarded
SQLServerResultSet) to the rest of the driver by addingisLoggable(Level.FINER)guards around 640 previously-unguardedloggerExternal.entering(...)/loggerExternal.exiting(...)call sites across 13 driver classes. When logging is disabled (the common production configuration), the unguarded variants still incur primitive autoboxing (int → Integer,boolean → Boolean, etc.) for the varargsObject...parameter,Object[]allocations on multi-argument call sites, virtual dispatch intoLogger.entering(...)/Logger.exiting(...), and an internalisLoggable(FINER)check before immediately returning. After this change, the explicit guard short-circuits all of that work whenever the logger level is aboveFINER(the default).Change
Applied mechanically across the remaining driver classes, including
SQLServerCallableStatement.java(235 wrapped call sites),SQLServerPreparedStatement.java(115),SQLServerConnection.java(112),SQLServerStatement.java(99),SQLServerDataSource.java(31),SQLServerBulkCopy.java(23),SQLServerDriver.java(12),SQLServerBulkRecord.java(6),SQLServerBulkCSVFileRecord.java(5), andSQLServerBulkBatchInsertRecord.java(2), for a total of 640 newly-guardedentering(...)/exiting(...)call sites.Every existing:
is now wrapped in:
There is no behavioral change; logging output remains identical whenever
FINERlogging is enabled. Already-guarded sites (833 total across these files) were intentionally left untouched — existingisLoggable(...)checks are detected and skipped automatically. Additionally, fully-qualifiedjava.util.logging.Level.FINERreferences were replaced with the importedLevel.FINERform for consistency with surrounding code, with no behavioral or bytecode impact.Performance Impact
The performance benefit is concentrated in per-row / per-column / per-parameter hot paths where the JIT cannot eliminate boxing and varargs allocations across the java.util.logging.Logger boundary.
Benchmark Results
Driver Fetch Size Avg (ms) Min (ms) Max (ms) Runs
Baseline (Microsoft) default (128) 52,424 48,039 66,302 60
Baseline (Microsoft) 512 51,433 48,038 64,474 60
Perf-Fix (Microsoft) default (128) 50,999 46,701 62,621 69
Perf-Fix (Microsoft) 512 50,628 46,732 66,539 60
Comparison Result
Perf-Fix vs Baseline ~2.7% faster
Interpretation
SQLServerPreparedStatement / SQLServerCallableStatement show the most realistic gains due to heavy parameter-binding paths.
SQLServerBulkCopy / SQLServerBulk*Record see smaller wins because TDS encoding still dominates total runtime.
SQLServerConnection, SQLServerStatement, SQLServerDriver, and SQLServerDataSource are included primarily for consistency; these are connection/query-frequency paths rather than row-frequency paths.
The wall-clock improvement is modest because network round-trips and TDS parsing dominate overall execution time.
The larger benefit is reduced young-generation allocation pressure and GC churn under sustained workloads, which is more visible under allocation profiling than end-to-end latency benchmarks.
For reference, PR #2945 previously measured ~1.82× improvement on a narrow mixed-type SQLServerResultSet benchmark after applying the same optimization pattern.
Risk