Skip to content

GitHub Issue 1435: DataIterator leaks DB connection when import abort… - #7919

Merged
labkey-jeckels merged 2 commits into
release26.7-SNAPSHOTfrom
26.7_fb_1435_dataIteratorResultSetLeak
Aug 10, 2026
Merged

GitHub Issue 1435: DataIterator leaks DB connection when import abort…#7919
labkey-jeckels merged 2 commits into
release26.7-SNAPSHOTfrom
26.7_fb_1435_dataIteratorResultSetLeak

Conversation

@labkey-jeckels

Copy link
Copy Markdown
Contributor

Rationale

We're leaking a DB connection (eventually cleaned up on garbage collection) when DataIterator construction bails out due to a problem like duplicate or unwanted columns.

Changes

  • Helper wrapOrClose() method to centralize closing when we bail out on a handled or unhandled error
  • Convert DataIterator implementations to use helper
  • Automated tests

* Builds `in` and hands it to `wrapper`, propagating a null input (which means the context has errors). If the
* wrapper throws or returns null, the built input is closed rather than abandoned/leaked.
*/
public static @Nullable DataIterator wrapOrClose(DataIteratorBuilder in, DataIteratorContext context, UnaryOperator<DataIterator> wrapper)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

DataIteratorBuilder instead of UnaryOperator wrapper?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OK, I get it. If I weren't trying to minimize the diff, I'd probably rewrite this so that final AbstractDataIteratorBuilder.getDataIterator() did this wrapOrClose() work, and had a abstract DataIterator _getDataItertor().

I might make the comment describe the intended pattern. "DataIteratorBuilder.getDataIterator() calls this to simplify implementing the success or close() input contract."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated, and added a little top-level class JavaDoc too.

* Builds `in` and hands it to `wrapper`, propagating a null input (which means the context has errors). If the
* wrapper throws or returns null, the built input is closed rather than abandoned/leaked.
*/
public static @Nullable DataIterator wrapOrClose(DataIteratorBuilder in, DataIteratorContext context, UnaryOperator<DataIterator> wrapper)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OK, I get it. If I weren't trying to minimize the diff, I'd probably rewrite this so that final AbstractDataIteratorBuilder.getDataIterator() did this wrapOrClose() work, and had a abstract DataIterator _getDataItertor().

I might make the comment describe the intended pattern. "DataIteratorBuilder.getDataIterator() calls this to simplify implementing the success or close() input contract."

@labkey-jeckels
labkey-jeckels merged commit b1340bb into release26.7-SNAPSHOT Aug 10, 2026
7 of 10 checks passed
@labkey-jeckels
labkey-jeckels deleted the 26.7_fb_1435_dataIteratorResultSetLeak branch August 10, 2026 23:40
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.

2 participants