Skip to content

Commit

Permalink
v17 backport: Solve RevertMigration.Comment read/write concurrency is…
Browse files Browse the repository at this point in the history
…sue (#13734)

Signed-off-by: Shlomi Noach <2607934+shlomi-noach@users.noreply.github.com>
  • Loading branch information
shlomi-noach committed Aug 8, 2023
1 parent c530400 commit 166a734
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 2 deletions.
5 changes: 5 additions & 0 deletions go/vt/schema/online_ddl.go
Expand Up @@ -273,6 +273,11 @@ func OnlineDDLFromCommentedStatement(stmt sqlparser.Statement) (onlineDDL *Onlin
default:
return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unsupported statement for Online DDL: %v", sqlparser.String(stmt))
}
// We clone the comments because they will end up being cached by the query planner. Then, the Directive() function actually modifies the comments.
// If comments are shared in cache, and Directive() modifies it, then we have a concurrency issue when someone else wants to read the comments.
// By cloning the comments we remove the concurrency problem.
comments = sqlparser.CloneRefOfParsedComments(comments)
comments.ResetDirectives()

if comments.Length() == 0 {
return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "no comments found in statement: %v", sqlparser.String(stmt))
Expand Down
2 changes: 1 addition & 1 deletion go/vt/servenv/version.go
Expand Up @@ -19,4 +19,4 @@ package servenv
// THIS FILE IS AUTO-GENERATED DURING NEW RELEASES BY ./tools/do_releases.sh
// DO NOT EDIT

const versionName = "17.0.1"
const versionName = "17.0.2-SNAPSHOT"
29 changes: 29 additions & 0 deletions go/vt/sqlparser/ast_test.go
Expand Up @@ -818,3 +818,32 @@ func BenchmarkStringTraces(b *testing.B) {
})
}
}

func TestCloneComments(t *testing.T) {
c := []string{"/*vt+ a=b */"}
parsedComments := Comments(c).Parsed()
directives := parsedComments.Directives()
{
assert.NotEmpty(t, directives.m)
val, ok := directives.m["a"]
assert.Truef(t, ok, "directives map: %v", directives.m)
assert.Equal(t, "b", val)
}
cloned := CloneRefOfParsedComments(parsedComments)
cloned.ResetDirectives()
clonedDirectives := cloned.Directives()
{
assert.NotEmpty(t, clonedDirectives.m)
val, ok := clonedDirectives.m["a"]
assert.Truef(t, ok, "directives map: %v", directives.m)
assert.Equal(t, "b", val)
}
{
delete(directives.m, "a")
assert.Empty(t, directives.m)

val, ok := clonedDirectives.m["a"]
assert.Truef(t, ok, "directives map: %v", directives.m)
assert.Equal(t, "b", val)
}
}
9 changes: 9 additions & 0 deletions go/vt/sqlparser/comments.go
Expand Up @@ -224,6 +224,15 @@ type CommentDirectives struct {
m map[string]string
}

// ResetDirectives sets the _directives member to `nil`, which means the next call to Directives()
// will re-evaluate it.
func (c *ParsedComments) ResetDirectives() {
if c == nil {
return
}
c._directives = nil
}

// Directives parses the comment list for any execution directives
// of the form:
//
Expand Down
2 changes: 1 addition & 1 deletion go/vt/vttablet/onlineddl/executor.go
Expand Up @@ -2850,7 +2850,7 @@ func (e *Executor) executeAlterViewOnline(ctx context.Context, onlineDDL *schema
Select: viewStmt.Select,
CheckOption: viewStmt.CheckOption,
IsReplace: true,
Comments: viewStmt.Comments,
Comments: sqlparser.CloneRefOfParsedComments(viewStmt.Comments),
}
stmt.SetTable("", artifactViewName)
default:
Expand Down

0 comments on commit 166a734

Please sign in to comment.