Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent batch infinite loop with arg length #1794

Merged
merged 3 commits into from
Sep 8, 2022

Conversation

chrisyxlee
Copy link
Contributor

@chrisyxlee chrisyxlee commented Aug 11, 2022

Because the batch queries are only being closed when checking for 2 errors (batch results closed or no result), other errors cause the generated code to infinite loop. This changes from a for loop that only breaks on checking the errors to a for loop that also considers the the total number of params passed in.

Some errors will not infinite loop if you close the results yourself. However, there are other errors that you can't close --

  • Context cancelled during a batch query
  • Connection is busy
  • Bad query

Bad queries typically happen in tests, but the infinite loop has eaten up >20Gb of RAM within a few minutes for me before.

This is usually what happens. It infinite loops, so I can't interrupt the process, and then I have to do ps aux | grep <> to find and kill the process manually:

Screen Shot 2022-08-15 at 15 05 18

Fixes #1678 (which was closed by the reporter since they found a workaround)

@chrisyxlee
Copy link
Contributor Author

🤔 This is the test failure --
At first glance, it seems like the DB connection was overloaded, but not sure if it's a symptom of something that I need to fix.

--- FAIL: TestBatchBooks (0.02s)
    db_test.go:15: db: ***localhost:5432/postgres?sslmode=disable
    db_test.go:94: error updating book 2: conn busy
FAIL
FAIL	github.com/kyleconroy/sqlc/examples/batch/postgresql	0.029s

@kyleconroy kyleconroy self-requested a review August 29, 2022 06:26
Copy link
Collaborator

@kyleconroy kyleconroy left a comment

Choose a reason for hiding this comment

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

Looking over the generated code, I think there's a cleaner way to implement the callbacks without having the check the return value of the error.

func (b *UpdateValuesBatchResults) Exec(f func(int, error)) {
	defer b.br.Close() // Close is safe to call multiple times
	for i := 0; i < b.tot; i++ {
		if b.closed {
			f(i, errrors.New("batch already closed"))
			continue
		}
		_, err := b.br.Exec()
		if f != nil {
			f(i, err)
		}
	}
}

func (b *UpdateValuesBatchResults) Close() error {
	return b.closed = true
	return b.br.Close()
}

Thoughts?

@chrisyxlee
Copy link
Contributor Author

Oh yeah that's super clean, thanks! I'll circle back around and request another review after I've updated everything.

@chrisyxlee
Copy link
Contributor Author

@kyleconroy kyleconroy merged commit 0ebe855 into sqlc-dev:main Sep 8, 2022
@chrisyxlee chrisyxlee deleted the chris/batch-infinite-loop branch September 8, 2022 06:41
jlisthood pushed a commit to jlisthood/sqlc that referenced this pull request Apr 26, 2023
jlisthood pushed a commit to jlisthood/sqlc that referenced this pull request Apr 28, 2023
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.

Errors in Batch cause infinite loop
2 participants