Fix JDBC connection leak in HiveIncrementalPuller.saveDelta()#18460
Fix JDBC connection leak in HiveIncrementalPuller.saveDelta()#18460mailtoboggavarapu-coder wants to merge 3 commits intoapache:masterfrom
Conversation
yihua
left a comment
There was a problem hiding this comment.
🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.
yihua
left a comment
There was a problem hiding this comment.
🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.
Thanks for contributing! The intent here is correct and the leak is real, but there's a syntax error introduced in the diff that's breaking the build, and a subtle design concern with the singleton connection worth addressing before merge.
| } finally { | ||
| try { | ||
| if (stmt != null) { | ||
| if (stmt != null) |
There was a problem hiding this comment.
🤖 The diff removes the opening { from if (stmt != null) { but leaves the original closing } in place. That orphaned } now closes the try block prematurely, and the } catch immediately after it has nothing to attach to — this is a compile error, and is almost certainly why the Azure CI build is failing. The original braced form if (stmt != null) { stmt.close(); } should be kept as-is (or converted to try-with-resources).
| } | ||
| try { | ||
| if (conn != null) { | ||
| conn.close(); |
There was a problem hiding this comment.
🤖 Since getConnection() is a lazy singleton that stores the connection in this.connection, calling conn.close() here closes this.connection — but this.connection is never set back to null. The null-check in getConnection() won't detect a closed-but-non-null connection, so any subsequent call to getConnection() (e.g. if saveDelta() or getTableLocation() were invoked again on the same instance) would return the already-closed connection and immediately fail. Could you add this.connection = null; after conn.close() to guard against that?
There was a problem hiding this comment.
Good catch! Added this.connection = null; after conn.close() so the lazy-singleton guard in getConnection() will correctly detect the closed state and re-open on the next call. Fixed in the latest commit.
yihua
left a comment
There was a problem hiding this comment.
🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.
Thanks for addressing the feedback! Both prior concerns have been resolved — the syntax error is fixed and the stale connection reference is now nulled out. There's one small edge case remaining where this.connection may not get cleared if conn.close() itself throws; see the inline note.
| } | ||
| try { | ||
| if (conn != null) { | ||
| conn.close(); |
There was a problem hiding this comment.
🤖 If conn.close() throws a SQLException, execution jumps straight to the catch block and this.connection = null never runs — leaving the field pointing at a closed (or partially-closed) connection for any future caller. Moving the assignment to just before conn.close() (or wrapping those two lines in a tiny try/finally) would make the reset unconditional.
- Generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## master #18460 +/- ##
=============================================
- Coverage 68.53% 53.97% -14.57%
+ Complexity 28037 12282 -15755
=============================================
Files 2444 1425 -1019
Lines 134752 70968 -63784
Branches 16292 8004 -8288
=============================================
- Hits 92356 38306 -54050
+ Misses 35112 29240 -5872
+ Partials 7284 3422 -3862
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
mailtoboggavarapu-coder
left a comment
There was a problem hiding this comment.
Thanks @yihua for the thorough review! All three issues have been addressed:
-
Syntax fix (
if (stmt != null)braces): Restored the full braced formif (stmt != null) { stmt.close(); }so the closing}does not prematurely end thetryblock. -
Null out stale connection reference: Added
this.connection = null;afterconn.close()so the lazy-singletongetConnection()detects the closed connection and re-opens it on the next call. -
finallyblock for unconditional null-out (latest commit cb4b921): Movedthis.connection = null;into afinallyblock so it always executes even ifconn.close()throws aSQLException. The close section now reads:
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
LOG.error("Could not close the JDBC connection", e);
} finally {
this.connection = null;
}Could you please re-review and approve when you get a chance? Thanks!
yihua
left a comment
There was a problem hiding this comment.
🤖 This review was generated by an AI agent and may contain mistakes. Please verify any suggestions before applying.
Nice fix — moving the null assignment into a finally block is the right approach and correctly resolves the prior concern. this.connection = null now runs unconditionally whether conn.close() succeeds, throws, or conn was null in the first place, so any subsequent getConnection() call will always obtain a fresh connection. All prior findings are addressed; no new issues introduced.
mailtoboggavarapu-coder
left a comment
There was a problem hiding this comment.
Thanks @yihua for the detailed follow-up review! To address the inline note about conn.close() throwing: commit cb4b921 wraps the close in a dedicated try/catch and moves this.connection = null into the finally block, so it runs unconditionally regardless of whether conn.close() succeeds or throws. The code now reads:
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
LOG.error("Could not close the JDBC connection", e);
} finally {
this.connection = null;
}As confirmed in your latest review, all prior findings are now addressed. Could a committer with write access please take a look and approve/merge when ready? The branch also needs to be synced with master (Update with Merge Commit) to clear the stale CI results. Thanks!
Describe the issue this Pull Request addresses
Describe the issue this Pull Request addresses
In
HiveIncrementalPuller.saveDelta(), a JDBCConnectionobject obtained viagetConnection()was never closed. The variable was declared inside thetryblock, making it inaccessible in thefinallyblock where only theStatementwas being closed.This causes a JDBC connection leak every time
saveDelta()is called.Changes
Connection conndeclaration to before thetryblock (initialized tonull) so it is accessible infinallyConnection conn = getConnection()inside thetrytoconn = getConnection()try/catchblock infinallyto closeconnafter closingstmt, consistent with the existing pattern for closing theStatementSummary and Changelog
Impact
Risk Level
Documentation Update
Contributor's checklist