-
Notifications
You must be signed in to change notification settings - Fork 695
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
Adds REASSIGN OWNED BY propagation #7319
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #7319 +/- ##
==========================================
- Coverage 89.61% 83.19% -6.43%
==========================================
Files 278 350 +72
Lines 60129 62749 +2620
Branches 7490 8131 +641
==========================================
- Hits 53882 52201 -1681
- Misses 4104 8170 +4066
- Partials 2143 2378 +235 |
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.
REASSIGN | TO non-distributed role | TO distributed role |
---|---|---|
OWNED BY all-non-distributed roles | C1 | C2 |
OWNED BY some-distributed roles | C3 | C4 |
OWNED BY all-distributed roles | C5 | C6 |
Going through all the possible scenarios, it's obvious that while Citus should not return any DDLJobs for C1, it needs to return a DDLJob for C6.
However, I'm confused about the other scenarios, namely, C2, C3, C4 and C5 i.e., the cases where DDL both references non-distributed roles as well as distributed ones, either in OWNED BY
clause or in TO
clause.
As an example, for C4, would it really make sense to only reassign the objects owned by distributed ones to the one given in TO
clause, or would it be confusing on user's end? We have two options here; either do what this PR proposes (filter the distributed roles in provided in OWNED BY
claue and forget about the others), or automatically propagate non-distributed roles before sending REASSIGN OWNED BY
command to workers.
I think choosing the first option would cause role objects to get out-of-sync on different nodes so might not be the ideal approach, so I'd like to talk more about this in weekly sync: @gurkanindibay, @JelteF.
Or, for C5, I'd expect the solution proposed in this PR to fail as it would incorrectly search for the role provided in TO
clause on worker nodes. Do we have any tests for that?
|
||
|
||
List * | ||
PreprocessReassignOwnedStmt(Node *node, const char *queryString, |
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.
Should we have this in Postprocess instead?
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.
There is no reason to move this to Postprocess actually. It just prepares the command.
Normally when you check other statements who is in the nature of Alter like PreprocessAlterDatabaseStmt, we use Preprocess
Create needs to have Post since address only exists after local execution, Drop needs to be Pre since address is missing after local drop execution.
For Alter style statements, there is no such requirement.
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.
let's get this into postprocess as we've discussed in group chat, due to reasons discussed there
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.
let's get this into postprocess as we've discussed in group chat, due to reasons discussed there
(discussion in group chat was still on-going indeed)
As we've discussed earlier this week, let's not filter out local roles but rely on workers to throw an error if the role doesn't exist on a worker node. |
ReassignOwnedStmt *stmt = castNode(ReassignOwnedStmt, node); | ||
List *allReassignRoles = stmt->roles; | ||
|
||
List *distributedReassignRoles = FilterDistributedRoles(allReassignRoles); |
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.
Should remove filtering logic as we've discussed two weeks ago.
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.
We decided to keep the filtering logic
|
||
|
||
List * | ||
PreprocessReassignOwnedStmt(Node *node, const char *queryString, |
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.
need to move this down to Postprocess phase
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.
Fixed
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.
Since we haven't still decided yet on the logic, I only added some comments for the tests. Thank you.
|
||
set citus.log_remote_commands to on; | ||
set citus.grep_remote_commands = '%REASSIGN OWNED BY%'; | ||
REASSIGN OWNED BY role1 TO role2; |
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.
-
Regardless of what we decide to do with the scenarios C1,C2,C3,C4,C5,C6,
we should have at least one test for each scenario. And also we should ensure to have test cases with >1 role in the BY clause, e.g. 2 roles:REASSIGN OWNED BY role0, role1 TO role2;
-
As always, let's also add tests where the role names have escaped characters :)
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 distributed and non-distributed roles with escape characters
Pre Review Request Changes
|
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.
Looking at the changes, I realize that it is much better to open a PR against this branch for the changed EnsureDependencies
function. It was hard to follow in this PR. I already left comments here, but can you consider that? Especially if we will ask for an extra review from Nils or someone else.
|
||
static void EnsureDependenciesCanBeDistributed(const ObjectAddress *relationAddress); | ||
static void ErrorIfCircularDependencyExists(const ObjectAddress *objectAddress); | ||
static int ObjectAddressComparator(const void *a, const void *b); | ||
static void EnsureDependenciesExistOnAllNodes(const ObjectAddress *target); | ||
static void EnsureRequiredObjectExistOnAllNodes(const ObjectAddress *target, |
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.
Naming suggestion: Let's use the name of the struct RequiredObjectSet inside the name of this function
static void EnsureRequiredObjectExistOnAllNodes(const ObjectAddress *target, | |
static void EnsureRequiredObjectSetExistsOnAllNodes(const ObjectAddress *target, |
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.
@onurctirtir what's your opinion?
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.
the suggestion makes sense to me
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.
Fixed
List *dependenciesWithCommands = NIL; | ||
Assert(requiredObjectSet == REQUIRE_ONLY_DEPENDENCIES || | ||
requiredObjectSet == REQUIRE_OBJECT_AND_DEPENDENCIES); | ||
|
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.
Before doing anything else, here we can first check if the target object is in fact distributed: if it is we can return early here, regardless of the RequiredObjectSet
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.
I tested to put IsAnyObjectDistributed method however got test failures so I removed
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.
I believe lastly we agreed on adding the following check?
if (IsAnyObjectDistributed(list_make1((ObjectAddress *) target))) | |
{ | |
return; | |
} |
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.
This is the test error when we use IsAnyObjectDistributed(list_make1((ObjectAddress *) target))
https://github.com/citusdata/citus/actions/runs/7321494377
int saveNestLevel = NewGUCNestLevel(); | ||
set_config_option("citus.enable_create_role_propagation", "on", | ||
(superuser() ? PGC_SUSET : PGC_USERSET), PGC_S_SESSION, | ||
GUC_ACTION_LOCAL, true, 0, false); |
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.
We never do anything when calling EnsureDependencies function, and sometimes we may need to propagate roles in that function. Whatever we did before, the same can be applied here. So, I think we don't need these lines.
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.
This block is required to set the GUC into previous state. I've used it in citus_internal_database_command
int saveNestLevel = NewGUCNestLevel(); |
appendStringInfo(buf, "REASSIGN OWNED BY "); | ||
|
||
AppendRoleList(buf, stmt->roles); | ||
char const *newRoleName = RoleSpecString(stmt->newrole, true); |
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.
minor;
char const *newRoleName = RoleSpecString(stmt->newrole, true); | |
char *newRoleName = RoleSpecString(stmt->newrole, true); |
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.
without const I'm getting compile warning below
deparser/deparse_owned_stmts.c:94:22: warning: initialization discards ‘const’ qualifier from pointer target type [-Wdiscarded-qualifiers]
94 | char *newRoleName = RoleSpecString(stmt->newrole, true);
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.
let's do const char
instead of char const
as we usually do then?
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.
please let's not forget changing this, see #7319 (comment)
List *dependenciesWithCommands = NIL; | ||
Assert(requiredObjectSet == REQUIRE_ONLY_DEPENDENCIES || | ||
requiredObjectSet == REQUIRE_OBJECT_AND_DEPENDENCIES); | ||
|
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.
I believe lastly we agreed on adding the following check?
if (IsAnyObjectDistributed(list_make1((ObjectAddress *) target))) | |
{ | |
return; | |
} |
(TODO for myself: Test the PR manually once #7319 (comment) is resolved.) |
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.
Looks very good to me, please consider those last two minor comments too, thanks!
set citus.enable_create_role_propagation to off; | ||
set citus.enable_alter_role_propagation to off; | ||
set citus.enable_alter_role_set_propagation to off; |
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.
awesome test!
show citus.enable_create_role_propagation; | ||
show citus.enable_alter_role_propagation; | ||
show citus.enable_alter_role_set_propagation; |
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.
show stmts are not needed
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.
I'm rollbacking GUC state to previous one so I wanted to test GUC state if it is rollbacked
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.
oh that really makes sense
appendStringInfo(buf, "REASSIGN OWNED BY "); | ||
|
||
AppendRoleList(buf, stmt->roles); | ||
char const *newRoleName = RoleSpecString(stmt->newrole, true); |
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.
please let's not forget changing this, see #7319 (comment)
DESCRIPTION: Adds REASSIGN OWNED BY propagation
This pull request introduces the propagation of the "Reassign owned by" statement. It accommodates both local and distributed roles for both the old and new assignments. However, when the old role is a local role, it undergoes filtering and is not propagated. On the other hand, if the new role is a local role, the process involves first creating the role on worker nodes before propagating the "Reassign owned" statement.