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

sql: make tail-call optimization work with nested routines #121109

Merged
merged 3 commits into from
Mar 28, 2024

Conversation

DrewKimball
Copy link
Collaborator

@DrewKimball DrewKimball commented Mar 26, 2024

sql: defer tail-call identification until execbuilding

This commit changes the way routine tail-calls are handled. Before, only
PL/pgSQL sub-routines were considered as tail-calls, and this was determined
by a TailCall property that was set during optbuilding. This approach was
fragile, did not work for explicit tail-calls, and did not work well with
nested routine calls in general.

Now, tail-calls are determined after optimization, during execbuilding.
This will allow explicit (user-specified) tail calls to be optimized. It
also prevents inlining rules from causing correctness bugs, since the old
TailCall property only applied to the original calling routine.

See ExtractTailCalls for further details. The next commit will add
additional testing.

Informs #120916

Release note: None

sql: add tests for tail-call property

This commit adds tests for the ExtractTailCalls function from the
previous commit, and adds a tail-call field to UDFCall expressions
that are in tail-call position in another routine. It also adds a
regression test for #120916.

Informs #120916

Release note: None

sql: check exception handler before applying TCO

This commit finishes the tail-call optimization fix begun by the previous
commits, by preventing TCO when it would lose the reference to the calling
routine's exception handler. PL/pgSQL sub-routines always maintain a
reference to their parent's exception handler, so this isn't a problem for
them. However, explicit (user-specified) nested routines do not track the
calling routine's exception handler.

There is no release note because this bug hasn't appeared in any release.

Fixes #120916

Release note: None

@DrewKimball DrewKimball requested a review from a team as a code owner March 26, 2024 10:26
Copy link

blathers-crl bot commented Mar 26, 2024

Your pull request contains more than 1000 changes. It is strongly encouraged to split big PRs into smaller chunks.

🦉 Hoot! I am a Blathers, a bot for CockroachDB. My owner is dev-inf.

@cockroach-teamcity
Copy link
Member

This change is Reviewable

Copy link
Member

@yuzefovich yuzefovich left a comment

Choose a reason for hiding this comment

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

Nice - very thorough testing!

Reviewed 8 of 8 files at r1, 19 of 19 files at r2, 3 of 3 files at r3, all commit messages.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @DrewKimball and @mgartner)


pkg/sql/routine.go line 504 at r3 (raw file):

		return childBlock == g.expr.BlockState || childBlock.Parent == g.expr.BlockState
	}
	return false

I'm confused here. Based on the comment within the if block, this return must be for the case when we don't have an exception handler, so I'd guess we would be returning true here. Why is this false?


pkg/sql/opt/memo/extract.go line 454 at r1 (raw file):

}

// ExtractTailCalls traverses of the given expression tree, searching for

nit: probably s/traverses of/traverses/.


pkg/sql/opt/memo/extract.go line 484 at r1 (raw file):

		// routine cannot directly be used as the result of the calling routine.
		//
		// * No routine in the input of the project can be a tail-call, since the

This condition doesn't seem to be included in the code - am I missing something?


pkg/sql/opt/memo/testdata/logprops/tail-calls line 0 at r1 (raw file):
nit: logprops/tail-calls is an empty file in the first commit.

Copy link
Collaborator Author

@DrewKimball DrewKimball left a comment

Choose a reason for hiding this comment

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

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @mgartner and @yuzefovich)


pkg/sql/routine.go line 504 at r3 (raw file):

Previously, yuzefovich (Yahor Yuzefovich) wrote…

I'm confused here. Based on the comment within the if block, this return must be for the case when we don't have an exception handler, so I'd guess we would be returning true here. Why is this false?

Good catch, that should be true. I plan to run some simple perf tests to make sure we're properly optimizing PL/pgSQL loops, which would catch this.


pkg/sql/opt/memo/extract.go line 454 at r1 (raw file):

Previously, yuzefovich (Yahor Yuzefovich) wrote…

nit: probably s/traverses of/traverses/.

Done.


pkg/sql/opt/memo/extract.go line 484 at r1 (raw file):

Previously, yuzefovich (Yahor Yuzefovich) wrote…

This condition doesn't seem to be included in the code - am I missing something?

We enforce this condition by simply not recursively calling ExtractTailCalls on the Project operator's input. I augmented the comment with this detail.


pkg/sql/opt/memo/testdata/logprops/tail-calls line at r1 (raw file):

Previously, yuzefovich (Yahor Yuzefovich) wrote…

nit: logprops/tail-calls is an empty file in the first commit.

Done.

Copy link
Member

@yuzefovich yuzefovich left a comment

Choose a reason for hiding this comment

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

The CI is still red, but the changes :LGTM:

Reviewed 23 of 23 files at r4, 20 of 20 files at r5, 3 of 3 files at r6, all commit messages.
Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @mgartner)

@DrewKimball DrewKimball force-pushed the nested-tail-call branch 2 times, most recently from aaf0f65 to da939ac Compare March 27, 2024 20:44
@DrewKimball
Copy link
Collaborator Author

TFYR!

bors r+

@craig
Copy link
Contributor

craig bot commented Mar 27, 2024

Build failed (retrying...):

@yuzefovich
Copy link
Member

Looks like this needs a rebase and ./dev gen testlogic.

bors r-

@craig
Copy link
Contributor

craig bot commented Mar 27, 2024

Canceled.

This commit changes the way routine tail-calls are handled. Before, only
PL/pgSQL sub-routines were considered as tail-calls, and this was determined
by a `TailCall` property that was set during optbuilding. This approach was
fragile, did not work for explicit tail-calls, and did not work well with
nested routine calls in general.

Now, tail-calls are determined after optimization, during execbuilding.
This will allow explicit (user-specified) tail calls to be optimized. It
also prevents inlining rules from causing correctness bugs, since the old
`TailCall` property only applied to the original calling routine.

See `ExtractTailCalls` for further details. The next commit will add
additional testing.

Informs cockroachdb#120916

Release note: None
This commit adds tests for the `ExtractTailCalls` function from the
previous commit, and adds a `tail-call` field to `UDFCall` expressions
that are in tail-call position in another routine. It also adds a
regression test for cockroachdb#120916.

Informs cockroachdb#120916

Release note: None
This commit finishes the tail-call optimization fix begun by the previous
commits, by preventing TCO when it would lose the reference to the calling
routine's exception handler. PL/pgSQL sub-routines always maintain a
reference to their parent's exception handler, so this isn't a problem for
them. However, explicit (user-specified) nested routines do not track the
calling routine's exception handler.

There is no release note because this bug hasn't appeared in any release.

Fixes cockroachdb#120916

Release note: None
@DrewKimball
Copy link
Collaborator Author

bors r+

@yuzefovich yuzefovich added the backport-24.1.x Flags PRs that need to be backported to 24.1. label Mar 28, 2024
@craig craig bot merged commit 00d91d5 into cockroachdb:master Mar 28, 2024
22 checks passed
@DrewKimball DrewKimball deleted the nested-tail-call branch March 28, 2024 19:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport-24.1.x Flags PRs that need to be backported to 24.1.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

sql/plpgsql: incorrect behavior for nested routines
3 participants