diff options
author | Paul Okstad <pokstad@gitlab.com> | 2020-07-11 03:29:18 +0300 |
---|---|---|
committer | Paul Okstad <pokstad@gitlab.com> | 2020-07-11 03:29:18 +0300 |
commit | 15f6d1a084092ace5feee754ec7f43e010e102ff (patch) | |
tree | 9f15bca1ff679fdcee2d41f8f035b3879b8303fd | |
parent | 74fa51387fbc4ac199309f5c0461d4cdde2a1a2f (diff) | |
parent | 74603c7b31aae78b70a5ad84054c3cce7e84f962 (diff) |
Merge branch 'pks-transactions-operations' into 'master'
Start using transactions for UserCreateBranch
See merge request gitlab-org/gitaly!2364
-rw-r--r-- | changelogs/unreleased/pks-transactions-operations.yml | 5 | ||||
-rw-r--r-- | internal/metadata/featureflag/feature_flags.go | 11 | ||||
-rw-r--r-- | internal/praefect/coordinator.go | 26 | ||||
-rw-r--r-- | internal/rubyserver/proxy.go | 7 | ||||
-rw-r--r-- | internal/service/operations/branches_test.go | 14 | ||||
-rw-r--r-- | ruby/lib/gitaly_server.rb | 2 | ||||
-rw-r--r-- | ruby/lib/gitaly_server/operations_service.rb | 3 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/hook.rb | 7 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/hooks_service.rb | 5 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/operation_service.rb | 13 | ||||
-rw-r--r-- | ruby/lib/gitlab/git/repository.rb | 4 | ||||
-rw-r--r-- | ruby/lib/praefect/transaction.rb | 24 |
12 files changed, 97 insertions, 24 deletions
diff --git a/changelogs/unreleased/pks-transactions-operations.yml b/changelogs/unreleased/pks-transactions-operations.yml new file mode 100644 index 000000000..43861fa2f --- /dev/null +++ b/changelogs/unreleased/pks-transactions-operations.yml @@ -0,0 +1,5 @@ +--- +title: Start using transactions for UserCreateBranch +merge_request: 2364 +author: +type: added diff --git a/internal/metadata/featureflag/feature_flags.go b/internal/metadata/featureflag/feature_flags.go index 2b075bc91..1580ef556 100644 --- a/internal/metadata/featureflag/feature_flags.go +++ b/internal/metadata/featureflag/feature_flags.go @@ -14,12 +14,19 @@ var ( RemoteBranchesLsRemote = FeatureFlag{Name: "ruby_remote_branches_ls_remote", OnByDefault: true} // GoFetchSourceBranch enables a go implementation of FetchSourceBranch GoFetchSourceBranch = FeatureFlag{Name: "go_fetch_source_branch", OnByDefault: false} - // ReferenceTransactions will handle Git reference updates via the transaction service for strong consistency - ReferenceTransactions = FeatureFlag{Name: "reference_transactions", OnByDefault: false} // DistributedReads allows praefect to redirect accessor operations to up-to-date secondaries DistributedReads = FeatureFlag{Name: "distributed_reads", OnByDefault: false} // GoPreReceiveHook will bypass the ruby pre-receive hook and use the go implementation GoPreReceiveHook = FeatureFlag{Name: "go_prereceive_hook", OnByDefault: true} + + // ReferenceTransactions will handle Git reference updates via the transaction service for strong consistency + ReferenceTransactions = FeatureFlag{Name: "reference_transactions", OnByDefault: false} + // ReferenceTransactionsOperationService will enable reference transactions for the OperationService + ReferenceTransactionsOperationService = FeatureFlag{Name: "reference_transactions_operation_service", OnByDefault: true} + // ReferenceTransactionsSmartHTTPService will enable reference transactions for the SmartHTTPService + ReferenceTransactionsSmartHTTPService = FeatureFlag{Name: "reference_transactions_smarthttp_service", OnByDefault: true} + // ReferenceTransactionsSSHService will enable reference transactions for the SSHService + ReferenceTransactionsSSHService = FeatureFlag{Name: "reference_transactions_ssh_service", OnByDefault: true} ) const ( diff --git a/internal/praefect/coordinator.go b/internal/praefect/coordinator.go index 38c16c282..274ea6419 100644 --- a/internal/praefect/coordinator.go +++ b/internal/praefect/coordinator.go @@ -157,9 +157,27 @@ func (c *Coordinator) accessorStreamParameters(ctx context.Context, call grpcCal }, nil, nil, nil), nil } -var transactionRPCs = map[string]struct{}{ - "/gitaly.SmartHTTPService/PostReceivePack": {}, - "/gitaly.SSHService/SSHReceivePack": {}, +var transactionRPCs = map[string]featureflag.FeatureFlag{ + "/gitaly.OperationService/UserCreateBranch": featureflag.ReferenceTransactionsOperationService, + "/gitaly.SSHService/SSHReceivePack": featureflag.ReferenceTransactionsSSHService, + "/gitaly.SmartHTTPService/PostReceivePack": featureflag.ReferenceTransactionsSmartHTTPService, +} + +func shouldUseTransaction(ctx context.Context, method string) bool { + if !featureflag.IsEnabled(ctx, featureflag.ReferenceTransactions) { + return false + } + + flag, ok := transactionRPCs[method] + if !ok { + return false + } + + if !featureflag.IsEnabled(ctx, flag) { + return false + } + + return true } func (c *Coordinator) mutatorStreamParameters(ctx context.Context, call grpcCall, targetRepo *gitalypb.Repository) (*proxy.StreamParameters, error) { @@ -194,7 +212,7 @@ func (c *Coordinator) mutatorStreamParameters(ctx context.Context, call grpcCall var secondaryDests []proxy.Destination - if _, ok := transactionRPCs[call.fullMethodName]; ok && featureflag.IsEnabled(ctx, featureflag.ReferenceTransactions) { + if shouldUseTransaction(ctx, call.fullMethodName) { // Make sure to only let healthy nodes take part in transactions, otherwise we'll be // completely blocked until they come back. healthySecondaries := shard.GetHealthySecondaries() diff --git a/internal/rubyserver/proxy.go b/internal/rubyserver/proxy.go index 87052c900..f0b8e3f9b 100644 --- a/internal/rubyserver/proxy.go +++ b/internal/rubyserver/proxy.go @@ -7,6 +7,7 @@ import ( "strings" "gitlab.com/gitlab-org/gitaly/internal/helper" + praefect_metadata "gitlab.com/gitlab-org/gitaly/internal/praefect/metadata" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/metadata" ) @@ -62,7 +63,11 @@ func setHeaders(ctx context.Context, repo *gitalypb.Repository, mustExist bool) ) // list of http/2 headers that will be forwarded as-is to gitaly-ruby - proxyHeaderWhitelist := []string{"gitaly-servers"} + proxyHeaderWhitelist := []string{ + "gitaly-servers", + praefect_metadata.TransactionMetadataKey, + praefect_metadata.PraefectMetadataKey, + } if inMD, ok := metadata.FromIncomingContext(ctx); ok { // Automatically whitelist any Ruby-specific feature flag diff --git a/internal/service/operations/branches_test.go b/internal/service/operations/branches_test.go index e290e3948..cbc90472d 100644 --- a/internal/service/operations/branches_test.go +++ b/internal/service/operations/branches_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "gitlab.com/gitlab-org/gitaly/internal/git/log" + "gitlab.com/gitlab-org/gitaly/internal/metadata/featureflag" "gitlab.com/gitlab-org/gitaly/internal/testhelper" "gitlab.com/gitlab-org/gitaly/proto/go/gitalypb" "google.golang.org/grpc/codes" @@ -75,10 +76,17 @@ func TestSuccessfulCreateBranchRequest(t *testing.T) { } func TestSuccessfulGitHooksForUserCreateBranchRequest(t *testing.T) { - ctx, cancel := testhelper.Context() - defer cancel() + featureSets, err := testhelper.NewFeatureSets([]featureflag.FeatureFlag{featureflag.ReferenceTransactions}) + require.NoError(t, err) - testSuccessfulGitHooksForUserCreateBranchRequest(t, ctx) + for _, featureSet := range featureSets { + ctx, cancel := testhelper.Context() + defer cancel() + + ctx = featureSet.WithParent(ctx) + + testSuccessfulGitHooksForUserCreateBranchRequest(t, ctx) + } } func testSuccessfulGitHooksForUserCreateBranchRequest(t *testing.T, ctx context.Context) { diff --git a/ruby/lib/gitaly_server.rb b/ruby/lib/gitaly_server.rb index b6a085f57..a3e68fbff 100644 --- a/ruby/lib/gitaly_server.rb +++ b/ruby/lib/gitaly_server.rb @@ -14,6 +14,8 @@ require_relative 'gitaly_server/remote_service.rb' require_relative 'gitaly_server/health_service.rb' require_relative 'gitaly_server/feature_flags.rb' +require_relative 'praefect/transaction.rb' + module GitalyServer STORAGE_PATH_HEADER = 'gitaly-storage-path'.freeze REPO_PATH_HEADER = 'gitaly-repo-path'.freeze diff --git a/ruby/lib/gitaly_server/operations_service.rb b/ruby/lib/gitaly_server/operations_service.rb index d4aebac0c..0f4db6c7d 100644 --- a/ruby/lib/gitaly_server/operations_service.rb +++ b/ruby/lib/gitaly_server/operations_service.rb @@ -49,10 +49,11 @@ module GitalyServer repo = Gitlab::Git::Repository.from_gitaly(request.repository, call) target = get_param!(request, :start_point) gitaly_user = get_param!(request, :user) + transaction = Praefect::Transaction.from_metadata(call.metadata) branch_name = request.branch_name user = Gitlab::Git::User.from_gitaly(gitaly_user) - created_branch = repo.add_branch(branch_name, user: user, target: target) + created_branch = repo.add_branch(branch_name, user: user, target: target, transaction: transaction) Gitaly::UserCreateBranchResponse.new unless created_branch rugged_commit = created_branch.dereferenced_target.rugged_commit diff --git a/ruby/lib/gitlab/git/hook.rb b/ruby/lib/gitlab/git/hook.rb index 78fa009fd..9fb54506e 100644 --- a/ruby/lib/gitlab/git/hook.rb +++ b/ruby/lib/gitlab/git/hook.rb @@ -28,13 +28,13 @@ module Gitlab File.exist?(path) end - def trigger(gl_id, gl_username, oldrev, newrev, ref, push_options: nil) + def trigger(gl_id, gl_username, oldrev, newrev, ref, push_options: nil, transaction: nil) return [true, nil] unless exists? Bundler.with_clean_env do case name when "pre-receive", "post-receive" - call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options) + call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options, transaction) when "update" call_update_hook(gl_id, gl_username, oldrev, newrev, ref) end @@ -43,7 +43,7 @@ module Gitlab private - def call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options) + def call_receive_hook(gl_id, gl_username, oldrev, newrev, ref, push_options, transaction) changes = [oldrev, newrev, ref].join(" ") exit_status = false @@ -51,6 +51,7 @@ module Gitlab vars = env_base_vars(gl_id, gl_username) vars.merge!(push_options.env_data) if push_options + vars.merge!(transaction.env_vars) if transaction options = { chdir: repo_path diff --git a/ruby/lib/gitlab/git/hooks_service.rb b/ruby/lib/gitlab/git/hooks_service.rb index 30501d388..5ad8e43b7 100644 --- a/ruby/lib/gitlab/git/hooks_service.rb +++ b/ruby/lib/gitlab/git/hooks_service.rb @@ -3,7 +3,7 @@ module Gitlab class HooksService attr_accessor :oldrev, :newrev, :ref - def execute(pusher, repository, oldrev, newrev, ref, push_options:) + def execute(pusher, repository, oldrev, newrev, ref, push_options:, transaction: nil) @repository = repository @gl_id = pusher.gl_id @gl_username = pusher.username @@ -11,6 +11,7 @@ module Gitlab @newrev = newrev @ref = ref @push_options = push_options + @transaction = transaction %w[pre-receive update].each do |hook_name| status, message = run_hook(hook_name) @@ -29,7 +30,7 @@ module Gitlab def run_hook(name) hook = Gitlab::Git::Hook.new(name, @repository) - hook.trigger(@gl_id, @gl_username, oldrev, newrev, ref, push_options: @push_options) + hook.trigger(@gl_id, @gl_username, oldrev, newrev, ref, push_options: @push_options, transaction: @transaction) end end end diff --git a/ruby/lib/gitlab/git/operation_service.rb b/ruby/lib/gitlab/git/operation_service.rb index 5be4d27e0..e6025b673 100644 --- a/ruby/lib/gitlab/git/operation_service.rb +++ b/ruby/lib/gitlab/git/operation_service.rb @@ -25,11 +25,11 @@ module Gitlab @repository = new_repository end - def add_branch(branch_name, newrev) + def add_branch(branch_name, newrev, transaction: nil) ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name oldrev = Gitlab::Git::BLANK_SHA - update_ref_in_hooks(ref, newrev, oldrev) + update_ref_in_hooks(ref, newrev, oldrev, transaction: transaction) end def rm_branch(branch) @@ -172,20 +172,21 @@ module Gitlab end end - def update_ref_in_hooks(ref, newrev, oldrev, push_options: nil) - with_hooks(ref, newrev, oldrev, push_options: push_options) do + def update_ref_in_hooks(ref, newrev, oldrev, push_options: nil, transaction: nil) + with_hooks(ref, newrev, oldrev, push_options: push_options, transaction: transaction) do update_ref(ref, newrev, oldrev) end end - def with_hooks(ref, newrev, oldrev, push_options: nil) + def with_hooks(ref, newrev, oldrev, push_options: nil, transaction: nil) Gitlab::Git::HooksService.new.execute( user, repository, oldrev, newrev, ref, - push_options: push_options + push_options: push_options, + transaction: transaction ) do |service| yield(service) end diff --git a/ruby/lib/gitlab/git/repository.rb b/ruby/lib/gitlab/git/repository.rb index 28502287c..675f4b2e2 100644 --- a/ruby/lib/gitlab/git/repository.rb +++ b/ruby/lib/gitlab/git/repository.rb @@ -88,11 +88,11 @@ module Gitlab @feature_flags.enabled?(flag, on_by_default: on_by_default) end - def add_branch(branch_name, user:, target:) + def add_branch(branch_name, user:, target:, transaction: nil) target_object = Ref.dereference_object(lookup(target)) raise InvalidRef, "target not found: #{target}" unless target_object - OperationService.new(user, self).add_branch(branch_name, target_object.oid) + OperationService.new(user, self).add_branch(branch_name, target_object.oid, transaction: transaction) find_branch(branch_name) rescue Rugged::ReferenceError => ex raise InvalidRef, ex diff --git a/ruby/lib/praefect/transaction.rb b/ruby/lib/praefect/transaction.rb new file mode 100644 index 000000000..3ddf6c5f6 --- /dev/null +++ b/ruby/lib/praefect/transaction.rb @@ -0,0 +1,24 @@ +module Praefect + class Transaction + PRAEFECT_SERVER_KEY = "praefect-server".freeze + PRAEFECT_SERVER_ENV = "PRAEFECT_SERVER".freeze + TRANSACTION_KEY = "transaction".freeze + TRANSACTION_ENV = "REFERENCE_TRANSACTION".freeze + + def self.from_metadata(metadata) + new(metadata[PRAEFECT_SERVER_KEY], metadata[TRANSACTION_KEY]) + end + + def initialize(server, transaction) + @server = server + @transaction = transaction + end + + def env_vars + { + TRANSACTION_ENV => @transaction, + PRAEFECT_SERVER_ENV => @server + }.reject { |_, v| v.nil? } + end + end +end |