-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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: Allow restart savepoint to be renamed #31971
Conversation
@andreimatei, can you review this since @knz is occupied this week? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However you missed something: the postgres savepoint name follows regular identifier naming rules.
For example it's possible to use mixed case identifiers with double quotes.
Therefore it is not correct to upper case the in-memory copy in the session variable, nor it is correct to case-insensitively compare the provided name with the stored name.
Please modify that part of the code and add mixed-case tests to exercise.
Thanks
Reviewed 10 of 10 files at r1.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale)
Is this patch about accepting a customizable prefix on |
Or rather, I think we should accept any prefix to |
What is this distinction "prefix" vs "all name" you're thinking about? The PR (and the original request) was about customizing the entire savepoint name. Not just the prefix. |
The message starts with "apps using Spring ORM that assume than an arbitrary savepoint prefix may be used". So perhaps we can just accept any prefix and be done with it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it useful to set a pattern on the name here, or should it just be a boolean variable treat_all_savepoints_as_cockroach_restart
? That is, in the future when/if we support real savepoints, would Spring (and others) support using one set of savepoint names for retries and another for regular savepoints? My guess is no, and in practice supporting any name other than cockroach_restart
will be equivalent to having no restrictions at all.
Reviewable status: complete! 1 of 0 LGTMs obtained
I very strongly disagree with the idea of "all savepoints should be retry savepoints". We need to delineate those savepoints which are used for the purpose of retries, so that we can add telemetry for all the others used for the purpose of savepointing. Otherwise we will lose the opportunity to measure demand for actual savepoints. |
To be clear, I'm not saying that we should remove the restriction entirely and automatically treat all savepoints as retry savepoints. I'm saying that applications should be able to opt in to this mode, and that opting in to this mode doesn't seem to be substantially worse than opting into a prefix-based whitelist (and it's easier - I doubt the naming scheme used by your ORM is well-documented or even guaranteed to be stable across releases). The prefix-based whitelist only makes sense if there are ORMs that don't allow enough control to use |
Ben, Andrei, why are both of you referring to "prefixes"? This PR (and the linked issue) are about opting in into an alternate identifier for the savepoint name. I don't see the specification/request to recognize a "prefix". Where did you get that idea? |
Regarding "prefixes", the existing code and this patch will accept any
savepoint name, so long as it's prefixed with `cockroach_restart` or
whatever the configured name is. There's a comment on
`ValidateRestartCheckpoint()` that this prefix behavior is to support
observed behavior in the C++ libpq.
…On Tue, Oct 30, 2018 at 11:07 AM kena ***@***.***> wrote:
Ben, Andrei, why are both of you referring to "prefixes"?
This PR (and the linked issue) are about opting in into an alternate
identifier for the savepoint name. I don't see the specification/request to
recognize a "prefix". Where did you get that idea?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#31971 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABGtlDt0795PfuWydNoDPEEvJcS4W0Qzks5uqGsqgaJpZM4X_f0o>
.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On my part, I was confused about what would be sufficient to support Spring - I thought Spring puts its own prefix in front of a user-configurable savepoint name - so we end up with savepoint xxx-cockroach_restart
. That's apparently not the case.
I've talked offline with @bobvawter and suggested that we just make a cluster setting that disables the savepoint name validation entirely (as Ben was also suggesting, although he didn't say cluster setting vs session var). The argument is that, since we reject savepoints coming after the beginning of the txn regardless of the name anyway, technically it's not incorrect to accept any name as the savepoint immediately after the begin
. Like, even if the app doesn't know what it's doing, savepoints immediately after begin
technically behave like proper SQL savepoints.
Reviewable status: complete! 1 of 0 LGTMs obtained
Bob, our design pattern for this kind of feature so far has been a session var, with a default value configurable via a cluster settings. See for example how the
|
That's not true. Once we accept a savepoint as a retry signal, we change the semantics of RELEASE SAVEPOINT, treating it as the real commit. That's why it's important that this be opt in, and as narrowly-scoped as possible (so I don't think a cluster setting is a good idea even if it's just setting a default for a session variable). |
Good point.
…On Tue, Oct 30, 2018 at 4:21 PM Ben Darnell ***@***.***> wrote:
The argument is that, since we reject savepoints coming after the
beginning of the txn regardless of the name anyway, technically it's not
incorrect to accept any name as the savepoint immediately after the begin.
Like, even if the app doesn't know what it's doing, savepoints immediately
after begin technically behave like proper SQL savepoints.
That's not true. Once we accept a savepoint as a retry signal, we change
the semantics of RELEASE SAVEPOINT, treating it as the real commit. That's
why it's important that this be opt in, and as narrowly-scoped as possible
(so I don't think a cluster setting is a good idea even if it's just
setting a default for a session variable).
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#31971 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAXBcRFMLtTABs4OqacxoIaMlQ6PpGyYks5uqLSzgaJpZM4X_f0o>
.
|
To summarize the discussion so far:
Based on the above, I'd like to rework the PR to:
I have a preference against exposing a cluster-wide setting to make Future work:
|
What's the evidence for that?
nope -- the syntax A difference would exist between No comment on the rest. I personally support the proposal to have an opt-in session var. I still would like to double-check the intended semantics by finding out actual evidence of what is needed by clients (see first point above). |
Have we explored the option of just executing the SAVEPOINT command directly with these customers? The ORM's nested transaction framework may use fixed savepoint names, but if they're not getting any benefit from integrating with the ORM then
SQLAlchemy (without our intrusive patch), for example, will always use a savepoint named
I agree with this plan. |
PTAL: This PR has been reworked with the boolean-flag approach. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM on principle -- I am personally a bit cold to the idea of "painting with a large brush" but as long as the setting is opt-in, we're good.
However before this merges this PR needs to clarify the identifier case sensitivity in tests -- I think there is a bug remaining (see my comment below) and an accompanying test should be added.
Reviewed 13 of 13 files at r2.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale)
pkg/sql/conn_executor_exec.go, line 1401 at r2 (raw file):
return errors.Errorf(`SAVEPOINT "%s" is in use`, ex.state.activeSavepointName) } if !ex.sessionData.ForceSavepointRestart && !strings.HasPrefix(savepoint.Normalize(), RestartSavepointName) {
Remove the Normalize()
call. This has been done by the lexer already.
Add tests that confirm the identifier casing rules are applied properly.
pkg/sql/conn_executor_exec.go, line 1403 at r2 (raw file):
if !ex.sessionData.ForceSavepointRestart && !strings.HasPrefix(savepoint.Normalize(), RestartSavepointName) { return pgerror.UnimplementedWithIssueError(10735, "SAVEPOINT not supported except for "+RestartSavepointName)
Consider adding a hint between parentheses that if the user is trying to implement client retries they can change the name of the savepoint with the new setting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added tests for case-sensitivity.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale)
pkg/sql/conn_executor_exec.go, line 1401 at r2 (raw file):
Previously, knz (kena) wrote…
Remove the
Normalize()
call. This has been done by the lexer already.Add tests that confirm the identifier casing rules are applied properly.
Done.
pkg/sql/conn_executor_exec.go, line 1403 at r2 (raw file):
Previously, knz (kena) wrote…
Consider adding a hint between parentheses that if the user is trying to implement client retries they can change the name of the savepoint with the new setting.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 4 of 4 files at r3.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale)
pkg/sql/conn_executor_exec.go, line 1401 at r2 (raw file):
Previously, bobvawter (Bob Vawter) wrote…
Done.
The new code is not correct either. You need string(savepoint)
.
.String()
happens to work because the current value of RestartSavepointName
happens to be lowercase and not a keyword. Should any of these two properties change, String() would fail to do what you want.
pkg/sql/conn_executor_exec.go, line 1399 at r3 (raw file):
return nil } return errors.Errorf(`SAVEPOINT "%s" is in use`, ex.state.activeSavepointName)
Use this instead:
`SAVEPOINT %q is in use`, tree.ErrString(&ex.state.activeSavepointName)
Also, consider using pgerror.NewErrorf
with a suitable error code (perhaps the same as in postgres - 3B001 CodeInvalidSavepointSpecificationError)
pkg/sql/conn_executor_exec.go, line 1405 at r3 (raw file):
"SAVEPOINT not supported except for "+RestartSavepointName, "Retryable transactions with arbitrary SAVEPOINT names can be enabled "+ "with SET force_savepoint_restart=true;")
nit: no need for a semicolon at the end. You can write ... can be enabled with "SET force_savepoint_restart = true".
Currently, the only allowable savepoint names are those beginning with `cockroach_restart` which triggers a Cockroach-specific transaction-retry flow. This creates compatibility issues with certain integration scenarios (e.g. apps using Spring ORM) that can take advantage of restartable transactions, but which assume than an arbitrary savepoint identifier may be used. This patch introduces a new session variable `force_savepoint_restart` which allows the user to customize the savepoint name to any valid identifier, while always triggering a restartable transaction. Telemetry: * Unimplemented-feature error now includes reference to #10735. * `sql.force_savepoint_restart` event recorded when enabled. Resolves #30588 (customize `SAVEPOINT` name) Relates to #15012 (possible change for detecting "empty" transactions) Release note (sql change): Users can customize the auto-retry savepoint name used by the `SAVEPOINT` command by setting the `force_savepoint_restart` session variable. For example: `SET force_savepoint_restart=true; BEGIN; SAVEPOINT foo` will now function as desired. This session variable may also be supplied as part of a connection string to support existing code that assumes that arbitrary savepoint names may be used. Release note (sql change): The names supplied to a `SAVEPOINT` command are now properly treated as SQL identifiers. That is `SAVEPOINT foo` and `SAVEPOINT FOO` are now equivalent statements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: complete! 0 of 0 LGTMs obtained (and 1 stale)
pkg/sql/conn_executor_exec.go, line 1401 at r2 (raw file):
Previously, knz (kena) wrote…
The new code is not correct either. You need
string(savepoint)
.
.String()
happens to work because the current value ofRestartSavepointName
happens to be lowercase and not a keyword. Should any of these two properties change, String() would fail to do what you want.
Done. It just feels shady to cast a type alias back into a string.
pkg/sql/conn_executor_exec.go, line 1399 at r3 (raw file):
Previously, knz (kena) wrote…
Use this instead:
`SAVEPOINT %q is in use`, tree.ErrString(&ex.state.activeSavepointName)
Also, consider using
pgerror.NewErrorf
with a suitable error code (perhaps the same as in postgres - 3B001 CodeInvalidSavepointSpecificationError)
Done.
pkg/sql/conn_executor_exec.go, line 1405 at r3 (raw file):
Previously, knz (kena) wrote…
nit: no need for a semicolon at the end. You can write
... can be enabled with "SET force_savepoint_restart = true".
Removed the semicolon. I suppose the user will be able to determine if they need it or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 1 files at r4.
Reviewable status: complete! 1 of 0 LGTMs obtained
pkg/sql/conn_executor_exec.go, line 1401 at r2 (raw file):
Previously, bobvawter (Bob Vawter) wrote…
Done. It just feels shady to cast a type alias back into a string.
Feel free to propose an additional method on Name
that does the right thing.
bors r+ |
31971: sql: Allow restart savepoint to be renamed r=bobvawter a=bobvawter Currently, the only allowable savepoint names are those beginning with `cockroach_restart` which triggers a Cockroach-specific transaction-retry flow. This creates compatibility issues with certain integration scenarios (e.g. apps using Spring ORM) that can take advantage of restartable transactions, but which assume than an arbitrary savepoint identifier may be used. This patch introduces a new session variable `force_savepoint_restart` which allows the user to customize the savepoint name to any valid identifier, while always triggering a restartable transaction. Telemetry: * Unimplemented-feature error now includes reference to #10735. * `sql.force_savepoint_restart` event recorded when enabled. Resolves #30588 (customize `SAVEPOINT` name) Relates to #15012 (possible change for detecting "empty" transactions) Release note (sql change): Users can customize the auto-retry savepoint name used by the `SAVEPOINT` command by setting the `force_savepoint_restart` session variable. For example: `SET force_savepoint_restart=true; BEGIN; SAVEPOINT foo` will now function as desired. This session variable may also be supplied as part of a connection string to support existing code that assumes that arbitrary savepoint names may be used. Release note (sql change): The names supplied to a `SAVEPOINT` command are now properly treated as SQL identifiers. That is `SAVEPOINT foo` and `SAVEPOINT FOO` are now equivalent statements. Co-authored-by: Bob Vawter <bob@cockroachlabs.com>
Build succeeded |
Currently, the only allowable savepoint names are those beginning with
cockroach_restart
which triggers a Cockroach-specific transaction-retry flow.This creates compatibility issues with certain integration scenarios (e.g. apps
using Spring ORM) that can take advantage of restartable transactions, but
which assume than an arbitrary savepoint identifier may be used.
This patch introduces a new session variable
force_savepoint_restart
whichallows the user to customize the savepoint name to any valid identifier, while
always triggering a restartable transaction.
Telemetry:
sql.force_savepoint_restart
event recorded when enabled.Resolves #30588 (customize
SAVEPOINT
name)Relates to #15012 (possible change for detecting "empty" transactions)
Release note (sql change): Users can customize the auto-retry savepoint name
used by the
SAVEPOINT
command by setting theforce_savepoint_restart
session variable. For example:
SET force_savepoint_restart=true; BEGIN; SAVEPOINT foo
will now function as desired. This session variable may also besupplied as part of a connection string to support existing code that assumes
that arbitrary savepoint names may be used.
Release note (sql change): The names supplied to a
SAVEPOINT
command are nowproperly treated as SQL identifiers. That is
SAVEPOINT foo
andSAVEPOINT FOO
are now equivalent statements.