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: settings from ALTER ROLE ... SET apply on session init #68128

Merged
merged 3 commits into from
Aug 6, 2021

Conversation

rafiss
Copy link
Collaborator

@rafiss rafiss commented Jul 27, 2021

Fixes #21151

The default settings are applied when creating a new pgwire session. The
information is cached alongside authentication info to reduce the
latency of establishing a connection and minimize the chance of a login
availability hit.

Release note (sql change): Default session variable settings configured
by ALTER ROLE ... SET are now supported. The following order of
precedence is used for variable settings:

  1. settings specified in the connection URL as a query parameter.
  2. per-role and per-database setting configured by ALTER ROLE.
  3. per-role and all-database setting configured by ALTER ROLE.
  4. all-role and per-database setting configured by ALTER ROLE.
  5. all-role and all-database setting configured by ALTER ROLE.

RESET does not validate the setting name.
SET validates both the name and the proposed default value.

Note that the default settings for a role are not inherited if one role
is a member of another role that has default settings. Also, the
defaults only apply during session initialization. Using SET DATABASE to change databases does not apply default settings for that
database.

The public, admin, and root roles cannot have default session
variables configured. The root role also will never use the "all-role"
default settings. This is so that root has fewer dependencies during
session initialization and to make it less likely for root
authentication to become unavailable during the loss of a node.

Changing the default settings for a role requires the role running the
ALTER command to either be an ADMIN or to have the CREATEROLE role
option. Only ADMINs can edit the default settings for another admin.
Futhermore, changing the default settings for ALL roles is
only allowed for ADMINs. Roles without ADMIN or CREATEROLE cannot
change the default settings for themselves.

@rafiss rafiss requested a review from a team July 27, 2021 19:14
@cockroach-teamcity
Copy link
Member

This change is Reviewable

@rafiss rafiss requested a review from RichardJCai July 27, 2021 19:14
@rafiss rafiss changed the title Alter user settings session init sql: settings from ALTER SET ... SET apply on session init Jul 27, 2021
@rafiss rafiss force-pushed the alter-user-settings-session-init branch from 90c7b5a to 18bd841 Compare July 27, 2021 19:25
@rafiss rafiss changed the title sql: settings from ALTER SET ... SET apply on session init sql: settings from ALTER ROLE ... SET apply on session init Jul 28, 2021
@rafiss rafiss force-pushed the alter-user-settings-session-init branch 7 times, most recently from 5301187 to 247bcbc Compare July 29, 2021 20:21
@rafiss rafiss requested a review from a team as a code owner July 29, 2021 20:21
Copy link
Contributor

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

Reviewed 2 of 13 files at r2.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss)


pkg/sql/user.go, line 65 at r3 (raw file):

//   used without a KV lookup.
//
func GetUserAuthInfo(

I think this function is starting to become a bit overloaded, would it be easy to split out the settings resolution into a separate function without adding round trips?


pkg/sql/vars.go, line 1601 at r3 (raw file):

}

// CheckSessionVariableValueValid returns an error iff the value is not valid

nit: sorry for being super super pedantic but it isn't iff since theres another condition it returns an error (in the comment below) 😛


pkg/sql/authentication/cache.go, line 94 at r3 (raw file):

// SettingsCacheEntry for the provided username and databaseName. If the
// information is not in the cache, or if the underlying tables have changed
// since the cache was populated, then the readFromStore callback is used to

nit: Can we rename readFromStore to readFromSystemTables for clarity

Actually why are we passing readFromStore as a function to Get I think it would be more clear if we defined it as a separate helper.


pkg/sql/authentication/cache.go, line 282 at r3 (raw file):

// writeBackToCache tries to put the fetched data into the cache, and returns
// true if it succeeded.

Add comment that this also checks if the data is up to date.

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.

Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss)


pkg/sql/alter_role.go, line 495 at r4 (raw file):

				newSettings,
			)
			if internalExecErr != nil {

nit: seems like this if could be pulled out outside of the outer if.


pkg/sql/drop_database.go, line 331 at r4 (raw file):

		return nil
	}
	rowsDeleted, err := p.ExtendedEvalContext().ExecCfg.InternalExecutor.ExecEx(

nit: this error is not checked right away now.


pkg/sql/pgwire/auth.go, line 141 at r4 (raw file):

	// Add all the defaults to this session's defaults. If there is an
	// error (e.g., a setting that no longer exists, or bad input,

nit: missing closing parenthesis.

@rafiss rafiss force-pushed the alter-user-settings-session-init branch 2 times, most recently from 7a31716 to 3fd15bb Compare August 3, 2021 22:24
@rafiss rafiss requested review from RichardJCai, yuzefovich and a team August 3, 2021 22:37
@rafiss
Copy link
Collaborator Author

rafiss commented Aug 3, 2021

this is ready for another look

@rafiss rafiss force-pushed the alter-user-settings-session-init branch 3 times, most recently from ff44894 to c55f798 Compare August 4, 2021 16:37
Copy link
Contributor

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

Reviewed 4 of 13 files at r2, 1 of 1 files at r4, 2 of 8 files at r5, 16 of 16 files at r8.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/user.go, line 65 at r3 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

I think this function is starting to become a bit overloaded, would it be easy to split out the settings resolution into a separate function without adding round trips?

Add comment here that GetUserAuthInfo also checks for default session settings and the flow here.


pkg/sql/sessioninit/cache.go, line 101 at r10 (raw file):

	f *descs.CollectionFactory,
	username security.SQLUsername,
	readFromSystemTables func(

Is there a reason we have to pass readFromSystemTables as an argument instead of just calling retrieveAuthInfo?


pkg/sql/sessioninit/cache.go, line 361 at r10 (raw file):

			break
		}
		sEntries = append(sEntries, SettingsCacheEntry{k, s})

If multiple entries are found for a setting, are we appending them all here?
I'm thinking if its defined for default user and for the user, both entries would be added to this return right?

I think we should note that this is handled when applying the session settings or maybe dont add duplicates here.


pkg/sql/sessioninit/cache.go, line 416 at r10 (raw file):

}

func (a *Cache) checkStaleness(

nit: rename to something like clearCacheIfStale

Copy link
Collaborator Author

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

oops i forgot to publish my comments from the round of reviews last week

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


pkg/sql/alter_role.go, line 495 at r4 (raw file):

Previously, yuzefovich (Yahor Yuzefovich) wrote…

nit: seems like this if could be pulled out outside of the outer if.

done


pkg/sql/user.go, line 65 at r3 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Add comment here that GetUserAuthInfo also checks for default session settings and the flow here.

done


pkg/sql/vars.go, line 1601 at r3 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

nit: sorry for being super super pedantic but it isn't iff since theres another condition it returns an error (in the comment below) 😛

LOL good catch; i think this was actually a typo, i didn't mean to put iff :D


pkg/sql/sessioninit/cache.go, line 101 at r10 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Is there a reason we have to pass readFromSystemTables as an argument instead of just calling retrieveAuthInfo?

the reason it's passed as a parameter is because this cache lives in a different package (authentication), which cannot depend on the sql package.


pkg/sql/sessioninit/cache.go, line 361 at r10 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

If multiple entries are found for a setting, are we appending them all here?
I'm thinking if its defined for default user and for the user, both entries would be added to this return right?

I think we should note that this is handled when applying the session settings or maybe dont add duplicates here.

yeah, both of those would be added.

there's a comment about this in the retrieveDefaultSettings function of user.go that explains

	// Add an empty slice for all the keys so that something gets cached and
	// prevents a lookup for the same key from happening later.

i'll add a similar note here


pkg/sql/sessioninit/cache.go, line 416 at r10 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

nit: rename to something like clearCacheIfStale

done


pkg/sql/authentication/cache.go, line 94 at r3 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

nit: Can we rename readFromStore to readFromSystemTables for clarity

Actually why are we passing readFromStore as a function to Get I think it would be more clear if we defined it as a separate helper.

the reason it's passed as a parameter is because this cache lives in a different package (authentication), which cannot depend on the sql package.


pkg/sql/authentication/cache.go, line 282 at r3 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Add comment that this also checks if the data is up to date.

done

Copy link
Collaborator Author

@rafiss rafiss 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 @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/authentication/cache.go, line 282 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

done

oh actually, it's done in the last commit of this PR already

@rafiss rafiss force-pushed the alter-user-settings-session-init branch from c55f798 to c4d7995 Compare August 5, 2021 04:00
The default settings are applied when creating a new pgwire session. The
information is cached alongside authentication info to reduce the
latency of establishing a connection and minimize the chance of a login
availability hit.

Release note (sql change): Default session variable settings configured
by `ALTER ROLE ... SET` are now supported. The following order of
precedence is used for variable settings:

1. settings specified in the connection URL as a query parameter.
2. per-role and per-database setting configured by ALTER ROLE.
3. per-role and all-database setting configured by ALTER ROLE.
4. all-role and per-database setting configured by ALTER ROLE.
5. all-role and all-database setting configured by ALTER ROLE.

RESET does not validate the setting name.
SET validates both the name and the proposed default value.

Note that the default settings for a role are not inherited if one role
is a member of another role that has default settings. Also, the
defaults _only_ apply during session initialization. Using `SET
DATABASE` to change databases does not apply default settings for that
database.

The `public`, `admin`, and `root` roles cannot have default session
variables configured. The `root` role also will never use the "all-role"
default settings. This is so that `root` has fewer dependencies during
session initialization and to make it less likely for `root`
authentication to become unavailable during the loss of a node.

Changing the default settings for a role requires the role running the
ALTER command to either be an ADMIN or to have the CREATEROLE role
option. Only ADMINs can edit the default settings for another admin.
Futhermore, changing the default settings for `ALL` roles is
_only_ allowed for ADMINs. Roles without ADMIN or CREATEROLE _cannot_
change the default settings for themselves.
@rafiss rafiss force-pushed the alter-user-settings-session-init branch from c4d7995 to 34d6622 Compare August 5, 2021 04:08
@rafiss rafiss requested a review from RichardJCai August 5, 2021 16:13
Copy link
Contributor

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

Looks almost good to me just some final questions / comments

Reviewed 7 of 17 files at r11, 7 of 19 files at r13.
Reviewable status: :shipit: complete! 0 of 0 LGTMs obtained (waiting on @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/user.go, line 146 at r13 (raw file):

			return retErr
		}
		// Avoid lookingup default settings for root and non-existent users.

nit: space


pkg/sql/sessioninit/cache.go, line 171 at r13 (raw file):

			}

			finishedLoop := a.writeAuthInfoBackToCache(

Should we be calling writeAuthInfoBackToCache if !CacheEnabled?

Or readAuthInfoFromCache?


pkg/sql/sessioninit/cache.go, line 290 at r13 (raw file):

		}

		if dbRoleSettingsTableDesc.IsUncommittedVersion() || !CacheEnabled.Get(&settings.SV) {

Does it make sense to check the !CacheEnabled case outside of this function and return readFromSystemTables outside this function?


pkg/sql/sessioninit/cache.go, line 298 at r13 (raw file):

				databaseID,
			)
			if err != nil || !CacheEnabled.Get(&settings.SV) {

nit: I'm confused


pkg/sql/authentication/cache.go, line 94 at r3 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

the reason it's passed as a parameter is because this cache lives in a different package (authentication), which cannot depend on the sql package.

Gotcha

Copy link
Collaborator Author

@rafiss rafiss 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 @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/sessioninit/cache.go, line 171 at r13 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Should we be calling writeAuthInfoBackToCache if !CacheEnabled?

Or readAuthInfoFromCache?

we would never reach this since the first line of GetAuthInfo() checks if the cache is enabled


pkg/sql/sessioninit/cache.go, line 290 at r13 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

Does it make sense to check the !CacheEnabled case outside of this function and return readFromSystemTables outside this function?

i would have preferred to (that's how GetAuthInfo works). but unfortunately we do need to look up the DB descriptor ID so we have to start a descFactor.Txn to do that


pkg/sql/sessioninit/cache.go, line 298 at r13 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

nit: I'm confused

this was a mistake. nice catch. we actually should just always end the Txn at this point (i also messed up GetAuthInfo)

Add a few comments to increase readability.

Release note: None
@rafiss rafiss force-pushed the alter-user-settings-session-init branch from 34d6622 to 617e51e Compare August 6, 2021 05:35
@rafiss rafiss requested a review from RichardJCai August 6, 2021 20:16
Copy link
Contributor

@RichardJCai RichardJCai left a comment

Choose a reason for hiding this comment

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

:lgtm: minor nit / question Do we test the caching functionality?

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/sessioninit/cache.go, line 298 at r13 (raw file):

Previously, rafiss (Rafi Shamim) wrote…

this was a mistake. nice catch. we actually should just always end the Txn at this point (i also messed up GetAuthInfo)

LOL I accidentally cut my comment short

Copy link
Collaborator Author

@rafiss rafiss left a comment

Choose a reason for hiding this comment

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

there's not a separate test for it -- the idea was that correctness would be checked by existing tests, and performance could be seen in the connection latency test. but as this review has caught there's definitely enough subtle logic in the cache that probably deserves it's own test

i will give some unit tests a shot. thanks for the nudge. i'll do it in a follow up PR so that Vy has a chance to do some acceptance testing on this before her PTO

bors r=RichardJCai

Reviewable status: :shipit: complete! 1 of 0 LGTMs obtained (waiting on @rafiss, @RichardJCai, and @yuzefovich)


pkg/sql/sessioninit/cache.go, line 298 at r13 (raw file):

Previously, RichardJCai (Richard Cai) wrote…

LOL I accidentally cut my comment short

:D

@craig
Copy link
Contributor

craig bot commented Aug 6, 2021

Build succeeded:

@craig craig bot merged commit c19b1e3 into cockroachdb:master Aug 6, 2021
@rafiss rafiss deleted the alter-user-settings-session-init branch August 10, 2021 06:42
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.

sql: Support user/role-level defaults for session variables
4 participants